Commit 5dea215028686a67e815c32a54dc89fb3467ab05

Authored by Mark Brown

Merge remote-tracking branch 'regmap/topic/irq' into regmap-next

Showing 4 changed files Side-by-side Diff

drivers/base/regmap/regmap-irq.c
... ... @@ -34,6 +34,7 @@
34 34 int irq;
35 35 int wake_count;
36 36  
  37 + void *status_reg_buf;
37 38 unsigned int *status_buf;
38 39 unsigned int *mask_buf;
39 40 unsigned int *mask_buf_def;
... ... @@ -87,6 +88,23 @@
87 88 if (ret != 0)
88 89 dev_err(d->map->dev, "Failed to sync masks in %x\n",
89 90 reg);
  91 +
  92 + reg = d->chip->wake_base +
  93 + (i * map->reg_stride * d->irq_reg_stride);
  94 + if (d->wake_buf) {
  95 + if (d->chip->wake_invert)
  96 + ret = regmap_update_bits(d->map, reg,
  97 + d->mask_buf_def[i],
  98 + ~d->wake_buf[i]);
  99 + else
  100 + ret = regmap_update_bits(d->map, reg,
  101 + d->mask_buf_def[i],
  102 + d->wake_buf[i]);
  103 + if (ret != 0)
  104 + dev_err(d->map->dev,
  105 + "Failed to sync wakes in %x: %d\n",
  106 + reg, ret);
  107 + }
