From 778a76e2dbdb896d005849e9e74518d6aba85671 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Mar 2010 22:05:10 +0000 Subject: ASoC: Implement WM8994 DAI tristate support This also adds the first DAI operation for AIF3 so fill out the ID and the ops for that too. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 29f3771c33a4..d01d3091fe81 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3332,6 +3332,36 @@ static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int reg, val, mask; + + switch (codec_dai->id) { + case 1: + reg = WM8994_AIF1_MASTER_SLAVE; + mask = WM8994_AIF1_TRI; + break; + case 2: + reg = WM8994_AIF2_MASTER_SLAVE; + mask = WM8994_AIF2_TRI; + break; + case 3: + reg = WM8994_POWER_MANAGEMENT_6; + mask = WM8994_AIF3_TRI; + break; + default: + return -EINVAL; + } + + if (tristate) + val = mask; + else + val = 0; + + return snd_soc_update_bits(codec, reg, mask, reg); +} + #define WM8994_RATES SNDRV_PCM_RATE_8000_96000 #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ @@ -3343,6 +3373,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { .hw_params = wm8994_hw_params, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, + .set_tristate = wm8994_set_tristate, }; static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { @@ -3351,6 +3382,11 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { .hw_params = wm8994_hw_params, .digital_mute = wm8994_aif_mute, .set_pll = wm8994_set_fll, + .set_tristate = wm8994_set_tristate, +}; + +static struct snd_soc_dai_ops wm8994_aif3_dai_ops = { + .set_tristate = wm8994_set_tristate, }; struct snd_soc_dai wm8994_dai[] = { @@ -3394,6 +3430,7 @@ struct snd_soc_dai wm8994_dai[] = { }, { .name = "WM8994 AIF3", + .id = 3, .playback = { .stream_name = "AIF3 Playback", .channels_min = 2, @@ -3408,6 +3445,7 @@ struct snd_soc_dai wm8994_dai[] = { .rates = WM8994_RATES, .formats = WM8994_FORMATS, }, + .ops = &wm8994_aif3_dai_ops, } }; EXPORT_SYMBOL_GPL(wm8994_dai); -- cgit v1.2.3 From 8876698406147986a9a7748586a54c4b14514c0e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Mar 2010 20:57:12 +0100 Subject: ASoC: Implement interrupt based WM8994 microphone detection Support interrupt based microphone bias detection. The WM8994 has two microphone bias supplies, with detection supported on both. Detection using GPIOs together with the standard GPIO based jack framework is already supported via the platform data for the WM8994 core driver. Note that as well as the microphone bias itself the system clock and whichever AIF clock is supplying the system clock will need to be enabled for detection to function. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 137 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bdda0936a404..fc3dce814924 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -61,6 +61,12 @@ static int wm8994_retune_mobile_base[] = { #define WM8994_REG_CACHE_SIZE 0x621 +struct wm8994_micdet { + struct snd_soc_jack *jack; + int det; + int shrt; +}; + /* codec private data */ struct wm8994_priv { struct wm_hubs_data hubs; @@ -86,6 +92,8 @@ struct wm8994_priv { int retune_mobile_cfg[WM8994_NUM_EQ]; struct soc_enum retune_mobile_enum; + struct wm8994_micdet micdet[2]; + struct wm8994_pdata *pdata; }; @@ -3702,6 +3710,96 @@ struct snd_soc_codec_device soc_codec_dev_wm8994 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); +/** + * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ + * + * @codec: WM8994 codec + * @jack: jack to report detection events on + * @micbias: microphone bias to detect on + * @det: value to report for presence detection + * @shrt: value to report for short detection + * + * Enable microphone detection via IRQ on the WM8994. If GPIOs are + * being used to bring out signals to the processor then only platform + * data configuration is needed for WM8903 and processor GPIOs should + * be configured using snd_soc_jack_add_gpios() instead. + * + * Configuration of detection levels is available via the micbias1_lvl + * and micbias2_lvl platform data members. + */ +int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, + int micbias, int det, int shrt) +{ + struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_micdet *micdet; + int reg; + + switch (micbias) { + case 1: + micdet = &wm8994->micdet[0]; + break; + case 2: + micdet = &wm8994->micdet[1]; + break; + default: + return -EINVAL; + } + + dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n", + micbias, det, shrt); + + /* Store the configuration */ + micdet->jack = jack; + micdet->det = det; + micdet->shrt = shrt; + + /* If either of the jacks is set up then enable detection */ + if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) + reg = WM8994_MICD_ENA; + else + reg = 0; + + snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); + + return 0; +} +EXPORT_SYMBOL_GPL(wm8994_mic_detect); + +static irqreturn_t wm8994_mic_irq(int irq, void *data) +{ + struct wm8994_priv *priv = data; + struct snd_soc_codec *codec = &priv->codec; + int reg; + int report; + + reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2); + if (reg < 0) { + dev_err(codec->dev, "Failed to read microphone status: %d\n", + reg); + return IRQ_HANDLED; + } + + dev_dbg(codec->dev, "Microphone status: %x\n", reg); + + report = 0; + if (reg & WM8994_MIC1_DET_STS) + report |= priv->micdet[0].det; + if (reg & WM8994_MIC1_SHRT_STS) + report |= priv->micdet[0].shrt; + snd_soc_jack_report(priv->micdet[0].jack, report, + priv->micdet[0].det | priv->micdet[0].shrt); + + report = 0; + if (reg & WM8994_MIC2_DET_STS) + report |= priv->micdet[1].det; + if (reg & WM8994_MIC2_SHRT_STS) + report |= priv->micdet[1].shrt; + snd_soc_jack_report(priv->micdet[1].jack, report, + priv->micdet[1].det | priv->micdet[1].shrt); + + return IRQ_HANDLED; +} + static int wm8994_codec_probe(struct platform_device *pdev) { int ret; @@ -3774,6 +3872,30 @@ static int wm8994_codec_probe(struct platform_device *pdev) } + ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET, + wm8994_mic_irq, "Mic 1 detect", wm8994); + if (ret != 0) + dev_warn(&pdev->dev, + "Failed to request Mic1 detect IRQ: %d\n", ret); + + ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, + wm8994_mic_irq, "Mic 1 short", wm8994); + if (ret != 0) + dev_warn(&pdev->dev, + "Failed to request Mic1 short IRQ: %d\n", ret); + + ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET, + wm8994_mic_irq, "Mic 2 detect", wm8994); + if (ret != 0) + dev_warn(&pdev->dev, + "Failed to request Mic2 detect IRQ: %d\n", ret); + + ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, + wm8994_mic_irq, "Mic 2 short", wm8994); + if (ret != 0) + dev_warn(&pdev->dev, + "Failed to request Mic2 short IRQ: %d\n", ret); + /* Remember if AIFnLRCLK is configured as a GPIO. This should be * configured on init - if a system wants to do this dynamically * at runtime we can deal with that then. @@ -3781,7 +3903,7 @@ static int wm8994_codec_probe(struct platform_device *pdev) ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1); if (ret < 0) { dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret); - goto err; + goto err_irq; } if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { wm8994->lrclk_shared[0] = 1; @@ -3793,7 +3915,7 @@ static int wm8994_codec_probe(struct platform_device *pdev) ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6); if (ret < 0) { dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret); - goto err; + goto err_irq; } if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) { wm8994->lrclk_shared[1] = 1; @@ -3843,7 +3965,7 @@ static int wm8994_codec_probe(struct platform_device *pdev) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - goto err; + goto err_irq; } ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); @@ -3858,6 +3980,11 @@ static int wm8994_codec_probe(struct platform_device *pdev) err_codec: snd_soc_unregister_codec(codec); +err_irq: + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994); err: kfree(wm8994); return ret; @@ -3871,6 +3998,10 @@ static int __devexit wm8994_codec_remove(struct platform_device *pdev) wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai)); snd_soc_unregister_codec(&wm8994->codec); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); + wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994); kfree(wm8994); wm8994_codec = NULL; -- cgit v1.2.3 From b2c812e22de88bb79c290c0e718280f10b64a48d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 14 Apr 2010 15:35:19 +0900 Subject: ASoC: Add indirection for CODEC private data One of the features of the multi CODEC work is that it embeds a struct device in the CODEC to provide diagnostics via a sysfs class rather than via the device tree, at which point it's much better to use the struct device private data rather than having two places to store it. Provide an accessor function to allow this change to be made more easily, and update all the CODEC drivers are updated. To ensure use of the accessor the private data structure member is renamed, meaning that if code developed with older an older core that still uses private_data is merged it will fail to build. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index e00201e0820e..29c4cfccd6b9 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1703,7 +1703,7 @@ static int wm8994_volatile(unsigned int reg) static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); BUG_ON(reg > WM8994_MAX_REGISTER); @@ -1728,7 +1728,7 @@ static unsigned int wm8994_read(struct snd_soc_codec *codec, static int configure_aif_clock(struct snd_soc_codec *codec, int aif) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int rate; int reg1 = 0; int offset; @@ -1780,7 +1780,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) static int configure_clock(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int old, new; /* Bring up the AIF clocks first */ @@ -1877,7 +1877,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_pdata *pdata = wm8994->pdata; int base = wm8994_drc_base[drc]; int cfg = wm8994->drc_cfg[drc]; @@ -1913,7 +1913,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_pdata *pdata = wm8994->pdata; int drc = wm8994_get_drc(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -1935,7 +1935,7 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int drc = wm8994_get_drc(kcontrol->id.name); ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc]; @@ -1945,7 +1945,7 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_pdata *pdata = wm8994->pdata; int base = wm8994_retune_mobile_base[block]; int iface, best, best_val, save, i, cfg; @@ -2016,7 +2016,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_pdata *pdata = wm8994->pdata; int block = wm8994_get_retune_mobile_block(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -2038,7 +2038,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int block = wm8994_get_retune_mobile_block(kcontrol->id.name); ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; @@ -2819,7 +2819,7 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = dai->codec; - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int reg_offset, ret; struct fll_div fll; u16 reg, aif1, aif2; @@ -2915,7 +2915,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = dai->codec; - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (dai->id) { case 1: @@ -3181,7 +3181,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int aif1_reg; int bclk_reg; int lrclk_reg; @@ -3468,7 +3468,7 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int i, ret; for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { @@ -3489,7 +3489,7 @@ static int wm8994_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 *reg_cache = codec->reg_cache; int i, ret; @@ -3684,7 +3684,7 @@ static int wm8994_probe(struct platform_device *pdev) return ret; } - wm8994_handle_pdata(codec->private_data); + wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec)); wm_hubs_add_analogue_controls(codec); snd_soc_add_controls(codec, wm8994_snd_controls, @@ -3735,7 +3735,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int micbias, int det, int shrt) { - struct wm8994_priv *wm8994 = codec->private_data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_micdet *micdet; int reg; @@ -3830,7 +3830,7 @@ static int wm8994_codec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); - codec->private_data = wm8994; + snd_soc_codec_set_drvdata(codec, wm8994); codec->control_data = dev_get_drvdata(pdev->dev.parent); codec->name = "WM8994"; codec->owner = THIS_MODULE; -- cgit v1.2.3 From 136ff2a272ad4bee33bf85f8c490ff8a2dd08f96 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Apr 2010 12:56:18 +0900 Subject: ASoC: Support FLL input clock selection on WM8994 The WM8994 FLL can be clocked from one of four inputs, the two MCLKs and the LRCLK and BCLK of the AIF associated with the FLL. Allow all four inputs to be used rather than defaulting to MCLK1. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 29c4cfccd6b9..a27b2ff769d9 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2843,6 +2843,16 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, return -EINVAL; } + switch (src) { + case WM8994_FLL_SRC_MCLK1: + case WM8994_FLL_SRC_MCLK2: + case WM8994_FLL_SRC_LRCLK: + case WM8994_FLL_SRC_BCLK: + break; + default: + return -EINVAL; + } + /* Are we changing anything? */ if (wm8994->fll[id].src == src && wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out) @@ -2883,8 +2893,10 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, fll.n << WM8994_FLL1_N_SHIFT); snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, - WM8994_FLL1_REFCLK_DIV_MASK, - fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT); + WM8994_FLL1_REFCLK_DIV_MASK | + WM8994_FLL1_REFCLK_SRC_MASK, + (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | + (src - 1)); /* Enable (with fractional mode if required) */ if (freq_out) { @@ -2899,6 +2911,7 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, wm8994->fll[id].in = freq_in; wm8994->fll[id].out = freq_out; + wm8994->fll[id].src = src; /* Enable any gated AIF clocks */ snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, -- cgit v1.2.3 From 7d48a6acbcf5325a2551e948bd1557a46dec4c76 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Apr 2010 13:36:11 +0900 Subject: ASoC: Set full range of WM8994 FLL Fratio values Use all the available Fratio values when configuring the WM8994 FLL, not just 0 and 3, following more complete characterisation of the device performance. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a27b2ff769d9..8d3ea9b24267 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2784,9 +2784,18 @@ static int wm8994_get_fll_config(struct fll_div *fll, if (freq_in > 1000000) { fll->fll_fratio = 0; - } else { + } else if (freq_in > 256000) { + fll->fll_fratio = 1; + freq_in *= 2; + } else if (freq_in > 128000) { + fll->fll_fratio = 2; + freq_in *= 4; + } else if (freq_in > 64000) { fll->fll_fratio = 3; freq_in *= 8; + } else { + fll->fll_fratio = 4; + freq_in *= 16; } pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in); -- cgit v1.2.3 From ee839a2127a4f74505c5597966919ca57413f4de Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Apr 2010 13:57:08 +0900 Subject: ASoC: Tone down debugging for WM8994 class W It's a little verbose during path changes. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 8d3ea9b24267..eefa2427b102 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2189,13 +2189,13 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec) /* Only support direct DAC->headphone paths */ reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1); if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) { - dev_dbg(codec->dev, "HPL connected to output mixer\n"); + dev_vdbg(codec->dev, "HPL connected to output mixer\n"); enable = 0; } reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2); if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) { - dev_dbg(codec->dev, "HPR connected to output mixer\n"); + dev_vdbg(codec->dev, "HPR connected to output mixer\n"); enable = 0; } @@ -2203,26 +2203,26 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec) reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); switch (reg) { case WM8994_AIF2DACL_TO_DAC1L: - dev_dbg(codec->dev, "Class W source AIF2DAC\n"); + dev_vdbg(codec->dev, "Class W source AIF2DAC\n"); source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT; break; case WM8994_AIF1DAC2L_TO_DAC1L: - dev_dbg(codec->dev, "Class W source AIF1DAC2\n"); + dev_vdbg(codec->dev, "Class W source AIF1DAC2\n"); source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT; break; case WM8994_AIF1DAC1L_TO_DAC1L: - dev_dbg(codec->dev, "Class W source AIF1DAC1\n"); + dev_vdbg(codec->dev, "Class W source AIF1DAC1\n"); source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT; break; default: - dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg); + dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg); enable = 0; break; } reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); if (reg_r != reg) { - dev_dbg(codec->dev, "Left and right DAC mixers different\n"); + dev_vdbg(codec->dev, "Left and right DAC mixers different\n"); enable = 0; } -- cgit v1.2.3 From 7add84aa779b4f7ca39484a82a11e01d7acd4dca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 22 Apr 2010 02:29:01 +0900 Subject: ASoC: Allow unspecified source when stopping WM8994 FLLs Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index eefa2427b102..cdfbfb633f30 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2853,6 +2853,11 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, } switch (src) { + case 0: + /* Allow no source specification when stopping */ + if (freq_out) + return -EINVAL; + break; case WM8994_FLL_SRC_MCLK1: case WM8994_FLL_SRC_MCLK2: case WM8994_FLL_SRC_LRCLK: -- cgit v1.2.3 From 5e5e2bef287b96ab29d2d93e89ecf0888323d7bf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 25 Apr 2010 12:20:30 +0100 Subject: ASoC: Warn on low WM8994 AIFCLK Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index cdfbfb633f30..f04a116e678b 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1769,6 +1769,11 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n", aif + 1, rate); } + + if (rate && rate < 3000000) + dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n", + aif + 1, rate); + wm8994->aifclk[aif] = rate; snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, -- cgit v1.2.3 From fd5722e5cdb233bbc47e782e10b3b5e3488a22fa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 May 2010 14:55:04 +0100 Subject: ASoC: Add register write logging for WM8994 Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index f04a116e678b..c6b3f1ebd62e 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1710,6 +1710,8 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, if (!wm8994_volatile(reg)) wm8994->reg_cache[reg] = value; + dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value); + return wm8994_reg_write(codec->control_data, reg, value); } -- cgit v1.2.3 From 6a2f1ee1f9bb5346644105c9355e9e06f6a847d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 May 2010 18:36:37 +0100 Subject: ASoC: Don't restart unconfigured WM8994 FLLs If the FLL is not configured attempting to resume it will produce a warning message so skip the resume. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc/codecs/wm8994.c') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c6b3f1ebd62e..dda356591fdb 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3548,6 +3548,9 @@ static int wm8994_resume(struct platform_device *pdev) wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { + if (!wm8994->fll_suspend[i].out) + continue; + ret = wm8994_set_fll(&codec->dai[0], i + 1, wm8994->fll_suspend[i].src, wm8994->fll_suspend[i].in, -- cgit v1.2.3