Skip to content

Commit faa87ce

Browse files
Aidan MacDonaldbroonie
authored andcommitted
regmap-irq: Introduce config registers for irq types
Config registers provide a more uniform approach to handling irq type registers. They are essentially an extension of the virtual registers used by the qcom-pm8008 driver. Config registers can be represented as a 2D array: config_base[0] reg0,0 reg0,1 reg0,2 reg0,3 config_base[1] reg1,0 reg1,1 reg1,2 reg1,3 config_base[2] reg2,0 reg2,1 reg2,2 reg2,3 There are 'num_config_bases' base registers, each of which is used to address 'num_config_regs' registers. The addresses are calculated in the same way as for other bases. It is assumed that an irq's type is controlled by one column of registers; that column is identified by the irq's 'type_reg_offset'. The set_type_config() callback is responsible for updating the config register contents. It receives an array of buffers (each represents a row of registers) and the index of the column to update, along with the 'struct regmap_irq' description and requested irq type. Buffered values are written to registers in regmap_irq_sync_unlock(). Note that the entire register contents are overwritten, which is a minor change in behavior from type registers via 'type_base'. Signed-off-by: Aidan MacDonald <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent f7cc506 commit faa87ce

File tree

2 files changed

+122
-5
lines changed

2 files changed

+122
-5
lines changed

drivers/base/regmap/regmap-irq.c

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct regmap_irq_chip_data {
3939
unsigned int *type_buf;
4040
unsigned int *type_buf_def;
4141
unsigned int **virt_buf;
42+
unsigned int **config_buf;
4243

4344
unsigned int irq_reg_stride;
4445

@@ -228,6 +229,17 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
228229
}
229230
}
230231

232+
for (i = 0; i < d->chip->num_config_bases; i++) {
233+
for (j = 0; j < d->chip->num_config_regs; j++) {
234+
reg = sub_irq_reg(d, d->chip->config_base[i], j);
235+
ret = regmap_write(map, reg, d->config_buf[i][j]);
236+
if (ret)
237+
dev_err(d->map->dev,
238+
"Failed to write config %x: %d\n",
239+
reg, ret);
240+
}
241+
}
242+
231243
if (d->chip->runtime_pm)
232244
pm_runtime_put(map->dev);
233245

@@ -287,7 +299,7 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
287299
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
288300
struct regmap *map = d->map;
289301
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
290-
int reg;
302+
int reg, ret;
291303
const struct regmap_irq_type *t = &irq_data->type;
292304

293305
if ((t->types_supported & type) != type)
@@ -327,9 +339,19 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
327339
return -EINVAL;
328340
}
329341

330-
if (d->chip->set_type_virt)
331-
return d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
332-
reg);
342+
if (d->chip->set_type_virt) {
343+
ret = d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
344+
reg);
345+
if (ret)
346+
return ret;
347+
}
348+
349+
if (d->chip->set_type_config) {
350+
ret = d->chip->set_type_config(d->config_buf, type,
351+
irq_data, reg);
352+
if (ret)
353+
return ret;
354+
}
333355

334356
return 0;
335357
}
@@ -599,6 +621,61 @@ static const struct irq_domain_ops regmap_domain_ops = {
599621
.xlate = irq_domain_xlate_onetwocell,
600622
};
601623

