[alsa-devel] [PATCHv6 1/9] ASOC: wm8971: clean for checkpatch --strict
Before adding wm8973 support, clean up existing wm8971 style.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 110 +++++++++++++++++++++++---------------------- sound/soc/codecs/wm8971.h | 30 ++++++------- 2 files changed, 72 insertions(+), 68 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 39ddb9b..01c76a4 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -29,9 +29,9 @@
#include "wm8971.h"
-#define WM8971_REG_COUNT 43 +#define WM8971_REG_COUNT 43
-static struct workqueue_struct *wm8971_workq = NULL; +static struct workqueue_struct *wm8971_workq;
/* codec private data */ struct wm8971_priv { @@ -92,25 +92,28 @@ static const struct reg_default wm8971_reg_defaults[] = { #define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0)
/* WM8971 Controls */ -static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; -static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz", - "200Hz @ 48kHz" }; -static const char *wm8971_treble[] = { "8kHz", "4kHz" }; -static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" }; -static const char *wm8971_ng_type[] = { "Constant PGA Gain", - "Mute ADC Output" }; -static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; -static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", - "Mono (Right)", "Digital Mono"}; -static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" }; -static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA", - "Differential"}; -static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA", - "Differential"}; -static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"}; -static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; -static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", - "L + R Invert"}; +static const char const *wm8971_bass[] = {"Linear Control", "Adaptive Boost"}; +static const char const *wm8971_bass_filter[] = {"130Hz @ 48kHz", + "200Hz @ 48kHz"}; +static const char const *wm8971_treble[] = {"8kHz", "4kHz"}; +static const char const *wm8971_alc_func[] = {"Off", "Right", + "Left", "Stereo"}; +static const char const *wm8971_ng_type[] = {"Constant PGA Gain", + "Mute ADC Output"}; +static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; +static const char const *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; +static const char const *wm8971_dac_phase[] = {"Non Inverted", "Inverted"}; +static const char const *wm8971_lline_mux[] = {"Line", "NC", "NC", + "PGA", "Differential"}; +static const char const *wm8971_rline_mux[] = {"Line", "Mic", "NC", + "PGA", "Differential"}; +static const char const *wm8971_lpga_sel[] = {"Line", "NC", "NC", + "Differential"}; +static const char const *wm8971_rpga_sel[] = {"Line", "Mic", "NC", + "Differential"}; +static const char const *wm8971_adcpol[] = {"Normal", "L Invert", + "R Invert", "L + R Invert"};
static const struct soc_enum wm8971_enum[] = { SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */ @@ -136,24 +139,24 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1),
SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V, - WM8971_ROUT1V, 7, 1, 0), + WM8971_ROUT1V, 7, 1, 0), SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V, - WM8971_ROUT2V, 7, 1, 0), + WM8971_ROUT2V, 7, 1, 0), SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0),
SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1, - WM8971_LOUTM2, 4, 7, 1), + WM8971_LOUTM2, 4, 7, 1), SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1, - WM8971_ROUTM2, 4, 7, 1), + WM8971_ROUTM2, 4, 7, 1), SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1, - WM8971_MOUTM2, 4, 7, 1), + WM8971_MOUTM2, 4, 7, 1),
SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V, - WM8971_ROUT1V, 0, 127, 0), + WM8971_ROUT1V, 0, 127, 0), SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, - WM8971_ROUT2V, 0, 127, 0), + WM8971_ROUT2V, 0, 127, 0),
SOC_ENUM("Bass Boost", wm8971_enum[0]), SOC_ENUM("Bass Filter", wm8971_enum[1]), @@ -238,14 +241,14 @@ SOC_DAPM_ENUM("Route", wm8971_enum[13]);
static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, - &wm8971_left_mixer_controls[0], - ARRAY_SIZE(wm8971_left_mixer_controls)), + &wm8971_left_mixer_controls[0], + ARRAY_SIZE(wm8971_left_mixer_controls)), SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, - &wm8971_right_mixer_controls[0], - ARRAY_SIZE(wm8971_right_mixer_controls)), + &wm8971_right_mixer_controls[0], + ARRAY_SIZE(wm8971_right_mixer_controls)), SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0, - &wm8971_mono_mixer_controls[0], - ARRAY_SIZE(wm8971_mono_mixer_controls)), + &wm8971_mono_mixer_controls[0], + ARRAY_SIZE(wm8971_mono_mixer_controls)),
SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0), SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0), @@ -260,18 +263,18 @@ static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, - &wm8971_left_pga_controls), + &wm8971_left_pga_controls), SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, - &wm8971_right_pga_controls), + &wm8971_right_pga_controls), SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, - &wm8971_left_line_controls), + &wm8971_left_line_controls), SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, - &wm8971_right_line_controls), + &wm8971_right_line_controls),
SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, - &wm8971_monomux_controls), + &wm8971_monomux_controls), SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, - &wm8971_monomux_controls), + &wm8971_monomux_controls),
SND_SOC_DAPM_OUTPUT("LOUT1"), SND_SOC_DAPM_OUTPUT("ROUT1"), @@ -431,7 +434,7 @@ static int get_coeff(int mclk, int rate) }
static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); @@ -449,7 +452,7 @@ static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, }
static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) + unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; u16 iface = 0; @@ -507,8 +510,8 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, }
static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); @@ -553,7 +556,7 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute) }
static int wm8971_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) + enum snd_soc_bias_level level) { u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -580,11 +583,12 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, }
#define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) + SNDRV_PCM_FMTBIT_S24_LE)
static const struct snd_soc_dai_ops wm8971_dai_ops = { .hw_params = wm8971_pcm_hw_params, @@ -616,6 +620,7 @@ static void wm8971_work(struct work_struct *work) container_of(work, struct snd_soc_dapm_context, delayed_work.work); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + wm8971_set_bias_level(codec, codec->dapm.bias_level); }
@@ -637,7 +642,7 @@ static int wm8971_resume(struct snd_soc_codec *codec) snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->dapm.bias_level = SND_SOC_BIAS_ON; queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); + msecs_to_jiffies(1000)); }
return 0; @@ -660,7 +665,7 @@ static int wm8971_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); + msecs_to_jiffies(1000));
/* set the update bits */ snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100); @@ -675,7 +680,6 @@ static int wm8971_probe(struct snd_soc_codec *codec) return ret; }
- /* power down chip */ static int wm8971_remove(struct snd_soc_codec *codec) { @@ -729,8 +733,8 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8971);
- ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8971, &wm8971_dai, 1); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8971, + &wm8971_dai, 1);
return ret; } diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h index f31c38f..dc38e21 100644 --- a/sound/soc/codecs/wm8971.h +++ b/sound/soc/codecs/wm8971.h @@ -22,25 +22,25 @@ #define WM8971_ADCDAC 0x05 #define WM8971_IFACE 0x07 #define WM8971_SRATE 0x08 -#define WM8971_LDAC 0x0a -#define WM8971_RDAC 0x0b -#define WM8971_BASS 0x0c +#define WM8971_LDAC 0x0a +#define WM8971_RDAC 0x0b +#define WM8971_BASS 0x0c #define WM8971_TREBLE 0x0d #define WM8971_RESET 0x0f -#define WM8971_ALC1 0x11 -#define WM8971_ALC2 0x12 -#define WM8971_ALC3 0x13 +#define WM8971_ALC1 0x11 +#define WM8971_ALC2 0x12 +#define WM8971_ALC3 0x13 #define WM8971_NGATE 0x14 -#define WM8971_LADC 0x15 -#define WM8971_RADC 0x16 -#define WM8971_ADCTL1 0x17 -#define WM8971_ADCTL2 0x18 -#define WM8971_PWR1 0x19 -#define WM8971_PWR2 0x1a -#define WM8971_ADCTL3 0x1b +#define WM8971_LADC 0x15 +#define WM8971_RADC 0x16 +#define WM8971_ADCTL1 0x17 +#define WM8971_ADCTL2 0x18 +#define WM8971_PWR1 0x19 +#define WM8971_PWR2 0x1a +#define WM8971_ADCTL3 0x1b #define WM8971_ADCIN 0x1f -#define WM8971_LADCIN 0x20 -#define WM8971_RADCIN 0x21 +#define WM8971_LADCIN 0x20 +#define WM8971_RADCIN 0x21 #define WM8971_LOUTM1 0x22 #define WM8971_LOUTM2 0x23 #define WM8971_ROUTM1 0x24
We uses SOC_ENUM_SINGLE_DECL macro to replace SOC_ENUM_SINGLE macro for easing reading and maintaining.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 29 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 01c76a4..60c90c6 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -7,6 +7,10 @@ * * Based on wm8753.c by Liam Girdwood * + * WM8971 Improve Copyright (C) 2014 Linaro, Ltd + * Author: Xavier Hsu xavier.hsu@linaro.org + * Andy Green andy.green@linaro.org + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -115,22 +119,30 @@ static const char const *wm8971_rpga_sel[] = {"Line", "Mic", "NC", static const char const *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"};
-static const struct soc_enum wm8971_enum[] = { - SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */ - SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter), - SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble), - SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func), - SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type), /* 4 */ - SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp), - SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux), - SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase), - SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */ - SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux), - SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel), - SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel), - SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol), /* 12 */ - SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux), -}; +static const SOC_ENUM_SINGLE_DECL(bass_boost, WM8971_BASS, 7, wm8971_bass); +static const SOC_ENUM_SINGLE_DECL(bass_filter, WM8971_BASS, + 6, wm8971_bass_filter); +static const SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8971_TREBLE, + 6, wm8971_treble); +static const SOC_ENUM_SINGLE_DECL(alc_capture_func, WM8971_ALC1, + 7, wm8971_alc_func); +static const SOC_ENUM_SINGLE_DECL(alc_capture_ngtype, WM8971_NGATE, + 1, wm8971_ng_type); +static const SOC_ENUM_SINGLE_DECL(dac_mono_mix, WM8971_ADCTL1, + 4, wm8971_mono_mux); +static const SOC_ENUM_SINGLE_DECL(dac_phase_inv, WM8971_ADCTL1, + 1, wm8971_dac_phase); +static const SOC_ENUM_SINGLE_DECL(left_line, WM8971_LOUTM1, + 0, wm8971_lline_mux); +static const SOC_ENUM_SINGLE_DECL(right_line, WM8971_ROUTM1, + 0, wm8971_rline_mux); +static const SOC_ENUM_SINGLE_DECL(left_pga, WM8971_LADCIN, 6, wm8971_lpga_sel); +static const SOC_ENUM_SINGLE_DECL(right_pga, WM8971_RADCIN, + 6, wm8971_rpga_sel); +static const SOC_ENUM_SINGLE_DECL(capture_polarity, WM8971_ADCDAC, + 5, wm8971_adcpol); +static const SOC_ENUM_SINGLE_DECL(monomux, WM8971_ADCIN, 6, wm8971_mono_mux); +static const SOC_ENUM_SINGLE_DECL(deemp, WM8971_ADCDAC, 1, wm8971_deemp);
static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), @@ -158,12 +170,12 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, WM8971_ROUT2V, 0, 127, 0),
- SOC_ENUM("Bass Boost", wm8971_enum[0]), - SOC_ENUM("Bass Filter", wm8971_enum[1]), + SOC_ENUM("Bass Boost", bass_boost), + SOC_ENUM("Bass Filter", bass_filter), SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1),
SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0), - SOC_ENUM("Treble Cut-off", wm8971_enum[2]), + SOC_ENUM("Treble Cut-off", treble_cutoff),
SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
@@ -172,21 +184,21 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = {
SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0), SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0), - SOC_ENUM("ALC Capture Function", wm8971_enum[3]), + SOC_ENUM("ALC Capture Function", alc_capture_func), SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0), SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0), SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0), SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0), SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0), - SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]), + SOC_ENUM("ALC Capture NG Type", alc_capture_ngtype), SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
- SOC_ENUM("Playback De-emphasis", wm8971_enum[5]), - SOC_ENUM("Playback Function", wm8971_enum[6]), - SOC_ENUM("Playback Phase", wm8971_enum[7]), + SOC_ENUM("Playback De-emphasis", deemp), + SOC_ENUM("Playback Function", dac_mono_mix), + SOC_ENUM("Playback Phase", dac_phase_inv),
SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), }; @@ -221,23 +233,23 @@ SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
/* Left Line Mux */ static const struct snd_kcontrol_new wm8971_left_line_controls = -SOC_DAPM_ENUM("Route", wm8971_enum[8]); +SOC_DAPM_ENUM("Route", left_line);
/* Right Line Mux */ static const struct snd_kcontrol_new wm8971_right_line_controls = -SOC_DAPM_ENUM("Route", wm8971_enum[9]); +SOC_DAPM_ENUM("Route", right_line);
/* Left PGA Mux */ static const struct snd_kcontrol_new wm8971_left_pga_controls = -SOC_DAPM_ENUM("Route", wm8971_enum[10]); +SOC_DAPM_ENUM("Route", left_pga);
/* Right PGA Mux */ static const struct snd_kcontrol_new wm8971_right_pga_controls = -SOC_DAPM_ENUM("Route", wm8971_enum[11]); +SOC_DAPM_ENUM("Route", right_pga);
/* Mono ADC Mux */ static const struct snd_kcontrol_new wm8971_monomux_controls = -SOC_DAPM_ENUM("Route", wm8971_enum[13]); +SOC_DAPM_ENUM("Route", monomux);
static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
We add a switch for automatic updating the frequency of wm8971.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) mode change 100644 => 100755 sound/soc/codecs/wm8971.c
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c old mode 100644 new mode 100755 index 60c90c6..b5cb636 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -40,6 +40,11 @@ static struct workqueue_struct *wm8971_workq; /* codec private data */ struct wm8971_priv { unsigned int sysclk; + + /* De-emphasis */ + struct mutex deemph_mutex; + int playback_fs; + bool deemph; };
/* @@ -104,7 +109,6 @@ static const char const *wm8971_alc_func[] = {"Off", "Right", "Left", "Stereo"}; static const char const *wm8971_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"}; -static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; static const char const *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", "Mono (Right)", "Digital Mono"}; static const char const *wm8971_dac_phase[] = {"Non Inverted", "Inverted"}; @@ -118,6 +122,66 @@ static const char const *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; static const char const *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"}; +static const char const *wm8971_deemp[] = {"None", "32kHz", + "44.1kHz", "48kHz"}; + +static int wm8971_set_deemph(struct snd_soc_codec *codec) +{ + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + int val = 0, i, best = 0; + + /* If we're using deemphasis select the nearest available sample + * rate. + */ + if (wm8971->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(wm8971_deemp); i++) { + if (abs(wm8971_deemp[i] - wm8971->playback_fs) < + abs(wm8971_deemp[best] - wm8971->playback_fs)) + best = i; + } + val = best << 1; + } + + dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n", + best, wm8971_deemp[best]); + + return snd_soc_update_bits(codec, WM8971_ADCDAC, 0x6, val); +} + +static int wm8971_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = wm8971->deemph; + + return 0; +} + +static int wm8971_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + int deemph = ucontrol->value.enumerated.item[0]; + int ret = 0; + + if (deemph > 1) + return -EINVAL; + + mutex_lock(&wm8971->deemph_mutex); + if (wm8971->deemph != deemph) { + wm8971->deemph = deemph; + wm8971_set_deemph(codec); + + ret = 1; + } + mutex_unlock(&wm8971->deemph_mutex); + + return ret; +}
static const SOC_ENUM_SINGLE_DECL(bass_boost, WM8971_BASS, 7, wm8971_bass); static const SOC_ENUM_SINGLE_DECL(bass_filter, WM8971_BASS, @@ -142,7 +206,6 @@ static const SOC_ENUM_SINGLE_DECL(right_pga, WM8971_RADCIN, static const SOC_ENUM_SINGLE_DECL(capture_polarity, WM8971_ADCDAC, 5, wm8971_adcpol); static const SOC_ENUM_SINGLE_DECL(monomux, WM8971_ADCIN, 6, wm8971_mono_mux); -static const SOC_ENUM_SINGLE_DECL(deemp, WM8971_ADCDAC, 1, wm8971_deemp);
static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), @@ -196,7 +259,8 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
- SOC_ENUM("Playback De-emphasis", deemp), + SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, + wm8971_get_deemph, wm8971_put_deemph), SOC_ENUM("Playback Function", dac_mono_mix), SOC_ENUM("Playback Phase", dac_phase_inv),
@@ -546,6 +610,9 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, break; }
+ wm8971->playback_fs = params_rate(params); + wm8971_set_deemph(codec); + /* set iface & srate */ snd_soc_write(codec, WM8971_IFACE, iface); if (coeff >= 0) @@ -739,6 +806,8 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, if (wm8971 == NULL) return -ENOMEM;
+ mutex_init(&wm8971->deemph_mutex); + regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap);
On Mon, Dec 01, 2014 at 02:51:55PM +0800, Xavier Hsu wrote:
We add a switch for automatic updating the frequency of wm8971.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org
sound/soc/codecs/wm8971.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) mode change 100644 => 100755 sound/soc/codecs/wm8971.c
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c old mode 100644 new mode 100755 index 60c90c6..b5cb636 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -40,6 +40,11 @@ static struct workqueue_struct *wm8971_workq; /* codec private data */ struct wm8971_priv { unsigned int sysclk;
- /* De-emphasis */
- struct mutex deemph_mutex;
- int playback_fs;
- bool deemph;
};
/* @@ -104,7 +109,6 @@ static const char const *wm8971_alc_func[] = {"Off", "Right", "Left", "Stereo"}; static const char const *wm8971_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"}; -static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; static const char const *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", "Mono (Right)", "Digital Mono"}; static const char const *wm8971_dac_phase[] = {"Non Inverted", "Inverted"}; @@ -118,6 +122,66 @@ static const char const *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; static const char const *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"}; +static const char const *wm8971_deemp[] = {"None", "32kHz",
"44.1kHz", "48kHz"};
This is the same as the original version of the array that you've deleted. I'm guess from the code below that you intended to change this to an array of integers, messed up, and didn't bother to test that your patch compiled before posting it up here.
+static int wm8971_set_deemph(struct snd_soc_codec *codec) +{
- struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
- int val = 0, i, best = 0;
- /* If we're using deemphasis select the nearest available sample
* rate.
- */
- if (wm8971->deemph) {
best = 1;
for (i = 2; i < ARRAY_SIZE(wm8971_deemp); i++) {
if (abs(wm8971_deemp[i] - wm8971->playback_fs) <
abs(wm8971_deemp[best] - wm8971->playback_fs))
wm8971_deemp[i] is a string and then you try to subtract a value from it. I wouldn't expect that to even compile (at least not without warnings), and if it does compile I can't imagine what the result would be and I doubt it is what you wanted. I'm not even sure what you were trying to do here.
best = i;
}
val = best << 1;
- }
- dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
best, wm8971_deemp[best]);
wm_8971_deemp[best] is a string
Hi Richard and Charles : Thanks for your feedback. Sorry for waste your time to help us for checking our patches because I make a mistake. We have a platform that contain wm8973 audio codec. I need to apply all patches and then I can test our patches. After testing our patches, I go back to PATCHv6 3/9 and modify our program. But I forgot to modify some code...... (static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; => static const int wm8971_deemp[] = {0, 32000, 44100, 48000};)
I am very sorry.... Please forgive my carelessness...
We will check all our patches and then release them. If you have any other suggestions, please let me know, thanks. Sorry again.
BR, Xavier
2014-12-01 18:04 GMT+08:00 Richard Fitzgerald < rf@opensource.wolfsonmicro.com>:
On Mon, Dec 01, 2014 at 02:51:55PM +0800, Xavier Hsu wrote:
We add a switch for automatic updating the frequency of wm8971.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org
sound/soc/codecs/wm8971.c | 75
+++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 72 insertions(+), 3 deletions(-) mode change 100644 => 100755 sound/soc/codecs/wm8971.c
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c old mode 100644 new mode 100755 index 60c90c6..b5cb636 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -40,6 +40,11 @@ static struct workqueue_struct *wm8971_workq; /* codec private data */ struct wm8971_priv { unsigned int sysclk;
/* De-emphasis */
struct mutex deemph_mutex;
int playback_fs;
bool deemph;
};
/* @@ -104,7 +109,6 @@ static const char const *wm8971_alc_func[] = {"Off",
"Right",
"Left", "Stereo"};
static const char const *wm8971_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"}; -static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz",
"48kHz"};
static const char const *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", "Mono (Right)", "Digital
Mono"};
static const char const *wm8971_dac_phase[] = {"Non Inverted",
"Inverted"};
@@ -118,6 +122,66 @@ static const char const *wm8971_rpga_sel[] =
{"Line", "Mic", "NC",
"Differential"};
static const char const *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"}; +static const char const *wm8971_deemp[] = {"None", "32kHz",
"44.1kHz", "48kHz"};
This is the same as the original version of the array that you've deleted. I'm guess from the code below that you intended to change this to an array of integers, messed up, and didn't bother to test that your patch compiled before posting it up here.
+static int wm8971_set_deemph(struct snd_soc_codec *codec) +{
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
int val = 0, i, best = 0;
/* If we're using deemphasis select the nearest available sample
* rate.
*/
if (wm8971->deemph) {
best = 1;
for (i = 2; i < ARRAY_SIZE(wm8971_deemp); i++) {
if (abs(wm8971_deemp[i] - wm8971->playback_fs) <
abs(wm8971_deemp[best] - wm8971->playback_fs))
wm8971_deemp[i] is a string and then you try to subtract a value from it. I wouldn't expect that to even compile (at least not without warnings), and if it does compile I can't imagine what the result would be and I doubt it is what you wanted. I'm not even sure what you were trying to do here.
best = i;
}
val = best << 1;
}
dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
best, wm8971_deemp[best]);
wm_8971_deemp[best] is a string
We add TLV information because all volume controls should have TLV information.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 57 +++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 18 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b5cb636..b06bd83 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -30,6 +30,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/initval.h> +#include <sound/tlv.h>
#include "wm8971.h"
@@ -207,8 +208,19 @@ static const SOC_ENUM_SINGLE_DECL(capture_polarity, WM8971_ADCDAC, 5, wm8971_adcpol); static const SOC_ENUM_SINGLE_DECL(monomux, WM8971_ADCIN, 6, wm8971_mono_mux);
+static const DECLARE_TLV_DB_SCALE(in_vol, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(out_vol, -6700, 91, 0); +static const DECLARE_TLV_DB_SCALE(attenuate_6db, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol, -12700, 50, 0); +static const DECLARE_TLV_DB_SCALE(tone_vol, -600, 150, 0); +static const DECLARE_TLV_DB_SCALE(alc_tar_vol, -2850, 150, 0); +static const DECLARE_TLV_DB_SCALE(alc_max_vol, -1200, 600, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol, -9700, 50, 0); +static const DECLARE_TLV_DB_SCALE(bypass_out_vol, -1500, 300, 0); + static const struct snd_kcontrol_new wm8971_snd_controls[] = { - SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), + SOC_DOUBLE_R_TLV("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, + 0, 63, 0, in_vol), SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL, 6, 1, 0), SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1), @@ -219,31 +231,35 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { WM8971_ROUT2V, 7, 1, 0), SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
- SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0), + SOC_DOUBLE_R_TLV("PCM Volume", WM8971_LDAC, WM8971_RDAC, + 0, 255, 0, dac_vol),
- SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1, - WM8971_LOUTM2, 4, 7, 1), - SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1, - WM8971_ROUTM2, 4, 7, 1), - SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1, - WM8971_MOUTM2, 4, 7, 1), + SOC_DOUBLE_R_TLV("Bypass Left Playback Volume", WM8971_LOUTM1, + WM8971_LOUTM2, 4, 7, 1, bypass_out_vol), + SOC_DOUBLE_R_TLV("Bypass Right Playback Volume", WM8971_ROUTM1, + WM8971_ROUTM2, 4, 7, 1, bypass_out_vol), + SOC_DOUBLE_R_TLV("Bypass Mono Playback Volume", WM8971_MOUTM1, + WM8971_MOUTM2, 4, 7, 1, bypass_out_vol),
- SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V, - WM8971_ROUT1V, 0, 127, 0), - SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, - WM8971_ROUT2V, 0, 127, 0), + SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8971_LOUT1V, + WM8971_ROUT1V, 0, 127, 0, out_vol), + SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8971_LOUT2V, + WM8971_ROUT2V, 0, 127, 0, out_vol), + SOC_SINGLE_TLV("Mono Playback Volume", WM8971_MOUTV, + 0, 127, 0, out_vol),
SOC_ENUM("Bass Boost", bass_boost), SOC_ENUM("Bass Filter", bass_filter), - SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1), + SOC_SINGLE_TLV("Bass Volume", WM8971_BASS, 0, 15, 1, tone_vol),
- SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0), + SOC_SINGLE_TLV("Treble Volume", WM8971_TREBLE, 0, 15, 0, tone_vol), SOC_ENUM("Treble Cut-off", treble_cutoff),
SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
- SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0), - SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0), + SOC_SINGLE_TLV("ALC Target Volume", WM8971_ALC1, + 0, 15, 0, alc_tar_vol), + SOC_SINGLE_TLV("ALC Max Volume", WM8971_ALC1, 4, 7, 0, alc_max_vol),
SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0), SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0), @@ -256,8 +272,10 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_ENUM("ALC Capture NG Type", alc_capture_ngtype), SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
- SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), - SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0), + SOC_SINGLE_TLV("Capture 6dB Attenuate", WM8971_ADCDAC, + 8, 1, 0, attenuate_6db), + SOC_SINGLE_TLV("Playback 6dB Attenuate", WM8971_ADCDAC, + 7, 1, 0, attenuate_6db),
SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, wm8971_get_deemph, wm8971_put_deemph), @@ -265,6 +283,9 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { SOC_ENUM("Playback Phase", dac_phase_inv),
SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), + + SOC_DOUBLE_R_TLV("ADC Volume", WM8971_LADC, WM8971_RADC, + 0, 255, 0, adc_vol), };
/*
We use snd_soc_update_bits() to replace snd_soc_write(). "As suggested by Mark Brown"
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b06bd83..5f711bd 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -552,12 +552,11 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0;
/* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - iface = 0x0040; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0040, 0x0040); break; case SND_SOC_DAIFMT_CBS_CFS: break; @@ -568,18 +567,18 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - iface |= 0x0002; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0002, 0x0002); break; case SND_SOC_DAIFMT_RIGHT_J: break; case SND_SOC_DAIFMT_LEFT_J: - iface |= 0x0001; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0001, 0x0001); break; case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0003, 0x0003); break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0013, 0x0013); break; default: return -EINVAL; @@ -590,19 +589,18 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_IF: - iface |= 0x0090; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0090, 0x0090); break; case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0080; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0080, 0x0080); break; case SND_SOC_DAIFMT_NB_IF: - iface |= 0x0010; + snd_soc_update_bits(codec, WM8971_IFACE, 0x0010, 0x0010); break; default: return -EINVAL; }
- snd_soc_write(codec, WM8971_IFACE, iface); return 0; }
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 80 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 5f711bd..1f3abbb 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -40,7 +40,9 @@ static struct workqueue_struct *wm8971_workq;
/* codec private data */ struct wm8971_priv { + /* MCLK */ unsigned int sysclk; + struct snd_pcm_hw_constraint_list *sysclk_constraints;
/* De-emphasis */ struct mutex deemph_mutex; @@ -530,6 +532,35 @@ static int get_coeff(int mclk, int rate) return -EINVAL; }
+/* The set of rates we can generate from the above for each SYSCLK */ +static const unsigned int rates_48000[] = { + 8000, 12000, 16000, 24000, 32000, 48000, 96000 +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static const unsigned int rates_44100[] = { + 8000, 11025, 22050, 44100, 88200 +}; + +static struct snd_pcm_hw_constraint_list constraints_44100 = { + .count = ARRAY_SIZE(rates_44100), + .list = rates_44100, +}; + +static const unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 41100, 48000, + 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { @@ -537,15 +568,29 @@ static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
switch (freq) { - case 11289600: - case 12000000: case 12288000: - case 16934400: + case 24576000: case 18432000: - wm8971->sysclk = freq; - return 0; + case 36864000: + wm8971->sysclk_constraints = &constraints_48000; + break; + case 11289600: + case 22579200: + case 16934400: + case 33868800: + wm8971->sysclk_constraints = &constraints_44100; + break; + case 12000000: + case 24000000: + wm8971->sysclk_constraints = &constraints_12; + break; + default: + return -EINVAL; } - return -EINVAL; + + wm8971->sysclk = freq; + + return 0; }
static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, @@ -604,6 +649,28 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; }
+static int wm8971_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + + /* The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!wm8971->sysclk) { + dev_err(codec->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + wm8971->sysclk_constraints); + + return 0; +} + static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -689,6 +756,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S24_LE)
static const struct snd_soc_dai_ops wm8971_dai_ops = { + .startup = wm8971_pcm_startup, .hw_params = wm8971_pcm_hw_params, .digital_mute = wm8971_mute, .set_fmt = wm8971_set_dai_fmt,
We use msleep to replace work queue. "As suggested by Mark Brown"
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 1f3abbb..60139bc 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -36,8 +36,6 @@
#define WM8971_REG_COUNT 43
-static struct workqueue_struct *wm8971_workq; - /* codec private data */ struct wm8971_priv { /* MCLK */ @@ -780,16 +778,6 @@ static struct snd_soc_dai_driver wm8971_dai = { .ops = &wm8971_dai_ops, };
-static void wm8971_work(struct work_struct *work) -{ - struct snd_soc_dapm_context *dapm = - container_of(work, struct snd_soc_dapm_context, - delayed_work.work); - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); - - wm8971_set_bias_level(codec, codec->dapm.bias_level); -} - static int wm8971_suspend(struct snd_soc_codec *codec) { wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -807,8 +795,8 @@ static int wm8971_resume(struct snd_soc_codec *codec) reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->dapm.bias_level = SND_SOC_BIAS_ON; - queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); + msleep(1000); + wm8971_set_bias_level(codec, codec->dapm.bias_level); }
return 0; @@ -819,19 +807,14 @@ static int wm8971_probe(struct snd_soc_codec *codec) int ret = 0; u16 reg;
- INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work); - wm8971_workq = create_workqueue("wm8971"); - if (wm8971_workq == NULL) - return -ENOMEM; - wm8971_reset(codec);
/* charge output caps - set vmid to 5k for quick power up */ reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; - queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, - msecs_to_jiffies(1000)); + msleep(1000); + wm8971_set_bias_level(codec, codec->dapm.bias_level);
/* set the update bits */ snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100); @@ -851,8 +834,6 @@ static int wm8971_remove(struct snd_soc_codec *codec) { wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
- if (wm8971_workq) - destroy_workqueue(wm8971_workq); return 0; }
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- sound/soc/codecs/wm8971.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 60139bc..b2641a6 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -38,6 +38,7 @@
/* codec private data */ struct wm8971_priv { + struct regmap *regmap; /* MCLK */ unsigned int sysclk; struct snd_pcm_hw_constraint_list *sysclk_constraints; @@ -721,6 +722,7 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute) static int wm8971_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
switch (level) { @@ -732,7 +734,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - snd_soc_cache_sync(codec); + regcache_sync(wm8971->regmap);
/* mute dac and set vmid to 500k, enable VREF */ snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); @@ -866,7 +868,6 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8971_priv *wm8971; - struct regmap *regmap; int ret;
wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), @@ -876,9 +877,9 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
mutex_init(&wm8971->deemph_mutex);
- regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); + if (IS_ERR(wm8971->regmap)) + return PTR_ERR(wm8971->regmap);
i2c_set_clientdata(i2c, wm8971);
This patch adds support for the wm8973 codec.
Signed-off-by: Xavier Hsu xavier.hsu@linaro.org Signed-off-by: Andy Green andy.green@linaro.org --- Documentation/devicetree/bindings/sound/wm8971.txt | 42 +++ sound/soc/codecs/wm8971.c | 330 ++++++++++++++++---- sound/soc/codecs/wm8971.h | 1 + 3 files changed, 315 insertions(+), 58 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wm8971.txt
diff --git a/Documentation/devicetree/bindings/sound/wm8971.txt b/Documentation/devicetree/bindings/sound/wm8971.txt new file mode 100644 index 0000000..5dc4010 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8971.txt @@ -0,0 +1,42 @@ +WM8971 and WM8973 audio CODEC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8971". + "wlf,wm8973". + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Optional properties: + + - mclk-div : Setting the CLKDIV2 bit for dividing MCLK. + mclk-div = <0> (Not divide & Default). + mclk-div = <1> (Divide by 2). + + - analogue-bias : Analogue Bias optimization + analogue-bias = <0> (AVDD 1.8V) + analogue-bias = <1> (AVDD 2.5V) + analogue-bias = <2> (AVDD 3.3V & Default) + + - headphone-en : This is a boolean property. If present, the HPSWEN bit + of R24 (Additional control 2) gets set, indicating that the Headphone + Switch is enabled. + + - headphone-pol : This is a boolean property. If present, the HPSWPOL bit + of R24 (Additional control 2) gets set, indicating that the HPDETECT + high represents speaker otherwise represents headphone. + +Example: + +codec: wm8973@1a { + compatible = "wlf,wm8973"; + reg = <0x1a>; + mclk-div = <1>; + analogue-bias = <0>; + headphone-en; + headphone-pol; +}; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b2641a6..1be0280 100755 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -7,7 +7,7 @@ * * Based on wm8753.c by Liam Girdwood * - * WM8971 Improve Copyright (C) 2014 Linaro, Ltd + * WM8971 Improve & WM8973 Support Copyright (C) 2014 Linaro, Ltd * Author: Xavier Hsu xavier.hsu@linaro.org * Andy Green andy.green@linaro.org * @@ -34,19 +34,29 @@
#include "wm8971.h"
+enum variant { + VARIANT_WM8971, + VARIANT_WM8973 +}; + #define WM8971_REG_COUNT 43
/* codec private data */ struct wm8971_priv { struct regmap *regmap; + enum variant variant; /* MCLK */ unsigned int sysclk; struct snd_pcm_hw_constraint_list *sysclk_constraints; - /* De-emphasis */ struct mutex deemph_mutex; int playback_fs; bool deemph; + /* From DT */ + int mclk_div; + int analogue_bias; + bool headphone_en; + bool headphone_pol; };
/* @@ -102,7 +112,7 @@ static const struct reg_default wm8971_reg_defaults[] = {
#define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0)
-/* WM8971 Controls */ +/* WM8971 / 3 Controls */ static const char const *wm8971_bass[] = {"Linear Control", "Adaptive Boost"}; static const char const *wm8971_bass_filter[] = {"130Hz @ 48kHz", "200Hz @ 48kHz"}; @@ -114,19 +124,33 @@ static const char const *wm8971_ng_type[] = {"Constant PGA Gain", static const char const *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", "Mono (Right)", "Digital Mono"}; static const char const *wm8971_dac_phase[] = {"Non Inverted", "Inverted"}; -static const char const *wm8971_lline_mux[] = {"Line", "NC", "NC", - "PGA", "Differential"}; -static const char const *wm8971_rline_mux[] = {"Line", "Mic", "NC", - "PGA", "Differential"}; -static const char const *wm8971_lpga_sel[] = {"Line", "NC", "NC", - "Differential"}; -static const char const *wm8971_rpga_sel[] = {"Line", "Mic", "NC", - "Differential"}; static const char const *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", "L + R Invert"}; static const char const *wm8971_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
+/* WM8971-only*/ +static const char const *wm8971_lline_mux[] = {"Line 1", "NC", "NC", + "PGA", "Differential"}; +static const char const *wm8971_rline_mux[] = {"Line 1", "Mic", "NC", + "PGA", "Differential"}; +static const char const *wm8971_lpga_sel[] = {"Line 1", "NC", "NC", + "Differential"}; +static const char const *wm8971_rpga_sel[] = {"Line 1", "Mic", "NC", + "Differential"}; + +/* WM8973-only*/ +static const char const *wm8973_line_mux[] = {"Line 1", "Line 2", "Line 3", + "PGA", "Differential"}; +static const char const *wm8973_pga_sel[] = {"Line 1", "Line 2", "Line 3", + "Differential"}; +static const char const *wm8973_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", + "ROUT1"}; +static const char const *wm8973_diff_sel[] = {"Line 1", "Line 2"}; +static const char const *wm8973_3d_lc[] = { "200Hz", "500Hz" }; +static const char const *wm8973_3d_uc[] = { "2.2kHz", "1.5kHz" }; +static const char const *wm8973_3d_func[] = {"Capture", "Playback"}; + static int wm8971_set_deemph(struct snd_soc_codec *codec) { struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); @@ -185,6 +209,7 @@ static int wm8971_put_deemph(struct snd_kcontrol *kcontrol, return ret; }
+/* WM8971 / 3 Controls */ static const SOC_ENUM_SINGLE_DECL(bass_boost, WM8971_BASS, 7, wm8971_bass); static const SOC_ENUM_SINGLE_DECL(bass_filter, WM8971_BASS, 6, wm8971_bass_filter); @@ -198,17 +223,39 @@ static const SOC_ENUM_SINGLE_DECL(dac_mono_mix, WM8971_ADCTL1, 4, wm8971_mono_mux); static const SOC_ENUM_SINGLE_DECL(dac_phase_inv, WM8971_ADCTL1, 1, wm8971_dac_phase); -static const SOC_ENUM_SINGLE_DECL(left_line, WM8971_LOUTM1, - 0, wm8971_lline_mux); -static const SOC_ENUM_SINGLE_DECL(right_line, WM8971_ROUTM1, - 0, wm8971_rline_mux); -static const SOC_ENUM_SINGLE_DECL(left_pga, WM8971_LADCIN, 6, wm8971_lpga_sel); -static const SOC_ENUM_SINGLE_DECL(right_pga, WM8971_RADCIN, - 6, wm8971_rpga_sel); static const SOC_ENUM_SINGLE_DECL(capture_polarity, WM8971_ADCDAC, 5, wm8971_adcpol); static const SOC_ENUM_SINGLE_DECL(monomux, WM8971_ADCIN, 6, wm8971_mono_mux);
+/* WM8971-only */ +static const SOC_ENUM_SINGLE_DECL(wm8971_left_line, WM8971_LOUTM1, + 0, wm8971_lline_mux); +static const SOC_ENUM_SINGLE_DECL(wm8971_right_line, WM8971_ROUTM1, + 0, wm8971_rline_mux); +static const SOC_ENUM_SINGLE_DECL(wm8971_left_pga, WM8971_LADCIN, + 6, wm8971_lpga_sel); +static const SOC_ENUM_SINGLE_DECL(wm8971_right_pga, WM8971_RADCIN, + 6, wm8971_rpga_sel); + +/* WM8973-only */ +static const SOC_ENUM_SINGLE_DECL(wm8973_left_line, WM8971_LOUTM1, + 0, wm8973_line_mux); +static const SOC_ENUM_SINGLE_DECL(wm8973_right_line, WM8971_ROUTM1, + 0, wm8973_line_mux); +static const SOC_ENUM_SINGLE_DECL(wm8973_left_pga, WM8971_LADCIN, + 6, wm8973_pga_sel); +static const SOC_ENUM_SINGLE_DECL(wm8973_right_pga, WM8971_RADCIN, + 6, wm8973_pga_sel); +static const SOC_ENUM_SINGLE_DECL(wm8973_out3_control, WM8971_ADCTL2, + 7, wm8973_out3); +static const SOC_ENUM_SINGLE_DECL(wm8973_diffmux, WM8971_ADCIN, + 8, wm8973_diff_sel); +static const SOC_ENUM_SINGLE_DECL(wm8973_lower_cutoff, WM8973_3D, + 5, wm8973_3d_lc); +static const SOC_ENUM_SINGLE_DECL(wm8973_upper_cutoff, WM8973_3D, + 6, wm8973_3d_uc); +static const SOC_ENUM_SINGLE_DECL(wm8973_mode, WM8973_3D, 7, wm8973_3d_func); + static const DECLARE_TLV_DB_SCALE(in_vol, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(out_vol, -6700, 91, 0); static const DECLARE_TLV_DB_SCALE(attenuate_6db, -600, 600, 0); @@ -287,6 +334,17 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = {
SOC_DOUBLE_R_TLV("ADC Volume", WM8971_LADC, WM8971_RADC, 0, 255, 0, adc_vol), + SOC_SINGLE("Right Speaker Playback Invert Switch", WM8971_ADCTL2, + 4, 1, 0), +}; + +static const struct snd_kcontrol_new wm8973_snd_controls[] = { + /* 3D Control */ + SOC_SINGLE("3D Switch", WM8973_3D, 0, 1, 0), + SOC_SINGLE("3D Volume", WM8973_3D, 1, 15, 0), + SOC_ENUM("3D Lower Cut-off", wm8973_lower_cutoff), + SOC_ENUM("3D Upper Cut-off", wm8973_upper_cutoff), + SOC_ENUM("3D Mode", wm8973_mode), };
/* @@ -319,25 +377,41 @@ SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
/* Left Line Mux */ static const struct snd_kcontrol_new wm8971_left_line_controls = -SOC_DAPM_ENUM("Route", left_line); +SOC_DAPM_ENUM("Route", wm8971_left_line); +static const struct snd_kcontrol_new wm8973_left_line_controls = +SOC_DAPM_ENUM("Route", wm8973_left_line);
/* Right Line Mux */ static const struct snd_kcontrol_new wm8971_right_line_controls = -SOC_DAPM_ENUM("Route", right_line); +SOC_DAPM_ENUM("Route", wm8971_right_line); +static const struct snd_kcontrol_new wm8973_right_line_controls = +SOC_DAPM_ENUM("Route", wm8973_right_line);
/* Left PGA Mux */ static const struct snd_kcontrol_new wm8971_left_pga_controls = -SOC_DAPM_ENUM("Route", left_pga); +SOC_DAPM_ENUM("Route", wm8971_left_pga); +static const struct snd_kcontrol_new wm8973_left_pga_controls = +SOC_DAPM_ENUM("Route", wm8973_left_pga);
/* Right PGA Mux */ static const struct snd_kcontrol_new wm8971_right_pga_controls = -SOC_DAPM_ENUM("Route", right_pga); +SOC_DAPM_ENUM("Route", wm8971_right_pga); +static const struct snd_kcontrol_new wm8973_right_pga_controls = +SOC_DAPM_ENUM("Route", wm8973_right_pga); + +/* Out 3 Mux */ +static const struct snd_kcontrol_new wm8973_out3_controls = +SOC_DAPM_ENUM("Route", wm8973_out3_control); + +/* Differential Mux */ +static const struct snd_kcontrol_new wm8973_diffmux_controls = +SOC_DAPM_ENUM("Route", wm8973_diffmux);
/* Mono ADC Mux */ static const struct snd_kcontrol_new wm8971_monomux_controls = SOC_DAPM_ENUM("Route", monomux);
-static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { +static const struct snd_soc_dapm_widget wm897x_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, &wm8971_left_mixer_controls[0], ARRAY_SIZE(wm8971_left_mixer_controls)), @@ -360,15 +434,6 @@ static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
- SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, - &wm8971_left_pga_controls), - SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, - &wm8971_right_pga_controls), - SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, - &wm8971_left_line_controls), - SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, - &wm8971_right_line_controls), - SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &wm8971_monomux_controls), SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, @@ -385,6 +450,41 @@ static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MIC"), };
+static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &wm8971_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &wm8971_right_line_controls), + SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, + &wm8971_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, + &wm8971_right_pga_controls), +}; + +static const struct snd_soc_dapm_widget wm8973_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &wm8973_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &wm8973_right_line_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, + &wm8973_right_pga_controls), + SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, + &wm8973_left_pga_controls), + SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, + &wm8973_out3_controls), + SND_SOC_DAPM_PGA("Out 3", WM8971_PWR2, 1, 0, NULL, 0), + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &wm8973_diffmux_controls), + + SND_SOC_DAPM_OUTPUT("OUT3"), + SND_SOC_DAPM_OUTPUT("VREF"), + + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("LINPUT3"), + SND_SOC_DAPM_INPUT("RINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT3"), +}; + static const struct snd_soc_dapm_route wm8971_dapm_routes[] = { /* left mixer */ {"Left Mixer", "Playback Switch", "Left DAC"}, @@ -425,27 +525,27 @@ static const struct snd_soc_dapm_route wm8971_dapm_routes[] = { {"MONO1", NULL, "Mono Out"},
/* Left Line Mux */ - {"Left Line Mux", "Line", "LINPUT1"}, + {"Left Line Mux", "Line 1", "LINPUT1"}, {"Left Line Mux", "PGA", "Left PGA Mux"}, {"Left Line Mux", "Differential", "Differential Mux"},
/* Right Line Mux */ - {"Right Line Mux", "Line", "RINPUT1"}, + {"Right Line Mux", "Line 1", "RINPUT1"}, {"Right Line Mux", "Mic", "MIC"}, {"Right Line Mux", "PGA", "Right PGA Mux"}, {"Right Line Mux", "Differential", "Differential Mux"},
/* Left PGA Mux */ - {"Left PGA Mux", "Line", "LINPUT1"}, + {"Left PGA Mux", "Line 1", "LINPUT1"}, {"Left PGA Mux", "Differential", "Differential Mux"},
/* Right PGA Mux */ - {"Right PGA Mux", "Line", "RINPUT1"}, + {"Right PGA Mux", "Line 1", "RINPUT1"}, {"Right PGA Mux", "Differential", "Differential Mux"},
/* Differential Mux */ - {"Differential Mux", "Line", "LINPUT1"}, - {"Differential Mux", "Line", "RINPUT1"}, + {"Differential Mux", "Line 1", "LINPUT1"}, + {"Differential Mux", "Line 1", "RINPUT1"},
/* Left ADC Mux */ {"Left ADC Mux", "Stereo", "Left PGA Mux"}, @@ -462,6 +562,49 @@ static const struct snd_soc_dapm_route wm8971_dapm_routes[] = { {"Right ADC", NULL, "Right ADC Mux"}, };
+static const struct snd_soc_dapm_route wm8973_dapm_routes[] = { + {"Out3 Mux", "VREF", "VREF"}, + {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, + {"Out3 Mux", "ROUT1", "Right Mixer"}, + {"Out3 Mux", "MonoOut", "MONO1"}, + {"Out 3", NULL, "Out3 Mux"}, + {"OUT3", NULL, "Out 3"}, + + {"Left Line Mux", "Line 2", "LINPUT2"}, + {"Left Line Mux", "Line 3", "LINPUT3"}, + + {"Right Line Mux", "Line 2", "RINPUT2"}, + {"Right Line Mux", "Line 3", "RINPUT3"}, + + {"Left PGA Mux", "Line 2", "LINPUT2"}, + {"Left PGA Mux", "Line 3", "LINPUT3"}, + + {"Right PGA Mux", "Line 2", "RINPUT2"}, + {"Right PGA Mux", "Line 3", "RINPUT3"}, + + {"Differential Mux", "Line 2", "LINPUT2"}, + {"Differential Mux", "Line 2", "RINPUT2"}, +}; + +static int wm897x_add_controls(struct snd_soc_codec *codec) +{ + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + + if (wm8971->variant) { + snd_soc_add_codec_controls(codec, wm8973_snd_controls, + ARRAY_SIZE(wm8973_snd_controls)); + snd_soc_dapm_new_controls(dapm, wm8973_dapm_widgets, + ARRAY_SIZE(wm8973_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, wm8973_dapm_routes, + ARRAY_SIZE(wm8973_dapm_routes)); + } else + snd_soc_dapm_new_controls(dapm, wm8971_dapm_widgets, + ARRAY_SIZE(wm8971_dapm_widgets)); + + return 0; +} + struct _coeff_div { u32 mclk; u32 rate; @@ -723,12 +866,15 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + static const u16 micbias[] = {0x00c1, 0x00c2}; + u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); + snd_soc_write(codec, WM8971_PWR1, + pwr_reg | micbias[wm8971->variant]); break; case SND_SOC_BIAS_PREPARE: break; @@ -763,21 +909,28 @@ static const struct snd_soc_dai_ops wm8971_dai_ops = { .set_sysclk = wm8971_set_dai_sysclk, };
-static struct snd_soc_dai_driver wm8971_dai = { - .name = "wm8971-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8971_RATES, - .formats = WM8971_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8971_RATES, - .formats = WM8971_FORMATS,}, - .ops = &wm8971_dai_ops, +static struct snd_soc_dai_driver wm8971_dai[] = { + { + .name = "wm8971-hifi-playback", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8971_RATES, + .formats = WM8971_FORMATS, + }, + .ops = &wm8971_dai_ops, + }, { + .name = "wm8971-hifi-capture", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8971_RATES, + .formats = WM8971_FORMATS, + }, + .ops = &wm8971_dai_ops, + }, };
static int wm8971_suspend(struct snd_soc_codec *codec) @@ -806,11 +959,59 @@ static int wm8971_resume(struct snd_soc_codec *codec)
static int wm8971_probe(struct snd_soc_codec *codec) { + struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); + const u32 *p; int ret = 0; u16 reg;
wm8971_reset(codec);
+ /* Master Clock Divide by 2 (0 = not div, 1 = div by 2) */ + if (codec->dev->of_node) { + p = of_get_property(codec->dev->of_node, "mclk-div", NULL); + if (p) + wm8971->mclk_div = be32_to_cpu(*p); + } + + if (wm8971->mclk_div) + snd_soc_update_bits(codec, WM8971_SRATE, 0x0040, 0x0040); + + /* Analouge Bias (0 = 1.8V, 1 = 2.5V, 2 = 3.3V) */ + if (codec->dev->of_node) { + p = of_get_property(codec->dev->of_node, "anglouge-bias", NULL); + if (p) + wm8971->analogue_bias = be32_to_cpu(*p); + } + + switch (wm8971->analogue_bias) { + case 0: + snd_soc_update_bits(codec, WM8971_ADCTL1, 0x00c0, 0x0000); + break; + case 1: + snd_soc_update_bits(codec, WM8971_ADCTL1, 0x00c0, 0x0040); + case 2: + /* Default */ + break; + default: + pr_err("The value is invalid [%d]\n", wm8971->analogue_bias); + } + + /* Headphone Switch (0 = disabled, 1 = enabled) */ + if (codec->dev->of_node) + if (of_property_read_bool(codec->dev->of_node, "headphone-en")) + wm8971->headphone_en = true; + if (wm8971->headphone_en) + snd_soc_update_bits(codec, WM8971_ADCTL2, 0x0040, 0x0040); + + /* Headphone Polarity (0 = HPDETECT high represent headphone, + * 1 = HPDETECT high represent speaker) + */ + if (codec->dev->of_node) + if (of_property_read_bool(codec->dev->of_node, "headphone-pol")) + wm8971->headphone_pol = true; + if (wm8971->headphone_pol) + snd_soc_update_bits(codec, WM8971_ADCTL2, 0x0020, 0x0020); + /* charge output caps - set vmid to 5k for quick power up */ reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); @@ -828,6 +1029,8 @@ static int wm8971_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
+ wm897x_add_controls(codec); + return ret; }
@@ -848,8 +1051,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
.controls = wm8971_snd_controls, .num_controls = ARRAY_SIZE(wm8971_snd_controls), - .dapm_widgets = wm8971_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets), + .dapm_widgets = wm897x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm897x_dapm_widgets), .dapm_routes = wm8971_dapm_routes, .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), }; @@ -876,6 +1079,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, return -ENOMEM;
mutex_init(&wm8971->deemph_mutex); + wm8971->variant = (int)id->driver_data;
wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); if (IS_ERR(wm8971->regmap)) @@ -884,7 +1088,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8971);
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8971, - &wm8971_dai, 1); + wm8971_dai, ARRAY_SIZE(wm8971_dai));
return ret; } @@ -896,15 +1100,23 @@ static int wm8971_i2c_remove(struct i2c_client *client) }
static const struct i2c_device_id wm8971_i2c_id[] = { - { "wm8971", 0 }, + { "wm8971", VARIANT_WM8971 }, + { "wm8973", VARIANT_WM8973 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
+static const struct of_device_id wm897x_dt_ids[] = { + { .compatible = "wlf,wm8971" }, + { .compatible = "wlf,wm8973" }, + { /* sentinel */ } +}; + static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", .owner = THIS_MODULE, + .of_match_table = wm897x_dt_ids, }, .probe = wm8971_i2c_probe, .remove = wm8971_i2c_remove, @@ -916,3 +1128,5 @@ module_i2c_driver(wm8971_i2c_driver); MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("*wm8971*"); +MODULE_ALIAS("*wm8973*"); diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h index dc38e21..161dae7 100644 --- a/sound/soc/codecs/wm8971.h +++ b/sound/soc/codecs/wm8971.h @@ -27,6 +27,7 @@ #define WM8971_BASS 0x0c #define WM8971_TREBLE 0x0d #define WM8971_RESET 0x0f +#define WM8973_3D 0x10 #define WM8971_ALC1 0x11 #define WM8971_ALC2 0x12 #define WM8971_ALC3 0x13
participants (2)
-
Richard Fitzgerald
-
Xavier Hsu