aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorGraeme Gregory <gg@slimlogic.co.uk>2012-05-14 09:40:43 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-05-14 12:40:05 -0400
commit022f926a2401c80ed36ebb48a1bffbac08f34d98 (patch)
tree7e39452a4312890ae6835f29ef87844467a5b2e0 /drivers/base
parent4af8be67fd9989f4e63a8d1defc1895ed0f7d341 (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.c54
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
38static inline const 39static 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:
306err_alloc: 296err_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}