diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-03 09:27:15 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-04 15:53:42 -0500 |
commit | a7440eaa90cf2659920b9b28973cc1a13a2b331f (patch) | |
tree | 0a49d1e09602bff848a0cbd8482f55497eda53f4 /drivers/base/regmap | |
parent | bbae92ca49f77898277576e3377b09e1391a3271 (diff) |
regmap: irq: Use a bulk read for interrupt status where possible
If the interrupt status registers are a single block of registers and the
chip supports bulk reads then do a single bulk read rather than pay the
extra I/O cost. This restores the original behaviour which was lost when
support for register striding was added.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 329be9836716..aaf599a320b3 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -34,6 +34,7 @@ struct regmap_irq_chip_data { | |||
34 | int irq; | 34 | int irq; |
35 | int wake_count; | 35 | int wake_count; |
36 | 36 | ||
37 | void *status_reg_buf; | ||
37 | unsigned int *status_buf; | 38 | unsigned int *status_buf; |
38 | unsigned int *mask_buf; | 39 | unsigned int *mask_buf; |
39 | unsigned int *mask_buf_def; | 40 | unsigned int *mask_buf_def; |
@@ -170,18 +171,60 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
170 | } | 171 | } |
171 | } | 172 | } |
172 | 173 | ||
173 | for (i = 0; i < data->chip->num_regs; i++) { | 174 | /* |
174 | ret = regmap_read(map, chip->status_base + (i * map->reg_stride | 175 | * Read in the statuses, using a single bulk read if possible |
175 | * data->irq_reg_stride), | 176 | * in order to reduce the I/O overheads. |
176 | &data->status_buf[i]); | 177 | */ |
178 | if (!map->use_single_rw && map->reg_stride == 1 && | ||
179 | data->irq_reg_stride == 1) { | ||
180 | u8 *buf8 = data->status_reg_buf; | ||
181 | u16 *buf16 = data->status_reg_buf; | ||
182 | u32 *buf32 = data->status_reg_buf; | ||
177 | 183 | ||
184 | BUG_ON(!data->status_reg_buf); | ||
185 | |||
186 | ret = regmap_bulk_read(map, chip->status_base, | ||
187 | data->status_reg_buf, | ||
188 | chip->num_regs); | ||
178 | if (ret != 0) { | 189 | if (ret != 0) { |
179 | dev_err(map->dev, "Failed to read IRQ status: %d\n", | 190 | dev_err(map->dev, "Failed to read IRQ status: %d\n", |
180 | ret); | 191 | ret); |
181 | if (chip->runtime_pm) | ||
182 | pm_runtime_put(map->dev); | ||
183 | return IRQ_NONE; | 192 | return IRQ_NONE; |
184 | } | 193 | } |
194 | |||
195 | for (i = 0; i < data->chip->num_regs; i++) { | ||
196 | switch (map->format.val_bytes) { | ||
197 | case 1: | ||
198 | data->status_buf[i] = buf8[i]; | ||
199 | break; | ||
200 | case 2: | ||
201 | data->status_buf[i] = buf16[i]; | ||
202 | break; | ||
203 | case 4: | ||
204 | data->status_buf[i] = buf32[i]; | ||
205 | break; | ||
206 | default: | ||
207 | BUG(); | ||
208 | return IRQ_NONE; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | } else { | ||
213 | for (i = 0; i < data->chip->num_regs; i++) { | ||
214 | ret = regmap_read(map, chip->status_base + | ||
215 | (i * map->reg_stride | ||
216 | * data->irq_reg_stride), | ||
217 | &data->status_buf[i]); | ||
218 | |||
219 | if (ret != 0) { | ||
220 | dev_err(map->dev, | ||
221 | "Failed to read IRQ status: %d\n", | ||
222 | ret); | ||
223 | if (chip->runtime_pm) | ||
224 | pm_runtime_put(map->dev); | ||
225 | return IRQ_NONE; | ||
226 | } | ||
227 | } | ||
185 | } | 228 | } |
186 | 229 | ||
187 | /* | 230 | /* |
@@ -327,6 +370,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
327 | else | 370 | else |
328 | d->irq_reg_stride = 1; | 371 | d->irq_reg_stride = 1; |
329 | 372 | ||
373 | if (!map->use_single_rw && map->reg_stride == 1 && | ||
374 | d->irq_reg_stride == 1) { | ||
375 | d->status_reg_buf = kmalloc(map->format.val_bytes * | ||
376 | chip->num_regs, GFP_KERNEL); | ||
377 | if (!d->status_reg_buf) | ||
378 | goto err_alloc; | ||
379 | } | ||
380 | |||
330 | mutex_init(&d->lock); | 381 | mutex_init(&d->lock); |
331 | 382 | ||
332 | for (i = 0; i < chip->num_irqs; i++) | 383 | for (i = 0; i < chip->num_irqs; i++) |
@@ -397,6 +448,7 @@ err_alloc: | |||
397 | kfree(d->mask_buf_def); | 448 | kfree(d->mask_buf_def); |
398 | kfree(d->mask_buf); | 449 | kfree(d->mask_buf); |
399 | kfree(d->status_buf); | 450 | kfree(d->status_buf); |
451 | kfree(d->status_reg_buf); | ||
400 | kfree(d); | 452 | kfree(d); |
401 | return ret; | 453 | return ret; |
402 | } | 454 | } |
@@ -418,6 +470,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | |||
418 | kfree(d->wake_buf); | 470 | kfree(d->wake_buf); |
419 | kfree(d->mask_buf_def); | 471 | kfree(d->mask_buf_def); |
420 | kfree(d->mask_buf); | 472 | kfree(d->mask_buf); |
473 | kfree(d->status_reg_buf); | ||
421 | kfree(d->status_buf); | 474 | kfree(d->status_buf); |
422 | kfree(d); | 475 | kfree(d); |
423 | } | 476 | } |