624+
/**
625+
* regmap_irq_set_type_config_simple() - Simple IRQ type configuration callback.
626+
* @buf: Buffer containing configuration register values, this is a 2D array of
627+
* `num_config_bases` rows, each of `num_config_regs` elements.
628+
* @type: The requested IRQ type.
629+
* @irq_data: The IRQ being configured.
630+
* @idx: Index of the irq's config registers within each array `buf[i]`
631+
*
632+
* This is a &struct regmap_irq_chip->set_type_config callback suitable for
633+
* chips with one config register. Register values are updated according to
634+
* the &struct regmap_irq_type data associated with an IRQ.
635+
*/
636+
int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
637+
const struct regmap_irq *irq_data, int idx)
638+
{
639+
const struct regmap_irq_type *t = &irq_data->type;
640+
641+
if (t->type_reg_mask)
642+
buf[0][idx] &= ~t->type_reg_mask;
643+
else
644+
buf[0][idx] &= ~(t->type_falling_val |
645+
t->type_rising_val |
646+
t->type_level_low_val |
647+
t->type_level_high_val);
648+
649+
switch (type) {
650+
case IRQ_TYPE_EDGE_FALLING:
651+
buf[0][idx] |= t->type_falling_val;
652+
break;
653+
654+
case IRQ_TYPE_EDGE_RISING:
655+
buf[0][idx] |= t->type_rising_val;
656+
break;
657+
658+
case IRQ_TYPE_EDGE_BOTH:
659+
buf[0][idx] |= (t->type_falling_val |
660+
t->type_rising_val);
661+
break;
662+
663+
case IRQ_TYPE_LEVEL_HIGH:
664+
buf[0][idx] |= t->type_level_high_val;
665+
break;
666+
667+
case IRQ_TYPE_LEVEL_LOW:
668+
buf[0][idx] |= t->type_level_low_val;
669+
break;
670+
671+
default:
672+
return -EINVAL;
673+
}
674+
675+
return 0;
676+
}
677+
EXPORT_SYMBOL_GPL(regmap_irq_set_type_config_simple);
678+
602679
/**
603680
* regmap_add_irq_chip_fwnode() - Use standard regmap IRQ controller handling
604681
*
@@ -724,6 +801,24 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
724801
}
725802
}
726803

804+
if (chip->num_config_bases && chip->num_config_regs) {
805+
/*
806+
* Create config_buf[num_config_bases][num_config_regs]
807+
*/
808+
d->config_buf = kcalloc(chip->num_config_bases,
809+
sizeof(*d->config_buf), GFP_KERNEL);
810+
if (!d->config_buf)
811+
goto err_alloc;
812+
813+
for (i = 0; i < chip->num_config_regs; i++) {
814+
d->config_buf[i] = kcalloc(chip->num_config_regs,
815+
sizeof(**d->config_buf),
816+
GFP_KERNEL);
817+
if (!d->config_buf[i])
818+
goto err_alloc;
819+
}
820+
}
821+
727822
d->irq_chip = regmap_irq_chip;
728823
d->irq_chip.name = chip->name;
729824
d->irq = irq;
@@ -894,6 +989,11 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
894989
kfree(d->virt_buf[i]);
895990
kfree(d->virt_buf);
896991
}
992+
if (d->config_buf) {
993+
for (i = 0; i < chip->num_config_bases; i++)
994+
kfree(d->config_buf[i]);
995+
kfree(d->config_buf);
996+
}
897997
kfree(d);
898998
return ret;
899999
}
@@ -934,7 +1034,7 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
9341034
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
9351035
{
9361036
unsigned int virq;
937-
int hwirq;
1037+
int i, hwirq;
9381038

9391039
if (!d)
9401040
return;
@@ -964,6 +1064,11 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
9641064
kfree(d->mask_buf);
9651065
kfree(d->status_reg_buf);
9661066
kfree(d->status_buf);
1067+
if (d->config_buf) {
1068+
for (i = 0; i < d->chip->num_config_bases; i++)
1069+
kfree(d->config_buf[i]);
1070+
kfree(d->config_buf);
1071+
}
9671072
kfree(d);
9681073
}
9691074
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);

include/linux/regmap.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,7 @@ struct regmap_irq_sub_irq_map {
14751475
* @wake_base: Base address for wake enables. If zero unsupported.
14761476
* @type_base: Base address for irq type. If zero unsupported.
14771477
* @virt_reg_base: Base addresses for extra config regs.
1478+
* @config_base: Base address for IRQ type config regs. If null unsupported.
14781479
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
14791480
* @init_ack_masked: Ack all masked interrupts once during initalization.
14801481
* @mask_invert: Inverted mask register: cleared bits are masked out.
@@ -1504,12 +1505,15 @@ struct regmap_irq_sub_irq_map {
15041505
* @num_type_reg: Number of type registers.
15051506
* @num_virt_regs: Number of non-standard irq configuration registers.
15061507
* If zero unsupported.
1508+
* @num_config_bases: Number of config base registers.
1509+
* @num_config_regs: Number of config registers for each config base register.
15071510
* @handle_pre_irq: Driver specific callback to handle interrupt from device
15081511
* before regmap_irq_handler process the interrupts.
15091512
* @handle_post_irq: Driver specific callback to handle interrupt from device
15101513
* after handling the interrupts in regmap_irq_handler().
15111514
* @set_type_virt: Driver specific callback to extend regmap_irq_set_type()
15121515
* and configure virt regs.
1516+
* @set_type_config: Callback used for configuring irq types.
15131517
* @irq_drv_data: Driver specific IRQ data which is passed as parameter when
15141518
* driver specific pre/post interrupt handler is called.
15151519
*
@@ -1532,6 +1536,7 @@ struct regmap_irq_chip {
15321536
unsigned int wake_base;
15331537
unsigned int type_base;
15341538
unsigned int *virt_reg_base;
1539+
const unsigned int *config_base;
15351540
unsigned int irq_reg_stride;
15361541
unsigned int init_ack_masked:1;
15371542
unsigned int mask_invert:1;
@@ -1553,16 +1558,23 @@ struct regmap_irq_chip {
15531558

15541559
int num_type_reg;
15551560
int num_virt_regs;
1561+
int num_config_bases;
1562+
int num_config_regs;
15561563

15571564
int (*handle_pre_irq)(void *irq_drv_data);
15581565
int (*handle_post_irq)(void *irq_drv_data);
15591566
int (*set_type_virt)(unsigned int **buf, unsigned int type,
15601567
unsigned long hwirq, int reg);
1568+
int (*set_type_config)(unsigned int **buf, unsigned int type,
1569+
const struct regmap_irq *irq_data, int idx);
15611570
void *irq_drv_data;
15621571
};
15631572

15641573
struct regmap_irq_chip_data;
15651574

1575+
int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
1576+
const struct regmap_irq *irq_data, int idx);
1577+
15661578
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
15671579
int irq_base, const struct regmap_irq_chip *chip,
15681580
struct regmap_irq_chip_data **data);

0 commit comments

Comments
 (0)