summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2015-09-17 15:21:25 +0300
committerLinus Walleij <linus.walleij@linaro.org>2015-10-02 14:19:31 +0300
commit1dbf7f299f90dc4b45e2322a3af843ad65e1501b (patch)
treed4fc3d07aa72ad6a9ba41e056101521bfe83e7a2
parentf881bab038c9667deab19a85d8666029cbfa6f2c (diff)
downloadlinux-1dbf7f299f90dc4b45e2322a3af843ad65e1501b.tar.xz
gpio: pl061: detail IRQ trigger handling
I couldn't follow this code flow. Make it dirt simple to figure out what is going on and get proper debug prints. Warn if we set up an IRQ without any trigger. Should make no semantic difference. Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/gpio-pl061.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 229ef653e0f8..5b1461f6aeed 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -158,24 +158,63 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
gpiois = readb(chip->base + GPIOIS);
gpioibe = readb(chip->base + GPIOIBE);
+ if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
+ (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
+ {
+ dev_err(gc->dev,
+ "trying to configure line %d for both level and edge "
+ "detection, choose one!\n",
+ offset);
+ return -EINVAL;
+ }
+
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
+
+ /* Disable edge detection */
+ gpioibe &= ~bit;
+ /* Enable level detection */
gpiois |= bit;
- if (trigger & IRQ_TYPE_LEVEL_HIGH)
+ /* Select polarity */
+ if (polarity)
gpioiev |= bit;
else
gpioiev &= ~bit;
- } else
- gpiois &= ~bit;
- if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- /* Setting this makes GPIOEV be ignored */
+ dev_dbg(gc->dev, "line %d: IRQ on %s level\n",
+ offset,
+ polarity ? "HIGH" : "LOW");
+ } else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+ /* Disable level detection */
+ gpiois &= ~bit;
+ /* Select both edges, setting this makes GPIOEV be ignored */
gpioibe |= bit;
- else {
+
+ dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset);
+ } else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
+ (trigger & IRQ_TYPE_EDGE_FALLING)) {
+ bool rising = trigger & IRQ_TYPE_EDGE_RISING;
+
+ /* Disable level detection */
+ gpiois &= ~bit;
+ /* Clear detection on both edges */
gpioibe &= ~bit;
- if (trigger & IRQ_TYPE_EDGE_RISING)
+ /* Select edge */
+ if (rising)
gpioiev |= bit;
- else if (trigger & IRQ_TYPE_EDGE_FALLING)
+ else
gpioiev &= ~bit;
+
+ dev_dbg(gc->dev, "line %d: IRQ on %s edge\n",
+ offset,
+ rising ? "RISING" : "FALLING");
+ } else {
+ /* No trigger: disable everything */
+ gpiois &= ~bit;
+ gpioibe &= ~bit;
+ gpioiev &= ~bit;
+ dev_warn(gc->dev, "no trigger selected for line %d\n",
+ offset);
}
writeb(gpiois, chip->base + GPIOIS);