From 19b34bdc6d267723f3fc526ae775efba0ca4c39b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:34 +0000 Subject: [PATCH 01/32] ASoC: arizona: Move selection of FLL REFCLK into init In preparation for additional features on the FLL this patch moves the code selecting the REFCLK source based on the 32kHz clock into the FLL initialisation function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 28 ++++++++++++++++------------ sound/soc/codecs/arizona.h | 3 +++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ac948a671ea6..c14e7551a332 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1079,7 +1079,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, { struct arizona *arizona = fll->arizona; struct arizona_fll_cfg cfg, sync; - unsigned int reg, val; + unsigned int reg; int syncsrc; bool ena; int ret; @@ -1096,16 +1096,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ena = reg & ARIZONA_FLL1_ENA; if (Fout) { - /* Do we have a 32kHz reference? */ - regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); - switch (val & ARIZONA_CLK_32K_SRC_MASK) { - case ARIZONA_CLK_SRC_MCLK1: - case ARIZONA_CLK_SRC_MCLK2: - syncsrc = val & ARIZONA_CLK_32K_SRC_MASK; - break; - default: - syncsrc = -1; - } + syncsrc = fll->ref_src; if (source == syncsrc) syncsrc = -1; @@ -1115,7 +1106,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ret != 0) return ret; - ret = arizona_calc_fll(fll, &cfg, 32768, Fout); + ret = arizona_calc_fll(fll, &cfg, fll->ref_freq, Fout); if (ret != 0) return ret; } else { @@ -1178,6 +1169,7 @@ 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); @@ -1185,6 +1177,18 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->base = base; fll->arizona = arizona; + /* Configure default refclk to 32kHz if we have one */ + regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); + switch (val & ARIZONA_CLK_32K_SRC_MASK) { + case ARIZONA_CLK_SRC_MCLK1: + case ARIZONA_CLK_SRC_MCLK2: + fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK; + break; + default: + fll->ref_src = -1; + } + fll->ref_freq = 32768; + snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id); snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), "FLL%d clock OK", id); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 116372c91f5d..124f9f0ef1ac 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,9 @@ struct arizona_fll { unsigned int fref; unsigned int fout; + int ref_src; + unsigned int ref_freq; + char lock_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN]; }; From 9e359c645fa86daf0e3e5cc2dcbe7388f6e4d16a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:35 +0000 Subject: [PATCH 02/32] ASoC: arizona: Tidy up SYNCCLK selection and cache values This patch caches the current SYNCCLK settings in the arizona_fll struct and uses these to simplify the code which determines which source should be used for the REFCLK and SYNCCLK inputs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 101 ++++++++++++++++++------------------- sound/soc/codecs/arizona.h | 2 + 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c14e7551a332..03076efa4d9e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1078,15 +1078,39 @@ int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { struct arizona *arizona = fll->arizona; - struct arizona_fll_cfg cfg, sync; + struct arizona_fll_cfg ref, sync; unsigned int reg; - int syncsrc; bool ena; int ret; if (fll->fref == Fref && fll->fout == Fout) return 0; + if (fll->ref_src < 0 || fll->ref_src == source) { + if (Fout) { + ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (ret != 0) + return ret; + } + + fll->sync_src = -1; + fll->ref_src = source; + fll->ref_freq = Fref; + } else { + if (Fout) { + ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); + if (ret != 0) + return ret; + + ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (ret != 0) + return ret; + } + + fll->sync_src = source; + fll->sync_freq = Fref; + } + ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", @@ -1096,24 +1120,32 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ena = reg & ARIZONA_FLL1_ENA; if (Fout) { - syncsrc = fll->ref_src; + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - if (source == syncsrc) - syncsrc = -1; + arizona_apply_fll(arizona, fll->base, &ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, &sync, + fll->sync_src); - if (syncsrc >= 0) { - ret = arizona_calc_fll(fll, &sync, Fref, Fout); - if (ret != 0) - return ret; + if (!ena) + pm_runtime_get(arizona->dev); - ret = arizona_calc_fll(fll, &cfg, fll->ref_freq, Fout); - if (ret != 0) - return ret; - } else { - ret = arizona_calc_fll(fll, &cfg, Fref, Fout); - if (ret != 0) - return ret; - } + /* Clear any pending completions */ + try_wait_for_completion(&fll->ok); + + regmap_update_bits(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); + if (fll->sync_src >= 0) + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, + ARIZONA_FLL1_SYNC_ENA); + + ret = wait_for_completion_timeout(&fll->ok, + msecs_to_jiffies(250)); + if (ret == 0) + arizona_fll_warn(fll, "Timed out waiting for lock\n"); } else { regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, 0); @@ -1122,42 +1154,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ena) pm_runtime_put_autosuspend(arizona->dev); - - fll->fref = Fref; - fll->fout = Fout; - - return 0; } - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - if (syncsrc >= 0) { - arizona_apply_fll(arizona, fll->base, &cfg, syncsrc); - arizona_apply_fll(arizona, fll->base + 0x10, &sync, source); - } else { - arizona_apply_fll(arizona, fll->base, &cfg, source); - } - - if (!ena) - pm_runtime_get(arizona->dev); - - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (syncsrc >= 0) - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, - ARIZONA_FLL1_SYNC_ENA); - - ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (ret == 0) - arizona_fll_warn(fll, "Timed out waiting for lock\n"); - fll->fref = Fref; fll->fout = Fout; @@ -1176,6 +1174,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->id = id; fll->base = base; fll->arizona = arizona; + fll->sync_src = -1; /* Configure default refclk to 32kHz if we have one */ regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 124f9f0ef1ac..37766b547b9d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,8 @@ struct arizona_fll { unsigned int fref; unsigned int fout; + int sync_src; + unsigned int sync_freq; int ref_src; unsigned int ref_freq; From d122d6c974e35c940a638c26aa70bea363141d27 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:36 +0000 Subject: [PATCH 03/32] ASoC: arizona: Factor out check for enabled FLL In preparation for additional features on the FLL this patch factors out the code which checks if an FLL is currently enabled into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 03076efa4d9e..4640bccbfba2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1074,12 +1074,27 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } +static bool arizona_is_enabled_fll(struct arizona_fll *fll) +{ + struct arizona *arizona = fll->arizona; + unsigned int reg; + int ret; + + ret = regmap_read(arizona->regmap, fll->base + 1, ®); + if (ret != 0) { + arizona_fll_err(fll, "Failed to read current state: %d\n", + ret); + return ret; + } + + return reg & ARIZONA_FLL1_ENA; +} + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { struct arizona *arizona = fll->arizona; struct arizona_fll_cfg ref, sync; - unsigned int reg; bool ena; int ret; @@ -1111,13 +1126,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; } - ret = regmap_read(arizona->regmap, fll->base + 1, ®); - if (ret != 0) { - arizona_fll_err(fll, "Failed to read current state: %d\n", - ret); - return ret; - } - ena = reg & ARIZONA_FLL1_ENA; + ena = arizona_is_enabled_fll(fll); if (Fout) { regmap_update_bits(arizona->regmap, fll->base + 5, From 7604054e13897c2da3570e33a67ecb76462212d8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:37 +0000 Subject: [PATCH 04/32] ASoC: arizona: Factor out FLL disable In preparation for additional features on the FLL this patch factors out the code for disabling an FLL into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 4640bccbfba2..a8821a819adc 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1090,6 +1090,20 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } +static void arizona_disable_fll(struct arizona_fll *fll) +{ + struct arizona *arizona = fll->arizona; + bool change; + + regmap_update_bits_check(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, 0, &change); + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0); + + if (change) + pm_runtime_put_autosuspend(arizona->dev); +} + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { @@ -1156,13 +1170,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); } else { - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0); - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, 0); - - if (ena) - pm_runtime_put_autosuspend(arizona->dev); + arizona_disable_fll(fll); } fll->fref = Fref; From 357228153b4a158bdeb05f1c46ee13ef60a675a6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:38 +0000 Subject: [PATCH 05/32] ASoC: arizona: Factor out FLL enable In preparation for additional features on the FLL this patch factors out the code for enabling an FLL into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 66 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a8821a819adc..e770945fa019 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1090,6 +1090,41 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } +static void arizona_enable_fll(struct arizona_fll *fll, + struct arizona_fll_cfg *ref, + struct arizona_fll_cfg *sync) +{ + struct arizona *arizona = fll->arizona; + int ret; + + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, sync, + fll->sync_src); + + if (!arizona_is_enabled_fll(fll)) + pm_runtime_get(arizona->dev); + + /* Clear any pending completions */ + try_wait_for_completion(&fll->ok); + + regmap_update_bits(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); + if (fll->sync_src >= 0) + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, + ARIZONA_FLL1_SYNC_ENA); + + ret = wait_for_completion_timeout(&fll->ok, + msecs_to_jiffies(250)); + if (ret == 0) + arizona_fll_warn(fll, "Timed out waiting for lock\n"); +} + static void arizona_disable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; @@ -1107,9 +1142,7 @@ static void arizona_disable_fll(struct arizona_fll *fll) int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - struct arizona *arizona = fll->arizona; struct arizona_fll_cfg ref, sync; - bool ena; int ret; if (fll->fref == Fref && fll->fout == Fout) @@ -1140,35 +1173,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; } - ena = arizona_is_enabled_fll(fll); - if (Fout) { - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - arizona_apply_fll(arizona, fll->base, &ref, fll->ref_src); - if (fll->sync_src >= 0) - arizona_apply_fll(arizona, fll->base + 0x10, &sync, - fll->sync_src); - - if (!ena) - pm_runtime_get(arizona->dev); - - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->sync_src >= 0) - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, - ARIZONA_FLL1_SYNC_ENA); - - ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (ret == 0) - arizona_fll_warn(fll, "Timed out waiting for lock\n"); + arizona_enable_fll(fll, &ref, &sync); } else { arizona_disable_fll(fll); } From de1e6eedddeab2fa417c38c231d896198f903129 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:39 +0000 Subject: [PATCH 06/32] ASoC: arizona: Improve suppression of noop FLL updates Previously updates that only changes FLL source would be missed, this patch corrects this. We also ensures that both REFCLK and SYNCCLK frequency changes are considered, in preparation for future updates. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 16 ++++++++++------ sound/soc/codecs/arizona.h | 3 +-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e770945fa019..149e44f42f84 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1145,10 +1145,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (fll->fref == Fref && fll->fout == Fout) - return 0; - if (fll->ref_src < 0 || fll->ref_src == source) { + if (fll->sync_src == -1 && + fll->ref_src == source && fll->ref_freq == Fref && + fll->fout == Fout) + return 0; + if (Fout) { ret = arizona_calc_fll(fll, &ref, Fref, Fout); if (ret != 0) @@ -1159,6 +1161,10 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; } else { + if (fll->sync_src == source && + fll->sync_freq == Fref && fll->fout == Fout) + return 0; + if (Fout) { ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); if (ret != 0) @@ -1172,6 +1178,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_src = source; fll->sync_freq = Fref; } + fll->fout = Fout; if (Fout) { arizona_enable_fll(fll, &ref, &sync); @@ -1179,9 +1186,6 @@ int arizona_set_fll(struct arizona_fll *fll, int source, arizona_disable_fll(fll); } - fll->fref = Fref; - fll->fout = Fout; - return 0; } EXPORT_SYMBOL_GPL(arizona_set_fll); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 37766b547b9d..bedf12a527e5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -198,9 +198,8 @@ struct arizona_fll { unsigned int base; unsigned int vco_mult; struct completion ok; - unsigned int fref; - unsigned int fout; + unsigned int fout; int sync_src; unsigned int sync_freq; int ref_src; From ee929a9780605f21ad67a1ccb626baa41e038c1a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:40 +0000 Subject: [PATCH 07/32] ASoC: arizona: Add support for directly setting the FLL REFCLK This patch allows the REFCLK to be set directly allowing much greater flexibility in how the FLLs are configured. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 39 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 2 ++ sound/soc/codecs/wm5102.c | 6 ++++++ sound/soc/codecs/wm5102.h | 6 ++++-- sound/soc/codecs/wm5110.c | 6 ++++++ sound/soc/codecs/wm5110.h | 6 ++++-- 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 149e44f42f84..2bebfae3485f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1139,6 +1139,45 @@ static void arizona_disable_fll(struct arizona_fll *fll) pm_runtime_put_autosuspend(arizona->dev); } +int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout) +{ + struct arizona_fll_cfg ref, sync; + int ret; + + if (source < 0) + return -EINVAL; + + if (fll->ref_src == source && fll->ref_freq == Fref && + fll->fout == Fout) + return 0; + + if (Fout) { + ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (ret != 0) + return ret; + + if (fll->sync_src >= 0) { + ret = arizona_calc_fll(fll, &sync, fll->sync_freq, Fout); + if (ret != 0) + return ret; + } + } + + fll->ref_src = source; + fll->ref_freq = Fref; + fll->fout = Fout; + + if (Fout) { + arizona_enable_fll(fll, &ref, &sync); + } else { + arizona_disable_fll(fll); + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index bedf12a527e5..f2ca41f8dc83 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -211,6 +211,8 @@ struct arizona_fll { extern int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll); +extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout); extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b8d461db369f..5515d85fd82f 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1483,6 +1483,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout); case WM5102_FLL2: return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout); + case WM5102_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref, + Fout); + case WM5102_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref, + Fout); default: return -EINVAL; } diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h index d30477f3070c..adb38040f661 100644 --- a/sound/soc/codecs/wm5102.h +++ b/sound/soc/codecs/wm5102.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5102_FLL1 1 -#define WM5102_FLL2 2 +#define WM5102_FLL1 1 +#define WM5102_FLL2 2 +#define WM5102_FLL1_REFCLK 3 +#define WM5102_FLL2_REFCLK 4 #endif diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index cd17b477781d..2d9b55f57eed 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -880,6 +880,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout); case WM5110_FLL2: return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout); + case WM5110_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref, + Fout); + case WM5110_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref, + Fout); default: return -EINVAL; } diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h index 75e9351ccab0..e6c0cd4235c5 100644 --- a/sound/soc/codecs/wm5110.h +++ b/sound/soc/codecs/wm5110.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5110_FLL1 1 -#define WM5110_FLL2 2 +#define WM5110_FLL1 1 +#define WM5110_FLL2 2 +#define WM5110_FLL1_REFCLK 3 +#define WM5110_FLL2_REFCLK 4 #endif From f3f1163d19ebd5aa374e5df5372a8f932f2bd5f9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:41 +0000 Subject: [PATCH 08/32] ASoC: arizona: Add convience define for clearing SYNCCLK Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 8 ++++---- sound/soc/codecs/arizona.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 2bebfae3485f..6837863b582d 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1185,7 +1185,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, int ret; if (fll->ref_src < 0 || fll->ref_src == source) { - if (fll->sync_src == -1 && + if (fll->sync_src == ARIZONA_FLL_SRC_NONE && fll->ref_src == source && fll->ref_freq == Fref && fll->fout == Fout) return 0; @@ -1196,7 +1196,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, return ret; } - fll->sync_src = -1; + fll->sync_src = ARIZONA_FLL_SRC_NONE; fll->ref_src = source; fll->ref_freq = Fref; } else { @@ -1240,7 +1240,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->id = id; fll->base = base; fll->arizona = arizona; - fll->sync_src = -1; + fll->sync_src = ARIZONA_FLL_SRC_NONE; /* Configure default refclk to 32kHz if we have one */ regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); @@ -1250,7 +1250,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK; break; default: - fll->ref_src = -1; + fll->ref_src = ARIZONA_FLL_SRC_NONE; } fll->ref_freq = 32768; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index f2ca41f8dc83..3f84943b23bf 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -32,6 +32,7 @@ #define ARIZONA_CLK_SRC_AIF2BCLK 0x9 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa +#define ARIZONA_FLL_SRC_NONE -1 #define ARIZONA_FLL_SRC_MCLK1 0 #define ARIZONA_FLL_SRC_MCLK2 1 #define ARIZONA_FLL_SRC_SLIMCLK 3 From ddbce97cd1798ba4661e33662c659b168e9f51ed Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 15 Feb 2013 17:27:22 +0000 Subject: [PATCH 09/32] ASoC: arizona: Only allow input volume updates when inputs are enabled Since we are automatically managing the mutes we may as well also manage the volume update bits, disabling volume updates while none of the inputs are active. Since we are doing this we may as well allow the volumes to ramp together so only enable volume updates once at the end of power up. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 39 ++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/arizona.h | 3 +++ sound/soc/codecs/wm5102.c | 26 ++++++++++++------------- sound/soc/codecs/wm5110.c | 34 ++++++++++++++++----------------- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6837863b582d..debd184cc706 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -332,9 +333,27 @@ const struct soc_enum arizona_ng_hold = 4, arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); +static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int i; + + if (ena) + val = ARIZONA_IN_VU; + else + val = 0; + + for (i = 0; i < priv->num_inputs; i++) + snd_soc_update_bits(codec, + ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4), + ARIZONA_IN_VU, val); +} + int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); unsigned int reg; if (w->shift % 2) @@ -343,13 +362,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->in_pending++; + break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); + + /* If this is the last input pending then allow VU */ + priv->in_pending--; + if (priv->in_pending == 0) { + msleep(1); + arizona_in_set_vu(w->codec, 1); + } break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, - ARIZONA_IN1L_MUTE); + snd_soc_update_bits(w->codec, reg, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU); break; + case SND_SOC_DAPM_POST_PMD: + /* Disable volume updates if no inputs are enabled */ + reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES); + if (reg == 0) + arizona_in_set_vu(w->codec, 0); } return 0; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 3f84943b23bf..d592adcc969c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -65,6 +65,9 @@ struct arizona_priv { int sysclk; int asyncclk; struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; + + int num_inputs; + unsigned int in_pending; }; #define ARIZONA_NUM_MIXER_INPUTS 99 diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 5515d85fd82f..44d4c69d25e5 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -973,22 +973,28 @@ SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -1599,13 +1605,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) #define WM5102_DIG_VU 0x0200 static unsigned int wm5102_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1648,6 +1647,7 @@ static int wm5102_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5102); wm5102->core.arizona = arizona; + wm5102->core.num_inputs = 6; wm5102->core.adsp[0].part = "wm5102"; wm5102->core.adsp[0].num = 1; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2d9b55f57eed..a64d3b8bc3b4 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -993,15 +1001,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) #define WM5110_DIG_VU 0x0200 static unsigned int wm5110_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_ADC_DIGITAL_VOLUME_4L, - ARIZONA_ADC_DIGITAL_VOLUME_4R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1046,6 +1045,7 @@ static int wm5110_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5110); wm5110->core.arizona = arizona; + wm5110->core.num_inputs = 8; for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) wm5110->fll[i].vco_mult = 3; From 1c5617fc230b399c1d84711b8a2e316199387eb9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2013 17:10:37 +0000 Subject: [PATCH 10/32] ASoC: arizona: Don't enable FLL on REFCLK configuration Enabling the FLL when REFCLK is being configured is not what the user would expect and can cause issues if SYNCCLK has no specified frequency. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index debd184cc706..e456cb4b196e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1183,17 +1183,17 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (source < 0) return -EINVAL; - if (fll->ref_src == source && fll->ref_freq == Fref && - fll->fout == Fout) + if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (Fout) { - ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (fll->fout) { + ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); if (ret != 0) return ret; if (fll->sync_src >= 0) { - ret = arizona_calc_fll(fll, &sync, fll->sync_freq, Fout); + ret = arizona_calc_fll(fll, &sync, fll->sync_freq, + fll->fout); if (ret != 0) return ret; } @@ -1201,12 +1201,9 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; - fll->fout = Fout; - if (Fout) { + if (fll->fout) { arizona_enable_fll(fll, &ref, &sync); - } else { - arizona_disable_fll(fll); } return 0; From ff680a173506e0f5f15c1d9c70251e7e3208c761 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 4 Mar 2013 16:00:19 +0800 Subject: [PATCH 11/32] ASoC: arizona: If we only have a clock to synchronise with make it REFCLK If there is only one clock active the FLL should use REFCLK rather than SYNCCLK as the clock to synchronise with since REFCLK is always required. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 74 +++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e456cb4b196e..0599ff8ea935 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1132,14 +1132,30 @@ static void arizona_enable_fll(struct arizona_fll *fll, struct arizona *arizona = fll->arizona; int ret; - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + /* + * If we have both REFCLK and SYNCCLK then enable both, + * otherwise apply the SYNCCLK settings to REFCLK. + */ + if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); - if (fll->sync_src >= 0) - arizona_apply_fll(arizona, fll->base + 0x10, sync, + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, sync, + fll->sync_src); + } else if (fll->sync_src >= 0) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, sync, fll->sync_src); + } else { + arizona_fll_err(fll, "No clocks provided\n"); + return; + } if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); @@ -1149,7 +1165,8 @@ static void arizona_enable_fll(struct arizona_fll *fll, regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->sync_src >= 0) + if (fll->ref_src >= 0 && fll->sync_src >= 0 && + fll->ref_src != fll->sync_src) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); @@ -1180,9 +1197,6 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (source < 0) - return -EINVAL; - if (fll->ref_src == source && fll->ref_freq == Fref) return 0; @@ -1216,39 +1230,25 @@ int arizona_set_fll(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (fll->ref_src < 0 || fll->ref_src == source) { - if (fll->sync_src == ARIZONA_FLL_SRC_NONE && - fll->ref_src == source && fll->ref_freq == Fref && - fll->fout == Fout) - return 0; + if (fll->sync_src == source && + fll->sync_freq == Fref && fll->fout == Fout) + return 0; - if (Fout) { - ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (Fout) { + if (fll->ref_src >= 0) { + ret = arizona_calc_fll(fll, &ref, fll->ref_freq, + Fout); if (ret != 0) return ret; } - fll->sync_src = ARIZONA_FLL_SRC_NONE; - fll->ref_src = source; - fll->ref_freq = Fref; - } else { - if (fll->sync_src == source && - fll->sync_freq == Fref && fll->fout == Fout) - return 0; - - if (Fout) { - ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); - if (ret != 0) - return ret; - - ret = arizona_calc_fll(fll, &sync, Fref, Fout); - if (ret != 0) - return ret; - } - - fll->sync_src = source; - fll->sync_freq = Fref; + ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (ret != 0) + return ret; } + + fll->sync_src = source; + fll->sync_freq = Fref; fll->fout = Fout; if (Fout) { From 1fd9c467b4f7e08beee41f9771396f39265f4c08 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 11:51:55 +0800 Subject: [PATCH 12/32] mfd: arizona: Define additional FLL control registers Signed-off-by: Mark Brown --- include/linux/mfd/arizona/registers.h | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 340355136069..a61ce90ecd3f 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -85,12 +85,14 @@ #define ARIZONA_FLL1_CONTROL_6 0x176 #define ARIZONA_FLL1_LOOP_FILTER_TEST_1 0x177 #define ARIZONA_FLL1_NCO_TEST_0 0x178 +#define ARIZONA_FLL1_CONTROL_7 0x179 #define ARIZONA_FLL1_SYNCHRONISER_1 0x181 #define ARIZONA_FLL1_SYNCHRONISER_2 0x182 #define ARIZONA_FLL1_SYNCHRONISER_3 0x183 #define ARIZONA_FLL1_SYNCHRONISER_4 0x184 #define ARIZONA_FLL1_SYNCHRONISER_5 0x185 #define ARIZONA_FLL1_SYNCHRONISER_6 0x186 +#define ARIZONA_FLL1_SYNCHRONISER_7 0x187 #define ARIZONA_FLL1_SPREAD_SPECTRUM 0x189 #define ARIZONA_FLL1_GPIO_CLOCK 0x18A #define ARIZONA_FLL2_CONTROL_1 0x191 @@ -101,12 +103,14 @@ #define ARIZONA_FLL2_CONTROL_6 0x196 #define ARIZONA_FLL2_LOOP_FILTER_TEST_1 0x197 #define ARIZONA_FLL2_NCO_TEST_0 0x198 +#define ARIZONA_FLL2_CONTROL_7 0x199 #define ARIZONA_FLL2_SYNCHRONISER_1 0x1A1 #define ARIZONA_FLL2_SYNCHRONISER_2 0x1A2 #define ARIZONA_FLL2_SYNCHRONISER_3 0x1A3 #define ARIZONA_FLL2_SYNCHRONISER_4 0x1A4 #define ARIZONA_FLL2_SYNCHRONISER_5 0x1A5 #define ARIZONA_FLL2_SYNCHRONISER_6 0x1A6 +#define ARIZONA_FLL2_SYNCHRONISER_7 0x1A7 #define ARIZONA_FLL2_SPREAD_SPECTRUM 0x1A9 #define ARIZONA_FLL2_GPIO_CLOCK 0x1AA #define ARIZONA_MIC_CHARGE_PUMP_1 0x200 @@ -1677,6 +1681,13 @@ #define ARIZONA_FLL1_FRC_INTEG_VAL_SHIFT 0 /* FLL1_FRC_INTEG_VAL - [11:0] */ #define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH 12 /* FLL1_FRC_INTEG_VAL - [11:0] */ +/* + * R377 (0x179) - FLL1 Control 7 + */ +#define ARIZONA_FLL1_GAIN_MASK 0x003c /* FLL1_GAIN */ +#define ARIZONA_FLL1_GAIN_SHIFT 2 /* FLL1_GAIN */ +#define ARIZONA_FLL1_GAIN_WIDTH 4 /* FLL1_GAIN */ + /* * R385 (0x181) - FLL1 Synchroniser 1 */ @@ -1723,6 +1734,17 @@ #define ARIZONA_FLL1_CLK_SYNC_SRC_SHIFT 0 /* FLL1_CLK_SYNC_SRC - [3:0] */ #define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH 4 /* FLL1_CLK_SYNC_SRC - [3:0] */ +/* + * R391 (0x187) - FLL1 Synchroniser 7 + */ +#define ARIZONA_FLL1_SYNC_GAIN_MASK 0x003c /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_GAIN_SHIFT 2 /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_GAIN_WIDTH 4 /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_BW 0x0001 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_MASK 0x0001 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_SHIFT 0 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_WIDTH 1 /* FLL1_SYNC_BW */ + /* * R393 (0x189) - FLL1 Spread Spectrum */ @@ -1815,6 +1837,13 @@ #define ARIZONA_FLL2_FRC_INTEG_VAL_SHIFT 0 /* FLL2_FRC_INTEG_VAL - [11:0] */ #define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH 12 /* FLL2_FRC_INTEG_VAL - [11:0] */ +/* + * R409 (0x199) - FLL2 Control 7 + */ +#define ARIZONA_FLL2_GAIN_MASK 0x003c /* FLL2_GAIN */ +#define ARIZONA_FLL2_GAIN_SHIFT 2 /* FLL2_GAIN */ +#define ARIZONA_FLL2_GAIN_WIDTH 4 /* FLL2_GAIN */ + /* * R417 (0x1A1) - FLL2 Synchroniser 1 */ @@ -1861,6 +1890,17 @@ #define ARIZONA_FLL2_CLK_SYNC_SRC_SHIFT 0 /* FLL2_CLK_SYNC_SRC - [3:0] */ #define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH 4 /* FLL2_CLK_SYNC_SRC - [3:0] */ +/* + * R423 (0x1A7) - FLL2 Synchroniser 7 + */ +#define ARIZONA_FLL2_SYNC_GAIN_MASK 0x003c /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_GAIN_SHIFT 2 /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_GAIN_WIDTH 4 /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_SHIFT 0 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_WIDTH 1 /* FLL2_SYNC_BW */ + /* * R425 (0x1A9) - FLL2 Spread Spectrum */ From 9a412cdb1ab0ad984b76debfe562cb7a2c815371 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 11:53:09 +0800 Subject: [PATCH 13/32] mfd: wm5102: Map in additional FLL control registers Signed-off-by: Mark Brown --- drivers/mfd/wm5102-tables.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index a433f580aa4c..8a6ce8c12505 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ { 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ @@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ @@ -1051,12 +1055,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_CONTROL_6: case ARIZONA_FLL1_LOOP_FILTER_TEST_1: case ARIZONA_FLL1_NCO_TEST_0: + case ARIZONA_FLL1_CONTROL_7: case ARIZONA_FLL1_SYNCHRONISER_1: case ARIZONA_FLL1_SYNCHRONISER_2: case ARIZONA_FLL1_SYNCHRONISER_3: case ARIZONA_FLL1_SYNCHRONISER_4: case ARIZONA_FLL1_SYNCHRONISER_5: case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: case ARIZONA_FLL1_SPREAD_SPECTRUM: case ARIZONA_FLL1_GPIO_CLOCK: case ARIZONA_FLL2_CONTROL_1: @@ -1067,12 +1073,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_CONTROL_6: case ARIZONA_FLL2_LOOP_FILTER_TEST_1: case ARIZONA_FLL2_NCO_TEST_0: + case ARIZONA_FLL2_CONTROL_7: case ARIZONA_FLL2_SYNCHRONISER_1: case ARIZONA_FLL2_SYNCHRONISER_2: case ARIZONA_FLL2_SYNCHRONISER_3: case ARIZONA_FLL2_SYNCHRONISER_4: case ARIZONA_FLL2_SYNCHRONISER_5: case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: case ARIZONA_FLL2_SPREAD_SPECTRUM: case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: From 576411be200ee0e0801f1fe57d5e7ee787bb1a90 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 12:07:16 +0800 Subject: [PATCH 14/32] ASoC: arizona: Increase FLL synchroniser bandwidth for high frequencies If we are using a high freqency SYNCCLK then increasing the bandwidth of the synchroniser improves performance. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0599ff8ea935..e3aee143487e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1157,6 +1157,17 @@ static void arizona_enable_fll(struct arizona_fll *fll, return; } + /* + * Increase the bandwidth if we're not using a low frequency + * sync source. + */ + if (fll->sync_src >= 0 && fll->sync_freq > 100000) + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, 0); + else + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); + if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); From 8f113d7d2606003e485c4e8452977750d916dbc6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 12:08:57 +0800 Subject: [PATCH 15/32] ASoC: arizona: Optimise FLL loop gains For optimal performance the FLL loop gain should be adjusted depending on the frequency of the input clock for the loop. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 43 ++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e3aee143487e..8b7855df99de 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -990,6 +990,16 @@ static struct { { 1000000, 13500000, 0, 1 }, }; +static struct { + unsigned int min; + unsigned int max; + u16 gain; +} fll_gains[] = { + { 0, 256000, 0 }, + { 256000, 1000000, 2 }, + { 1000000, 13500000, 4 }, +}; + struct arizona_fll_cfg { int n; int theta; @@ -997,6 +1007,7 @@ struct arizona_fll_cfg { int refdiv; int outdiv; int fratio; + int gain; }; static int arizona_calc_fll(struct arizona_fll *fll, @@ -1056,6 +1067,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, return -EINVAL; } + for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { + if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { + cfg->gain = fll_gains[i].gain; + break; + } + } + if (i == ARRAY_SIZE(fll_gains)) { + arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", + Fref); + return -EINVAL; + } + cfg->n = target / (ratio * Fref); if (target % (ratio * Fref)) { @@ -1083,13 +1106,15 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); + arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain); return 0; } static void arizona_apply_fll(struct arizona *arizona, unsigned int base, - struct arizona_fll_cfg *cfg, int source) + struct arizona_fll_cfg *cfg, int source, + bool sync) { regmap_update_bits(arizona->regmap, base + 3, ARIZONA_FLL1_THETA_MASK, cfg->theta); @@ -1104,6 +1129,15 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); + if (sync) + regmap_update_bits(arizona->regmap, base + 0x7, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + else + regmap_update_bits(arizona->regmap, base + 0x9, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + regmap_update_bits(arizona->regmap, base + 2, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, ARIZONA_FLL1_CTRL_UPD | cfg->n); @@ -1141,17 +1175,18 @@ static void arizona_enable_fll(struct arizona_fll *fll, ARIZONA_FLL1_OUTDIV_MASK, ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, + false); if (fll->sync_src >= 0) arizona_apply_fll(arizona, fll->base + 0x10, sync, - fll->sync_src); + fll->sync_src, true); } else if (fll->sync_src >= 0) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, sync, - fll->sync_src); + fll->sync_src, false); } else { arizona_fll_err(fll, "No clocks provided\n"); return; From eca2e8e24a0c712c2613ce5704e9e73b693d2e98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Mar 2013 00:09:59 +0800 Subject: [PATCH 16/32] ASoC: arizona: Ensure synchroniser is disabled when not needed When live configuring a FLL configuration with no synchroniser disable the synchroniser in case the previous configuration used one. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 8b7855df99de..53ddd529769c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1187,6 +1187,9 @@ static void arizona_enable_fll(struct arizona_fll *fll, arizona_apply_fll(arizona, fll->base, sync, fll->sync_src, false); + + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0); } else { arizona_fll_err(fll, "No clocks provided\n"); return; From 86cd684fcb3220f4aa20cf9e32fd1059373a608a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 7 Mar 2013 16:14:04 +0800 Subject: [PATCH 17/32] ASoC: arizona: Suppress reference calculations when setting REFCLK to 0 Allow users to keep on specifying their output frequency when disabling the reference clock. Reported-by: Kyung Kwee Ryu Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 53ddd529769c..ad21d8255341 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1249,7 +1249,7 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (fll->fout) { + if (fll->fout && Fref > 0) { ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); if (ret != 0) return ret; @@ -1265,7 +1265,7 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; - if (fll->fout) { + if (fll->fout && Fref > 0) { arizona_enable_fll(fll, &ref, &sync); } From 3f341f741de956980775761370e3abc4122be53a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 8 Mar 2013 15:22:29 +0800 Subject: [PATCH 18/32] ASoC: arizona: Provide defines for the clock rates Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 12 ++++++------ sound/soc/codecs/arizona.h | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ad21d8255341..0c70d503fd32 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -504,27 +504,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, break; case 11289600: case 12288000: - val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 22579200: case 24576000: - val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 45158400: case 49152000: - val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 67737600: case 73728000: - val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 90316800: case 98304000: - val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 135475200: case 147456000: - val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 0: dev_dbg(arizona->dev, "%s cleared\n", name); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index d592adcc969c..572f11bc90b4 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -49,6 +49,14 @@ #define ARIZONA_MIXER_VOL_SHIFT 1 #define ARIZONA_MIXER_VOL_WIDTH 7 +#define ARIZONA_CLK_6MHZ 0 +#define ARIZONA_CLK_12MHZ 1 +#define ARIZONA_CLK_24MHZ 2 +#define ARIZONA_CLK_49MHZ 3 +#define ARIZONA_CLK_73MHZ 4 +#define ARIZONA_CLK_98MHZ 5 +#define ARIZONA_CLK_147MHZ 6 + #define ARIZONA_MAX_DAI 4 #define ARIZONA_MAX_ADSP 4 From 76bf969e6f86e5de788dd943ff2d4340bac71822 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 14:17:47 +0800 Subject: [PATCH 19/32] ASoC: arizona: Ensure we clock two channels for I2S mode I2S requires stereo clocking even for mono data. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c70d503fd32..2b0803ec8234 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -818,7 +818,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, struct arizona *arizona = priv->arizona; int base = dai->driver->base; const int *rates; - int i, ret; + int i, ret, val; int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; int bclk, lrclk, wl, frame, bclk_target; @@ -834,6 +834,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, bclk_target *= chan_limit; } + /* Force stereo for I2S mode */ + val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); + if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { + arizona_aif_dbg(dai, "Forcing stereo mode\n"); + bclk_target *= 2; + } + for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { if (rates[i] >= bclk_target && rates[i] % params_rate(params) == 0) { From 4f1b07581613bf076b0dacdd9a3fb290d3caa227 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Jan 2013 15:38:48 +0000 Subject: [PATCH 20/32] mfd: wm5102: Add additional speaker control registers Signed-off-by: Mark Brown --- drivers/mfd/wm5102-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 8a6ce8c12505..7d01069c09db 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -1169,6 +1169,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_NOISE_GATE_CONTROL: case ARIZONA_PDM_SPK1_CTRL_1: case ARIZONA_PDM_SPK1_CTRL_2: + case ARIZONA_SPK_CTRL_2: + case ARIZONA_SPK_CTRL_3: case ARIZONA_DAC_COMP_1: case ARIZONA_DAC_COMP_2: case ARIZONA_DAC_COMP_3: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index a61ce90ecd3f..a47fd358016f 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -217,6 +217,8 @@ #define ARIZONA_PDM_SPK1_CTRL_2 0x491 #define ARIZONA_PDM_SPK2_CTRL_1 0x492 #define ARIZONA_PDM_SPK2_CTRL_2 0x493 +#define ARIZONA_SPK_CTRL_2 0x4B5 +#define ARIZONA_SPK_CTRL_3 0x4B6 #define ARIZONA_DAC_COMP_1 0x4DC #define ARIZONA_DAC_COMP_2 0x4DD #define ARIZONA_DAC_COMP_3 0x4DE From 56447e1324009d7e3cec40e3cc2987843b59a00f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Jan 2013 14:45:58 +0000 Subject: [PATCH 21/32] ASoC: arizona: Factor out speaker widgets from CODEC drivers Some system designs have been identified which repurpose portions of the speaker driver circuits for other functions which will require that they not be managed using DAPM. Prepare for this by factoring out the creation of the speaker widgets into the core driver, the widgets will be replaced by dummy ones when the additional functions are enabled. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 82 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 5 +++ sound/soc/codecs/wm5102.c | 52 +----------------------- sound/soc/codecs/wm5110.c | 6 --- 4 files changed, 89 insertions(+), 56 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 2b0803ec8234..009810b8c667 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,87 @@ #define arizona_aif_dbg(_dai, fmt, ...) \ dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) +static int arizona_spk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + bool manual_ena = false; + + switch (arizona->type) { + case WM5102: + switch (arizona->rev) { + case 0: + break; + default: + manual_ena = true; + break; + } + default: + break; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!priv->spk_ena && manual_ena) { + snd_soc_write(codec, 0x4f5, 0x25a); + priv->spk_ena_pending = true; + } + break; + case SND_SOC_DAPM_POST_PMU: + if (priv->spk_ena_pending) { + msleep(75); + snd_soc_write(codec, 0x4f5, 0xda); + priv->spk_ena_pending = false; + priv->spk_ena++; + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (manual_ena) { + priv->spk_ena--; + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x25a); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (manual_ena) { + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x0da); + } + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget arizona_spkl = + SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +static const struct snd_soc_dapm_widget arizona_spkr = + SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +int arizona_init_spk(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); + if (ret != 0) + return ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1); + if (ret != 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 572f11bc90b4..9399940f700d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -76,6 +76,9 @@ struct arizona_priv { int num_inputs; unsigned int in_pending; + + unsigned int spk_ena:2; + unsigned int spk_ena_pending:1; }; #define ARIZONA_NUM_MIXER_INPUTS 99 @@ -228,6 +231,8 @@ extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); +extern int arizona_init_spk(struct snd_soc_codec *codec); + extern int arizona_init_dai(struct arizona_priv *priv, int dai); int arizona_set_output_mode(struct snd_soc_codec *codec, int output, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 44d4c69d25e5..97757bc5fd0e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -36,9 +36,6 @@ struct wm5102_priv { struct arizona_priv core; struct arizona_fll fll[2]; - - unsigned int spk_ena:2; - unsigned int spk_ena_pending:1; }; static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); @@ -817,47 +814,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), }; -static int wm5102_spk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = w->codec; - struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); - - if (arizona->rev < 1) - return 0; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (!wm5102->spk_ena) { - snd_soc_write(codec, 0x4f5, 0x25a); - wm5102->spk_ena_pending = true; - } - break; - case SND_SOC_DAPM_POST_PMU: - if (wm5102->spk_ena_pending) { - msleep(75); - snd_soc_write(codec, 0x4f5, 0xda); - wm5102->spk_ena_pending = false; - wm5102->spk_ena++; - } - break; - case SND_SOC_DAPM_PRE_PMD: - wm5102->spk_ena--; - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x25a); - break; - case SND_SOC_DAPM_POST_PMD: - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x0da); - break; - } - - return 0; -} - - ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); @@ -1141,12 +1097,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -1586,6 +1536,8 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; + arizona_init_spk(codec); + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); priv->core.arizona->dapm = &codec->dapm; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index a64d3b8bc3b4..b6329c8c19df 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -577,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), From 899817e27a58038546b53bc42eeaa4aae5a886cb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 13 Mar 2013 12:32:10 +0000 Subject: [PATCH 22/32] ASoC: arizona: Log thermal events Help with debuggability. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 009810b8c667..895ddf007de2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -122,6 +122,42 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, return 0; } +static irqreturn_t arizona_thermal_warn(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) { + dev_crit(arizona->dev, "Thermal warning\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t arizona_thermal_shutdown(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, "Thermal shutdown\n"); + } + + return IRQ_HANDLED; +} + static const struct snd_soc_dapm_widget arizona_spkl = SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, @@ -134,6 +170,8 @@ static const struct snd_soc_dapm_widget arizona_spkr = int arizona_init_spk(struct snd_soc_codec *codec) { + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; int ret; ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); @@ -144,6 +182,22 @@ int arizona_init_spk(struct snd_soc_codec *codec) if (ret != 0) return ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, + "Thermal warning", arizona_thermal_warn, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal warning IRQ: %d\n", + ret); + + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN, + "Thermal shutdown", arizona_thermal_shutdown, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal shutdown IRQ: %d\n", + ret); + return 0; } EXPORT_SYMBOL_GPL(arizona_init_spk); From f4a76e7cc6d1c402e990e2111fb94afb305fb974 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 13 Mar 2013 12:22:39 +0000 Subject: [PATCH 23/32] ASoC: arizona: Suppress speaker enable if thermal shutdown is flagged Ensure that the device state does not diverge from the state we have set in the register map in order to make the behaviour clearer. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 895ddf007de2..6c773804ffe0 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -75,6 +75,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); bool manual_ena = false; + int val; switch (arizona->type) { case WM5102: @@ -97,6 +98,16 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMU: + val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); + if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, + "Speaker not enabled due to temperature\n"); + return -EBUSY; + } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 1 << w->shift); + if (priv->spk_ena_pending) { msleep(75); snd_soc_write(codec, 0x4f5, 0xda); @@ -110,6 +121,9 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, if (!priv->spk_ena) snd_soc_write(codec, 0x4f5, 0x25a); } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 0); break; case SND_SOC_DAPM_POST_PMD: if (manual_ena) { @@ -153,18 +167,26 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) ret); } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { dev_crit(arizona->dev, "Thermal shutdown\n"); + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4L_ENA | + ARIZONA_OUT4R_ENA, 0); + if (ret != 0) + dev_crit(arizona->dev, + "Failed to disable speaker outputs: %d\n", + ret); } return IRQ_HANDLED; } static const struct snd_soc_dapm_widget arizona_spkl = - SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, + SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); static const struct snd_soc_dapm_widget arizona_spkr = - SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, + SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM, ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); From dc91428a6152b2c8428a39a27ab9b5e429848f55 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 18 Feb 2013 19:09:23 +0000 Subject: [PATCH 24/32] ASoC: arizona: Basic support for ISRC rate selection Since ASoC does not yet really have the framework features needed to support propagating sample rates through the device well yet implement basic support for the ISRCs equivalent to that we currently have for the ASRCs. The user can opt for 8kHz or 16kHz as the rate for the DSP blocks in addition to the main audio rate, these being the primary use cases. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 27 +++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 6 ++++++ sound/soc/codecs/wm5102.c | 11 ++++++++++- sound/soc/codecs/wm_adsp.c | 24 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6c773804ffe0..26e1579c36cb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -433,6 +433,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values); const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); EXPORT_SYMBOL_GPL(arizona_mixer_tlv); +const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { + "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate", +}; +EXPORT_SYMBOL_GPL(arizona_rate_text); + +const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { + 0, 1, 2, 8, +}; +EXPORT_SYMBOL_GPL(arizona_rate_val); + + +const struct soc_enum arizona_isrc_fsl[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2, + ARIZONA_ISRC1_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2, + ARIZONA_ISRC2_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2, + ARIZONA_ISRC3_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; +EXPORT_SYMBOL_GPL(arizona_isrc_fsl); + static const char *arizona_vol_ramp_text[] = { "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", "15ms/6dB", "30ms/6dB", diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9399940f700d..a754a1c0217f 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -180,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_ROUTES(name, name "L"), \ ARIZONA_MIXER_ROUTES(name, name "R") +#define ARIZONA_RATE_ENUM_SIZE 4 +extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; +extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; + +extern const struct soc_enum arizona_isrc_fsl[]; + extern const struct soc_enum arizona_in_vi_ramp; extern const struct soc_enum arizona_in_vd_ramp; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 97757bc5fd0e..a0084b1febdb 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -731,6 +731,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), + ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -1532,7 +1535,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1); + ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); if (ret != 0) return ret; @@ -1624,6 +1627,12 @@ static int wm5102_probe(struct platform_device *pdev) ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, &wm5102->fll[1]); + /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, + ARIZONA_SAMPLE_RATE_2_MASK, 0x11); + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, + ARIZONA_SAMPLE_RATE_3_MASK, 0x12); + for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++) arizona_init_dai(&wm5102->core, i); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f3f7e75f8628..3a481fd1bf9a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -31,6 +31,7 @@ #include +#include "arizona.h" #include "wm_adsp.h" #define adsp_crit(_dsp, fmt, ...) \ @@ -246,15 +247,38 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; +static const struct soc_enum wm_adsp_rate_enum[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; + const struct snd_kcontrol_new wm_adsp_fw_controls[] = { SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP1 Rate", wm_adsp_rate_enum[0]), SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP2 Rate", wm_adsp_rate_enum[1]), SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP3 Rate", wm_adsp_rate_enum[2]), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP4 Rate", wm_adsp_rate_enum[3]), }; EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); From aed9913e6fad5a7eccce2b7a3ee6daa96b575157 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 26 Mar 2013 14:47:08 +0800 Subject: [PATCH 25/32] ASoC: arizona: remove duplicated include from arizona.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 26e1579c36cb..c979ff2b4191 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include From 03409071ce2751ca124f35edebe4bcad52de22c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 12 Feb 2013 13:00:31 +0000 Subject: [PATCH 26/32] extcon: arizona: Factor out magic application We have a very similar sequence doing magic writes in several places (one of which missed an update to interlock with the CODEC driver) so factor it out into a function. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 91 +++++++++++++-------------------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index dc357a4051f6..896a923546e0 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -100,6 +100,39 @@ static const char *arizona_cable[] = { NULL, }; +static void arizona_extcon_do_magic(struct arizona_extcon_info *info, + unsigned int magic) +{ + struct arizona *arizona = info->arizona; + unsigned int val; + int ret; + + mutex_lock(&arizona->dapm->card->dapm_mutex); + + ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read output enables: %d\n", + ret); + val = 0; + } + + if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { + ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + + ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + } + + mutex_unlock(&arizona->dapm->card->dapm_mutex); +} + static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) { struct arizona *arizona = info->arizona; @@ -484,7 +517,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; int report = ARIZONA_CABLE_HEADPHONE; - unsigned int val; int ret, reading; mutex_lock(&info->lock); @@ -539,28 +571,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) dev_err(arizona->dev, "Failed to report HP/line: %d\n", ret); - mutex_lock(&arizona->dapm->card->dapm_mutex); - - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; - } - - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", - ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", - ret); - } - - mutex_unlock(&arizona->dapm->card->dapm_mutex); + arizona_extcon_do_magic(info, 0); done: if (id_gpio) @@ -606,13 +617,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) if (info->mic) arizona_stop_mic(info); - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); + arizona_extcon_do_magic(info, 0x4000); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, @@ -653,7 +658,6 @@ err: static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) { struct arizona *arizona = info->arizona; - unsigned int val; int ret; dev_dbg(arizona->dev, "Starting identification via HPDET\n"); @@ -665,30 +669,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) arizona_extcon_pulse_micbias(info); - mutex_lock(&arizona->dapm->card->dapm_mutex); - - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; - } - - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, - 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", - ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, - 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", - ret); - } - - mutex_unlock(&arizona->dapm->card->dapm_mutex); + arizona_extcon_do_magic(info, 0x4000); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, From f607e31ce3963327f749b56c65dfec2642aa623c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Feb 2013 18:36:53 +0000 Subject: [PATCH 27/32] ASoC: arizona: Fix interaction between headphone outputs and identification Running HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running. Do the ASoC side of this by storing the enable state in the core driver structure and only writing to the device if a flag indicating that the accessory detection side is in a state where it can have the headphone output stage enabled. Signed-off-by: Mark Brown --- include/linux/mfd/arizona/core.h | 3 +++ sound/soc/codecs/arizona.c | 33 ++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 3 +++ sound/soc/codecs/wm5102.c | 8 ++++---- sound/soc/codecs/wm5110.c | 8 ++++---- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index a710255528d7..cc281368dc55 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -100,6 +100,9 @@ struct arizona { struct regmap_irq_chip_data *aod_irq_chip; struct regmap_irq_chip_data *irq_chip; + bool hpdet_magic; + unsigned int hp_ena; + struct mutex clk_lock; int clk32k_ref; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ac948a671ea6..e7d34711412c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -364,6 +364,39 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(arizona_out_ev); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); + unsigned int mask = 1 << w->shift; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = mask; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 0; + break; + default: + return -EINVAL; + } + + /* Store the desired state for the HP outputs */ + priv->arizona->hp_ena &= ~mask; + priv->arizona->hp_ena |= val; + + /* Force off if HPDET magic is active */ + if (priv->arizona->hpdet_magic) + val = 0; + + snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val); + + return arizona_out_ev(w, kcontrol, event); +} +EXPORT_SYMBOL_GPL(arizona_hp_ev); + static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 116372c91f5d..13dd2916b721 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -184,6 +184,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w, extern int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b82bbf584146..2657aad3f8b1 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1131,11 +1131,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index cdeb301da1f6..7841b42a819c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -551,11 +551,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, From df8c3dbee9e6f19ddb0ae8e05cdf76eb2d3b7f00 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Feb 2013 18:38:03 +0000 Subject: [PATCH 28/32] extcon: arizona: Fix interaction between headphone outputs and identification Running HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running. For extcon instead of checking if the headphone output is enabled when doing magic application unconditionally disable the output and restore the state which ASoC wants set when undoing the magic. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 44 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 896a923546e0..b28927972128 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -104,29 +104,45 @@ static void arizona_extcon_do_magic(struct arizona_extcon_info *info, unsigned int magic) { struct arizona *arizona = info->arizona; - unsigned int val; int ret; mutex_lock(&arizona->dapm->card->dapm_mutex); - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; + arizona->hpdet_magic = magic; + + /* Keep the HP output stages disabled while doing the magic */ + if (magic) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT1L_ENA | + ARIZONA_OUT1R_ENA, 0); + if (ret != 0) + dev_warn(arizona->dev, + "Failed to disable headphone outputs: %d\n", + ret); } - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, - magic); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, - magic); + ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + + /* Restore the desired state while not doing the magic */ + if (!magic) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT1L_ENA | + ARIZONA_OUT1R_ENA, arizona->hp_ena); if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + dev_warn(arizona->dev, + "Failed to restore headphone outputs: %d\n", ret); } From 1a2c7d568f624307c5821f31e54727a4b374855c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 24 Mar 2013 22:50:23 +0000 Subject: [PATCH 29/32] ASoC: arizona: Add delay after powering up line level outputs Ensure that the outputs are fully enabled before we begin passing audio through them. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index abdd019c5b6e..389f23253831 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -579,6 +579,24 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + msleep(17); + break; + + default: + break; + } + break; + } + return 0; } EXPORT_SYMBOL_GPL(arizona_out_ev); From 658e6101d045ae0bc97d31f5d6a5ea117a86c92a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 25 Mar 2013 15:50:22 +0000 Subject: [PATCH 30/32] ASoC: wm5102: Implement OSR support Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b7a3fdceec7f..a1ff43c8b479 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -612,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const char *wm5102_osr_text[] = { + "Low power", "Normal", "High performance", +}; + +static const unsigned int wm5102_osr_val[] = { + 0x0, 0x3, 0x5, +}; + +static const struct soc_enum wm5102_hpout_osr[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, + ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, + ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, + ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), +}; + #define WM5102_NG_SRC(name, base) \ SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ @@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), +SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, + ARIZONA_OUT4_OSR_SHIFT, 1, 0), SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, ARIZONA_OUT5_OSR_SHIFT, 1, 0), @@ -790,6 +812,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), +SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), +SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]), + SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), From a96f5e9394d298689eb3b876e6619166f1a37cc4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 27 Mar 2013 10:50:53 +0000 Subject: [PATCH 31/32] ASoC: wm5102: Correctly use SOC_VALUE_ENUM for ISRC FSL controls Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index a1ff43c8b479..d1b43ebec087 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -762,8 +762,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), From b6ed61cfa24786e36164869b593d44d411a700ad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Mar 2013 18:00:24 +0000 Subject: [PATCH 32/32] ASoC: wm_adsp: Split ADSP1 and ADSP2 firmware controls Now that we have regular register mapped controls we should be splitting the control sets for ADSP1 and ADSP2 as the register maps are not identical. Do that. Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm_adsp.c | 26 +++++++++++++++++++------- sound/soc/codecs/wm_adsp.h | 3 ++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index ddc98f02ecbd..57ba315d0c84 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec) return ret; } - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); + ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2); if (ret != 0) return ret; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index d1b43ebec087..cb03cc448da6 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1572,7 +1572,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); + ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 3a481fd1bf9a..bc03baef39fa 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -247,7 +247,18 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; -static const struct soc_enum wm_adsp_rate_enum[] = { +const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { + SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], + wm_adsp_fw_get, wm_adsp_fw_put), +}; +EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); + +#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) +static const struct soc_enum wm_adsp2_rate_enum[] = { SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, ARIZONA_DSP1_RATE_SHIFT, 0xf, ARIZONA_RATE_ENUM_SIZE, @@ -266,21 +277,22 @@ static const struct soc_enum wm_adsp_rate_enum[] = { arizona_rate_text, arizona_rate_val), }; -const struct snd_kcontrol_new wm_adsp_fw_controls[] = { +const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP1 Rate", wm_adsp_rate_enum[0]), + SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP2 Rate", wm_adsp_rate_enum[1]), + SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP3 Rate", wm_adsp_rate_enum[2]), + SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP4 Rate", wm_adsp_rate_enum[3]), + SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), }; -EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); +EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); +#endif static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, int type) diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index cb8871a3ec00..9f90c9fea842 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -65,7 +65,8 @@ struct wm_adsp { .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } -extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; int wm_adsp1_init(struct wm_adsp *adsp); int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);