Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Graeme Gregory and committed by
Mark Brown
022f926a 4af8be67

+23 -33
+21 -33
drivers/base/regmap/regmap-irq.c
··· 29 29 int irq_base; 30 30 struct irq_domain *domain; 31 31 32 - void *status_reg_buf; 33 32 unsigned int *status_buf; 34 33 unsigned int *mask_buf; 35 34 unsigned int *mask_buf_def; 35 + 36 + unsigned int irq_reg_stride; 36 37 }; 37 38 38 39 static inline const ··· 63 62 */ 64 63 for (i = 0; i < d->chip->num_regs; i++) { 65 64 ret = regmap_update_bits(d->map, d->chip->mask_base + 66 - (i * map->reg_stride), 65 + (i * map->reg_stride * 66 + d->irq_reg_stride), 67 67 d->mask_buf_def[i], d->mask_buf[i]); 68 68 if (ret != 0) 69 69 dev_err(d->map->dev, "Failed to sync masks in %x\n", ··· 106 104 struct regmap_irq_chip *chip = data->chip; 107 105 struct regmap *map = data->map; 108 106 int ret, i; 109 - u8 *buf8 = data->status_reg_buf; 110 - u16 *buf16 = data->status_reg_buf; 111 - u32 *buf32 = data->status_reg_buf; 112 107 bool handled = false; 113 - 114 - ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf, 115 - chip->num_regs); 116 - if (ret != 0) { 117 - dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); 118 - return IRQ_NONE; 119 - } 120 108 121 109 /* 122 110 * Ignore masked IRQs and ack if we need to; we ack early so ··· 116 124 * doing a write per register. 117 125 */ 118 126 for (i = 0; i < data->chip->num_regs; i++) { 119 - switch (map->format.val_bytes) { 120 - case 1: 121 - data->status_buf[i] = buf8[i]; 122 - break; 123 - case 2: 124 - data->status_buf[i] = buf16[i]; 125 - break; 126 - case 4: 127 - data->status_buf[i] = buf32[i]; 128 - break; 129 - default: 130 - BUG(); 127 + ret = regmap_read(map, chip->mask_base + (i * map->reg_stride 128 + * data->irq_reg_stride), 129 + &data->status_buf[i]); 130 + 131 + if (ret != 0) { 132 + dev_err(map->dev, "Failed to read IRQ status: %d\n", 133 + ret); 131 134 return IRQ_NONE; 132 135 } 133 136 ··· 130 143 131 144 if (data->status_buf[i] && chip->ack_base) { 132 145 ret = regmap_write(map, chip->ack_base + 133 - (i * map->reg_stride), 146 + (i * map->reg_stride * 147 + data->irq_reg_stride), 134 148 data->status_buf[i]); 135 149 if (ret != 0) 136 150 dev_err(map->dev, "Failed to ack 0x%x: %d\n", ··· 230 242 if (!d->status_buf) 231 243 goto err_alloc; 232 244 233 - d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs, 234 - GFP_KERNEL); 235 - if (!d->status_reg_buf) 236 - goto err_alloc; 237 - 238 245 d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, 239 246 GFP_KERNEL); 240 247 if (!d->mask_buf) ··· 243 260 d->map = map; 244 261 d->chip = chip; 245 262 d->irq_base = irq_base; 263 + 264 + if (chip->irq_reg_stride) 265 + d->irq_reg_stride = chip->irq_reg_stride; 266 + else 267 + d->irq_reg_stride = 1; 268 + 246 269 mutex_init(&d->lock); 247 270 248 271 for (i = 0; i < chip->num_irqs; i++) ··· 258 269 /* Mask all the interrupts by default */ 259 270 for (i = 0; i < chip->num_regs; i++) { 260 271 d->mask_buf[i] = d->mask_buf_def[i]; 261 - ret = regmap_write(map, chip->mask_base + (i * map->reg_stride), 272 + ret = regmap_write(map, chip->mask_base + (i * map->reg_stride 273 + * d->irq_reg_stride), 262 274 d->mask_buf[i]); 263 275 if (ret != 0) { 264 276 dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", ··· 296 306 err_alloc: 297 307 kfree(d->mask_buf_def); 298 308 kfree(d->mask_buf); 299 - kfree(d->status_reg_buf); 300 309 kfree(d->status_buf); 301 310 kfree(d); 302 311 return ret; ··· 317 328 /* We should unmap the domain but... */ 318 329 kfree(d->mask_buf_def); 319 330 kfree(d->mask_buf); 320 - kfree(d->status_reg_buf); 321 331 kfree(d->status_buf); 322 332 kfree(d); 323 333 }
+2
include/linux/regmap.h
··· 219 219 * @status_base: Base status register address. 220 220 * @mask_base: Base mask register address. 221 221 * @ack_base: Base ack address. If zero then the chip is clear on read. 222 + * @irq_reg_stride: Stride to use for chips where registers are not contiguous. 222 223 * 223 224 * @num_regs: Number of registers in each control bank. 224 225 * @irqs: Descriptors for individual IRQs. Interrupt numbers are ··· 232 231 unsigned int status_base; 233 232 unsigned int mask_base; 234 233 unsigned int ack_base; 234 + unsigned int irq_reg_stride; 235 235 236 236 int num_regs; 237 237