diff options
Diffstat (limited to 'drivers/base/regmap/regmap-irq.c')
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 126 |
1 files changed, 100 insertions, 26 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 5972ad958544..020ea2b9fd2f 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; |
@@ -87,6 +88,23 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
87 | if (ret != 0) | 88 | if (ret != 0) |
88 | dev_err(d->map->dev, "Failed to sync masks in %x\n", | 89 | dev_err(d->map->dev, "Failed to sync masks in %x\n", |
89 | reg); | 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 | if (d->chip->runtime_pm) | 110 | if (d->chip->runtime_pm) |
@@ -129,16 +147,15 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) | |||
129 | struct regmap *map = d->map; | 147 | struct regmap *map = d->map; |
130 | const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); | 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 | if (on) { | 150 | if (on) { |
136 | d->wake_buf[irq_data->reg_offset / map->reg_stride] | 151 | if (d->wake_buf) |
137 | &= ~irq_data->mask; | 152 | d->wake_buf[irq_data->reg_offset / map->reg_stride] |
153 | &= ~irq_data->mask; | ||
138 | d->wake_count++; | 154 | d->wake_count++; |
139 | } else { | 155 | } else { |
140 | d->wake_buf[irq_data->reg_offset / map->reg_stride] | 156 | if (d->wake_buf) |
141 | |= irq_data->mask; | 157 | d->wake_buf[irq_data->reg_offset / map->reg_stride] |
158 | |= irq_data->mask; | ||
142 | d->wake_count--; | 159 | d->wake_count--; |
143 | } | 160 | } |
144 | 161 | ||
@@ -167,30 +184,75 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
167 | if (ret < 0) { | 184 | if (ret < 0) { |
168 | dev_err(map->dev, "IRQ thread failed to resume: %d\n", | 185 | dev_err(map->dev, "IRQ thread failed to resume: %d\n", |
169 | ret); | 186 | ret); |
187 | pm_runtime_put(map->dev); | ||
170 | return IRQ_NONE; | 188 | return IRQ_NONE; |
171 | } | 189 | } |
172 | } | 190 | } |
173 | 191 | ||
174 | /* | 192 | /* |
175 | * Ignore masked IRQs and ack if we need to; we ack early so | 193 | * Read in the statuses, using a single bulk read if possible |
176 | * there is no race between handling and acknowleding the | 194 | * in order to reduce the I/O overheads. |
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. | ||
180 | */ | 195 | */ |
181 | for (i = 0; i < data->chip->num_regs; i++) { | 196 | if (!map->use_single_rw && map->reg_stride == 1 && |
182 | ret = regmap_read(map, chip->status_base + (i * map->reg_stride | 197 | data->irq_reg_stride == 1) { |
183 | * data->irq_reg_stride), | 198 | u8 *buf8 = data->status_reg_buf; |
184 | &data->status_buf[i]); | 199 | u16 *buf16 = data->status_reg_buf; |
200 | u32 *buf32 = data->status_reg_buf; | ||
185 | 201 | ||
202 | BUG_ON(!data->status_reg_buf); | ||
203 | |||
204 | ret = regmap_bulk_read(map, chip->status_base, | ||
205 | data->status_reg_buf, | ||
206 | chip->num_regs); | ||
186 | if (ret != 0) { | 207 | if (ret != 0) { |
187 | dev_err(map->dev, "Failed to read IRQ status: %d\n", | 208 | dev_err(map->dev, "Failed to read IRQ status: %d\n", |
188 | ret); | 209 | ret); |
189 | if (chip->runtime_pm) | ||
190 | pm_runtime_put(map->dev); | ||
191 | return IRQ_NONE; | 210 | return IRQ_NONE; |
192 | } | 211 | } |
193 | 212 | ||
213 | for (i = 0; i < data->chip->num_regs; i++) { | ||
214 | switch (map->format.val_bytes) { | ||
215 | case 1: | ||
216 | data->status_buf[i] = buf8[i]; | ||
217 | break; | ||
218 | case 2: | ||
219 | data->status_buf[i] = buf16[i]; | ||
220 | break; | ||
221 | case 4: | ||
222 | data->status_buf[i] = buf32[i]; | ||
223 | break; | ||
224 | default: | ||
225 | BUG(); | ||
226 | return IRQ_NONE; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | } else { | ||
231 | for (i = 0; i < data->chip->num_regs; i++) { | ||
232 | ret = regmap_read(map, chip->status_base + | ||
233 | (i * map->reg_stride | ||
234 | * data->irq_reg_stride), | ||
235 | &data->status_buf[i]); | ||
236 | |||
237 | if (ret != 0) { | ||
238 | dev_err(map->dev, | ||
239 | "Failed to read IRQ status: %d\n", | ||
240 | ret); | ||
241 | if (chip->runtime_pm) | ||
242 | pm_runtime_put(map->dev); | ||
243 | return IRQ_NONE; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Ignore masked IRQs and ack if we need to; we ack early so | ||
250 | * there is no race between handling and acknowleding the | ||
251 | * interrupt. We assume that typically few of the interrupts | ||
252 | * will fire simultaneously so don't worry about overhead from | ||
253 | * doing a write per register. | ||
254 | */ | ||
255 | for (i = 0; i < data->chip->num_regs; i++) { | ||
194 | data->status_buf[i] &= ~data->mask_buf[i]; | 256 | data->status_buf[i] &= ~data->mask_buf[i]; |
195 | 257 | ||
196 | if (data->status_buf[i] && chip->ack_base) { | 258 | if (data->status_buf[i] && chip->ack_base) { |
@@ -316,11 +378,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
316 | 378 | ||
317 | d->irq_chip = regmap_irq_chip; | 379 | d->irq_chip = regmap_irq_chip; |
318 | d->irq_chip.name = chip->name; | 380 | 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 | d->irq = irq; | 381 | d->irq = irq; |
325 | d->map = map; | 382 | d->map = map; |
326 | d->chip = chip; | 383 | d->chip = chip; |
@@ -331,6 +388,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
331 | else | 388 | else |
332 | d->irq_reg_stride = 1; | 389 | d->irq_reg_stride = 1; |
333 | 390 | ||
391 | if (!map->use_single_rw && map->reg_stride == 1 && | ||
392 | d->irq_reg_stride == 1) { | ||
393 | d->status_reg_buf = kmalloc(map->format.val_bytes * | ||
394 | chip->num_regs, GFP_KERNEL); | ||
395 | if (!d->status_reg_buf) | ||
396 | goto err_alloc; | ||
397 | } | ||
398 | |||
334 | mutex_init(&d->lock); | 399 | mutex_init(&d->lock); |
335 | 400 | ||
336 | for (i = 0; i < chip->num_irqs; i++) | 401 | for (i = 0; i < chip->num_irqs; i++) |
@@ -361,8 +426,15 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
361 | d->wake_buf[i] = d->mask_buf_def[i]; | 426 | d->wake_buf[i] = d->mask_buf_def[i]; |
362 | reg = chip->wake_base + | 427 | reg = chip->wake_base + |
363 | (i * map->reg_stride * d->irq_reg_stride); | 428 | (i * map->reg_stride * d->irq_reg_stride); |
364 | ret = regmap_update_bits(map, reg, d->wake_buf[i], | 429 | |
365 | d->wake_buf[i]); | 430 | if (chip->wake_invert) |
431 | ret = regmap_update_bits(map, reg, | ||
432 | d->mask_buf_def[i], | ||
433 | 0); | ||
434 | else | ||
435 | ret = regmap_update_bits(map, reg, | ||
436 | d->mask_buf_def[i], | ||
437 | d->wake_buf[i]); | ||
366 | if (ret != 0) { | 438 | if (ret != 0) { |
367 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | 439 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", |
368 | reg, ret); | 440 | reg, ret); |
@@ -401,6 +473,7 @@ err_alloc: | |||
401 | kfree(d->mask_buf_def); | 473 | kfree(d->mask_buf_def); |
402 | kfree(d->mask_buf); | 474 | kfree(d->mask_buf); |
403 | kfree(d->status_buf); | 475 | kfree(d->status_buf); |
476 | kfree(d->status_reg_buf); | ||
404 | kfree(d); | 477 | kfree(d); |
405 | return ret; | 478 | return ret; |
406 | } | 479 | } |
@@ -422,6 +495,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | |||
422 | kfree(d->wake_buf); | 495 | kfree(d->wake_buf); |
423 | kfree(d->mask_buf_def); | 496 | kfree(d->mask_buf_def); |
424 | kfree(d->mask_buf); | 497 | kfree(d->mask_buf); |
498 | kfree(d->status_reg_buf); | ||
425 | kfree(d->status_buf); | 499 | kfree(d->status_buf); |
426 | kfree(d); | 500 | kfree(d); |
427 | } | 501 | } |