if (d->chip->runtime_pm) {
ret = pm_runtime_get_sync(map->dev); if (ret < 0)
dev_err(map->dev, "IRQ sync failed to resume: %d\n",
ret);
}
if (d->clear_status) { for (i = 0; i < d->chip->num_regs; i++) {
reg = d->get_irq_reg(d, d->chip->status_base, i);
ret = regmap_read(map, reg, &val); if (ret)
dev_err(d->map->dev, "Failed to clear the interrupt status bits\n");
}
d->clear_status = false;
}
/* *Ifthere'sbeenachangeinthemaskwriteitbacktothe *hardware.Werelyontheuseoftheregmapcorecacheto *suppresspointlesswrites.
*/ for (i = 0; i < d->chip->num_regs; i++) { if (d->chip->handle_mask_sync)
d->chip->handle_mask_sync(i, d->mask_buf_def[i],
d->mask_buf[i],
d->chip->irq_drv_data);
if (d->chip->mask_base && !d->chip->handle_mask_sync) {
reg = d->get_irq_reg(d, d->chip->mask_base, i);
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i],
d->mask_buf[i]); if (ret)
dev_err(d->map->dev, "Failed to sync masks in %x\n", reg);
}
if (d->chip->unmask_base && !d->chip->handle_mask_sync) {
reg = d->get_irq_reg(d, d->chip->unmask_base, i);
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i], ~d->mask_buf[i]); if (ret)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
reg);
}
reg = d->get_irq_reg(d, d->chip->wake_base, i); if (d->wake_buf) { if (d->chip->wake_invert)
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i],
~d->wake_buf[i]); else
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i],
d->wake_buf[i]); if (ret != 0)
dev_err(d->map->dev, "Failed to sync wakes in %x: %d\n",
reg, ret);
}
if (!d->chip->init_ack_masked) continue; /* *Ackallthemaskedinterruptsunconditionally, *ORifthereismaskedinterruptwhichhasn'tbeenAcked, *it'llbeignoredinirqhandler,thenmayintroduceirqstorm
*/ if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
reg = d->get_irq_reg(d, d->chip->ack_base, i);
/* some chips ack by write 0 */ if (d->chip->ack_invert)
ret = regmap_write(map, reg, ~d->mask_buf[i]); else
ret = regmap_write(map, reg, d->mask_buf[i]); if (d->chip->clear_ack) { if (d->chip->ack_invert && !ret)
ret = regmap_write(map, reg, UINT_MAX); elseif (!ret)
ret = regmap_write(map, reg, 0);
} if (ret != 0)
dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
reg, ret);
}
}
for (i = 0; i < d->chip->num_config_bases; i++) { for (j = 0; j < d->chip->num_config_regs; j++) {
reg = d->get_irq_reg(d, d->chip->config_base[i], j);
ret = regmap_write(map, reg, d->config_buf[i][j]); if (ret)
dev_err(d->map->dev, "Failed to write config %x: %d\n",
reg, ret);
}
}
if (d->chip->runtime_pm)
pm_runtime_put(map->dev);
/* If we've changed our wakeup count propagate it to the parent */ if (d->wake_count < 0) for (i = d->wake_count; i < 0; i++)
disable_irq_wake(d->irq); elseif (d->wake_count > 0) for (i = 0; i < d->wake_count; i++)
enable_irq_wake(d->irq);
if (chip->no_status) { /* no status register so default to all active */
memset32(data->status_buf, GENMASK(31, 0), chip->num_regs);
} elseif (chip->num_main_regs) { unsignedint max_main_bits;
max_main_bits = (chip->num_main_status_bits) ?
chip->num_main_status_bits : chip->num_regs; /* Clear the status buf as we don't read all status regs */
memset32(data->status_buf, 0, chip->num_regs);
/* We could support bulk read for main status registers *butIdon'texpecttoseedeviceswithreallymanymain *statusregisterssolet'sonlysupportsinglereadsforthe *sakeofsimplicity.andaddbulkreadsonlyifneeded
*/ for (i = 0; i < chip->num_main_regs; i++) {
reg = data->get_irq_reg(data, chip->main_status, i);
ret = regmap_read(map, reg, &data->main_status_buf[i]); if (ret) {
dev_err(map->dev, "Failed to read IRQ status %d\n", ret); return ret;
}
}
/* Read sub registers with active IRQs */ for (i = 0; i < chip->num_main_regs; i++) { unsignedint b; constunsignedlong mreg = data->main_status_buf[i];
for_each_set_bit(b, &mreg, map->format.val_bytes * 8) { if (i * map->format.val_bytes * 8 + b >
max_main_bits) break;
ret = read_sub_irq_data(data, b);
if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status %d\n", ret); return ret;
}
}
d->domain = irq_domain_instantiate(&info); if (IS_ERR(d->domain)) {
dev_err(d->map->dev, "Failed to create IRQ domain\n"); return PTR_ERR(d->domain);
}
return0;
}
/** *regmap_add_irq_chip_fwnode()-UsestandardregmapIRQcontrollerhandling * *@fwnode:ThefirmwarenodewheretheIRQdomainshouldbeaddedto. *@map:Theregmapforthedevice. *@irq:TheIRQthedeviceusestosignalinterrupts. *@irq_flags:TheIRQF_flagstousefortheprimaryinterrupt. *@irq_base:AllocateatspecificIRQnumberifirq_base>0. *@chip:Configurationfortheinterruptcontroller. *@data:Runtimedatastructureforthecontroller,allocatedonsuccess. * *Returns0onsuccessoranerrnoonfailure. * *Inorderforthistobeefficientthechipreallyshouldusea *registercache.Thechipdriverisresponsibleforrestoringthe *registervaluesusedbytheIRQcontrolleroversuspendandresume.
*/ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, struct regmap *map, int irq, int irq_flags, int irq_base, conststruct regmap_irq_chip *chip, struct regmap_irq_chip_data **data)
{ struct regmap_irq_chip_data *d; int i; int ret = -ENOMEM;
u32 reg;
if (chip->num_regs <= 0) return -EINVAL;
if (chip->clear_on_unmask && (chip->ack_base || chip->use_ack)) return -EINVAL;
if (chip->mask_base && chip->unmask_base && !chip->mask_unmask_non_inverted) return -EINVAL;
for (i = 0; i < chip->num_irqs; i++) { if (chip->irqs[i].reg_offset % map->reg_stride) return -EINVAL; if (chip->irqs[i].reg_offset / map->reg_stride >=
chip->num_regs) return -EINVAL;
}
if (irq_base) {
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); if (irq_base < 0) {
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
irq_base); return irq_base;
}
}
d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM;
if (chip->num_main_regs) {
d->main_status_buf = kcalloc(chip->num_main_regs, sizeof(*d->main_status_buf),
GFP_KERNEL);
if (!d->main_status_buf) goto err_alloc;
}
d->status_buf = kcalloc(chip->num_regs, sizeof(*d->status_buf),
GFP_KERNEL); if (!d->status_buf) goto err_alloc;
if (chip->status_is_level) {
d->prev_status_buf = kcalloc(chip->num_regs, sizeof(*d->prev_status_buf),
GFP_KERNEL); if (!d->prev_status_buf) goto err_alloc;
}
d->mask_buf = kcalloc(chip->num_regs, sizeof(*d->mask_buf),
GFP_KERNEL); if (!d->mask_buf) goto err_alloc;
d->mask_buf_def = kcalloc(chip->num_regs, sizeof(*d->mask_buf_def),
GFP_KERNEL); if (!d->mask_buf_def) goto err_alloc;
if (chip->wake_base) {
d->wake_buf = kcalloc(chip->num_regs, sizeof(*d->wake_buf),
GFP_KERNEL); if (!d->wake_buf) goto err_alloc;
}
if (chip->type_in_mask) {
d->type_buf_def = kcalloc(chip->num_regs, sizeof(*d->type_buf_def), GFP_KERNEL); if (!d->type_buf_def) goto err_alloc;
d->type_buf = kcalloc(chip->num_regs, sizeof(*d->type_buf), GFP_KERNEL); if (!d->type_buf) goto err_alloc;
}
if (chip->num_config_bases && chip->num_config_regs) { /* *Createconfig_buf[num_config_bases][num_config_regs]
*/
d->config_buf = kcalloc(chip->num_config_bases, sizeof(*d->config_buf), GFP_KERNEL); if (!d->config_buf) goto err_alloc;
for (i = 0; i < chip->num_config_bases; i++) {
d->config_buf[i] = kcalloc(chip->num_config_regs, sizeof(**d->config_buf),
GFP_KERNEL); if (!d->config_buf[i]) goto err_alloc;
}
}
for (i = 0; i < chip->num_irqs; i++)
d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
|= chip->irqs[i].mask;
/* Mask all the interrupts by default */ for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
if (chip->handle_mask_sync) {
ret = chip->handle_mask_sync(i, d->mask_buf_def[i],
d->mask_buf[i],
chip->irq_drv_data); if (ret) goto err_mutex;
}
if (chip->mask_base && !chip->handle_mask_sync) {
reg = d->get_irq_reg(d, chip->mask_base, i);
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i],
d->mask_buf[i]); if (ret) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
reg, ret); goto err_mutex;
}
}
if (chip->unmask_base && !chip->handle_mask_sync) {
reg = d->get_irq_reg(d, chip->unmask_base, i);
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i], ~d->mask_buf[i]); if (ret) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
reg, ret); goto err_mutex;
}
}
if (!chip->init_ack_masked) continue;
/* Ack masked but set interrupts */ if (d->chip->no_status) { /* no status register so default to all active */
d->status_buf[i] = UINT_MAX;
} else {
reg = d->get_irq_reg(d, d->chip->status_base, i);
ret = regmap_read(map, reg, &d->status_buf[i]); if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n",
ret); goto err_mutex;
}
}
if (chip->status_invert)
d->status_buf[i] = ~d->status_buf[i];
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
reg = d->get_irq_reg(d, d->chip->ack_base, i); if (chip->ack_invert)
ret = regmap_write(map, reg,
~(d->status_buf[i] & d->mask_buf[i])); else
ret = regmap_write(map, reg,
d->status_buf[i] & d->mask_buf[i]); if (chip->clear_ack) { if (chip->ack_invert && !ret)
ret = regmap_write(map, reg, UINT_MAX); elseif (!ret)
ret = regmap_write(map, reg, 0);
} if (ret != 0) {
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
reg, ret); goto err_mutex;
}
}
}
/* Wake is disabled by default */ if (d->wake_buf) { for (i = 0; i < chip->num_regs; i++) {
d->wake_buf[i] = d->mask_buf_def[i];
reg = d->get_irq_reg(d, d->chip->wake_base, i);
if (chip->wake_invert)
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i], 0); else
ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i],
d->wake_buf[i]); if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
reg, ret); goto err_mutex;
}
}
}
/* Store current levels */ if (chip->status_is_level) {
ret = read_irq_data(d); if (ret < 0) goto err_mutex;
/** *regmap_del_irq_chip()-StopinterrupthandlingforaregmapIRQchip * *@irq:PrimaryIRQforthedevice *@d:®map_irq_chip_dataallocatedbyregmap_add_irq_chip() * *ThisfunctionalsodisposesofallmappedIRQsonthechip.
*/ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
{ unsignedint virq; int i, hwirq;
if (!d) return;
free_irq(irq, d);
/* Dispose all virtual irq from irq domain before removing it */ for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) { /* Ignore hwirq if holes in the IRQ list */ if (!d->chip->irqs[hwirq].mask) continue;
/** *regmap_irq_get_virq()-MapaninterruptonachiptoavirtualIRQ * *@data:regmapirqcontrollertooperateon. *@irq:indexoftheinterruptrequestedinthechipIRQs. * *UsefulfordriverstorequesttheirownIRQs.
*/ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
{ /* Handle holes in the IRQ list */ if (!data->chip->irqs[irq].mask) return -EINVAL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.