Skip to content

Commit 1066cfb

Browse files
Guru Das Srinageshbroonie
authored andcommitted
regmap-irq: Extend sub-irq to support non-fixed reg strides
Qualcomm's MFD chips have a top level interrupt status register and sub-irqs (peripherals). When a bit in the main status register goes high, it means that the peripheral corresponding to that bit has an unserviced interrupt. If the bit is not set, this means that the corresponding peripheral does not. Commit a2d2184 ("regmap: regmap-irq: Add main status register support") introduced the sub-irq logic that is currently applied only when reading status registers, but not for any other functions like acking or masking. Extend the use of sub-irq to all other functions, with two caveats regarding the specification of offsets: - Each member of the sub_reg_offsets array should be of length 1 - The specified offsets should be the unequal strides for each sub-irq device. In QCOM's case, all the *_base registers are to be configured to the base addresses of the first sub-irq group, with offsets of each subsequent group calculated as a difference from these addresses. Continuing from the example mentioned in the cover letter: /* * Address of MISC_INT_MASK = 0x1011 * Address of TEMP_ALARM_INT_MASK = 0x2011 * Address of GPIO01_INT_MASK = 0x3011 * * Calculate offsets as: * offset_0 = 0x1011 - 0x1011 = 0 (to access MISC's * registers) * offset_1 = 0x2011 - 0x1011 = 0x1000 * offset_2 = 0x3011 - 0x1011 = 0x2000 */ static unsigned int sub_unit0_offsets[] = {0}; static unsigned int sub_unit1_offsets[] = {0x1000}; static unsigned int sub_unit2_offsets[] = {0x2000}; static struct regmap_irq_sub_irq_map chip_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(sub_unit0_offsets), REGMAP_IRQ_MAIN_REG_OFFSET(sub_unit0_offsets), REGMAP_IRQ_MAIN_REG_OFFSET(sub_unit0_offsets), }; static struct regmap_irq_chip chip_irq_chip = { --------8<-------- .not_fixed_stride = true, .mask_base = MISC_INT_MASK, .type_base = MISC_INT_TYPE, .ack_base = MISC_INT_ACK, .sub_reg_offsets = chip_sub_irq_offsets, --------8<-------- }; Signed-off-by: Guru Das Srinagesh <gurus@codeaurora.org> Link: https://lore.kernel.org/r/526562423eaa58b4075362083f561841f1d6956c.1615423027.git.gurus@codeaurora.org Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent e41a962 commit 1066cfb

2 files changed

Lines changed: 60 additions & 28 deletions

File tree

drivers/base/regmap/regmap-irq.c

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,27 @@ struct regmap_irq_chip_data {
4545
bool clear_status:1;
4646
};
4747

48+
static int sub_irq_reg(struct regmap_irq_chip_data *data,
49+
unsigned int base_reg, int i)
50+
{
51+
const struct regmap_irq_chip *chip = data->chip;
52+
struct regmap *map = data->map;
53+
struct regmap_irq_sub_irq_map *subreg;
54+
unsigned int offset;
55+
int reg = 0;
56+
57+
if (!chip->sub_reg_offsets || !chip->not_fixed_stride) {
58+
/* Assume linear mapping */
59+
reg = base_reg + (i * map->reg_stride * data->irq_reg_stride);
60+
} else {
61+
subreg = &chip->sub_reg_offsets[i];
62+
offset = subreg->offset[0];
63+
reg = base_reg + offset;
64+
}
65+
66+
return reg;
67+
}
68+
4869
static inline const
4970
struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
5071
int irq)
@@ -87,8 +108,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
87108

