[PATCH v2] regmap: irq: allow different device for irq chip and regmap

From: Michael Grzeschik
Date: Thu Jun 22 2017 - 07:03:35 EST


From: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx>

If the irq chip device is using the regmap of its parent device or
a syscon regmap that doesn't have an associated device at all,
allow the driver to provide its own device. That makes it possible
to reference the irq controller from other devices running on the
same regmap.

Signed-off-by: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx>
Signed-off-by: Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx>
---
v1 -> v2: Added my own missing Signed-off-by.

drivers/base/regmap/regmap-irq.c | 93 +++++++++++++++++++++++++---------------
include/linux/regmap.h | 4 ++
2 files changed, 62 insertions(+), 35 deletions(-)

diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index cd54189f2b1d4..a2525705c1ad0 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -25,6 +25,7 @@ struct regmap_irq_chip_data {
struct mutex lock;
struct irq_chip irq_chip;

+ struct device *dev;
struct regmap *map;
const struct regmap_irq_chip *chip;

@@ -63,16 +64,16 @@ static void regmap_irq_lock(struct irq_data *data)
static void regmap_irq_sync_unlock(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct device *dev = d->dev;
struct regmap *map = d->map;
int i, ret;
u32 reg;
u32 unmask_offset;

if (d->chip->runtime_pm) {
- ret = pm_runtime_get_sync(map->dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
- dev_err(map->dev, "IRQ sync failed to resume: %d\n",
- ret);
+ dev_err(dev, "IRQ sync failed to resume: %d\n", ret);
}

/*
@@ -106,8 +107,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
d->mask_buf_def[i], d->mask_buf[i]);
}
if (ret != 0)
- dev_err(d->map->dev, "Failed to sync masks in %x\n",
- reg);
+ dev_err(dev, "Failed to sync masks in %x\n", reg);

reg = d->chip->wake_base +
(i * map->reg_stride * d->irq_reg_stride);
@@ -121,8 +121,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
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",
+ dev_err(dev, "Failed to sync wakes in %x: %d\n",
reg, ret);
}

@@ -142,7 +141,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
else
ret = regmap_write(map, reg, d->mask_buf[i]);
if (ret != 0)
- dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
+ dev_err(dev, "Failed to ack 0x%x: %d\n",
reg, ret);
}
}
@@ -164,7 +163,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
}

if (d->chip->runtime_pm)
- pm_runtime_put(map->dev);
+ pm_runtime_put(dev);

/* If we've changed our wakeup count propagate it to the parent */
if (d->wake_count < 0)
@@ -263,6 +262,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
{
struct regmap_irq_chip_data *data = d;
const struct regmap_irq_chip *chip = data->chip;
+ struct device *dev = data->dev;
struct regmap *map = data->map;
int ret, i;
bool handled = false;
@@ -272,11 +272,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
chip->handle_pre_irq(chip->irq_drv_data);

if (chip->runtime_pm) {
- ret = pm_runtime_get_sync(map->dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0) {
- dev_err(map->dev, "IRQ thread failed to resume: %d\n",
- ret);
- pm_runtime_put(map->dev);
+ dev_err(dev, "IRQ thread failed to resume: %d\n", ret);
+ pm_runtime_put(dev);
goto exit;
}
}
@@ -297,8 +296,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
data->status_reg_buf,
chip->num_regs);
if (ret != 0) {
- dev_err(map->dev, "Failed to read IRQ status: %d\n",
- ret);
+ dev_err(dev, "Failed to read IRQ status: %d\n", ret);
goto exit;
}

@@ -327,11 +325,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
&data->status_buf[i]);

if (ret != 0) {
- dev_err(map->dev,
- "Failed to read IRQ status: %d\n",
+ dev_err(dev, "Failed to read IRQ status: %d\n",
ret);
if (chip->runtime_pm)
- pm_runtime_put(map->dev);
+ pm_runtime_put(dev);
goto exit;
}
}
@@ -352,7 +349,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
(i * map->reg_stride * data->irq_reg_stride);
ret = regmap_write(map, reg, data->status_buf[i]);
if (ret != 0)
- dev_err(map->dev, "Failed to ack 0x%x: %d\n",
+ dev_err(dev, "Failed to ack 0x%x: %d\n",
reg, ret);
}
}
@@ -366,7 +363,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}

if (chip->runtime_pm)
- pm_runtime_put(map->dev);
+ pm_runtime_put(data->dev);

exit:
if (chip->handle_post_irq)
@@ -398,8 +395,9 @@ static const struct irq_domain_ops regmap_domain_ops = {
};

