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

regmap: Convert regmap_irq to use irq_domain

This gets us up to date with the recommended current kernel infrastructure
and should transparently give us device tree interrupt bindings for any
devices using the framework. If an explicit IRQ mapping is passed in then
a legacy interrupt range is created, otherwise a simple linear mapping is
used. Previously a mapping was mandatory so existing drivers should not
be affected.

A function regmap_irq_get_virq() is provided to allow drivers to map
individual IRQs which should be used in preference to the existing
regmap_irq_chip_get_base() which is only valid if a legacy IRQ range is
provided.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

+74 -27
+70 -27
drivers/base/regmap/regmap-irq.c
··· 15 15 #include <linux/regmap.h> 16 16 #include <linux/irq.h> 17 17 #include <linux/interrupt.h> 18 + #include <linux/irqdomain.h> 18 19 #include <linux/slab.h> 19 20 20 21 #include "internal.h" ··· 27 26 struct regmap_irq_chip *chip; 28 27 29 28 int irq_base; 29 + struct irq_domain *domain; 30 30 31 31 void *status_reg_buf; 32 32 unsigned int *status_buf; ··· 39 37 struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data, 40 38 int irq) 41 39 { 42 - return &data->chip->irqs[irq - data->irq_base]; 40 + return &data->chip->irqs[irq]; 43 41 } 44 42 45 43 static void regmap_irq_lock(struct irq_data *data) ··· 76 74 { 77 75 struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); 78 76 struct regmap *map = d->map; 79 - const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); 77 + const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); 80 78 81 79 d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask; 82 80 } ··· 85 83 { 86 84 struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); 87 85 struct regmap *map = d->map; 88 - const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); 86 + const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); 89 87 90 88 d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; 91 89 } ··· 155 153 for (i = 0; i < chip->num_irqs; i++) { 156 154 if (data->status_buf[chip->irqs[i].reg_offset / 157 155 map->reg_stride] & chip->irqs[i].mask) { 158 - handle_nested_irq(data->irq_base + i); 156 + handle_nested_irq(irq_find_mapping(data->domain, i)); 159 157 handled = true; 160 158 } 161 159 } ··· 165 163 else 166 164 return IRQ_NONE; 167 165 } 166 + 167 + static int regmap_irq_map(struct irq_domain *h, unsigned int virq, 168 + irq_hw_number_t hw) 169 + { 170 + struct regmap_irq_chip_data *data = h->host_data; 171 + 172 + irq_set_chip_data(virq, data); 173 + irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq); 174 + irq_set_nested_thread(virq, 1); 175 + 176 + /* ARM needs us to explicitly flag the IRQ as valid 177 + * and will set them noprobe when we do so. */ 178 + #ifdef CONFIG_ARM 179 + set_irq_flags(virq, IRQF_VALID); 180 + #else 181 + irq_set_noprobe(virq); 182 + #endif 183 + 184 + return 0; 185 + } 186 + 187 + static struct irq_domain_ops regmap_domain_ops = { 188 + .map = regmap_irq_map, 189 + .xlate = irq_domain_xlate_twocell, 190 + }; 168 191 169 192 /** 170 193 * regmap_add_irq_chip(): Use standard regmap IRQ controller handling ··· 211 184 struct regmap_irq_chip_data **data) 212 185 { 213 186 struct regmap_irq_chip_data *d; 214 - int cur_irq, i; 187 + int i; 215 188 int ret = -ENOMEM; 216 189 217 190 for (i = 0; i < chip->num_irqs; i++) { ··· 222 195 return -EINVAL; 223 196 } 224 197 225 - irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); 226 - if (irq_base < 0) { 227 - dev_warn(map->dev, "Failed to allocate IRQs: %d\n", 228 - irq_base); 229 - return irq_base; 198 + if (irq_base) { 199 + irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); 200 + if (irq_base < 0) { 201 + dev_warn(map->dev, "Failed to allocate IRQs: %d\n", 202 + irq_base); 203 + return irq_base; 204 + } 230 205 } 231 206 232 207 d = kzalloc(sizeof(*d), GFP_KERNEL); ··· 278 249 } 279 250 } 280 251 281 - /* Register them with genirq */ 282 - for (cur_irq = irq_base; 283 - cur_irq < chip->num_irqs + irq_base; 284 - cur_irq++) { 285 - irq_set_chip_data(cur_irq, d); 286 - irq_set_chip_and_handler(cur_irq, &regmap_irq_chip, 287 - handle_edge_irq); 288 - irq_set_nested_thread(cur_irq, 1); 289 - 290 - /* ARM needs us to explicitly flag the IRQ as valid 291 - * and will set them noprobe when we do so. */ 292 - #ifdef CONFIG_ARM 293 - set_irq_flags(cur_irq, IRQF_VALID); 294 - #else 295 - irq_set_noprobe(cur_irq); 296 - #endif 252 + if (irq_base) 253 + d->domain = irq_domain_add_legacy(map->dev->of_node, 254 + chip->num_irqs, irq_base, 0, 255 + &regmap_domain_ops, d); 256 + else 257 + d->domain = irq_domain_add_linear(map->dev->of_node, 258 + chip->num_irqs, 259 + &regmap_domain_ops, d); 260 + if (!d->domain) { 261 + dev_err(map->dev, "Failed to create IRQ domain\n"); 262 + ret = -ENOMEM; 263 + goto err_alloc; 297 264 } 298 265 299 266 ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags, 300 267 chip->name, d); 301 268 if (ret != 0) { 302 269 dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret); 303 - goto err_alloc; 270 + goto err_domain; 304 271 } 305 272 306 273 return 0; 307 274 275 + err_domain: 276 + /* Should really dispose of the domain but... */ 308 277 err_alloc: 309 278 kfree(d->mask_buf_def); 310 279 kfree(d->mask_buf); ··· 325 298 return; 326 299 327 300 free_irq(irq, d); 301 + /* We should unmap the domain but... */ 328 302 kfree(d->mask_buf_def); 329 303 kfree(d->mask_buf); 330 304 kfree(d->status_reg_buf); ··· 343 315 */ 344 316 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) 345 317 { 318 + WARN_ON(!data->irq_base); 346 319 return data->irq_base; 347 320 } 348 321 EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); 322 + 323 + /** 324 + * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ 325 + * 326 + * Useful for drivers to request their own IRQs. 327 + * 328 + * @data: regmap_irq controller to operate on. 329 + * @irq: index of the interrupt requested in the chip IRQs 330 + */ 331 + int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) 332 + { 333 + return irq_create_mapping(data->domain, irq); 334 + } 335 + EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
+3
drivers/mfd/Kconfig
··· 376 376 377 377 config MFD_DA9052_SPI 378 378 bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" 379 + select IRQ_DOMAIN 379 380 select REGMAP_SPI 380 381 select REGMAP_IRQ 381 382 select PMIC_DA9052 ··· 389 388 390 389 config MFD_DA9052_I2C 391 390 bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" 391 + select IRQ_DOMAIN 392 392 select REGMAP_I2C 393 393 select REGMAP_IRQ 394 394 select PMIC_DA9052 ··· 560 558 bool "Support Wolfson Microelectronics WM8994" 561 559 select MFD_CORE 562 560 select REGMAP_I2C 561 + select IRQ_DOMAIN 563 562 select REGMAP_IRQ 564 563 depends on I2C=y && GENERIC_HARDIRQS 565 564 help
+1
include/linux/regmap.h
··· 245 245 struct regmap_irq_chip_data **data); 246 246 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); 247 247 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); 248 + int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq); 248 249 249 250 #else 250 251