88109
if (d->clear_status) {
89110
for (i = 0; i < d->chip->num_regs; i++) {
90-
reg = d->chip->status_base +
91-
(i * map->reg_stride * d->irq_reg_stride);
111+
reg = sub_irq_reg(d, d->chip->status_base, i);
92112

93113
ret = regmap_read(map, reg, &val);
94114
if (ret)
@@ -108,8 +128,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
108128
if (!d->chip->mask_base)
109129
continue;
110130

111-
reg = d->chip->mask_base +
112-
(i * map->reg_stride * d->irq_reg_stride);
131+
reg = sub_irq_reg(d, d->chip->mask_base, i);
113132
if (d->chip->mask_invert) {
114133
ret = regmap_irq_update_bits(d, reg,
115134
d->mask_buf_def[i], ~d->mask_buf[i]);
@@ -136,8 +155,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
136155
dev_err(d->map->dev, "Failed to sync masks in %x\n",
137156
reg);
138157

139-
reg = d->chip->wake_base +
140-
(i * map->reg_stride * d->irq_reg_stride);
158+
reg = sub_irq_reg(d, d->chip->wake_base, i);
141159
if (d->wake_buf) {
142160
if (d->chip->wake_invert)
143161
ret = regmap_irq_update_bits(d, reg,
@@ -161,8 +179,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
161179
* it'll be ignored in irq handler, then may introduce irq storm
162180
*/
163181
if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
164-
reg = d->chip->ack_base +
165-
(i * map->reg_stride * d->irq_reg_stride);
182+
reg = sub_irq_reg(d, d->chip->ack_base, i);
183+
166184
/* some chips ack by write 0 */
167185
if (d->chip->ack_invert)
168186
ret = regmap_write(map, reg, ~d->mask_buf[i]);
@@ -187,8 +205,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
187205
for (i = 0; i < d->chip->num_type_reg; i++) {
188206
if (!d->type_buf_def[i])
189207
continue;
190-
reg = d->chip->type_base +
191-
(i * map->reg_stride * d->type_reg_stride);
208+
reg = sub_irq_reg(d, d->chip->type_base, i);
192209
if (d->chip->type_invert)
193210
ret = regmap_irq_update_bits(d, reg,
194211
d->type_buf_def[i], ~d->type_buf[i]);
@@ -352,8 +369,15 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
352369
for (i = 0; i < subreg->num_regs; i++) {
353370
unsigned int offset = subreg->offset[i];
354371

355-
ret = regmap_read(map, chip->status_base + offset,
356-
&data->status_buf[offset]);
372+
if (chip->not_fixed_stride)
373+
ret = regmap_read(map,
374+
chip->status_base + offset,
375+
&data->status_buf[b]);
376+
else
377+
ret = regmap_read(map,
378+
chip->status_base + offset,
379+
&data->status_buf[offset]);
380+
357381
if (ret)
358382
break;
359383
}
@@ -474,10 +498,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
474498

475499
} else {
476500
for (i = 0; i < data->chip->num_regs; i++) {
477-
ret = regmap_read(map, chip->status_base +
478-
(i * map->reg_stride
479-
* data->irq_reg_stride),
480-
&data->status_buf[i]);
501+
unsigned int reg = sub_irq_reg(data,
502+
data->chip->status_base, i);
503+
ret = regmap_read(map, reg, &data->status_buf[i]);
481504

482505
if (ret != 0) {
483506
dev_err(map->dev,
@@ -499,8 +522,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
499522
data->status_buf[i] &= ~data->mask_buf[i];
500523

501524
if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) {
502-
reg = chip->ack_base +
503-
(i * map->reg_stride * data->irq_reg_stride);
525+
reg = sub_irq_reg(data, data->chip->ack_base, i);
526+
504527
if (chip->ack_invert)
505528
ret = regmap_write(map, reg,
506529
~data->status_buf[i]);
@@ -605,6 +628,12 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
605628
return -EINVAL;
606629
}
607630

631+
if (chip->not_fixed_stride) {
632+
for (i = 0; i < chip->num_regs; i++)
633+
if (chip->sub_reg_offsets[i].num_regs != 1)
634+
return -EINVAL;
635+
}
636+
608637
if (irq_base) {
609638
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
610639
if (irq_base < 0) {
@@ -700,8 +729,8 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
700729
if (!chip->mask_base)
701730
continue;
702731

703-
reg = chip->mask_base +
704-
(i * map->reg_stride * d->irq_reg_stride);
732+
reg = sub_irq_reg(d, d->chip->mask_base, i);
733+
705734
if (chip->mask_invert)
706735
ret = regmap_irq_update_bits(d, reg,
707736
d->mask_buf[i], ~d->mask_buf[i]);
@@ -725,8 +754,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
725754
continue;
726755

727756
/* Ack masked but set interrupts */
728-
reg = chip->status_base +
729-
(i * map->reg_stride * d->irq_reg_stride);
757+
reg = sub_irq_reg(d, d->chip->status_base, i);
730758
ret = regmap_read(map, reg, &d->status_buf[i]);
731759
if (ret != 0) {
732760
dev_err(map->dev, "Failed to read IRQ status: %d\n",
@@ -735,8 +763,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
735763
}
736764

737765
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
738-
reg = chip->ack_base +
739-
(i * map->reg_stride * d->irq_reg_stride);
766+
reg = sub_irq_reg(d, d->chip->ack_base, i);
740767
if (chip->ack_invert)
741768
ret = regmap_write(map, reg,
742769
~(d->status_buf[i] & d->mask_buf[i]));
@@ -765,8 +792,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
765792
if (d->wake_buf) {
766793
for (i = 0; i < chip->num_regs; i++) {
767794
d->wake_buf[i] = d->mask_buf_def[i];
768-
reg = chip->wake_base +
769-
(i * map->reg_stride * d->irq_reg_stride);
795+
reg = sub_irq_reg(d, d->chip->wake_base, i);
770796

771797
if (chip->wake_invert)
772798
ret = regmap_irq_update_bits(d, reg,
@@ -786,8 +812,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
786812

787813
if (chip->num_type_reg && !chip->type_in_mask) {
788814
for (i = 0; i < chip->num_type_reg; ++i) {
789-
reg = chip->type_base +
790-
(i * map->reg_stride * d->type_reg_stride);
815+
reg = sub_irq_reg(d, d->chip->type_base, i);
791816

792817
ret = regmap_read(map, reg, &d->type_buf_def[i]);
793818

include/linux/regmap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,9 @@ struct regmap_irq_sub_irq_map {
13781378
* status_base. Should contain num_regs arrays.
13791379
* Can be provided for chips with more complex mapping than
13801380
* 1.st bit to 1.st sub-reg, 2.nd bit to 2.nd sub-reg, ...
1381+
* When used with not_fixed_stride, each one-element array
1382+
* member contains offset calculated as address from each
1383+
* peripheral to first peripheral.
13811384
* @num_main_regs: Number of 'main status' irq registers for chips which have
13821385
* main_status set.
13831386
*
@@ -1404,6 +1407,9 @@ struct regmap_irq_sub_irq_map {
14041407
* @clear_on_unmask: For chips with interrupts cleared on read: read the status
14051408
* registers before unmasking interrupts to clear any bits
14061409
* set when they were masked.
1410+
* @not_fixed_stride: Used when chip peripherals are not laid out with fixed
1411+
* stride. Must be used with sub_reg_offsets containing the
1412+
* offsets to each peripheral.
14071413
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
14081414
*
14091415
* @num_regs: Number of registers in each control bank.
@@ -1450,6 +1456,7 @@ struct regmap_irq_chip {
14501456
bool type_invert:1;
14511457
bool type_in_mask:1;
14521458
bool clear_on_unmask:1;
1459+
bool not_fixed_stride:1;
14531460

14541461
int num_regs;
14551462

0 commit comments

Comments
 (0)