90 108 }
91 109  
92 110 if (d->chip->runtime_pm)
93 111  
94 112  
... ... @@ -129,16 +147,15 @@
129 147 struct regmap *map = d->map;
130 148 const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
131 149  
132   - if (!d->chip->wake_base)
133   - return -EINVAL;
134   -
135 150 if (on) {
136   - d->wake_buf[irq_data->reg_offset / map->reg_stride]
137   - &= ~irq_data->mask;
  151 + if (d->wake_buf)
  152 + d->wake_buf[irq_data->reg_offset / map->reg_stride]
  153 + &= ~irq_data->mask;
138 154 d->wake_count++;
139 155 } else {
140   - d->wake_buf[irq_data->reg_offset / map->reg_stride]
141   - |= irq_data->mask;
  156 + if (d->wake_buf)
  157 + d->wake_buf[irq_data->reg_offset / map->reg_stride]
  158 + |= irq_data->mask;
142 159 d->wake_count--;
143 160 }
144 161  
145 162  
146 163  
147 164  
148 165  
... ... @@ -172,25 +189,69 @@
172 189 }
173 190  
174 191 /*
175   - * Ignore masked IRQs and ack if we need to; we ack early so
176   - * there is no race between handling and acknowleding the
177   - * interrupt. We assume that typically few of the interrupts
178   - * will fire simultaneously so don't worry about overhead from
179   - * doing a write per register.
  192 + * Read in the statuses, using a single bulk read if possible
  193 + * in order to reduce the I/O overheads.
180 194 */
181   - for (i = 0; i < data->chip->num_regs; i++) {
182   - ret = regmap_read(map, chip->status_base + (i * map->reg_stride
183   - * data->irq_reg_stride),
184   - &data->status_buf[i]);
  195 + if (!map->use_single_rw && map->reg_stride == 1 &&
  196 + data->irq_reg_stride == 1) {
  197 + u8 *buf8 = data->status_reg_buf;
  198 + u16 *buf16 = data->status_reg_buf;
  199 + u32 *buf32 = data->status_reg_buf;
185 200  
  201 + BUG_ON(!data->status_reg_buf);
  202 +
  203 + ret = regmap_bulk_read(map, chip->status_base,
  204 + data->status_reg_buf,
  205 + chip->num_regs);
186 206 if (ret != 0) {
187 207 dev_err(map->dev, "Failed to read IRQ status: %d\n",
188   - ret);
189   - if (chip->runtime_pm)
190   - pm_runtime_put(map->dev);
  208 + ret);
191 209 return IRQ_NONE;
192 210 }
193 211  
  212 + for (i = 0; i < data->chip->num_regs; i++) {
  213 + switch (map->format.val_bytes) {
  214 + case 1:
  215 + data->status_buf[i] = buf8[i];
  216 + break;
  217 + case 2:
  218 + data->status_buf[i] = buf16[i];
  219 + break;
  220 + case 4:
  221 + data->status_buf[i] = buf32[i];
  222 + break;
  223 + default:
  224 + BUG();
  225 + return IRQ_NONE;
  226 + }
  227 + }
  228 +
  229 + } else {
  230 + for (i = 0; i < data->chip->num_regs; i++) {
  231 + ret = regmap_read(map, chip->status_base +
  232 + (i * map->reg_stride
  233 + * data->irq_reg_stride),
  234 + &data->status_buf[i]);
  235 +
  236 + if (ret != 0) {
  237 + dev_err(map->dev,
  238 + "Failed to read IRQ status: %d\n",
  239 + ret);
  240 + if (chip->runtime_pm)
  241 + pm_runtime_put(map->dev);
  242 + return IRQ_NONE;
  243 + }
  244 + }
  245 + }
  246 +
  247 + /*
  248 + * Ignore masked IRQs and ack if we need to; we ack early so
  249 + * there is no race between handling and acknowleding the
  250 + * interrupt. We assume that typically few of the interrupts
  251 + * will fire simultaneously so don't worry about overhead from
  252 + * doing a write per register.
  253 + */
  254 + for (i = 0; i < data->chip->num_regs; i++) {
194 255 data->status_buf[i] &= ~data->mask_buf[i];
195 256  
196 257 if (data->status_buf[i] && chip->ack_base) {
... ... @@ -316,11 +377,6 @@
316 377  
317 378 d->irq_chip = regmap_irq_chip;
318 379 d->irq_chip.name = chip->name;
319   - if (!chip->wake_base) {
320   - d->irq_chip.irq_set_wake = NULL;
321   - d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
322   - IRQCHIP_SKIP_SET_WAKE;
323   - }
324 380 d->irq = irq;
325 381 d->map = map;
326 382 d->chip = chip;
... ... @@ -331,6 +387,14 @@
331 387 else
332 388 d->irq_reg_stride = 1;
333 389  
  390 + if (!map->use_single_rw && map->reg_stride == 1 &&
  391 + d->irq_reg_stride == 1) {
  392 + d->status_reg_buf = kmalloc(map->format.val_bytes *
  393 + chip->num_regs, GFP_KERNEL);
  394 + if (!d->status_reg_buf)
  395 + goto err_alloc;
  396 + }
  397 +
334 398 mutex_init(&d->lock);
335 399  
336 400 for (i = 0; i < chip->num_irqs; i++)
... ... @@ -361,8 +425,15 @@
361 425 d->wake_buf[i] = d->mask_buf_def[i];
362 426 reg = chip->wake_base +
363 427 (i * map->reg_stride * d->irq_reg_stride);
364   - ret = regmap_update_bits(map, reg, d->wake_buf[i],
365   - d->wake_buf[i]);
  428 +
  429 + if (chip->wake_invert)
  430 + ret = regmap_update_bits(map, reg,
  431 + d->mask_buf_def[i],
  432 + 0);
  433 + else
  434 + ret = regmap_update_bits(map, reg,
  435 + d->mask_buf_def[i],
  436 + d->wake_buf[i]);
366 437 if (ret != 0) {
367 438 dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
368 439 reg, ret);
... ... @@ -401,6 +472,7 @@
401 472 kfree(d->mask_buf_def);
402 473 kfree(d->mask_buf);
403 474 kfree(d->status_buf);
  475 + kfree(d->status_reg_buf);
404 476 kfree(d);
405 477 return ret;
406 478 }
... ... @@ -422,6 +494,7 @@
422 494 kfree(d->wake_buf);
423 495 kfree(d->mask_buf_def);
424 496 kfree(d->mask_buf);
  497 + kfree(d->status_reg_buf);
425 498 kfree(d->status_buf);
426 499 kfree(d);
427 500 }
drivers/mfd/wm5102-tables.c
... ... @@ -96,6 +96,7 @@
96 96 .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
97 97 .ack_base = ARIZONA_AOD_IRQ1,
98 98 .wake_base = ARIZONA_WAKE_CONTROL,
  99 + .wake_invert = 1,
99 100 .num_regs = 1,
100 101 .irqs = wm5102_aod_irqs,
101 102 .num_irqs = ARRAY_SIZE(wm5102_aod_irqs),
drivers/mfd/wm5110-tables.c
... ... @@ -255,6 +255,7 @@
255 255 .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
256 256 .ack_base = ARIZONA_AOD_IRQ1,
257 257 .wake_base = ARIZONA_WAKE_CONTROL,
  258 + .wake_invert = 1,
258 259 .num_regs = 1,
259 260 .irqs = wm5110_aod_irqs,
260 261 .num_irqs = ARRAY_SIZE(wm5110_aod_irqs),
include/linux/regmap.h
... ... @@ -398,6 +398,7 @@
398 398 unsigned int wake_base;
399 399 unsigned int irq_reg_stride;
400 400 unsigned int mask_invert;
  401 + unsigned int wake_invert;
401 402 bool runtime_pm;
402 403  
403 404 int num_regs;