From 1816cb3409f1f6909e25e52effc57857803c678c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Jan 2013 16:54:18 +0900 Subject: mfd: arizona: Disable all wake sources by default Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mfd/arizona-irq.c') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 2bec5f0db3ee..846262c59049 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -192,6 +192,9 @@ int arizona_irq_init(struct arizona *arizona) return -EINVAL; } + /* Disable all wake sources by default */ + regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); + if (arizona->pdata.irq_active_high) { ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, ARIZONA_IRQ_POL, 0); -- cgit v1.2.3 From 7994c664bdf365124a920457f9c3c9c111f89bcf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 19 Mar 2013 09:51:14 +0000 Subject: mfd: arizona: Clarify error message for failed primary IRQ request regmap has a very similar looking error, help identify where the error comes from by changing the error message. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd/arizona-irq.c') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 846262c59049..0aa39e2eb008 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -264,7 +264,7 @@ int arizona_irq_init(struct arizona *arizona) flags, "arizona", arizona); if (ret != 0) { - dev_err(arizona->dev, "Failed to request IRQ %d: %d\n", + dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n", arizona->irq, ret); goto err_main_irq; } -- cgit v1.2.3 From f8a0941f1bbdbaa68441142675986501b48da8f5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Mar 2013 12:59:33 +0100 Subject: mfd: arizona: Basic support for edge triggered IRQs Allow the user to configure edge triggered IRQs, though we do not yet fully handle new interrupts occurring while an interrupt is being handled. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- arch/arm/mach-s3c64xx/mach-crag6410-module.c | 4 ++-- drivers/mfd/arizona-irq.c | 12 +++++++----- include/linux/mfd/arizona/pdata.h | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/mfd/arizona-irq.c') diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index bf3d1c09b085..40b0e75b1ecc 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -208,7 +208,7 @@ static const struct i2c_board_info wm1277_devs[] = { static struct arizona_pdata wm5102_reva_pdata = { .ldoena = S3C64XX_GPN(7), .gpio_base = CODEC_GPIO_BASE, - .irq_active_high = true, + .irq_flags = IRQF_TRIGGER_HIGH, .micd_pol_gpio = CODEC_GPIO_BASE + 4, .gpio_defaults = { [2] = 0x10000, /* AIF3TXLRCLK */ @@ -237,7 +237,7 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { static struct arizona_pdata wm5102_pdata = { .ldoena = S3C64XX_GPN(7), .gpio_base = CODEC_GPIO_BASE, - .irq_active_high = true, + .irq_flags = IRQF_TRIGGER_HIGH, .micd_pol_gpio = CODEC_GPIO_BASE + 2, .gpio_defaults = { [2] = 0x10000, /* AIF3TXLRCLK */ diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 0aa39e2eb008..aa25468d24aa 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -195,7 +195,11 @@ int arizona_irq_init(struct arizona *arizona) /* Disable all wake sources by default */ regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); - if (arizona->pdata.irq_active_high) { + if (!arizona->pdata.irq_flags) + arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; + + if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH | + IRQF_TRIGGER_RISING)) { ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, ARIZONA_IRQ_POL, 0); if (ret != 0) { @@ -203,12 +207,10 @@ int arizona_irq_init(struct arizona *arizona) ret); goto err; } - - flags |= IRQF_TRIGGER_HIGH; - } else { - flags |= IRQF_TRIGGER_LOW; } + flags |= arizona->pdata.irq_flags; + /* Allocate a virtual IRQ domain to distribute to the regmap domains */ arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, arizona); diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 455c51d22d6b..84fefede3a23 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -99,7 +99,8 @@ struct arizona_pdata { /** If a direct 32kHz clock is provided on an MCLK specify it here */ int clk32k_src; - bool irq_active_high; /** IRQ polarity */ + /** Mode for primary IRQ (defaults to active low) */ + unsigned int irq_flags; /* Base GPIO */ int gpio_base; -- cgit v1.2.3 From 3092f8050eccce8463afe771f0910634a433e24b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 24 Mar 2013 23:05:58 +0000 Subject: 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: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 66 +++++++++++++++++++++++++++++++-------- include/linux/mfd/arizona/pdata.h | 3 ++ 2 files changed, 56 insertions(+), 13 deletions(-) (limited to 'drivers/mfd/arizona-irq.c') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index aa25468d24aa..f761cc119c01 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -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,20 +104,39 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) return IRQ_NONE; } - /* Always handle the AoD domain */ - handle_nested_irq(irq_find_mapping(arizona->virq, 0)); + do { + poll = false; + + /* Always handle the AoD domain */ + handle_nested_irq(irq_find_mapping(arizona->virq, 0)); + + /* + * 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); + 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); + } - /* - * 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); - 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); - } + /* + * 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); diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index 84fefede3a23..8755dd05ab78 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h @@ -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 -- cgit v1.2.3 From 22c75fe7c772c4c47df47364d9e807dcf204d7c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 24 Mar 2013 23:16:56 +0000 Subject: mfd: arizona: Try to use interrupt flags from interrupt controller If no irq_flags are passed in platform data then query the interrupt controller for the trigger type and try to use that. This provides default operation with a wider range of hardware and will be needed for device tree support where the interrupt flags are configured on the interrupt controller. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/mfd/arizona-irq.c') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index f761cc119c01..64cd9b6dac92 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -189,6 +189,7 @@ int arizona_irq_init(struct arizona *arizona) int ret, i; const struct regmap_irq_chip *aod, *irq; bool ctrlif_error = true; + struct irq_data *irq_data; switch (arizona->type) { #ifdef CONFIG_MFD_WM5102 @@ -215,8 +216,30 @@ int arizona_irq_init(struct arizona *arizona) /* Disable all wake sources by default */ regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); - if (!arizona->pdata.irq_flags) - arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; + /* Read the flags from the interrupt controller if not specified */ + if (!arizona->pdata.irq_flags) { + irq_data = irq_get_irq_data(arizona->irq); + if (!irq_data) { + dev_err(arizona->dev, "Invalid IRQ: %d\n", + arizona->irq); + return -EINVAL; + } + + arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data); + switch (arizona->pdata.irq_flags) { + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_FALLING: + break; + + case IRQ_TYPE_NONE: + default: + /* Device default */ + arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; + break; + } + } if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_RISING)) { -- cgit v1.2.3