diff options
author | Graeme Gregory <gg@slimlogic.co.uk> | 2012-05-14 09:40:43 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-05-14 12:40:05 -0400 |
commit | 022f926a2401c80ed36ebb48a1bffbac08f34d98 (patch) | |
tree | 7e39452a4312890ae6835f29ef87844467a5b2e0 /drivers/base | |
parent | 4af8be67fd9989f4e63a8d1defc1895ed0f7d341 (diff) |
regmap: add support for non contiguous status to regmap-irq
In some chips the IRQ status registers are not contiguous in the register
map but spaced at even spaces. This is an easy case to handle with minor
changes. It is assume for this purpose that the stride for status is
equal to the stride for mask/ack registers as well.
Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 54 |
1 files changed, 21 insertions, 33 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index db5305b37c9d..502cbdbab638 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -29,10 +29,11 @@ struct regmap_irq_chip_data { | |||
29 | int irq_base; | 29 | int irq_base; |
30 | struct irq_domain *domain; | 30 | struct irq_domain *domain; |
31 | 31 | ||
32 | void *status_reg_buf; | ||
33 | unsigned int *status_buf; | 32 | unsigned int *status_buf; |
34 | unsigned int *mask_buf; | 33 | unsigned int *mask_buf; |
35 | unsigned int *mask_buf_def; | 34 | unsigned int *mask_buf_def; |
35 | |||
36 | unsigned int irq_reg_stride; | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | static inline const | 39 | static inline const |
@@ -62,7 +63,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
62 | */ | 63 | */ |
63 | for (i = 0; i < d->chip->num_regs; i++) { | 64 | for (i = 0; i < d->chip->num_regs; i++) { |
64 | ret = regmap_update_bits(d->map, d->chip->mask_base + | 65 | ret = regmap_update_bits(d->map, d->chip->mask_base + |
65 | (i * map->reg_stride), | 66 | (i * map->reg_stride * |
67 | d->irq_reg_stride), | ||
66 | d->mask_buf_def[i], d->mask_buf[i]); | 68 | d->mask_buf_def[i], d->mask_buf[i]); |
67 | if (ret != 0) | 69 | if (ret != 0) |
68 | dev_err(d->map->dev, "Failed to sync masks in %x\n", | 70 | dev_err(d->map->dev, "Failed to sync masks in %x\n", |
@@ -104,18 +106,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
104 | struct regmap_irq_chip *chip = data->chip; | 106 | struct regmap_irq_chip *chip = data->chip; |
105 | struct regmap *map = data->map; | 107 | struct regmap *map = data->map; |
106 | int ret, i; | 108 | int ret, i; |
107 | u8 *buf8 = data->status_reg_buf; | ||
108 | u16 *buf16 = data->status_reg_buf; | ||
109 | u32 *buf32 = data->status_reg_buf; | ||
110 | bool handled = false; | 109 | bool handled = false; |
111 | 110 | ||
112 | ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf, | ||
113 | chip->num_regs); | ||
114 | if (ret != 0) { | ||
115 | dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); | ||
116 | return IRQ_NONE; | ||
117 | } | ||
118 | |||
119 | /* | 111 | /* |
120 | * Ignore masked IRQs and ack if we need to; we ack early so | 112 | * Ignore masked IRQs and ack if we need to; we ack early so |
121 | * there is no race between handling and acknowleding the | 113 | * there is no race between handling and acknowleding the |
@@ -124,18 +116,13 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
124 | * doing a write per register. | 116 | * doing a write per register. |
125 | */ | 117 | */ |
126 | for (i = 0; i < data->chip->num_regs; i++) { | 118 | for (i = 0; i < data->chip->num_regs; i++) { |
127 | switch (map->format.val_bytes) { | 119 | ret = regmap_read(map, chip->mask_base + (i * map->reg_stride |
128 | case 1: | 120 | * data->irq_reg_stride), |
129 | data->status_buf[i] = buf8[i]; | 121 | &data->status_buf[i]); |
130 | break; | 122 | |
131 | case 2: | 123 | if (ret != 0) { |
132 | data->status_buf[i] = buf16[i]; | 124 | dev_err(map->dev, "Failed to read IRQ status: %d\n", |
133 | break; | 125 | ret); |
134 | case 4: | ||
135 | data->status_buf[i] = buf32[i]; | ||
136 | break; | ||
137 | default: | ||
138 | BUG(); | ||
139 | return IRQ_NONE; | 126 | return IRQ_NONE; |
140 | } | 127 | } |
141 | 128 | ||
@@ -143,7 +130,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) | |||
143 | 130 | ||
144 | if (data->status_buf[i] && chip->ack_base) { | 131 | if (data->status_buf[i] && chip->ack_base) { |
145 | ret = regmap_write(map, chip->ack_base + | 132 | ret = regmap_write(map, chip->ack_base + |
146 | (i * map->reg_stride), | 133 | (i * map->reg_stride * |
134 | data->irq_reg_stride), | ||
147 | data->status_buf[i]); | 135 | data->status_buf[i]); |
148 | if (ret != 0) | 136 | if (ret != 0) |
149 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", | 137 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", |
@@ -242,11 +230,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
242 | if (!d->status_buf) | 230 | if (!d->status_buf) |
243 | goto err_alloc; | 231 | goto err_alloc; |
244 | 232 | ||
245 | d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs, | ||
246 | GFP_KERNEL); | ||
247 | if (!d->status_reg_buf) | ||
248 | goto err_alloc; | ||
249 | |||
250 | d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, | 233 | d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, |
251 | GFP_KERNEL); | 234 | GFP_KERNEL); |
252 | if (!d->mask_buf) | 235 | if (!d->mask_buf) |
@@ -260,6 +243,12 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
260 | d->map = map; | 243 | d->map = map; |
261 | d->chip = chip; | 244 | d->chip = chip; |
262 | d->irq_base = irq_base; | 245 | d->irq_base = irq_base; |
246 | |||
247 | if (chip->irq_reg_stride) | ||
248 | d->irq_reg_stride = chip->irq_reg_stride; | ||
249 | else | ||
250 | d->irq_reg_stride = 1; | ||
251 | |||
263 | mutex_init(&d->lock); | 252 | mutex_init(&d->lock); |
264 | 253 | ||
265 | for (i = 0; i < chip->num_irqs; i++) | 254 | for (i = 0; i < chip->num_irqs; i++) |
@@ -269,7 +258,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
269 | /* Mask all the interrupts by default */ | 258 | /* Mask all the interrupts by default */ |
270 | for (i = 0; i < chip->num_regs; i++) { | 259 | for (i = 0; i < chip->num_regs; i++) { |
271 | d->mask_buf[i] = d->mask_buf_def[i]; | 260 | d->mask_buf[i] = d->mask_buf_def[i]; |
272 | ret = regmap_write(map, chip->mask_base + (i * map->reg_stride), | 261 | ret = regmap_write(map, chip->mask_base + (i * map->reg_stride |
262 | * d->irq_reg_stride), | ||
273 | d->mask_buf[i]); | 263 | d->mask_buf[i]); |
274 | if (ret != 0) { | 264 | if (ret != 0) { |
275 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | 265 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", |
@@ -306,7 +296,6 @@ err_domain: | |||
306 | err_alloc: | 296 | err_alloc: |
307 | kfree(d->mask_buf_def); | 297 | kfree(d->mask_buf_def); |
308 | kfree(d->mask_buf); | 298 | kfree(d->mask_buf); |
309 | kfree(d->status_reg_buf); | ||
310 | kfree(d->status_buf); | 299 | kfree(d->status_buf); |
311 | kfree(d); | 300 | kfree(d); |
312 | return ret; | 301 | return ret; |
@@ -328,7 +317,6 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | |||
328 | /* We should unmap the domain but... */ | 317 | /* We should unmap the domain but... */ |
329 | kfree(d->mask_buf_def); | 318 | kfree(d->mask_buf_def); |
330 | kfree(d->mask_buf); | 319 | kfree(d->mask_buf); |
331 | kfree(d->status_reg_buf); | ||
332 | kfree(d->status_buf); | 320 | kfree(d->status_buf); |
333 | kfree(d); | 321 | kfree(d); |
334 | } | 322 | } |