| From 0e7659712836ca59b4735bc5cc94de38698a5e01 Mon Sep 17 00:00:00 2001 |
| From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| Date: Tue, 25 Aug 2015 12:43:48 +0100 |
| Subject: ASoC: arizona: Poll for FLL clock OK rather than use interrupts |
| |
| From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| |
| commit 0e7659712836ca59b4735bc5cc94de38698a5e01 upstream. |
| |
| The extcon driver takes the DAPM mutex from within the interrupt thread |
| in several places, which makes it possible to get into a situation where |
| the interrupt thread is blocked waiting on the DAPM mutex whilst a DAPM |
| sequence is running which is attempting to configure the FLL. In this |
| case the FLL completion can't be completed as as the IRQ handler is |
| ONE_SHOT, which cause the FLL lock to use the full time out (250mS) and |
| report that the process timed out. |
| |
| It is not really practical to make the extcon driver not take the DAPM |
| mutex from within the interrupt thread, at least not without extensive |
| modification. So this patch fixes the issue by switching the wait for |
| the FLL lock to polling. A few fast polls are done first as the FLL |
| should lock quickly for a good quality reference clock, (indeed it hits |
| on the first poll on my system) and it will poll every 20mS after that |
| until it times out. |
| |
| Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/soc/codecs/arizona.c | 47 ++++++++++++++++++--------------------------- |
| sound/soc/codecs/arizona.h | 1 |
| 2 files changed, 19 insertions(+), 29 deletions(-) |
| |
| --- a/sound/soc/codecs/arizona.c |
| +++ b/sound/soc/codecs/arizona.c |
| @@ -1756,17 +1756,6 @@ int arizona_init_dai(struct arizona_priv |
| } |
| EXPORT_SYMBOL_GPL(arizona_init_dai); |
| |
| -static irqreturn_t arizona_fll_clock_ok(int irq, void *data) |
| -{ |
| - struct arizona_fll *fll = data; |
| - |
| - arizona_fll_dbg(fll, "clock OK\n"); |
| - |
| - complete(&fll->ok); |
| - |
| - return IRQ_HANDLED; |
| -} |
| - |
| static struct { |
| unsigned int min; |
| unsigned int max; |
| @@ -2048,10 +2037,11 @@ static int arizona_is_enabled_fll(struct |
| static int arizona_enable_fll(struct arizona_fll *fll) |
| { |
| struct arizona *arizona = fll->arizona; |
| - unsigned long time_left; |
| bool use_sync = false; |
| int already_enabled = arizona_is_enabled_fll(fll); |
| struct arizona_fll_cfg cfg; |
| + int i; |
| + unsigned int val; |
| |
| if (already_enabled < 0) |
| return already_enabled; |
| @@ -2110,9 +2100,6 @@ static int arizona_enable_fll(struct ari |
| if (!already_enabled) |
| pm_runtime_get(arizona->dev); |
| |
| - /* Clear any pending completions */ |
| - try_wait_for_completion(&fll->ok); |
| - |
| regmap_update_bits_async(arizona->regmap, fll->base + 1, |
| ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); |
| if (use_sync) |
| @@ -2124,10 +2111,24 @@ static int arizona_enable_fll(struct ari |
| regmap_update_bits_async(arizona->regmap, fll->base + 1, |
| ARIZONA_FLL1_FREERUN, 0); |
| |
| - time_left = wait_for_completion_timeout(&fll->ok, |
| - msecs_to_jiffies(250)); |
| - if (time_left == 0) |
| + arizona_fll_dbg(fll, "Waiting for FLL lock...\n"); |
| + val = 0; |
| + for (i = 0; i < 15; i++) { |
| + if (i < 5) |
| + usleep_range(200, 400); |
| + else |
| + msleep(20); |
| + |
| + regmap_read(arizona->regmap, |
| + ARIZONA_INTERRUPT_RAW_STATUS_5, |
| + &val); |
| + if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1))) |
| + break; |
| + } |
| + if (i == 15) |
| arizona_fll_warn(fll, "Timed out waiting for lock\n"); |
| + else |
| + arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i); |
| |
| return 0; |
| } |
| @@ -2212,11 +2213,8 @@ EXPORT_SYMBOL_GPL(arizona_set_fll); |
| int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, |
| int ok_irq, struct arizona_fll *fll) |
| { |
| - int ret; |
| unsigned int val; |
| |
| - init_completion(&fll->ok); |
| - |
| fll->id = id; |
| fll->base = base; |
| fll->arizona = arizona; |
| @@ -2238,13 +2236,6 @@ int arizona_init_fll(struct arizona *ari |
| snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), |
| "FLL%d clock OK", id); |
| |
| - ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, |
| - arizona_fll_clock_ok, fll); |
| - if (ret != 0) { |
| - dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n", |
| - id, ret); |
| - } |
| - |
| regmap_update_bits(arizona->regmap, fll->base + 1, |
| ARIZONA_FLL1_FREERUN, 0); |
| |
| --- a/sound/soc/codecs/arizona.h |
| +++ b/sound/soc/codecs/arizona.h |
| @@ -242,7 +242,6 @@ struct arizona_fll { |
| int id; |
| unsigned int base; |
| unsigned int vco_mult; |
| - struct completion ok; |
| |
| unsigned int fout; |
| int sync_src; |