From ecbb1b8d97a78a72003fcb19292da502d393bf80 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Jul 2017 00:39:29 +0000 Subject: ASoC: hdmi-codec: ELD control corresponds to the PCM stream Current hdmi-codec driver is using hdmi_controls for "ELD" control. But, hdmi-codec driver might be used from many HDMIs. Thus, we need to correspond device number, otherwise we will receive below error. xxx: control x:x:x:ELD:x is already present This patch registers ELD control in .pcm_new by using .device = rtd->pcm->device to corresponding to PCM stream. Signed-off-by: Kuninori Morimoto [Takashi: use snd_ctl_new1()/snd_ctl_add()] Signed-off-by: Takashi Iwai Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 22ed0dc88f0a..7686a80861f1 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -399,18 +399,6 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } - -static const struct snd_kcontrol_new hdmi_controls[] = { - { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdmi_eld_ctl_info, - .get = hdmi_eld_ctl_get, - }, -}; - static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -668,6 +656,16 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai_driver *drv = dai->driver; struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct snd_kcontrol *kctl; + struct snd_kcontrol_new hdmi_eld_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = hdmi_eld_ctl_info, + .get = hdmi_eld_ctl_get, + .device = rtd->pcm->device, + }; int ret; dev_dbg(dai->dev, "%s()\n", __func__); @@ -686,7 +684,12 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - return 0; + /* add ELD ctl with the device number corresponding to the PCM stream */ + kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); + if (!kctl) + return -ENOMEM; + + return snd_ctl_add(rtd->card->snd_card, kctl); } static struct snd_soc_dai_driver hdmi_i2s_dai = { @@ -732,8 +735,6 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, static struct snd_soc_codec_driver hdmi_codec = { .component_driver = { - .controls = hdmi_controls, - .num_controls = ARRAY_SIZE(hdmi_controls), .dapm_widgets = hdmi_widgets, .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .dapm_routes = hdmi_routes, -- cgit v1.2.3 From 1d6463a3e23e55621101a1b9b842101988c596ff Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Jul 2017 15:08:55 +0100 Subject: ASoC: hdmi-codec: make const array hdmi_codec_eld_spk_alloc_bits static Don't populate array hdmi_codec_eld_spk_alloc_bits on the stack but make it static. Makes the object code smaller by over 260 bytes: Before: text data bss dec hex filename 10882 3384 64 14330 37fa sound/soc/codecs/hdmi-codec.o After: text data bss dec hex filename 10557 3440 64 14061 36ed sound/soc/codecs/hdmi-codec.o Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 7686a80861f1..509ab513b4b2 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -326,7 +326,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc) { int i; - const unsigned long hdmi_codec_eld_spk_alloc_bits[] = { + static const unsigned long hdmi_codec_eld_spk_alloc_bits[] = { [0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR, [4] = RC, [5] = FLC | FRC, [6] = RLC | RRC, }; -- cgit v1.2.3 From ea4daf81fc5a37766a606479f592cd9dfe6f1da8 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 10 Jul 2017 10:03:12 +0800 Subject: ASoC: rt5514: Move the auto disable DSP function to set_bias_level() Move the auto disable DSP function from the widget event "DAPM Pre" to the set_bias_level() function to avoid the unexpected behavior. While the SPI was recording using the DAI "rt5514-dsp-cpu-dai", the event "DAPM Pre" would be manipulated even the DAPM widgets were not connected, and it also would power off the DSP that cause the DSP buffered data lost. So the auto disable DSP function should move to the set_bias_level() function to make sure that it is only manipulated by the DAPM widgets are connected. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 49 +++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 31 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 1b6796c4c471..a71e63097aaf 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -471,35 +471,6 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } -static int rt5514_pre_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /** - * If the DSP is enabled in start of recording, the DSP - * should be disabled, and sync back to normal recording - * settings to make sure recording properly. - */ - if (rt5514->dsp_enabled) { - rt5514->dsp_enabled = 0; - regmap_multi_reg_write(rt5514->i2c_regmap, - rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch)); - regcache_mark_dirty(rt5514->regmap); - regcache_sync(rt5514->regmap); - } - break; - - default: - return 0; - } - - return 0; -} - static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { /* Input Lines */ SND_SOC_DAPM_INPUT("DMIC1L"), @@ -607,8 +578,6 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { /* Audio Interface */ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_PRE("DAPM Pre", rt5514_pre_event), }; static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { @@ -975,6 +944,24 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec, } break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + /* + * If the DSP is enabled in start of recording, the DSP + * should be disabled, and sync back to normal recording + * settings to make sure recording properly. + */ + if (rt5514->dsp_enabled) { + rt5514->dsp_enabled = 0; + regmap_multi_reg_write(rt5514->i2c_regmap, + rt5514_i2c_patch, + ARRAY_SIZE(rt5514_i2c_patch)); + regcache_mark_dirty(rt5514->regmap); + regcache_sync(rt5514->regmap); + } + } + break; + default: break; } -- cgit v1.2.3 From 7d8e00c78924d50eb71d3cf991096021eadce641 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Fri, 7 Jul 2017 16:58:57 +0800 Subject: ASoC: rt5663: Update the calibration funciton The patch updates the calibration funciton for getting the correct DC offset of headphone output. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 100 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 21 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index a33202affeb1..18b3b526b7c5 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2986,47 +2986,75 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) { int value, count; - regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280); + regmap_write(rt5663->regmap, RT5663_RESET, 0x0000); + msleep(20); + regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_4, 0x00a1); + regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380); regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); - regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000); regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); - regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); - msleep(20); - regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); - regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400); - regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000); - regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); - regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8); - regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003); - regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); - regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111); + regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x000c); + regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x0324); + regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23b); + msleep(30); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8000); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x0008); regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); + regmap_write(rt5663->regmap, RT5663_CBJ_1, 0x8c10); + regmap_write(rt5663->regmap, RT5663_IL_CMD_2, 0x00c1); + regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb880); + regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4110); + regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4118); + + count = 0; + while (true) { + regmap_read(rt5663->regmap, RT5663_INT_ST_2, &value); + if (!(value & 0x80)) + usleep_range(10000, 10005); + else + break; + + if (count > 200) + break; + } + + regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x0000); regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0038); regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8003); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); - regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b); - regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080); + regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000); regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c); - regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba); + regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xafaa); regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224); regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088); regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017); regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017); regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040); + regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000); regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005); regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000); regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9); regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c); - regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); - regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702); - msleep(200); + regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x1111); + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4402); + regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x3311); regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069); - regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2); - regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00); - regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06ce); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6800); + regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x1100); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0057); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe800); + count = 0; while (true) { regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value); @@ -3039,6 +3067,36 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) return; count++; } + + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6200); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0059); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe200); + + count = 0; + while (true) { + regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 200) + return; + count++; + } + + regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb8e0); + usleep_range(10000, 10005); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0x003b); + usleep_range(10000, 10005); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0000); + usleep_range(10000, 10005); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x000b); + usleep_range(10000, 10005); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0008); + usleep_range(10000, 10005); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0000); + usleep_range(10000, 10005); } static int rt5663_i2c_probe(struct i2c_client *i2c, -- cgit v1.2.3 From 8f24412784bd0f544307bb184e3f264064f68ff0 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Fri, 7 Jul 2017 16:58:58 +0800 Subject: ASoC: rt5663: Optimize the Jack Type detection The patch optimizes the Jack Type detection. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 18b3b526b7c5..ebd9ae00e04d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1508,7 +1508,7 @@ static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert) static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) { struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); - int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + int val, i = 0; dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); @@ -1543,17 +1543,22 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); snd_soc_update_bits(codec, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); - while (i < 5) { - msleep(sleep_time[i]); - val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & - 0x0003; - dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n", - __func__, val, sleep_time[i]); - i++; - if (val == 0x1 || val == 0x2 || val == 0x3) + + while (true) { + regmap_read(rt5663->regmap, RT5663_INT_ST_2, &val); + if (!(val & 0x80)) + usleep_range(10000, 10005); + else + break; + + if (i > 200) break; + i++; } + + val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003; dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + switch (val) { case 1: case 2: -- cgit v1.2.3 From 1325734c97c533c2042794f2bd873486b4905cdb Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Fri, 7 Jul 2017 16:58:59 +0800 Subject: ASoC: rt5663: Modify the power sequence for reducing the pop sound The patch modifies the power sequence for reducing the pop sound. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index ebd9ae00e04d..82edbcf39caa 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2029,10 +2029,6 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, RT5663_HP_SIG_SRC1_SILENCE); } else { snd_soc_write(codec, RT5663_DEPOP_2, 0x3003); - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, - 0x000b); - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, - 0x0030); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS); snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371); @@ -2055,9 +2051,6 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0); - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, - 0x000b); } break; @@ -2068,6 +2061,31 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (rt5663->codec_ver == CODEC_VER_0) + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x003b, + 0x003b); + break; + + case SND_SOC_DAPM_POST_PMD: + if (rt5663->codec_ver == CODEC_VER_0) + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x003b, 0); + break; + + default: + return 0; + } + + return 0; +} + static int rt5663_bst2_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -2187,6 +2205,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), /* Headphone*/ + SND_SOC_DAPM_SUPPLY("HP Charge Pump", SND_SOC_NOPM, 0, 0, + rt5663_charge_pump_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -2343,6 +2364,7 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { { "STO1 DAC MIXR", NULL, "STO1 DAC R Power" }, { "STO1 DAC MIXR", NULL, "STO1 DAC Filter" }, + { "HP Amp", NULL, "HP Charge Pump" }, { "HP Amp", NULL, "DAC L" }, { "HP Amp", NULL, "DAC R" }, }; -- cgit v1.2.3 From 09b8852c759917e3ea10062b374692a5313cbfd8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 10 Jul 2017 16:20:45 +0100 Subject: ASoC: rt5663: add in missing loop counter to avoid infinite loop The loop counter 'count' is missing an increment, so we could end up with an infinite loop. Add in a pre-increment to count to fix this. Detected by CoverityScan, CID#1450120 ("Logically Dead Code") Fixes: 1a425dbf1a10 ("ASoC: rt5663: Update the calibration funciton") Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 82edbcf39caa..5b3c50c641d8 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3044,7 +3044,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) else break; - if (count > 200) + if (++count > 200) break; } -- cgit v1.2.3 From 450f0f6a8fb499a6ef3d10ab5c29a7c4650a9958 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 10 Jul 2017 11:14:56 +0800 Subject: ASoC: rt5663: Add the manual offset field to compensate the DC offset The patch adds the manual offset field in the devicetree to compensate the DC offset that will be different between the PCB layout. It only can be measured by the real production. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5663.txt | 5 ++ include/sound/rt5663.h | 20 ++++++++ sound/soc/codecs/rt5663.c | 55 ++++++++++++++++++++-- sound/soc/codecs/rt5663.h | 2 + 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 include/sound/rt5663.h (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/rt5663.txt b/Documentation/devicetree/bindings/sound/rt5663.txt index 70eaeaed2b18..f7c7cc513ee8 100644 --- a/Documentation/devicetree/bindings/sound/rt5663.txt +++ b/Documentation/devicetree/bindings/sound/rt5663.txt @@ -12,6 +12,11 @@ Required properties: Optional properties: +- "realtek,dc_offset_l_manual" +- "realtek,dc_offset_r_manual" + Based on the different PCB layout, add the manual offset value to + compensate the DC offset for each L and R channel. + Pins on the device (for linking into audio routes) for RT5663: * IN1P diff --git a/include/sound/rt5663.h b/include/sound/rt5663.h new file mode 100644 index 000000000000..be6f1b2d8fbd --- /dev/null +++ b/include/sound/rt5663.h @@ -0,0 +1,20 @@ +/* + * linux/sound/rt5663.h -- Platform data for RT5663 + * + * Copyright 2017 Realtek Semiconductor Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_RT5663_H +#define __LINUX_SND_RT5663_H + +struct rt5663_platform_data { + unsigned int dc_offset_l_manual; + unsigned int dc_offset_r_manual; +}; + +#endif + diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 5b3c50c641d8..963cda9c995a 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -40,6 +40,7 @@ enum { struct rt5663_priv { struct snd_soc_codec *codec; + struct rt5663_platform_data pdata; struct regmap *regmap; struct delayed_work jack_detect_work; struct snd_soc_jack *hs_jack; @@ -57,6 +58,10 @@ struct rt5663_priv { int jack_type; }; +static const struct reg_sequence rt5663_patch_list[] = { + { 0x002a, 0x8080 }, +}; + static const struct reg_default rt5663_v2_reg[] = { { 0x0000, 0x0000 }, { 0x0001, 0xc8c8 }, @@ -476,7 +481,7 @@ static const struct reg_default rt5663_reg[] = { { 0x0023, 0x0039 }, { 0x0026, 0xc0c0 }, { 0x0029, 0x8080 }, - { 0x002a, 0xa0a0 }, + { 0x002a, 0x8080 }, { 0x002c, 0x000c }, { 0x002d, 0x0000 }, { 0x0040, 0x0808 }, @@ -1958,15 +1963,11 @@ static const struct snd_kcontrol_new rt5663_adda_r_mix[] = { static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1), - SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1), - SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1), }; /* Out Switch */ @@ -3126,9 +3127,20 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) usleep_range(10000, 10005); } +static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) +{ + device_property_read_u32(dev, "realtek,dc_offset_l_manual", + &rt5663->pdata.dc_offset_l_manual); + device_property_read_u32(dev, "realtek,dc_offset_r_manual", + &rt5663->pdata.dc_offset_r_manual); + + return 0; +} + static int rt5663_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; int ret; unsigned int val; @@ -3142,6 +3154,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5663); + if (pdata) + rt5663->pdata = *pdata; + else + rt5663_parse_dp(rt5663, &i2c->dev); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); @@ -3190,6 +3207,34 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, regmap_write(rt5663->regmap, RT5663_RESET, 0); dev_dbg(&i2c->dev, "calibrate done\n"); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + break; + case CODEC_VER_0: + ret = regmap_register_patch(rt5663->regmap, rt5663_patch_list, + ARRAY_SIZE(rt5663_patch_list)); + if (ret != 0) + dev_warn(&i2c->dev, + "Failed to apply regmap patch: %d\n", ret); + break; + default: + dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); + } + + if (rt5663->pdata.dc_offset_l_manual) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2, + rt5663->pdata.dc_offset_l_manual >> 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3, + rt5663->pdata.dc_offset_l_manual & 0xffff); + } + + if (rt5663->pdata.dc_offset_r_manual) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5, + rt5663->pdata.dc_offset_r_manual >> 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6, + rt5663->pdata.dc_offset_r_manual & 0xffff); + } + /* GPIO1 as IRQ */ regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK, RT5663_GP1_PIN_IRQ); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index 4621812c94d8..c5a9b69579ad 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -12,6 +12,8 @@ #ifndef __RT5663_H__ #define __RT5663_H__ +#include + /* Info */ #define RT5663_RESET 0x0000 #define RT5663_VENDOR_ID 0x00fd -- cgit v1.2.3 From cfe267da9de756d15eab095358b0b122c57816a6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Jun 2017 17:26:48 -0500 Subject: ASoC: twl6040: fix error return code in twl6040_probe() platform_get_irq() returns an error code, but the twl6040 driver ignores it and always returns -EINVAL. This is not correct, and prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error. Print and propagate the return value of platform_get_irq on failure. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 2b6ad09e0886..96cf94a2b7a0 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1123,8 +1123,8 @@ static int twl6040_probe(struct snd_soc_codec *codec) priv->plug_irq = platform_get_irq(pdev, 0); if (priv->plug_irq < 0) { - dev_err(codec->dev, "invalid irq\n"); - return -EINVAL; + dev_err(codec->dev, "invalid irq: %d\n", priv->plug_irq); + return priv->plug_irq; } INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); -- cgit v1.2.3 From fa05899c12d54d3a1befa742f62d3188e551a87c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 14 Jul 2017 14:36:32 +0800 Subject: ASoC: rt5665: force using PLL if MCLK is not suitable Idealy PLL will be set in machine driver if MCLK doesn't meet the requirement of codec. To let the codec driver be more general, we can use a common PLL setting once sysclk/pll doesn't set properly in machine driver. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 370ed54d1e15..d3103efcb135 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4098,9 +4098,12 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, rt5665->lrck[dai->id] = params_rate(params); pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]); if (pre_div < 0) { - dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", - rt5665->lrck[dai->id], dai->id); - return -EINVAL; + dev_warn(codec->dev, "Force using PLL"); + snd_soc_codec_set_pll(codec, 0, RT5665_PLL1_S_MCLK, + rt5665->sysclk, rt5665->lrck[dai->id] * 512); + snd_soc_codec_set_sysclk(codec, RT5665_SCLK_S_PLL1, 0, + rt5665->lrck[dai->id] * 512, 0); + pre_div = 1; } frame_size = snd_soc_params_to_frame_size(params); if (frame_size < 0) { -- cgit v1.2.3 From 68feed90070e5133c0bfe26648410a39e092018d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:08 -0300 Subject: ASoC: adau1977: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index b319db6a69f8..ccc5cf0e4f80 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -388,8 +388,7 @@ static int adau1977_power_disable(struct adau1977 *adau1977) regcache_mark_dirty(adau1977->regmap); - if (adau1977->reset_gpio) - gpiod_set_value_cansleep(adau1977->reset_gpio, 0); + gpiod_set_value_cansleep(adau1977->reset_gpio, 0); regcache_cache_only(adau1977->regmap, true); @@ -420,8 +419,7 @@ static int adau1977_power_enable(struct adau1977 *adau1977) goto err_disable_avdd; } - if (adau1977->reset_gpio) - gpiod_set_value_cansleep(adau1977->reset_gpio, 1); + gpiod_set_value_cansleep(adau1977->reset_gpio, 1); regcache_cache_only(adau1977->regmap, false); -- cgit v1.2.3 From 89b13706c4bb6dae0263014051dd59986376faa5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:07 -0300 Subject: ASoC: wm8804: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index af95d648265b..fc69b87443d8 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -623,8 +623,7 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) return ret; } - if (wm8804->reset) - gpiod_set_value_cansleep(wm8804->reset, 1); + gpiod_set_value_cansleep(wm8804->reset, 1); ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); if (ret < 0) { -- cgit v1.2.3 From c5660778b4851b1aea5d848ccfde3f27949f6418 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:09 -0300 Subject: ASoC: cs35l33: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l33.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 6df29fa30fb9..1eea91271ebb 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -869,8 +869,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev) dev_dbg(dev, "%s\n", __func__); - if (cs35l33->reset_gpio) - gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); ret = regulator_bulk_enable(cs35l33->num_core_supplies, cs35l33->core_supplies); @@ -881,8 +880,7 @@ static int __maybe_unused cs35l33_runtime_resume(struct device *dev) regcache_cache_only(cs35l33->regmap, false); - if (cs35l33->reset_gpio) - gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); msleep(CS35L33_BOOT_DELAY); @@ -1191,8 +1189,7 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client, return ret; } - if (cs35l33->reset_gpio) - gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); msleep(CS35L33_BOOT_DELAY); regcache_cache_only(cs35l33->regmap, false); @@ -1262,8 +1259,7 @@ static int cs35l33_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); - if (cs35l33->reset_gpio) - gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); pm_runtime_disable(&client->dev); regulator_bulk_disable(cs35l33->num_core_supplies, -- cgit v1.2.3 From db3be255a101da11f67c0f3053b750e767eb10fe Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:10 -0300 Subject: ASoC: cs35l34: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 0a747c66cc6c..dade899b38dc 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -1138,8 +1138,7 @@ static int cs35l34_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); - if (cs35l34->reset_gpio) - gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); pm_runtime_disable(&client->dev); regulator_bulk_disable(cs35l34->num_core_supplies, -- cgit v1.2.3 From 205cbac065f9589c77a79f26339cf63023f08f6e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:11 -0300 Subject: ASoC: cs42l42: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 55e4520cdcaf..55caf5ff3e64 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1898,8 +1898,7 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client) snd_soc_unregister_codec(&i2c_client->dev); /* Hold down reset */ - if (cs42l42->reset_gpio) - gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); return 0; } @@ -1913,8 +1912,7 @@ static int cs42l42_runtime_suspend(struct device *dev) regcache_mark_dirty(cs42l42->regmap); /* Hold down reset */ - if (cs42l42->reset_gpio) - gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); /* remove power */ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), @@ -1937,8 +1935,7 @@ static int cs42l42_runtime_resume(struct device *dev) return ret; } - if (cs42l42->reset_gpio) - gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); regcache_cache_only(cs42l42->regmap, false); regcache_sync(cs42l42->regmap); -- cgit v1.2.3 From 55be663dc71ec50f0e383c50886cbd3be69fcd2e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:12 -0300 Subject: ASoC: cs53l30: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/cs53l30.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 06933a5d0a75..92fbe6303dd4 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -842,8 +842,7 @@ static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); - if (priv->mute_gpio) - gpiod_set_value_cansleep(priv->mute_gpio, mute); + gpiod_set_value_cansleep(priv->mute_gpio, mute); return 0; } @@ -960,8 +959,7 @@ static int cs53l30_i2c_probe(struct i2c_client *client, goto error; } - if (cs53l30->reset_gpio) - gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); + gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); i2c_set_clientdata(client, cs53l30); @@ -1056,8 +1054,7 @@ static int cs53l30_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); /* Hold down reset */ - if (cs53l30->reset_gpio) - gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); + gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), cs53l30->supplies); @@ -1073,8 +1070,7 @@ static int cs53l30_runtime_suspend(struct device *dev) regcache_cache_only(cs53l30->regmap, true); /* Hold down reset */ - if (cs53l30->reset_gpio) - gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); + gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), cs53l30->supplies); @@ -1094,8 +1090,7 @@ static int cs53l30_runtime_resume(struct device *dev) return ret; } - if (cs53l30->reset_gpio) - gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); + gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); regcache_cache_only(cs53l30->regmap, false); ret = regcache_sync(cs53l30->regmap); -- cgit v1.2.3 From c5efe232e09ef29cc2f9e8333a49dd8891366c22 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 16 Jul 2017 18:11:13 -0300 Subject: ASoC: sta32x: Remove unneeded gpiod NULL check The gpiod API checks for NULL descriptors, so there is no need to duplicate the check in the driver. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 0790ae8530d9..5b888476d9ff 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -847,8 +847,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, msleep(300); sta32x_watchdog_stop(sta32x); - if (sta32x->gpiod_nreset) - gpiod_set_value(sta32x->gpiod_nreset, 0); + gpiod_set_value(sta32x->gpiod_nreset, 0); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); -- cgit v1.2.3 From 173f4612690ac569d9f912a31aa69af15b84047c Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Thu, 13 Jul 2017 19:42:20 +0800 Subject: ASoC: rt5514: Support the DSP recording continuously after the hotwording triggered The patch uses the IRQ to copy the PCM data to userspace continuously after the hotwording triggered from DSP. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 139 ++++++++++++++++++++++-------------------- sound/soc/codecs/rt5514-spi.h | 7 +-- 2 files changed, 76 insertions(+), 70 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 7ed62e8c80b4..950d1ffdc06c 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -43,9 +43,7 @@ struct rt5514_dsp { struct mutex dma_lock; struct snd_pcm_substream *substream; unsigned int buf_base, buf_limit, buf_rp; - size_t buf_size; - size_t dma_offset; - size_t dsp_offset; + size_t buf_size, get_size, dma_offset; }; static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = { @@ -80,6 +78,8 @@ static void rt5514_spi_copy_work(struct work_struct *work) container_of(work, struct rt5514_dsp, copy_work.work); struct snd_pcm_runtime *runtime; size_t period_bytes, truncated_bytes = 0; + unsigned int cur_wp, remain_data; + u8 buf[8]; mutex_lock(&rt5514_dsp->dma_lock); if (!rt5514_dsp->substream) { @@ -90,8 +90,24 @@ static void rt5514_spi_copy_work(struct work_struct *work) runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); - if (rt5514_dsp->buf_size - rt5514_dsp->dsp_offset < period_bytes) - period_bytes = rt5514_dsp->buf_size - rt5514_dsp->dsp_offset; + if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) { + rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf, + sizeof(buf)); + cur_wp = buf[0] | buf[1] << 8 | buf[2] << 16 | + buf[3] << 24; + + if (cur_wp >= rt5514_dsp->buf_rp) + remain_data = (cur_wp - rt5514_dsp->buf_rp); + else + remain_data = + (rt5514_dsp->buf_limit - rt5514_dsp->buf_rp) + + (cur_wp - rt5514_dsp->buf_base); + + if (remain_data < period_bytes) { + schedule_delayed_work(&rt5514_dsp->copy_work, 5); + goto done; + } + } if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) { rt5514_spi_burst_read(rt5514_dsp->buf_rp, @@ -112,24 +128,58 @@ static void rt5514_spi_copy_work(struct work_struct *work) runtime->dma_area + rt5514_dsp->dma_offset + truncated_bytes, period_bytes - truncated_bytes); - rt5514_dsp->buf_rp = rt5514_dsp->buf_base + - period_bytes - truncated_bytes; + rt5514_dsp->buf_rp = rt5514_dsp->buf_base + period_bytes - + truncated_bytes; } + rt5514_dsp->get_size += period_bytes; rt5514_dsp->dma_offset += period_bytes; if (rt5514_dsp->dma_offset >= runtime->dma_bytes) rt5514_dsp->dma_offset = 0; - rt5514_dsp->dsp_offset += period_bytes; - snd_pcm_period_elapsed(rt5514_dsp->substream); - if (rt5514_dsp->dsp_offset < rt5514_dsp->buf_size) - schedule_delayed_work(&rt5514_dsp->copy_work, 5); + schedule_delayed_work(&rt5514_dsp->copy_work, 5); + done: mutex_unlock(&rt5514_dsp->dma_lock); } +static irqreturn_t rt5514_spi_irq(int irq, void *data) +{ + struct rt5514_dsp *rt5514_dsp = data; + u8 buf[8]; + + rt5514_dsp->get_size = 0; + rt5514_dsp->dma_offset = 0; + + /** + * The address area x1800XXXX is the register address, and it cannot + * support spi burst read perfectly. So we use the spi burst read + * individually to make sure the data correctly. + */ + rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf, + sizeof(buf)); + rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 | + buf[3] << 24; + + rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf, + sizeof(buf)); + rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 | + buf[3] << 24; + + rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf, + sizeof(buf)); + rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 | + buf[3] << 24; + + rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base; + + schedule_delayed_work(&rt5514_dsp->copy_work, 0); + + return IRQ_HANDLED; +} + /* PCM for streaming audio from the DSP buffer */ static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream) { @@ -170,59 +220,6 @@ static int rt5514_spi_hw_free(struct snd_pcm_substream *substream) return snd_pcm_lib_free_vmalloc_buffer(substream); } -static int rt5514_spi_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct rt5514_dsp *rt5514_dsp = - snd_soc_platform_get_drvdata(rtd->platform); - u8 buf[8]; - - rt5514_dsp->dma_offset = 0; - rt5514_dsp->dsp_offset = 0; - - /** - * The address area x1800XXXX is the register address, and it cannot - * support spi burst read perfectly. So we use the spi burst read - * individually to make sure the data correctly. - */ - rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf, - sizeof(buf)); - rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 | - buf[3] << 24; - - rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf, - sizeof(buf)); - rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 | - buf[3] << 24; - - rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP, (u8 *)&buf, - sizeof(buf)); - rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 | - buf[3] << 24; - - rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE, (u8 *)&buf, - sizeof(buf)); - rt5514_dsp->buf_size = buf[0] | buf[1] << 8 | buf[2] << 16 | - buf[3] << 24; - - return 0; -} - -static int rt5514_spi_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct rt5514_dsp *rt5514_dsp = - snd_soc_platform_get_drvdata(rtd->platform); - - if (cmd == SNDRV_PCM_TRIGGER_START) { - if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && - rt5514_dsp->buf_rp && rt5514_dsp->buf_size) - schedule_delayed_work(&rt5514_dsp->copy_work, 0); - } - - return 0; -} - static snd_pcm_uframes_t rt5514_spi_pcm_pointer( struct snd_pcm_substream *substream) { @@ -238,8 +235,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = { .open = rt5514_spi_pcm_open, .hw_params = rt5514_spi_hw_params, .hw_free = rt5514_spi_hw_free, - .trigger = rt5514_spi_trigger, - .prepare = rt5514_spi_prepare, .pointer = rt5514_spi_pcm_pointer, .mmap = snd_pcm_lib_mmap_vmalloc, .page = snd_pcm_lib_get_vmalloc_page, @@ -248,6 +243,7 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = { static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform) { struct rt5514_dsp *rt5514_dsp; + int ret; rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp), GFP_KERNEL); @@ -257,6 +253,17 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform) INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work); snd_soc_platform_set_drvdata(platform, rt5514_dsp); + if (rt5514_spi->irq) { + ret = devm_request_threaded_irq(&rt5514_spi->dev, + rt5514_spi->irq, NULL, rt5514_spi_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5514-spi", + rt5514_dsp); + if (ret) + dev_err(&rt5514_spi->dev, + "%s Failed to reguest IRQ: %d\n", __func__, + ret); + } + return 0; } diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h index f69b1cdf2f9b..a6434ee6ff03 100644 --- a/sound/soc/codecs/rt5514-spi.h +++ b/sound/soc/codecs/rt5514-spi.h @@ -17,10 +17,9 @@ */ #define RT5514_SPI_BUF_LEN 240 -#define RT5514_BUFFER_VOICE_BASE 0x18001034 -#define RT5514_BUFFER_VOICE_LIMIT 0x18001038 -#define RT5514_BUFFER_VOICE_RP 0x1800103c -#define RT5514_BUFFER_VOICE_SIZE 0x18001040 +#define RT5514_BUFFER_VOICE_BASE 0x18000200 +#define RT5514_BUFFER_VOICE_LIMIT 0x18000204 +#define RT5514_BUFFER_VOICE_WP 0x1800020c /* SPI Command */ enum { -- cgit v1.2.3 From fde0543f1129967dfa73f1fa3477c7fe12052da5 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 12 Jul 2017 13:36:59 -0500 Subject: ASoC: tlv320aic32x4: Add support for tlv320aic32x6 Add support for the tlv320aic32x6 family of devices. These devices share the same register set as the tlv320aic32x4 and this driver can be re-used. TLV320aic32x6 data sheets are here: tlv320aic3256 - http://www.ti.com/lit/gpn/tlv320aic3256 tlv320aic3206 - http://www.ti.com/lit/gpn/tlv320aic3206 Signed-off-by: Dan Murphy Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic32x4.txt | 4 +++- sound/soc/codecs/tlv320aic32x4-i2c.c | 2 ++ sound/soc/codecs/tlv320aic32x4-spi.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 5e2741af27be..9651fc7503a4 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -3,7 +3,9 @@ Texas Instruments - tlv320aic32x4 Codec module The tlv320aic32x4 serial control bus communicates through I2C protocols Required properties: - - compatible: Should be "ti,tlv320aic32x4" + - compatible - "string" - One of: + "ti,tlv320aic32x4" TLV320AIC3204 + "ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256 - reg: I2C slave address - supply-*: Required supply regulators are: "iov" - digital IO power supply diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index 59606cf3008f..385fa2e9525a 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -47,12 +47,14 @@ static int aic32x4_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id aic32x4_i2c_id[] = { { "tlv320aic32x4", 0 }, + { "tlv320aic32x6", 1 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); static const struct of_device_id aic32x4_of_id[] = { { .compatible = "ti,tlv320aic32x4", }, + { .compatible = "ti,tlv320aic32x6", }, { /* senitel */ } }; MODULE_DEVICE_TABLE(of, aic32x4_of_id); diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index 724fcdd491b2..07d78ae51e05 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -48,12 +48,14 @@ static int aic32x4_spi_remove(struct spi_device *spi) static const struct spi_device_id aic32x4_spi_id[] = { { "tlv320aic32x4", 0 }, + { "tlv320aic32x6", 1 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, aic32x4_spi_id); static const struct of_device_id aic32x4_of_id[] = { { .compatible = "ti,tlv320aic32x4", }, + { .compatible = "ti,tlv320aic32x6", }, { /* senitel */ } }; MODULE_DEVICE_TABLE(of, aic32x4_of_id); -- cgit v1.2.3 From b9045b9c6b79d2ea5b888a0f9e9aa156d09ba8a9 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 12 Jul 2017 13:37:00 -0500 Subject: ASoC: tlv320aic32x4: Add gpio configuration to the codec Add the ability to configure the MFP1->MFP5 registers as GPIOs. In addition adding ALSA controls to get and set the GPIO state. Per the data sheet each MFP can be configured as a GPIO input only, output only or either an input or output. Signed-off-by: Dan Murphy Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tlv320aic32x4.txt | 9 + include/sound/tlv320aic32x4.h | 23 +++ sound/soc/codecs/tlv320aic32x4.c | 206 +++++++++++++++++++++ sound/soc/codecs/tlv320aic32x4.h | 3 + 4 files changed, 241 insertions(+) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 9651fc7503a4..ca75890f0d07 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -20,6 +20,8 @@ Optional properties: - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt - clocks/clock-names: Clock named 'mclk' for the master clock of the codec. See clock/clock-bindings.txt for information about the detailed format. + - aic32x4-gpio-func - + - Types are defined in include/sound/tlv320aic32x4.h Example: @@ -29,4 +31,11 @@ codec: tlv320aic32x4@18 { reg = <0x18>; clocks = <&clks 201>; clock-names = "mclk"; + aic32x4-gpio-func= < + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */ + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */ + >; }; diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h index 24e5d991f148..22305c0ab31a 100644 --- a/include/sound/tlv320aic32x4.h +++ b/include/sound/tlv320aic32x4.h @@ -22,7 +22,30 @@ #define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 #define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 +/* GPIO API */ +#define AIC32X4_MFPX_DEFAULT_VALUE 0xff + +#define AIC32X4_MFP1_DIN_DISABLED 0 +#define AIC32X4_MFP1_DIN_ENABLED 0x2 +#define AIC32X4_MFP1_GPIO_IN 0x4 + +#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 + +#define AIC32X4_MFP_GPIO_ENABLED 0x4 + +#define AIC32X4_MFP5_GPIO_DISABLED 0x0 +#define AIC32X4_MFP5_GPIO_INPUT 0x8 +#define AIC32X4_MFP5_GPIO_OUTPUT 0xc +#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 + +struct aic32x4_setup_data { + unsigned int gpio_func[5]; +}; + struct aic32x4_pdata { + struct aic32x4_setup_data *setup; u32 power_cfg; u32 micpga_routing; bool swapdacs; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 28fdfc5ec544..300ee2890df3 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -74,6 +74,152 @@ struct aic32x4_priv { struct regulator *supply_iov; struct regulator *supply_dv; struct regulator *supply_av; + + struct aic32x4_setup_data *setup; + struct device *dev; +}; + +static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + + val = snd_soc_read(codec, AIC32X4_DINCTL); + + ucontrol->value.integer.value[0] = (val & 0x01); + + return 0; +}; + +static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + u8 gpio_check; + + val = snd_soc_read(codec, AIC32X4_DOUTCTL); + gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); + if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { + printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n", + __func__); + return -EINVAL; + } + + if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH)) + return 0; + + if (ucontrol->value.integer.value[0]) + val |= ucontrol->value.integer.value[0]; + else + val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH; + + snd_soc_write(codec, AIC32X4_DOUTCTL, val); + + return 0; +}; + +static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + + val = snd_soc_read(codec, AIC32X4_SCLKCTL); + + ucontrol->value.integer.value[0] = (val & 0x01); + + return 0; +}; + +static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + u8 gpio_check; + + val = snd_soc_read(codec, AIC32X4_MISOCTL); + gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); + if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { + printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n", + __func__); + return -EINVAL; + } + + if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH)) + return 0; + + if (ucontrol->value.integer.value[0]) + val |= ucontrol->value.integer.value[0]; + else + val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH; + + snd_soc_write(codec, AIC32X4_MISOCTL, val); + + return 0; +}; + +static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + + val = snd_soc_read(codec, AIC32X4_GPIOCTL); + ucontrol->value.integer.value[0] = ((val & 0x2) >> 1); + + return 0; +}; + +static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 val; + u8 gpio_check; + + val = snd_soc_read(codec, AIC32X4_GPIOCTL); + gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT); + if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) { + printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n", + __func__); + return -EINVAL; + } + + if (ucontrol->value.integer.value[0] == (val & 0x1)) + return 0; + + if (ucontrol->value.integer.value[0]) + val |= ucontrol->value.integer.value[0]; + else + val &= 0xfe; + + snd_soc_write(codec, AIC32X4_GPIOCTL, val); + + return 0; +}; + +static const struct snd_kcontrol_new aic32x4_mfp1[] = { + SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), +}; + +static const struct snd_kcontrol_new aic32x4_mfp2[] = { + SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), +}; + +static const struct snd_kcontrol_new aic32x4_mfp3[] = { + SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), +}; + +static const struct snd_kcontrol_new aic32x4_mfp4[] = { + SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), +}; + +static const struct snd_kcontrol_new aic32x4_mfp5[] = { + SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, + aic32x4_set_mfp5_gpio), }; /* 0dB min, 0.5dB steps */ @@ -734,6 +880,52 @@ static struct snd_soc_dai_driver aic32x4_dai = { .symmetric_rates = 1, }; +static void aic32x4_setup_gpios(struct snd_soc_codec *codec) +{ + struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); + + /* setup GPIO functions */ + /* MFP1 */ + if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { + snd_soc_write(codec, AIC32X4_DINCTL, + aic32x4->setup->gpio_func[0]); + snd_soc_add_codec_controls(codec, aic32x4_mfp1, + ARRAY_SIZE(aic32x4_mfp1)); + } + + /* MFP2 */ + if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { + snd_soc_write(codec, AIC32X4_DOUTCTL, + aic32x4->setup->gpio_func[1]); + snd_soc_add_codec_controls(codec, aic32x4_mfp2, + ARRAY_SIZE(aic32x4_mfp2)); + } + + /* MFP3 */ + if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { + snd_soc_write(codec, AIC32X4_SCLKCTL, + aic32x4->setup->gpio_func[2]); + snd_soc_add_codec_controls(codec, aic32x4_mfp3, + ARRAY_SIZE(aic32x4_mfp3)); + } + + /* MFP4 */ + if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { + snd_soc_write(codec, AIC32X4_MISOCTL, + aic32x4->setup->gpio_func[3]); + snd_soc_add_codec_controls(codec, aic32x4_mfp4, + ARRAY_SIZE(aic32x4_mfp4)); + } + + /* MFP5 */ + if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { + snd_soc_write(codec, AIC32X4_GPIOCTL, + aic32x4->setup->gpio_func[4]); + snd_soc_add_codec_controls(codec, aic32x4_mfp5, + ARRAY_SIZE(aic32x4_mfp5)); + } +} + static int aic32x4_codec_probe(struct snd_soc_codec *codec) { struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); @@ -746,6 +938,9 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, AIC32X4_RESET, 0x01); + if (aic32x4->setup) + aic32x4_setup_gpios(codec); + /* Power platform configuration */ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { snd_soc_write(codec, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN | @@ -810,10 +1005,20 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) { + struct aic32x4_setup_data *aic32x4_setup; + + aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup), + GFP_KERNEL); + if (!aic32x4_setup) + return -ENOMEM; + aic32x4->swapdacs = false; aic32x4->micpga_routing = 0; aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (of_property_read_u32_array(np, "aic32x4-gpio-func", + aic32x4_setup->gpio_func, 5) >= 0) + aic32x4->setup = aic32x4_setup; return 0; } @@ -932,6 +1137,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) if (aic32x4 == NULL) return -ENOMEM; + aic32x4->dev = dev; dev_set_drvdata(dev, aic32x4); if (pdata) { diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index a197dd51addc..da7cec482bcb 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -44,8 +44,11 @@ int aic32x4_remove(struct device *dev); #define AIC32X4_IFACE4 31 #define AIC32X4_IFACE5 32 #define AIC32X4_IFACE6 33 +#define AIC32X4_GPIOCTL 52 #define AIC32X4_DOUTCTL 53 #define AIC32X4_DINCTL 54 +#define AIC32X4_MISOCTL 55 +#define AIC32X4_SCLKCTL 56 #define AIC32X4_DACSPB 60 #define AIC32X4_ADCSPB 61 #define AIC32X4_DACSETUP 63 -- cgit v1.2.3 From 72a63c6e78887f5c2063ce147b57fdfecf366e0e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:26 -0500 Subject: ASoC: cs42l42: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 55caf5ff3e64..a2324a0e72ee 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -911,7 +911,7 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute) SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops cs42l42_ops = { +static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, -- cgit v1.2.3 From 6ccf3a6d031c47d6319cb56ee35dd4b546905e91 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:36 -0500 Subject: ASoC: rt5663: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 963cda9c995a..71c073c63866 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2888,7 +2888,7 @@ static int rt5663_resume(struct snd_soc_codec *codec) #define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5663_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5663_aif_dai_ops = { .hw_params = rt5663_hw_params, .set_fmt = rt5663_set_dai_fmt, .set_sysclk = rt5663_set_dai_sysclk, -- cgit v1.2.3 From f1d68ea36f4fe97ed1de8d40eaa43758b8386c29 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:43 -0500 Subject: ASoC: rt5616: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 7d6e0823f98f..33bdfe7c394a 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1265,7 +1265,7 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5616_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5616_aif_dai_ops = { .hw_params = rt5616_hw_params, .set_fmt = rt5616_set_dai_fmt, .set_sysclk = rt5616_set_dai_sysclk, -- cgit v1.2.3 From af2f010e0f12fdeb26fce502adf4b353daeb302c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:48 -0500 Subject: ASoC: msm8916-wcd-analog: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index a78802920c3c..aec1e1626993 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -753,7 +753,7 @@ static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, RST_CTL_DIG_SW_RST_N_MASK, 0); } -static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { +static const struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { .startup = pm8916_wcd_analog_startup, .shutdown = pm8916_wcd_analog_shutdown, }; -- cgit v1.2.3 From dfcfd4b68a551b7038e046040dac2a467f5efd10 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:54 -0500 Subject: ASoC: max98926: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 1eff7e0b092e..f16145d8ee6b 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -459,7 +459,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, #define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops max98926_dai_ops = { +static const struct snd_soc_dai_ops max98926_dai_ops = { .set_fmt = max98926_dai_set_fmt, .hw_params = max98926_dai_hw_params, }; -- cgit v1.2.3 From 9894dbafb6f864207f9e6aeaca2c8de949955651 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:37:59 -0500 Subject: ASoC: rt5514: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Also, make rt5514_aif_dai_ops static, as it is not used outside this module. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a71e63097aaf..4ca73bf83cc1 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1006,7 +1006,7 @@ static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val) #define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -struct snd_soc_dai_ops rt5514_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5514_aif_dai_ops = { .hw_params = rt5514_hw_params, .set_fmt = rt5514_set_dai_fmt, .set_sysclk = rt5514_set_dai_sysclk, -- cgit v1.2.3 From a9689bb890ce633c3015ed51e4e2c6ee320fe4dc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:38:14 -0500 Subject: ASoC: codecs: msm8916-wcd-digital: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index f690442af8c9..7e3794fb8c2c 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -788,7 +788,7 @@ static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); } -static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { +static const struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { .startup = msm8916_wcd_digital_startup, .shutdown = msm8916_wcd_digital_shutdown, .hw_params = msm8916_wcd_digital_hw_params, -- cgit v1.2.3 From df9401b47c346480e1c1068f12c1cd32e45809f1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:38:26 -0500 Subject: ASoC: max9867: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 2a40a69a7513..3e421e9d14a5 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -350,7 +350,7 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, return 0; } -static struct snd_soc_dai_ops max9867_dai_ops = { +static const struct snd_soc_dai_ops max9867_dai_ops = { .set_fmt = max9867_dai_set_fmt, .set_sysclk = max9867_set_dai_sysclk, .prepare = max9867_prepare, -- cgit v1.2.3 From fcf005a645e6855d68f98b9455f6b47ac2ed161c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:38:32 -0500 Subject: ASoC: rk3036: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/inno_rk3036.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index b918ba5c8ce5..edf42d252fa1 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -310,7 +310,7 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops rk3036_codec_dai_ops = { +static const struct snd_soc_dai_ops rk3036_codec_dai_ops = { .set_fmt = rk3036_codec_dai_set_fmt, .hw_params = rk3036_codec_dai_hw_params, }; -- cgit v1.2.3 From 61b3b3cc68c4161ba202f401a6572250360ff18c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:38:38 -0500 Subject: ASoC: hdac_hdmi: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index bc2e74ff3b2d..e6de50acefd4 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1360,7 +1360,7 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) } -static struct snd_soc_dai_ops hdmi_dai_ops = { +static const struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, .hw_params = hdac_hdmi_set_hw_params, -- cgit v1.2.3 From 86464ef83af934b7e489c4e100d0136319794010 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Jul 2017 15:38:47 -0500 Subject: ASoC: tas5720: constify snd_soc_dai_ops structure This structure is only stored in the ops field of a snd_soc_dai_driver structure. That field is declared const, so snd_soc_dai_ops structures that have this property can be declared as const also. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index c65b917598d2..01e9ed242378 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -507,7 +507,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5720 = { #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops tas5720_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = { .hw_params = tas5720_hw_params, .set_fmt = tas5720_set_dai_fmt, .set_tdm_slot = tas5720_set_dai_tdm_slot, -- cgit v1.2.3 From d26ed933581d924937aa92251afe1751cf86661c Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Tue, 18 Jul 2017 10:12:58 +0800 Subject: ASoC: rt5663: Modify the default value for ASRC function The patch modifies the default value for ASRC function. It could prevent the pop noise and recording no sound with ASRC function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 71c073c63866..d3f7bc2173e8 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -60,6 +60,7 @@ struct rt5663_priv { static const struct reg_sequence rt5663_patch_list[] = { { 0x002a, 0x8080 }, + { 0x0086, 0x0028 }, }; static const struct reg_default rt5663_v2_reg[] = { @@ -509,7 +510,7 @@ static const struct reg_default rt5663_reg[] = { { 0x0082, 0x0000 }, { 0x0083, 0x0000 }, { 0x0084, 0x0000 }, - { 0x0086, 0x0008 }, + { 0x0086, 0x0028 }, { 0x0087, 0x0000 }, { 0x008a, 0x0000 }, { 0x008b, 0x0000 }, -- cgit v1.2.3 From c7e79b2b2d2d7c13c6162ed8672357f4ad0fd8f5 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 14 Jul 2017 14:25:52 +0800 Subject: ASoC: rt274: add rt274 codec driver RT274 is a HD-A/SOC dual mode codec. This is the initial codec driver of SOC mode. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt274.txt | 33 + sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt274.c | 1228 +++++++++++++++++++++ sound/soc/codecs/rt274.h | 217 ++++ 5 files changed, 1487 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt274.txt create mode 100644 sound/soc/codecs/rt274.c create mode 100644 sound/soc/codecs/rt274.h (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/rt274.txt b/Documentation/devicetree/bindings/sound/rt274.txt new file mode 100644 index 000000000000..e9a6178c78cf --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt274.txt @@ -0,0 +1,33 @@ +RT274 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt274". + +- reg : The I2C address of the device. + +Optional properties: + +- interrupts : The CODEC's interrupt output. + + +Pins on the device (for linking into audio routes) for RT274: + + * DMIC1 Pin + * DMIC2 Pin + * MIC + * LINE1 + * LINE2 + * HPO Pin + * SPDIF + * LINE3 + +Example: + +codec: rt274@1c { + compatible = "realtek,rt274"; + reg = <0x1c>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6c78b0b49b81..024ddc9938ed 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -114,6 +114,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM5102A select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_RT274 if I2C select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C select SND_SOC_RT5514 if I2C @@ -716,11 +717,17 @@ config SND_SOC_RL6231 config SND_SOC_RL6347A tristate + default y if SND_SOC_RT274=y default y if SND_SOC_RT286=y default y if SND_SOC_RT298=y + default m if SND_SOC_RT274=m default m if SND_SOC_RT286=m default m if SND_SOC_RT298=m +config SND_SOC_RT274 + tristate + depends on I2C + config SND_SOC_RT286 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..a8a4b0797f46 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -113,6 +113,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o +snd-soc-rt274-objs := rt274.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o snd-soc-rt5514-objs := rt5514.o @@ -349,6 +350,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o +obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c new file mode 100644 index 000000000000..81e29ba2f50c --- /dev/null +++ b/sound/soc/codecs/rt274.c @@ -0,0 +1,1228 @@ +/* + * rt274.c -- RT274 ALSA SoC audio codec driver + * + * Copyright 2017 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6347a.h" +#include "rt274.h" + +#define RT274_VENDOR_ID 0x10ec0274 + +struct rt274_priv { + struct reg_default *index_cache; + int index_cache_size; + struct regmap *regmap; + struct snd_soc_codec *codec; + struct i2c_client *i2c; + struct snd_soc_jack *jack; + struct delayed_work jack_detect_work; + int sys_clk; + int clk_id; + int fs; + bool master; +}; + +static const struct reg_default rt274_index_def[] = { + { 0x00, 0x1004 }, + { 0x01, 0xaaaa }, + { 0x02, 0x88aa }, + { 0x03, 0x0002 }, + { 0x04, 0xaa09 }, + { 0x05, 0x0700 }, + { 0x06, 0x6110 }, + { 0x07, 0x0200 }, + { 0x08, 0xa807 }, + { 0x09, 0x0021 }, + { 0x0a, 0x7770 }, + { 0x0b, 0x7770 }, + { 0x0c, 0x002b }, + { 0x0d, 0x2420 }, + { 0x0e, 0x65c0 }, + { 0x0f, 0x7770 }, + { 0x10, 0x0420 }, + { 0x11, 0x7418 }, + { 0x12, 0x6bd0 }, + { 0x13, 0x645f }, + { 0x14, 0x0400 }, + { 0x15, 0x8ccc }, + { 0x16, 0x4c50 }, + { 0x17, 0xff00 }, + { 0x18, 0x0003 }, + { 0x19, 0x2c11 }, + { 0x1a, 0x830b }, + { 0x1b, 0x4e4b }, + { 0x1c, 0x0000 }, + { 0x1d, 0x0000 }, + { 0x1e, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x20, 0x51ff }, + { 0x21, 0x8000 }, + { 0x22, 0x8f00 }, + { 0x23, 0x88f4 }, + { 0x24, 0x0000 }, + { 0x25, 0x0000 }, + { 0x26, 0x0000 }, + { 0x27, 0x0000 }, + { 0x28, 0x0000 }, + { 0x29, 0x3000 }, + { 0x2a, 0x0000 }, + { 0x2b, 0x0000 }, + { 0x2c, 0x0f00 }, + { 0x2d, 0x100f }, + { 0x2e, 0x2902 }, + { 0x2f, 0xe280 }, + { 0x30, 0x1000 }, + { 0x31, 0x8400 }, + { 0x32, 0x5aaa }, + { 0x33, 0x8420 }, + { 0x34, 0xa20c }, + { 0x35, 0x096a }, + { 0x36, 0x5757 }, + { 0x37, 0xfe05 }, + { 0x38, 0x4901 }, + { 0x39, 0x110a }, + { 0x3a, 0x0010 }, + { 0x3b, 0x60d9 }, + { 0x3c, 0xf214 }, + { 0x3d, 0xc2ba }, + { 0x3e, 0xa928 }, + { 0x3f, 0x0000 }, + { 0x40, 0x9800 }, + { 0x41, 0x0000 }, + { 0x42, 0x2000 }, + { 0x43, 0x3d90 }, + { 0x44, 0x4900 }, + { 0x45, 0x5289 }, + { 0x46, 0x0004 }, + { 0x47, 0xa47a }, + { 0x48, 0xd049 }, + { 0x49, 0x0049 }, + { 0x4a, 0xa83b }, + { 0x4b, 0x0777 }, + { 0x4c, 0x065c }, + { 0x4d, 0x7fff }, + { 0x4e, 0x7fff }, + { 0x4f, 0x0000 }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0xbf5f }, + { 0x53, 0x3320 }, + { 0x54, 0xcc00 }, + { 0x55, 0x0000 }, + { 0x56, 0x3f00 }, + { 0x57, 0x0000 }, + { 0x58, 0x0000 }, + { 0x59, 0x0000 }, + { 0x5a, 0x1300 }, + { 0x5b, 0x005f }, + { 0x5c, 0x0000 }, + { 0x5d, 0x1001 }, + { 0x5e, 0x1000 }, + { 0x5f, 0x0000 }, + { 0x60, 0x5554 }, + { 0x61, 0xffc0 }, + { 0x62, 0xa000 }, + { 0x63, 0xd010 }, + { 0x64, 0x0000 }, + { 0x65, 0x3fb1 }, + { 0x66, 0x1881 }, + { 0x67, 0xc810 }, + { 0x68, 0x2000 }, + { 0x69, 0xfff0 }, + { 0x6a, 0x0300 }, + { 0x6b, 0x5060 }, + { 0x6c, 0x0000 }, + { 0x6d, 0x0000 }, + { 0x6e, 0x0c25 }, + { 0x6f, 0x0c0b }, + { 0x70, 0x8000 }, + { 0x71, 0x4008 }, + { 0x72, 0x0000 }, + { 0x73, 0x0800 }, + { 0x74, 0xa28f }, + { 0x75, 0xa050 }, + { 0x76, 0x7fe8 }, + { 0x77, 0xdb8c }, + { 0x78, 0x0000 }, + { 0x79, 0x0000 }, + { 0x7a, 0x2a96 }, + { 0x7b, 0x800f }, + { 0x7c, 0x0200 }, + { 0x7d, 0x1600 }, + { 0x7e, 0x0000 }, + { 0x7f, 0x0000 }, +}; +#define INDEX_CACHE_SIZE ARRAY_SIZE(rt274_index_def) + +static const struct reg_default rt274_reg[] = { + { 0x00170500, 0x00000400 }, + { 0x00220000, 0x00000031 }, + { 0x00239000, 0x00000057 }, + { 0x0023a000, 0x00000057 }, + { 0x00270500, 0x00000400 }, + { 0x00370500, 0x00000400 }, + { 0x00870500, 0x00000400 }, + { 0x00920000, 0x00000031 }, + { 0x00935000, 0x00000097 }, + { 0x00936000, 0x00000097 }, + { 0x00970500, 0x00000400 }, + { 0x00b37000, 0x00000400 }, + { 0x00b37200, 0x00000400 }, + { 0x00b37300, 0x00000400 }, + { 0x00c37000, 0x00000400 }, + { 0x00c37100, 0x00000400 }, + { 0x01270500, 0x00000400 }, + { 0x01370500, 0x00000400 }, + { 0x01371f00, 0x411111f0 }, + { 0x01937000, 0x00000000 }, + { 0x01970500, 0x00000400 }, + { 0x02050000, 0x0000001b }, + { 0x02139000, 0x00000080 }, + { 0x0213a000, 0x00000080 }, + { 0x02170100, 0x00000001 }, + { 0x02170500, 0x00000400 }, + { 0x02170700, 0x00000000 }, + { 0x02270100, 0x00000000 }, + { 0x02370100, 0x00000000 }, + { 0x01970700, 0x00000020 }, + { 0x00830000, 0x00000097 }, + { 0x00930000, 0x00000097 }, + { 0x01270700, 0x00000000 }, +}; + +static bool rt274_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT274_GET_HP_SENSE: + case RT274_GET_MIC_SENSE: + case RT274_PROC_COEF: + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0): + return true; + default: + return false; + } + + +} + +static bool rt274_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT274_GET_HP_SENSE: + case RT274_GET_MIC_SENSE: + case RT274_SET_AUDIO_POWER: + case RT274_SET_HPO_POWER: + case RT274_SET_DMIC1_POWER: + case RT274_LOUT_MUX: + case RT274_HPO_MUX: + case RT274_ADC0_MUX: + case RT274_ADC1_MUX: + case RT274_SET_MIC: + case RT274_SET_PIN_HPO: + case RT274_SET_PIN_LOUT3: + case RT274_SET_PIN_DMIC1: + case RT274_SET_AMP_GAIN_HPO: + case RT274_SET_DMIC2_DEFAULT: + case RT274_DAC0L_GAIN: + case RT274_DAC0R_GAIN: + case RT274_DAC1L_GAIN: + case RT274_DAC1R_GAIN: + case RT274_ADCL_GAIN: + case RT274_ADCR_GAIN: + case RT274_MIC_GAIN: + case RT274_HPOL_GAIN: + case RT274_HPOR_GAIN: + case RT274_LOUTL_GAIN: + case RT274_LOUTR_GAIN: + case RT274_DAC_FORMAT: + case RT274_ADC_FORMAT: + case RT274_COEF_INDEX: + case RT274_PROC_COEF: + case RT274_SET_AMP_GAIN_ADC_IN1: + case RT274_SET_AMP_GAIN_ADC_IN2: + case RT274_SET_POWER(RT274_DAC_OUT0): + case RT274_SET_POWER(RT274_DAC_OUT1): + case RT274_SET_POWER(RT274_ADC_IN1): + case RT274_SET_POWER(RT274_ADC_IN2): + case RT274_SET_POWER(RT274_DMIC2): + case RT274_SET_POWER(RT274_MIC): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0): + case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0): + case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0): + case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0): + case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0): + case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0): + return true; + default: + return false; + } +} + +#ifdef CONFIG_PM +static void rt274_index_sync(struct snd_soc_codec *codec) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + int i; + + for (i = 0; i < INDEX_CACHE_SIZE; i++) { + snd_soc_write(codec, rt274->index_cache[i].reg, + rt274->index_cache[i].def); + } +} +#endif + +static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) +{ + unsigned int buf; + + *hp = false; + *mic = false; + + if (!rt274->codec) + return -EINVAL; + + regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + *mic = buf & 0x80000000; + + pr_debug("*hp = %d *mic = %d\n", *hp, *mic); + + return 0; +} + +static void rt274_jack_detect_work(struct work_struct *work) +{ + struct rt274_priv *rt274 = + container_of(work, struct rt274_priv, jack_detect_work.work); + int status = 0; + bool hp = false; + bool mic = false; + + if (rt274_jack_detect(rt274, &hp, &mic) < 0) + return; + + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt274->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); +} + +static irqreturn_t rt274_irq(int irq, void *data); + +static int rt274_mic_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, void *data) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + if (jack == NULL) { + /* Disable jack detection */ + regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, + RT274_IRQ_EN, RT274_IRQ_DIS); + + return 0; + } + rt274->jack = jack; + + regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, + RT274_IRQ_EN, RT274_IRQ_EN); + + /* Send an initial report */ + rt274_irq(0, rt274); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt274_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT274_DAC0L_GAIN, + RT274_DAC0R_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R_TLV("DAC1 Playback Volume", RT274_DAC1L_GAIN, + RT274_DAC1R_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT274_ADCL_GAIN, + RT274_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R("ADC0 Capture Switch", RT274_ADCL_GAIN, + RT274_ADCR_GAIN, RT274_MUTE_SFT, 1, 1), + SOC_SINGLE_TLV("AMIC Volume", RT274_MIC_GAIN, + 0, 0x3, 0, mic_vol_tlv), +}; + +static const struct snd_kcontrol_new hpol_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOL_GAIN, + RT274_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpor_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOR_GAIN, + RT274_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new loutl_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTL_GAIN, + RT274_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new loutr_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTR_GAIN, + RT274_MUTE_SFT, 1, 1); + +/* ADC0 source */ +static const char * const rt274_adc_src[] = { + "Mic", "Line1", "Line2", "Dmic" +}; + +static SOC_ENUM_SINGLE_DECL( + rt274_adc0_enum, RT274_ADC0_MUX, RT274_ADC_SEL_SFT, + rt274_adc_src); + +static const struct snd_kcontrol_new rt274_adc0_mux = + SOC_DAPM_ENUM("ADC 0 source", rt274_adc0_enum); + +static SOC_ENUM_SINGLE_DECL( + rt274_adc1_enum, RT274_ADC1_MUX, RT274_ADC_SEL_SFT, + rt274_adc_src); + +static const struct snd_kcontrol_new rt274_adc1_mux = + SOC_DAPM_ENUM("ADC 1 source", rt274_adc1_enum); + +static const char * const rt274_dac_src[] = { + "DAC OUT0", "DAC OUT1" +}; +/* HP-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt274_hpo_enum, RT274_HPO_MUX, + 0, rt274_dac_src); + +static const struct snd_kcontrol_new rt274_hpo_mux = +SOC_DAPM_ENUM("HPO source", rt274_hpo_enum); + +/* Line out source */ +static SOC_ENUM_SINGLE_DECL(rt274_lout_enum, RT274_LOUT_MUX, + 0, rt274_dac_src); + +static const struct snd_kcontrol_new rt274_lout_mux = +SOC_DAPM_ENUM("LOUT source", rt274_lout_enum); + +static const struct snd_soc_dapm_widget rt274_dapm_widgets[] = { + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC1 Pin"), + SND_SOC_DAPM_INPUT("DMIC2 Pin"), + SND_SOC_DAPM_INPUT("MIC"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + + /* DMIC */ + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC 0", NULL, RT274_SET_STREAMID_ADC1, 4, 0), + SND_SOC_DAPM_ADC("ADC 1", NULL, RT274_SET_STREAMID_ADC2, 4, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("ADC 0 Mux", SND_SOC_NOPM, 0, 0, + &rt274_adc0_mux), + SND_SOC_DAPM_MUX("ADC 1 Mux", SND_SOC_NOPM, 0, 0, + &rt274_adc1_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RXL", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF1RXR", "AIF1 Playback", 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TXL", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TXR", "AIF1 Capture", 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RXL", "AIF1 Playback", 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RXR", "AIF1 Playback", 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TXL", "AIF1 Capture", 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TXR", "AIF1 Capture", 3, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DACs */ + SND_SOC_DAPM_DAC("DAC 0", NULL, RT274_SET_STREAMID_DAC0, 4, 0), + SND_SOC_DAPM_DAC("DAC 1", NULL, RT274_SET_STREAMID_DAC1, 4, 0), + + /* Output Mux */ + SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt274_hpo_mux), + SND_SOC_DAPM_MUX("LOUT Mux", SND_SOC_NOPM, 0, 0, &rt274_lout_mux), + + SND_SOC_DAPM_SUPPLY("HP Power", RT274_SET_PIN_HPO, + RT274_SET_PIN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LOUT Power", RT274_SET_PIN_LOUT3, + RT274_SET_PIN_SFT, 0, NULL, 0), + + /* Output Mixer */ + SND_SOC_DAPM_PGA("DAC OUT0", SND_SOC_NOPM, 0, 0, + NULL, 0), + SND_SOC_DAPM_PGA("DAC OUT1", SND_SOC_NOPM, 0, 0, + NULL, 0), + + /* Output Pga */ + SND_SOC_DAPM_SWITCH("LOUT L", SND_SOC_NOPM, 0, 0, + &loutl_enable_control), + SND_SOC_DAPM_SWITCH("LOUT R", SND_SOC_NOPM, 0, 0, + &loutr_enable_control), + SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, + &hpol_enable_control), + SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, + &hpor_enable_control), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPO Pin"), + SND_SOC_DAPM_OUTPUT("SPDIF"), + SND_SOC_DAPM_OUTPUT("LINE3"), +}; + +static const struct snd_soc_dapm_route rt274_dapm_routes[] = { + {"DMIC1", NULL, "DMIC1 Pin"}, + {"DMIC2", NULL, "DMIC2 Pin"}, + + {"ADC 0 Mux", "Mic", "MIC"}, + {"ADC 0 Mux", "Dmic", "DMIC1"}, + {"ADC 0 Mux", "Line1", "LINE1"}, + {"ADC 0 Mux", "Line2", "LINE2"}, + {"ADC 1 Mux", "Mic", "MIC"}, + {"ADC 1 Mux", "Dmic", "DMIC2"}, + {"ADC 1 Mux", "Line1", "LINE1"}, + {"ADC 1 Mux", "Line2", "LINE2"}, + + {"ADC 0", NULL, "ADC 0 Mux"}, + {"ADC 1", NULL, "ADC 1 Mux"}, + + {"AIF1TXL", NULL, "ADC 0"}, + {"AIF1TXR", NULL, "ADC 0"}, + {"AIF2TXL", NULL, "ADC 1"}, + {"AIF2TXR", NULL, "ADC 1"}, + + {"DAC 0", NULL, "AIF1RXL"}, + {"DAC 0", NULL, "AIF1RXR"}, + {"DAC 1", NULL, "AIF2RXL"}, + {"DAC 1", NULL, "AIF2RXR"}, + + {"DAC OUT0", NULL, "DAC 0"}, + + {"DAC OUT1", NULL, "DAC 1"}, + + {"LOUT Mux", "DAC OUT0", "DAC OUT0"}, + {"LOUT Mux", "DAC OUT1", "DAC OUT1"}, + + {"LOUT L", "Switch", "LOUT Mux"}, + {"LOUT R", "Switch", "LOUT Mux"}, + {"LOUT L", NULL, "LOUT Power"}, + {"LOUT R", NULL, "LOUT Power"}, + + {"LINE3", NULL, "LOUT L"}, + {"LINE3", NULL, "LOUT R"}, + + {"HPO Mux", "DAC OUT0", "DAC OUT0"}, + {"HPO Mux", "DAC OUT1", "DAC OUT1"}, + + {"HPO L", "Switch", "HPO Mux"}, + {"HPO R", "Switch", "HPO Mux"}, + {"HPO L", NULL, "HP Power"}, + {"HPO R", NULL, "HP Power"}, + + {"HPO Pin", NULL, "HPO L"}, + {"HPO Pin", NULL, "HPO R"}, +}; + +static int rt274_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + int d_len_code = 0, c_len_code = 0; + + switch (params_rate(params)) { + /* bit 14 0:48K 1:44.1K */ + case 44100: + case 48000: + break; + default: + dev_err(codec->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + switch (rt274->sys_clk) { + case 12288000: + case 24576000: + if (params_rate(params) != 48000) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt274->sys_clk); + return -EINVAL; + } + break; + case 11289600: + case 22579200: + if (params_rate(params) != 44100) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt274->sys_clk); + return -EINVAL; + } + break; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(codec->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 16: + d_len_code = 0; + c_len_code = 0; + val |= (0x1 << 4); + break; + case 32: + d_len_code = 2; + c_len_code = 3; + val |= (0x4 << 4); + break; + case 20: + d_len_code = 1; + c_len_code = 1; + val |= (0x2 << 4); + break; + case 24: + d_len_code = 2; + c_len_code = 2; + val |= (0x3 << 4); + break; + case 8: + d_len_code = 3; + c_len_code = 0; + break; + default: + return -EINVAL; + } + + if (rt274->master) + c_len_code = 0x3; + + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, 0xc018, d_len_code << 3 | c_len_code << 14); + dev_dbg(codec->dev, "format val = 0x%x\n", val); + + snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x407f, val); + snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x407f, val); + + return 0; +} + +static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M); + rt274->master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S); + rt274->master = false; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + snd_soc_update_bits(codec, RT274_I2S_CTRL1, + RT274_I2S_FMT_MASK, RT274_I2S_FMT_I2S); + break; + case SND_SOC_DAIFMT_LEFT_J: + snd_soc_update_bits(codec, RT274_I2S_CTRL1, + RT274_I2S_FMT_MASK, RT274_I2S_FMT_LJ); + break; + case SND_SOC_DAIFMT_DSP_A: + snd_soc_update_bits(codec, RT274_I2S_CTRL1, + RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMA); + break; + case SND_SOC_DAIFMT_DSP_B: + snd_soc_update_bits(codec, RT274_I2S_CTRL1, + RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMB); + break; + default: + return -EINVAL; + } + /* bit 15 Stream Type 0:PCM 1:Non-PCM */ + snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x8000, 0); + snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x8000, 0); + + return 0; +} + +static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + switch (source) { + case RT274_PLL2_S_MCLK: + snd_soc_update_bits(codec, RT274_PLL2_CTRL, + RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_MCLK); + break; + default: + dev_warn(codec->dev, "invalid pll source, use BCLK\n"); + case RT274_PLL2_S_BCLK: + snd_soc_update_bits(codec, RT274_PLL2_CTRL, + RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK); + break; + } + + if (source == RT274_PLL2_S_BCLK) { + snd_soc_update_bits(codec, RT274_MCLK_CTRL, + (0x3 << 12), (0x3 << 12)); + switch (rt274->fs) { + case 50: + snd_soc_write(codec, 0x7a, 0xaab6); + snd_soc_write(codec, 0x7b, 0x0301); + snd_soc_write(codec, 0x7c, 0x04fe); + break; + case 64: + snd_soc_write(codec, 0x7a, 0xaa96); + snd_soc_write(codec, 0x7b, 0x8003); + snd_soc_write(codec, 0x7c, 0x081e); + break; + case 128: + snd_soc_write(codec, 0x7a, 0xaa96); + snd_soc_write(codec, 0x7b, 0x8003); + snd_soc_write(codec, 0x7c, 0x080e); + break; + default: + dev_warn(codec->dev, "invalid freq_in, assume 4.8M\n"); + case 100: + snd_soc_write(codec, 0x7a, 0xaab6); + snd_soc_write(codec, 0x7b, 0x0301); + snd_soc_write(codec, 0x7c, 0x047e); + break; + } + } + + return 0; +} + +static int rt274_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + unsigned int clk_src, mclk_en; + + dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); + + switch (clk_id) { + case RT274_SCLK_S_MCLK: + mclk_en = RT274_MCLK_MODE_EN; + clk_src = RT274_CLK_SRC_MCLK; + break; + case RT274_SCLK_S_PLL1: + mclk_en = RT274_MCLK_MODE_DIS; + clk_src = RT274_CLK_SRC_MCLK; + break; + case RT274_SCLK_S_PLL2: + mclk_en = RT274_MCLK_MODE_EN; + clk_src = RT274_CLK_SRC_PLL2; + break; + default: + mclk_en = RT274_MCLK_MODE_DIS; + clk_src = RT274_CLK_SRC_MCLK; + dev_warn(codec->dev, "invalid sysclk source, use PLL1\n"); + break; + } + snd_soc_update_bits(codec, RT274_MCLK_CTRL, + RT274_MCLK_MODE_MASK, mclk_en); + snd_soc_update_bits(codec, RT274_CLK_CTRL, + RT274_CLK_SRC_MASK, clk_src); + + switch (freq) { + case 19200000: + if (clk_id == RT274_SCLK_S_MCLK) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT274_I2S_CTRL2, 0x40, 0x40); + break; + case 24000000: + if (clk_id == RT274_SCLK_S_MCLK) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT274_I2S_CTRL2, 0x40, 0x0); + break; + case 12288000: + case 11289600: + snd_soc_update_bits(codec, + RT274_MCLK_CTRL, 0x1fcf, 0x0008); + break; + case 24576000: + case 22579200: + snd_soc_update_bits(codec, + RT274_MCLK_CTRL, 0x1fcf, 0x1543); + break; + default: + dev_err(codec->dev, "Unsupported system clock\n"); + return -EINVAL; + } + + rt274->sys_clk = freq; + rt274->clk_id = clk_id; + + return 0; +} + +static int rt274_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + rt274->fs = ratio; + if ((ratio / 50) == 0) + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, 0x1000, 0x1000); + else + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, 0x1000, 0x0); + + + return 0; +} + +static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) + +{ + struct snd_soc_codec *codec = dai->codec; + + if (rx_mask || tx_mask) { + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_EN); + } else { + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_DIS); + return 0; + } + + switch (slots) { + case 4: + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_4CH); + break; + case 2: + snd_soc_update_bits(codec, + RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_2CH); + break; + default: + dev_err(codec->dev, + "Support 2 or 4 slots TDM only\n"); + return -EINVAL; + } + + return 0; +} + +static int rt274_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == + snd_soc_codec_get_bias_level(codec)) { + snd_soc_write(codec, + RT274_SET_AUDIO_POWER, AC_PWRST_D0); + } + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, + RT274_SET_AUDIO_POWER, AC_PWRST_D3); + break; + + default: + break; + } + + return 0; +} + +static irqreturn_t rt274_irq(int irq, void *data) +{ + struct rt274_priv *rt274 = data; + bool hp = false; + bool mic = false; + int ret, status = 0; + + /* Clear IRQ */ + regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, + RT274_IRQ_CLR, RT274_IRQ_CLR); + + ret = rt274_jack_detect(rt274, &hp, &mic); + + if (ret == 0) { + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt274->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + pm_wakeup_event(&rt274->i2c->dev, 300); + } + + return IRQ_HANDLED; +} + +static int rt274_probe(struct snd_soc_codec *codec) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + rt274->codec = codec; + + if (rt274->i2c->irq) { + INIT_DELAYED_WORK(&rt274->jack_detect_work, + rt274_jack_detect_work); + schedule_delayed_work(&rt274->jack_detect_work, + msecs_to_jiffies(1250)); + } + + return 0; +} + +static int rt274_remove(struct snd_soc_codec *codec) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + cancel_delayed_work_sync(&rt274->jack_detect_work); + + return 0; +} + +#ifdef CONFIG_PM +static int rt274_suspend(struct snd_soc_codec *codec) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt274->regmap, true); + regcache_mark_dirty(rt274->regmap); + + return 0; +} + +static int rt274_resume(struct snd_soc_codec *codec) +{ + struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt274->regmap, false); + rt274_index_sync(codec); + regcache_sync(rt274->regmap); + + return 0; +} +#else +#define rt274_suspend NULL +#define rt274_resume NULL +#endif + +#define RT274_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT274_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt274_aif_dai_ops = { + .hw_params = rt274_hw_params, + .set_fmt = rt274_set_dai_fmt, + .set_sysclk = rt274_set_dai_sysclk, + .set_pll = rt274_set_dai_pll, + .set_bclk_ratio = rt274_set_bclk_ratio, + .set_tdm_slot = rt274_set_tdm_slot, +}; + +static struct snd_soc_dai_driver rt274_dai[] = { + { + .name = "rt274-aif1", + .id = RT274_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT274_STEREO_RATES, + .formats = RT274_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT274_STEREO_RATES, + .formats = RT274_FORMATS, + }, + .ops = &rt274_aif_dai_ops, + .symmetric_rates = 1, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt274 = { + .probe = rt274_probe, + .remove = rt274_remove, + .suspend = rt274_suspend, + .resume = rt274_resume, + .set_bias_level = rt274_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt274_snd_controls, + .num_controls = ARRAY_SIZE(rt274_snd_controls), + .dapm_widgets = rt274_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt274_dapm_widgets), + .dapm_routes = rt274_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt274_dapm_routes), + }, + .set_jack = rt274_mic_detect, +}; + +static const struct regmap_config rt274_regmap = { + .reg_bits = 32, + .val_bits = 32, + .max_register = 0x05bfffff, + .volatile_reg = rt274_volatile_register, + .readable_reg = rt274_readable_register, + .reg_write = rl6347a_hw_write, + .reg_read = rl6347a_hw_read, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt274_reg, + .num_reg_defaults = ARRAY_SIZE(rt274_reg), +}; + +#ifdef CONFIG_OF +static const struct of_device_id rt274_of_match[] = { + {.compatible = "realtek,rt274"}, + {}, +}; +MODULE_DEVICE_TABLE(of, rt274_of_match); +#endif + +static const struct i2c_device_id rt274_i2c_id[] = { + {"rt274", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt274_i2c_id); + +static const struct acpi_device_id rt274_acpi_match[] = { + { "10EC0274", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt274_acpi_match); + +static int rt274_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt274_priv *rt274; + + int ret; + unsigned int val; + + rt274 = devm_kzalloc(&i2c->dev, sizeof(*rt274), + GFP_KERNEL); + if (rt274 == NULL) + return -ENOMEM; + + rt274->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt274_regmap); + if (IS_ERR(rt274->regmap)) { + ret = PTR_ERR(rt274->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt274->regmap, + RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val); + if (val != RT274_VENDOR_ID) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt274\n", val); + return -ENODEV; + } + + rt274->index_cache = devm_kmemdup(&i2c->dev, rt274_index_def, + sizeof(rt274_index_def), GFP_KERNEL); + if (!rt274->index_cache) + return -ENOMEM; + + rt274->index_cache_size = INDEX_CACHE_SIZE; + rt274->i2c = i2c; + i2c_set_clientdata(i2c, rt274); + + /* reset codec */ + regmap_write(rt274->regmap, RT274_RESET, 0); + regmap_update_bits(rt274->regmap, 0x1a, 0x4000, 0x4000); + + /* Set Pad PDB is floating */ + regmap_update_bits(rt274->regmap, RT274_PAD_CTRL12, 0x3, 0x0); + regmap_write(rt274->regmap, RT274_COEF5b_INDEX, 0x01); + regmap_write(rt274->regmap, RT274_COEF5b_COEF, 0x8540); + regmap_update_bits(rt274->regmap, 0x6f, 0x0100, 0x0100); + /* Combo jack auto detect */ + regmap_write(rt274->regmap, 0x4a, 0x201b); + /* Aux mode off */ + regmap_update_bits(rt274->regmap, 0x6f, 0x3000, 0x2000); + /* HP DC Calibration */ + regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0x0); + //Set NID=58h.Index 00h [15]= 1b; + regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00); + regmap_write(rt274->regmap, RT274_COEF58_COEF, 0xb888); + msleep(500); + regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0xb); + regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00); + regmap_write(rt274->regmap, RT274_COEF58_COEF, 0x3888); + /* Set pin widget */ + regmap_write(rt274->regmap, RT274_SET_PIN_HPO, 0x40); + regmap_write(rt274->regmap, RT274_SET_PIN_LOUT3, 0x40); + regmap_write(rt274->regmap, RT274_SET_MIC, 0x20); + regmap_write(rt274->regmap, RT274_SET_PIN_DMIC1, 0x20); + + regmap_update_bits(rt274->regmap, RT274_I2S_CTRL2, 0xc004, 0x4004); + regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, + RT274_GPI2_SEL_MASK, RT274_GPI2_SEL_DMIC_CLK); + + /* jack detection */ + regmap_write(rt274->regmap, RT274_UNSOLICITED_HP_OUT, 0x81); + regmap_write(rt274->regmap, RT274_UNSOLICITED_MIC, 0x82); + + if (rt274->i2c->irq) { + ret = request_threaded_irq(rt274->i2c->irq, NULL, rt274_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt274", rt274); + if (ret != 0) { + dev_err(&i2c->dev, + "Failed to reguest IRQ: %d\n", ret); + return ret; + } + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt274, + rt274_dai, ARRAY_SIZE(rt274_dai)); + + return ret; +} + +static int rt274_i2c_remove(struct i2c_client *i2c) +{ + struct rt274_priv *rt274 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt274); + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + + +static struct i2c_driver rt274_i2c_driver = { + .driver = { + .name = "rt274", + .acpi_match_table = ACPI_PTR(rt274_acpi_match), +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rt274_of_match), +#endif + }, + .probe = rt274_i2c_probe, + .remove = rt274_i2c_remove, + .id_table = rt274_i2c_id, +}; + +module_i2c_driver(rt274_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT274 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt274.h b/sound/soc/codecs/rt274.h new file mode 100644 index 000000000000..4fd1bcb73dba --- /dev/null +++ b/sound/soc/codecs/rt274.h @@ -0,0 +1,217 @@ +/* + * rt274.h -- RT274 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT274_H__ +#define __RT274_H__ + +#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) + +#define RT274_AUDIO_FUNCTION_GROUP 0x01 +#define RT274_DAC_OUT0 0x02 +#define RT274_DAC_OUT1 0x03 +#define RT274_ADC_IN2 0x08 +#define RT274_ADC_IN1 0x09 +#define RT274_DIG_CVT 0x0a +#define RT274_DMIC1 0x12 +#define RT274_DMIC2 0x13 +#define RT274_MIC 0x19 +#define RT274_LINE1 0x1a +#define RT274_LINE2 0x1b +#define RT274_LINE3 0x16 +#define RT274_SPDIF 0x1e +#define RT274_VENDOR_REGISTERS 0x20 +#define RT274_HP_OUT 0x21 +#define RT274_MIXER_IN1 0x22 +#define RT274_MIXER_IN2 0x23 +#define RT274_INLINE_CMD 0x55 + +#define RT274_SET_PIN_SFT 6 +#define RT274_SET_PIN_ENABLE 0x40 +#define RT274_SET_PIN_DISABLE 0 +#define RT274_SET_EAPD_HIGH 0x2 +#define RT274_SET_EAPD_LOW 0 + +#define RT274_MUTE_SFT 7 + +/* Verb commands */ +#define RT274_RESET\ + VERB_CMD(AC_VERB_SET_CODEC_RESET, RT274_AUDIO_FUNCTION_GROUP, 0) +#define RT274_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) +#define RT274_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) +#define RT274_SET_AUDIO_POWER RT274_SET_POWER(RT274_AUDIO_FUNCTION_GROUP) +#define RT274_SET_HPO_POWER RT274_SET_POWER(RT274_HP_OUT) +#define RT274_SET_DMIC1_POWER RT274_SET_POWER(RT274_DMIC1) +#define RT274_LOUT_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_LINE3, 0) +#define RT274_HPO_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_HP_OUT, 0) +#define RT274_ADC0_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN1, 0) +#define RT274_ADC1_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN2, 0) +#define RT274_SET_MIC\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_MIC, 0) +#define RT274_SET_PIN_LOUT3\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_LINE3, 0) +#define RT274_SET_PIN_HPO\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0) +#define RT274_SET_PIN_DMIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0) +#define RT274_SET_PIN_SPDIF\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_SPDIF, 0) +#define RT274_SET_PIN_DIG_CVT\ + VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT274_DIG_CVT, 0) +#define RT274_SET_AMP_GAIN_HPO\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0) +#define RT274_SET_AMP_GAIN_ADC_IN1\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0) +#define RT274_SET_AMP_GAIN_ADC_IN2\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0) +#define RT274_GET_HP_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_HP_OUT, 0) +#define RT274_GET_MIC_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_MIC, 0) +#define RT274_SET_DMIC2_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_DMIC2, 0) +#define RT274_SET_SPDIF_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_SPDIF, 0) +#define RT274_DAC0L_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0xa000) +#define RT274_DAC0R_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0x9000) +#define RT274_DAC1L_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0xa000) +#define RT274_DAC1R_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0x9000) +#define RT274_ADCL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x6000) +#define RT274_ADCR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x5000) +#define RT274_MIC_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_MIC, 0x7000) +#define RT274_LOUTL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0xa000) +#define RT274_LOUTR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0x9000) +#define RT274_HPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0xa000) +#define RT274_HPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0x9000) +#define RT274_DAC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_DAC_OUT0, 0) +#define RT274_ADC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_ADC_IN1, 0) +#define RT274_COEF_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, RT274_VENDOR_REGISTERS, 0) +#define RT274_PROC_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, RT274_VENDOR_REGISTERS, 0) +#define RT274_UNSOLICITED_INLINE_CMD\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_INLINE_CMD, 0) +#define RT274_UNSOLICITED_HP_OUT\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_HP_OUT, 0) +#define RT274_UNSOLICITED_MIC\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_MIC, 0) +#define RT274_COEF58_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x58, 0) +#define RT274_COEF58_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, 0x58, 0) +#define RT274_COEF5b_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x5b, 0) +#define RT274_COEF5b_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, 0x5b, 0) +#define RT274_SET_STREAMID_DAC0\ + VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT0, 0) +#define RT274_SET_STREAMID_DAC1\ + VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT1, 0) +#define RT274_SET_STREAMID_ADC1\ + VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN1, 0) +#define RT274_SET_STREAMID_ADC2\ + VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN2, 0) + +/* Index registers */ +#define RT274_EAPD_GPIO_IRQ_CTRL 0x10 +#define RT274_PAD_CTRL12 0x35 +#define RT274_I2S_CTRL1 0x63 +#define RT274_I2S_CTRL2 0x64 +#define RT274_MCLK_CTRL 0x71 +#define RT274_CLK_CTRL 0x72 +#define RT274_PLL2_CTRL 0x7b + + +/* EAPD GPIO IRQ control (Index 0x10) */ +#define RT274_IRQ_DIS (0x0 << 13) +#define RT274_IRQ_EN (0x1 << 13) +#define RT274_IRQ_CLR (0x1 << 12) +#define RT274_GPI2_SEL_MASK (0x3 << 7) +#define RT274_GPI2_SEL_GPIO2 (0x0 << 7) +#define RT274_GPI2_SEL_I2S (0x1 << 7) +#define RT274_GPI2_SEL_DMIC_CLK (0x2 << 7) +#define RT274_GPI2_SEL_CBJ (0x3 << 7) + +/* Front I2S_Interface control 1 (Index 0x63) */ +#define RT274_I2S_MODE_MASK (0x1 << 11) +#define RT274_I2S_MODE_S (0x0 << 11) +#define RT274_I2S_MODE_M (0x1 << 11) +#define RT274_TDM_DIS (0x0 << 10) +#define RT274_TDM_EN (0x1 << 10) +#define RT274_TDM_CH_NUM (0x1 << 7) +#define RT274_TDM_2CH (0x0 << 7) +#define RT274_TDM_4CH (0x1 << 7) +#define RT274_I2S_FMT_MASK (0x3 << 8) +#define RT274_I2S_FMT_I2S (0x0 << 8) +#define RT274_I2S_FMT_LJ (0x1 << 8) +#define RT274_I2S_FMT_PCMA (0x2 << 8) +#define RT274_I2S_FMT_PCMB (0x3 << 8) + +/* MCLK clock domain control (Index 0x71) */ +#define RT274_MCLK_MODE_MASK (0x1 << 14) +#define RT274_MCLK_MODE_DIS (0x0 << 14) +#define RT274_MCLK_MODE_EN (0x1 << 14) + +/* Clock control (Index 0x72) */ +#define RT274_CLK_SRC_MASK (0x7 << 3) +#define RT274_CLK_SRC_MCLK (0x0 << 3) +#define RT274_CLK_SRC_PLL2 (0x3 << 3) + +/* PLL2 control (Index 0x7b) */ +#define RT274_PLL2_SRC_MASK (0x1 << 13) +#define RT274_PLL2_SRC_MCLK (0x0 << 13) +#define RT274_PLL2_SRC_BCLK (0x1 << 13) + +/* HP-OUT (0x21) */ +#define RT274_M_HP_MUX_SFT 14 +#define RT274_HP_SEL_MASK 0x1 +#define RT274_HP_SEL_SFT 0 +#define RT274_HP_SEL_F 0 +#define RT274_HP_SEL_S 1 + +/* ADC (0x22) (0x23) */ +#define RT274_ADC_SEL_MASK 0x7 +#define RT274_ADC_SEL_SFT 0 +#define RT274_ADC_SEL_MIC 0 +#define RT274_ADC_SEL_LINE1 1 +#define RT274_ADC_SEL_LINE2 2 +#define RT274_ADC_SEL_DMIC 3 + +#define RT274_SCLK_S_MCLK 0 +#define RT274_SCLK_S_PLL1 1 +#define RT274_SCLK_S_PLL2 2 + +#define RT274_PLL2_S_MCLK 0 +#define RT274_PLL2_S_BCLK 1 + +enum { + RT274_AIF1, + RT274_AIFS, +}; + +#endif /* __RT274_H__ */ + -- cgit v1.2.3 From 49a69163ddbe47063be960ad5c2fcfe94c8b473b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 19 Jul 2017 09:52:12 +0800 Subject: ASoC: rt274: correct comment style There was a comment style issue in the driver. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 81e29ba2f50c..fb683ffc4e03 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1159,7 +1159,7 @@ static int rt274_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt274->regmap, 0x6f, 0x3000, 0x2000); /* HP DC Calibration */ regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0x0); - //Set NID=58h.Index 00h [15]= 1b; + /* Set NID=58h.Index 00h [15]= 1b; */ regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00); regmap_write(rt274->regmap, RT274_COEF58_COEF, 0xb888); msleep(500); -- cgit v1.2.3 From 1d5c5b6582cf829fc4c0c8eef6b9f9f0dc29c7b2 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Wed, 19 Jul 2017 10:20:23 +0800 Subject: ASoC: rt5663: Correct the mixer switch setting and remove redundant routing path The patch corrects the mixer siwtch setting that was the mistake in the previous commitment. And remove the redundant routing paths. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index d3f7bc2173e8..45f8a9888f7d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -59,7 +59,7 @@ struct rt5663_priv { }; static const struct reg_sequence rt5663_patch_list[] = { - { 0x002a, 0x8080 }, + { 0x002a, 0x8020 }, { 0x0086, 0x0028 }, }; @@ -482,7 +482,7 @@ static const struct reg_default rt5663_reg[] = { { 0x0023, 0x0039 }, { 0x0026, 0xc0c0 }, { 0x0029, 0x8080 }, - { 0x002a, 0x8080 }, + { 0x002a, 0x8020 }, { 0x002c, 0x000c }, { 0x002d, 0x0000 }, { 0x0040, 0x0808 }, @@ -1967,8 +1967,8 @@ static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { }; static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { - SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, - RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, + RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1), }; /* Out Switch */ @@ -2358,11 +2358,9 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { { "DAC R1", NULL, "ADDA MIXR" }, { "STO1 DAC MIXL", "DAC L Switch", "DAC L1" }, - { "STO1 DAC MIXL", "DAC R Switch", "DAC R1" }, { "STO1 DAC MIXL", NULL, "STO1 DAC L Power" }, { "STO1 DAC MIXL", NULL, "STO1 DAC Filter" }, { "STO1 DAC MIXR", "DAC R Switch", "DAC R1" }, - { "STO1 DAC MIXR", "DAC L Switch", "DAC L1" }, { "STO1 DAC MIXR", NULL, "STO1 DAC R Power" }, { "STO1 DAC MIXR", NULL, "STO1 DAC Filter" }, -- cgit v1.2.3 From ddc9e69b9dc23d4c0d8ed829575327746ea77a04 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 20:34:17 +0300 Subject: ASoC: rt5677: Hide platform data in the module sources There is no user of legacy platform data. Remove separate header and hide its content inside module sources. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- include/sound/rt5677.h | 45 --------------------------------------------- sound/soc/codecs/rt5677.c | 29 +++++++++++++++++------------ sound/soc/codecs/rt5677.h | 30 +++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 58 deletions(-) delete mode 100644 include/sound/rt5677.h (limited to 'sound/soc/codecs') diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h deleted file mode 100644 index a6207043ac3c..000000000000 --- a/include/sound/rt5677.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * linux/sound/rt5677.h -- Platform data for RT5677 - * - * Copyright 2013 Realtek Semiconductor Corp. - * Author: Oder Chiou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_SND_RT5677_H -#define __LINUX_SND_RT5677_H - -enum rt5677_dmic2_clk { - RT5677_DMIC_CLK1 = 0, - RT5677_DMIC_CLK2 = 1, -}; - - -struct rt5677_platform_data { - /* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */ - bool in1_diff; - bool in2_diff; - bool lout1_diff; - bool lout2_diff; - bool lout3_diff; - /* DMIC2 clock source selection */ - enum rt5677_dmic2_clk dmic2_clk_pin; - - /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ - u8 gpio_config[6]; - - /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */ - unsigned int jd1_gpio; - /* jd2 and jd3 can select 0 ~ 3 as - OFF, GPIO4, GPIO5 and GPIO6 respectively */ - unsigned int jd2_gpio; - unsigned int jd3_gpio; - - /* Set MICBIAS1 VDD 1v8 or 3v3 */ - bool micbias1_vdd_3v3; -}; - -#endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 36e530a36c82..0f9642c2198a 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -5019,25 +5020,21 @@ static const struct regmap_config rt5677_regmap = { }; static const struct i2c_device_id rt5677_i2c_id[] = { - { "rt5677", RT5677 }, - { "rt5676", RT5676 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); static const struct of_device_id rt5677_of_match[] = { - { .compatible = "realtek,rt5677", }, + { .compatible = "realtek,rt5677", RT5677 }, { } }; MODULE_DEVICE_TABLE(of, rt5677_of_match); -#ifdef CONFIG_ACPI static const struct acpi_device_id rt5677_acpi_match[] = { { "RT5677CE", RT5677 }, { } }; MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match); -#endif static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677, struct device *dev) @@ -5147,7 +5144,6 @@ static void rt5677_free_irq(struct i2c_client *i2c) static int rt5677_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct rt5677_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5677_priv *rt5677; int ret; unsigned int val; @@ -5159,16 +5155,25 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5677); - rt5677->type = id->driver_data; + if (i2c->dev.of_node) { + const struct of_device_id *match_id; + + match_id = of_match_device(rt5677_of_match, &i2c->dev); + if (match_id) + rt5677->type = (enum rt5677_type)match_id->data; - if (pdata) - rt5677->pdata = *pdata; - else if (i2c->dev.of_node) rt5677_read_device_properties(rt5677, &i2c->dev); - else if (ACPI_HANDLE(&i2c->dev)) + } else if (ACPI_HANDLE(&i2c->dev)) { + const struct acpi_device_id *acpi_id; + + acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev); + if (acpi_id) + rt5677->type = (enum rt5677_type)acpi_id->driver_data; + rt5677_read_acpi_properties(rt5677, &i2c->dev); - else + } else { return -EINVAL; + } /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d46855a42c40..97239973edc4 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -12,7 +12,6 @@ #ifndef __RT5677_H__ #define __RT5677_H__ -#include #include #include @@ -1761,6 +1760,35 @@ enum { RT5677_I2S4_SOURCE = (0x1 << 18), }; +enum rt5677_dmic2_clk { + RT5677_DMIC_CLK1 = 0, + RT5677_DMIC_CLK2 = 1, +}; + +struct rt5677_platform_data { + /* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */ + bool in1_diff; + bool in2_diff; + bool lout1_diff; + bool lout2_diff; + bool lout3_diff; + /* DMIC2 clock source selection */ + enum rt5677_dmic2_clk dmic2_clk_pin; + + /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ + u8 gpio_config[6]; + + /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */ + unsigned int jd1_gpio; + /* jd2 and jd3 can select 0 ~ 3 as + OFF, GPIO4, GPIO5 and GPIO6 respectively */ + unsigned int jd2_gpio; + unsigned int jd3_gpio; + + /* Set MICBIAS1 VDD 1v8 or 3v3 */ + bool micbias1_vdd_3v3; +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; -- cgit v1.2.3 From d4e753d3aa2c278cb1f7b4a61987c4037316e0fd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 20:34:18 +0300 Subject: ASoC: rt5677: Refactor code to avoid comparison unsigned >= 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rt5677_to_irq() has couple of redundant conditionals, one of which compares unsigned variable to be great than or equal to zero which is always true as compiler notices: sound/soc/codecs/rt5677.c: In function ‘rt5677_to_irq’: sound/soc/codecs/rt5677.c:4626:13: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] Refactor the code by removing redundant conditionals. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 50 ++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 0f9642c2198a..a3cce57739c3 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4625,35 +4625,27 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) struct regmap_irq_chip_data *data = rt5677->irq_data; int irq; - if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) { - if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || - (rt5677->pdata.jd1_gpio == 2 && - offset == RT5677_GPIO2) || - (rt5677->pdata.jd1_gpio == 3 && - offset == RT5677_GPIO3)) { - irq = RT5677_IRQ_JD1; - } else { - return -ENXIO; - } - } - - if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) { - if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || - (rt5677->pdata.jd2_gpio == 2 && - offset == RT5677_GPIO5) || - (rt5677->pdata.jd2_gpio == 3 && - offset == RT5677_GPIO6)) { - irq = RT5677_IRQ_JD2; - } else if ((rt5677->pdata.jd3_gpio == 1 && - offset == RT5677_GPIO4) || - (rt5677->pdata.jd3_gpio == 2 && - offset == RT5677_GPIO5) || - (rt5677->pdata.jd3_gpio == 3 && - offset == RT5677_GPIO6)) { - irq = RT5677_IRQ_JD3; - } else { - return -ENXIO; - } + if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || + (rt5677->pdata.jd1_gpio == 2 && + offset == RT5677_GPIO2) || + (rt5677->pdata.jd1_gpio == 3 && + offset == RT5677_GPIO3)) { + irq = RT5677_IRQ_JD1; + } else if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || + (rt5677->pdata.jd2_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd2_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD2; + } else if ((rt5677->pdata.jd3_gpio == 1 && + offset == RT5677_GPIO4) || + (rt5677->pdata.jd3_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd3_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD3; + } else { + return -ENXIO; } return regmap_irq_get_virq(data, irq); -- cgit v1.2.3 From 5622bc955898f4d5fa2ce8f507e5991b08367824 Mon Sep 17 00:00:00 2001 From: Pradeep Tewani Date: Thu, 20 Jul 2017 11:40:56 +0530 Subject: ASoC: hdac_hdmi: Add the vendor nid for Geminilake HDMI Geminilake HDMI codec has the different vendor nid. This patch adds the vendor nid as the part of driver data and uses it. Signed-off-by: Pradeep Tewani Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index bc2e74ff3b2d..eb3ed8c5ed30 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; +struct hdac_hdmi_drv_data { + unsigned int vendor_nid; +}; + struct hdac_hdmi_priv { struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS]; struct list_head pin_list; @@ -131,6 +135,7 @@ struct hdac_hdmi_priv { int num_ports; struct mutex pin_mutex; struct hdac_chmap chmap; + struct hdac_hdmi_drv_data *drv_data; }; static struct hdac_hdmi_pcm * @@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) } #define INTEL_VENDOR_NID 0x08 +#define INTEL_GLK_VENDOR_NID 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ @@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) { unsigned int vendor_param; + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + unsigned int vendor_nid = hdmi->drv_data->vendor_nid; - vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, INTEL_GET_VENDOR_VERB, 0); if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) return; vendor_param |= INTEL_EN_ALL_PIN_CVTS; - vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, INTEL_SET_VENDOR_VERB, vendor_param); if (vendor_param == -1) return; @@ -1345,15 +1354,18 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) { unsigned int vendor_param; + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + unsigned int vendor_nid = hdmi->drv_data->vendor_nid; - vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, INTEL_GET_VENDOR_VERB, 0); if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) return; /* enable DP1.2 mode */ vendor_param |= INTEL_EN_DP12; - vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, INTEL_SET_VENDOR_VERB, vendor_param); if (vendor_param == -1) return; @@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) return port->eld.info.spk_alloc; } +static struct hdac_hdmi_drv_data intel_glk_drv_data = { + .vendor_nid = INTEL_GLK_VENDOR_NID, +}; + +static struct hdac_hdmi_drv_data intel_drv_data = { + .vendor_nid = INTEL_VENDOR_NID, +}; + static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) { struct hdac_device *codec = &edev->hdac; @@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) struct hdac_ext_link *hlink = NULL; int num_dais = 0; int ret = 0; + struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver); + const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv); /* hold the ref while we probe */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); @@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; + if (hdac_id->driver_data) + hdmi_priv->drv_data = + (struct hdac_hdmi_drv_data *)hdac_id->driver_data; + else + hdmi_priv->drv_data = &intel_drv_data; + dev_set_drvdata(&codec->dev, edev); INIT_LIST_HEAD(&hdmi_priv->pin_list); @@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = { HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), - HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0), + HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", + &intel_glk_drv_data), {} }; -- cgit v1.2.3 From c0d1cb8366bab9963822c27b0d40cb8b32928cdc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 20:34:19 +0300 Subject: ASoC: rt5677: Remove never used variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two variables that have never been used. sound/soc/codecs/rt5677.c:785:35: warning: ‘in_vol_tlv’ defined but not used [-Wunused-const-variable=] static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); sound/soc/codecs/rt5677.c:783:35: warning: ‘out_vol_tlv’ defined but not used [-Wunused-const-variable=] static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); Simple remove them. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index a3cce57739c3..9e9de0e274ea 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -780,9 +780,7 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) return 0; } -static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); -static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); -- cgit v1.2.3 From e8be3a5ad335316ddf1b90e0386426093187bfc7 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Thu, 20 Jul 2017 12:05:34 +0800 Subject: ASoC: rt5514: Support the TDM docking mode The TDM docking mode can share the bus to other devices simultaneously. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 33 ++++++++++++++++++++++++++++++++- sound/soc/codecs/rt5514.h | 12 ++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 4ca73bf83cc1..a105c84ef555 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -871,11 +871,38 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, { struct snd_soc_codec *codec = dai->codec; struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); - unsigned int val = 0; + unsigned int val = 0, val2 = 0; if (rx_mask || tx_mask) val |= RT5514_TDM_MODE; + switch (tx_mask) { + case 0x3: + val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 | + RT5514_TDM_DOCKING_START_SLOT0; + break; + + case 0x30: + val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 | + RT5514_TDM_DOCKING_START_SLOT4; + break; + + case 0xf: + val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 | + RT5514_TDM_DOCKING_START_SLOT0; + break; + + case 0xf0: + val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 | + RT5514_TDM_DOCKING_START_SLOT4; + break; + + default: + break; + } + + + switch (slots) { case 4: val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH; @@ -921,6 +948,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK | RT5514_TDM_MODE2, val); + regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL2, + RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH_MASK | + RT5514_TDM_DOCKING_START_MASK, val2); + return 0; } diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 02bc212a86d9..75024a4bb7f5 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -164,6 +164,18 @@ #define RT5514_I2S_DL_24 (0x2 << 0) #define RT5514_I2S_DL_8 (0x3 << 0) +/* RT5514_I2S_CTRL2 (0x2014) */ +#define RT5514_TDM_DOCKING_MODE (0x1 << 31) +#define RT5514_TDM_DOCKING_MODE_SFT 31 +#define RT5514_TDM_DOCKING_VALID_CH_MASK (0x1 << 29) +#define RT5514_TDM_DOCKING_VALID_CH_SFT 29 +#define RT5514_TDM_DOCKING_VALID_CH2 (0x0 << 29) +#define RT5514_TDM_DOCKING_VALID_CH4 (0x1 << 29) +#define RT5514_TDM_DOCKING_START_MASK (0x1 << 28) +#define RT5514_TDM_DOCKING_START_SFT 28 +#define RT5514_TDM_DOCKING_START_SLOT0 (0x0 << 28) +#define RT5514_TDM_DOCKING_START_SLOT4 (0x1 << 28) + /* RT5514_DIG_SOURCE_CTRL (0x20a4) */ #define RT5514_AD1_DMIC_INPUT_SEL (0x1 << 1) #define RT5514_AD1_DMIC_INPUT_SEL_SFT 1 -- cgit v1.2.3 From 01dfb1ec15ce6120055401953265c7b51e899292 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 20 Jul 2017 13:07:50 +0800 Subject: ASoC: rt5665: add clcok control for master mode Add i2s clock control for codec master mode. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 24 +++++++++++++++++++++++- sound/soc/codecs/rt5665.h | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index d3103efcb135..ef27561c4993 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4186,6 +4186,15 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, break; } + if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) { + snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1, + RT5665_I2S2_M_PD_MASK, pre_div << RT5665_I2S2_M_PD_SFT); + } + if (rt5665->master[RT5665_AIF3]) { + snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1, + RT5665_I2S3_M_PD_MASK, pre_div << RT5665_I2S3_M_PD_SFT); + } + return 0; } @@ -4262,7 +4271,7 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); - unsigned int reg_val = 0; + unsigned int reg_val = 0, src = 0; if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src) return 0; @@ -4270,12 +4279,15 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id, switch (clk_id) { case RT5665_SCLK_S_MCLK: reg_val |= RT5665_SCLK_SRC_MCLK; + src = RT5665_CLK_SRC_MCLK; break; case RT5665_SCLK_S_PLL1: reg_val |= RT5665_SCLK_SRC_PLL1; + src = RT5665_CLK_SRC_PLL1; break; case RT5665_SCLK_S_RCCLK: reg_val |= RT5665_SCLK_SRC_RCCLK; + src = RT5665_CLK_SRC_RCCLK; break; default: dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); @@ -4283,6 +4295,16 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id, } snd_soc_update_bits(codec, RT5665_GLB_CLK, RT5665_SCLK_SRC_MASK, reg_val); + + if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) { + snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1, + RT5665_I2S2_SRC_MASK, src << RT5665_I2S2_SRC_SFT); + } + if (rt5665->master[RT5665_AIF3]) { + snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1, + RT5665_I2S3_SRC_MASK, src << RT5665_I2S3_SRC_SFT); + } + rt5665->sysclk = freq; rt5665->sysclk_src = clk_id; diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h index 1db5c6a62a8e..8f08acb9c446 100644 --- a/sound/soc/codecs/rt5665.h +++ b/sound/soc/codecs/rt5665.h @@ -1628,6 +1628,27 @@ #define RT5665_PWR_CLK1M_PD (0x0 << 8) #define RT5665_PWR_CLK1M_PU (0x1 << 8) +/* I2S Master Mode Clock Control 1 (0x00a0) */ +#define RT5665_CLK_SRC_MCLK (0x0) +#define RT5665_CLK_SRC_PLL1 (0x1) +#define RT5665_CLK_SRC_RCCLK (0x2) +#define RT5665_I2S_PD_1 (0x0) +#define RT5665_I2S_PD_2 (0x1) +#define RT5665_I2S_PD_3 (0x2) +#define RT5665_I2S_PD_4 (0x3) +#define RT5665_I2S_PD_6 (0x4) +#define RT5665_I2S_PD_8 (0x5) +#define RT5665_I2S_PD_12 (0x6) +#define RT5665_I2S_PD_16 (0x7) +#define RT5665_I2S2_SRC_MASK (0x3 << 12) +#define RT5665_I2S2_SRC_SFT 12 +#define RT5665_I2S2_M_PD_MASK (0x7 << 8) +#define RT5665_I2S2_M_PD_SFT 8 +#define RT5665_I2S3_SRC_MASK (0x3 << 4) +#define RT5665_I2S3_SRC_SFT 4 +#define RT5665_I2S3_M_PD_MASK (0x7 << 0) +#define RT5665_I2S3_M_PD_SFT 0 + /* EQ Control 1 (0x00b0) */ #define RT5665_EQ_SRC_DAC (0x0 << 15) -- cgit v1.2.3 From 8bfa426845419d1fe895fc5668ab29b3a0c36c85 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 20 Jul 2017 13:07:51 +0800 Subject: ASoC: rt5665: add clock sync control for master mode We can sleect the i2s clock source for each i2s bus in master mode. The choice is depended on the HW design and the use case. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index ef27561c4993..7e64b25f8585 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -1381,6 +1381,16 @@ static void rt5665_jack_detect_handler(struct work_struct *work) mutex_unlock(&rt5665->calibrate_mutex); } +static const char * const rt5665_clk_sync[] = { + "I2S1_1", "I2S1_2", "I2S2", "I2S3", "IF2 Slave", "IF3 Slave" +}; + +static const struct soc_enum rt5665_enum[] = { + SOC_ENUM_SINGLE(RT5665_I2S1_SDP, 11, 5, rt5665_clk_sync), + SOC_ENUM_SINGLE(RT5665_I2S2_SDP, 11, 5, rt5665_clk_sync), + SOC_ENUM_SINGLE(RT5665_I2S3_SDP, 11, 5, rt5665_clk_sync), +}; + static const struct snd_kcontrol_new rt5665_snd_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN, @@ -1446,6 +1456,11 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = { SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST, RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), + + /* I2S3 CLK Source */ + SOC_ENUM("I2S1 Master Clk Sel", rt5665_enum[0]), + SOC_ENUM("I2S2 Master Clk Sel", rt5665_enum[1]), + SOC_ENUM("I2S3 Master Clk Sel", rt5665_enum[2]), }; /** -- cgit v1.2.3 From b833786b69c14fe98846c38d36d8f6e5e92ccdd8 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 24 Jul 2017 19:11:52 +0800 Subject: ASoC: rt5665: add MONOVOL Playback Volume control MONOVOL Playback Volume is a playback volume control on "MONOVOL MIX". Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 7e64b25f8585..54ace3b98ec3 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -1402,6 +1402,9 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = { RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw, rt5665_mono_vol_put, mono_vol_tlv), + SOC_SINGLE_TLV("MONOVOL Playback Volume", RT5665_MONO_OUT, + RT5665_L_VOL_SFT, 39, 1, out_vol_tlv), + /* Output Volume */ SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 39, 1, out_vol_tlv), -- cgit v1.2.3 From 1628ef89042fdb90aaea657942455e00e160174d Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 24 Jul 2017 15:34:23 +0800 Subject: ASoC: rt5514: Add the I2S ASRC support The patch adds the I2S ASRC support. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 19 +++++++++++++++++++ sound/soc/codecs/rt5514.h | 7 +++++++ 2 files changed, 26 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a105c84ef555..882fdc4a6fd4 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -63,6 +63,7 @@ static const struct reg_sequence rt5514_patch[] = { {RT5514_SRC_CTRL, 0x44000eee}, {RT5514_ANA_CTRL_LDO10, 0x00028604}, {RT5514_ANA_CTRL_ADCFED, 0x00000800}, + {RT5514_ASRC_IN_CTRL1, 0x00000003}, }; static const struct reg_default rt5514_reg[] = { @@ -471,6 +472,15 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int rt5514_i2s_use_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + + return (rt5514->sysclk > rt5514->lrck * 384); +} + static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { /* Input Lines */ SND_SOC_DAPM_INPUT("DMIC1L"), @@ -541,6 +551,10 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASRC AD1", 1, RT5514_CLK_CTRL2, + RT5514_CLK_AD0_ASRC_EN_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASRC AD2", 1, RT5514_CLK_CTRL2, + RT5514_CLK_AD1_ASRC_EN_BIT, 0, NULL, 0), /* ADC Mux */ SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, @@ -638,6 +652,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" }, { "Stereo1 ADC MIX", NULL, "adc stereo1 filter" }, { "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll }, + { "adc stereo1 filter", NULL, "ASRC AD1", rt5514_i2s_use_asrc }, { "Stereo2 DMIC Mux", "DMIC1", "DMIC1" }, { "Stereo2 DMIC Mux", "DMIC2", "DMIC2" }, @@ -654,6 +669,7 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { { "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" }, { "Stereo2 ADC MIX", NULL, "adc stereo2 filter" }, { "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll }, + { "adc stereo2 filter", NULL, "ASRC AD2", rt5514_i2s_use_asrc }, { "AIF1TX", NULL, "Stereo1 ADC MIX"}, { "AIF1TX", NULL, "Stereo2 ADC MIX"}, @@ -706,6 +722,9 @@ static int rt5514_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK, val_len); + regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1, + RT5514_CLK_AD_ANA1_SEL_MASK, + (pre_div + 1) << RT5514_CLK_AD_ANA1_SEL_SFT); regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2, RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK, pre_div << RT5514_CLK_SYS_DIV_OUT_SFT | diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 75024a4bb7f5..2dc40e6d8b3f 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -37,6 +37,7 @@ #define RT5514_PLL3_CALIB_CTRL5 0x2124 #define RT5514_DELAY_BUF_CTRL1 0x2140 #define RT5514_DELAY_BUF_CTRL3 0x2148 +#define RT5514_ASRC_IN_CTRL1 0x2180 #define RT5514_DOWNFILTER0_CTRL1 0x2190 #define RT5514_DOWNFILTER0_CTRL2 0x2194 #define RT5514_DOWNFILTER0_CTRL3 0x2198 @@ -197,8 +198,14 @@ #define RT5514_CLK_AD0_EN_BIT 23 #define RT5514_CLK_DMIC_OUT_SEL_MASK (0x7 << 8) #define RT5514_CLK_DMIC_OUT_SEL_SFT 8 +#define RT5514_CLK_AD_ANA1_SEL_MASK (0xf << 0) +#define RT5514_CLK_AD_ANA1_SEL_SFT 0 /* RT5514_CLK_CTRL2 (0x2108) */ +#define RT5514_CLK_AD1_ASRC_EN (0x1 << 17) +#define RT5514_CLK_AD1_ASRC_EN_BIT 17 +#define RT5514_CLK_AD0_ASRC_EN (0x1 << 16) +#define RT5514_CLK_AD0_ASRC_EN_BIT 16 #define RT5514_CLK_SYS_DIV_OUT_MASK (0x7 << 8) #define RT5514_CLK_SYS_DIV_OUT_SFT 8 #define RT5514_SEL_ADC_OSR_MASK (0x7 << 4) -- cgit v1.2.3 From 8a43c2240c862bbf3fc612d0533b891bd75ec771 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 22:53:24 +0530 Subject: ASoC: rt5514: constify acpi_device_id. acpi_device_id are not supposed to change at runtime. All functions working with acpi_device_id provided by work with const acpi_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 882fdc4a6fd4..3d0aea8f3801 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1134,7 +1134,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt5514_acpi_match[] = { +static const struct acpi_device_id rt5514_acpi_match[] = { { "10EC5514", 0}, {}, }; -- cgit v1.2.3 From 1d89147cc3dfef185e701baad437fa91c0977384 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 22:53:25 +0530 Subject: ASoC: rt5663: constify acpi_device_id. acpi_device_id are not supposed to change at runtime. All functions working with acpi_device_id provided by work with const acpi_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index a33202affeb1..271cc81f2aef 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2956,7 +2956,7 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt5663_acpi_match[] = { +static const struct acpi_device_id rt5663_acpi_match[] = { { "10EC5663", 0}, {}, }; -- cgit v1.2.3 From f36544a425d3b75281a1601fe663086aec5b36c7 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 22:53:26 +0530 Subject: ASoC: rt5659: constify acpi_device_id. acpi_device_id are not supposed to change at runtime. All functions working with acpi_device_id provided by work with const acpi_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/codecs/rt5659.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 1b7060850340..0a99fad48392 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -4222,7 +4222,7 @@ MODULE_DEVICE_TABLE(of, rt5659_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt5659_acpi_match[] = { +static const struct acpi_device_id rt5659_acpi_match[] = { { "10EC5658", 0, }, { "10EC5659", 0, }, { }, -- cgit v1.2.3 From abfedab1163a6b01ab400a67f4eed0fea3ccbdd1 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 22:53:27 +0530 Subject: ASoC: rt5665: constify acpi_device_id. acpi_device_id are not supposed to change at runtime. All functions working with acpi_device_id provided by work with const acpi_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 54ace3b98ec3..d0a9490f97f1 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4970,7 +4970,7 @@ MODULE_DEVICE_TABLE(of, rt5665_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt5665_acpi_match[] = { +static const struct acpi_device_id rt5665_acpi_match[] = { {"10EC5665", 0,}, {"10EC5666", 0,}, {"10EC5668", 0,}, -- cgit v1.2.3 From c2bf252536577db77c719f62a54cad2e4be5c4d7 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Wed, 26 Jul 2017 18:32:20 +0800 Subject: ASoC: rt5514: Use the IS_ENABLED to supports the module build The patch uses the macro IS_ENABLED to make sure that the SPI function also supports the module build. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 3d0aea8f3801..21cbb566c0d3 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -31,7 +31,7 @@ #include "rl6231.h" #include "rt5514.h" -#if defined(CONFIG_SND_SOC_RT5514_SPI) +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) #include "rt5514-spi.h" #endif @@ -312,7 +312,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, request_firmware(&fw, RT5514_FIRMWARE1, codec->dev); if (fw) { -#if defined(CONFIG_SND_SOC_RT5514_SPI) +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) rt5514_spi_burst_write(0x4ff60000, fw->data, ((fw->size/8)+1)*8); #else @@ -325,7 +325,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, request_firmware(&fw, RT5514_FIRMWARE2, codec->dev); if (fw) { -#if defined(CONFIG_SND_SOC_RT5514_SPI) +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) rt5514_spi_burst_write(0x4ffc0000, fw->data, ((fw->size/8)+1)*8); #else -- cgit v1.2.3 From 8215313c8bf487b6b15839be3c18fdd1598b1e79 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 26 Jul 2017 15:28:26 +0800 Subject: ASoC: rt5670: add symmetric_rates flag rt5670 requires symmetric rate of capture and playback. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0ec7985ed306..174141fefc79 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2743,6 +2743,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = { .formats = RT5670_FORMATS, }, .ops = &rt5670_aif_dai_ops, + .symmetric_rates = 1, }, { .name = "rt5670-aif2", @@ -2762,6 +2763,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = { .formats = RT5670_FORMATS, }, .ops = &rt5670_aif_dai_ops, + .symmetric_rates = 1, }, }; -- cgit v1.2.3 From a7e1149b64091ac87dfb18b177abb63ba4cbbd3d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Jul 2017 05:17:08 +0000 Subject: ASoC: remove cache_bypass from snd_soc_codec snd_soc_codec .cache_bypass related operation code has been removed. Let's remove remaining code. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/codecs/max98927.c | 1 - 2 files changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/sound/soc.h b/include/sound/soc.h index 9c94b97c17f8..10b71beb9f13 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -894,7 +894,6 @@ struct snd_soc_codec { struct list_head list; /* runtime */ - unsigned int cache_bypass:1; /* Suppress access to the cache */ unsigned int cache_init:1; /* codec cache has been initialized */ /* codec IO */ diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index b5ee29499e16..b0380b560bf5 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -577,7 +577,6 @@ static int max98927_probe(struct snd_soc_codec *codec) max98927->codec = codec; codec->control_data = max98927->regmap; - codec->cache_bypass = 1; /* Software Reset */ regmap_write(max98927->regmap, -- cgit v1.2.3 From ea746a296df3670359ae7d43baa968b0a1a54a01 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 26 Jul 2017 20:00:19 +0800 Subject: ASoC: rt5670: merge ADC L/R Mux Some ADC L/R Muxes share the some control bit. So, merge them. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 174141fefc79..0f4e5bc4476f 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1151,20 +1151,15 @@ static const char * const rt5670_stereo_adc1_src[] = { static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc1_enum, RT5670_STO1_ADC_MIXER, RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src); -static const struct snd_kcontrol_new rt5670_sto_adc_l1_mux = - SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5670_stereo1_adc1_enum); - -static const struct snd_kcontrol_new rt5670_sto_adc_r1_mux = - SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5670_stereo1_adc1_enum); +static const struct snd_kcontrol_new rt5670_sto_adc_1_mux = + SOC_DAPM_ENUM("Stereo1 ADC 1 Mux", rt5670_stereo1_adc1_enum); static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc1_enum, RT5670_STO2_ADC_MIXER, RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src); -static const struct snd_kcontrol_new rt5670_sto2_adc_l1_mux = - SOC_DAPM_ENUM("Stereo2 ADC L1 source", rt5670_stereo2_adc1_enum); +static const struct snd_kcontrol_new rt5670_sto2_adc_1_mux = + SOC_DAPM_ENUM("Stereo2 ADC 1 Mux", rt5670_stereo2_adc1_enum); -static const struct snd_kcontrol_new rt5670_sto2_adc_r1_mux = - SOC_DAPM_ENUM("Stereo2 ADC R1 source", rt5670_stereo2_adc1_enum); /* MX-27 MX-26 [11] */ static const char * const rt5670_stereo_adc2_src[] = { @@ -1174,20 +1169,15 @@ static const char * const rt5670_stereo_adc2_src[] = { static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc2_enum, RT5670_STO1_ADC_MIXER, RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src); -static const struct snd_kcontrol_new rt5670_sto_adc_l2_mux = - SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5670_stereo1_adc2_enum); - -static const struct snd_kcontrol_new rt5670_sto_adc_r2_mux = - SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5670_stereo1_adc2_enum); +static const struct snd_kcontrol_new rt5670_sto_adc_2_mux = + SOC_DAPM_ENUM("Stereo1 ADC 2 Mux", rt5670_stereo1_adc2_enum); static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src); -static const struct snd_kcontrol_new rt5670_sto2_adc_l2_mux = - SOC_DAPM_ENUM("Stereo2 ADC L2 source", rt5670_stereo2_adc2_enum); +static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux = + SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum); -static const struct snd_kcontrol_new rt5670_sto2_adc_r2_mux = - SOC_DAPM_ENUM("Stereo2 ADC R2 source", rt5670_stereo2_adc2_enum); /* MX-27 MX26 [10] */ static const char * const rt5670_stereo_adc_src[] = { @@ -1642,23 +1632,23 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, &rt5670_sto1_dmic_mux), SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto_adc_l2_mux), + &rt5670_sto_adc_2_mux), SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto_adc_r2_mux), + &rt5670_sto_adc_2_mux), SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto_adc_l1_mux), + &rt5670_sto_adc_1_mux), SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto_adc_r1_mux), + &rt5670_sto_adc_1_mux), SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0, &rt5670_sto2_dmic_mux), SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto2_adc_l2_mux), + &rt5670_sto2_adc_2_mux), SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto2_adc_r2_mux), + &rt5670_sto2_adc_2_mux), SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto2_adc_l1_mux), + &rt5670_sto2_adc_1_mux), SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, - &rt5670_sto2_adc_r1_mux), + &rt5670_sto2_adc_1_mux), SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0, &rt5670_sto2_adc_lr_mux), SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, -- cgit v1.2.3 From 007b6a54c305688d1db7255e5c724e3d76ba5aa4 Mon Sep 17 00:00:00 2001 From: Mihai Serban Date: Thu, 27 Jul 2017 17:55:10 +0300 Subject: ASoC: codecs: add wm8524 codec driver WM8524 is a 24-bit 192KHz stereo digital/analog converter (DAC) with integral charge pump and a simple hardware control interface. Product information can be found at: https://www.cirrus.com/products/wm8524/ Signed-off-by: Mihai Serban Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8524.txt | 16 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8524.c | 265 +++++++++++++++++++++ 4 files changed, 288 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8524.txt create mode 100644 sound/soc/codecs/wm8524.c (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/wm8524.txt b/Documentation/devicetree/bindings/sound/wm8524.txt new file mode 100644 index 000000000000..20c62002cbcd --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8524.txt @@ -0,0 +1,16 @@ +WM8524 audio CODEC + +This device does not use I2C or SPI but a simple Hardware Control Interface. + +Required properties: + + - compatible : "wlf,wm8524" + + - wlf,mute-gpios: a GPIO spec for the MUTE pin. + +Example: + +codec: wm8524@0 { + compatible = "wlf,wm8524"; + wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6c78b0b49b81..c3d8aef98608 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -173,6 +173,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8523 if I2C + select SND_SOC_WM8524 if GPIOLIB select SND_SOC_WM8580 if I2C select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8727 @@ -967,6 +968,10 @@ config SND_SOC_WM8523 tristate "Wolfson Microelectronics WM8523 DAC" depends on I2C +config SND_SOC_WM8524 + tristate "Wolfson Microelectronics WM8524 DAC" + depends on GPIOLIB + config SND_SOC_WM8580 tristate "Wolfson Microelectronics WM8580 and WM8581 CODECs" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..66a8567d76d1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -182,6 +182,7 @@ snd-soc-wm8350-objs := wm8350.o snd-soc-wm8400-objs := wm8400.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8523-objs := wm8523.o +snd-soc-wm8524-objs := wm8524.o snd-soc-wm8580-objs := wm8580.o snd-soc-wm8711-objs := wm8711.o snd-soc-wm8727-objs := wm8727.o @@ -414,6 +415,7 @@ obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o +obj-$(CONFIG_SND_SOC_WM8524) += snd-soc-wm8524.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c new file mode 100644 index 000000000000..f42ec664877c --- /dev/null +++ b/sound/soc/codecs/wm8524.c @@ -0,0 +1,265 @@ +/* + * wm8524.c -- WM8524 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * Copyright 2017 NXP + * + * Based on WM8523 ALSA SoC Audio driver written by Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WM8524_NUM_RATES 7 + +/* codec private data */ +struct wm8524_priv { + struct gpio_desc *mute; + unsigned int sysclk; + unsigned int rate_constraint_list[WM8524_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; +}; + + +static const struct snd_soc_dapm_widget wm8524_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LINEVOUTL"), +SND_SOC_DAPM_OUTPUT("LINEVOUTR"), +}; + +static const struct snd_soc_dapm_route wm8524_dapm_routes[] = { + { "LINEVOUTL", NULL, "DAC" }, + { "LINEVOUTR", NULL, "DAC" }, +}; + +static const struct { + int value; + int ratio; +} lrclk_ratios[WM8524_NUM_RATES] = { + { 1, 128 }, + { 2, 192 }, + { 3, 256 }, + { 4, 384 }, + { 5, 512 }, + { 6, 768 }, + { 7, 1152 }, +}; + +static int wm8524_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8524_priv *wm8524 = 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 (!wm8524->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, + &wm8524->rate_constraint); + + gpiod_set_value_cansleep(wm8524->mute, 1); + + return 0; +} + +static void wm8524_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec); + + gpiod_set_value_cansleep(wm8524->mute, 0); +} + +static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int i, j = 0; + + wm8524->sysclk = freq; + + wm8524->rate_constraint.count = 0; + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { + val = freq / lrclk_ratios[i].ratio; + /* Check that it's a standard rate since core can't + * cope with others and having the odd rates confuses + * constraint matching. + */ + switch (val) { + case 8000: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + case 176400: + case 192000: + dev_err(codec->dev, "Supported sample rate: %dHz\n", + val); + wm8524->rate_constraint_list[j++] = val; + wm8524->rate_constraint.count++; + break; + default: + dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", + val); + } + } + + /* Need at least one supported rate... */ + if (wm8524->rate_constraint.count == 0) + return -EINVAL; + + return 0; +} + +static int wm8524_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | + SND_SOC_DAIFMT_MASTER_MASK); + + if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS)) { + dev_err(codec_dai->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(dai->codec); + + if (wm8524->mute) + gpiod_set_value_cansleep(wm8524->mute, mute); + + return 0; +} + +#define WM8524_RATES SNDRV_PCM_RATE_8000_192000 + +#define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops wm8524_dai_ops = { + .startup = wm8524_startup, + .shutdown = wm8524_shutdown, + .set_sysclk = wm8524_set_dai_sysclk, + .set_fmt = wm8524_set_fmt, + .mute_stream = wm8524_mute_stream, +}; + +static struct snd_soc_dai_driver wm8524_dai = { + .name = "wm8524-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8524_RATES, + .formats = WM8524_FORMATS, + }, + .ops = &wm8524_dai_ops, +}; + +static int wm8524_probe(struct snd_soc_codec *codec) +{ + struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec); + + wm8524->rate_constraint.list = &wm8524->rate_constraint_list[0]; + wm8524->rate_constraint.count = + ARRAY_SIZE(wm8524->rate_constraint_list); + + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_wm8524 = { + .probe = wm8524_probe, + + .component_driver = { + .dapm_widgets = wm8524_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8524_dapm_widgets), + .dapm_routes = wm8524_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8524_dapm_routes), + }, +}; + +#ifdef CONFIG_OF +static const struct of_device_id wm8524_of_match[] = { + { .compatible = "wlf,wm8524" }, + { /* sentinel*/ } +}; +MODULE_DEVICE_TABLE(of, wm8524_of_match); +#endif + +static int wm8524_codec_probe(struct platform_device *pdev) +{ + struct wm8524_priv *wm8524; + int ret; + + wm8524 = devm_kzalloc(&pdev->dev, sizeof(struct wm8524_priv), + GFP_KERNEL); + if (wm8524 == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, wm8524); + + wm8524->mute = devm_gpiod_get(&pdev->dev, "wlf,mute", GPIOD_OUT_LOW); + if (IS_ERR(wm8524->mute)) { + ret = PTR_ERR(wm8524->mute); + dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_wm8524, &wm8524_dai, 1); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + snd_soc_unregister_platform(&pdev->dev); + } + + return ret; +} + +static int wm8524_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver wm8524_codec_driver = { + .probe = wm8524_codec_probe, + .remove = wm8524_codec_remove, + .driver = { + .name = "wm8524-codec", + .of_match_table = wm8524_of_match, + }, +}; +module_platform_driver(wm8524_codec_driver); + +MODULE_DESCRIPTION("ASoC WM8524 driver"); +MODULE_AUTHOR("Mihai Serban "); +MODULE_ALIAS("platform:wm8524-codec"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From bf11ecb7eebd28d70bf5aa3170c6fe7156c33c5b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 31 Jul 2017 18:05:46 +0200 Subject: ASoC: codecs: fix wm8524 build error When CONFIG_OF is disabled, we run into a build error: sound/soc/codecs/wm8524.c:257:21: error: 'wm8524_of_match' undeclared here (not in a function); did you mean 'wm8524_dai'? This removes the unnecessary #ifdef around the match table. Fixes: 007b6a54c305 ("ASoC: codecs: add wm8524 codec driver") Signed-off-by: Arnd Bergmann Acked-by: Mihai Serban Signed-off-by: Mark Brown --- sound/soc/codecs/wm8524.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index f42ec664877c..e22b76d64e32 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -206,13 +206,11 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8524 = { }, }; -#ifdef CONFIG_OF static const struct of_device_id wm8524_of_match[] = { { .compatible = "wlf,wm8524" }, { /* sentinel*/ } }; MODULE_DEVICE_TABLE(of, wm8524_of_match); -#endif static int wm8524_codec_probe(struct platform_device *pdev) { -- cgit v1.2.3 From c1bbaff6d7dd55314ee453df8dfe00befd7ce1b2 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Tue, 1 Aug 2017 19:14:02 +0800 Subject: ASoC: rt5663: Add the delay time to correct the calibration The patch adds the delay time to correct the calibration. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 45f8a9888f7d..c1f0a72c0133 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3058,6 +3058,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b); + msleep(40); regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000); regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c); regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xafaa); -- cgit v1.2.3 From 818010dac09183e99ff02e35836544b2e1d659f3 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 31 Jul 2017 13:47:42 +0800 Subject: ASoC: rt5514: Add the sanity checks of the buffer related address The patch add the sanity checks of the buffer related address to make sure the addresses are valid. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 950d1ffdc06c..6f513cc4c56c 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -173,9 +173,14 @@ static irqreturn_t rt5514_spi_irq(int irq, void *data) rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; + if (rt5514_dsp->buf_rp % 8) + rt5514_dsp->buf_rp = (rt5514_dsp->buf_rp / 8) * 8; + rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base; - schedule_delayed_work(&rt5514_dsp->copy_work, 0); + if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && + rt5514_dsp->buf_rp && rt5514_dsp->buf_size) + schedule_delayed_work(&rt5514_dsp->copy_work, 0); return IRQ_HANDLED; } -- cgit v1.2.3 From 19b4b7292615358b9599ff9410a3e564b4844e90 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Aug 2017 17:55:13 +0800 Subject: ASoC: wm8523: Fix array size for bclk_ratios ARRAY_SIZE(bclk_ratios) returns 7 for current code, then it cannot catch the error if "no matching BCLK/fs ratio". Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/wm8523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 6d0a2723bfde..b1e4ce72e533 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -116,7 +116,7 @@ static struct { static struct { int value; int ratio; -} bclk_ratios[WM8523_NUM_RATES] = { +} bclk_ratios[] = { { 2, 32 }, { 3, 64 }, { 4, 128 }, -- cgit v1.2.3 From c0d088f04f115409287003b5fc0dfd3184d7d306 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Aug 2017 17:55:14 +0800 Subject: ASoC: wm8523: Constfiy lrclk_ratios and bclk_ratios Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/wm8523.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index b1e4ce72e533..c7c33e98fbcb 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -100,7 +100,7 @@ static const struct snd_soc_dapm_route wm8523_dapm_routes[] = { { "LINEVOUTR", NULL, "DAC" }, }; -static struct { +static const struct { int value; int ratio; } lrclk_ratios[WM8523_NUM_RATES] = { @@ -113,7 +113,7 @@ static struct { { 7, 1152 }, }; -static struct { +static const struct { int value; int ratio; } bclk_ratios[] = { -- cgit v1.2.3 From 80bfd0431f7dc133f4edbc0b864f800c4ed7a3f4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Aug 2017 16:13:46 +0800 Subject: ASoC: wm8524: Don't use dev_err to show supported sample rate Switch to use dev_dbg instead. Signed-off-by: Axel Lin Acked-by: Mihai Serban Signed-off-by: Mark Brown --- sound/soc/codecs/wm8524.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index e22b76d64e32..b66147e0631b 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -118,7 +118,7 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai, case 96000: case 176400: case 192000: - dev_err(codec->dev, "Supported sample rate: %dHz\n", + dev_dbg(codec->dev, "Supported sample rate: %dHz\n", val); wm8524->rate_constraint_list[j++] = val; wm8524->rate_constraint.count++; -- cgit v1.2.3 From 278982b50b28d654ff8cca0efb1ff6e835c6cc4c Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Wed, 2 Aug 2017 16:01:27 +0800 Subject: ASoC: rt5663: Seprate the DC offset between headphone and headset The patch seprates the DC offset between headphone and headset. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5663.txt | 5 ++- include/sound/rt5663.h | 2 + sound/soc/codecs/rt5663.c | 52 ++++++++++++++++------ 3 files changed, 44 insertions(+), 15 deletions(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/rt5663.txt b/Documentation/devicetree/bindings/sound/rt5663.txt index f7c7cc513ee8..ff381718c517 100644 --- a/Documentation/devicetree/bindings/sound/rt5663.txt +++ b/Documentation/devicetree/bindings/sound/rt5663.txt @@ -14,8 +14,11 @@ Optional properties: - "realtek,dc_offset_l_manual" - "realtek,dc_offset_r_manual" +- "realtek,dc_offset_l_manual_mic" +- "realtek,dc_offset_r_manual_mic" Based on the different PCB layout, add the manual offset value to - compensate the DC offset for each L and R channel. + compensate the DC offset for each L and R channel, and they are different + between headphone and headset. Pins on the device (for linking into audio routes) for RT5663: diff --git a/include/sound/rt5663.h b/include/sound/rt5663.h index be6f1b2d8fbd..7d00e5849706 100644 --- a/include/sound/rt5663.h +++ b/include/sound/rt5663.h @@ -14,6 +14,8 @@ struct rt5663_platform_data { unsigned int dc_offset_l_manual; unsigned int dc_offset_r_manual; + unsigned int dc_offset_l_manual_mic; + unsigned int dc_offset_r_manual_mic; }; #endif diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index c1f0a72c0133..be93231b0f58 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1570,9 +1570,43 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) case 2: rt5663->jack_type = SND_JACK_HEADSET; rt5663_enable_push_button_irq(codec, true); + + if (rt5663->pdata.dc_offset_l_manual_mic) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2, + rt5663->pdata.dc_offset_l_manual_mic >> + 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3, + rt5663->pdata.dc_offset_l_manual_mic & + 0xffff); + } + + if (rt5663->pdata.dc_offset_r_manual_mic) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5, + rt5663->pdata.dc_offset_r_manual_mic >> + 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6, + rt5663->pdata.dc_offset_r_manual_mic & + 0xffff); + } break; default: rt5663->jack_type = SND_JACK_HEADPHONE; + + if (rt5663->pdata.dc_offset_l_manual) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2, + rt5663->pdata.dc_offset_l_manual >> 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3, + rt5663->pdata.dc_offset_l_manual & + 0xffff); + } + + if (rt5663->pdata.dc_offset_r_manual) { + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5, + rt5663->pdata.dc_offset_r_manual >> 16); + regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6, + rt5663->pdata.dc_offset_r_manual & + 0xffff); + } break; } } else { @@ -3133,6 +3167,10 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) &rt5663->pdata.dc_offset_l_manual); device_property_read_u32(dev, "realtek,dc_offset_r_manual", &rt5663->pdata.dc_offset_r_manual); + device_property_read_u32(dev, "realtek,dc_offset_l_manual_mic", + &rt5663->pdata.dc_offset_l_manual_mic); + device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic", + &rt5663->pdata.dc_offset_r_manual_mic); return 0; } @@ -3221,20 +3259,6 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); } - if (rt5663->pdata.dc_offset_l_manual) { - regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2, - rt5663->pdata.dc_offset_l_manual >> 16); - regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3, - rt5663->pdata.dc_offset_l_manual & 0xffff); - } - - if (rt5663->pdata.dc_offset_r_manual) { - regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5, - rt5663->pdata.dc_offset_r_manual >> 16); - regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6, - rt5663->pdata.dc_offset_r_manual & 0xffff); - } - /* GPIO1 as IRQ */ regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK, RT5663_GP1_PIN_IRQ); -- cgit v1.2.3 From 29685e207b37ad7f415e4bf21320076c025f3df1 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 25 Jul 2017 10:48:14 +0200 Subject: ASoC: codec: add DT support in dmic codec Add of_table to allows DT probing. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/dmic.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index c82b9dc41e9a..d50f142e2972 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -73,9 +73,15 @@ static int dmic_dev_remove(struct platform_device *pdev) MODULE_ALIAS("platform:dmic-codec"); +static const struct of_device_id dmic_dev_match[] = { + {.compatible = "dmic-codec"}, + {} +}; + static struct platform_driver dmic_driver = { .driver = { .name = "dmic-codec", + .of_match_table = dmic_dev_match, }, .probe = dmic_dev_probe, .remove = dmic_dev_remove, -- cgit v1.2.3 From 2032ce4de818366adb78d8e0b29291ce58ae1e40 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 2 Aug 2017 15:17:46 +0200 Subject: ASoC: codecs: msm8916-wcd-digital: add support to set_sysclk This patch adds support to set_sysclk() which can let the sound card driver to set default mclk rate. In this case MCLK for internal audio codec is expected to be at 9.6MHz by default. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 7e3794fb8c2c..661cd6dd5473 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -568,6 +568,15 @@ static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) return 0; } +static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev); + + return clk_set_rate(p->mclk, freq); +} + static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -823,6 +832,7 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { static struct snd_soc_codec_driver msm8916_wcd_digital = { .probe = msm8916_wcd_digital_codec_probe, + .set_sysclk = msm8916_wcd_digital_codec_set_sysclk, .component_driver = { .controls = msm8916_wcd_digital_snd_controls, .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), -- cgit v1.2.3 From 820f7541f952afa8db08ccd420f29a2c6c148709 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 2 Aug 2017 15:17:46 +0200 Subject: ASoC: codecs: msm8916-wcd-digital: add support to set_sysclk This patch adds support to set_sysclk() which can let the sound card driver to set default mclk rate. In this case MCLK for internal audio codec is expected to be at 9.6MHz by default. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index f690442af8c9..825cc7d70bb3 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -568,6 +568,15 @@ static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) return 0; } +static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev); + + return clk_set_rate(p->mclk, freq); +} + static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -823,6 +832,7 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { static struct snd_soc_codec_driver msm8916_wcd_digital = { .probe = msm8916_wcd_digital_codec_probe, + .set_sysclk = msm8916_wcd_digital_codec_set_sysclk, .component_driver = { .controls = msm8916_wcd_digital_snd_controls, .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), -- cgit v1.2.3 From 3a88a3757dc654c29c87f4537053d0f3dc28d9e0 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 2 Aug 2017 15:17:48 +0200 Subject: ASoC: codecs: msm8916-wcd-digital: add CIC filter source selection path This patch fixes a missing selection of DMIC in CIC filter source path to dapm route. Without this patch dmic is not functional. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 825cc7d70bb3..d2993e72d1e2 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -218,6 +218,8 @@ static const char *const rx_mix1_text[] = { static const char *const dec_mux_text[] = { "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" }; + +static const char *const cic_mux_text[] = { "AMIC", "DMIC" }; static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; @@ -256,11 +258,21 @@ static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); +/* CIC */ +static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text); +static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text); + /* RDAC2 MUX */ static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( "DEC1 MUX Mux", dec1_mux_enum); static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( "DEC2 MUX Mux", dec2_mux_enum); +static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM( + "CIC1 MUX Mux", cic1_mux_enum); +static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM( + "CIC2 MUX Mux", cic2_mux_enum); static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( @@ -500,6 +512,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, &rx3_mix1_inp3_mux), + SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux), + SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux), /* TX */ SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -536,6 +550,8 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { /* Connectivity Clock */ SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, NULL, 0), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), }; @@ -655,6 +671,11 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { {"AIF1 Capture", NULL, "I2S TX2"}, {"AIF1 Capture", NULL, "I2S TX3"}, + {"CIC1 MUX", "DMIC", "DEC1 MUX"}, + {"CIC1 MUX", "AMIC", "DEC1 MUX"}, + {"CIC2 MUX", "DMIC", "DEC2 MUX"}, + {"CIC2 MUX", "AMIC", "DEC2 MUX"}, + /* Decimator Inputs */ {"DEC1 MUX", "DMIC1", "DMIC1"}, {"DEC1 MUX", "DMIC2", "DMIC2"}, @@ -673,8 +694,8 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { {"DMIC1", NULL, "DMIC_CLK"}, {"DMIC2", NULL, "DMIC_CLK"}, - {"I2S TX1", NULL, "DEC1 MUX"}, - {"I2S TX2", NULL, "DEC2 MUX"}, + {"I2S TX1", NULL, "CIC1 MUX"}, + {"I2S TX2", NULL, "CIC2 MUX"}, {"I2S TX1", NULL, "TX_I2S_CLK"}, {"I2S TX2", NULL, "TX_I2S_CLK"}, -- cgit v1.2.3 From b56bff43a965ffe03b4a994fd1a102059d272807 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 7 Aug 2017 18:39:32 +0800 Subject: ASoC: rt5514: reset dma_offset at hw_params dma_offset needs reset every time otherwise for consecutive PCM open the last dma_offset value will cause incorrect pointer position be reported to user space. Signed-off-by: Hsin-Yu Chao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 6f513cc4c56c..640193d845be 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -151,7 +151,6 @@ static irqreturn_t rt5514_spi_irq(int irq, void *data) u8 buf[8]; rt5514_dsp->get_size = 0; - rt5514_dsp->dma_offset = 0; /** * The address area x1800XXXX is the register address, and it cannot @@ -205,6 +204,7 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream, ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); rt5514_dsp->substream = substream; + rt5514_dsp->dma_offset = 0; mutex_unlock(&rt5514_dsp->dma_lock); return ret; -- cgit v1.2.3 From ade82fdbae6905e80f107596f2e0b4df84490d28 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Wed, 9 Aug 2017 09:56:14 +0800 Subject: ASoC: rt5514: Eliminate the noise in the ASRC case In the ASRC case, there is the noise if the clock is asynchronous with the LRCK. The default settings will eliminate the noise. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 21cbb566c0d3..0eabe569ab73 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -64,6 +64,8 @@ static const struct reg_sequence rt5514_patch[] = { {RT5514_ANA_CTRL_LDO10, 0x00028604}, {RT5514_ANA_CTRL_ADCFED, 0x00000800}, {RT5514_ASRC_IN_CTRL1, 0x00000003}, + {RT5514_DOWNFILTER0_CTRL3, 0x10000362}, + {RT5514_DOWNFILTER1_CTRL3, 0x10000362}, }; static const struct reg_default rt5514_reg[] = { @@ -89,10 +91,10 @@ static const struct reg_default rt5514_reg[] = { {RT5514_DELAY_BUF_CTRL3, 0x00000000}, {RT5514_DOWNFILTER0_CTRL1, 0x00020c2f}, {RT5514_DOWNFILTER0_CTRL2, 0x00020c2f}, - {RT5514_DOWNFILTER0_CTRL3, 0x00000362}, + {RT5514_DOWNFILTER0_CTRL3, 0x10000362}, {RT5514_DOWNFILTER1_CTRL1, 0x00020c2f}, {RT5514_DOWNFILTER1_CTRL2, 0x00020c2f}, - {RT5514_DOWNFILTER1_CTRL3, 0x00000362}, + {RT5514_DOWNFILTER1_CTRL3, 0x10000362}, {RT5514_ANA_CTRL_LDO10, 0x00028604}, {RT5514_ANA_CTRL_LDO18_16, 0x02000345}, {RT5514_ANA_CTRL_ADC12, 0x0000a2a8}, -- cgit v1.2.3 From a180ba45b1cf630b3bd5912ce235b2ee16606b8e Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Thu, 3 Aug 2017 21:30:19 +0530 Subject: ASoC: codecs: add const to snd_soc_codec_driver structures Declare snd_soc_codec_driver structures as const as they are only passed as an argument to the function snd_soc_register_codec. This argument is of type const, so declare the structures with this property as const. In file codecs/sn95031.c, snd_soc_codec_driver structure is also used in a copy operation along with getting passed to snd_soc_register_codec. So, it can be made const too. Done using Coccinelle: @match disable optional_qualifier@ identifier s; position p; @@ static struct snd_soc_codec_driver s@p={...}; @good1@ identifier match.s; position p; @@ snd_soc_register_codec(...,&s@p,...) @bad@ identifier match.s; position p!={match.p,good1.p}; @@ s@p @depends on !bad disable optional_qualifier@ identifier match.s; @@ static +const struct snd_soc_codec_driver s={...}; Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 2 +- sound/soc/codecs/ab8500-codec.c | 2 +- sound/soc/codecs/ac97.c | 2 +- sound/soc/codecs/ad1836.c | 2 +- sound/soc/codecs/ad193x.c | 2 +- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/ad73311.c | 2 +- sound/soc/codecs/adau1373.c | 2 +- sound/soc/codecs/adau1701.c | 2 +- sound/soc/codecs/adau1977.c | 2 +- sound/soc/codecs/adav80x.c | 2 +- sound/soc/codecs/ads117x.c | 2 +- sound/soc/codecs/ak4104.c | 2 +- sound/soc/codecs/ak4535.c | 2 +- sound/soc/codecs/ak4554.c | 2 +- sound/soc/codecs/ak4613.c | 2 +- sound/soc/codecs/ak4641.c | 2 +- sound/soc/codecs/ak4642.c | 2 +- sound/soc/codecs/ak4671.c | 2 +- sound/soc/codecs/ak5386.c | 2 +- sound/soc/codecs/alc5623.c | 2 +- sound/soc/codecs/bt-sco.c | 2 +- sound/soc/codecs/cq93vc.c | 2 +- sound/soc/codecs/cs35l33.c | 2 +- sound/soc/codecs/cs35l34.c | 2 +- sound/soc/codecs/cs35l35.c | 2 +- sound/soc/codecs/cs4271.c | 2 +- sound/soc/codecs/cs42l51.c | 2 +- sound/soc/codecs/cs4349.c | 2 +- sound/soc/codecs/cs47l24.c | 2 +- sound/soc/codecs/cs53l30.c | 2 +- sound/soc/codecs/cx20442.c | 2 +- sound/soc/codecs/da7210.c | 2 +- sound/soc/codecs/da7213.c | 2 +- sound/soc/codecs/da7218.c | 2 +- sound/soc/codecs/da7219.c | 2 +- sound/soc/codecs/da732x.c | 2 +- sound/soc/codecs/da9055.c | 2 +- sound/soc/codecs/dmic.c | 2 +- sound/soc/codecs/es7134.c | 2 +- sound/soc/codecs/es8316.c | 2 +- sound/soc/codecs/es8328.c | 2 +- sound/soc/codecs/hdac_hdmi.c | 2 +- sound/soc/codecs/hdmi-codec.c | 2 +- sound/soc/codecs/ics43432.c | 2 +- sound/soc/codecs/inno_rk3036.c | 2 +- sound/soc/codecs/isabelle.c | 2 +- sound/soc/codecs/jz4740.c | 2 +- sound/soc/codecs/lm49453.c | 2 +- sound/soc/codecs/max98088.c | 2 +- sound/soc/codecs/max98090.c | 2 +- sound/soc/codecs/max98095.c | 2 +- sound/soc/codecs/max98357a.c | 2 +- sound/soc/codecs/max9850.c | 2 +- sound/soc/codecs/max9860.c | 2 +- sound/soc/codecs/max9867.c | 2 +- sound/soc/codecs/max98926.c | 2 +- sound/soc/codecs/mc13783.c | 2 +- sound/soc/codecs/ml26124.c | 2 +- sound/soc/codecs/msm8916-wcd-analog.c | 2 +- sound/soc/codecs/msm8916-wcd-digital.c | 2 +- sound/soc/codecs/nau8540.c | 2 +- sound/soc/codecs/nau8810.c | 2 +- sound/soc/codecs/nau8824.c | 2 +- sound/soc/codecs/nau8825.c | 2 +- sound/soc/codecs/pcm1681.c | 2 +- sound/soc/codecs/pcm179x.c | 2 +- sound/soc/codecs/pcm3008.c | 2 +- sound/soc/codecs/pcm512x.c | 2 +- sound/soc/codecs/rt274.c | 2 +- sound/soc/codecs/rt286.c | 2 +- sound/soc/codecs/rt298.c | 2 +- sound/soc/codecs/rt5514.c | 2 +- sound/soc/codecs/rt5616.c | 2 +- sound/soc/codecs/rt5631.c | 2 +- sound/soc/codecs/rt5640.c | 2 +- sound/soc/codecs/rt5645.c | 2 +- sound/soc/codecs/rt5651.c | 2 +- sound/soc/codecs/rt5659.c | 2 +- sound/soc/codecs/rt5660.c | 2 +- sound/soc/codecs/rt5663.c | 2 +- sound/soc/codecs/rt5665.c | 2 +- sound/soc/codecs/rt5670.c | 2 +- sound/soc/codecs/rt5677.c | 2 +- sound/soc/codecs/sgtl5000.c | 2 +- sound/soc/codecs/si476x.c | 2 +- sound/soc/codecs/sirf-audio-codec.c | 2 +- sound/soc/codecs/sn95031.c | 2 +- sound/soc/codecs/spdif_receiver.c | 2 +- sound/soc/codecs/spdif_transmitter.c | 2 +- sound/soc/codecs/ssm2518.c | 2 +- sound/soc/codecs/ssm2602.c | 2 +- sound/soc/codecs/ssm4567.c | 2 +- sound/soc/codecs/stac9766.c | 2 +- sound/soc/codecs/tas2552.c | 2 +- sound/soc/codecs/tas5086.c | 2 +- sound/soc/codecs/tas5720.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/codecs/tlv320aic26.c | 2 +- sound/soc/codecs/tlv320aic31xx.c | 2 +- sound/soc/codecs/tlv320aic32x4.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/tlv320dac33.c | 2 +- sound/soc/codecs/twl4030.c | 2 +- sound/soc/codecs/twl6040.c | 2 +- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda1380.c | 2 +- sound/soc/codecs/wl1273.c | 2 +- sound/soc/codecs/zx_aud96p22.c | 2 +- 109 files changed, 109 insertions(+), 109 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index b013a4c62b63..848c5fe49bc7 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1355,7 +1355,7 @@ static struct regmap *pm860x_get_regmap(struct device *dev) return pm860x->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_pm860x = { +static const struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, .set_bias_level = pm860x_set_bias_level, diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 312b2a11abb6..006627b8c3a8 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2523,7 +2523,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) return status; } -static struct snd_soc_codec_driver ab8500_codec_driver = { +static const struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, .component_driver = { .controls = ab8500_ctrls, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index f7f04c6be01e..440b4ce54376 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -112,7 +112,7 @@ static int ac97_soc_resume(struct snd_soc_codec *codec) #define ac97_soc_resume NULL #endif -static struct snd_soc_codec_driver soc_codec_dev_ac97 = { +static const struct snd_soc_codec_driver soc_codec_dev_ac97 = { .probe = ac97_soc_probe, .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index a478239aadac..d0361caad09e 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -321,7 +321,7 @@ static int ad1836_remove(struct snd_soc_codec *codec) AD1836_ADC_SERFMT_MASK, 0); } -static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { +static const struct snd_soc_codec_driver soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, .suspend = ad1836_suspend, diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index d643557d89a7..d10988eec0c1 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -408,7 +408,7 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_ad193x = { +static const struct snd_soc_codec_driver soc_codec_dev_ad193x = { .probe = ad193x_codec_probe, .component_driver = { .controls = ad193x_snd_controls, diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index b7c1b9f4bf5f..ce89bfb42094 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -295,7 +295,7 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { +static const struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .probe = ad1980_soc_probe, .remove = ad1980_soc_remove, diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 3e358a49442d..d8d86a0fea60 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -54,7 +54,7 @@ static struct snd_soc_dai_driver ad73311_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; -static struct snd_soc_codec_driver soc_codec_dev_ad73311 = { +static const struct snd_soc_codec_driver soc_codec_dev_ad73311 = { .component_driver = { .dapm_widgets = ad73311_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets), diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 8fa9045571ff..a865945d776a 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1458,7 +1458,7 @@ static const struct regmap_config adau1373_regmap_config = { .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), }; -static struct snd_soc_codec_driver adau1373_codec_driver = { +static const struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 3bad1bc8c00a..805afac8146b 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -757,7 +757,7 @@ static int adau1701_resume(struct snd_soc_codec *codec) #define adau1701_suspend NULL #endif /* CONFIG_PM */ -static struct snd_soc_codec_driver adau1701_codec_drv = { +static const struct snd_soc_codec_driver adau1701_codec_drv = { .probe = adau1701_probe, .remove = adau1701_remove, .resume = adau1701_resume, diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index b319db6a69f8..329281675765 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -867,7 +867,7 @@ static int adau1977_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver adau1977_codec_driver = { +static const struct snd_soc_codec_driver adau1977_codec_driver = { .probe = adau1977_codec_probe, .set_bias_level = adau1977_set_bias_level, .set_sysclk = adau1977_set_sysclk, diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 6e793ebb5883..da7ca81f47cf 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -825,7 +825,7 @@ static int adav80x_resume(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver adav80x_codec_driver = { +static const struct snd_soc_codec_driver adav80x_codec_driver = { .probe = adav80x_probe, .resume = adav80x_resume, .set_bias_level = adav80x_set_bias_level, diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 90c756d183b4..b7f0057c0239 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -58,7 +58,7 @@ static struct snd_soc_dai_driver ads117x_dai = { .formats = ADS117X_FORMATS,}, }; -static struct snd_soc_codec_driver soc_codec_dev_ads117x = { +static const struct snd_soc_codec_driver soc_codec_dev_ads117x = { .component_driver = { .dapm_widgets = ads117x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets), diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 1a9d233c94d0..dbb184118f2e 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -242,7 +242,7 @@ static int ak4104_soc_resume(struct snd_soc_codec *codec) #define ak4104_soc_resume NULL #endif /* CONFIG_PM */ -static struct snd_soc_codec_driver soc_codec_device_ak4104 = { +static const struct snd_soc_codec_driver soc_codec_device_ak4104 = { .probe = ak4104_probe, .remove = ak4104_remove, .suspend = ak4104_soc_suspend, diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 66cfffde9a12..e3c157dc88db 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -390,7 +390,7 @@ static const struct regmap_config ak4535_regmap = { .num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults), }; -static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .resume = ak4535_resume, .set_bias_level = ak4535_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c index b92c548b9d29..0bb4fe5c122a 100644 --- a/sound/soc/codecs/ak4554.c +++ b/sound/soc/codecs/ak4554.c @@ -64,7 +64,7 @@ static struct snd_soc_dai_driver ak4554_dai = { .symmetric_rates = 1, }; -static struct snd_soc_codec_driver soc_codec_dev_ak4554 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4554 = { .component_driver = { .dapm_widgets = ak4554_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets), diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 690edebf029e..b95bb8b52e51 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -522,7 +522,7 @@ static int ak4613_resume(struct snd_soc_codec *codec) return regcache_sync(regmap); } -static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4613 = { .suspend = ak4613_suspend, .resume = ak4613_resume, .set_bias_level = ak4613_set_bias_level, diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index ebdaf56c1d61..60142ff32d4f 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -524,7 +524,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4641 = { .component_driver = { .controls = ak4641_snd_controls, .num_controls = ARRAY_SIZE(ak4641_snd_controls), diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 66de8a2013a6..29530c567bd9 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -550,7 +550,7 @@ static int ak4642_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .probe = ak4642_probe, .suspend = ak4642_suspend, .resume = ak4642_resume, diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 6088afaabf62..dcfdff56fc5a 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -610,7 +610,7 @@ static struct snd_soc_dai_driver ak4671_dai = { .ops = &ak4671_dai_ops, }; -static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { +static const struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .set_bias_level = ak4671_set_bias_level, .component_driver = { .controls = ak4671_snd_controls, diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 0ef2df223336..d0e16c03815c 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -69,7 +69,7 @@ static int ak5386_soc_resume(struct snd_soc_codec *codec) #define ak5386_soc_resume NULL #endif /* CONFIG_PM */ -static struct snd_soc_codec_driver soc_codec_ak5386 = { +static const struct snd_soc_codec_driver soc_codec_ak5386 = { .probe = ak5386_soc_probe, .remove = ak5386_soc_remove, .suspend = ak5386_soc_suspend, diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index d2e3a3ef7499..1db965a93632 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -951,7 +951,7 @@ static int alc5623_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_device_alc5623 = { +static const struct snd_soc_codec_driver soc_codec_device_alc5623 = { .probe = alc5623_probe, .suspend = alc5623_suspend, .resume = alc5623_resume, diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index 8014e697d540..806191addb44 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -62,7 +62,7 @@ static struct snd_soc_dai_driver bt_sco_dai[] = { } }; -static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { +static const struct snd_soc_codec_driver soc_codec_dev_bt_sco = { .component_driver = { .dapm_widgets = bt_sco_widgets, .num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets), diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 7a2d9a2ee427..6ed2cc374768 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -128,7 +128,7 @@ static struct regmap *cq93vc_get_regmap(struct device *dev) return davinci_vc->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { +static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, .get_regmap = cq93vc_get_regmap, .component_driver = { diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 6df29fa30fb9..61d128b53e14 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -831,7 +831,7 @@ static int cs35l33_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs35l33 = { .probe = cs35l33_probe, .set_bias_level = cs35l33_set_bias_level, diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 0a747c66cc6c..15d712f4803e 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -779,7 +779,7 @@ static int cs35l34_probe(struct snd_soc_codec *codec) } -static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs35l34 = { .probe = cs35l34_probe, .component_driver = { diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index f1ee184ecab2..129978d1243e 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1079,7 +1079,7 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { .probe = cs35l35_codec_probe, .set_sysclk = cs35l35_codec_set_sysclk, .component_driver = { diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index d8824773dc29..49a80627af12 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -639,7 +639,7 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec) return 0; }; -static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs4271 = { .probe = cs4271_codec_probe, .remove = cs4271_codec_remove, .suspend = cs4271_soc_suspend, diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 96cfe38943cd..f8072f1897d4 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -504,7 +504,7 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { +static const struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .probe = cs42l51_codec_probe, .component_driver = { diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 231ca935cdf3..0a749c79ef57 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -255,7 +255,7 @@ static struct snd_soc_dai_driver cs4349_dai = { .symmetric_rates = 1, }; -static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs4349 = { .component_driver = { .controls = cs4349_snd_controls, .num_controls = ARRAY_SIZE(cs4349_snd_controls), diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 47e6fddef92b..d323caa9c816 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1183,7 +1183,7 @@ static struct regmap *cs47l24_get_regmap(struct device *dev) return priv->core.arizona->regmap; } -static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { .probe = cs47l24_codec_probe, .remove = cs47l24_codec_remove, .get_regmap = cs47l24_get_regmap, diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 06933a5d0a75..da4ee5633778 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -892,7 +892,7 @@ static int cs53l30_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver cs53l30_driver = { +static const struct snd_soc_codec_driver cs53l30_driver = { .probe = cs53l30_codec_probe, .set_bias_level = cs53l30_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 2c12471e42a6..46b1fbb66eba 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -398,7 +398,7 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) static const u8 cx20442_reg; -static struct snd_soc_codec_driver cx20442_codec_dev = { +static const struct snd_soc_codec_driver cx20442_codec_dev = { .probe = cx20442_codec_probe, .remove = cx20442_codec_remove, .set_bias_level = cx20442_set_bias_level, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 17053dfc94cf..1af443ccbc51 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1164,7 +1164,7 @@ static int da7210_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_da7210 = { +static const struct snd_soc_codec_driver soc_codec_dev_da7210 = { .probe = da7210_probe, .component_driver = { diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index c3e11897f8ae..cc0b2d2eaf15 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1787,7 +1787,7 @@ static int da7213_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_da7213 = { +static const struct snd_soc_codec_driver soc_codec_dev_da7213 = { .probe = da7213_probe, .set_bias_level = da7213_set_bias_level, diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 6e1940eb0653..b2d42ec1dcd9 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3035,7 +3035,7 @@ static int da7218_resume(struct snd_soc_codec *codec) #define da7218_resume NULL #endif -static struct snd_soc_codec_driver soc_codec_dev_da7218 = { +static const struct snd_soc_codec_driver soc_codec_dev_da7218 = { .probe = da7218_probe, .remove = da7218_remove, .suspend = da7218_suspend, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index f71d72c22bfc..6f088536df32 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1891,7 +1891,7 @@ static int da7219_resume(struct snd_soc_codec *codec) #define da7219_resume NULL #endif -static struct snd_soc_codec_driver soc_codec_dev_da7219 = { +static const struct snd_soc_codec_driver soc_codec_dev_da7219 = { .probe = da7219_probe, .remove = da7219_remove, .suspend = da7219_suspend, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index c1cc1c1c28f2..83db4d23c90b 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1499,7 +1499,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, return 0; } -static struct snd_soc_codec_driver soc_codec_dev_da732x = { +static const struct snd_soc_codec_driver soc_codec_dev_da732x = { .set_bias_level = da732x_set_bias_level, .component_driver = { .controls = da732x_snd_controls, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 4efb5f897a0c..bd7faaee5802 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1451,7 +1451,7 @@ static int da9055_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_da9055 = { +static const struct snd_soc_codec_driver soc_codec_dev_da9055 = { .probe = da9055_probe, .set_bias_level = da9055_set_bias_level, diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index c82b9dc41e9a..6fe6c0ac4f0b 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -50,7 +50,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"DMIC AIF", NULL, "DMic"}, }; -static struct snd_soc_codec_driver soc_dmic = { +static const struct snd_soc_codec_driver soc_dmic = { .component_driver = { .dapm_widgets = dmic_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c index 25ede825d349..3869025754d8 100644 --- a/sound/soc/codecs/es7134.c +++ b/sound/soc/codecs/es7134.c @@ -69,7 +69,7 @@ static const struct snd_soc_dapm_route es7134_dapm_routes[] = { { "AOUTR", NULL, "DAC" }, }; -static struct snd_soc_codec_driver es7134_codec_driver = { +static const struct snd_soc_codec_driver es7134_codec_driver = { .component_driver = { .dapm_widgets = es7134_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets), diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index ecc02449c569..4f35af6a5d3a 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -554,7 +554,7 @@ static int es8316_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_es8316 = { +static const struct snd_soc_codec_driver soc_codec_dev_es8316 = { .probe = es8316_probe, .idle_bias_off = true, diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index ed7cc42d1ee2..bcdb8914ec16 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -830,7 +830,7 @@ const struct regmap_config es8328_regmap_config = { }; EXPORT_SYMBOL_GPL(es8328_regmap_config); -static struct snd_soc_codec_driver es8328_codec_driver = { +static const struct snd_soc_codec_driver es8328_codec_driver = { .probe = es8328_codec_probe, .suspend = es8328_suspend, .resume = es8328_resume, diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e6de50acefd4..e808f94bf8d1 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1858,7 +1858,7 @@ static void hdmi_codec_complete(struct device *dev) #define hdmi_codec_complete NULL #endif -static struct snd_soc_codec_driver hdmi_hda_codec = { +static const struct snd_soc_codec_driver hdmi_hda_codec = { .probe = hdmi_codec_probe, .remove = hdmi_codec_remove, .idle_bias_off = true, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 509ab513b4b2..f288404f0a61 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -733,7 +733,7 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, return ret; } -static struct snd_soc_codec_driver hdmi_codec = { +static const struct snd_soc_codec_driver hdmi_codec = { .component_driver = { .dapm_widgets = hdmi_widgets, .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index dd850b93938d..651206273f36 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -37,7 +37,7 @@ static struct snd_soc_dai_driver ics43432_dai = { }, }; -static struct snd_soc_codec_driver ics43432_codec_driver = { +static const struct snd_soc_codec_driver ics43432_codec_driver = { }; static int ics43432_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index b918ba5c8ce5..64b0be94bea3 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -376,7 +376,7 @@ static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec, return 0; } -static struct snd_soc_codec_driver rk3036_codec_driver = { +static const struct snd_soc_codec_driver rk3036_codec_driver = { .probe = rk3036_codec_probe, .remove = rk3036_codec_remove, .set_bias_level = rk3036_codec_set_bias_level, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index a4b0eded984a..5ca99280ae00 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1087,7 +1087,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_isabelle = { +static const struct snd_soc_codec_driver soc_codec_dev_isabelle = { .set_bias_level = isabelle_set_bias_level, .component_driver = { .controls = isabelle_snd_controls, diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 0290fab383da..6324ccdc8a5c 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -293,7 +293,7 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { +static const struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .probe = jz4740_codec_dev_probe, .set_bias_level = jz4740_codec_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 8d413c2677cc..41e09d1287b8 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1389,7 +1389,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { +static const struct snd_soc_codec_driver soc_codec_dev_lm49453 = { .set_bias_level = lm49453_set_bias_level, .component_driver = { .controls = lm49453_snd_controls, diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 72f77455582e..f0bb830874e5 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1698,7 +1698,7 @@ static int max98088_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_max98088 = { +static const struct snd_soc_codec_driver soc_codec_dev_max98088 = { .probe = max98088_probe, .remove = max98088_remove, .set_bias_level = max98088_set_bias_level, diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 66828480d484..13bcfb1ef9b4 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2499,7 +2499,7 @@ static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm, } } -static struct snd_soc_codec_driver soc_codec_dev_max98090 = { +static const struct snd_soc_codec_driver soc_codec_dev_max98090 = { .probe = max98090_probe, .remove = max98090_remove, .seq_notifier = max98090_seq_notifier, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 6f8a757876ed..5ead87d2ab1d 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2102,7 +2102,7 @@ static int max98095_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_max98095 = { +static const struct snd_soc_codec_driver soc_codec_dev_max98095 = { .probe = max98095_probe, .remove = max98095_remove, .suspend = max98095_suspend, diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 6a6b68a4cb52..426ed2dae6ca 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -72,7 +72,7 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver max98357a_codec_driver = { +static const struct snd_soc_codec_driver max98357a_codec_driver = { .probe = max98357a_codec_probe, .component_driver = { .dapm_widgets = max98357a_dapm_widgets, diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 0610840733d1..a3dfc918c278 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -301,7 +301,7 @@ static int max9850_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_max9850 = { +static const struct snd_soc_codec_driver soc_codec_dev_max9850 = { .probe = max9850_probe, .set_bias_level = max9850_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 499bdbfd0a2d..a2dc6a47f466 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -534,7 +534,7 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec, return 0; } -static struct snd_soc_codec_driver max9860_codec_driver = { +static const struct snd_soc_codec_driver max9860_codec_driver = { .set_bias_level = max9860_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 2a40a69a7513..6c0c0d6e8f3c 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -413,7 +413,7 @@ static int max9867_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver max9867_codec = { +static const struct snd_soc_codec_driver max9867_codec = { .probe = max9867_probe, .component_driver = { .controls = max9867_snd_controls, diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 1eff7e0b092e..7a39bfb9e0f9 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -496,7 +496,7 @@ static int max98926_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_max98926 = { +static const struct snd_soc_codec_driver soc_codec_dev_max98926 = { .probe = max98926_probe, .component_driver = { .controls = max98926_snd_controls, diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 90562703dcfd..4fd8d1dc4eef 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -733,7 +733,7 @@ static struct regmap *mc13783_get_regmap(struct device *dev) return dev_get_regmap(dev->parent, NULL); } -static struct snd_soc_codec_driver soc_codec_dev_mc13783 = { +static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, .get_regmap = mc13783_get_regmap, diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 69e5e18880c5..5cc960d8211e 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -537,7 +537,7 @@ static int ml26124_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_ml26124 = { +static const struct snd_soc_codec_driver soc_codec_dev_ml26124 = { .probe = ml26124_probe, .set_bias_level = ml26124_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index a78802920c3c..4cc52cecf3b7 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -785,7 +785,7 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { }, }; -static struct snd_soc_codec_driver pm8916_wcd_analog = { +static const struct snd_soc_codec_driver pm8916_wcd_analog = { .probe = pm8916_wcd_analog_probe, .remove = pm8916_wcd_analog_remove, .get_regmap = pm8916_get_regmap, diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 661cd6dd5473..43a915c725a0 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -830,7 +830,7 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { }, }; -static struct snd_soc_codec_driver msm8916_wcd_digital = { +static const struct snd_soc_codec_driver msm8916_wcd_digital = { .probe = msm8916_wcd_digital_codec_probe, .set_sysclk = msm8916_wcd_digital_codec_set_sysclk, .component_driver = { diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index c8bcb1db966d..f9c9933acffb 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -735,7 +735,7 @@ static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver nau8540_codec_driver = { +static const struct snd_soc_codec_driver nau8540_codec_driver = { .set_sysclk = nau8540_set_sysclk, .set_pll = nau8540_set_pll, .suspend = nau8540_suspend, diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index e45518629968..c8e2451ae0a3 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -808,7 +808,7 @@ static const struct regmap_config nau8810_regmap_config = { .num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults), }; -static struct snd_soc_codec_driver nau8810_codec_driver = { +static const struct snd_soc_codec_driver nau8810_codec_driver = { .set_bias_level = nau8810_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 3a309b18035e..0240759f951c 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -1469,7 +1469,7 @@ static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver nau8824_codec_driver = { +static const struct snd_soc_codec_driver nau8824_codec_driver = { .probe = nau8824_codec_probe, .set_sysclk = nau8824_set_sysclk, .set_pll = nau8824_set_pll, diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 46a30eaa7ace..000aa79314fa 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2388,7 +2388,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver nau8825_codec_driver = { +static const struct snd_soc_codec_driver nau8825_codec_driver = { .probe = nau8825_codec_probe, .remove = nau8825_codec_remove, .set_sysclk = nau8825_set_sysclk, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 0b14efab6280..c7e28dd2e815 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -288,7 +288,7 @@ static const struct regmap_config pcm1681_regmap = { .readable_reg = pcm1681_accessible_reg, }; -static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = { +static const struct snd_soc_codec_driver soc_codec_dev_pcm1681 = { .component_driver = { .controls = pcm1681_controls, .num_controls = ARRAY_SIZE(pcm1681_controls), diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index b813a154ddd9..82a3d9db32cb 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -205,7 +205,7 @@ const struct regmap_config pcm179x_regmap_config = { }; EXPORT_SYMBOL_GPL(pcm179x_regmap_config); -static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { +static const struct snd_soc_codec_driver soc_codec_dev_pcm179x = { .component_driver = { .controls = pcm179x_controls, .num_controls = ARRAY_SIZE(pcm179x_controls), diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 708af05486f6..e59d8ffb93bd 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -98,7 +98,7 @@ static struct snd_soc_dai_driver pcm3008_dai = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { +static const struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { .component_driver = { .dapm_widgets = pcm3008_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets), diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 72b19e62f626..f1005a31c709 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1344,7 +1344,7 @@ static struct snd_soc_dai_driver pcm512x_dai = { .ops = &pcm512x_dai_ops, }; -static struct snd_soc_codec_driver pcm512x_codec_driver = { +static const struct snd_soc_codec_driver pcm512x_codec_driver = { .set_bias_level = pcm512x_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index fb683ffc4e03..58cfe244f81e 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1055,7 +1055,7 @@ static struct snd_soc_dai_driver rt274_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt274 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt274 = { .probe = rt274_probe, .remove = rt274_remove, .suspend = rt274_suspend, diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 7899a2cdeb42..af6325c78292 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1046,7 +1046,7 @@ static struct snd_soc_dai_driver rt286_dai[] = { }; -static struct snd_soc_codec_driver soc_codec_dev_rt286 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt286 = { .probe = rt286_probe, .remove = rt286_remove, .suspend = rt286_suspend, diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index d9e96e65e1c4..ce963768449f 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1113,7 +1113,7 @@ static struct snd_soc_dai_driver rt298_dai[] = { }; -static struct snd_soc_codec_driver soc_codec_dev_rt298 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt298 = { .probe = rt298_probe, .remove = rt298_remove, .suspend = rt298_suspend, diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 1b6796c4c471..7a1b36f6596a 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1042,7 +1042,7 @@ struct snd_soc_dai_driver rt5514_dai[] = { } }; -static struct snd_soc_codec_driver soc_codec_dev_rt5514 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5514 = { .probe = rt5514_probe, .idle_bias_off = true, .set_bias_level = rt5514_set_bias_level, diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 7d6e0823f98f..3c5f555ae6d0 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver rt5616_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5616 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5616 = { .probe = rt5616_probe, .suspend = rt5616_suspend, .resume = rt5616_resume, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 0e418089c053..55b04c55fb4b 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1653,7 +1653,7 @@ static struct snd_soc_dai_driver rt5631_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5631 = { .probe = rt5631_probe, .set_bias_level = rt5631_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 1584ccc3a87b..438fe52a12df 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2259,7 +2259,7 @@ static struct snd_soc_dai_driver rt5640_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5640 = { .probe = rt5640_probe, .remove = rt5640_remove, .suspend = rt5640_suspend, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ec58166f7c4..ce31d0dcf894 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3473,7 +3473,7 @@ static struct snd_soc_dai_driver rt5645_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5645 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5645 = { .probe = rt5645_probe, .remove = rt5645_remove, .suspend = rt5645_suspend, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index db05b60d5002..da60b28ba3df 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1664,7 +1664,7 @@ static struct snd_soc_dai_driver rt5651_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5651 = { .probe = rt5651_probe, .suspend = rt5651_suspend, .resume = rt5651_resume, diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 1b7060850340..e8018fce7e4b 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3730,7 +3730,7 @@ static struct snd_soc_dai_driver rt5659_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5659 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = { .probe = rt5659_probe, .remove = rt5659_remove, .suspend = rt5659_suspend, diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index c93490d77f2a..d22ef00e0d96 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1197,7 +1197,7 @@ static struct snd_soc_dai_driver rt5660_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5660 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5660 = { .probe = rt5660_probe, .remove = rt5660_remove, .suspend = rt5660_suspend, diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index a33202affeb1..ebc5e3b2b62b 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2891,7 +2891,7 @@ static struct snd_soc_dai_driver rt5663_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5663 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5663 = { .probe = rt5663_probe, .remove = rt5663_remove, .suspend = rt5663_suspend, diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 370ed54d1e15..2c405456d89f 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4562,7 +4562,7 @@ static struct snd_soc_dai_driver rt5665_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5665 = { .probe = rt5665_probe, .remove = rt5665_remove, .suspend = rt5665_suspend, diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0ec7985ed306..52a6ce8f0b39 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2765,7 +2765,7 @@ static struct snd_soc_dai_driver rt5670_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5670 = { .probe = rt5670_probe, .remove = rt5670_remove, .suspend = rt5670_suspend, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 36e530a36c82..ce9b65d466e8 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4968,7 +4968,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { +static const struct snd_soc_codec_driver soc_codec_dev_rt5677 = { .probe = rt5677_probe, .remove = rt5677_remove, .suspend = rt5677_suspend, diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 8f6814c1eb6b..68e7020b2875 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1248,7 +1248,7 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver sgtl5000_driver = { +static const struct snd_soc_codec_driver sgtl5000_driver = { .probe = sgtl5000_probe, .remove = sgtl5000_remove, .set_bias_level = sgtl5000_set_bias_level, diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 5344f4aa8fde..354dc0d64f11 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -236,7 +236,7 @@ static struct regmap *si476x_get_regmap(struct device *dev) return dev_get_regmap(dev->parent, NULL); } -static struct snd_soc_codec_driver soc_codec_dev_si476x = { +static const struct snd_soc_codec_driver soc_codec_dev_si476x = { .get_regmap = si476x_get_regmap, .component_driver = { .dapm_widgets = si476x_dapm_widgets, diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 6bfd25c289d1..50bc22266ecb 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -429,7 +429,7 @@ static int sirf_audio_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { +static const struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { .probe = sirf_audio_codec_probe, .remove = sirf_audio_codec_remove, .dapm_widgets = sirf_audio_codec_dapm_widgets, diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index eae54c37cff9..887923e68849 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -883,7 +883,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver sn95031_codec = { +static const struct snd_soc_codec_driver sn95031_codec = { .probe = sn95031_codec_probe, .set_bias_level = sn95031_set_vaud_bias, .idle_bias_off = true, diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 234f87b54838..7acd05140a81 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dir_routes[] = { SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) -static struct snd_soc_codec_driver soc_codec_spdif_dir = { +static const struct snd_soc_codec_driver soc_codec_spdif_dir = { .component_driver = { .dapm_widgets = dir_widgets, .num_dapm_widgets = ARRAY_SIZE(dir_widgets), diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index ee367536a498..063a64ff82d3 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -37,7 +37,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { { "spdif-out", NULL, "Playback" }, }; -static struct snd_soc_codec_driver soc_codec_spdif_dit = { +static const struct snd_soc_codec_driver soc_codec_spdif_dit = { .component_driver = { .dapm_widgets = dit_widgets, .num_dapm_widgets = ARRAY_SIZE(dit_widgets), diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 38a85f3adc80..15486fd16269 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -710,7 +710,7 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, SSM2518_POWER1_NO_BCLK, val); } -static struct snd_soc_codec_driver ssm2518_codec_driver = { +static const struct snd_soc_codec_driver ssm2518_codec_driver = { .set_bias_level = ssm2518_set_bias_level, .set_sysclk = ssm2518_set_sysclk, .idle_bias_off = true, diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 993bde29ca1b..9b341c23f62b 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -591,7 +591,7 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec) return ret; } -static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { +static const struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { .probe = ssm260x_codec_probe, .resume = ssm2602_resume, .set_bias_level = ssm2602_set_bias_level, diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index a622623e8558..4afeddef7728 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -417,7 +417,7 @@ static struct snd_soc_dai_driver ssm4567_dai = { .ops = &ssm4567_dai_ops, }; -static struct snd_soc_codec_driver ssm4567_codec_driver = { +static const struct snd_soc_codec_driver ssm4567_codec_driver = { .set_bias_level = ssm4567_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 9de7fe8af255..c66363a2cac7 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -307,7 +307,7 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { +static const struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .component_driver = { .controls = stac9766_snd_ac97_controls, .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 8840f72f3c4a..49cf9bc32eb6 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -660,7 +660,7 @@ static int tas2552_resume(struct snd_soc_codec *codec) #define tas2552_resume NULL #endif -static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { +static const struct snd_soc_codec_driver soc_codec_dev_tas2552 = { .probe = tas2552_codec_probe, .remove = tas2552_codec_remove, .suspend = tas2552_suspend, diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index b7de857abb16..199272d5cb6a 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -885,7 +885,7 @@ static int tas5086_remove(struct snd_soc_codec *codec) return 0; }; -static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { +static const struct snd_soc_codec_driver soc_codec_dev_tas5086 = { .probe = tas5086_probe, .remove = tas5086_remove, .suspend = tas5086_soc_suspend, diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index c65b917598d2..d14b78b1917b 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -483,7 +483,7 @@ static const struct snd_soc_dapm_route tas5720_audio_map[] = { { "OUT", NULL, "DAC" }, }; -static struct snd_soc_codec_driver soc_codec_dev_tas5720 = { +static const struct snd_soc_codec_driver soc_codec_dev_tas5720 = { .probe = tas5720_codec_probe, .remove = tas5720_codec_remove, .suspend = tas5720_suspend, diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 628a8eeaab68..3d42138a7974 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -576,7 +576,7 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { +static const struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .probe = tlv320aic23_codec_probe, .resume = tlv320aic23_resume, .set_bias_level = tlv320aic23_set_bias_level, diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 14aa96d41719..89421caaeb70 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -319,7 +319,7 @@ static int aic26_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver aic26_soc_codec_dev = { +static const struct snd_soc_codec_driver aic26_soc_codec_dev = { .probe = aic26_probe, .component_driver = { .controls = aic26_snd_controls, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index d7d03c92cb8a..54a87a905eb6 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1185,7 +1185,7 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { +static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, .remove = aic31xx_codec_remove, .set_bias_level = aic31xx_set_bias_level, diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 28fdfc5ec544..ccfc955321ae 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -792,7 +792,7 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { +static const struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { .probe = aic32x4_codec_probe, .set_bias_level = aic32x4_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 29bf8c81ae02..405f4602888a 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1684,7 +1684,7 @@ static int aic3x_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_aic3x = { +static const struct snd_soc_codec_driver soc_codec_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, .idle_bias_off = true, .probe = aic3x_probe, diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 7bcf01efdf9a..5b94a151539c 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1433,7 +1433,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { +static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { .read = dac33_read_reg_cache, .write = dac33_write_locked, .set_bias_level = dac33_set_bias_level, diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index a2104d68169d..d439c4c6fe50 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2191,7 +2191,7 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { +static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .probe = twl4030_soc_probe, .remove = twl4030_soc_remove, .read = twl4030_read, diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 2b6ad09e0886..0dc21f7e0af9 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1155,7 +1155,7 @@ static int twl6040_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { +static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .probe = twl6040_probe, .remove = twl6040_remove, .read = twl6040_read, diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 5fdee874406d..77c9cc4467b8 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -518,7 +518,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_uda134x = { +static const struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, .set_bias_level = uda134x_set_bias_level, .suspend_bias_off = true, diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 61cdc79840e7..926c81ae8185 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -720,7 +720,7 @@ static int uda1380_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { +static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, .read = uda1380_read_reg_cache, .write = uda1380_write, diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index fcffb6e707d9..942f1644973e 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -480,7 +480,7 @@ static int wl1273_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { +static const struct snd_soc_codec_driver soc_codec_dev_wl1273 = { .probe = wl1273_probe, .remove = wl1273_remove, diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c index 032fb7cf6cbd..36d0a7087a54 100644 --- a/sound/soc/codecs/zx_aud96p22.c +++ b/sound/soc/codecs/zx_aud96p22.c @@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = { { "LINEOUTMN", NULL, "LD2" }, }; -static struct snd_soc_codec_driver aud96p22_driver = { +static const struct snd_soc_codec_driver aud96p22_driver = { .component_driver = { .controls = aud96p22_snd_controls, .num_controls = ARRAY_SIZE(aud96p22_snd_controls), -- cgit v1.2.3 From 52981e29eedf6e90ee381c2c1a64be1848d3353e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 9 Aug 2017 18:49:23 +0200 Subject: ASoC: codecs: msm8916-wcd-analog: move codec reset to probe This patch move the codec reset code from dai ops to codec probe, so that the codec is not held in reset when headset detection block is still active. Without this patch the codec block will be in reset as long as its not actively used, which means headset events will not be functional if the codec dai is not actively used. Point to note is that the headset detection blocks will work in low power when there is no active audio usecase and switch to micbias source when audio usecase is active. Existing dapms should put the codec in low power state anyway when there is no audio usecase. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index a78802920c3c..f9a74ff2ce99 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -536,6 +536,9 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, wcd_reg_defaults_2_0[reg].def); + snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, + RST_CTL_DIG_SW_RST_N_REMOVE_RESET); return 0; } @@ -543,6 +546,9 @@ static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec) { struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, 0); + return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); } @@ -736,28 +742,6 @@ static struct regmap *pm8916_get_regmap(struct device *dev) return dev_get_regmap(dev->parent, NULL); } -static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, - RST_CTL_DIG_SW_RST_N_MASK, - RST_CTL_DIG_SW_RST_N_REMOVE_RESET); - - return 0; -} - -static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, - RST_CTL_DIG_SW_RST_N_MASK, 0); -} - -static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { - .startup = pm8916_wcd_analog_startup, - .shutdown = pm8916_wcd_analog_shutdown, -}; - static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { [0] = { .name = "pm8916_wcd_analog_pdm_rx", @@ -769,7 +753,6 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { .channels_min = 1, .channels_max = 3, }, - .ops = &pm8916_wcd_analog_dai_ops, }, [1] = { .name = "pm8916_wcd_analog_pdm_tx", @@ -781,7 +764,6 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { .channels_min = 1, .channels_max = 4, }, - .ops = &pm8916_wcd_analog_dai_ops, }, }; -- cgit v1.2.3 From 4428ffa1fe66a9e3cf68bba3ad135f17be4ed674 Mon Sep 17 00:00:00 2001 From: Sapthagiri Baratam Date: Mon, 14 Aug 2017 15:46:24 +0100 Subject: arizona: anc: Correct setting of FCx_MIC_MODE_SEL The mask rather than the shift is accidentally passed to the SOC_ENUM_SINGLE macro which results in the wrong bits being set for this control, change to using the shift to correct this. Signed-off-by: Sapthagiri Baratam Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0a734d910850..a1149f6a8450 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -710,7 +710,7 @@ const struct soc_enum arizona_anc_input_src[] = { ARRAY_SIZE(arizona_anc_input_src_text), arizona_anc_input_src_text), SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL, - ARIZONA_FCL_MIC_MODE_SEL, + ARIZONA_FCL_MIC_MODE_SEL_SHIFT, ARRAY_SIZE(arizona_anc_channel_src_text), arizona_anc_channel_src_text), SOC_ENUM_SINGLE(ARIZONA_ANC_SRC, @@ -718,7 +718,7 @@ const struct soc_enum arizona_anc_input_src[] = { ARRAY_SIZE(arizona_anc_input_src_text), arizona_anc_input_src_text), SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL, - ARIZONA_FCR_MIC_MODE_SEL, + ARIZONA_FCR_MIC_MODE_SEL_SHIFT, ARRAY_SIZE(arizona_anc_channel_src_text), arizona_anc_channel_src_text), }; -- cgit v1.2.3 From 9ab51b9469e6a63dbf4385bdd02704e87b65a039 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 13 Aug 2017 16:00:33 +0100 Subject: ASoC: max98926: make max98926_spk_tlv and max98926_current_tlv static max98926_spk_tlv and max98926_current_tlv are local to the source and do not need to be in global scope, so make them static. Cleans up sparse warnings: symbol 'max98926_spk_tlv' was not declared. Should it be static? symbol 'max98926_current_tlv' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index f16145d8ee6b..13d2708657e1 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -213,8 +213,8 @@ static bool max98926_readable_register(struct device *dev, unsigned int reg) } }; -DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); -DECLARE_TLV_DB_RANGE(max98926_current_tlv, +static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); +static DECLARE_TLV_DB_RANGE(max98926_current_tlv, 0, 11, TLV_DB_SCALE_ITEM(20, 20, 0), 12, 15, TLV_DB_SCALE_ITEM(320, 40, 0), ); -- cgit v1.2.3 From e5e8e6182a3b9514cde41d957684b59ee8f6cf21 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 13 Aug 2017 16:08:03 +0100 Subject: ASoC: rt5514: make array rt5514_dai static The array rt5514_dai is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warnings: symbol 'rt5514_dai' was not declared. Should it be static? warning: symbol 'rt5514_dai' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 0eabe569ab73..a694ce9fed86 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1066,7 +1066,7 @@ static const struct snd_soc_dai_ops rt5514_aif_dai_ops = { .set_tdm_slot = rt5514_set_tdm_slot, }; -struct snd_soc_dai_driver rt5514_dai[] = { +static struct snd_soc_dai_driver rt5514_dai[] = { { .name = "rt5514-aif1", .id = 0, -- cgit v1.2.3 From def4b1243e56774fdc47de9292111a344f14e88c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 13 Aug 2017 16:28:08 +0100 Subject: ASoC: zx_aud96p22: make array aud96p22_dt_ids static The array aud96p22_dt_ids is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warning: symbol 'aud96p22_dt_ids' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/zx_aud96p22.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c index 032fb7cf6cbd..bc23ce1a30a1 100644 --- a/sound/soc/codecs/zx_aud96p22.c +++ b/sound/soc/codecs/zx_aud96p22.c @@ -382,7 +382,7 @@ static int aud96p22_i2c_remove(struct i2c_client *i2c) return 0; } -const struct of_device_id aud96p22_dt_ids[] = { +static const struct of_device_id aud96p22_dt_ids[] = { { .compatible = "zte,zx-aud96p22", }, { } }; -- cgit v1.2.3 From c5755fbc0702ddb38d2b476a49327b59d4d75a00 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Mon, 14 Aug 2017 09:46:59 +0800 Subject: ASoC: rt5663: Fine tune for the headphone output pop sound The patch fine tunes for the headphone output pop sound. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index be93231b0f58..fdc2bbcb67c2 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1565,6 +1565,10 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003; dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5663_OSW_HP_L_MASK | RT5663_OSW_HP_R_MASK, + RT5663_OSW_HP_L_EN | RT5663_OSW_HP_R_EN); + switch (val) { case 1: case 2: @@ -2073,6 +2077,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766); snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa); snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777); + snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000, + 0x8000); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x3000); } @@ -2105,14 +2111,19 @@ static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - if (rt5663->codec_ver == CODEC_VER_0) - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x003b, - 0x003b); + if (rt5663->codec_ver == CODEC_VER_0) { + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, + 0x0030); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, + 0x0003); + } break; case SND_SOC_DAPM_POST_PMD: - if (rt5663->codec_ver == CODEC_VER_0) - snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x003b, 0); + if (rt5663->codec_ver == CODEC_VER_0) { + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0); + } break; default: -- cgit v1.2.3 From 0ed6f15701efa0d62b4556900cd67a726578389e Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 14 Aug 2017 17:08:40 +0530 Subject: ASoC: codecs: make snd_soc_platform_driver const Make these const as they are either passed as the 2nd argument to the function devm_snd_soc_register_platform or snd_soc_register_platform, and the arguments are of type const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 2 +- sound/soc/codecs/rt5514-spi.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm5110.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index d323caa9c816..505dbc9d73cf 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1213,7 +1213,7 @@ static struct snd_compr_ops cs47l24_compr_ops = { .copy = wm_adsp_compr_copy, }; -static struct snd_soc_platform_driver cs47l24_compr_platform = { +static const struct snd_soc_platform_driver cs47l24_compr_platform = { .compr_ops = &cs47l24_compr_ops, }; diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 7ed62e8c80b4..87a587fa90fe 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -260,7 +260,7 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform) return 0; } -static struct snd_soc_platform_driver rt5514_spi_platform = { +static const struct snd_soc_platform_driver rt5514_spi_platform = { .probe = rt5514_spi_pcm_probe, .ops = &rt5514_spi_pcm_ops, }; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 1fe358e6be61..f5006923be2e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2027,7 +2027,7 @@ static struct snd_compr_ops wm5102_compr_ops = { .copy = wm_adsp_compr_copy, }; -static struct snd_soc_platform_driver wm5102_compr_platform = { +static const struct snd_soc_platform_driver wm5102_compr_platform = { .compr_ops = &wm5102_compr_ops, }; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 1bc942152eff..d6fae1397ce2 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2382,7 +2382,7 @@ static struct snd_compr_ops wm5110_compr_ops = { .copy = wm_adsp_compr_copy, }; -static struct snd_soc_platform_driver wm5110_compr_platform = { +static const struct snd_soc_platform_driver wm5110_compr_platform = { .compr_ops = &wm5110_compr_ops, }; -- cgit v1.2.3 From 3013c75fadc581160be8d89c2c0f29219971c58f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 12 Aug 2017 23:50:28 +0100 Subject: ASoC: hdmi-codec: make a function and two arrays static The function hdmi_codec_eld_chmap and arrays hdmi_codec_stereo_chmaps and hdmi_codec_8ch_chmaps are local to the source and do not need to be in global scope, so make them static. Cleans up sparse warnings: symbol 'hdmi_codec_eld_chmap' was not declared. Should it be static? symbol 'hdmi_codec_stereo_chmaps' was not declared. Should it be static? symbol 'hdmi_codec_8ch_chmaps' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 509ab513b4b2..f7520413c671 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -67,14 +67,14 @@ struct hdmi_codec_cea_spk_alloc { }; /* Channel maps stereo HDMI */ -const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = { +static const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = { { .channels = 2, .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, { } }; /* Channel maps for multi-channel playbacks, up to 8 n_ch */ -const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { +static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { { .channels = 2, /* CA_ID 0x00 */ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, { .channels = 4, /* CA_ID 0x01 */ @@ -340,7 +340,7 @@ static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc) return spk_mask; } -void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp) +static void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp) { u8 spk_alloc; unsigned long spk_mask; -- cgit v1.2.3 From a6a67da3da332dbde7c04cba9fccef04648c704a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 15 Aug 2017 17:10:10 +0200 Subject: ASoC: codecs: es8316: constify snd_soc_dai_ops structures These snd_soc_dai_ops structures are only stored in the ops field of a snd_soc_dai_driver structure, which is const. Thus, the snd_soc_dai_ops structures can be const too. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index ecc02449c569..f5cf48c9c3b0 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -502,7 +502,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute) #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops es8316_ops = { +static const struct snd_soc_dai_ops es8316_ops = { .startup = es8316_pcm_startup, .hw_params = es8316_pcm_hw_params, .set_fmt = es8316_set_dai_fmt, -- cgit v1.2.3 From 66f41da341cd97ad362c4a40e1c9a0a28d746f81 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 15 Aug 2017 17:10:11 +0200 Subject: ASoC: codecs: zx_aud96p22: constify snd_soc_dai_ops structures These snd_soc_dai_ops structures are only stored in the ops field of a snd_soc_dai_driver structure, which is const. Thus, the snd_soc_dai_ops structures can be const too. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/codecs/zx_aud96p22.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c index bc23ce1a30a1..0e5b43b948b4 100644 --- a/sound/soc/codecs/zx_aud96p22.c +++ b/sound/soc/codecs/zx_aud96p22.c @@ -312,7 +312,7 @@ static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static struct snd_soc_dai_ops aud96p22_dai_ops = { +static const struct snd_soc_dai_ops aud96p22_dai_ops = { .set_fmt = aud96p22_set_fmt, }; -- cgit v1.2.3 From 4dbcc5ff2513f2192dc2a5dfdbb9ad3d7e891e85 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 16 Aug 2017 16:09:01 +0530 Subject: ASoC: codecs: make snd_compr_ops const Make these const as they are only stored in the compr_ops field of a snd_soc_platform_driver structure, which is of type const. Done using Coccinelle Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm5110.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 47e6fddef92b..c1cbe23169d7 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1203,7 +1203,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { }, }; -static struct snd_compr_ops cs47l24_compr_ops = { +static const struct snd_compr_ops cs47l24_compr_ops = { .open = cs47l24_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 1fe358e6be61..a8bdbe464f2e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2017,7 +2017,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = { }, }; -static struct snd_compr_ops wm5102_compr_ops = { +static const struct snd_compr_ops wm5102_compr_ops = { .open = wm5102_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 1bc942152eff..8aa136c28ec1 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2372,7 +2372,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = { }, }; -static struct snd_compr_ops wm5110_compr_ops = { +static const struct snd_compr_ops wm5110_compr_ops = { .open = wm5110_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, -- cgit v1.2.3 From 23c7159a799f3364720b3d250f57bc8e26b17287 Mon Sep 17 00:00:00 2001 From: huang lin Date: Thu, 17 Aug 2017 10:24:44 +0800 Subject: ASoC: codec: use enable pin to control dmic start and stop on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. Signed-off-by: Lin Huang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/dmic.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6c78b0b49b81..952c44dd5e90 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -71,7 +71,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_DIO2125 - select SND_SOC_DMIC + select SND_SOC_DMIC if GPIOLIB select SND_SOC_ES8316 if I2C select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index d50f142e2972..b88a1ee66f80 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -19,6 +19,8 @@ * */ +#include +#include #include #include #include @@ -27,6 +29,34 @@ #include #include +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai); + + if (!dmic_en) + return 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(dmic_en, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(dmic_en, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger = dmic_daiops_trigger, +}; + static struct snd_soc_dai_driver dmic_dai = { .name = "dmic-hifi", .capture = { @@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &dmic_dai_ops, }; +static int dmic_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *dmic_en; + + dmic_en = devm_gpiod_get_optional(codec->dev, + "dmicen", GPIOD_OUT_LOW); + if (IS_ERR(dmic_en)) + return PTR_ERR(dmic_en); + + snd_soc_codec_set_drvdata(codec, dmic_en); + + return 0; +} + static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0, SND_SOC_NOPM, 0, 0), @@ -50,7 +95,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"DMIC AIF", NULL, "DMic"}, }; -static struct snd_soc_codec_driver soc_dmic = { +static const struct snd_soc_codec_driver soc_dmic = { + .probe = dmic_codec_probe, .component_driver = { .dapm_widgets = dmic_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), -- cgit v1.2.3 From 6e37f933ed1ade3201dd609d103c0ef79c0ef6b0 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 16 Aug 2017 22:45:09 +0530 Subject: ASoC: codecs: make snd_soc_dai_driver and snd_soc_component_driver const Make these two structure variables const as they are either used in a copy operation or passed to devm_snd_soc_register_component having the corresponding argument as const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 2 +- sound/soc/codecs/lm4857.c | 2 +- sound/soc/codecs/max9768.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index f288404f0a61..d73d2c1ed823 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -692,7 +692,7 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, return snd_ctl_add(rtd->card->snd_card, kctl); } -static struct snd_soc_dai_driver hdmi_i2s_dai = { +static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, .playback = { diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 558de1053f73..1e964079642a 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -100,7 +100,7 @@ static const struct snd_soc_dapm_route lm4857_routes[] = { { "EP", "Earpiece", "Mode" }, }; -static struct snd_soc_component_driver lm4857_component_driver = { +static const struct snd_soc_component_driver lm4857_component_driver = { .controls = lm4857_controls, .num_controls = ARRAY_SIZE(lm4857_controls), .dapm_widgets = lm4857_dapm_widgets, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 5b82e26cd5d1..7017c0389e73 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -151,7 +151,7 @@ static int max9768_probe(struct snd_soc_component *component) return 0; } -static struct snd_soc_component_driver max9768_component_driver = { +static const struct snd_soc_component_driver max9768_component_driver = { .probe = max9768_probe, .controls = max9768_volume, .num_controls = ARRAY_SIZE(max9768_volume), -- cgit v1.2.3 From eb59d73cb535ba32df928f210fb9a8529bf465c0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 18 Aug 2017 17:35:59 +0530 Subject: ASoC: codecs: constify snd_soc_dai_ops structures snd_soc_dai_ops are not supposed to change at runtime. All functions working with snd_soc_dai_ops provided by work with const snd_soc_dai_ops. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 2 +- sound/soc/codecs/es8316.c | 2 +- sound/soc/codecs/inno_rk3036.c | 2 +- sound/soc/codecs/max9867.c | 2 +- sound/soc/codecs/max98926.c | 2 +- sound/soc/codecs/msm8916-wcd-analog.c | 2 +- sound/soc/codecs/rt5616.c | 2 +- sound/soc/codecs/rt5663.c | 2 +- sound/soc/codecs/tas5720.c | 2 +- sound/soc/codecs/zx_aud96p22.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 55e4520cdcaf..9e860dfa0163 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -911,7 +911,7 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute) SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops cs42l42_ops = { +static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 4f35af6a5d3a..da2d353af5ba 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -502,7 +502,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute) #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops es8316_ops = { +static const struct snd_soc_dai_ops es8316_ops = { .startup = es8316_pcm_startup, .hw_params = es8316_pcm_hw_params, .set_fmt = es8316_set_dai_fmt, diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 64b0be94bea3..6b59b6f08298 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -310,7 +310,7 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops rk3036_codec_dai_ops = { +static const struct snd_soc_dai_ops rk3036_codec_dai_ops = { .set_fmt = rk3036_codec_dai_set_fmt, .hw_params = rk3036_codec_dai_hw_params, }; diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 6c0c0d6e8f3c..2f60924fe919 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -350,7 +350,7 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, return 0; } -static struct snd_soc_dai_ops max9867_dai_ops = { +static const struct snd_soc_dai_ops max9867_dai_ops = { .set_fmt = max9867_dai_set_fmt, .set_sysclk = max9867_set_dai_sysclk, .prepare = max9867_prepare, diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 7a39bfb9e0f9..59d03d036945 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -459,7 +459,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, #define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops max98926_dai_ops = { +static const struct snd_soc_dai_ops max98926_dai_ops = { .set_fmt = max98926_dai_set_fmt, .hw_params = max98926_dai_hw_params, }; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 4cc52cecf3b7..f07674eddc52 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -753,7 +753,7 @@ static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, RST_CTL_DIG_SW_RST_N_MASK, 0); } -static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { +static const struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { .startup = pm8916_wcd_analog_startup, .shutdown = pm8916_wcd_analog_shutdown, }; diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 3c5f555ae6d0..c94e94fe8297 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1265,7 +1265,7 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5616_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5616_aif_dai_ops = { .hw_params = rt5616_hw_params, .set_fmt = rt5616_set_dai_fmt, .set_sysclk = rt5616_set_dai_sysclk, diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index ebc5e3b2b62b..1bbe36338cd3 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2860,7 +2860,7 @@ static int rt5663_resume(struct snd_soc_codec *codec) #define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5663_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5663_aif_dai_ops = { .hw_params = rt5663_hw_params, .set_fmt = rt5663_set_dai_fmt, .set_sysclk = rt5663_set_dai_sysclk, diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index d14b78b1917b..a736a2a6976c 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -507,7 +507,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_tas5720 = { #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops tas5720_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = { .hw_params = tas5720_hw_params, .set_fmt = tas5720_set_dai_fmt, .set_tdm_slot = tas5720_set_dai_tdm_slot, diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c index 36d0a7087a54..51fad48892d3 100644 --- a/sound/soc/codecs/zx_aud96p22.c +++ b/sound/soc/codecs/zx_aud96p22.c @@ -312,7 +312,7 @@ static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static struct snd_soc_dai_ops aud96p22_dai_ops = { +static const struct snd_soc_dai_ops aud96p22_dai_ops = { .set_fmt = aud96p22_set_fmt, }; -- cgit v1.2.3 From e269998d588f8ad96eaf86916e23b8ee3d2b9f1b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 17 Aug 2017 10:02:09 +0200 Subject: ASoC: codecs: msm8916-wcd-analog: get micbias voltage from dt This patch adds bindings in DT to provide required micbias voltage which could be specific to board. With this new binding, now the mic bias voltage is left at hardware default value if the device tree does not specify any mic bias voltage value. Correct micbias value is required for mbhc buttons to work. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- .../bindings/sound/qcom,msm8916-wcd-analog.txt | 1 + sound/soc/codecs/msm8916-wcd-analog.c | 27 +++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt index ccb401cfef9d..05b67a1d4851 100644 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt @@ -33,6 +33,7 @@ Required properties - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. Optional Properties: +- qcom,micbias-lvl: Voltage (mV) for Mic Bias - qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor connected. - qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index a0de3e7204d5..8633524b1961 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -93,8 +93,12 @@ #define MICB_1_EN_TX3_GND_SEL_TX_GND 0 #define CDC_A_MICB_1_VAL (0xf141) +#define MICB_MIN_VAL 1600 +#define MICB_STEP_SIZE 50 +#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE) #define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3) #define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3) +#define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3) #define CDC_A_MICB_1_CTL (0xf142) #define MICB_1_CTL_CFILT_REF_SEL_MASK BIT(1) @@ -225,6 +229,7 @@ struct pm8916_wcd_analog_priv { struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; unsigned int micbias1_cap_mode; unsigned int micbias2_cap_mode; + unsigned int micbias_mv; }; static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; @@ -265,18 +270,25 @@ static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = { static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) { + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, MICB_1_CTL_EXT_PRECHARG_EN_MASK | MICB_1_CTL_INT_PRECHARG_BYP_MASK, MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); - snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V); - /* - * Special headset needs MICBIAS as 2.7V so wait for - * 50 msec for the MICBIAS to reach 2.7 volts. - */ - msleep(50); + if (wcd->micbias_mv) { + snd_soc_write(codec, CDC_A_MICB_1_VAL, + MICB_VOLTAGE_REGVAL(wcd->micbias_mv)); + /* + * Special headset needs MICBIAS as 2.7V so wait for + * 50 msec for the MICBIAS to reach 2.7 volts. + */ + if (wcd->micbias_mv >= 2700) + msleep(50); + } + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, MICB_1_CTL_EXT_PRECHARG_EN_MASK | MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0); @@ -795,6 +807,9 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev, else priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + of_property_read_u32(dev->of_node, "qcom,micbias-lvl", + &priv->micbias_mv); + return 0; } -- cgit v1.2.3 From de66b3455023e6f78fdf55a387c604c6b0114869 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 17 Aug 2017 10:02:10 +0200 Subject: ASoC: codecs: msm8916-wcd-analog: add MBHC support MBHC (MultiButton Headset Control) support is available in pm8921 in two blocks, one to detect mechanical headset insertion and removal and other block to support headset type detection and 5 button detection and othe features like impedance calculation. This patch adds support to: 1> Support to NC and NO type of headset Jacks. 2> Mechanical insertion and detection of headset jack. 3> Detect a 3 pole Headphone and a 4 pole Headset. 4> Detect 5 buttons. Tested it on DB410c with Audio Mezz board with 4 pole and 3 pole headset/headphones. Signed-off-by: Srinivas Kandagatla Tested-by: Damien Riegel Signed-off-by: Mark Brown --- .../bindings/sound/qcom,msm8916-wcd-analog.txt | 17 +- sound/soc/codecs/msm8916-wcd-analog.c | 373 ++++++++++++++++++++- 2 files changed, 388 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt index 05b67a1d4851..551ecab67efe 100644 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt @@ -31,9 +31,22 @@ Required properties - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. - Optional Properties: + - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons + detection on headset when the mbhc is powered up + by internal current source, this is a low power. + - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons + detection on headset when mbhc is powered up + from micbias. - qcom,micbias-lvl: Voltage (mV) for Mic Bias +- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a + NO (Normally Open). If not specified, then + its assumed that hphl pin on jack is NC + (Normally Closed). +- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is + NO (Normally Open). If not specified, then + its assumed that gnd pin on jack is NC + (Normally Closed). - qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor connected. - qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor @@ -49,6 +62,8 @@ spmi_bus { reg-names = "pmic-codec-core"; clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; clock-names = "mclk"; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; interrupt-parent = <&spmi_bus>; interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, <0x1 0xf0 0x1 IRQ_TYPE_NONE>, diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 8633524b1961..f834a639b350 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -12,9 +12,16 @@ #include #include #include +#include #define CDC_D_REVISION1 (0xf000) #define CDC_D_PERPH_SUBTYPE (0xf005) +#define CDC_D_INT_EN_SET (0x015) +#define CDC_D_INT_EN_CLR (0x016) +#define MBHC_SWITCH_INT BIT(7) +#define MBHC_MIC_ELECTRICAL_INS_REM_DET BIT(6) +#define MBHC_BUTTON_PRESS_DET BIT(5) +#define MBHC_BUTTON_RELEASE_DET BIT(4) #define CDC_D_CDC_RST_CTL (0xf046) #define RST_CTL_DIG_SW_RST_N_MASK BIT(7) #define RST_CTL_DIG_SW_RST_N_RESET 0 @@ -37,6 +44,8 @@ #define DIG_CLK_CTL_RXD1_CLK_EN BIT(0) #define DIG_CLK_CTL_RXD2_CLK_EN BIT(1) #define DIG_CLK_CTL_RXD3_CLK_EN BIT(2) +#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK BIT(3) +#define DIG_CLK_CTL_D_MBHC_CLK_EN BIT(3) #define DIG_CLK_CTL_TXD_CLK_EN BIT(4) #define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6) #define DIG_CLK_CTL_NCP_CLK_EN BIT(6) @@ -132,8 +141,51 @@ #define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0 #define CDC_A_MICB_2_EN (0xf144) +#define CDC_A_MICB_2_EN_ENABLE BIT(7) +#define CDC_A_MICB_2_PULL_DOWN_EN_MASK BIT(5) +#define CDC_A_MICB_2_PULL_DOWN_EN BIT(5) #define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145) #define CDC_A_MASTER_BIAS_CTL (0xf146) +#define CDC_A_MBHC_DET_CTL_1 (0xf147) +#define CDC_A_MBHC_DET_CTL_L_DET_EN BIT(7) +#define CDC_A_MBHC_DET_CTL_GND_DET_EN BIT(6) +#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION BIT(5) +#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL (0) +#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK BIT(5) +#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT (5) +#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO BIT(4) +#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL BIT(3) +#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK GENMASK(4, 3) +#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN BIT(2) +#define CDC_A_MBHC_DET_CTL_2 (0xf150) +#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 (BIT(7) | BIT(6)) +#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD BIT(5) +#define CDC_A_PLUG_TYPE_MASK GENMASK(4, 3) +#define CDC_A_HPHL_PLUG_TYPE_NO BIT(4) +#define CDC_A_GND_PLUG_TYPE_NO BIT(3) +#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK BIT(0) +#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN BIT(0) +#define CDC_A_MBHC_FSM_CTL (0xf151) +#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN BIT(7) +#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK BIT(7) +#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA (0x3 << 4) +#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK GENMASK(6, 4) +#define CDC_A_MBHC_DBNC_TIMER (0xf152) +#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS BIT(3) +#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS (0x9 << 4) +#define CDC_A_MBHC_BTN0_ZDET_CTL_0 (0xf153) +#define CDC_A_MBHC_BTN1_ZDET_CTL_1 (0xf154) +#define CDC_A_MBHC_BTN2_ZDET_CTL_2 (0xf155) +#define CDC_A_MBHC_BTN3_CTL (0xf156) +#define CDC_A_MBHC_BTN4_CTL (0xf157) +#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT (2) +#define CDC_A_MBHC_BTN_VREF_FINE_MASK GENMASK(4, 2) +#define CDC_A_MBHC_BTN_VREF_COARSE_MASK GENMASK(7, 5) +#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5) +#define CDC_A_MBHC_BTN_VREF_MASK (CDC_A_MBHC_BTN_VREF_COARSE_MASK | \ + CDC_A_MBHC_BTN_VREF_FINE_MASK) +#define CDC_A_MBHC_RESULT_1 (0xf158) +#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK GENMASK(4, 0) #define CDC_A_TX_1_EN (0xf160) #define CDC_A_TX_2_EN (0xf161) #define CDC_A_TX_1_2_TEST_CTL_1 (0xf162) @@ -217,16 +269,34 @@ #define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE) +static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4; +static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET; + static const char * const supply_names[] = { "vdd-cdc-io", "vdd-cdc-tx-rx-cx", }; +#define MBHC_MAX_BUTTONS (5) + struct pm8916_wcd_analog_priv { u16 pmic_rev; u16 codec_version; + bool mbhc_btn_enabled; + /* special event to detect accessory type */ + bool mbhc_btn0_pressed; + bool detect_accessory_type; struct clk *mclk; + struct snd_soc_codec *codec; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + struct snd_soc_jack *jack; + bool hphl_jack_type_normally_open; + bool gnd_jack_type_normally_open; + /* Voltage threshold when internal current source of 100uA is used */ + u32 vref_btn_cs[MBHC_MAX_BUTTONS]; + /* Voltage threshold when microphone bias is ON */ + u32 vref_btn_micb[MBHC_MAX_BUTTONS]; unsigned int micbias1_cap_mode; unsigned int micbias2_cap_mode; unsigned int micbias_mv; @@ -373,6 +443,97 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct wcd->micbias1_cap_mode); } +static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd) +{ + struct snd_soc_codec *codec = wcd->codec; + u32 plug_type = 0; + u32 int_en_mask; + + snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1, + CDC_A_MBHC_DET_CTL_L_DET_EN | + CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION | + CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO | + CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN); + + if (wcd->hphl_jack_type_normally_open) + plug_type |= CDC_A_HPHL_PLUG_TYPE_NO; + + if (wcd->gnd_jack_type_normally_open) + plug_type |= CDC_A_GND_PLUG_TYPE_NO; + + snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2, + CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 | + CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD | + plug_type | + CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN); + + + snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER, + CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS | + CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS); + + /* enable MBHC clock */ + snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL, + DIG_CLK_CTL_D_MBHC_CLK_EN_MASK, + DIG_CLK_CTL_D_MBHC_CLK_EN); + + int_en_mask = MBHC_SWITCH_INT; + if (wcd->mbhc_btn_enabled) + int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET; + + snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0); + snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask); + wcd->mbhc_btn0_pressed = false; + wcd->detect_accessory_type = true; +} + +static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv, + bool micbias2_enabled) +{ + struct snd_soc_codec *codec = priv->codec; + u32 coarse, fine, reg_val, reg_addr; + int *vrefs, i; + + if (!micbias2_enabled) { /* use internal 100uA Current source */ + /* Enable internal 2.2k Internal Rbias Resistor */ + snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS, + MICB_1_INT_TX2_INT_RBIAS_EN_MASK, + MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE); + /* Remove pull down on MIC BIAS2 */ + snd_soc_update_bits(codec, CDC_A_MICB_2_EN, + CDC_A_MICB_2_PULL_DOWN_EN_MASK, + 0); + /* enable 100uA internal current source */ + snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL, + CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK, + CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA); + } + snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL, + CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK, + CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN); + + if (micbias2_enabled) + vrefs = &priv->vref_btn_micb[0]; + else + vrefs = &priv->vref_btn_cs[0]; + + /* program vref ranges for all the buttons */ + reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0; + for (i = 0; i < MBHC_MAX_BUTTONS; i++) { + /* split mv in to coarse parts of 100mv & fine parts of 12mv */ + coarse = (vrefs[i] / 100); + fine = ((vrefs[i] % 100) / 12); + reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) | + (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT); + snd_soc_update_bits(codec, reg_addr, + CDC_A_MBHC_BTN_VREF_MASK, + reg_val); + reg_addr++; + } + + return 0; +} + static int pm8916_wcd_analog_enable_micbias_int2(struct snd_soc_dapm_widget *w, struct snd_kcontrol @@ -381,6 +542,15 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMU: + pm8916_mbhc_configure_bias(wcd, true); + break; + case SND_SOC_DAPM_POST_PMD: + pm8916_mbhc_configure_bias(wcd, false); + break; + } + return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, wcd->micbias2_cap_mode); } @@ -548,9 +718,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, wcd_reg_defaults_2_0[reg].def); + priv->codec = codec; + snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL, RST_CTL_DIG_SW_RST_N_MASK, RST_CTL_DIG_SW_RST_N_REMOVE_RESET); + + pm8916_wcd_setup_mbhc(priv); + return 0; } @@ -749,11 +924,130 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0), }; +static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, + void *data) +{ + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + wcd->jack = jack; + + return 0; +} + static struct regmap *pm8916_get_regmap(struct device *dev) { return dev_get_regmap(dev->parent, NULL); } +static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg) +{ + struct pm8916_wcd_analog_priv *priv = arg; + + if (priv->detect_accessory_type) { + struct snd_soc_codec *codec = priv->codec; + u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1); + + /* check if its BTN0 thats released */ + if ((val >= 0) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK)) + priv->mbhc_btn0_pressed = false; + + } else { + snd_soc_jack_report(priv->jack, 0, btn_mask); + } + + return IRQ_HANDLED; +} + +static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg) +{ + struct pm8916_wcd_analog_priv *priv = arg; + struct snd_soc_codec *codec = priv->codec; + u32 btn_result; + + btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) & + CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK; + + switch (btn_result) { + case 0xf: + snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask); + break; + case 0x7: + snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask); + break; + case 0x3: + snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask); + break; + case 0x1: + snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask); + break; + case 0x0: + /* handle BTN_0 specially for type detection */ + if (priv->detect_accessory_type) + priv->mbhc_btn0_pressed = true; + else + snd_soc_jack_report(priv->jack, + SND_JACK_BTN_0, btn_mask); + break; + default: + dev_err(codec->dev, + "Unexpected button press result (%x)", btn_result); + break; + } + + return IRQ_HANDLED; +} + + +static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg) +{ + struct pm8916_wcd_analog_priv *priv = arg; + struct snd_soc_codec *codec = priv->codec; + bool ins = false; + + if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) & + CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK) + ins = true; + + /* Set the detection type appropriately */ + snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1, + CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK, + (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT)); + + + if (ins) { /* hs insertion */ + bool micbias_enabled = false; + + if (snd_soc_read(codec, CDC_A_MICB_2_EN) & + CDC_A_MICB_2_EN_ENABLE) + micbias_enabled = true; + + pm8916_mbhc_configure_bias(priv, micbias_enabled); + + /* + * if only a btn0 press event is receive just before + * insert event then its a 3 pole headphone else if + * both press and release event received then its + * a headset. + */ + if (priv->mbhc_btn0_pressed) + snd_soc_jack_report(priv->jack, + SND_JACK_HEADPHONE, hs_jack_mask); + else + snd_soc_jack_report(priv->jack, + SND_JACK_HEADSET, hs_jack_mask); + + priv->detect_accessory_type = false; + + } else { /* removal */ + snd_soc_jack_report(priv->jack, 0, hs_jack_mask); + priv->detect_accessory_type = true; + priv->mbhc_btn0_pressed = false; + } + + return IRQ_HANDLED; +} + static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { [0] = { .name = "pm8916_wcd_analog_pdm_rx", @@ -782,6 +1076,7 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { static const struct snd_soc_codec_driver pm8916_wcd_analog = { .probe = pm8916_wcd_analog_probe, .remove = pm8916_wcd_analog_remove, + .set_jack = pm8916_wcd_analog_set_jack, .get_regmap = pm8916_get_regmap, .component_driver = { .controls = pm8916_wcd_analog_snd_controls, @@ -796,6 +1091,7 @@ static const struct snd_soc_codec_driver pm8916_wcd_analog = { static int pm8916_wcd_analog_parse_dt(struct device *dev, struct pm8916_wcd_analog_priv *priv) { + int rval; if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; @@ -810,6 +1106,39 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev, of_property_read_u32(dev->of_node, "qcom,micbias-lvl", &priv->micbias_mv); + if (of_property_read_bool(dev->of_node, + "qcom,hphl-jack-type-normally-open")) + priv->hphl_jack_type_normally_open = true; + else + priv->hphl_jack_type_normally_open = false; + + if (of_property_read_bool(dev->of_node, + "qcom,gnd-jack-type-normally-open")) + priv->gnd_jack_type_normally_open = true; + else + priv->gnd_jack_type_normally_open = false; + + priv->mbhc_btn_enabled = true; + rval = of_property_read_u32_array(dev->of_node, + "qcom,mbhc-vthreshold-low", + &priv->vref_btn_cs[0], + MBHC_MAX_BUTTONS); + if (rval < 0) { + priv->mbhc_btn_enabled = false; + } else { + rval = of_property_read_u32_array(dev->of_node, + "qcom,mbhc-vthreshold-high", + &priv->vref_btn_micb[0], + MBHC_MAX_BUTTONS); + if (rval < 0) + priv->mbhc_btn_enabled = false; + } + + if (!priv->mbhc_btn_enabled) + dev_err(dev, + "DT property missing, MBHC btn detection disabled\n"); + + return 0; } @@ -817,7 +1146,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) { struct pm8916_wcd_analog_priv *priv; struct device *dev = &pdev->dev; - int ret, i; + int ret, i, irq; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -849,6 +1178,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return ret; } + irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); + if (irq < 0) { + dev_err(dev, "failed to get mbhc switch irq\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "mbhc switch irq", priv); + if (ret) + dev_err(dev, "cannot request mbhc switch irq\n"); + + if (priv->mbhc_btn_enabled) { + irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); + if (irq < 0) { + dev_err(dev, "failed to get button press irq\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "mbhc btn press irq", priv); + if (ret) + dev_err(dev, "cannot request mbhc button press irq\n"); + + irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); + if (irq < 0) { + dev_err(dev, "failed to get button release irq\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "mbhc btn release irq", priv); + if (ret) + dev_err(dev, "cannot request mbhc button release irq\n"); + + } + dev_set_drvdata(dev, priv); return snd_soc_register_codec(dev, &pm8916_wcd_analog, -- cgit v1.2.3 From 6cbcad079ecdb8ecd214d33688fd7f19167fe57a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 23 Aug 2017 05:11:44 +0000 Subject: ASoC: wm8524: remove unnecessary snd_soc_unregister_platform() wm8524 doesn't register platform, unregister platform is not needed Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8524.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index b66147e0631b..856a6950a451 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -233,10 +233,8 @@ static int wm8524_codec_probe(struct platform_device *pdev) ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8524, &wm8524_dai, 1); - if (ret < 0) { + if (ret < 0) dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); - } return ret; } -- cgit v1.2.3 From cb0236eca79c8ceb5cdb8d2a15ce272e754d2921 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Aug 2017 15:32:35 -0500 Subject: ASoC: codecs: rt5645: add quirks for Asus T100HA Fix jack detection and dmic setup Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ec58166f7c4..500bb42d0804 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3637,6 +3637,24 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = { {} }; +static struct rt5645_platform_data general_platform_data2 = { + .dmic1_data_pin = RT5645_DMIC_DATA_IN2N, + .dmic2_data_pin = RT5645_DMIC2_DISABLE, + .jd_mode = 3, + .inv_jd1_1 = true, +}; + +static struct dmi_system_id dmi_platform_asus_t100ha[] = { + { + .ident = "ASUS T100HAN", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"), + }, + }, + { } +}; + static bool rt5645_check_dp(struct device *dev) { if (device_property_present(dev, "realtek,in2-differential") || @@ -3689,6 +3707,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, rt5645->pdata = general_platform_data; else if (dmi_check_system(dmi_platform_gpd_win)) rt5645->pdata = gpd_win_platform_data; + else if (dmi_check_system(dmi_platform_asus_t100ha)) + rt5645->pdata = general_platform_data2; if (quirk != -1) { rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk); -- cgit v1.2.3 From c26d8389be4dab2bb5a8ac16211a9966bf67091a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Aug 2017 15:32:37 -0500 Subject: ASoC: codecs: rt5670: add jack detection quirk for Dell Venue 5585 Jack is not detected by default, using jdmode=3 works fine Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0f4e5bc4476f..4ea51b487b8c 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2851,6 +2851,17 @@ static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = { {} }; +static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode3[] = { + { + .ident = "Dell Venue 8 Pro 5855", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"), + }, + }, + {} +}; + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2880,6 +2891,11 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; rt5670->pdata.dev_gpio = true; rt5670->pdata.jd_mode = 2; + } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode3)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.dev_gpio = true; + rt5670->pdata.jd_mode = 3; } rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); -- cgit v1.2.3 From cd6d6477f130c861c42e6eddc060e7c880e94bf3 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 23 Aug 2017 20:05:22 +0530 Subject: ASoC: rt5645: make rt5645_platform_data const Make these const as they are only used during a copy operation. Done using Coccinelle. @match disable optional_qualifier@ identifier s; @@ static struct rt5645_platform_data s = {...}; @ref@ position p; identifier match.s; @@ s@p @good1@ position ref.p; identifier match.s,f,c; expression e; @@ ( e = s@p | e = s@p.f | c(...,s@p.f,...) | c(...,s@p,...) ) @bad depends on !good1@ position ref.p; identifier match.s; @@ s@p @depends on forall !bad disable optional_qualifier@ identifier match.s; @@ static + const struct rt5645_platform_data s; Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 500bb42d0804..d2f038001908 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3559,7 +3559,7 @@ static const struct acpi_device_id rt5645_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); #endif -static struct rt5645_platform_data general_platform_data = { +static const struct rt5645_platform_data general_platform_data = { .dmic1_data_pin = RT5645_DMIC1_DISABLE, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, @@ -3593,7 +3593,7 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { { } }; -static struct rt5645_platform_data buddy_platform_data = { +static const struct rt5645_platform_data buddy_platform_data = { .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, @@ -3610,7 +3610,7 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = { { } }; -static struct rt5645_platform_data gpd_win_platform_data = { +static const struct rt5645_platform_data gpd_win_platform_data = { .jd_mode = 3, .inv_jd1_1 = true, }; -- cgit v1.2.3 From 56026714bd45fccda710114982789c5145285560 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Aug 2017 13:07:41 +0300 Subject: ASoC: codecs: msm8916-wcd-analog: always true condition Static checkers complain that unsigned int val is always >= 0. The context is that snd_soc_read() returns -1U on error. This is harmless because we're checking that CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK is not set, and it will always be set for -1U. I could have just removed the check against -1 but I preserved it because I thought it helped with readability. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index f834a639b350..cd4d60ef4c77 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -949,7 +949,7 @@ static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg) u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1); /* check if its BTN0 thats released */ - if ((val >= 0) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK)) + if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK)) priv->mbhc_btn0_pressed = false; } else { -- cgit v1.2.3 From d18420b0a0b8f8f51f55fc654b2e0eb86d8b41d7 Mon Sep 17 00:00:00 2001 From: Hsin-Yu Chao Date: Wed, 23 Aug 2017 18:29:31 +0800 Subject: ASoC: rt5514: expose Hotword Model control This change exposes mixer control 'Hotword Model' for switching hotword model in runtime. This new function requires updated firmware to load hotword model at address 0x4ff80000. Signed-off-by: Hsin-Yu Chao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5514.h | 3 +++ 2 files changed, 55 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a694ce9fed86..0e239e8c7bf8 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -302,6 +302,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); struct snd_soc_codec *codec = rt5514->codec; const struct firmware *fw = NULL; + int ret = 0; if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled) return 0; @@ -338,6 +339,27 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, fw = NULL; } + if (rt5514->model_buf && rt5514->model_len) { + ret = rt5514_spi_burst_write(0x4ff80000, + rt5514->model_buf, + ((rt5514->model_len / 8) + 1) * 8); + if (ret) { + dev_err(codec->dev, + "Model load failed %d\n", ret); + return ret; + } + } else { + request_firmware(&fw, RT5514_FIRMWARE3, + codec->dev); + if (fw) { + rt5514_spi_burst_write(0x4ff80000, + fw->data, + ((fw->size/8)+1)*8); + release_firmware(fw); + fw = NULL; + } + } + /* DSP run */ regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x00055148); @@ -352,6 +374,34 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, return 0; } +static int rt5514_hotword_model_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, unsigned int size) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); + struct snd_soc_codec *codec = rt5514->codec; + int ret = 0; + + if (rt5514->model_buf || rt5514->model_len < size) { + if (rt5514->model_buf) + devm_kfree(codec->dev, rt5514->model_buf); + rt5514->model_buf = devm_kmalloc(codec->dev, size, GFP_KERNEL); + if (!rt5514->model_buf) { + ret = -ENOMEM; + goto done; + } + } + + /* Skips the TLV header. */ + bytes += 2; + + if (copy_from_user(rt5514->model_buf, bytes, size)) + ret = -EFAULT; +done: + rt5514->model_len = (ret ? 0 : size); + return ret; +} + static const struct snd_kcontrol_new rt5514_snd_controls[] = { SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), @@ -363,6 +413,8 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = { adc_vol_tlv), SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0, rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put), + SND_SOC_BYTES_TLV("Hotword Model", 0x8504, + NULL, rt5514_hotword_model_put), }; /* ADC Mixer*/ diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 2dc40e6d8b3f..803311cb7e2a 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -255,6 +255,7 @@ #define RT5514_FIRMWARE1 "rt5514_dsp_fw1.bin" #define RT5514_FIRMWARE2 "rt5514_dsp_fw2.bin" +#define RT5514_FIRMWARE3 "rt5514_dsp_fw3.bin" /* System Clock Source */ enum { @@ -281,6 +282,8 @@ struct rt5514_priv { int pll_in; int pll_out; int dsp_enabled; + u8 *model_buf; + unsigned int model_len; }; #endif /* __RT5514_H__ */ -- cgit v1.2.3 From 3dfcd3468cf05861654b1c7857500da6c8a9fc88 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 25 Aug 2017 11:35:44 +0800 Subject: ASoC: nau8825: correct typo of semaphore comment There are a lot of typo about semaphore in the comment. Correct it from semaphone to semaphore. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 46a30eaa7ace..a97b0b6d9086 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -260,11 +260,11 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) if (timeout) { ret = down_timeout(&nau8825->xtalk_sem, timeout); if (ret < 0) - dev_warn(nau8825->dev, "Acquire semaphone timeout\n"); + dev_warn(nau8825->dev, "Acquire semaphore timeout\n"); } else { ret = down_interruptible(&nau8825->xtalk_sem); if (ret < 0) - dev_warn(nau8825->dev, "Acquire semaphone fail\n"); + dev_warn(nau8825->dev, "Acquire semaphore fail\n"); } return ret; @@ -1299,7 +1299,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK, val_len); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); return 0; @@ -1361,7 +1361,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_MS_MASK, ctrl2_val); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); return 0; @@ -2140,7 +2140,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, break; case NAU8825_CLK_MCLK: - /* Acquire the semaphone to synchronize the playback and + /* Acquire the semaphore to synchronize the playback and * interrupt handler. In order to avoid the playback inter- * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. @@ -2150,7 +2150,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, /* MCLK not changed by clock tree */ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_MCLK_SRC_MASK, 0); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); ret = nau8825_mclk_prepare(nau8825, freq); @@ -2188,7 +2188,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, break; case NAU8825_CLK_FLL_MCLK: - /* Acquire the semaphone to synchronize the playback and + /* Acquire the semaphore to synchronize the playback and * interrupt handler. In order to avoid the playback inter- * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. @@ -2201,7 +2201,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, regmap_update_bits(regmap, NAU8825_REG_FLL3, NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, NAU8825_FLL_CLK_SRC_MCLK | 0); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); ret = nau8825_mclk_prepare(nau8825, freq); @@ -2210,7 +2210,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, break; case NAU8825_CLK_FLL_BLK: - /* Acquire the semaphone to synchronize the playback and + /* Acquire the semaphore to synchronize the playback and * interrupt handler. In order to avoid the playback inter- * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. @@ -2226,7 +2226,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, NAU8825_FLL_CLK_SRC_BLK | (0xf << NAU8825_GAIN_ERR_SFT)); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); if (nau8825->mclk_freq) { @@ -2236,7 +2236,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, break; case NAU8825_CLK_FLL_FS: - /* Acquire the semaphone to synchronize the playback and + /* Acquire the semaphore to synchronize the playback and * interrupt handler. In order to avoid the playback inter- * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. @@ -2252,7 +2252,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, NAU8825_FLL_CLK_SRC_FS | (0xf << NAU8825_GAIN_ERR_SFT)); - /* Release the semaphone. */ + /* Release the semaphore. */ nau8825_sema_release(nau8825); if (nau8825->mclk_freq) { @@ -2563,7 +2563,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c, return PTR_ERR(nau8825->regmap); nau8825->dev = dev; nau8825->irq = i2c->irq; - /* Initiate parameters, semaphone and work queue which are needed in + /* Initiate parameters, semaphore and work queue which are needed in * cross talk suppression measurment function. */ nau8825->xtalk_state = NAU8825_XTALK_DONE; -- cgit v1.2.3 From eb33869c720656c16e614ea40a175a014f60007b Mon Sep 17 00:00:00 2001 From: Hsin-Yu Chao Date: Mon, 28 Aug 2017 15:13:50 +0800 Subject: ASoC: rt5514: Guard Hotword Model bytes loading If the rt5514-spi driver is not enabled in kernel, hotword model will not be loaded when "DSP Voice Wake Up" is set to turn on DSP mode, and an error is logged instead. Signed-off-by: Hsin-Yu Chao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 0e239e8c7bf8..23fccdf3e84a 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -302,7 +302,6 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); struct snd_soc_codec *codec = rt5514->codec; const struct firmware *fw = NULL; - int ret = 0; if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled) return 0; @@ -340,6 +339,9 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, } if (rt5514->model_buf && rt5514->model_len) { +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) + int ret; + ret = rt5514_spi_burst_write(0x4ff80000, rt5514->model_buf, ((rt5514->model_len / 8) + 1) * 8); @@ -348,13 +350,22 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, "Model load failed %d\n", ret); return ret; } +#else + dev_err(codec->dev, + "No SPI driver for loading firmware\n"); +#endif } else { request_firmware(&fw, RT5514_FIRMWARE3, codec->dev); if (fw) { +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) rt5514_spi_burst_write(0x4ff80000, fw->data, ((fw->size/8)+1)*8); +#else + dev_err(codec->dev, + "No SPI driver to load fw\n"); +#endif release_firmware(fw); fw = NULL; } -- cgit v1.2.3 From 1bb7cb68feb73a8106546cbd3379590297b0a950 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Fri, 25 Aug 2017 21:36:56 +0000 Subject: ASoC: tas2552: Fix fraction overflow in PLL calculation Setting the PLL involves the calculation of a fixed point ratio with 4 decimal digits fraction, referred to as "J.D". The fraction "D" is stored separately from the integer part "J" and is limited to 0..9999. The current algorithm uses integer registers to calculate the fraction part, but failed to compensate for rounding errors, resulting in values larger than 9999 for the fraction part occasionally, e.g. for 44.1kHz audio rate and pll_clkin = 3763400 it would set J to 11 and D to 10002, which will at best result in wrong pitch. The critical part is the "pll_clkin / 10000", which would be ok with real numbers, but using integer arithmetic the rounding decreases the divisor, thus increasing the final quotient. The issue is solved by linear interpolation over the reciprocal function between the two adjacent points with integer divisor, i.e. pll_clkin / 10000 and pll_clkin / 10000 + 1, and doing all rounding to the lower result. As a side effect to the bug fix, the approximation to the desired frequency is much better, for the above mentioned example we get 11.9993, while the true ratio is 11.9993623. Signed-off-by: Oskar Schirmer Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 8840f72f3c4a..10116169a239 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -192,7 +192,7 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec, * pll_clk = (.5 * pll_clkin * J.D) / 2^p * Need to fill in J and D here based on incoming freq */ - unsigned int d; + unsigned int d, q, t; u8 j; u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK; u8 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1); @@ -200,9 +200,12 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec, p = (p >> 7); recalc: - j = (pll_clk * 2 * (1 << p)) / pll_clkin; - d = (pll_clk * 2 * (1 << p)) % pll_clkin; - d /= (pll_clkin / 10000); + t = (pll_clk * 2) << p; + j = t / pll_clkin; + d = t % pll_clkin; + t = pll_clkin / 10000; + q = d / (t + 1); + d = q + ((9999 - pll_clkin % 10000) * (d / t - q)) / 10000; if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) { if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) { -- cgit v1.2.3 From 60b0fdeac19945107b956a8a2a0ba3a14827db60 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 30 Aug 2017 12:28:31 +0800 Subject: ASoC: rt274: add acpi id Add ACPI id for Intel platform. Signed-off-by: Guneshwor Singh Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index fb683ffc4e03..0be69c112c45 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1102,6 +1102,7 @@ MODULE_DEVICE_TABLE(i2c, rt274_i2c_id); static const struct acpi_device_id rt274_acpi_match[] = { { "10EC0274", 0 }, + { "INT34C2", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, rt274_acpi_match); -- cgit v1.2.3 From 9c324afe3b90e406b15938acafaa2636a7e85ff3 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Wed, 30 Aug 2017 13:08:31 +0800 Subject: ASoC: rt5663: Add delay for jack plug in Codec initialize takes some time when 3.5mm jack plugged in. Add a delay to report jack plugged event to user space to avoid pop noise. Signed-off-by: Hsinyu Chao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index fdc2bbcb67c2..14716d25173b 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1705,6 +1705,9 @@ static void rt5663_jack_detect_work(struct work_struct *work) default: dev_err(codec->dev, "Unknown CODEC Version\n"); } + + /* Delay the jack insert report to avoid pop noise */ + msleep(30); } else { /* jack is already in, report button event */ report = SND_JACK_HEADSET; -- cgit v1.2.3 From 943fa0228252320de503b923dfe46334f755aaae Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Sat, 12 Aug 2017 08:40:38 +0800 Subject: ASoC: hdmi-codec: Use different name for playback streams Currently the hdmi i2s playback stream and hdmi spdif playback stream are using the same name. So when they are enabled at the same time, kernel will print this warning: [ 2.201835] hdmi-audio-codec hdmi-audio-codec.1.auto: ASoC: Failed to create Playback debugfs file Assign different names to them to avoid that. Signed-off-by: Jeffy Chen Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index f7520413c671..189af068f28d 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -696,7 +696,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, .playback = { - .stream_name = "Playback", + .stream_name = "I2S Playback", .channels_min = 2, .channels_max = 8, .rates = HDMI_RATES, @@ -711,7 +711,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, .playback = { - .stream_name = "Playback", + .stream_name = "SPDIF Playback", .channels_min = 2, .channels_max = 2, .rates = HDMI_RATES, -- cgit v1.2.3 From 19b0fa11bb1c0c24296c9f670a37c091bd3c815d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 31 Aug 2017 11:49:47 +0300 Subject: ASoC: tlv320aic3x: Support for OCMV configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In aic3x class of devices Output Common-Mode Voltage can be configured for better analog performance. The OCMV value depends on the Analog and digital domain power supply voltage configuration. The default OCMV of 1.35V gives best performance when AVDD is around 2.7V and DVDD is 1.525V, but for higher AVDD/DVDD higher OCMV setting is recommended. The patch gives an automatic way of guessing the best OCMV which can be overwritten by a DT parameter if needed. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tlv320aic3x.txt | 5 +++ sound/soc/codecs/tlv320aic3x.c | 45 ++++++++++++++++++++++ sound/soc/codecs/tlv320aic3x.h | 8 ++++ 3 files changed, 58 insertions(+) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 47a213c411ce..ba5b45c483f5 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -26,6 +26,11 @@ Optional properties: 3 - MICBIAS output is connected to AVDD, If this node is not mentioned or if the value is incorrect, then MicBias is powered down. +- ai3x-ocmv - Output Common-Mode Voltage selection: + 0 - 1.35V, + 1 - 1.5V, + 2 - 1.65V, + 3 - 1.8V - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the device as covered in Documentation/devicetree/bindings/regulator/regulator.txt diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 29bf8c81ae02..ca880859f0c3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -93,6 +93,8 @@ struct aic3x_priv { /* Selects the micbias voltage */ enum aic3x_micbias_voltage micbias_vg; + /* Output Common-Mode Voltage */ + u8 ocmv; }; static const struct reg_default aic3x_reg[] = { @@ -1572,6 +1574,10 @@ static int aic3x_init(struct snd_soc_codec *codec) break; } + /* Output common-mode voltage = 1.5 V */ + snd_soc_update_bits(codec, HPOUT_SC, HPOUT_SC_OCMV_MASK, + aic3x->ocmv << HPOUT_SC_OCMV_SHIFT); + return 0; } @@ -1699,6 +1705,43 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { }, }; +static void aic3x_configure_ocmv(struct i2c_client *client) +{ + struct device_node *np = client->dev.of_node; + struct aic3x_priv *aic3x = i2c_get_clientdata(client); + u32 value; + int dvdd, avdd; + + if (np && !of_property_read_u32(np, "ai3x-ocmv", &value)) { + /* OCMV setting is forced by DT */ + if (value <= 3) { + aic3x->ocmv = value; + return; + } + } + + dvdd = regulator_get_voltage(aic3x->supplies[1].consumer); + avdd = regulator_get_voltage(aic3x->supplies[2].consumer); + + if (avdd > 3600000 || dvdd > 1950000) { + dev_warn(&client->dev, + "Too high supply voltage(s) AVDD: %d, DVDD: %d\n", + avdd, dvdd); + } else if (avdd == 3600000 && dvdd == 1950000) { + aic3x->ocmv = HPOUT_SC_OCMV_1_8V; + } else if (avdd > 3300000 && dvdd > 1800000) { + aic3x->ocmv = HPOUT_SC_OCMV_1_65V; + } else if (avdd > 3000000 && dvdd > 1650000) { + aic3x->ocmv = HPOUT_SC_OCMV_1_5V; + } else if (avdd >= 2700000 && dvdd >= 1525000) { + aic3x->ocmv = HPOUT_SC_OCMV_1_35V; + } else { + dev_warn(&client->dev, + "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n", + avdd, dvdd); + } +} + /* * AIC3X 2 wire address can be up to 4 devices with device addresses * 0x18, 0x19, 0x1A, 0x1B @@ -1816,6 +1859,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, goto err_gpio; } + aic3x_configure_ocmv(i2c); + if (aic3x->model == AIC3X_MODEL_3007) { ret = regmap_register_patch(aic3x->regmap, aic3007_class_d, ARRAY_SIZE(aic3007_class_d)); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 89fa692df206..34c35196aa0d 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -243,6 +243,14 @@ #define MICBIAS_LEVEL_SHIFT (6) #define MICBIAS_LEVEL_MASK (3 << 6) +/* HPOUT_SC */ +#define HPOUT_SC_OCMV_MASK (3 << 6) +#define HPOUT_SC_OCMV_SHIFT (6) +#define HPOUT_SC_OCMV_1_35V 0 +#define HPOUT_SC_OCMV_1_5V 1 +#define HPOUT_SC_OCMV_1_65V 2 +#define HPOUT_SC_OCMV_1_8V 3 + /* headset detection / button API */ /* The AIC3x supports detection of stereo headsets (GND + left + right signal) -- cgit v1.2.3 From 88faae2c2e35c88a806c052a7fc20948211b0895 Mon Sep 17 00:00:00 2001 From: Ian W MORRISON Date: Thu, 31 Aug 2017 08:35:47 +1000 Subject: ASoC: rt5645: Add jack detection workaround for MINIX Z83-4 based devices The MINIX NEO Z83-4 and MINIX NEO Z83-4 Pro devices requires jd_mode=3 to make the jack detection work. Using a BIOS DMI product of "Z83-4" will match both devices of 'NEO Z83-4' and 'Z83-4 Pro'. Signed-off-by: Ian W Morrison Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d2f038001908..2e145f089d9d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3655,6 +3655,21 @@ static struct dmi_system_id dmi_platform_asus_t100ha[] = { { } }; +static struct rt5645_platform_data minix_z83_4_platform_data = { + .jd_mode = 3, +}; + +static struct dmi_system_id dmi_platform_minix_z83_4[] = { + { + .ident = "MINIX Z83-4", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"), + DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), + }, + }, + { } +}; + static bool rt5645_check_dp(struct device *dev) { if (device_property_present(dev, "realtek,in2-differential") || @@ -3709,6 +3724,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, rt5645->pdata = gpd_win_platform_data; else if (dmi_check_system(dmi_platform_asus_t100ha)) rt5645->pdata = general_platform_data2; + else if (dmi_check_system(dmi_platform_minix_z83_4)) + rt5645->pdata = minix_z83_4_platform_data; if (quirk != -1) { rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk); -- cgit v1.2.3 From 9c1743ebe0da614517a1b94f171924d5fd758df4 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:30:55 -0700 Subject: ASoC: max98927: Updated volatile register list Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index b5ee29499e16..768e84dbcdf6 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -495,6 +495,13 @@ static bool max98927_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3: + case MAX98927_R004C_MEAS_ADC_CH0_READ: + case MAX98927_R004D_MEAS_ADC_CH1_READ: + case MAX98927_R004E_MEAS_ADC_CH2_READ: + case MAX98927_R0051_BROWNOUT_STATUS: + case MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ: + case MAX98927_R01FF_REV_ID: + case MAX98927_R0100_SOFT_RESET: return true; default: return false; -- cgit v1.2.3 From 01c6f1b5c832b75af5d34555201050db896285a8 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:30:56 -0700 Subject: ASoC: max98927: Added missing \n to end of dev_err messages Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 768e84dbcdf6..f74cdb065bf2 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -159,7 +159,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) mode = MAX98927_PCM_MASTER_MODE_MASTER; break; default: - dev_err(codec->dev, "DAI clock mode unsupported"); + dev_err(codec->dev, "DAI clock mode unsupported\n"); return -EINVAL; } @@ -175,7 +175,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE; break; default: - dev_err(codec->dev, "DAI invert mode unsupported"); + dev_err(codec->dev, "DAI invert mode unsupported\n"); return -EINVAL; } @@ -311,7 +311,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32; break; default: - dev_err(codec->dev, "format unsupported %d", + dev_err(codec->dev, "format unsupported %d\n", params_format(params)); goto err; } -- cgit v1.2.3 From 848844b87a26265019215dbb7fb588a5fac0a110 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:30:58 -0700 Subject: ASoC: max98927: Modified chip default register values Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index f74cdb065bf2..5b853604120a 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -44,9 +44,9 @@ static struct reg_default max98927_reg[] = { {MAX98927_R0011_CLK_MON, 0x00}, {MAX98927_R0012_WDOG_CTRL, 0x00}, {MAX98927_R0013_WDOG_RST, 0x00}, - {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00}, - {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00}, - {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00}, + {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x75}, + {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x8c}, + {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x08}, {MAX98927_R0017_PIN_CFG, 0x55}, {MAX98927_R0018_PCM_RX_EN_A, 0x00}, {MAX98927_R0019_PCM_RX_EN_B, 0x00}, @@ -82,14 +82,14 @@ static struct reg_default max98927_reg[] = { {MAX98927_R003A_AMP_EN, 0x00}, {MAX98927_R003B_SPK_SRC_SEL, 0x00}, {MAX98927_R003C_SPK_GAIN, 0x00}, - {MAX98927_R003D_SSM_CFG, 0x01}, + {MAX98927_R003D_SSM_CFG, 0x04}, {MAX98927_R003E_MEAS_EN, 0x00}, {MAX98927_R003F_MEAS_DSP_CFG, 0x04}, {MAX98927_R0040_BOOST_CTRL0, 0x00}, {MAX98927_R0041_BOOST_CTRL3, 0x00}, {MAX98927_R0042_BOOST_CTRL1, 0x00}, {MAX98927_R0043_MEAS_ADC_CFG, 0x00}, - {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00}, + {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x01}, {MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00}, {MAX98927_R0046_ADC_CH0_DIVIDE, 0x00}, {MAX98927_R0047_ADC_CH1_DIVIDE, 0x00}, -- cgit v1.2.3 From f81991ddd001981bbe4ea0d25f88a4f95fb018be Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:30:59 -0700 Subject: ASoC: max98927: Added PM suspend and resume function Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 5b853604120a..caf5340ca6bb 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -701,6 +701,31 @@ static int max98927_probe(struct snd_soc_codec *codec) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max98927_suspend(struct device *dev) +{ + struct max98927_priv *max98927 = dev_get_drvdata(dev); + + regcache_cache_only(max98927->regmap, true); + regcache_mark_dirty(max98927->regmap); + return 0; +} +static int max98927_resume(struct device *dev) +{ + struct max98927_priv *max98927 = dev_get_drvdata(dev); + + regmap_write(max98927->regmap, + MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regcache_cache_only(max98927->regmap, false); + regcache_sync(max98927->regmap); + return 0; +} +#endif + +static const struct dev_pm_ops max98927_pm = { + SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume) +}; + static const struct snd_soc_codec_driver soc_codec_dev_max98927 = { .probe = max98927_probe, .component_driver = { @@ -834,7 +859,7 @@ static struct i2c_driver max98927_i2c_driver = { .name = "max98927", .of_match_table = of_match_ptr(max98927_of_match), .acpi_match_table = ACPI_PTR(max98927_acpi_match), - .pm = NULL, + .pm = &max98927_pm, }, .probe = max98927_i2c_probe, .remove = max98927_i2c_remove, -- cgit v1.2.3 From 607f7777bf0c0224bfadd31a37acc8d1fd25324d Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:31:00 -0700 Subject: ASoC: max98927: Modified DAPM widget and map to enable/disable VI sense path Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index caf5340ca6bb..4bbf2098f255 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -418,11 +418,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, MAX98927_AMP_EN_MASK, 1); - /* enable VMON and IMON */ - regmap_update_bits(max98927->regmap, - MAX98927_R003E_MEAS_EN, - MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, - MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN); regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, MAX98927_GLOBAL_EN_MASK, 1); @@ -434,10 +429,6 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, MAX98927_AMP_EN_MASK, 0); - /* disable VMON and IMON */ - regmap_update_bits(max98927->regmap, - MAX98927_R003E_MEAS_EN, - MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0); break; default: return 0; @@ -456,14 +447,24 @@ static const struct soc_enum dai_sel_enum = static const struct snd_kcontrol_new max98927_dai_controls = SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); +static const struct snd_kcontrol_new max98927_vi_control = + SOC_DAPM_SINGLE("Switch", MAX98927_R003F_MEAS_DSP_CFG, 2, 1, 0); + static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { - SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN, 0, 0, max98927_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, &max98927_dai_controls), SND_SOC_DAPM_OUTPUT("BE_OUT"), + SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, + MAX98927_R003E_MEAS_EN, 0, 0), + SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, + MAX98927_R003E_MEAS_EN, 1, 0), + SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, + &max98927_vi_control), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON"), }; static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0); @@ -550,11 +551,16 @@ static const struct snd_kcontrol_new max98927_snd_controls[] = { }; static const struct snd_soc_dapm_route max98927_audio_map[] = { - {"Amp Enable", NULL, "DAI_OUT"}, + /* Plabyack */ {"DAI Sel Mux", "Left", "Amp Enable"}, {"DAI Sel Mux", "Right", "Amp Enable"}, {"DAI Sel Mux", "LeftRight", "Amp Enable"}, {"BE_OUT", NULL, "DAI Sel Mux"}, + /* Capture */ + { "VI Sense", "Switch", "VMON" }, + { "VI Sense", "Switch", "IMON" }, + { "Voltage Sense", NULL, "VI Sense" }, + { "Current Sense", NULL, "VI Sense" }, }; static struct snd_soc_dai_driver max98927_dai[] = { -- cgit v1.2.3 From dea110501745734baf7a90dc1e1b50481ade6191 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 28 Aug 2017 16:31:01 -0700 Subject: ASoC: max98927: Changed device property read function Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 4bbf2098f255..926871e36132 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -759,14 +759,14 @@ static void max98927_slot_config(struct i2c_client *i2c, struct max98927_priv *max98927) { int value; + struct device *dev = &i2c->dev; - if (!of_property_read_u32(i2c->dev.of_node, - "vmon-slot-no", &value)) + if (!device_property_read_u32(dev, "vmon-slot-no", &value)) max98927->v_l_slot = value & 0xF; else max98927->v_l_slot = 0; - if (!of_property_read_u32(i2c->dev.of_node, - "imon-slot-no", &value)) + + if (!device_property_read_u32(dev, "imon-slot-no", &value)) max98927->i_l_slot = value & 0xF; else max98927->i_l_slot = 1; -- cgit v1.2.3 From 8f1e5bf9b4408e91942b94c76583eaf098f19382 Mon Sep 17 00:00:00 2001 From: Li Xu Date: Fri, 18 Aug 2017 11:00:19 -0500 Subject: ASoC: cs43130: Add support for CS43130 codec Add support for Cirrus Logic CS43130 codec. Support: I2S/DSP PCM playback. DoP/DSD playback. HP detection and DC/AC impedance measurement. Signed-off-by: Li Xu Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs43130.c | 2690 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs43130.h | 546 +++++++++ 4 files changed, 3244 insertions(+) create mode 100644 sound/soc/codecs/cs43130.c create mode 100644 sound/soc/codecs/cs43130.h (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6c78b0b49b81..ea7a2d540e5e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -60,6 +60,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_I2C if I2C select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C + select SND_SOC_CS43130 if I2C select SND_SOC_CS4349 if I2C select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CS53L30 if I2C @@ -486,6 +487,11 @@ config SND_SOC_CS42XX8_I2C select SND_SOC_CS42XX8 select REGMAP_I2C +# Cirrus Logic CS43130 HiFi DAC +config SND_SOC_CS43130 + tristate "Cirrus Logic CS43130 CODEC" + depends on I2C + # Cirrus Logic CS4349 HiFi DAC config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..5030e1f440d4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -53,6 +53,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o +snd-soc-cs43130-objs := cs43130.o snd-soc-cs4349-objs := cs4349.o snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs53l30-objs := cs53l30.o @@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o +obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c new file mode 100644 index 000000000000..220e30199c5b --- /dev/null +++ b/sound/soc/codecs/cs43130.c @@ -0,0 +1,2690 @@ +/* + * cs43130.c -- CS43130 ALSA Soc Audio driver + * + * Copyright 2017 Cirrus Logic, Inc. + * + * Authors: Li Xu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs43130.h" + +static const struct reg_default cs43130_reg_defaults[] = { + {CS43130_SYS_CLK_CTL_1, 0x06}, + {CS43130_SP_SRATE, 0x01}, + {CS43130_SP_BITSIZE, 0x05}, + {CS43130_PAD_INT_CFG, 0x03}, + {CS43130_PWDN_CTL, 0xFE}, + {CS43130_CRYSTAL_SET, 0x04}, + {CS43130_PLL_SET_1, 0x00}, + {CS43130_PLL_SET_2, 0x00}, + {CS43130_PLL_SET_3, 0x00}, + {CS43130_PLL_SET_4, 0x00}, + {CS43130_PLL_SET_5, 0x40}, + {CS43130_PLL_SET_6, 0x10}, + {CS43130_PLL_SET_7, 0x80}, + {CS43130_PLL_SET_8, 0x03}, + {CS43130_PLL_SET_9, 0x02}, + {CS43130_PLL_SET_10, 0x02}, + {CS43130_CLKOUT_CTL, 0x00}, + {CS43130_ASP_NUM_1, 0x01}, + {CS43130_ASP_NUM_2, 0x00}, + {CS43130_ASP_DEN_1, 0x08}, + {CS43130_ASP_DEN_2, 0x00}, + {CS43130_ASP_LRCK_HI_TIME_1, 0x1F}, + {CS43130_ASP_LRCK_HI_TIME_2, 0x00}, + {CS43130_ASP_LRCK_PERIOD_1, 0x3F}, + {CS43130_ASP_LRCK_PERIOD_2, 0x00}, + {CS43130_ASP_CLOCK_CONF, 0x0C}, + {CS43130_ASP_FRAME_CONF, 0x0A}, + {CS43130_XSP_NUM_1, 0x01}, + {CS43130_XSP_NUM_2, 0x00}, + {CS43130_XSP_DEN_1, 0x02}, + {CS43130_XSP_DEN_2, 0x00}, + {CS43130_XSP_LRCK_HI_TIME_1, 0x1F}, + {CS43130_XSP_LRCK_HI_TIME_2, 0x00}, + {CS43130_XSP_LRCK_PERIOD_1, 0x3F}, + {CS43130_XSP_LRCK_PERIOD_2, 0x00}, + {CS43130_XSP_CLOCK_CONF, 0x0C}, + {CS43130_XSP_FRAME_CONF, 0x0A}, + {CS43130_ASP_CH_1_LOC, 0x00}, + {CS43130_ASP_CH_2_LOC, 0x00}, + {CS43130_ASP_CH_1_SZ_EN, 0x06}, + {CS43130_ASP_CH_2_SZ_EN, 0x0E}, + {CS43130_XSP_CH_1_LOC, 0x00}, + {CS43130_XSP_CH_2_LOC, 0x00}, + {CS43130_XSP_CH_1_SZ_EN, 0x06}, + {CS43130_XSP_CH_2_SZ_EN, 0x0E}, + {CS43130_DSD_VOL_B, 0x78}, + {CS43130_DSD_VOL_A, 0x78}, + {CS43130_DSD_PATH_CTL_1, 0xA8}, + {CS43130_DSD_INT_CFG, 0x00}, + {CS43130_DSD_PATH_CTL_2, 0x02}, + {CS43130_DSD_PCM_MIX_CTL, 0x00}, + {CS43130_DSD_PATH_CTL_3, 0x40}, + {CS43130_HP_OUT_CTL_1, 0x30}, + {CS43130_PCM_FILT_OPT, 0x02}, + {CS43130_PCM_VOL_B, 0x78}, + {CS43130_PCM_VOL_A, 0x78}, + {CS43130_PCM_PATH_CTL_1, 0xA8}, + {CS43130_PCM_PATH_CTL_2, 0x00}, + {CS43130_CLASS_H_CTL, 0x1E}, + {CS43130_HP_DETECT, 0x04}, + {CS43130_HP_LOAD_1, 0x00}, + {CS43130_HP_MEAS_LOAD_1, 0x00}, + {CS43130_HP_MEAS_LOAD_2, 0x00}, + {CS43130_INT_MASK_1, 0xFF}, + {CS43130_INT_MASK_2, 0xFF}, + {CS43130_INT_MASK_3, 0xFF}, + {CS43130_INT_MASK_4, 0xFF}, + {CS43130_INT_MASK_5, 0xFF}, +}; + +static bool cs43130_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: + case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2: + case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2: + return true; + default: + return false; + } +} + +static bool cs43130_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1: + case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG: + case CS43130_PWDN_CTL: + case CS43130_CRYSTAL_SET: + case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5: + case CS43130_PLL_SET_6: + case CS43130_PLL_SET_7: + case CS43130_PLL_SET_8: + case CS43130_PLL_SET_9: + case CS43130_PLL_SET_10: + case CS43130_CLKOUT_CTL: + case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF: + case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF: + case CS43130_ASP_CH_1_LOC: + case CS43130_ASP_CH_2_LOC: + case CS43130_ASP_CH_1_SZ_EN: + case CS43130_ASP_CH_2_SZ_EN: + case CS43130_XSP_CH_1_LOC: + case CS43130_XSP_CH_2_LOC: + case CS43130_XSP_CH_1_SZ_EN: + case CS43130_XSP_CH_2_SZ_EN: + case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3: + case CS43130_HP_OUT_CTL_1: + case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2: + case CS43130_CLASS_H_CTL: + case CS43130_HP_DETECT: + case CS43130_HP_STATUS: + case CS43130_HP_LOAD_1: + case CS43130_HP_MEAS_LOAD_1: + case CS43130_HP_MEAS_LOAD_2: + case CS43130_HP_DC_STAT_1: + case CS43130_HP_DC_STAT_2: + case CS43130_HP_AC_STAT_1: + case CS43130_HP_AC_STAT_2: + case CS43130_HP_LOAD_STAT: + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: + case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5: + return true; + default: + return false; + } +} + +static bool cs43130_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: + return true; + default: + return false; + } +} + +struct cs43130_pll_params { + unsigned int pll_in; + u8 sclk_prediv; + u8 pll_div_int; + u32 pll_div_frac; + u8 pll_mode; + u8 pll_divout; + unsigned int pll_out; + u8 pll_cal_ratio; +}; + +static const struct cs43130_pll_params pll_ratio_table[] = { + {9600000, 0x02, 0x49, 0x800000, 0x00, 0x08, 22579200, 151}, + {9600000, 0x02, 0x50, 0x000000, 0x00, 0x08, 24576000, 164}, + + {11289600, 0x02, 0X40, 0, 0x01, 0x08, 22579200, 128}, + {11289600, 0x02, 0x44, 0x06F700, 0x0, 0x08, 24576000, 139}, + + {12000000, 0x02, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120}, + {12000000, 0x02, 0x40, 0x000000, 0x00, 0x08, 24576000, 131}, + + {12288000, 0x02, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118}, + {12288000, 0x02, 0x40, 0x000000, 0x01, 0x08, 24576000, 128}, + + {13000000, 0x02, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111}, + {13000000, 0x02, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121}, + + {19200000, 0x03, 0x49, 0x800000, 0x00, 0x08, 22579200, 151}, + {19200000, 0x03, 0x50, 0x000000, 0x00, 0x08, 24576000, 164}, + + {22579200, 0, 0, 0, 0, 0, 22579200, 0}, + {22579200, 0x03, 0x44, 0x06F700, 0x00, 0x08, 24576000, 139}, + + {24000000, 0x03, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120}, + {24000000, 0x03, 0x40, 0x000000, 0x00, 0x08, 24576000, 131}, + + {24576000, 0x03, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118}, + {24576000, 0, 0, 0, 0, 0, 24576000, 0}, + + {26000000, 0x03, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111}, + {26000000, 0x03, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121}, +}; + +static const struct cs43130_pll_params *cs43130_get_pll_table( + unsigned int freq_in, unsigned int freq_out) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].pll_in == freq_in && + pll_ratio_table[i].pll_out == freq_out) + return &pll_ratio_table[i]; + } + + return NULL; +} + +static int cs43130_pll_config(struct snd_soc_codec *codec) +{ + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + const struct cs43130_pll_params *pll_entry; + + dev_dbg(codec->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", + cs43130->mclk, cs43130->mclk_int); + + pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int); + if (!pll_entry) + return -EINVAL; + + if (pll_entry->pll_cal_ratio == 0) { + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1, + CS43130_PLL_START_MASK, 0); + + cs43130->pll_bypass = true; + return 0; + } + + cs43130->pll_bypass = false; + + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_2, + CS43130_PLL_DIV_DATA_MASK, + pll_entry->pll_div_frac >> + CS43130_PLL_DIV_FRAC_0_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_3, + CS43130_PLL_DIV_DATA_MASK, + pll_entry->pll_div_frac >> + CS43130_PLL_DIV_FRAC_1_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_4, + CS43130_PLL_DIV_DATA_MASK, + pll_entry->pll_div_frac >> + CS43130_PLL_DIV_FRAC_2_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_PLL_SET_5, + pll_entry->pll_div_int); + regmap_write(cs43130->regmap, CS43130_PLL_SET_6, pll_entry->pll_divout); + regmap_write(cs43130->regmap, CS43130_PLL_SET_7, + pll_entry->pll_cal_ratio); + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_8, + CS43130_PLL_MODE_MASK, + pll_entry->pll_mode << CS43130_PLL_MODE_SHIFT); + regmap_write(cs43130->regmap, CS43130_PLL_SET_9, + pll_entry->sclk_prediv); + regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1, + CS43130_PLL_START_MASK, 1); + + return 0; +} + +static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + int ret = 0; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (freq_in) { + case 9600000: + case 11289600: + case 12000000: + case 12288000: + case 13000000: + case 19200000: + case 22579200: + case 24000000: + case 24576000: + case 26000000: + cs43130->mclk = freq_in; + break; + default: + dev_err(codec->dev, + "unsupported pll input reference clock:%d\n", freq_in); + return -EINVAL; + } + + switch (freq_out) { + case 22579200: + cs43130->mclk_int = freq_out; + break; + case 24576000: + cs43130->mclk_int = freq_out; + break; + default: + dev_err(codec->dev, + "unsupported pll output ref clock: %u\n", freq_out); + return -EINVAL; + } + + ret = cs43130_pll_config(codec); + dev_dbg(codec->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); + return ret; +} + +static int cs43130_change_clksrc(struct snd_soc_codec *codec, + enum cs43130_mclk_src_sel src) +{ + int ret; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + int mclk_int_decoded; + + if (src == cs43130->mclk_int_src) { + /* clk source has not changed */ + return 0; + } + + switch (cs43130->mclk_int) { + case CS43130_MCLK_22M: + mclk_int_decoded = CS43130_MCLK_22P5; + break; + case CS43130_MCLK_24M: + mclk_int_decoded = CS43130_MCLK_24P5; + break; + default: + dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); + return -EINVAL; + } + + switch (src) { + case CS43130_MCLK_SRC_EXT: + cs43130->pll_bypass = true; + cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT; + if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) { + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_XTAL_MASK, + 1 << CS43130_PDN_XTAL_SHIFT); + } else { + reinit_completion(&cs43130->xtal_rdy); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_RDY_INT_MASK, 0); + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_XTAL_MASK, 0); + ret = wait_for_completion_timeout(&cs43130->xtal_rdy, + msecs_to_jiffies(100)); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_RDY_INT_MASK, + 1 << CS43130_XTAL_RDY_INT_SHIFT); + if (ret == 0) { + dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n"); + return -ETIMEDOUT; + } + } + + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_SRC_SEL_MASK, + src << CS43130_MCLK_SRC_SEL_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_INT_MASK, + mclk_int_decoded << CS43130_MCLK_INT_SHIFT); + usleep_range(150, 200); + + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_PLL_MASK, + 1 << CS43130_PDN_PLL_SHIFT); + break; + case CS43130_MCLK_SRC_PLL: + cs43130->pll_bypass = false; + cs43130->mclk_int_src = CS43130_MCLK_SRC_PLL; + if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) { + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_XTAL_MASK, + 1 << CS43130_PDN_XTAL_SHIFT); + } else { + reinit_completion(&cs43130->xtal_rdy); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_RDY_INT_MASK, 0); + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_XTAL_MASK, 0); + ret = wait_for_completion_timeout(&cs43130->xtal_rdy, + msecs_to_jiffies(100)); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_RDY_INT_MASK, + 1 << CS43130_XTAL_RDY_INT_SHIFT); + if (ret == 0) { + dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n"); + return -ETIMEDOUT; + } + } + + reinit_completion(&cs43130->pll_rdy); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_PLL_RDY_INT_MASK, 0); + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_PLL_MASK, 0); + ret = wait_for_completion_timeout(&cs43130->pll_rdy, + msecs_to_jiffies(100)); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_PLL_RDY_INT_MASK, + 1 << CS43130_PLL_RDY_INT_SHIFT); + if (ret == 0) { + dev_err(codec->dev, "Timeout waiting for PLL_READY interrupt\n"); + return -ETIMEDOUT; + } + + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_SRC_SEL_MASK, + src << CS43130_MCLK_SRC_SEL_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_INT_MASK, + mclk_int_decoded << CS43130_MCLK_INT_SHIFT); + usleep_range(150, 200); + break; + case CS43130_MCLK_SRC_RCO: + cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; + + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_SRC_SEL_MASK, + src << CS43130_MCLK_SRC_SEL_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, + CS43130_MCLK_INT_MASK, + CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT); + usleep_range(150, 200); + + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_XTAL_MASK, + 1 << CS43130_PDN_XTAL_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, + CS43130_PDN_PLL_MASK, + 1 << CS43130_PDN_PLL_SHIFT); + break; + default: + dev_err(codec->dev, "Invalid MCLK source value\n"); + return -EINVAL; + } + + return 0; +} + +static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = { + {8, CS43130_SP_BIT_SIZE_8, CS43130_CH_BIT_SIZE_8}, + {16, CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16}, + {24, CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24}, + {32, CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32}, +}; + +static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table( + unsigned int bitwidth) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) { + if (cs43130_bitwidth_table[i].bitwidth == bitwidth) + return &cs43130_bitwidth_table[i]; + } + + return NULL; +} + +static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai, + struct regmap *regmap) +{ + const struct cs43130_bitwidth_map *bw_map; + + bw_map = cs43130_get_bitwidth_table(bitwidth_dai); + if (!bw_map) + return -EINVAL; + + switch (dai_id) { + case CS43130_ASP_PCM_DAI: + case CS43130_ASP_DOP_DAI: + regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN, + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); + regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN, + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); + regmap_update_bits(regmap, CS43130_SP_BITSIZE, + CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit); + break; + case CS43130_XSP_DOP_DAI: + regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN, + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); + regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN, + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); + regmap_update_bits(regmap, CS43130_SP_BITSIZE, + CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit << + CS43130_XSP_BITSIZE_SHIFT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct cs43130_rate_map cs43130_rate_table[] = { + {32000, CS43130_ASP_SPRATE_32K}, + {44100, CS43130_ASP_SPRATE_44_1K}, + {48000, CS43130_ASP_SPRATE_48K}, + {88200, CS43130_ASP_SPRATE_88_2K}, + {96000, CS43130_ASP_SPRATE_96K}, + {176400, CS43130_ASP_SPRATE_176_4K}, + {192000, CS43130_ASP_SPRATE_192K}, + {352800, CS43130_ASP_SPRATE_352_8K}, + {384000, CS43130_ASP_SPRATE_384K}, +}; + +static const struct cs43130_rate_map *cs43130_get_rate_table(int fs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) { + if (cs43130_rate_table[i].fs == fs) + return &cs43130_rate_table[i]; + } + + return NULL; +} + +static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs, + const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table) +{ + int i; + + for (i = 0; i < len_clk_gen_table; i++) { + if (clk_gen_table[i].mclk_int == mclk_int && + clk_gen_table[i].fs == fs) + return &clk_gen_table[i]; + } + + return NULL; +} + +static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, + struct snd_pcm_hw_params *params, + struct cs43130_private *cs43130) +{ + u16 frm_size; + u16 hi_size; + u8 frm_delay; + u8 frm_phase; + u8 frm_data; + u8 sclk_edge; + u8 lrck_edge; + u8 clk_data; + u8 loc_ch1; + u8 loc_ch2; + u8 dai_mode_val; + const struct cs43130_clk_gen *clk_gen; + + switch (cs43130->dais[dai_id].dai_format) { + case SND_SOC_DAIFMT_I2S: + hi_size = bitwidth_sclk; + frm_delay = 2; + frm_phase = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + hi_size = bitwidth_sclk; + frm_delay = 2; + frm_phase = 1; + break; + case SND_SOC_DAIFMT_DSP_A: + hi_size = 1; + frm_delay = 2; + frm_phase = 1; + break; + case SND_SOC_DAIFMT_DSP_B: + hi_size = 1; + frm_delay = 0; + frm_phase = 1; + break; + default: + return -EINVAL; + } + + switch (cs43130->dais[dai_id].dai_mode) { + case SND_SOC_DAIFMT_CBS_CFS: + dai_mode_val = 0; + break; + case SND_SOC_DAIFMT_CBM_CFM: + dai_mode_val = 1; + break; + default: + return -EINVAL; + } + + frm_size = bitwidth_sclk * params_channels(params); + sclk_edge = 1; + lrck_edge = 0; + loc_ch1 = 0; + loc_ch2 = bitwidth_sclk * (params_channels(params) - 1); + + frm_data = frm_delay & CS43130_SP_FSD_MASK; + frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK; + + clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK; + clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) & + CS43130_SP_LCPOL_OUT_MASK; + clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) & + CS43130_SP_SCPOL_IN_MASK; + clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) & + CS43130_SP_SCPOL_OUT_MASK; + clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) & + CS43130_SP_MODE_MASK; + + switch (dai_id) { + case CS43130_ASP_PCM_DAI: + case CS43130_ASP_DOP_DAI: + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1, + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> + CS43130_SP_LCPR_LSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2, + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> + CS43130_SP_LCPR_MSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1, + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> + CS43130_SP_LCHI_LSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2, + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> + CS43130_SP_LCHI_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data); + regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1); + regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2); + regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN, + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN, + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data); + break; + case CS43130_XSP_DOP_DAI: + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1, + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> + CS43130_SP_LCPR_LSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2, + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> + CS43130_SP_LCPR_MSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1, + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> + CS43130_SP_LCHI_LSB_DATA_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2, + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> + CS43130_SP_LCHI_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data); + regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1); + regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2); + regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN, + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN, + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data); + break; + default: + return -EINVAL; + } + + switch (frm_size) { + case 16: + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, + params_rate(params), + cs43130_16_clk_gen, + ARRAY_SIZE(cs43130_16_clk_gen)); + break; + case 32: + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, + params_rate(params), + cs43130_32_clk_gen, + ARRAY_SIZE(cs43130_32_clk_gen)); + break; + case 48: + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, + params_rate(params), + cs43130_48_clk_gen, + ARRAY_SIZE(cs43130_48_clk_gen)); + break; + case 64: + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, + params_rate(params), + cs43130_64_clk_gen, + ARRAY_SIZE(cs43130_64_clk_gen)); + break; + default: + return -EINVAL; + } + + if (!clk_gen) + return -EINVAL; + + switch (dai_id) { + case CS43130_ASP_PCM_DAI: + case CS43130_ASP_DOP_DAI: + regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, + (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + CS43130_SP_M_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, + (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + CS43130_SP_M_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, + (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + CS43130_SP_N_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, + (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + CS43130_SP_N_MSB_DATA_SHIFT); + break; + case CS43130_XSP_DOP_DAI: + regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, + (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + CS43130_SP_M_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, + (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + CS43130_SP_M_MSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, + (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + CS43130_SP_N_LSB_DATA_SHIFT); + regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, + (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + CS43130_SP_N_MSB_DATA_SHIFT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs43130_pcm_dsd_mix(bool en, struct regmap *regmap) +{ + if (en) { + regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, + CS43130_MIX_PCM_PREP_MASK, + 1 << CS43130_MIX_PCM_PREP_SHIFT); + usleep_range(6000, 6050); + regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, + CS43130_MIX_PCM_DSD_MASK, + 1 << CS43130_MIX_PCM_DSD_SHIFT); + } else { + regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, + CS43130_MIX_PCM_DSD_MASK, + 0 << CS43130_MIX_PCM_DSD_SHIFT); + usleep_range(1600, 1650); + regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, + CS43130_MIX_PCM_PREP_MASK, + 0 << CS43130_MIX_PCM_PREP_SHIFT); + } + + return 0; +} + +static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + unsigned int required_clk; + u8 dsd_speed; + + mutex_lock(&cs43130->clk_mutex); + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; + + cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); + } + + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); + mutex_unlock(&cs43130->clk_mutex); + + switch (params_rate(params)) { + case 176400: + dsd_speed = 0; + break; + case 352800: + dsd_speed = 1; + break; + default: + dev_err(codec->dev, "Rate(%u) not supported\n", + params_rate(params)); + return -EINVAL; + } + + if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) + regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG, + CS43130_DSD_MASTER, CS43130_DSD_MASTER); + else + regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG, + CS43130_DSD_MASTER, 0); + + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_SPEED_MASK, + dsd_speed << CS43130_DSD_SPEED_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_DSD << + CS43130_DSD_SRC_SHIFT); + + return 0; +} + +static int cs43130_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + const struct cs43130_rate_map *rate_map; + unsigned int sclk = cs43130->dais[dai->id].sclk; + unsigned int bitwidth_sclk; + unsigned int bitwidth_dai = (unsigned int)(params_width(params)); + unsigned int required_clk; + u8 dsd_speed; + + mutex_lock(&cs43130->clk_mutex); + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; + + cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); + } + + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); + mutex_unlock(&cs43130->clk_mutex); + + switch (dai->id) { + case CS43130_ASP_DOP_DAI: + case CS43130_XSP_DOP_DAI: + /* DoP bitwidth is always 24-bit */ + bitwidth_dai = 24; + sclk = params_rate(params) * bitwidth_dai * + params_channels(params); + + switch (params_rate(params)) { + case 176400: + dsd_speed = 0; + break; + case 352800: + dsd_speed = 1; + break; + default: + dev_err(codec->dev, "Rate(%u) not supported\n", + params_rate(params)); + return -EINVAL; + } + + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_SPEED_MASK, + dsd_speed << CS43130_DSD_SPEED_SHIFT); + break; + case CS43130_ASP_PCM_DAI: + rate_map = cs43130_get_rate_table(params_rate(params)); + if (!rate_map) + return -EINVAL; + + regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val); + break; + default: + dev_err(codec->dev, "Invalid DAI (%d)\n", dai->id); + return -EINVAL; + } + + switch (dai->id) { + case CS43130_ASP_DOP_DAI: + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP << + CS43130_DSD_SRC_SHIFT); + break; + case CS43130_XSP_DOP_DAI: + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP << + CS43130_DSD_SRC_SHIFT); + } + + if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) + /* Calculate SCLK in master mode if unassigned */ + sclk = params_rate(params) * bitwidth_dai * + params_channels(params); + + if (!sclk) { + /* at this point, SCLK must be set */ + dev_err(codec->dev, "SCLK freq is not set\n"); + return -EINVAL; + } + + bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params); + if (bitwidth_sclk < bitwidth_dai) { + dev_err(codec->dev, "Format not supported: SCLK freq is too low\n"); + return -EINVAL; + } + + dev_dbg(codec->dev, + "sclk = %u, fs = %d, bitwidth_dai = %u\n", + sclk, params_rate(params), bitwidth_dai); + + dev_dbg(codec->dev, + "bitwidth_sclk = %u, num_ch = %u\n", + bitwidth_sclk, params_channels(params)); + + cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap); + cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130); + + return 0; +} + +static int cs43130_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&cs43130->clk_mutex); + cs43130->clk_req--; + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO); + cs43130_pcm_dsd_mix(false, cs43130->regmap); + } + mutex_unlock(&cs43130->clk_mutex); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(pcm_vol_tlv, -12750, 50, 1); + +static const char * const pcm_ch_text[] = { + "Left-Right Ch", + "Left-Left Ch", + "Right-Left Ch", + "Right-Right Ch", +}; + +static const struct reg_sequence pcm_ch_en_seq[] = { + {CS43130_DXD1, 0x99}, + {0x180005, 0x8C}, + {0x180007, 0xAB}, + {0x180015, 0x31}, + {0x180017, 0xB2}, + {0x180025, 0x30}, + {0x180027, 0x84}, + {0x180035, 0x9C}, + {0x180037, 0xAE}, + {0x18000D, 0x24}, + {0x18000F, 0xA3}, + {0x18001D, 0x05}, + {0x18001F, 0xD4}, + {0x18002D, 0x0B}, + {0x18002F, 0xC7}, + {0x18003D, 0x71}, + {0x18003F, 0xE7}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence pcm_ch_dis_seq[] = { + {CS43130_DXD1, 0x99}, + {0x180005, 0x24}, + {0x180007, 0xA3}, + {0x180015, 0x05}, + {0x180017, 0xD4}, + {0x180025, 0x0B}, + {0x180027, 0xC7}, + {0x180035, 0x71}, + {0x180037, 0xE7}, + {0x18000D, 0x8C}, + {0x18000F, 0xAB}, + {0x18001D, 0x31}, + {0x18001F, 0xB2}, + {0x18002D, 0x30}, + {0x18002F, 0x84}, + {0x18003D, 0x9C}, + {0x18003F, 0xAE}, + {CS43130_DXD1, 0}, +}; + +static int cs43130_pcm_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return snd_soc_get_enum_double(kcontrol, ucontrol); +} + +static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + unsigned int val; + + if (item[0] >= e->items) + return -EINVAL; + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + switch (cs43130->dev_id) { + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + if (val >= 2) + regmap_multi_reg_write(cs43130->regmap, pcm_ch_en_seq, + ARRAY_SIZE(pcm_ch_en_seq)); + else + regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq, + ARRAY_SIZE(pcm_ch_dis_seq)); + } + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + +static SOC_ENUM_SINGLE_DECL(pcm_ch_enum, CS43130_PCM_PATH_CTL_2, 0, + pcm_ch_text); + +static const char * const pcm_spd_texts[] = { + "Fast", + "Slow", +}; + +static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7, + pcm_spd_texts); + +static const char * const dsd_texts[] = { + "Off", + "BCKA Mode", + "BCKD Mode", +}; + +static const unsigned int dsd_values[] = { + CS43130_DSD_SRC_DSD, + CS43130_DSD_SRC_ASP, + CS43130_DSD_SRC_XSP, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(dsd_enum, CS43130_DSD_INT_CFG, 0, 0x03, + dsd_texts, dsd_values); + +static const struct snd_kcontrol_new cs43130_snd_controls[] = { + SOC_DOUBLE_R_TLV("Master Playback Volume", + CS43130_PCM_VOL_A, CS43130_PCM_VOL_B, 0, 0xFF, 1, + pcm_vol_tlv), + SOC_DOUBLE_R_TLV("Master DSD Playback Volume", + CS43130_DSD_VOL_A, CS43130_DSD_VOL_B, 0, 0xFF, 1, + pcm_vol_tlv), + SOC_ENUM_EXT("PCM Ch Select", pcm_ch_enum, cs43130_pcm_ch_get, + cs43130_pcm_ch_put), + SOC_ENUM("PCM Filter Speed", pcm_spd_enum), + SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0), + SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0), + SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0), + SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0), + SOC_ENUM("DSD Phase Modulation", dsd_enum), +}; + +static const struct reg_sequence pcm_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD7, 0x01}, + {CS43130_DXD8, 0}, + {CS43130_DXD9, 0x01}, + {CS43130_DXD3, 0x12}, + {CS43130_DXD4, 0}, + {CS43130_DXD10, 0x28}, + {CS43130_DXD11, 0x28}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence dsd_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD7, 0x01}, + {CS43130_DXD8, 0}, + {CS43130_DXD9, 0x01}, + {CS43130_DXD3, 0x12}, + {CS43130_DXD4, 0}, + {CS43130_DXD10, 0x1E}, + {CS43130_DXD11, 0x20}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence pop_free_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD12, 0x0A}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence pop_free_seq2[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD13, 0x20}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence mute_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD3, 0x12}, + {CS43130_DXD5, 0x02}, + {CS43130_DXD4, 0x12}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence unmute_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD3, 0x10}, + {CS43130_DXD5, 0}, + {CS43130_DXD4, 0x16}, + {CS43130_DXD1, 0}, +}; + +static int cs43130_dsd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, dsd_seq, + ARRAY_SIZE(dsd_seq)); + } + break; + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_1, + CS43130_MUTE_MASK, 0); + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, unmute_seq, + ARRAY_SIZE(unmute_seq)); + } + break; + case SND_SOC_DAPM_PRE_PMD: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, mute_seq, + ARRAY_SIZE(mute_seq)); + regmap_update_bits(cs43130->regmap, + CS43130_DSD_PATH_CTL_1, + CS43130_MUTE_MASK, CS43130_MUTE_EN); + /* + * DSD Power Down Sequence + * According to Design, 130ms is preferred. + */ + msleep(130); + break; + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + regmap_update_bits(cs43130->regmap, + CS43130_DSD_PATH_CTL_1, + CS43130_MUTE_MASK, CS43130_MUTE_EN); + } + break; + default: + dev_err(codec->dev, "Invalid event = 0x%x\n", event); + return -EINVAL; + } + return 0; +} + +static int cs43130_pcm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, pcm_seq, + ARRAY_SIZE(pcm_seq)); + } + break; + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(cs43130->regmap, CS43130_PCM_PATH_CTL_1, + CS43130_MUTE_MASK, 0); + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, unmute_seq, + ARRAY_SIZE(unmute_seq)); + } + break; + case SND_SOC_DAPM_PRE_PMD: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, mute_seq, + ARRAY_SIZE(mute_seq)); + regmap_update_bits(cs43130->regmap, + CS43130_PCM_PATH_CTL_1, + CS43130_MUTE_MASK, CS43130_MUTE_EN); + /* + * PCM Power Down Sequence + * According to Design, 130ms is preferred. + */ + msleep(130); + break; + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + regmap_update_bits(cs43130->regmap, + CS43130_PCM_PATH_CTL_1, + CS43130_MUTE_MASK, CS43130_MUTE_EN); + } + break; + default: + dev_err(codec->dev, "Invalid event = 0x%x\n", event); + return -EINVAL; + } + return 0; +} + +static const struct reg_sequence dac_postpmu_seq[] = { + {CS43130_DXD9, 0x0C}, + {CS43130_DXD3, 0x10}, + {CS43130_DXD4, 0x20}, +}; + +static const struct reg_sequence dac_postpmd_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD6, 0x01}, + {CS43130_DXD1, 0}, +}; + +static int cs43130_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, pop_free_seq, + ARRAY_SIZE(pop_free_seq)); + break; + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, pop_free_seq2, + ARRAY_SIZE(pop_free_seq2)); + } + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(10000, 10050); + + regmap_write(cs43130->regmap, CS43130_DXD1, 0x99); + + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, dac_postpmu_seq, + ARRAY_SIZE(dac_postpmu_seq)); + /* + * Per datasheet, Sec. PCM Power-Up Sequence. + * According to Design, CS43130_DXD12 must be 0 to meet + * THDN and Dynamic Range spec. + */ + msleep(1000); + regmap_write(cs43130->regmap, CS43130_DXD12, 0); + break; + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + usleep_range(12000, 12010); + regmap_write(cs43130->regmap, CS43130_DXD13, 0); + } + + regmap_write(cs43130->regmap, CS43130_DXD1, 0); + break; + case SND_SOC_DAPM_POST_PMD: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq, + ARRAY_SIZE(dac_postpmd_seq)); + } + break; + default: + dev_err(codec->dev, "Invalid DAC event = 0x%x\n", event); + return -EINVAL; + } + return 0; +} + +static const struct reg_sequence hpin_prepmd_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD15, 0x64}, + {CS43130_DXD14, 0}, + {CS43130_DXD2, 0}, + {CS43130_DXD1, 0}, +}; + +static const struct reg_sequence hpin_postpmu_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD2, 1}, + {CS43130_DXD14, 0xDC}, + {CS43130_DXD15, 0xE4}, + {CS43130_DXD1, 0}, +}; + +static int cs43130_hpin_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + regmap_multi_reg_write(cs43130->regmap, hpin_prepmd_seq, + ARRAY_SIZE(hpin_prepmd_seq)); + break; + case SND_SOC_DAPM_PRE_PMU: + regmap_multi_reg_write(cs43130->regmap, hpin_postpmu_seq, + ARRAY_SIZE(hpin_postpmu_seq)); + break; + default: + dev_err(codec->dev, "Invalid HPIN event = 0x%x\n", event); + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dapm_widget digital_hp_widgets[] = { + SND_SOC_DAPM_OUTPUT("HPOUTA"), + SND_SOC_DAPM_OUTPUT("HPOUTB"), + + SND_SOC_DAPM_AIF_IN_E("ASPIN PCM", NULL, 0, CS43130_PWDN_CTL, + CS43130_PDN_ASP_SHIFT, 1, cs43130_pcm_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD)), + + SND_SOC_DAPM_AIF_IN_E("ASPIN DoP", NULL, 0, CS43130_PWDN_CTL, + CS43130_PDN_ASP_SHIFT, 1, cs43130_dsd_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD)), + + SND_SOC_DAPM_AIF_IN_E("XSPIN DoP", NULL, 0, CS43130_PWDN_CTL, + CS43130_PDN_XSP_SHIFT, 1, cs43130_dsd_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD)), + + SND_SOC_DAPM_AIF_IN_E("XSPIN DSD", NULL, 0, CS43130_PWDN_CTL, + CS43130_PDN_DSDIF_SHIFT, 1, cs43130_dsd_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD)), + + SND_SOC_DAPM_DAC("DSD", NULL, CS43130_DSD_PATH_CTL_2, + CS43130_DSD_EN_SHIFT, 0), + + SND_SOC_DAPM_DAC_E("HiFi DAC", NULL, CS43130_PWDN_CTL, + CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD)), +}; + +static const struct snd_soc_dapm_widget analog_hp_widgets[] = { + SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1, + CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)), +}; + +static struct snd_soc_dapm_widget all_hp_widgets[ + ARRAY_SIZE(digital_hp_widgets) + + ARRAY_SIZE(analog_hp_widgets)]; + +static const struct snd_soc_dapm_route digital_hp_routes[] = { + {"ASPIN PCM", NULL, "ASP PCM Playback"}, + {"ASPIN DoP", NULL, "ASP DoP Playback"}, + {"XSPIN DoP", NULL, "XSP DoP Playback"}, + {"XSPIN DSD", NULL, "XSP DSD Playback"}, + {"DSD", NULL, "ASPIN DoP"}, + {"DSD", NULL, "XSPIN DoP"}, + {"DSD", NULL, "XSPIN DSD"}, + {"HiFi DAC", NULL, "ASPIN PCM"}, + {"HiFi DAC", NULL, "DSD"}, + {"HPOUTA", NULL, "HiFi DAC"}, + {"HPOUTB", NULL, "HiFi DAC"}, +}; + +static const struct snd_soc_dapm_route analog_hp_routes[] = { + {"HPOUTA", NULL, "Analog Playback"}, + {"HPOUTB", NULL, "Analog Playback"}, +}; + +static struct snd_soc_dapm_route all_hp_routes[ + ARRAY_SIZE(digital_hp_routes) + + ARRAY_SIZE(analog_hp_routes)]; + +static const unsigned int cs43130_asp_src_rates[] = { + 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 +}; + +static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = { + .count = ARRAY_SIZE(cs43130_asp_src_rates), + .list = cs43130_asp_src_rates, +}; + +static int cs43130_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &cs43130_asp_constraints); +} + +static const unsigned int cs43130_dop_src_rates[] = { + 176400, 352800, +}; + +static const struct snd_pcm_hw_constraint_list cs43130_dop_constraints = { + .count = ARRAY_SIZE(cs43130_dop_src_rates), + .list = cs43130_dop_src_rates, +}; + +static int cs43130_dop_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &cs43130_dop_constraints); +} + +static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; + break; + case SND_SOC_DAIFMT_CBM_CFM: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; + break; + default: + dev_err(codec->dev, "unsupported mode\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B; + break; + default: + dev_err(codec->dev, + "unsupported audio format\n"); + return -EINVAL; + } + + dev_dbg(codec->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", + codec_dai->id, + cs43130->dais[codec_dai->id].dai_mode, + cs43130->dais[codec_dai->id].dai_format); + + return 0; +} + +static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; + break; + case SND_SOC_DAIFMT_CBM_CFM: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; + break; + default: + dev_err(codec->dev, "Unsupported DAI format.\n"); + return -EINVAL; + } + + dev_dbg(codec->dev, "dai_mode = 0x%x\n", + cs43130->dais[codec_dai->id].dai_mode); + + return 0; +} + +static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + cs43130->dais[codec_dai->id].sclk = freq; + dev_dbg(codec->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, + cs43130->dais[codec_dai->id].sclk); + + return 0; +} + +static const struct snd_soc_dai_ops cs43130_pcm_ops = { + .startup = cs43130_pcm_startup, + .hw_params = cs43130_hw_params, + .hw_free = cs43130_hw_free, + .set_sysclk = cs43130_set_sysclk, + .set_fmt = cs43130_pcm_set_fmt, +}; + +static const struct snd_soc_dai_ops cs43130_dop_ops = { + .startup = cs43130_dop_startup, + .hw_params = cs43130_hw_params, + .hw_free = cs43130_hw_free, + .set_sysclk = cs43130_set_sysclk, + .set_fmt = cs43130_pcm_set_fmt, +}; + +static const struct snd_soc_dai_ops cs43130_dsd_ops = { + .startup = cs43130_dop_startup, + .hw_params = cs43130_dsd_hw_params, + .hw_free = cs43130_hw_free, + .set_fmt = cs43130_dsd_set_fmt, +}; + +static struct snd_soc_dai_driver cs43130_dai[] = { + { + .name = "cs43130-asp-pcm", + .id = CS43130_ASP_PCM_DAI, + .playback = { + .stream_name = "ASP PCM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS43130_PCM_FORMATS, + }, + .ops = &cs43130_pcm_ops, + .symmetric_rates = 1, + }, + { + .name = "cs43130-asp-dop", + .id = CS43130_ASP_DOP_DAI, + .playback = { + .stream_name = "ASP DoP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS43130_DOP_FORMATS, + }, + .ops = &cs43130_dop_ops, + .symmetric_rates = 1, + }, + { + .name = "cs43130-xsp-dop", + .id = CS43130_XSP_DOP_DAI, + .playback = { + .stream_name = "XSP DoP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS43130_DOP_FORMATS, + }, + .ops = &cs43130_dop_ops, + .symmetric_rates = 1, + }, + { + .name = "cs43130-xsp-dsd", + .id = CS43130_XSP_DSD_DAI, + .playback = { + .stream_name = "XSP DSD Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS43130_DOP_FORMATS, + }, + .ops = &cs43130_dsd_ops, + }, + +}; + +static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, + int dir) +{ + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", + clk_id, source, freq, dir); + + switch (freq) { + case CS43130_MCLK_22M: + case CS43130_MCLK_24M: + cs43130->mclk = freq; + break; + default: + dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", freq); + return -EINVAL; + } + + if (source == CS43130_MCLK_SRC_EXT) { + cs43130->pll_bypass = true; + } else { + dev_err(codec->dev, "Invalid MCLK source\n"); + return -EINVAL; + } + + return 0; +} + +static inline u16 cs43130_get_ac_reg_val(u16 ac_freq) +{ + /* AC freq is counted in 5.94Hz step. */ + return ac_freq / 6; +} + +static int cs43130_show_dc(struct device *dev, char *buf, u8 ch) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cs43130_private *cs43130 = i2c_get_clientdata(client); + + if (!cs43130->hpload_done) + return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + else + return scnprintf(buf, PAGE_SIZE, "%u\n", + cs43130->hpload_dc[ch]); +} + +static ssize_t cs43130_show_dc_l(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return cs43130_show_dc(dev, buf, HP_LEFT); +} + +static ssize_t cs43130_show_dc_r(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return cs43130_show_dc(dev, buf, HP_RIGHT); +} + +static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = { + 24, + 43, + 93, + 200, + 431, + 928, + 2000, + 4309, + 9283, + 20000, +}; + +static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) +{ + int i, j = 0, tmp; + struct i2c_client *client = to_i2c_client(dev); + struct cs43130_private *cs43130 = i2c_get_clientdata(client); + + if (cs43130->hpload_done && cs43130->ac_meas) { + for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) { + tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n", + cs43130->hpload_ac[i][ch]); + if (!tmp) + break; + + j += tmp; + } + + return j; + } else { + return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + } +} + +static ssize_t cs43130_show_ac_l(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return cs43130_show_ac(dev, buf, HP_LEFT); +} + +static ssize_t cs43130_show_ac_r(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return cs43130_show_ac(dev, buf, HP_RIGHT); +} + +static DEVICE_ATTR(hpload_dc_l, S_IRUGO, cs43130_show_dc_l, NULL); +static DEVICE_ATTR(hpload_dc_r, S_IRUGO, cs43130_show_dc_r, NULL); +static DEVICE_ATTR(hpload_ac_l, S_IRUGO, cs43130_show_ac_l, NULL); +static DEVICE_ATTR(hpload_ac_r, S_IRUGO, cs43130_show_ac_r, NULL); + +static struct reg_sequence hp_en_cal_seq[] = { + {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, + {CS43130_HP_MEAS_LOAD_1, 0}, + {CS43130_HP_MEAS_LOAD_2, 0}, + {CS43130_INT_MASK_4, 0}, + {CS43130_DXD1, 0x99}, + {CS43130_DXD16, 0xBB}, + {CS43130_DXD12, 0x01}, + {CS43130_DXD19, 0xCB}, + {CS43130_DXD17, 0x95}, + {CS43130_DXD18, 0x0B}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0x80}, +}; + +static struct reg_sequence hp_en_cal_seq2[] = { + {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, + {CS43130_HP_MEAS_LOAD_1, 0}, + {CS43130_HP_MEAS_LOAD_2, 0}, + {CS43130_INT_MASK_4, 0}, + {CS43130_HP_LOAD_1, 0x80}, +}; + +static struct reg_sequence hp_dis_cal_seq[] = { + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_DXD1, 0x99}, + {CS43130_DXD12, 0}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0}, +}; + +static struct reg_sequence hp_dis_cal_seq2[] = { + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_HP_LOAD_1, 0}, +}; + +static struct reg_sequence hp_dc_ch_l_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD19, 0x0A}, + {CS43130_DXD17, 0x93}, + {CS43130_DXD18, 0x0A}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_HP_LOAD_1, 0x81}, +}; + +static struct reg_sequence hp_dc_ch_l_seq2[] = { + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_HP_LOAD_1, 0x81}, +}; + +static struct reg_sequence hp_dc_ch_r_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD19, 0x8A}, + {CS43130_DXD17, 0x15}, + {CS43130_DXD18, 0x06}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0x90}, + {CS43130_HP_LOAD_1, 0x91}, +}; + +static struct reg_sequence hp_dc_ch_r_seq2[] = { + {CS43130_HP_LOAD_1, 0x90}, + {CS43130_HP_LOAD_1, 0x91}, +}; + +static struct reg_sequence hp_ac_ch_l_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD19, 0x0A}, + {CS43130_DXD17, 0x93}, + {CS43130_DXD18, 0x0A}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_HP_LOAD_1, 0x82}, +}; + +static struct reg_sequence hp_ac_ch_l_seq2[] = { + {CS43130_HP_LOAD_1, 0x80}, + {CS43130_HP_LOAD_1, 0x82}, +}; + +static struct reg_sequence hp_ac_ch_r_seq[] = { + {CS43130_DXD1, 0x99}, + {CS43130_DXD19, 0x8A}, + {CS43130_DXD17, 0x15}, + {CS43130_DXD18, 0x06}, + {CS43130_DXD1, 0}, + {CS43130_HP_LOAD_1, 0x90}, + {CS43130_HP_LOAD_1, 0x92}, +}; + +static struct reg_sequence hp_ac_ch_r_seq2[] = { + {CS43130_HP_LOAD_1, 0x90}, + {CS43130_HP_LOAD_1, 0x92}, +}; + +static struct reg_sequence hp_cln_seq[] = { + {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, + {CS43130_HP_MEAS_LOAD_1, 0}, + {CS43130_HP_MEAS_LOAD_2, 0}, +}; + +struct reg_sequences { + struct reg_sequence *seq; + int size; + unsigned int msk; +}; + +static struct reg_sequences hpload_seq1[] = { + { + .seq = hp_en_cal_seq, + .size = ARRAY_SIZE(hp_en_cal_seq), + .msk = CS43130_HPLOAD_ON_INT, + }, + { + .seq = hp_dc_ch_l_seq, + .size = ARRAY_SIZE(hp_dc_ch_l_seq), + .msk = CS43130_HPLOAD_DC_INT, + }, + { + .seq = hp_ac_ch_l_seq, + .size = ARRAY_SIZE(hp_ac_ch_l_seq), + .msk = CS43130_HPLOAD_AC_INT, + }, + { + .seq = hp_dis_cal_seq, + .size = ARRAY_SIZE(hp_dis_cal_seq), + .msk = CS43130_HPLOAD_OFF_INT, + }, + { + .seq = hp_en_cal_seq, + .size = ARRAY_SIZE(hp_en_cal_seq), + .msk = CS43130_HPLOAD_ON_INT, + }, + { + .seq = hp_dc_ch_r_seq, + .size = ARRAY_SIZE(hp_dc_ch_r_seq), + .msk = CS43130_HPLOAD_DC_INT, + }, + { + .seq = hp_ac_ch_r_seq, + .size = ARRAY_SIZE(hp_ac_ch_r_seq), + .msk = CS43130_HPLOAD_AC_INT, + }, +}; + +static struct reg_sequences hpload_seq2[] = { + { + .seq = hp_en_cal_seq2, + .size = ARRAY_SIZE(hp_en_cal_seq2), + .msk = CS43130_HPLOAD_ON_INT, + }, + { + .seq = hp_dc_ch_l_seq2, + .size = ARRAY_SIZE(hp_dc_ch_l_seq2), + .msk = CS43130_HPLOAD_DC_INT, + }, + { + .seq = hp_ac_ch_l_seq2, + .size = ARRAY_SIZE(hp_ac_ch_l_seq2), + .msk = CS43130_HPLOAD_AC_INT, + }, + { + .seq = hp_dis_cal_seq2, + .size = ARRAY_SIZE(hp_dis_cal_seq2), + .msk = CS43130_HPLOAD_OFF_INT, + }, + { + .seq = hp_en_cal_seq2, + .size = ARRAY_SIZE(hp_en_cal_seq2), + .msk = CS43130_HPLOAD_ON_INT, + }, + { + .seq = hp_dc_ch_r_seq2, + .size = ARRAY_SIZE(hp_dc_ch_r_seq2), + .msk = CS43130_HPLOAD_DC_INT, + }, + { + .seq = hp_ac_ch_r_seq2, + .size = ARRAY_SIZE(hp_ac_ch_r_seq2), + .msk = CS43130_HPLOAD_AC_INT, + }, +}; + +static int cs43130_update_hpload(unsigned int msk, int ac_idx, + struct cs43130_private *cs43130) +{ + bool left_ch = true; + unsigned int reg; + u32 addr; + u16 impedance; + struct snd_soc_codec *codec = cs43130->codec; + + switch (msk) { + case CS43130_HPLOAD_DC_INT: + case CS43130_HPLOAD_AC_INT: + break; + default: + return 0; + } + + regmap_read(cs43130->regmap, CS43130_HP_LOAD_1, ®); + if (reg & CS43130_HPLOAD_CHN_SEL) + left_ch = false; + + if (msk == CS43130_HPLOAD_DC_INT) + addr = CS43130_HP_DC_STAT_1; + else + addr = CS43130_HP_AC_STAT_1; + + regmap_read(cs43130->regmap, addr, ®); + impedance = reg >> 3; + regmap_read(cs43130->regmap, addr + 1, ®); + impedance |= reg << 5; + + if (msk == CS43130_HPLOAD_DC_INT) { + if (left_ch) + cs43130->hpload_dc[HP_LEFT] = impedance; + else + cs43130->hpload_dc[HP_RIGHT] = impedance; + + dev_dbg(codec->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, + impedance); + } else { + if (left_ch) + cs43130->hpload_ac[ac_idx][HP_LEFT] = impedance; + else + cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance; + + dev_dbg(codec->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", + cs43130->ac_freq[ac_idx], !left_ch, impedance); + } + + return 0; +} + +static int cs43130_hpload_proc(struct cs43130_private *cs43130, + struct reg_sequence *seq, int seq_size, + unsigned int rslt_msk, int ac_idx) +{ + int ret; + unsigned int msk; + u16 ac_reg_val; + struct snd_soc_codec *codec = cs43130->codec; + + reinit_completion(&cs43130->hpload_evt); + + if (rslt_msk == CS43130_HPLOAD_AC_INT) { + ac_reg_val = cs43130_get_ac_reg_val(cs43130->ac_freq[ac_idx]); + regmap_update_bits(cs43130->regmap, CS43130_HP_LOAD_1, + CS43130_HPLOAD_AC_START, 0); + regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_1, + CS43130_HP_MEAS_LOAD_MASK, + ac_reg_val >> CS43130_HP_MEAS_LOAD_1_SHIFT); + regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_2, + CS43130_HP_MEAS_LOAD_MASK, + ac_reg_val >> CS43130_HP_MEAS_LOAD_2_SHIFT); + } + + regmap_multi_reg_write(cs43130->regmap, seq, + seq_size); + + ret = wait_for_completion_timeout(&cs43130->hpload_evt, + msecs_to_jiffies(1000)); + regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk); + if (!ret) { + dev_err(codec->dev, "Timeout waiting for HPLOAD interrupt\n"); + return -1; + } + + dev_dbg(codec->dev, "HP load stat: %x, INT_MASK_4: %x\n", + cs43130->hpload_stat, msk); + if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT | + CS43130_HPLOAD_UNPLUG_INT | + CS43130_HPLOAD_OOR_INT)) || + !(cs43130->hpload_stat & rslt_msk)) { + dev_dbg(codec->dev, "HP load measure failed\n"); + return -1; + } + + return 0; +} + +static const struct reg_sequence hv_seq[][2] = { + { + {CS43130_CLASS_H_CTL, 0x1C}, + {CS43130_HP_OUT_CTL_1, 0x10}, + }, + { + {CS43130_CLASS_H_CTL, 0x1E}, + {CS43130_HP_OUT_CTL_1, 0x20}, + }, + { + {CS43130_CLASS_H_CTL, 0x1E}, + {CS43130_HP_OUT_CTL_1, 0x30}, + }, +}; + +static int cs43130_set_hv(struct regmap *regmap, u16 hpload_dc, + const u16 *dc_threshold) +{ + int i; + + for (i = 0; i < CS43130_DC_THRESHOLD; i++) { + if (hpload_dc <= dc_threshold[i]) + break; + } + + regmap_multi_reg_write(regmap, hv_seq[i], ARRAY_SIZE(hv_seq[i])); + + return 0; +} + +static void cs43130_imp_meas(struct work_struct *wk) +{ + unsigned int reg, seq_size; + int i, ret, ac_idx; + struct cs43130_private *cs43130; + struct snd_soc_codec *codec; + struct reg_sequences *hpload_seq; + + cs43130 = container_of(wk, struct cs43130_private, work); + codec = cs43130->codec; + + if (!cs43130->mclk) + return; + + cs43130->hpload_done = false; + + mutex_lock(&cs43130->clk_mutex); + if (!cs43130->clk_req) { + /* clk not in use */ + cs43130_set_pll(codec, 0, 0, cs43130->mclk, CS43130_MCLK_22M); + if (cs43130->pll_bypass) + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); + } + + cs43130->clk_req++; + mutex_unlock(&cs43130->clk_mutex); + + regmap_read(cs43130->regmap, CS43130_INT_STATUS_4, ®); + + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + hpload_seq = hpload_seq1; + seq_size = ARRAY_SIZE(hpload_seq1); + break; + case CS43131_CHIP_ID: + hpload_seq = hpload_seq2; + seq_size = ARRAY_SIZE(hpload_seq2); + } + + i = 0; + ac_idx = 0; + while (i < seq_size) { + ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq, + hpload_seq[i].size, + hpload_seq[i].msk, ac_idx); + if (ret < 0) + goto exit; + + cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130); + + if (cs43130->ac_meas && + hpload_seq[i].msk == CS43130_HPLOAD_AC_INT && + ac_idx < CS43130_AC_FREQ - 1) { + ac_idx++; + } else { + ac_idx = 0; + i++; + } + } + cs43130->hpload_done = true; + + if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD) + snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT, + CS43130_JACK_MASK); + else + snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE, + CS43130_JACK_MASK); + + dev_dbg(codec->dev, "Set HP output control. DC threshold\n"); + for (i = 0; i < CS43130_DC_THRESHOLD; i++) + dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i, + cs43130->dc_threshold[i]); + + cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT], + cs43130->dc_threshold); + +exit: + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + cs43130_hpload_proc(cs43130, hp_dis_cal_seq, + ARRAY_SIZE(hp_dis_cal_seq), + CS43130_HPLOAD_OFF_INT, ac_idx); + break; + case CS43131_CHIP_ID: + cs43130_hpload_proc(cs43130, hp_dis_cal_seq2, + ARRAY_SIZE(hp_dis_cal_seq2), + CS43130_HPLOAD_OFF_INT, ac_idx); + } + + regmap_multi_reg_write(cs43130->regmap, hp_cln_seq, + ARRAY_SIZE(hp_cln_seq)); + + mutex_lock(&cs43130->clk_mutex); + cs43130->clk_req--; + /* clk not in use */ + if (!cs43130->clk_req) + cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO); + mutex_unlock(&cs43130->clk_mutex); +} + +static irqreturn_t cs43130_irq_thread(int irq, void *data) +{ + struct cs43130_private *cs43130 = (struct cs43130_private *)data; + struct snd_soc_codec *codec = cs43130->codec; + unsigned int stickies[CS43130_NUM_INT]; + unsigned int irq_occurrance = 0; + unsigned int masks[CS43130_NUM_INT]; + int i, j; + + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i, + &stickies[i]); + regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i, + &masks[i]); + } + + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + stickies[i] = stickies[i] & (~masks[i]); + for (j = 0; j < 8; j++) + irq_occurrance += (stickies[i] >> j) & 1; + } + dev_dbg(codec->dev, "number of interrupts occurred (%u)\n", + irq_occurrance); + + if (!irq_occurrance) + return IRQ_NONE; + + if (stickies[0] & CS43130_XTAL_RDY_INT) { + complete(&cs43130->xtal_rdy); + return IRQ_HANDLED; + } + + if (stickies[0] & CS43130_PLL_RDY_INT) { + complete(&cs43130->pll_rdy); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) { + cs43130->hpload_stat = stickies[3]; + dev_err(codec->dev, + "DC load has not completed before AC load (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) { + cs43130->hpload_stat = stickies[3]; + dev_err(codec->dev, "HP unplugged during measurement (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_OOR_INT) { + cs43130->hpload_stat = stickies[3]; + dev_err(codec->dev, "HP load out of range (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_AC_INT) { + cs43130->hpload_stat = stickies[3]; + dev_dbg(codec->dev, "HP AC load measurement done (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_DC_INT) { + cs43130->hpload_stat = stickies[3]; + dev_dbg(codec->dev, "HP DC load measurement done (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_ON_INT) { + cs43130->hpload_stat = stickies[3]; + dev_dbg(codec->dev, "HP load state machine on done (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[3] & CS43130_HPLOAD_OFF_INT) { + cs43130->hpload_stat = stickies[3]; + dev_dbg(codec->dev, "HP load state machine off done (%x)\n", + cs43130->hpload_stat); + complete(&cs43130->hpload_evt); + return IRQ_HANDLED; + } + + if (stickies[0] & CS43130_XTAL_ERR_INT) { + dev_err(codec->dev, "Crystal err: clock is not running\n"); + return IRQ_HANDLED; + } + + if (stickies[0] & CS43130_HP_UNPLUG_INT) { + dev_dbg(codec->dev, "HP unplugged\n"); + cs43130->hpload_done = false; + snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK); + return IRQ_HANDLED; + } + + if (stickies[0] & CS43130_HP_PLUG_INT) { + if (cs43130->dc_meas && !cs43130->hpload_done && + !work_busy(&cs43130->work)) { + dev_dbg(codec->dev, "HP load queue work\n"); + queue_work(cs43130->wq, &cs43130->work); + } + + snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL, + CS43130_JACK_MASK); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int cs43130_probe(struct snd_soc_codec *codec) +{ + int ret; + struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_card *card = codec->component.card; + unsigned int reg; + + cs43130->codec = codec; + + if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) { + regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET, + CS43130_XTAL_IBIAS_MASK, + cs43130->xtal_ibias); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_ERR_INT, 0); + } + + ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, + &cs43130->jack, NULL, 0); + if (ret < 0) { + dev_err(codec->dev, "Cannot create jack\n"); + return ret; + } + + cs43130->hpload_done = false; + if (cs43130->dc_meas) { + ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l); + if (ret < 0) + return ret; + + ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r); + if (ret < 0) + return ret; + + ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l); + if (ret < 0) + return ret; + + ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r); + if (ret < 0) + return ret; + + cs43130->wq = create_singlethread_workqueue("cs43130_hp"); + INIT_WORK(&cs43130->work, cs43130_imp_meas); + } + + regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, ®); + regmap_read(cs43130->regmap, CS43130_HP_STATUS, ®); + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0); + regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, + CS43130_HP_DETECT_CTRL_MASK, 0); + regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, + CS43130_HP_DETECT_CTRL_MASK, + CS43130_HP_DETECT_CTRL_MASK); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs43130 = { + .probe = cs43130_probe, + .component_driver = { + .controls = cs43130_snd_controls, + .num_controls = ARRAY_SIZE(cs43130_snd_controls), + }, + .set_sysclk = cs43130_codec_set_sysclk, + .set_pll = cs43130_set_pll, +}; + +static const struct regmap_config cs43130_regmap = { + .reg_bits = 24, + .pad_bits = 8, + .val_bits = 8, + + .max_register = CS43130_LASTREG, + .reg_defaults = cs43130_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs43130_reg_defaults), + .readable_reg = cs43130_readable_register, + .precious_reg = cs43130_precious_register, + .volatile_reg = cs43130_volatile_register, + .cache_type = REGCACHE_RBTREE, + .use_single_rw = true, /* needed for regcache_sync */ +}; + +static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { + 50, + 120, +}; + +static int cs43130_handle_device_data(struct i2c_client *i2c_client, + struct cs43130_private *cs43130) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + int i; + + if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) { + /* Crystal is unused. System clock is used for external MCLK */ + cs43130->xtal_ibias = CS43130_XTAL_UNUSED; + return 0; + } + + switch (val) { + case 1: + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA; + break; + case 2: + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA; + break; + case 3: + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA; + break; + default: + dev_err(&i2c_client->dev, + "Invalid cirrus,xtal-ibias value: %d\n", val); + return -EINVAL; + } + + cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure"); + cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure"); + + if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq, + CS43130_AC_FREQ) < 0) { + for (i = 0; i < CS43130_AC_FREQ; i++) + cs43130->ac_freq[i] = cs43130_ac_freq[i]; + } + + if (of_property_read_u16_array(np, "cirrus,dc-threshold", + cs43130->dc_threshold, + CS43130_DC_THRESHOLD) < 0) { + for (i = 0; i < CS43130_DC_THRESHOLD; i++) + cs43130->dc_threshold[i] = cs43130_dc_threshold[i]; + } + + return 0; +} + +static int cs43130_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs43130_private *cs43130; + int ret; + unsigned int devid = 0; + unsigned int reg; + int i; + + cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL); + if (!cs43130) + return -ENOMEM; + + i2c_set_clientdata(client, cs43130); + + cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap); + if (IS_ERR(cs43130->regmap)) { + ret = PTR_ERR(cs43130->regmap); + return ret; + } + + if (client->dev.of_node) { + ret = cs43130_handle_device_data(client, cs43130); + if (ret != 0) + return ret; + } + for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) + cs43130->supplies[i].supply = cs43130_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(cs43130->supplies), + cs43130->supplies); + if (ret != 0) { + dev_err(&client->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies), + cs43130->supplies); + if (ret != 0) { + dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs43130->reset_gpio)) + return PTR_ERR(cs43130->reset_gpio); + + gpiod_set_value_cansleep(cs43130->reset_gpio, 1); + + usleep_range(2000, 2050); + + ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, ®); + + devid = (reg & 0xFF) << 12; + ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + switch (devid) { + case CS43130_CHIP_ID: + case CS4399_CHIP_ID: + case CS43131_CHIP_ID: + case CS43198_CHIP_ID: + break; + default: + dev_err(&client->dev, + "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n", + devid, CS43130_CHIP_ID, CS4399_CHIP_ID, + CS43131_CHIP_ID, CS43198_CHIP_ID); + ret = -ENODEV; + goto err; + } + + cs43130->dev_id = devid; + ret = regmap_read(cs43130->regmap, CS43130_REV_ID, ®); + if (ret < 0) { + dev_err(&client->dev, "Get Revision ID failed\n"); + goto err; + } + + dev_info(&client->dev, + "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid, + reg & 0xFF); + + mutex_init(&cs43130->clk_mutex); + + init_completion(&cs43130->xtal_rdy); + init_completion(&cs43130->pll_rdy); + init_completion(&cs43130->hpload_evt); + + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, cs43130_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs43130", cs43130); + if (ret != 0) { + dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); + return ret; + } + + cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; + + pm_runtime_set_autosuspend_delay(&client->dev, 100); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + + switch (cs43130->dev_id) { + case CS43130_CHIP_ID: + case CS43131_CHIP_ID: + memcpy(all_hp_widgets, digital_hp_widgets, + sizeof(digital_hp_widgets)); + memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets), + analog_hp_widgets, sizeof(analog_hp_widgets)); + memcpy(all_hp_routes, digital_hp_routes, + sizeof(digital_hp_routes)); + memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes), + analog_hp_routes, sizeof(analog_hp_routes)); + + soc_codec_dev_cs43130.component_driver.dapm_widgets = + all_hp_widgets; + soc_codec_dev_cs43130.component_driver.num_dapm_widgets = + ARRAY_SIZE(all_hp_widgets); + soc_codec_dev_cs43130.component_driver.dapm_routes = + all_hp_routes; + soc_codec_dev_cs43130.component_driver.num_dapm_routes = + ARRAY_SIZE(all_hp_routes); + break; + case CS43198_CHIP_ID: + case CS4399_CHIP_ID: + soc_codec_dev_cs43130.component_driver.dapm_widgets = + digital_hp_widgets; + soc_codec_dev_cs43130.component_driver.num_dapm_widgets = + ARRAY_SIZE(digital_hp_widgets); + soc_codec_dev_cs43130.component_driver.dapm_routes = + digital_hp_routes; + soc_codec_dev_cs43130.component_driver.num_dapm_routes = + ARRAY_SIZE(digital_hp_routes); + } + + ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130, + cs43130_dai, ARRAY_SIZE(cs43130_dai)); + if (ret < 0) { + dev_err(&client->dev, + "snd_soc_register_codec failed with ret = %d\n", ret); + goto err; + } + + regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, + CS43130_ASP_3ST_MASK, 0); + regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, + CS43130_XSP_3ST_MASK, 0); + + return 0; +err: + return ret; +} + +static int cs43130_i2c_remove(struct i2c_client *client) +{ + struct cs43130_private *cs43130 = i2c_get_clientdata(client); + + if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_ERR_INT, + 1 << CS43130_XTAL_ERR_INT_SHIFT); + + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, + CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT); + + if (cs43130->dc_meas) { + cancel_work_sync(&cs43130->work); + flush_workqueue(cs43130->wq); + + device_remove_file(&client->dev, &dev_attr_hpload_dc_l); + device_remove_file(&client->dev, &dev_attr_hpload_dc_r); + device_remove_file(&client->dev, &dev_attr_hpload_ac_l); + device_remove_file(&client->dev, &dev_attr_hpload_ac_r); + } + + if (cs43130->reset_gpio) + gpiod_set_value_cansleep(cs43130->reset_gpio, 0); + + pm_runtime_disable(&client->dev); + regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); + + snd_soc_unregister_codec(&client->dev); + + return 0; +} + +static int cs43130_runtime_suspend(struct device *dev) +{ + struct cs43130_private *cs43130 = dev_get_drvdata(dev); + + if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_ERR_INT, + 1 << CS43130_XTAL_ERR_INT_SHIFT); + + regcache_cache_only(cs43130->regmap, true); + regcache_mark_dirty(cs43130->regmap); + + gpiod_set_value_cansleep(cs43130->reset_gpio, 0); + + regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); + + return 0; +} + +static int cs43130_runtime_resume(struct device *dev) +{ + struct cs43130_private *cs43130 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + regcache_cache_only(cs43130->regmap, false); + + gpiod_set_value_cansleep(cs43130->reset_gpio, 1); + + usleep_range(2000, 2050); + + ret = regcache_sync(cs43130->regmap); + if (ret != 0) { + dev_err(dev, "Failed to restore register cache\n"); + goto err; + } + + if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, + CS43130_XTAL_ERR_INT, 0); + + return 0; +err: + regcache_cache_only(cs43130->regmap, true); + regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); + + return ret; +} + +static const struct dev_pm_ops cs43130_runtime_pm = { + SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, + NULL) +}; + +static const struct of_device_id cs43130_of_match[] = { + {.compatible = "cirrus,cs43130",}, + {.compatible = "cirrus,cs4399",}, + {.compatible = "cirrus,cs43131",}, + {.compatible = "cirrus,cs43198",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, cs43130_of_match); + +static const struct i2c_device_id cs43130_i2c_id[] = { + {"cs43130", 0}, + {"cs4399", 0}, + {"cs43131", 0}, + {"cs43198", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id); + +static struct i2c_driver cs43130_i2c_driver = { + .driver = { + .name = "cs43130", + .of_match_table = cs43130_of_match, + .pm = &cs43130_runtime_pm, + }, + .id_table = cs43130_i2c_id, + .probe = cs43130_i2c_probe, + .remove = cs43130_i2c_remove, +}; + +module_i2c_driver(cs43130_i2c_driver); + +MODULE_AUTHOR("Li Xu "); +MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h new file mode 100644 index 000000000000..781258418d89 --- /dev/null +++ b/sound/soc/codecs/cs43130.h @@ -0,0 +1,546 @@ +/* + * ALSA SoC CS43130 codec driver + * + * Copyright 2017 Cirrus Logic, Inc. + * + * Author: Li Xu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef __CS43130_H__ +#define __CS43130_H__ + +/* CS43130 registers addresses */ +/* all reg address is shifted by a byte for control byte to be LSB */ +#define CS43130_FIRSTREG 0x010000 +#define CS43130_LASTREG 0x190000 +#define CS43130_CHIP_ID 0x00043130 +#define CS4399_CHIP_ID 0x00043990 +#define CS43131_CHIP_ID 0x00043131 +#define CS43198_CHIP_ID 0x00043198 +#define CS43130_DEVID_AB 0x010000 /* Device ID A & B [RO] */ +#define CS43130_DEVID_CD 0x010001 /* Device ID C & D [RO] */ +#define CS43130_DEVID_E 0x010002 /* Device ID E [RO] */ +#define CS43130_FAB_ID 0x010003 /* Fab ID [RO] */ +#define CS43130_REV_ID 0x010004 /* Revision ID [RO] */ +#define CS43130_SUBREV_ID 0x010005 /* Subrevision ID */ +#define CS43130_SYS_CLK_CTL_1 0x010006 /* System Clocking Ctl 1 */ +#define CS43130_SP_SRATE 0x01000B /* Serial Port Sample Rate */ +#define CS43130_SP_BITSIZE 0x01000C /* Serial Port Bit Size */ +#define CS43130_PAD_INT_CFG 0x01000D /* Pad Interface Config */ +#define CS43130_DXD1 0x010010 /* DXD1 */ +#define CS43130_DXD7 0x010025 /* DXD7 */ +#define CS43130_DXD19 0x010026 /* DXD19 */ +#define CS43130_DXD17 0x010027 /* DXD17 */ +#define CS43130_DXD18 0x010028 /* DXD18 */ +#define CS43130_DXD12 0x01002C /* DXD12 */ +#define CS43130_DXD8 0x01002E /* DXD8 */ +#define CS43130_PWDN_CTL 0x020000 /* Power Down Ctl */ +#define CS43130_DXD2 0x020019 /* DXD2 */ +#define CS43130_CRYSTAL_SET 0x020052 /* Crystal Setting */ +#define CS43130_PLL_SET_1 0x030001 /* PLL Setting 1 */ +#define CS43130_PLL_SET_2 0x030002 /* PLL Setting 2 */ +#define CS43130_PLL_SET_3 0x030003 /* PLL Setting 3 */ +#define CS43130_PLL_SET_4 0x030004 /* PLL Setting 4 */ +#define CS43130_PLL_SET_5 0x030005 /* PLL Setting 5 */ +#define CS43130_PLL_SET_6 0x030008 /* PLL Setting 6 */ +#define CS43130_PLL_SET_7 0x03000A /* PLL Setting 7 */ +#define CS43130_PLL_SET_8 0x03001B /* PLL Setting 8 */ +#define CS43130_PLL_SET_9 0x040002 /* PLL Setting 9 */ +#define CS43130_PLL_SET_10 0x040003 /* PLL Setting 10 */ +#define CS43130_CLKOUT_CTL 0x040004 /* CLKOUT Ctl */ +#define CS43130_ASP_NUM_1 0x040010 /* ASP Numerator 1 */ +#define CS43130_ASP_NUM_2 0x040011 /* ASP Numerator 2 */ +#define CS43130_ASP_DEN_1 0x040012 /* ASP Denominator 1 */ +#define CS43130_ASP_DEN_2 0x040013 /* ASP Denominator 2 */ +#define CS43130_ASP_LRCK_HI_TIME_1 0x040014 /* ASP LRCK High Time 1 */ +#define CS43130_ASP_LRCK_HI_TIME_2 0x040015 /* ASP LRCK High Time 2 */ +#define CS43130_ASP_LRCK_PERIOD_1 0x040016 /* ASP LRCK Period 1 */ +#define CS43130_ASP_LRCK_PERIOD_2 0x040017 /* ASP LRCK Period 2 */ +#define CS43130_ASP_CLOCK_CONF 0x040018 /* ASP Clock Config */ +#define CS43130_ASP_FRAME_CONF 0x040019 /* ASP Frame Config */ +#define CS43130_XSP_NUM_1 0x040020 /* XSP Numerator 1 */ +#define CS43130_XSP_NUM_2 0x040021 /* XSP Numerator 2 */ +#define CS43130_XSP_DEN_1 0x040022 /* XSP Denominator 1 */ +#define CS43130_XSP_DEN_2 0x040023 /* XSP Denominator 2 */ +#define CS43130_XSP_LRCK_HI_TIME_1 0x040024 /* XSP LRCK High Time 1 */ +#define CS43130_XSP_LRCK_HI_TIME_2 0x040025 /* XSP LRCK High Time 2 */ +#define CS43130_XSP_LRCK_PERIOD_1 0x040026 /* XSP LRCK Period 1 */ +#define CS43130_XSP_LRCK_PERIOD_2 0x040027 /* XSP LRCK Period 2 */ +#define CS43130_XSP_CLOCK_CONF 0x040028 /* XSP Clock Config */ +#define CS43130_XSP_FRAME_CONF 0x040029 /* XSP Frame Config */ +#define CS43130_ASP_CH_1_LOC 0x050000 /* ASP Chan 1 Location */ +#define CS43130_ASP_CH_2_LOC 0x050001 /* ASP Chan 2 Location */ +#define CS43130_ASP_CH_1_SZ_EN 0x05000A /* ASP Chan 1 Size, Enable */ +#define CS43130_ASP_CH_2_SZ_EN 0x05000B /* ASP Chan 2 Size, Enable */ +#define CS43130_XSP_CH_1_LOC 0x060000 /* XSP Chan 1 Location */ +#define CS43130_XSP_CH_2_LOC 0x060001 /* XSP Chan 2 Location */ +#define CS43130_XSP_CH_1_SZ_EN 0x06000A /* XSP Chan 1 Size, Enable */ +#define CS43130_XSP_CH_2_SZ_EN 0x06000B /* XSP Chan 2 Size, Enable */ +#define CS43130_DSD_VOL_B 0x070000 /* DSD Volume B */ +#define CS43130_DSD_VOL_A 0x070001 /* DSD Volume A */ +#define CS43130_DSD_PATH_CTL_1 0x070002 /* DSD Proc Path Sig Ctl 1 */ +#define CS43130_DSD_INT_CFG 0x070003 /* DSD Interface Config */ +#define CS43130_DSD_PATH_CTL_2 0x070004 /* DSD Proc Path Sig Ctl 2 */ +#define CS43130_DSD_PCM_MIX_CTL 0x070005 /* DSD and PCM Mixing Ctl */ +#define CS43130_DSD_PATH_CTL_3 0x070006 /* DSD Proc Path Sig Ctl 3 */ +#define CS43130_HP_OUT_CTL_1 0x080000 /* HP Output Ctl 1 */ +#define CS43130_DXD16 0x080024 /* DXD16 */ +#define CS43130_DXD13 0x080032 /* DXD13 */ +#define CS43130_PCM_FILT_OPT 0x090000 /* PCM Filter Option */ +#define CS43130_PCM_VOL_B 0x090001 /* PCM Volume B */ +#define CS43130_PCM_VOL_A 0x090002 /* PCM Volume A */ +#define CS43130_PCM_PATH_CTL_1 0x090003 /* PCM Path Signal Ctl 1 */ +#define CS43130_PCM_PATH_CTL_2 0x090004 /* PCM Path Signal Ctl 2 */ +#define CS43130_DXD6 0x090097 /* DXD6 */ +#define CS43130_CLASS_H_CTL 0x0B0000 /* Class H Ctl */ +#define CS43130_DXD15 0x0B0005 /* DXD15 */ +#define CS43130_DXD14 0x0B0006 /* DXD14 */ +#define CS43130_DXD3 0x0C0002 /* DXD3 */ +#define CS43130_DXD10 0x0C0003 /* DXD10 */ +#define CS43130_DXD11 0x0C0005 /* DXD11 */ +#define CS43130_DXD9 0x0C0006 /* DXD9 */ +#define CS43130_DXD4 0x0C0009 /* DXD4 */ +#define CS43130_DXD5 0x0C000E /* DXD5 */ +#define CS43130_HP_DETECT 0x0D0000 /* HP Detect */ +#define CS43130_HP_STATUS 0x0D0001 /* HP Status [RO] */ +#define CS43130_HP_LOAD_1 0x0E0000 /* HP Load 1 */ +#define CS43130_HP_MEAS_LOAD_1 0x0E0003 /* HP Load Measurement 1 */ +#define CS43130_HP_MEAS_LOAD_2 0x0E0004 /* HP Load Measurement 2 */ +#define CS43130_HP_DC_STAT_1 0x0E000D /* HP DC Load Status 0 [RO] */ +#define CS43130_HP_DC_STAT_2 0x0E000E /* HP DC Load Status 1 [RO] */ +#define CS43130_HP_AC_STAT_1 0x0E0010 /* HP AC Load Status 0 [RO] */ +#define CS43130_HP_AC_STAT_2 0x0E0011 /* HP AC Load Status 1 [RO] */ +#define CS43130_HP_LOAD_STAT 0x0E001A /* HP Load Status [RO] */ +#define CS43130_INT_STATUS_1 0x0F0000 /* Interrupt Status 1 */ +#define CS43130_INT_STATUS_2 0x0F0001 /* Interrupt Status 2 */ +#define CS43130_INT_STATUS_3 0x0F0002 /* Interrupt Status 3 */ +#define CS43130_INT_STATUS_4 0x0F0003 /* Interrupt Status 4 */ +#define CS43130_INT_STATUS_5 0x0F0004 /* Interrupt Status 5 */ +#define CS43130_INT_MASK_1 0x0F0010 /* Interrupt Mask 1 */ +#define CS43130_INT_MASK_2 0x0F0011 /* Interrupt Mask 2 */ +#define CS43130_INT_MASK_3 0x0F0012 /* Interrupt Mask 3 */ +#define CS43130_INT_MASK_4 0x0F0013 /* Interrupt Mask 4 */ +#define CS43130_INT_MASK_5 0x0F0014 /* Interrupt Mask 5 */ + +#define CS43130_MCLK_SRC_SEL_MASK 0x03 +#define CS43130_MCLK_SRC_SEL_SHIFT 0 +#define CS43130_MCLK_INT_MASK 0x04 +#define CS43130_MCLK_INT_SHIFT 2 +#define CS43130_CH_BITSIZE_MASK 0x03 +#define CS43130_CH_EN_MASK 0x04 +#define CS43130_CH_EN_SHIFT 2 +#define CS43130_ASP_BITSIZE_MASK 0x03 +#define CS43130_XSP_BITSIZE_MASK 0x0C +#define CS43130_XSP_BITSIZE_SHIFT 2 +#define CS43130_SP_BITSIZE_ASP_SHIFT 0 +#define CS43130_HP_DETECT_CTRL_SHIFT 6 +#define CS43130_HP_DETECT_CTRL_MASK (0x03 << CS43130_HP_DETECT_CTRL_SHIFT) +#define CS43130_HP_DETECT_INV_SHIFT 5 +#define CS43130_HP_DETECT_INV_MASK (1 << CS43130_HP_DETECT_INV_SHIFT) + +/* CS43130_INT_MASK_1 */ +#define CS43130_HP_PLUG_INT_SHIFT 6 +#define CS43130_HP_PLUG_INT (1 << CS43130_HP_PLUG_INT_SHIFT) +#define CS43130_HP_UNPLUG_INT_SHIFT 5 +#define CS43130_HP_UNPLUG_INT (1 << CS43130_HP_UNPLUG_INT_SHIFT) +#define CS43130_XTAL_RDY_INT_SHIFT 4 +#define CS43130_XTAL_RDY_INT_MASK 0x10 +#define CS43130_XTAL_RDY_INT (1 << CS43130_XTAL_RDY_INT_SHIFT) +#define CS43130_XTAL_ERR_INT_SHIFT 3 +#define CS43130_XTAL_ERR_INT (1 << CS43130_XTAL_ERR_INT_SHIFT) +#define CS43130_PLL_RDY_INT_MASK 0x04 +#define CS43130_PLL_RDY_INT_SHIFT 2 +#define CS43130_PLL_RDY_INT (1 << CS43130_PLL_RDY_INT_SHIFT) + +/* CS43130_INT_MASK_4 */ +#define CS43130_INT_MASK_ALL 0xFF +#define CS43130_HPLOAD_NO_DC_INT_SHIFT 7 +#define CS43130_HPLOAD_NO_DC_INT (1 << CS43130_HPLOAD_NO_DC_INT_SHIFT) +#define CS43130_HPLOAD_UNPLUG_INT_SHIFT 6 +#define CS43130_HPLOAD_UNPLUG_INT (1 << CS43130_HPLOAD_UNPLUG_INT_SHIFT) +#define CS43130_HPLOAD_OOR_INT_SHIFT 4 +#define CS43130_HPLOAD_OOR_INT (1 << CS43130_HPLOAD_OOR_INT_SHIFT) +#define CS43130_HPLOAD_AC_INT_SHIFT 3 +#define CS43130_HPLOAD_AC_INT (1 << CS43130_HPLOAD_AC_INT_SHIFT) +#define CS43130_HPLOAD_DC_INT_SHIFT 2 +#define CS43130_HPLOAD_DC_INT (1 << CS43130_HPLOAD_DC_INT_SHIFT) +#define CS43130_HPLOAD_OFF_INT_SHIFT 1 +#define CS43130_HPLOAD_OFF_INT (1 << CS43130_HPLOAD_OFF_INT_SHIFT) +#define CS43130_HPLOAD_ON_INT 1 + +/* CS43130_HP_LOAD_1 */ +#define CS43130_HPLOAD_EN_SHIFT 7 +#define CS43130_HPLOAD_EN (1 << CS43130_HPLOAD_EN_SHIFT) +#define CS43130_HPLOAD_CHN_SEL_SHIFT 4 +#define CS43130_HPLOAD_CHN_SEL (1 << CS43130_HPLOAD_CHN_SEL_SHIFT) +#define CS43130_HPLOAD_AC_START_SHIFT 1 +#define CS43130_HPLOAD_AC_START (1 << CS43130_HPLOAD_AC_START_SHIFT) +#define CS43130_HPLOAD_DC_START 1 + +/* Reg CS43130_SP_BITSIZE */ +#define CS43130_SP_BIT_SIZE_8 0x03 +#define CS43130_SP_BIT_SIZE_16 0x02 +#define CS43130_SP_BIT_SIZE_24 0x01 +#define CS43130_SP_BIT_SIZE_32 0x00 + +/* Reg CS43130_SP_CH_SZ_EN */ +#define CS43130_CH_BIT_SIZE_8 0x00 +#define CS43130_CH_BIT_SIZE_16 0x01 +#define CS43130_CH_BIT_SIZE_24 0x02 +#define CS43130_CH_BIT_SIZE_32 0x03 + +/* PLL */ +#define CS43130_PLL_START_MASK 0x01 +#define CS43130_PLL_MODE_MASK 0x02 +#define CS43130_PLL_MODE_SHIFT 1 + +#define CS43130_PLL_REF_PREDIV_MASK 0x3 + +#define CS43130_SP_STP_MASK 0x10 +#define CS43130_SP_STP_SHIFT 4 +#define CS43130_SP_5050_MASK 0x08 +#define CS43130_SP_5050_SHIFT 3 +#define CS43130_SP_FSD_MASK 0x07 + +#define CS43130_SP_MODE_MASK 0x10 +#define CS43130_SP_MODE_SHIFT 4 +#define CS43130_SP_SCPOL_OUT_MASK 0x08 +#define CS43130_SP_SCPOL_OUT_SHIFT 3 +#define CS43130_SP_SCPOL_IN_MASK 0x04 +#define CS43130_SP_SCPOL_IN_SHIFT 2 +#define CS43130_SP_LCPOL_OUT_MASK 0x02 +#define CS43130_SP_LCPOL_OUT_SHIFT 1 +#define CS43130_SP_LCPOL_IN_MASK 0x01 +#define CS43130_SP_LCPOL_IN_SHIFT 0 + +/* Reg CS43130_PWDN_CTL */ +#define CS43130_PDN_XSP_MASK 0x80 +#define CS43130_PDN_XSP_SHIFT 7 +#define CS43130_PDN_ASP_MASK 0x40 +#define CS43130_PDN_ASP_SHIFT 6 +#define CS43130_PDN_DSPIF_MASK 0x20 +#define CS43130_PDN_DSDIF_SHIFT 5 +#define CS43130_PDN_HP_MASK 0x10 +#define CS43130_PDN_HP_SHIFT 4 +#define CS43130_PDN_XTAL_MASK 0x08 +#define CS43130_PDN_XTAL_SHIFT 3 +#define CS43130_PDN_PLL_MASK 0x04 +#define CS43130_PDN_PLL_SHIFT 2 +#define CS43130_PDN_CLKOUT_MASK 0x02 +#define CS43130_PDN_CLKOUT_SHIFT 1 + +/* Reg CS43130_HP_OUT_CTL_1 */ +#define CS43130_HP_IN_EN_SHIFT 3 +#define CS43130_HP_IN_EN_MASK 0x08 + +/* Reg CS43130_PAD_INT_CFG */ +#define CS43130_ASP_3ST_MASK 0x01 +#define CS43130_XSP_3ST_MASK 0x02 + +/* Reg CS43130_PLL_SET_2 */ +#define CS43130_PLL_DIV_DATA_MASK 0x000000FF +#define CS43130_PLL_DIV_FRAC_0_DATA_SHIFT 0 + +/* Reg CS43130_PLL_SET_3 */ +#define CS43130_PLL_DIV_FRAC_1_DATA_SHIFT 8 + +/* Reg CS43130_PLL_SET_4 */ +#define CS43130_PLL_DIV_FRAC_2_DATA_SHIFT 16 + +/* Reg CS43130_SP_DEN_1 */ +#define CS43130_SP_M_LSB_DATA_MASK 0x00FF +#define CS43130_SP_M_LSB_DATA_SHIFT 0 + +/* Reg CS43130_SP_DEN_2 */ +#define CS43130_SP_M_MSB_DATA_MASK 0xFF00 +#define CS43130_SP_M_MSB_DATA_SHIFT 8 + +/* Reg CS43130_SP_NUM_1 */ +#define CS43130_SP_N_LSB_DATA_MASK 0x00FF +#define CS43130_SP_N_LSB_DATA_SHIFT 0 + +/* Reg CS43130_SP_NUM_2 */ +#define CS43130_SP_N_MSB_DATA_MASK 0xFF00 +#define CS43130_SP_N_MSB_DATA_SHIFT 8 + +/* Reg CS43130_SP_LRCK_HI_TIME_1 */ +#define CS43130_SP_LCHI_DATA_MASK 0x00FF +#define CS43130_SP_LCHI_LSB_DATA_SHIFT 0 + +/* Reg CS43130_SP_LRCK_HI_TIME_2 */ +#define CS43130_SP_LCHI_MSB_DATA_SHIFT 8 + +/* Reg CS43130_SP_LRCK_PERIOD_1 */ +#define CS43130_SP_LCPR_DATA_MASK 0x00FF +#define CS43130_SP_LCPR_LSB_DATA_SHIFT 0 + +/* Reg CS43130_SP_LRCK_PERIOD_2 */ +#define CS43130_SP_LCPR_MSB_DATA_SHIFT 8 + +#define CS43130_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define CS43130_DOP_FORMATS (SNDRV_PCM_FMTBIT_DSD_U16_LE | \ + SNDRV_PCM_FMTBIT_DSD_U16_BE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* Reg CS43130_CRYSTAL_SET */ +#define CS43130_XTAL_IBIAS_MASK 0x07 + +/* Reg CS43130_PATH_CTL_1 */ +#define CS43130_MUTE_MASK 0x03 +#define CS43130_MUTE_EN 0x03 + +/* Reg CS43130_DSD_INT_CFG */ +#define CS43130_DSD_MASTER 0x04 + +/* Reg CS43130_DSD_PATH_CTL_2 */ +#define CS43130_DSD_SRC_MASK 0x60 +#define CS43130_DSD_SRC_SHIFT 5 +#define CS43130_DSD_EN_SHIFT 4 +#define CS43130_DSD_SPEED_MASK 0x04 +#define CS43130_DSD_SPEED_SHIFT 2 + +/* Reg CS43130_DSD_PCM_MIX_CTL */ +#define CS43130_MIX_PCM_PREP_SHIFT 1 +#define CS43130_MIX_PCM_PREP_MASK 0x02 + +#define CS43130_MIX_PCM_DSD_SHIFT 0 +#define CS43130_MIX_PCM_DSD_MASK 0x01 + +/* Reg CS43130_HP_MEAS_LOAD */ +#define CS43130_HP_MEAS_LOAD_MASK 0x000000FF +#define CS43130_HP_MEAS_LOAD_1_SHIFT 0 +#define CS43130_HP_MEAS_LOAD_2_SHIFT 8 + +#define CS43130_MCLK_22M 22579200 +#define CS43130_MCLK_24M 24576000 + +#define CS43130_LINEOUT_LOAD 5000 +#define CS43130_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT) +#define CS43130_JACK_HEADPHONE (SND_JACK_MECHANICAL | \ + SND_JACK_HEADPHONE) +#define CS43130_JACK_MASK (SND_JACK_MECHANICAL | \ + SND_JACK_LINEOUT | \ + SND_JACK_HEADPHONE) + +enum cs43130_dsd_src { + CS43130_DSD_SRC_DSD = 0, + CS43130_DSD_SRC_ASP = 2, + CS43130_DSD_SRC_XSP = 3, +}; + +enum cs43130_asp_rate { + CS43130_ASP_SPRATE_32K = 0, + CS43130_ASP_SPRATE_44_1K, + CS43130_ASP_SPRATE_48K, + CS43130_ASP_SPRATE_88_2K, + CS43130_ASP_SPRATE_96K, + CS43130_ASP_SPRATE_176_4K, + CS43130_ASP_SPRATE_192K, + CS43130_ASP_SPRATE_352_8K, + CS43130_ASP_SPRATE_384K, +}; + +enum cs43130_mclk_src_sel { + CS43130_MCLK_SRC_EXT = 0, + CS43130_MCLK_SRC_PLL, + CS43130_MCLK_SRC_RCO +}; + +enum cs43130_mclk_int_freq { + CS43130_MCLK_24P5 = 0, + CS43130_MCLK_22P5, +}; + +enum cs43130_xtal_ibias { + CS43130_XTAL_UNUSED = -1, + CS43130_XTAL_IBIAS_15UA = 2, + CS43130_XTAL_IBIAS_12_5UA = 4, + CS43130_XTAL_IBIAS_7_5UA = 6, +}; + +enum cs43130_dai_id { + CS43130_ASP_PCM_DAI = 0, + CS43130_ASP_DOP_DAI, + CS43130_XSP_DOP_DAI, + CS43130_XSP_DSD_DAI, + CS43130_DAI_ID_MAX, +}; + +struct cs43130_clk_gen { + unsigned int mclk_int; + int fs; + u16 den; + u16 num; +}; + +/* frm_size = 16 */ +static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { + {22579200, 32000, 441, 10,}, + {22579200, 44100, 32, 1,}, + {22579200, 48000, 147, 5,}, + {22579200, 88200, 16, 1,}, + {22579200, 96000, 147, 10,}, + {22579200, 176400, 8, 1,}, + {22579200, 192000, 147, 20,}, + {22579200, 352800, 4, 1,}, + {22579200, 384000, 147, 40,}, + {24576000, 32000, 48, 1,}, + {24576000, 44100, 5120, 147,}, + {24576000, 48000, 32, 1,}, + {24576000, 88200, 2560, 147,}, + {24576000, 96000, 16, 1,}, + {24576000, 176400, 1280, 147,}, + {24576000, 192000, 8, 1,}, + {24576000, 352800, 640, 147,}, + {24576000, 384000, 4, 1,}, +}; + +/* frm_size = 32 */ +static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { + {22579200, 32000, 441, 20,}, + {22579200, 44100, 16, 1,}, + {22579200, 48000, 147, 10,}, + {22579200, 88200, 8, 1,}, + {22579200, 96000, 147, 20,}, + {22579200, 176400, 4, 1,}, + {22579200, 192000, 147, 40,}, + {22579200, 352800, 2, 1,}, + {22579200, 384000, 147, 80,}, + {24576000, 32000, 24, 1,}, + {24576000, 44100, 2560, 147,}, + {24576000, 48000, 16, 1,}, + {24576000, 88200, 1280, 147,}, + {24576000, 96000, 8, 1,}, + {24576000, 176400, 640, 147,}, + {24576000, 192000, 4, 1,}, + {24576000, 352800, 320, 147,}, + {24576000, 384000, 2, 1,}, +}; + +/* frm_size = 48 */ +static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { + {22579200, 32000, 147, 100,}, + {22579200, 44100, 32, 3,}, + {22579200, 48000, 49, 5,}, + {22579200, 88200, 16, 3,}, + {22579200, 96000, 49, 10,}, + {22579200, 176400, 8, 3,}, + {22579200, 192000, 49, 20,}, + {22579200, 352800, 4, 3,}, + {22579200, 384000, 49, 40,}, + {24576000, 32000, 16, 1,}, + {24576000, 44100, 5120, 441,}, + {24576000, 48000, 32, 3,}, + {24576000, 88200, 2560, 441,}, + {24576000, 96000, 16, 3,}, + {24576000, 176400, 1280, 441,}, + {24576000, 192000, 8, 3,}, + {24576000, 352800, 640, 441,}, + {24576000, 384000, 4, 3,}, +}; + +/* frm_size = 64 */ +static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { + {22579200, 32000, 441, 40,}, + {22579200, 44100, 8, 1,}, + {22579200, 48000, 147, 20,}, + {22579200, 88200, 4, 1,}, + {22579200, 96000, 147, 40,}, + {22579200, 176400, 2, 1,}, + {22579200, 192000, 147, 80,}, + {22579200, 352800, 1, 1,}, + {24576000, 32000, 12, 1,}, + {24576000, 44100, 1280, 147,}, + {24576000, 48000, 8, 1,}, + {24576000, 88200, 640, 147,}, + {24576000, 96000, 4, 1,}, + {24576000, 176400, 320, 147,}, + {24576000, 192000, 2, 1,}, + {24576000, 352800, 160, 147,}, + {24576000, 384000, 1, 1,}, +}; + +struct cs43130_bitwidth_map { + unsigned int bitwidth; + u8 sp_bit; + u8 ch_bit; +}; + +struct cs43130_rate_map { + int fs; + int val; +}; + +#define HP_LEFT 0 +#define HP_RIGHT 1 +#define CS43130_AC_FREQ 10 +#define CS43130_DC_THRESHOLD 2 + +#define CS43130_NUM_SUPPLIES 5 +static const char *const cs43130_supply_names[CS43130_NUM_SUPPLIES] = { + "VA", + "VP", + "VCP", + "VD", + "VL", +}; + +#define CS43130_NUM_INT 5 /* number of interrupt status reg */ + +struct cs43130_dai { + unsigned int sclk; + unsigned int dai_format; + unsigned int dai_mode; +}; + +struct cs43130_private { + struct snd_soc_codec *codec; + struct regmap *regmap; + struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES]; + struct gpio_desc *reset_gpio; + unsigned int dev_id; /* codec device ID */ + int xtal_ibias; + + /* shared by both DAIs */ + struct mutex clk_mutex; + int clk_req; + bool pll_bypass; + struct completion xtal_rdy; + struct completion pll_rdy; + unsigned int mclk; + unsigned int mclk_int; + int mclk_int_src; + + /* DAI specific */ + struct cs43130_dai dais[CS43130_DAI_ID_MAX]; + + /* HP load specific */ + bool dc_meas; + bool ac_meas; + bool hpload_done; + struct completion hpload_evt; + unsigned int hpload_stat; + u16 hpload_dc[2]; + u16 dc_threshold[CS43130_DC_THRESHOLD]; + u16 ac_freq[CS43130_AC_FREQ]; + u16 hpload_ac[CS43130_AC_FREQ][2]; + struct workqueue_struct *wq; + struct work_struct work; + struct snd_soc_jack jack; +}; + +#endif /* __CS43130_H__ */ -- cgit v1.2.3 From a3dcadd220b4572f9baaad5f3c0c00044273c961 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Sep 2017 04:33:01 +0000 Subject: ASoC: add missing compile rule for max98371 It is still using old driver style, this patch also fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 1 + sound/soc/codecs/max98371.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..b4d576dab48a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -320,6 +320,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index 781be9ba8dba..7bc2a17c1e94 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = { }; static const struct snd_soc_codec_driver max98371_codec = { - .controls = max98371_snd_controls, - .num_controls = ARRAY_SIZE(max98371_snd_controls), - .dapm_routes = max98371_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), - .dapm_widgets = max98371_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), + .component_driver = { + .controls = max98371_snd_controls, + .num_controls = ARRAY_SIZE(max98371_snd_controls), + .dapm_routes = max98371_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), + .dapm_widgets = max98371_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), + }, }; static const struct regmap_config max98371_regmap = { -- cgit v1.2.3 From 2dc3b7b06bace6d8986a5fae6569ef30276cdd73 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Sep 2017 04:33:27 +0000 Subject: ASoC: add missing compile rule for sirf-audio-codec It is still using old driver style, this patch also fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 1 + sound/soc/codecs/sirf-audio-codec.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b4d576dab48a..8ed3c9256a74 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -373,6 +373,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o +obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 6bfd25c289d1..01d7690a1520 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -432,10 +432,12 @@ static int sirf_audio_codec_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { .probe = sirf_audio_codec_probe, .remove = sirf_audio_codec_remove, - .dapm_widgets = sirf_audio_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets), - .dapm_routes = sirf_audio_codec_map, - .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map), + .component_driver = { + .dapm_widgets = sirf_audio_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets), + .dapm_routes = sirf_audio_codec_map, + .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map), + }, .idle_bias_off = true, }; -- cgit v1.2.3 From b21f0522ee376ddbea54fab47ff36f687f2a438b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Sep 2017 04:33:01 +0000 Subject: ASoC: add missing compile rule for max98371 It is still using old driver style, this patch also fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 1 + sound/soc/codecs/max98371.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..b4d576dab48a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -320,6 +320,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index 781be9ba8dba..7bc2a17c1e94 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = { }; static const struct snd_soc_codec_driver max98371_codec = { - .controls = max98371_snd_controls, - .num_controls = ARRAY_SIZE(max98371_snd_controls), - .dapm_routes = max98371_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), - .dapm_widgets = max98371_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), + .component_driver = { + .controls = max98371_snd_controls, + .num_controls = ARRAY_SIZE(max98371_snd_controls), + .dapm_routes = max98371_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), + .dapm_widgets = max98371_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), + }, }; static const struct regmap_config max98371_regmap = { -- cgit v1.2.3