struct regmap_irq_chip_data {
struct mutex lock;
+ struct mutex shutdown_lock;
struct irq_chip irq_chip;
struct regmap *map;
int irq_base;
struct irq_domain *domain;
+ int shutdown;
int irq;
int wake_count;
bool handled = false;
u32 reg;
+ mutex_lock(&data->shutdown_lock);
+ if (data->shutdown) {
+ dev_err(map->dev, "IRQ %d thread calls after shutdown\n", irq);
+ goto exit;
+ }
+
if (chip->runtime_pm) {
ret = pm_runtime_get_sync(map->dev);
if (ret < 0) {
dev_err(map->dev, "IRQ thread failed to resume: %d\n",
ret);
pm_runtime_put(map->dev);
- return IRQ_NONE;
+ goto exit;
}
}
if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n",
ret);
- return IRQ_NONE;
+ goto exit;
}
for (i = 0; i < data->chip->num_regs; i++) {
break;
default:
BUG();
- return IRQ_NONE;
+ goto exit;
}
}
ret);
if (chip->runtime_pm)
pm_runtime_put(map->dev);
- return IRQ_NONE;
+ goto exit;
}
}
}
if (chip->runtime_pm)
pm_runtime_put(map->dev);
+exit:
+ mutex_unlock(&data->shutdown_lock);
if (handled)
return IRQ_HANDLED;
else
}
mutex_init(&d->lock);
+ mutex_init(&d->shutdown_lock);
for (i = 0; i < chip->num_irqs; i++)
d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
}
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
+/**
+ * regmap_shutdown_irq_chip(): Shutdown all interrupts
+ *
+ * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ */
+void regmap_shutdown_irq_chip(struct regmap_irq_chip_data *d)
+{
+ u32 reg;
+ int i, ret;
+
+ if (!d)
+ return;
+
+ mutex_lock(&d->shutdown_lock);
+ disable_irq(d->irq);
+
+ /* Mask all the interrupts by default */
+ for (i = 0; i < d->chip->num_regs; i++) {
+ if (!d->chip->mask_base)
+ continue;
+
+ reg = d->chip->mask_base +
+ (i * d->map->reg_stride * d->irq_reg_stride);
+ if (d->chip->mask_invert)
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i], ~d->mask_buf_def[i]);
+ else
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i], d->mask_buf_def[i]);
+ if (ret != 0)
+ dev_err(d->map->dev, "Failed to set masks in 0x%x: %d\n",
+ reg, ret);
+ }
+
+ d->shutdown = true;
+ mutex_unlock(&d->shutdown_lock);
+}
+EXPORT_SYMBOL_GPL(regmap_shutdown_irq_chip);
+
/**
* regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
*
int irq_base, const struct regmap_irq_chip *chip,
struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
+void regmap_shutdown_irq_chip(struct regmap_irq_chip_data *d);
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);