/**
- * regmap_add_irq_chip() - Use standard regmap IRQ controller handling
+ * dev_regmap_add_irq_chip() - Use standard regmap IRQ controller handling
*
+ * @dev: Device for the irq_chip.
* @map: The regmap for the device.
* @irq: The IRQ the device uses to signal interrupts.
* @irq_flags: The IRQF_ flags to use for the primary interrupt.
@@ -413,9 +411,10 @@ static const struct irq_domain_ops regmap_domain_ops = {
* register cache. The chip driver is responsible for restoring the
* register values used by the IRQ controller over suspend and resume.
*/
-int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
- int irq_base, const struct regmap_irq_chip *chip,
- struct regmap_irq_chip_data **data)
+int dev_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
+ int irq_flags, int irq_base,
+ const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data)
{
struct regmap_irq_chip_data *d;
int i;
@@ -437,7 +436,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
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",
+ dev_warn(dev, "Failed to allocate IRQs: %d\n",
irq_base);
return irq_base;
}
@@ -484,6 +483,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name;
d->irq = irq;
+ d->dev = dev;
d->map = map;
d->chip = chip;
d->irq_base = irq_base;
@@ -532,7 +532,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
ret = regmap_update_bits(map, reg,
d->mask_buf[i], d->mask_buf[i]);
if (ret != 0) {
- dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+ dev_err(dev, "Failed to set masks in 0x%x: %d\n",
reg, ret);
goto err_alloc;
}
@@ -545,8 +545,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
(i * map->reg_stride * d->irq_reg_stride);
ret = regmap_read(map, reg, &d->status_buf[i]);
if (ret != 0) {
- dev_err(map->dev, "Failed to read IRQ status: %d\n",
- ret);
+ dev_err(dev, "Failed to read IRQ status: %d\n", ret);
goto err_alloc;
}

@@ -560,7 +559,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
ret = regmap_write(map, reg,
d->status_buf[i] & d->mask_buf[i]);
if (ret != 0) {
- dev_err(map->dev, "Failed to ack 0x%x: %d\n",
+ dev_err(dev, "Failed to ack 0x%x: %d\n",
reg, ret);
goto err_alloc;
}
@@ -583,7 +582,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
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",
+ dev_err(dev, "Failed to set masks in 0x%x: %d\n",
reg, ret);
goto err_alloc;
}
@@ -618,15 +617,15 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
}

if (irq_base)
- d->domain = irq_domain_add_legacy(map->dev->of_node,
+ d->domain = irq_domain_add_legacy(dev->of_node,
chip->num_irqs, irq_base, 0,
&regmap_domain_ops, d);
else
- d->domain = irq_domain_add_linear(map->dev->of_node,
+ d->domain = irq_domain_add_linear(dev->of_node,
chip->num_irqs,
&regmap_domain_ops, d);
if (!d->domain) {
- dev_err(map->dev, "Failed to create IRQ domain\n");
+ dev_err(dev, "Failed to create IRQ domain\n");
ret = -ENOMEM;
goto err_alloc;
}
@@ -635,8 +634,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
irq_flags | IRQF_ONESHOT,
chip->name, d);
if (ret != 0) {
- dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
- irq, chip->name, ret);
+ dev_err(dev, "Failed to request IRQ %d for %s: %d\n", irq,
+ chip->name, ret);
goto err_domain;
}

@@ -657,6 +656,30 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
kfree(d);
return ret;
}
+EXPORT_SYMBOL_GPL(dev_regmap_add_irq_chip);
+
+/**
+ * regmap_add_irq_chip(): Use standard regmap IRQ controller handling
+ *
+ * @map: The regmap for the device.
+ * @irq: The IRQ the device uses to signal interrupts
+ * @irq_flags: The IRQF_ flags to use for the primary interrupt.
+ * @chip: Configuration for the interrupt controller.
+ * @data: Runtime data structure for the controller, allocated on success
+ *
+ * Returns 0 on success or an errno on failure.
+ *
+ * In order for this to be efficient the chip really should use a
+ * register cache. The chip driver is responsible for restoring the
+ * register values used by the IRQ controller over suspend and resume.
+ */
+int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
+ int irq_base, const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data)
+{
+ return dev_regmap_add_irq_chip(map->dev, map, irq, irq_flags, irq_base,
+ chip, data);
+}
EXPORT_SYMBOL_GPL(regmap_add_irq_chip);

/**
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index e88649225a607..7cdbb0dd04497 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -950,6 +950,10 @@ struct regmap_irq_chip {

struct regmap_irq_chip_data;

+int dev_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
+ int irq_flags, int irq_base,
+ const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data);
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
int irq_base, const struct regmap_irq_chip *chip,
struct regmap_irq_chip_data **data);
--
2.11.0