Commit 3092f805 authored by Mark Brown's avatar Mark Brown Committed by Samuel Ortiz

mfd: arizona: Allow GPIO to be specified for IRQ line

If a GPIO is specified for the chip IRQ line then request it. This
improves support for systems that do not put pins into input mode when
used as interrupts.

Also use this GPIO when the primary IRQ is in edge triggered mode to
detect if we have handled pending interrupts in order to improve
robustness.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent f8a0941f
......@@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data)
static irqreturn_t arizona_irq_thread(int irq, void *data)
{
struct arizona *arizona = data;
bool poll;
unsigned int val;
int ret;
......@@ -103,6 +104,9 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
return IRQ_NONE;
}
do {
poll = false;
/* Always handle the AoD domain */
handle_nested_irq(irq_find_mapping(arizona->virq, 0));
......@@ -110,13 +114,29 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
* Check if one of the main interrupts is asserted and only
* check that domain if it is.
*/
ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val);
ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS,
&val);
if (ret == 0 && val & ARIZONA_IRQ1_STS) {
handle_nested_irq(irq_find_mapping(arizona->virq, 1));
} else if (ret != 0) {
dev_err(arizona->dev, "Failed to read main IRQ status: %d\n",
ret);
dev_err(arizona->dev,
"Failed to read main IRQ status: %d\n", ret);
}
/*
* Poll the IRQ pin status to see if we're really done
* if the interrupt controller can't do it for us.
*/
if (!arizona->pdata.irq_gpio) {
break;
} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING &&
gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
poll = true;
} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING &&
!gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
poll = true;
}
} while (poll);
pm_runtime_mark_last_busy(arizona->dev);
pm_runtime_put_autosuspend(arizona->dev);
......@@ -262,6 +282,26 @@ int arizona_irq_init(struct arizona *arizona)
}
}
/* Used to emulate edge trigger and to work around broken pinmux */
if (arizona->pdata.irq_gpio) {
if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n",
arizona->irq, arizona->pdata.irq_gpio,
gpio_to_irq(arizona->pdata.irq_gpio));
arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio);
}
ret = devm_gpio_request_one(arizona->dev,
arizona->pdata.irq_gpio,
GPIOF_IN, "arizona IRQ");
if (ret != 0) {
dev_err(arizona->dev,
"Failed to request IRQ GPIO %d:: %d\n",
arizona->pdata.irq_gpio, ret);
arizona->pdata.irq_gpio = 0;
}
}
ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
flags, "arizona", arizona);
......
......@@ -163,6 +163,9 @@ struct arizona_pdata {
/** Haptic actuator type */
unsigned int hap_act;
/** GPIO for primary IRQ (used for edge triggered emulation) */
int irq_gpio;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment