diff options
Diffstat (limited to 'sound/soc/codecs')
75 files changed, 2984 insertions, 762 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index a2bf27f4baa..a0f265327fd 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -386,7 +386,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol, static int pm860x_rsync_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); /* * In order to avoid current on the load, mute power-on and power-off @@ -403,7 +403,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w, static int pm860x_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int dac = 0; int data; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8349f982a58..064e6c18e10 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C + select SND_SOC_MAX98357A select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -456,6 +457,9 @@ config SND_SOC_MAX98090 config SND_SOC_MAX98095 tristate +config SND_SOC_MAX98357A + tristate + config SND_SOC_MAX9850 tristate @@ -525,7 +529,7 @@ config SND_SOC_RT5677 config SND_SOC_RT5677_SPI tristate - default SND_SOC_RT5677 + default SND_SOC_RT5677 && SPI #Freescale sgtl5000 codec config SND_SOC_SGTL5000 @@ -580,7 +584,9 @@ config SND_SOC_SSM4567 depends on I2C config SND_SOC_STA32X - tristate + tristate "STA326, STA328 and STA329 speaker amplifier" + depends on I2C + select REGMAP_I2C config SND_SOC_STA350 tristate "STA350 speaker amplifier" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bbdfd1e1c18..69b8666d187 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -64,6 +64,7 @@ snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o +snd-soc-max98357a-objs := max98357a.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o 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_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 387530b0b0f..17c95359566 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -333,8 +333,8 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec) regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); /* de-emphasis: 48kHz, powedown dac */ regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); - /* powerdown dac, dac in tdm mode */ - regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41); + /* dac in tdm mode */ + regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40); /* high-pass filter enable */ regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); /* sata delay=1, adc aux mode */ diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 686cacb0e83..632e89f793a 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -163,7 +163,7 @@ static const struct snd_kcontrol_new ak4671_snd_controls[] = { static int ak4671_out2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index bdf8c5ac8ca..0e357996864 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -55,18 +55,20 @@ static inline int alc5623_reset(struct snd_soc_codec *codec) static int amp_mixer_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); + /* to power-on/off class-d amp generators/speaker */ /* need to write to 'index-46h' register : */ /* so write index num (here 0x46) to reg 0x6a */ /* and then 0xffff/0 to reg 0x6c */ - snd_soc_write(w->codec, ALC5623_HID_CTRL_INDEX, 0x46); + snd_soc_write(codec, ALC5623_HID_CTRL_INDEX, 0x46); switch (event) { case SND_SOC_DAPM_PRE_PMU: - snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0xFFFF); + snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0xFFFF); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0); + snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0); break; } diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index d1fdbc26663..db3283abbe1 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -116,18 +116,20 @@ static inline int alc5632_reset(struct regmap *map) static int amp_mixer_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); + /* to power-on/off class-d amp generators/speaker */ /* need to write to 'index-46h' register : */ /* so write index num (here 0x46) to reg 0x6a */ /* and then 0xffff/0 to reg 0x6c */ - snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46); + snd_soc_write(codec, ALC5632_HID_CTRL_INDEX, 0x46); switch (event) { case SND_SOC_DAPM_PRE_PMU: - snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF); + snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0xFFFF); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0); + snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0); break; } @@ -1066,7 +1068,7 @@ static int alc5632_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_device_alc5632 = { +static const struct snd_soc_codec_driver soc_codec_device_alc5632 = { .probe = alc5632_probe, .resume = alc5632_resume, .set_bias_level = alc5632_set_bias_level, @@ -1080,7 +1082,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5632 = { .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes), }; -static struct regmap_config alc5632_regmap = { +static const struct regmap_config alc5632_regmap = { .reg_bits = 8, .val_bits = 16, diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 9550d7433ad..29202610dd0 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -84,7 +84,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); bool manual_ena = false; @@ -692,7 +692,8 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); unsigned int reg; if (w->shift % 2) @@ -705,25 +706,25 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, priv->in_pending++; break; case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); + snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0); /* If this is the last input pending then allow VU */ priv->in_pending--; if (priv->in_pending == 0) { msleep(1); - arizona_in_set_vu(w->codec, 1); + arizona_in_set_vu(codec, 1); } break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, reg, + snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE | ARIZONA_IN_VU, ARIZONA_IN1L_MUTE | ARIZONA_IN_VU); break; case SND_SOC_DAPM_POST_PMD: /* Disable volume updates if no inputs are enabled */ - reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES); + reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES); if (reg == 0) - arizona_in_set_vu(w->codec, 0); + arizona_in_set_vu(codec, 0); } return 0; @@ -734,7 +735,25 @@ int arizona_out_ev(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 arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + priv->out_up_pending++; + priv->out_up_delay += 17; + break; + default: + break; + } + break; case SND_SOC_DAPM_POST_PMU: switch (w->shift) { case ARIZONA_OUT1L_ENA_SHIFT: @@ -743,13 +762,50 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, case ARIZONA_OUT2R_ENA_SHIFT: case ARIZONA_OUT3L_ENA_SHIFT: case ARIZONA_OUT3R_ENA_SHIFT: - msleep(17); + priv->out_up_pending--; + if (!priv->out_up_pending) { + msleep(priv->out_up_delay); + priv->out_up_delay = 0; + } break; default: break; } break; + case SND_SOC_DAPM_PRE_PMD: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + priv->out_down_pending++; + priv->out_down_delay++; + break; + default: + break; + } + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + priv->out_down_pending--; + if (!priv->out_down_pending) { + msleep(priv->out_down_delay); + priv->out_down_delay = 0; + } + break; + default: + break; + } + break; } return 0; @@ -760,7 +816,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; unsigned int mask = 1 << w->shift; unsigned int val; @@ -772,6 +829,9 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMD: val = 0; break; + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_out_ev(w, kcontrol, event); default: return -EINVAL; } diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 942cfb197b6..11ff899b027 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -77,6 +77,11 @@ struct arizona_priv { int num_inputs; unsigned int in_pending; + unsigned int out_up_pending; + unsigned int out_up_delay; + unsigned int out_down_pending; + unsigned int out_down_delay; + unsigned int spk_ena:2; unsigned int spk_ena_pending:1; }; diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index 5075bf0a727..e7238b8904b 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -86,5 +86,5 @@ static struct platform_driver bt_sco_driver = { module_platform_driver(bt_sco_driver); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver"); +MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index ec55c590afd..f2b8aad2127 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -264,7 +264,7 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); } -static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { .set_sysclk = cs35l32_codec_set_sysclk, .dapm_widgets = cs35l32_dapm_widgets, @@ -288,7 +288,7 @@ static const struct reg_default cs35l32_monitor_patch[] = { { 0x00, 0x00 }, }; -static struct regmap_config cs35l32_regmap = { +static const struct regmap_config cs35l32_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 35fbef743fb..1589e7a881d 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1103,7 +1103,7 @@ static int cs42l52_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { .probe = cs42l52_probe, .remove = cs42l52_remove, .set_bias_level = cs42l52_set_bias_level, @@ -1130,7 +1130,7 @@ static const struct reg_default cs42l52_threshold_patch[] = { }; -static struct regmap_config cs42l52_regmap = { +static const struct regmap_config cs42l52_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 2ddc7ac10ad..cbc654fe48c 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1164,7 +1164,7 @@ static int cs42l56_remove(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .probe = cs42l56_probe, .remove = cs42l56_remove, .set_bias_level = cs42l56_set_bias_level, @@ -1179,7 +1179,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .num_controls = ARRAY_SIZE(cs42l56_snd_controls), }; -static struct regmap_config cs42l56_regmap = { +static const struct regmap_config cs42l56_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 7c55537c69c..8ecedba7960 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1347,7 +1347,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { +static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .probe = cs42l73_probe, .set_bias_level = cs42l73_set_bias_level, .suspend_bias_off = true, @@ -1361,7 +1361,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .num_controls = ARRAY_SIZE(cs42l73_snd_controls), }; -static struct regmap_config cs42l73_regmap = { +static const struct regmap_config cs42l73_regmap = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 61b2f9a2eef..ffe96175a8a 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -609,7 +609,7 @@ static const struct snd_kcontrol_new da732x_snd_controls[] = { static int da732x_adc_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -663,7 +663,7 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w, static int da732x_out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c new file mode 100644 index 00000000000..1806333ea29 --- /dev/null +++ b/sound/soc/codecs/max98357a.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + * + * max98357a.c -- MAX98357A ALSA SoC Codec driver + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <sound/soc.h> + +#define DRV_NAME "max98357a" + +static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(sdmode, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(sdmode, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { + SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("Speaker"), +}; + +static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { + {"Speaker", NULL, "SDMode"}, +}; + +static int max98357a_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *sdmode; + + sdmode = devm_gpiod_get(codec->dev, "sdmode"); + if (IS_ERR(sdmode)) { + dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", + __func__, PTR_ERR(sdmode)); + return PTR_ERR(sdmode); + } + gpiod_direction_output(sdmode, 0); + snd_soc_codec_set_drvdata(codec, sdmode); + + return 0; +} + +static struct snd_soc_codec_driver max98357a_codec_driver = { + .probe = max98357a_codec_probe, + .dapm_widgets = max98357a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), + .dapm_routes = max98357a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), +}; + +static struct snd_soc_dai_ops max98357a_dai_ops = { + .trigger = max98357a_daiops_trigger, +}; + +static struct snd_soc_dai_driver max98357a_dai_driver = { + .name = DRV_NAME, + .playback = { + .stream_name = DRV_NAME "-playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &max98357a_dai_ops, +}; + +static int max98357a_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, + &max98357a_dai_driver, 1); + if (ret) + dev_err(&pdev->dev, "%s() error registering codec driver: %d\n", + __func__, ret); + + return ret; +} + +static int max98357a_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id max98357a_device_id[] = { + { .compatible = "maxim," DRV_NAME, }, + {} +}; +MODULE_DEVICE_TABLE(of, max98357a_device_id); +#endif + +static struct platform_driver max98357a_platform_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(max98357a_device_id), + }, + .probe = max98357a_platform_probe, + .remove = max98357a_platform_remove, +}; +module_platform_driver(max98357a_platform_driver); + +MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index c1e441c2c8a..2ffb9a0570d 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -328,16 +328,16 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai, } switch (rx_mask) { - case 0xfffffffc: + case 0x03: val |= SSI_NETWORK_DAC_RXSLOT_0_1; break; - case 0xfffffff3: + case 0x0c: val |= SSI_NETWORK_DAC_RXSLOT_2_3; break; - case 0xffffffcf: + case 0x30: val |= SSI_NETWORK_DAC_RXSLOT_4_5; break; - case 0xffffff3f: + case 0xc0: val |= SSI_NETWORK_DAC_RXSLOT_6_7; break; default: @@ -360,7 +360,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai, if (slots != 4) return -EINVAL; - if (tx_mask != 0xfffffffc) + if (tx_mask != 0x3) return -EINVAL; val |= (0x00 << 2); /* primary timeslot RX/TX(?) is 0 */ diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 7e73fa4b318..8fb445f33f6 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -32,7 +32,7 @@ static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct pcm3008_setup_data *setup = codec->dev->platform_data; gpio_set_value_cansleep(setup->pdda_pin, @@ -45,7 +45,7 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct pcm3008_setup_data *setup = codec->dev->platform_data; gpio_set_value_cansleep(setup->pdad_pin, diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index d0547fa275f..dcdfac0ffeb 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -46,6 +46,8 @@ static int pcm512x_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id pcm512x_i2c_id[] = { { "pcm5121", }, { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, { } }; MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); @@ -53,6 +55,8 @@ MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5121", }, { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, { } }; MODULE_DEVICE_TABLE(of, pcm512x_of_match); diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index f297058c003..7b64a9cef70 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -43,6 +43,8 @@ static int pcm512x_spi_remove(struct spi_device *spi) static const struct spi_device_id pcm512x_spi_id[] = { { "pcm5121", }, { "pcm5122", }, + { "pcm5141", }, + { "pcm5142", }, { }, }; MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); @@ -50,6 +52,8 @@ MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); static const struct of_device_id pcm512x_of_match[] = { { .compatible = "ti,pcm5121", }, { .compatible = "ti,pcm5122", }, + { .compatible = "ti,pcm5141", }, + { .compatible = "ti,pcm5142", }, { } }; MODULE_DEVICE_TABLE(of, pcm512x_of_match); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index e5f2fb884bf..9974f201a08 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -21,12 +21,19 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/gcd.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <sound/pcm_params.h> #include <sound/tlv.h> #include "pcm512x.h" +#define DIV_ROUND_DOWN_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) +#define DIV_ROUND_CLOSEST_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) + #define PCM512x_NUM_SUPPLIES 3 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { "AVDD", @@ -39,6 +46,14 @@ struct pcm512x_priv { struct clk *sclk; struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; + int fmt; + int pll_in; + int pll_out; + int pll_r; + int pll_j; + int pll_d; + int pll_p; + unsigned long real_pll; }; /* @@ -69,6 +84,7 @@ static const struct reg_default pcm512x_reg_defaults[] = { { PCM512x_MUTE, 0x00 }, { PCM512x_DSP, 0x00 }, { PCM512x_PLL_REF, 0x00 }, + { PCM512x_DAC_REF, 0x00 }, { PCM512x_DAC_ROUTING, 0x11 }, { PCM512x_DSP_PROGRAM, 0x01 }, { PCM512x_CLKDET, 0x00 }, @@ -87,6 +103,25 @@ static const struct reg_default pcm512x_reg_defaults[] = { { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, { PCM512x_VCOM_CTRL_1, 0x00 }, { PCM512x_VCOM_CTRL_2, 0x01 }, + { PCM512x_BCLK_LRCLK_CFG, 0x00 }, + { PCM512x_MASTER_MODE, 0x7c }, + { PCM512x_GPIO_DACIN, 0x00 }, + { PCM512x_GPIO_PLLIN, 0x00 }, + { PCM512x_SYNCHRONIZE, 0x10 }, + { PCM512x_PLL_COEFF_0, 0x00 }, + { PCM512x_PLL_COEFF_1, 0x00 }, + { PCM512x_PLL_COEFF_2, 0x00 }, + { PCM512x_PLL_COEFF_3, 0x00 }, + { PCM512x_PLL_COEFF_4, 0x00 }, + { PCM512x_DSP_CLKDIV, 0x00 }, + { PCM512x_DAC_CLKDIV, 0x00 }, + { PCM512x_NCP_CLKDIV, 0x00 }, + { PCM512x_OSR_CLKDIV, 0x00 }, + { PCM512x_MASTER_CLKDIV_1, 0x00 }, + { PCM512x_MASTER_CLKDIV_2, 0x00 }, + { PCM512x_FS_SPEED_MODE, 0x00 }, + { PCM512x_IDAC_1, 0x01 }, + { PCM512x_IDAC_2, 0x00 }, }; static bool pcm512x_readable(struct device *dev, unsigned int reg) @@ -103,6 +138,10 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) case PCM512x_DSP_GPIO_INPUT: case PCM512x_MASTER_MODE: case PCM512x_PLL_REF: + case PCM512x_DAC_REF: + case PCM512x_GPIO_DACIN: + case PCM512x_GPIO_PLLIN: + case PCM512x_SYNCHRONIZE: case PCM512x_PLL_COEFF_0: case PCM512x_PLL_COEFF_1: case PCM512x_PLL_COEFF_2: @@ -143,6 +182,7 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) case PCM512x_RATE_DET_2: case PCM512x_RATE_DET_3: case PCM512x_RATE_DET_4: + case PCM512x_CLOCK_STATUS: case PCM512x_ANALOG_MUTE_DET: case PCM512x_GPIN: case PCM512x_DIGITAL_MUTE_DET: @@ -154,6 +194,8 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) case PCM512x_VCOM_CTRL_1: case PCM512x_VCOM_CTRL_2: case PCM512x_CRAM_CTRL: + case PCM512x_FLEX_A: + case PCM512x_FLEX_B: return true; default: /* There are 256 raw register addresses */ @@ -170,6 +212,7 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) case PCM512x_RATE_DET_2: case PCM512x_RATE_DET_3: case PCM512x_RATE_DET_4: + case PCM512x_CLOCK_STATUS: case PCM512x_ANALOG_MUTE_DET: case PCM512x_GPIN: case PCM512x_DIGITAL_MUTE_DET: @@ -188,8 +231,8 @@ static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); static const char * const pcm512x_dsp_program_texts[] = { "FIR interpolation with de-emphasis", "Low latency IIR with de-emphasis", - "Fixed process flow", "High attenuation with de-emphasis", + "Fixed process flow", "Ringing-less low latency FIR", }; @@ -277,7 +320,7 @@ SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_ACTL_SHIFT, 1, 0), SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, - PCM512x_AMLR_SHIFT, 1, 0), + PCM512x_AMRE_SHIFT, 1, 0), SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), @@ -303,6 +346,136 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { { "OUTR", NULL, "DACR" }, }; +static const u32 pcm512x_dai_rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000, 384000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_slave = { + .count = ARRAY_SIZE(pcm512x_dai_rates), + .list = pcm512x_dai_rates, +}; + +static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval ranges[2]; + int frame_size; + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) + return frame_size; + + switch (frame_size) { + case 32: + /* No hole when the frame size is 32. */ + return 0; + case 48: + case 64: + /* There is only one hole in the range of supported + * rates, but it moves with the frame size. + */ + memset(ranges, 0, sizeof(ranges)); + ranges[0].min = 8000; + ranges[0].max = 25000000 / frame_size / 2; + ranges[1].min = DIV_ROUND_UP(16000000, frame_size); + ranges[1].max = 384000; + break; + default: + return -EINVAL; + } + + return snd_interval_ranges(hw_param_interval(params, rule->var), + ARRAY_SIZE(ranges), ranges, 0); +} + +static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + struct device *dev = dai->dev; + struct snd_pcm_hw_constraint_ratnums *constraints_no_pll; + struct snd_ratnum *rats_no_pll; + + if (IS_ERR(pcm512x->sclk)) { + dev_err(dev, "Need SCLK for master mode: %ld\n", + PTR_ERR(pcm512x->sclk)); + return PTR_ERR(pcm512x->sclk); + } + + if (pcm512x->pll_out) + return snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + pcm512x_hw_rule_rate, + NULL, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + + constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll), + GFP_KERNEL); + if (!constraints_no_pll) + return -ENOMEM; + constraints_no_pll->nrats = 1; + rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL); + if (!rats_no_pll) + return -ENOMEM; + constraints_no_pll->rats = rats_no_pll; + rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; + rats_no_pll->den_min = 1; + rats_no_pll->den_max = 128; + rats_no_pll->den_step = 1; + + return snd_pcm_hw_constraint_ratnums(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + constraints_no_pll); +} + +static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + struct device *dev = dai->dev; + struct regmap *regmap = pcm512x->regmap; + + if (IS_ERR(pcm512x->sclk)) { + dev_info(dev, "No SCLK, using BCLK: %ld\n", + PTR_ERR(pcm512x->sclk)); + + /* Disable reporting of missing SCLK as an error */ + regmap_update_bits(regmap, PCM512x_ERROR_DETECT, + PCM512x_IDCH, PCM512x_IDCH); + + /* Switch PLL input to BCLK */ + regmap_update_bits(regmap, PCM512x_PLL_REF, + PCM512x_SREF, PCM512x_SREF_BCK); + } + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_slave); +} + +static int pcm512x_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + return pcm512x_dai_startup_master(substream, dai); + + case SND_SOC_DAIFMT_CBS_CFS: + return pcm512x_dai_startup_slave(substream, dai); + + default: + return -EINVAL; + } +} + static int pcm512x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -340,17 +513,717 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec, return 0; } +static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, + unsigned long bclk_rate) +{ + struct device *dev = dai->dev; + unsigned long sck_rate; + int pow2; + + /* 64 MHz <= pll_rate <= 100 MHz, VREF mode */ + /* 16 MHz <= sck_rate <= 25 MHz, VREF mode */ + + /* select sck_rate as a multiple of bclk_rate but still with + * as many factors of 2 as possible, as that makes it easier + * to find a fast DAC rate + */ + pow2 = 1 << fls((25000000 - 16000000) / bclk_rate); + for (; pow2; pow2 >>= 1) { + sck_rate = rounddown(25000000, bclk_rate * pow2); + if (sck_rate >= 16000000) + break; + } + if (!pow2) { + dev_err(dev, "Impossible to generate a suitable SCK\n"); + return 0; + } + + dev_dbg(dev, "sck_rate %lu\n", sck_rate); + return sck_rate; +} + +/* pll_rate = pllin_rate * R * J.D / P + * 1 <= R <= 16 + * 1 <= J <= 63 + * 0 <= D <= 9999 + * 1 <= P <= 15 + * 64 MHz <= pll_rate <= 100 MHz + * if D == 0 + * 1 MHz <= pllin_rate / P <= 20 MHz + * else if D > 0 + * 6.667 MHz <= pllin_rate / P <= 20 MHz + * 4 <= J <= 11 + * R = 1 + */ +static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai, + unsigned long pllin_rate, + unsigned long pll_rate) +{ + struct device *dev = dai->dev; + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + unsigned long common; + int R, J, D, P; + unsigned long K; /* 10000 * J.D */ + unsigned long num; + unsigned long den; + + common = gcd(pll_rate, pllin_rate); + dev_dbg(dev, "pll %lu pllin %lu common %lu\n", + pll_rate, pllin_rate, common); + num = pll_rate / common; + den = pllin_rate / common; + + /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */ + if (pllin_rate / den > 20000000 && num < 8) { + num *= 20000000 / (pllin_rate / den); + den *= 20000000 / (pllin_rate / den); + } + dev_dbg(dev, "num / den = %lu / %lu\n", num, den); + + P = den; + if (den <= 15 && num <= 16 * 63 + && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) { + /* Try the case with D = 0 */ + D = 0; + /* factor 'num' into J and R, such that R <= 16 and J <= 63 */ + for (R = 16; R; R--) { + if (num % R) + continue; + J = num / R; + if (J == 0 || J > 63) + continue; + + dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P); + pcm512x->real_pll = pll_rate; + goto done; + } + /* no luck */ + } + + R = 1; + + if (num > 0xffffffffUL / 10000) + goto fallback; + + /* Try to find an exact pll_rate using the D > 0 case */ + common = gcd(10000 * num, den); + num = 10000 * num / common; + den /= common; + dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common); + + for (P = den; P <= 15; P++) { + if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P) + continue; + if (num * P % den) + continue; + K = num * P / den; + /* J == 12 is ok if D == 0 */ + if (K < 40000 || K > 120000) + continue; + + J = K / 10000; + D = K % 10000; + dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P); + pcm512x->real_pll = pll_rate; + goto done; + } + + /* Fall back to an approximate pll_rate */ + +fallback: + /* find smallest possible P */ + P = DIV_ROUND_UP(pllin_rate, 20000000); + if (!P) + P = 1; + else if (P > 15) { + dev_err(dev, "Need a slower clock as pll-input\n"); + return -EINVAL; + } + if (pllin_rate / P < 6667000) { + dev_err(dev, "Need a faster clock as pll-input\n"); + return -EINVAL; + } + K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate); + if (K < 40000) + K = 40000; + /* J == 12 is ok if D == 0 */ + if (K > 120000) + K = 120000; + J = K / 10000; + D = K % 10000; + dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P); + pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P); + +done: + pcm512x->pll_r = R; + pcm512x->pll_j = J; + pcm512x->pll_d = D; + pcm512x->pll_p = P; + return 0; +} + +static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, + unsigned long osr_rate, + unsigned long pllin_rate) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + unsigned long dac_rate; + + if (!pcm512x->pll_out) + return 0; /* no PLL to bypass, force SCK as DAC input */ + + if (pllin_rate % osr_rate) + return 0; /* futile, quit early */ + + /* run DAC no faster than 6144000 Hz */ + for (dac_rate = rounddown(6144000, osr_rate); + dac_rate; + dac_rate -= osr_rate) { + + if (pllin_rate / dac_rate > 128) + return 0; /* DAC divider would be too big */ + + if (!(pllin_rate % dac_rate)) + return dac_rate; + + dac_rate -= osr_rate; + } + + return 0; +} + +static int pcm512x_set_dividers(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params) +{ + struct device *dev = dai->dev; + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + unsigned long pllin_rate = 0; + unsigned long pll_rate; + unsigned long sck_rate; + unsigned long mck_rate; + unsigned long bclk_rate; + unsigned long sample_rate; + unsigned long osr_rate; + unsigned long dacsrc_rate; + int bclk_div; + int lrclk_div; + int dsp_div; + int dac_div; + unsigned long dac_rate; + int ncp_div; + int osr_div; + int ret; + int idac; + int fssp; + int gpio; + + lrclk_div = snd_soc_params_to_frame_size(params); + if (lrclk_div == 0) { + dev_err(dev, "No LRCLK?\n"); + return -EINVAL; + } + + if (!pcm512x->pll_out) { + sck_rate = clk_get_rate(pcm512x->sclk); + bclk_div = params->rate_den * 64 / lrclk_div; + bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); + + mck_rate = sck_rate; + } else { + ret = snd_soc_params_to_bclk(params); + if (ret < 0) { + dev_err(dev, "Failed to find suitable BCLK: %d\n", ret); + return ret; + } + if (ret == 0) { + dev_err(dev, "No BCLK?\n"); + return -EINVAL; + } + bclk_rate = ret; + + pllin_rate = clk_get_rate(pcm512x->sclk); + + sck_rate = pcm512x_find_sck(dai, bclk_rate); + if (!sck_rate) + return -EINVAL; + pll_rate = 4 * sck_rate; + + ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate); + if (ret != 0) + return ret; + + ret = regmap_write(pcm512x->regmap, + PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1); + if (ret != 0) { + dev_err(dev, "Failed to write PLL P: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_PLL_COEFF_1, pcm512x->pll_j); + if (ret != 0) { + dev_err(dev, "Failed to write PLL J: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8); + if (ret != 0) { + dev_err(dev, "Failed to write PLL D msb: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff); + if (ret != 0) { + dev_err(dev, "Failed to write PLL D lsb: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1); + if (ret != 0) { + dev_err(dev, "Failed to write PLL R: %d\n", ret); + return ret; + } + + mck_rate = pcm512x->real_pll; + + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); + } + + if (bclk_div > 128) { + dev_err(dev, "Failed to find BCLK divider\n"); + return -EINVAL; + } + + /* the actual rate */ + sample_rate = sck_rate / bclk_div / lrclk_div; + osr_rate = 16 * sample_rate; + + /* run DSP no faster than 50 MHz */ + dsp_div = mck_rate > 50000000 ? 2 : 1; + + dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); + if (dac_rate) { + /* the desired clock rate is "compatible" with the pll input + * clock, so use that clock as dac input instead of the pll + * output clock since the pll will introduce jitter and thus + * noise. + */ + dev_dbg(dev, "using pll input as dac input\n"); + ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, + PCM512x_SDAC, PCM512x_SDAC_GPIO); + if (ret != 0) { + dev_err(codec->dev, + "Failed to set gpio as dacref: %d\n", ret); + return ret; + } + + gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN, + PCM512x_GREF, gpio); + if (ret != 0) { + dev_err(codec->dev, + "Failed to set gpio %d as dacin: %d\n", + pcm512x->pll_in, ret); + return ret; + } + + dacsrc_rate = pllin_rate; + } else { + /* run DAC no faster than 6144000 Hz */ + unsigned long dac_mul = 6144000 / osr_rate; + unsigned long sck_mul = sck_rate / osr_rate; + + for (; dac_mul; dac_mul--) { + if (!(sck_mul % dac_mul)) + break; + } + if (!dac_mul) { + dev_err(dev, "Failed to find DAC rate\n"); + return -EINVAL; + } + + dac_rate = dac_mul * osr_rate; + dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", + dac_rate, sample_rate); + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, + PCM512x_SDAC, PCM512x_SDAC_SCK); + if (ret != 0) { + dev_err(codec->dev, + "Failed to set sck as dacref: %d\n", ret); + return ret; + } + + dacsrc_rate = sck_rate; + } + + dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); + if (dac_div > 128) { + dev_err(dev, "Failed to find DAC divider\n"); + return -EINVAL; + } + + ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); + if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { + /* run NCP no faster than 2048000 Hz, but why? */ + ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); + if (ncp_div > 128) { + dev_err(dev, "Failed to find NCP divider\n"); + return -EINVAL; + } + } + + osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); + if (osr_div > 128) { + dev_err(dev, "Failed to find OSR divider\n"); + return -EINVAL; + } + + idac = mck_rate / (dsp_div * sample_rate); + + ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write DSP divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write DAC divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write NCP divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write OSR divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_MASTER_CLKDIV_1, bclk_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write BCLK divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, + PCM512x_MASTER_CLKDIV_2, lrclk_div - 1); + if (ret != 0) { + dev_err(dev, "Failed to write LRCLK divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8); + if (ret != 0) { + dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff); + if (ret != 0) { + dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret); + return ret; + } + + if (sample_rate <= 48000) + fssp = PCM512x_FSSP_48KHZ; + else if (sample_rate <= 96000) + fssp = PCM512x_FSSP_96KHZ; + else if (sample_rate <= 192000) + fssp = PCM512x_FSSP_192KHZ; + else + fssp = PCM512x_FSSP_384KHZ; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE, + PCM512x_FSSP, fssp); + if (ret != 0) { + dev_err(codec->dev, "Failed to set fs speed: %d\n", ret); + return ret; + } + + dev_dbg(codec->dev, "DSP divider %d\n", dsp_div); + dev_dbg(codec->dev, "DAC divider %d\n", dac_div); + dev_dbg(codec->dev, "NCP divider %d\n", ncp_div); + dev_dbg(codec->dev, "OSR divider %d\n", osr_div); + dev_dbg(codec->dev, "BCK divider %d\n", bclk_div); + dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div); + dev_dbg(codec->dev, "IDAC %d\n", idac); + dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp); + + return 0; +} + +static int pcm512x_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 pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + int alen; + int gpio; + int clock_output; + int master_mode; + int ret; + + dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n", + params_rate(params), + params_channels(params)); + + switch (snd_pcm_format_width(params_format(params))) { + case 16: + alen = PCM512x_ALEN_16; + break; + case 20: + alen = PCM512x_ALEN_20; + break; + case 24: + alen = PCM512x_ALEN_24; + break; + case 32: + alen = PCM512x_ALEN_32; + break; + default: + dev_err(codec->dev, "Bad frame size: %d\n", + snd_pcm_format_width(params_format(params))); + return -EINVAL; + } + + switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + ret = regmap_update_bits(pcm512x->regmap, + PCM512x_BCLK_LRCLK_CFG, + PCM512x_BCKP + | PCM512x_BCKO | PCM512x_LRKO, + 0); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable slave mode: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, + PCM512x_DCAS, 0); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable clock divider autoset: %d\n", + ret); + return ret; + } + return 0; + case SND_SOC_DAIFMT_CBM_CFM: + clock_output = PCM512x_BCKO | PCM512x_LRKO; + master_mode = PCM512x_RLRK | PCM512x_RBCK; + break; + case SND_SOC_DAIFMT_CBM_CFS: + clock_output = PCM512x_BCKO; + master_mode = PCM512x_RBCK; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, + PCM512x_ALEN, alen); + if (ret != 0) { + dev_err(codec->dev, "Failed to set frame size: %d\n", ret); + return ret; + } + + if (pcm512x->pll_out) { + ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11); + if (ret != 0) { + dev_err(codec->dev, "Failed to set FLEX_A: %d\n", ret); + return ret; + } + + ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff); + if (ret != 0) { + dev_err(codec->dev, "Failed to set FLEX_B: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, + PCM512x_IDFS | PCM512x_IDBK + | PCM512x_IDSK | PCM512x_IDCH + | PCM512x_IDCM | PCM512x_DCAS + | PCM512x_IPLK, + PCM512x_IDFS | PCM512x_IDBK + | PCM512x_IDSK | PCM512x_IDCH + | PCM512x_DCAS); + if (ret != 0) { + dev_err(codec->dev, + "Failed to ignore auto-clock failures: %d\n", + ret); + return ret; + } + } else { + ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, + PCM512x_IDFS | PCM512x_IDBK + | PCM512x_IDSK | PCM512x_IDCH + | PCM512x_IDCM | PCM512x_DCAS + | PCM512x_IPLK, + PCM512x_IDFS | PCM512x_IDBK + | PCM512x_IDSK | PCM512x_IDCH + | PCM512x_DCAS | PCM512x_IPLK); + if (ret != 0) { + dev_err(codec->dev, + "Failed to ignore auto-clock failures: %d\n", + ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, + PCM512x_PLLE, 0); + if (ret != 0) { + dev_err(codec->dev, "Failed to disable pll: %d\n", ret); + return ret; + } + } + + ret = pcm512x_set_dividers(dai, params); + if (ret != 0) + return ret; + + if (pcm512x->pll_out) { + ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF, + PCM512x_SREF, PCM512x_SREF_GPIO); + if (ret != 0) { + dev_err(codec->dev, + "Failed to set gpio as pllref: %d\n", ret); + return ret; + } + + gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN, + PCM512x_GREF, gpio); + if (ret != 0) { + dev_err(codec->dev, + "Failed to set gpio %d as pllin: %d\n", + pcm512x->pll_in, ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, + PCM512x_PLLE, PCM512x_PLLE); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable pll: %d\n", ret); + return ret; + } + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, + PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, + clock_output); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable clock output: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, + PCM512x_RLRK | PCM512x_RBCK, + master_mode); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable master mode: %d\n", ret); + return ret; + } + + if (pcm512x->pll_out) { + gpio = PCM512x_G1OE << (pcm512x->pll_out - 1); + ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN, + gpio, gpio); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable gpio %d: %d\n", + pcm512x->pll_out, ret); + return ret; + } + + gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1; + ret = regmap_update_bits(pcm512x->regmap, gpio, + PCM512x_GxSL, PCM512x_GxSL_PLLCK); + if (ret != 0) { + dev_err(codec->dev, "Failed to output pll on %d: %d\n", + ret, pcm512x->pll_out); + return ret; + } + + gpio = PCM512x_G1OE << (4 - 1); + ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN, + gpio, gpio); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable gpio %d: %d\n", + 4, ret); + return ret; + } + + gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1; + ret = regmap_update_bits(pcm512x->regmap, gpio, + PCM512x_GxSL, PCM512x_GxSL_PLLLK); + if (ret != 0) { + dev_err(codec->dev, + "Failed to output pll lock on %d: %d\n", + ret, 4); + return ret; + } + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, + PCM512x_RQSY, PCM512x_RQSY_HALT); + if (ret != 0) { + dev_err(codec->dev, "Failed to halt clocks: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, + PCM512x_RQSY, PCM512x_RQSY_RESUME); + if (ret != 0) { + dev_err(codec->dev, "Failed to resume clocks: %d\n", ret); + return ret; + } + + return 0; +} + +static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + pcm512x->fmt = fmt; + + return 0; +} + +static const struct snd_soc_dai_ops pcm512x_dai_ops = { + .startup = pcm512x_dai_startup, + .hw_params = pcm512x_hw_params, + .set_fmt = pcm512x_set_fmt, +}; + static struct snd_soc_dai_driver pcm512x_dai = { .name = "pcm512x-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, + .ops = &pcm512x_dai_ops, }; static struct snd_soc_codec_driver pcm512x_codec_driver = { @@ -448,21 +1321,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) } pcm512x->sclk = devm_clk_get(dev, NULL); - if (IS_ERR(pcm512x->sclk)) { - if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - dev_info(dev, "No SCLK, using BCLK: %ld\n", - PTR_ERR(pcm512x->sclk)); - - /* Disable reporting of missing SCLK as an error */ - regmap_update_bits(regmap, PCM512x_ERROR_DETECT, - PCM512x_IDCH, PCM512x_IDCH); - - /* Switch PLL input to BCLK */ - regmap_update_bits(regmap, PCM512x_PLL_REF, - PCM512x_SREF, PCM512x_SREF); - } else { + if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR(pcm512x->sclk)) { ret = clk_prepare_enable(pcm512x->sclk); if (ret != 0) { dev_err(dev, "Failed to enable SCLK: %d\n", ret); @@ -483,6 +1344,43 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) pm_runtime_enable(dev); pm_runtime_idle(dev); +#ifdef CONFIG_OF + if (dev->of_node) { + const struct device_node *np = dev->of_node; + u32 val; + + if (of_property_read_u32(np, "pll-in", &val) >= 0) { + if (val > 6) { + dev_err(dev, "Invalid pll-in\n"); + ret = -EINVAL; + goto err_clk; + } + pcm512x->pll_in = val; + } + + if (of_property_read_u32(np, "pll-out", &val) >= 0) { + if (val > 6) { + dev_err(dev, "Invalid pll-out\n"); + ret = -EINVAL; + goto err_clk; + } + pcm512x->pll_out = val; + } + + if (!pcm512x->pll_in != !pcm512x->pll_out) { + dev_err(dev, + "Error: both pll-in and pll-out, or none\n"); + ret = -EINVAL; + goto err_clk; + } + if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) { + dev_err(dev, "Error: pll-in == pll-out\n"); + ret = -EINVAL; + goto err_clk; + } + } +#endif + ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, &pcm512x_dai, 1); if (ret != 0) { diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index 6ee76aaca09..b7c31020722 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h @@ -37,6 +37,10 @@ #define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) +#define PCM512x_DAC_REF (PCM512x_PAGE_BASE(0) + 14) +#define PCM512x_GPIO_DACIN (PCM512x_PAGE_BASE(0) + 16) +#define PCM512x_GPIO_PLLIN (PCM512x_PAGE_BASE(0) + 18) +#define PCM512x_SYNCHRONIZE (PCM512x_PAGE_BASE(0) + 19) #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) #define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) #define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) @@ -77,6 +81,7 @@ #define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) #define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) #define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) +#define PCM512x_CLOCK_STATUS (PCM512x_PAGE_BASE(0) + 95) #define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) #define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) #define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) @@ -91,7 +96,10 @@ #define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) -#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) +#define PCM512x_FLEX_A (PCM512x_PAGE_BASE(253) + 63) +#define PCM512x_FLEX_B (PCM512x_PAGE_BASE(253) + 64) + +#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(253) + 64) /* Page 0, Register 1 - reset */ #define PCM512x_RSTR (1 << 0) @@ -108,8 +116,8 @@ #define PCM512x_RQML_SHIFT 4 /* Page 0, Register 4 - PLL */ -#define PCM512x_PLCE (1 << 0) -#define PCM512x_RLCE_SHIFT 0 +#define PCM512x_PLLE (1 << 0) +#define PCM512x_PLLE_SHIFT 0 #define PCM512x_PLCK (1 << 4) #define PCM512x_PLCK_SHIFT 4 @@ -119,8 +127,66 @@ #define PCM512x_DEMP (1 << 4) #define PCM512x_DEMP_SHIFT 4 +/* Page 0, Register 8 - GPIO output enable */ +#define PCM512x_G1OE (1 << 0) +#define PCM512x_G2OE (1 << 1) +#define PCM512x_G3OE (1 << 2) +#define PCM512x_G4OE (1 << 3) +#define PCM512x_G5OE (1 << 4) +#define PCM512x_G6OE (1 << 5) + +/* Page 0, Register 9 - BCK, LRCLK configuration */ +#define PCM512x_LRKO (1 << 0) +#define PCM512x_LRKO_SHIFT 0 +#define PCM512x_BCKO (1 << 4) +#define PCM512x_BCKO_SHIFT 4 +#define PCM512x_BCKP (1 << 5) +#define PCM512x_BCKP_SHIFT 5 + +/* Page 0, Register 12 - Master mode BCK, LRCLK reset */ +#define PCM512x_RLRK (1 << 0) +#define PCM512x_RLRK_SHIFT 0 +#define PCM512x_RBCK (1 << 1) +#define PCM512x_RBCK_SHIFT 1 + /* Page 0, Register 13 - PLL reference */ -#define PCM512x_SREF (1 << 4) +#define PCM512x_SREF (7 << 4) +#define PCM512x_SREF_SHIFT 4 +#define PCM512x_SREF_SCK (0 << 4) +#define PCM512x_SREF_BCK (1 << 4) +#define PCM512x_SREF_GPIO (3 << 4) + +/* Page 0, Register 14 - DAC reference */ +#define PCM512x_SDAC (7 << 4) +#define PCM512x_SDAC_SHIFT 4 +#define PCM512x_SDAC_MCK (0 << 4) +#define PCM512x_SDAC_PLL (1 << 4) +#define PCM512x_SDAC_SCK (3 << 4) +#define PCM512x_SDAC_BCK (4 << 4) +#define PCM512x_SDAC_GPIO (5 << 4) + +/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */ +#define PCM512x_GREF (7 << 0) +#define PCM512x_GREF_SHIFT 0 +#define PCM512x_GREF_GPIO1 (0 << 0) +#define PCM512x_GREF_GPIO2 (1 << 0) +#define PCM512x_GREF_GPIO3 (2 << 0) +#define PCM512x_GREF_GPIO4 (3 << 0) +#define PCM512x_GREF_GPIO5 (4 << 0) +#define PCM512x_GREF_GPIO6 (5 << 0) + +/* Page 0, Register 19 - synchronize */ +#define PCM512x_RQSY (1 << 0) +#define PCM512x_RQSY_RESUME (0 << 0) +#define PCM512x_RQSY_HALT (1 << 0) + +/* Page 0, Register 34 - fs speed mode */ +#define PCM512x_FSSP (3 << 0) +#define PCM512x_FSSP_SHIFT 0 +#define PCM512x_FSSP_48KHZ (0 << 0) +#define PCM512x_FSSP_96KHZ (1 << 0) +#define PCM512x_FSSP_192KHZ (2 << 0) +#define PCM512x_FSSP_384KHZ (3 << 0) /* Page 0, Register 37 - Error detection */ #define PCM512x_IPLK (1 << 0) @@ -131,6 +197,20 @@ #define PCM512x_IDBK (1 << 5) #define PCM512x_IDFS (1 << 6) +/* Page 0, Register 40 - I2S configuration */ +#define PCM512x_ALEN (3 << 0) +#define PCM512x_ALEN_SHIFT 0 +#define PCM512x_ALEN_16 (0 << 0) +#define PCM512x_ALEN_20 (1 << 0) +#define PCM512x_ALEN_24 (2 << 0) +#define PCM512x_ALEN_32 (3 << 0) +#define PCM512x_AFMT (3 << 4) +#define PCM512x_AFMT_SHIFT 4 +#define PCM512x_AFMT_I2S (0 << 4) +#define PCM512x_AFMT_DSP (1 << 4) +#define PCM512x_AFMT_RTJ (2 << 4) +#define PCM512x_AFMT_LTJ (3 << 4) + /* Page 0, Register 42 - DAC routing */ #define PCM512x_AUPR_SHIFT 0 #define PCM512x_AUPL_SHIFT 4 @@ -152,7 +232,26 @@ /* Page 0, Register 65 - Digital mute enables */ #define PCM512x_ACTL_SHIFT 2 #define PCM512x_AMLE_SHIFT 1 -#define PCM512x_AMLR_SHIFT 0 +#define PCM512x_AMRE_SHIFT 0 + +/* Page 0, Register 80-85, GPIO output selection */ +#define PCM512x_GxSL (31 << 0) +#define PCM512x_GxSL_SHIFT 0 +#define PCM512x_GxSL_OFF (0 << 0) +#define PCM512x_GxSL_DSP (1 << 0) +#define PCM512x_GxSL_REG (2 << 0) +#define PCM512x_GxSL_AMUTB (3 << 0) +#define PCM512x_GxSL_AMUTL (4 << 0) +#define PCM512x_GxSL_AMUTR (5 << 0) +#define PCM512x_GxSL_CLKI (6 << 0) +#define PCM512x_GxSL_SDOUT (7 << 0) +#define PCM512x_GxSL_ANMUL (8 << 0) +#define PCM512x_GxSL_ANMUR (9 << 0) +#define PCM512x_GxSL_PLLLK (10 << 0) +#define PCM512x_GxSL_CPCLK (11 << 0) +#define PCM512x_GxSL_UV0_7 (14 << 0) +#define PCM512x_GxSL_UV0_3 (15 << 0) +#define PCM512x_GxSL_PLLCK (16 << 0) /* Page 1, Register 2 - analog volume control */ #define PCM512x_RAGN_SHIFT 0 diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 2cd4fe46310..f374840a5a7 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -34,6 +34,7 @@ #include "rt286.h" #define RT286_VENDOR_ID 0x10ec0286 +#define RT288_VENDOR_ID 0x10ec0288 struct rt286_priv { struct regmap *regmap; @@ -305,6 +306,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) *hp = false; *mic = false; + if (!rt286->codec) + return -EINVAL; if (rt286->pdata.cbj_en) { regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); *hp = buf & 0x80000000; @@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(rt286_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); if (rt286->clk_id == RT286_SCLK_S_MCLK) return 1; @@ -417,6 +421,8 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt286_snd_controls[] = { SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN, RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R("ADC0 Capture Switch", RT286_ADCL_GAIN, + RT286_ADCR_GAIN, 7, 1, 1), SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN, RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN, @@ -500,7 +506,7 @@ SOC_DAPM_ENUM("SPO source", rt286_spo_enum); static int rt286_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -522,7 +528,7 @@ static int rt286_spk_event(struct snd_soc_dapm_widget *w, static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -538,36 +544,10 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt286_adc_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - unsigned int nid; - - nid = (w->reg >> 20) & 0xff; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(codec, - VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), - 0x7080, 0x7000); - break; - case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(codec, - VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), - 0x7080, 0x7080); - break; - default: - return 0; - } - - return 0; -} - static int rt286_vref_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -585,7 +565,7 @@ static int rt286_vref_event(struct snd_soc_dapm_widget *w, static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -604,7 +584,7 @@ static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, static int rt286_mic1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -667,12 +647,10 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), /* ADC Mux */ - SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1, - &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | - SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1, - &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | - SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1, + &rt286_adc0_mux), + SND_SOC_DAPM_MUX("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1, + &rt286_adc1_mux), /* Audio Interface */ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), @@ -861,10 +839,8 @@ static int rt286_hw_params(struct snd_pcm_substream *substream, RT286_I2S_CTRL1, 0x0018, d_len_code << 3); dev_dbg(codec->dev, "format val = 0x%x\n", val); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val); - else - snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val); + snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val); + snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val); return 0; } @@ -1196,6 +1172,7 @@ static const struct regmap_config rt286_regmap = { static const struct i2c_device_id rt286_i2c_id[] = { {"rt286", 0}, + {"rt288", 0}, {} }; MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); @@ -1216,6 +1193,17 @@ static struct dmi_system_id force_combo_jack_table[] = { { } }; +static struct dmi_system_id dmi_dell_dino[] = { + { + .ident = "Dell Dino", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_BOARD_NAME, "0144P8") + } + }, + { } +}; + static int rt286_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1238,7 +1226,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, regmap_read(rt286->regmap, RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); - if (ret != RT286_VENDOR_ID) { + if (ret != RT286_VENDOR_ID && ret != RT288_VENDOR_ID) { dev_err(&i2c->dev, "Device with ID register %x is not rt286\n", ret); return -ENODEV; @@ -1251,7 +1239,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c, if (pdata) rt286->pdata = *pdata; - if (dmi_check_system(force_combo_jack_table)) + if (dmi_check_system(force_combo_jack_table) || + dmi_check_system(dmi_dell_dino)) rt286->pdata.cbj_en = true; regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); @@ -1290,6 +1279,17 @@ static int rt286_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); + if (dmi_check_system(dmi_dell_dino)) { + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_MASK, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_DIRECTION, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_SET_GPIO_DATA, 0x40, 0x40); + regmap_update_bits(rt286->regmap, + RT286_GPIO_CTRL, 0xc, 0x8); + } + if (rt286->i2c->irq) { ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h index b539b7320a7..7130edb152e 100644 --- a/sound/soc/codecs/rt286.h +++ b/sound/soc/codecs/rt286.h @@ -117,6 +117,12 @@ VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0) #define RT286_PROC_COEF\ VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0) +#define RT286_SET_GPIO_MASK\ + VERB_CMD(AC_VERB_SET_GPIO_MASK, RT286_AUDIO_FUNCTION_GROUP, 0) +#define RT286_SET_GPIO_DIRECTION\ + VERB_CMD(AC_VERB_SET_GPIO_DIRECTION, RT286_AUDIO_FUNCTION_GROUP, 0) +#define RT286_SET_GPIO_DATA\ + VERB_CMD(AC_VERB_SET_GPIO_DATA, RT286_AUDIO_FUNCTION_GROUP, 0) /* Index registers */ #define RT286_A_BIAS_CTRL1 0x01 @@ -131,6 +137,7 @@ #define RT286_POWER_CTRL3 0x0f #define RT286_MIC1_DET_CTRL 0x19 #define RT286_MISC_CTRL1 0x20 +#define RT286_GPIO_CTRL 0x29 #define RT286_IRQ_CTRL 0x33 #define RT286_PLL_CTRL1 0x49 #define RT286_CBJ_CTRL1 0x4f diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 6d7b7ca7d53..c61852742ee 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -287,70 +287,78 @@ static const struct snd_kcontrol_new rt5631_snd_controls[] = { static int check_sysclk1_source(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL); + reg = snd_soc_read(codec, RT5631_GLOBAL_CLK_CTRL); return reg & RT5631_SYSCLK_SOUR_SEL_PLL; } static int check_dmic_used(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); return rt5631->dmic_used_flag; } static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL); + reg = snd_soc_read(codec, RT5631_OUTMIXER_L_CTRL); return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L); } static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL); + reg = snd_soc_read(codec, RT5631_OUTMIXER_R_CTRL); return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R); } static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL); + reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL); return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L); } static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL); + reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL); return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R); } static int check_adcl_select(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER); + reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER); return !(reg & RT5631_M_MIC1_TO_RECMIXER_L); } static int check_adcr_select(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; - reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER); + reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER); return !(reg & RT5631_M_MIC2_TO_RECMIXER_R); } @@ -556,7 +564,7 @@ static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable) static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -590,7 +598,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, static int set_dmic_params(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); switch (rt5631->rx_rate) { diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index c3f2decd643..178e55d4d48 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -458,7 +458,7 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = { static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); int idx = -EINVAL; @@ -475,9 +475,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int val; - val = snd_soc_read(source->codec, RT5640_GLB_CLK); + val = snd_soc_read(codec, RT5640_GLB_CLK); val &= RT5640_SCLK_SRC_MASK; if (val == RT5640_SCLK_SRC_PLL1) return 1; @@ -963,7 +964,7 @@ static void rt5640_pmu_depop(struct snd_soc_codec *codec) static int rt5640_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -987,7 +988,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1003,7 +1004,7 @@ static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w, static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -2124,6 +2125,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match); static struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, { "10EC5640", 0 }, + { "10EC5642", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 27141e2df87..c9a4c5be083 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -31,6 +31,7 @@ #include "rt5645.h" #define RT5645_DEVICE_ID 0x6308 +#define RT5650_DEVICE_ID 0x6419 #define RT5645_PR_RANGE_BASE (0xff + 1) #define RT5645_PR_SPACING 0x100 @@ -59,6 +60,10 @@ static const struct reg_default init_list[] = { }; #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) +static const struct reg_default rt5650_init_list[] = { + {0xf6, 0x0100}, +}; + static const struct reg_default rt5645_reg[] = { { 0x00, 0x0000 }, { 0x01, 0xc8c8 }, @@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = { { 0x2a, 0x5656 }, { 0x2b, 0x5454 }, { 0x2c, 0xaaa0 }, + { 0x2d, 0x0000 }, { 0x2f, 0x1002 }, { 0x31, 0x5000 }, { 0x32, 0x0000 }, @@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = { { 0xdb, 0x0003 }, { 0xdc, 0x0049 }, { 0xdd, 0x001b }, + { 0xdf, 0x0008 }, + { 0xe0, 0x4000 }, { 0xe6, 0x8000 }, { 0xe7, 0x0200 }, { 0xec, 0xb300 }, @@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg) case RT5645_IRQ_CTRL3: case RT5645_INT_IRQ_ST: case RT5645_IL_CMD: + case RT5650_4BTN_IL_CMD1: case RT5645_VENDOR_ID: case RT5645_VENDOR_ID1: case RT5645_VENDOR_ID2: @@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_STO_DAC_MIXER: case RT5645_MONO_DAC_MIXER: case RT5645_DIG_MIXER: + case RT5650_A_DAC_SOUR: case RT5645_DIG_INF1_DATA: case RT5645_PDM_OUT_CTRL: case RT5645_REC_L1_MIXER: @@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_IL_CMD: case RT5645_IL_CMD2: case RT5645_IL_CMD3: + case RT5650_4BTN_IL_CMD1: + case RT5650_4BTN_IL_CMD2: case RT5645_DRC1_HL_CTRL1: case RT5645_DRC2_HL_CTRL1: case RT5645_ADC_MONO_HP_CTRL1: @@ -527,7 +539,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); int idx = -EINVAL; @@ -544,9 +556,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int val; - val = snd_soc_read(source->codec, RT5645_GLB_CLK); + val = snd_soc_read(codec, RT5645_GLB_CLK); val &= RT5645_SCLK_SRC_MASK; if (val == RT5645_SCLK_SRC_PLL1) return 1; @@ -557,6 +570,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, static int is_using_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); unsigned int reg, shift, val; switch (source->shift) { @@ -588,7 +602,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, return 0; } - val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; + val = (snd_soc_read(codec, reg) >> shift) & 0xf; switch (val) { case 1: case 2: @@ -601,6 +615,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, } +/** + * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5645_CLK_SEL_SYS: + case RT5645_CLK_SEL_I2S1_ASRC: + case RT5645_CLK_SEL_I2S2_ASRC: + case RT5645_CLK_SEL_SYS2: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5645_DA_STEREO_FILTER) { + asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5645_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_L_FILTER) { + asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_R_FILTER) { + asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_STEREO_FILTER) { + asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_L_FILTER) { + asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_R_FILTER) { + asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5645_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5645_ASRC_3, + asrc3_mask, asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, @@ -1007,6 +1102,44 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); +/* MX-2d [3] [2] */ +static const char * const rt5650_a_dac1_src[] = { + "DAC1", "Stereo DAC Mixer" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src); + +static const struct snd_kcontrol_new rt5650_a_dac1_l_mux = + SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src); + +static const struct snd_kcontrol_new rt5650_a_dac1_r_mux = + SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum); + +/* MX-2d [1] [0] */ +static const char * const rt5650_a_dac2_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src); + +static const struct snd_kcontrol_new rt5650_a_dac2_l_mux = + SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src); + +static const struct snd_kcontrol_new rt5650_a_dac2_r_mux = + SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum); + /* MX-2F [13:12] */ static const char * const rt5645_if2_adc_in_src[] = { "IF_ADC1", "IF_ADC2", "VAD_ADC" @@ -1144,18 +1277,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) static int rt5645_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: hp_amp_power(codec, 1); /* headphone unmute sequence */ - snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK | - RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK, - (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | - (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | - (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); + } else { + snd_soc_update_bits(codec, RT5645_DEPOP_M3, + RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | + RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); + } regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5645_DEPOP_M1, @@ -1175,12 +1313,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMD: /* headphone mute sequence */ - snd_soc_update_bits(codec, RT5645_DEPOP_M3, - RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | - RT5645_CP_FQ3_MASK, - (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | - (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | - (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); + } else { + snd_soc_update_bits(codec, RT5645_DEPOP_M3, + RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | + RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); + } regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5645_DEPOP_M1, @@ -1205,7 +1347,7 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w, static int rt5645_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1232,7 +1374,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w, static int rt5645_lout_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1262,7 +1404,7 @@ static int rt5645_lout_event(struct snd_soc_dapm_widget *w, static int rt5645_bst2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1574,6 +1716,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("SPOR"), }; +static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { + SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac1_l_mux), + SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac1_r_mux), + SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac2_l_mux), + SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac2_r_mux), +}; + static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, @@ -1779,13 +1932,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, - { "DAC L1", NULL, "Stereo DAC MIXL" }, { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC R1", NULL, "Stereo DAC MIXR" }, { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC L2", NULL, "Mono DAC MIXL" }, { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC R2", NULL, "Mono DAC MIXR" }, { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, { "SPK MIXL", "BST1 Switch", "BST1" }, @@ -1874,6 +2023,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "SPOR", NULL, "SPK amp" }, }; +static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = { + { "A DAC1 L Mux", "DAC1", "DAC1 MIXL"}, + { "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"}, + { "A DAC1 R Mux", "DAC1", "DAC1 MIXR"}, + { "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"}, + + { "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"}, + { "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"}, + { "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"}, + { "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"}, + + { "DAC L1", NULL, "A DAC1 L Mux" }, + { "DAC R1", NULL, "A DAC1 R Mux" }, + { "DAC L2", NULL, "A DAC2 L Mux" }, + { "DAC R2", NULL, "A DAC2 R Mux" }, +}; + +static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = { + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + { "DAC L2", NULL, "Mono DAC MIXL" }, + { "DAC R2", NULL, "Mono DAC MIXR" }, +}; + static int rt5645_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -2293,6 +2466,22 @@ static int rt5645_probe(struct snd_soc_codec *codec) rt5645->codec = codec; + switch (rt5645->codec_type) { + case CODEC_TYPE_RT5645: + snd_soc_dapm_add_routes(&codec->dapm, + rt5645_specific_dapm_routes, + ARRAY_SIZE(rt5645_specific_dapm_routes)); + break; + case CODEC_TYPE_RT5650: + snd_soc_dapm_new_controls(&codec->dapm, + rt5650_specific_dapm_widgets, + ARRAY_SIZE(rt5650_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5650_specific_dapm_routes, + ARRAY_SIZE(rt5650_specific_dapm_routes)); + break; + } + rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); @@ -2424,6 +2613,7 @@ static const struct regmap_config rt5645_regmap = { static const struct i2c_device_id rt5645_i2c_id[] = { { "rt5645", 0 }, + { "rt5650", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); @@ -2456,9 +2646,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); - if (val != RT5645_DEVICE_ID) { + + switch (val) { + case RT5645_DEVICE_ID: + rt5645->codec_type = CODEC_TYPE_RT5645; + break; + case RT5650_DEVICE_ID: + rt5645->codec_type = CODEC_TYPE_RT5650; + break; + default: dev_err(&i2c->dev, - "Device with ID register %x is not rt5645\n", val); + "Device with ID register %x is not rt5645 or rt5650\n", + val); return -ENODEV; } @@ -2469,6 +2668,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + ret = regmap_register_patch(rt5645->regmap, rt5650_init_list, + ARRAY_SIZE(rt5650_init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n", + ret); + } + if (rt5645->pdata.in2_diff) regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, RT5645_IN_DF2, RT5645_IN_DF2); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index a815e36a2bd..dbfd98c22f4 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -47,6 +47,7 @@ #define RT5645_STO_DAC_MIXER 0x2a #define RT5645_MONO_DAC_MIXER 0x2b #define RT5645_DIG_MIXER 0x2c +#define RT5650_A_DAC_SOUR 0x2d #define RT5645_DIG_INF1_DATA 0x2f /* Mixer - PDM */ #define RT5645_PDM_OUT_CTRL 0x31 @@ -150,6 +151,8 @@ #define RT5645_IL_CMD 0xdb #define RT5645_IL_CMD2 0xdc #define RT5645_IL_CMD3 0xdd +#define RT5650_4BTN_IL_CMD1 0xdf +#define RT5650_4BTN_IL_CMD2 0xe0 #define RT5645_DRC1_HL_CTRL1 0xe7 #define RT5645_DRC2_HL_CTRL1 0xe9 #define RT5645_MUTI_DRC_CTRL1 0xea @@ -472,6 +475,12 @@ #define RT5645_DAC_L2_DAC_R_VOL_MASK (0x1 << 4) #define RT5645_DAC_L2_DAC_R_VOL_SFT 4 +/* Analog DAC1/2 Input Source Control (0x2d) */ +#define RT5650_A_DAC1_L_IN_SFT 3 +#define RT5650_A_DAC1_R_IN_SFT 2 +#define RT5650_A_DAC2_L_IN_SFT 1 +#define RT5650_A_DAC2_R_IN_SFT 0 + /* Digital Interface Data Control (0x2f) */ #define RT5645_IF1_ADC2_IN_SEL (0x1 << 15) #define RT5645_IF1_ADC2_IN_SFT 15 @@ -1111,50 +1120,27 @@ #define RT5645_DMIC_2_M_NOR (0x0 << 8) #define RT5645_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5645_CLK_SEL_SYS (0x0) +#define RT5645_CLK_SEL_I2S1_ASRC (0x1) +#define RT5645_CLK_SEL_I2S2_ASRC (0x2) +#define RT5645_CLK_SEL_SYS2 (0x5) + /* ASRC Control 2 (0x84) */ -#define RT5645_MDA_L_M_MASK (0x1 << 15) -#define RT5645_MDA_L_M_SFT 15 -#define RT5645_MDA_L_M_NOR (0x0 << 15) -#define RT5645_MDA_L_M_ASYN (0x1 << 15) -#define RT5645_MDA_R_M_MASK (0x1 << 14) -#define RT5645_MDA_R_M_SFT 14 -#define RT5645_MDA_R_M_NOR (0x0 << 14) -#define RT5645_MDA_R_M_ASYN (0x1 << 14) -#define RT5645_MAD_L_M_MASK (0x1 << 13) -#define RT5645_MAD_L_M_SFT 13 -#define RT5645_MAD_L_M_NOR (0x0 << 13) -#define RT5645_MAD_L_M_ASYN (0x1 << 13) -#define RT5645_MAD_R_M_MASK (0x1 << 12) -#define RT5645_MAD_R_M_SFT 12 -#define RT5645_MAD_R_M_NOR (0x0 << 12) -#define RT5645_MAD_R_M_ASYN (0x1 << 12) -#define RT5645_ADC_M_MASK (0x1 << 11) -#define RT5645_ADC_M_SFT 11 -#define RT5645_ADC_M_NOR (0x0 << 11) -#define RT5645_ADC_M_ASYN (0x1 << 11) -#define RT5645_STO_DAC_M_MASK (0x1 << 5) -#define RT5645_STO_DAC_M_SFT 5 -#define RT5645_STO_DAC_M_NOR (0x0 << 5) -#define RT5645_STO_DAC_M_ASYN (0x1 << 5) -#define RT5645_I2S1_R_D_MASK (0x1 << 4) -#define RT5645_I2S1_R_D_SFT 4 -#define RT5645_I2S1_R_D_DIS (0x0 << 4) -#define RT5645_I2S1_R_D_EN (0x1 << 4) -#define RT5645_I2S2_R_D_MASK (0x1 << 3) -#define RT5645_I2S2_R_D_SFT 3 -#define RT5645_I2S2_R_D_DIS (0x0 << 3) -#define RT5645_I2S2_R_D_EN (0x1 << 3) -#define RT5645_PRE_SCLK_MASK (0x3) -#define RT5645_PRE_SCLK_SFT 0 -#define RT5645_PRE_SCLK_512 (0x0) -#define RT5645_PRE_SCLK_1024 (0x1) -#define RT5645_PRE_SCLK_2048 (0x2) +#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5645_DA_STO_CLK_SEL_SFT 12 +#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5645_DA_MONOL_CLK_SEL_SFT 8 +#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5645_DA_MONOR_CLK_SEL_SFT 4 +#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5645_I2S1_RATE_MASK (0xf << 12) -#define RT5645_I2S1_RATE_SFT 12 -#define RT5645_I2S2_RATE_MASK (0xf << 8) -#define RT5645_I2S2_RATE_SFT 8 +#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5645_AD_MONOL_CLK_SEL_SFT 4 +#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5645_I2S1_PD_MASK (0x7 << 12) @@ -2175,6 +2161,24 @@ enum { RT5645_DMIC_DATA_GPIO11, }; +enum { + CODEC_TYPE_RT5645, + CODEC_TYPE_RT5650, +}; + +/* filter mask */ +enum { + RT5645_DA_STEREO_FILTER = 0x1, + RT5645_DA_MONO_L_FILTER = (0x1 << 1), + RT5645_DA_MONO_R_FILTER = (0x1 << 2), + RT5645_AD_STEREO_FILTER = (0x1 << 3), + RT5645_AD_MONO_L_FILTER = (0x1 << 4), + RT5645_AD_MONO_R_FILTER = (0x1 << 5), +}; + +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5645_priv { struct snd_soc_codec *codec; struct rt5645_platform_data pdata; @@ -2184,6 +2188,7 @@ struct rt5645_priv { struct snd_soc_jack *mic_jack; struct delayed_work jack_detect_work; + int codec_type; int sysclk; int sysclk_src; int lrck[RT5645_AIFS]; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index bb0a3ab5416..9f4c7be6d79 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -376,7 +376,7 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = { static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); int idx = -EINVAL; @@ -394,9 +394,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int val; - val = snd_soc_read(source->codec, RT5651_GLB_CLK); + val = snd_soc_read(codec, RT5651_GLB_CLK); val &= RT5651_SCLK_SRC_MASK; if (val == RT5651_SCLK_SRC_PLL1) return 1; @@ -731,7 +732,7 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux = static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -769,7 +770,7 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w, static int rt5651_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -813,7 +814,8 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -833,7 +835,7 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w, static int rt5651_bst1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -856,7 +858,7 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w, static int rt5651_bst2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -879,7 +881,7 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w, static int rt5651_bst3_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8a0833de166..e1a4a45c57e 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -14,10 +14,12 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/acpi.h> #include <linux/spi/spi.h> +#include <linux/dmi.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -498,7 +500,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = { static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); int idx = -EINVAL; @@ -515,9 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int val; - val = snd_soc_read(source->codec, RT5670_GLB_CLK); + val = snd_soc_read(codec, RT5670_GLB_CLK); val &= RT5670_SCLK_SRC_MASK; if (val == RT5670_SCLK_SRC_PLL1) return 1; @@ -528,6 +531,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, static int is_using_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); unsigned int reg, shift, val; switch (source->shift) { @@ -563,7 +567,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, return 0; } - val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; + val = (snd_soc_read(codec, reg) >> shift) & 0xf; switch (val) { case 1: case 2: @@ -588,6 +592,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, return 0; } + +/** + * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0, asrc2_value = 0; + unsigned int asrc3_mask = 0, asrc3_value = 0; + + if (clk_src > RT5670_CLK_SEL_SYS3) + return -EINVAL; + + if (filter_mask & RT5670_DA_STEREO_FILTER) { + asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5670_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_L_FILTER) { + asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_R_FILTER) { + asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_STEREO_FILTER) { + asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_L_FILTER) { + asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_R_FILTER) { + asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_UP_RATE_FILTER) { + asrc3_mask |= RT5670_UP_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK) + | (clk_src << RT5670_UP_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DOWN_RATE_FILTER) { + asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK) + | (clk_src << RT5670_DOWN_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5670_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5670_ASRC_3, + asrc3_mask, asrc3_value); + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, @@ -1146,7 +1233,7 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux = static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1182,7 +1269,7 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, static int rt5670_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1232,7 +1319,7 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w, static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1255,7 +1342,7 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, static int rt5670_bst2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -2188,6 +2275,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) return 0; + if (rt5670->pdata.jd_mode) { + if (clk_id == RT5670_SCLK_S_PLL1) + snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); + else + snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); + snd_soc_dapm_sync(&codec->dapm); + } switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2522,6 +2616,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { static const struct regmap_config rt5670_regmap = { .reg_bits = 8, .val_bits = 16, + .use_single_rw = true, .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * RT5670_PR_SPACING), .volatile_reg = rt5670_volatile_register, @@ -2549,6 +2644,17 @@ static struct acpi_device_id rt5670_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); #endif +static const struct dmi_system_id dmi_platform_intel_braswell[] = { + { + .ident = "Intel Braswell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), + }, + }, + {} +}; + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2568,6 +2674,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (pdata) rt5670->pdata = *pdata; + if (dmi_check_system(dmi_platform_intel_braswell)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.jd_mode = 1; + } + rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); if (IS_ERR(rt5670->regmap)) { ret = PTR_ERR(rt5670->regmap); @@ -2609,6 +2721,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } if (rt5670->pdata.jd_mode) { + regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); + rt5670->sysclk = 0; + rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, RT5670_PWR_MB, RT5670_PWR_MB); regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, @@ -2716,18 +2832,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, rt5670_dai, ARRAY_SIZE(rt5670_dai)); if (ret < 0) goto err; + pm_runtime_put(&i2c->dev); + return 0; err: + pm_runtime_disable(&i2c->dev); + return ret; } static int rt5670_i2c_remove(struct i2c_client *i2c) { + pm_runtime_disable(&i2c->dev); snd_soc_unregister_codec(&i2c->dev); return 0; diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index d11b9c207e2..21f8e18c13c 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1023,50 +1023,33 @@ #define RT5670_DMIC_2_M_NOR (0x0 << 8) #define RT5670_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5670_CLK_SEL_SYS (0x0) +#define RT5670_CLK_SEL_I2S1_ASRC (0x1) +#define RT5670_CLK_SEL_I2S2_ASRC (0x2) +#define RT5670_CLK_SEL_I2S3_ASRC (0x3) +#define RT5670_CLK_SEL_SYS2 (0x5) +#define RT5670_CLK_SEL_SYS3 (0x6) + /* ASRC Control 2 (0x84) */ -#define RT5670_MDA_L_M_MASK (0x1 << 15) -#define RT5670_MDA_L_M_SFT 15 -#define RT5670_MDA_L_M_NOR (0x0 << 15) -#define RT5670_MDA_L_M_ASYN (0x1 << 15) -#define RT5670_MDA_R_M_MASK (0x1 << 14) -#define RT5670_MDA_R_M_SFT 14 -#define RT5670_MDA_R_M_NOR (0x0 << 14) -#define RT5670_MDA_R_M_ASYN (0x1 << 14) -#define RT5670_MAD_L_M_MASK (0x1 << 13) -#define RT5670_MAD_L_M_SFT 13 -#define RT5670_MAD_L_M_NOR (0x0 << 13) -#define RT5670_MAD_L_M_ASYN (0x1 << 13) -#define RT5670_MAD_R_M_MASK (0x1 << 12) -#define RT5670_MAD_R_M_SFT 12 -#define RT5670_MAD_R_M_NOR (0x0 << 12) -#define RT5670_MAD_R_M_ASYN (0x1 << 12) -#define RT5670_ADC_M_MASK (0x1 << 11) -#define RT5670_ADC_M_SFT 11 -#define RT5670_ADC_M_NOR (0x0 << 11) -#define RT5670_ADC_M_ASYN (0x1 << 11) -#define RT5670_STO_DAC_M_MASK (0x1 << 5) -#define RT5670_STO_DAC_M_SFT 5 -#define RT5670_STO_DAC_M_NOR (0x0 << 5) -#define RT5670_STO_DAC_M_ASYN (0x1 << 5) -#define RT5670_I2S1_R_D_MASK (0x1 << 4) -#define RT5670_I2S1_R_D_SFT 4 -#define RT5670_I2S1_R_D_DIS (0x0 << 4) -#define RT5670_I2S1_R_D_EN (0x1 << 4) -#define RT5670_I2S2_R_D_MASK (0x1 << 3) -#define RT5670_I2S2_R_D_SFT 3 -#define RT5670_I2S2_R_D_DIS (0x0 << 3) -#define RT5670_I2S2_R_D_EN (0x1 << 3) -#define RT5670_PRE_SCLK_MASK (0x3) -#define RT5670_PRE_SCLK_SFT 0 -#define RT5670_PRE_SCLK_512 (0x0) -#define RT5670_PRE_SCLK_1024 (0x1) -#define RT5670_PRE_SCLK_2048 (0x2) +#define RT5670_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5670_DA_STO_CLK_SEL_SFT 12 +#define RT5670_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5670_DA_MONOL_CLK_SEL_SFT 8 +#define RT5670_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5670_DA_MONOR_CLK_SEL_SFT 4 +#define RT5670_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5670_I2S1_RATE_MASK (0xf << 12) -#define RT5670_I2S1_RATE_SFT 12 -#define RT5670_I2S2_RATE_MASK (0xf << 8) -#define RT5670_I2S2_RATE_SFT 8 +#define RT5670_UP_CLK_SEL_MASK (0xf << 12) +#define RT5670_UP_CLK_SEL_SFT 12 +#define RT5670_DOWN_CLK_SEL_MASK (0xf << 8) +#define RT5670_DOWN_CLK_SEL_SFT 8 +#define RT5670_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5670_AD_MONOL_CLK_SEL_SFT 4 +#define RT5670_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5670_I2S1_PD_MASK (0x7 << 12) @@ -1983,6 +1966,21 @@ enum { RT5670_DMIC_DATA_GPIO5, }; +/* filter mask */ +enum { + RT5670_DA_STEREO_FILTER = 0x1, + RT5670_DA_MONO_L_FILTER = (0x1 << 1), + RT5670_DA_MONO_R_FILTER = (0x1 << 2), + RT5670_AD_STEREO_FILTER = (0x1 << 3), + RT5670_AD_MONO_L_FILTER = (0x1 << 4), + RT5670_AD_MONO_R_FILTER = (0x1 << 5), + RT5670_UP_RATE_FILTER = (0x1 << 6), + RT5670_DOWN_RATE_FILTER = (0x1 << 7), +}; + +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index c0fbe188143..5d0bb8748dd 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -702,6 +702,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) static bool activity; int ret; + if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)) + return -ENXIO; + if (on && !activity) { activity = true; @@ -896,7 +899,7 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); int idx = rl6231_calc_dmic_clk(rt5677->sysclk); @@ -911,7 +914,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(source->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); unsigned int val; regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val); @@ -922,6 +926,101 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int is_using_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 rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + unsigned int reg, shift, val; + + if (source->reg == RT5677_ASRC_1) { + switch (source->shift) { + case 12: + reg = RT5677_ASRC_4; + shift = 0; + break; + case 13: + reg = RT5677_ASRC_4; + shift = 4; + break; + case 14: + reg = RT5677_ASRC_4; + shift = 8; + break; + case 15: + reg = RT5677_ASRC_4; + shift = 12; + break; + default: + return 0; + } + } else { + switch (source->shift) { + case 0: + reg = RT5677_ASRC_6; + shift = 8; + break; + case 1: + reg = RT5677_ASRC_6; + shift = 12; + break; + case 2: + reg = RT5677_ASRC_5; + shift = 0; + break; + case 3: + reg = RT5677_ASRC_5; + shift = 4; + break; + case 4: + reg = RT5677_ASRC_5; + shift = 8; + break; + case 5: + reg = RT5677_ASRC_5; + shift = 12; + break; + case 12: + reg = RT5677_ASRC_3; + shift = 0; + break; + case 13: + reg = RT5677_ASRC_3; + shift = 4; + break; + case 14: + reg = RT5677_ASRC_3; + shift = 12; + break; + default: + return 0; + } + } + + regmap_read(rt5677->regmap, reg, &val); + val = (val >> shift) & 0xf; + + switch (val) { + case 1 ... 6: + return 1; + default: + return 0; + } + +} + +static int can_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 rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + + if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384) + return 1; + + return 0; +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, @@ -2031,7 +2130,7 @@ static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux = static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -2055,7 +2154,7 @@ static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, static int rt5677_bst2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -2079,14 +2178,18 @@ static int rt5677_bst2_event(struct snd_soc_dapm_widget *w, static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { - case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMU: regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x2); + break; + + case SND_SOC_DAPM_POST_PMU: regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x0); break; + default: return 0; } @@ -2097,14 +2200,18 @@ static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w, static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { - case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMU: regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x2); + break; + + case SND_SOC_DAPM_POST_PMU: regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x0); break; + default: return 0; } @@ -2115,7 +2222,7 @@ static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w, static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -2142,7 +2249,7 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); unsigned int value; @@ -2165,7 +2272,7 @@ static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w, static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); unsigned int value; @@ -2188,7 +2295,7 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, static int rt5677_vref_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -2212,9 +2319,50 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, - 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), + 0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("PLL2", RT5677_PWR_ANLG2, RT5677_PWR_PLL2_BIT, - 0, rt5677_set_pll2_event, SND_SOC_DAPM_POST_PMU), + 0, rt5677_set_pll2_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL, + 0), /* Input Side */ /* micbias */ @@ -2646,10 +2794,18 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { /* DAC Mixer */ SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2, + SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2, + SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2, RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2, + RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0), SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)), @@ -2722,6 +2878,31 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { + { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, + { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, + { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc }, + { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc }, + { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, + { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, + { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, + { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, + { "I2S3", NULL, "I2S3 ASRC", can_use_asrc}, + { "I2S4", NULL, "I2S4 ASRC", can_use_asrc}, + + { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc }, + { "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc }, + { "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc }, + { "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc }, + { "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc }, + { "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc }, + { "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc }, + { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, + { "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc }, + { "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc }, + { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, + { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, + { "DMIC1", NULL, "DMIC L1" }, { "DMIC1", NULL, "DMIC R1" }, { "DMIC2", NULL, "DMIC L2" }, @@ -2852,8 +3033,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, - { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -2874,8 +3053,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, { "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" }, - { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, { "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" }, { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -2890,8 +3067,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" }, { "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" }, - { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" }, { "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" }, { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -2906,8 +3081,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" }, { "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" }, - { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, - { "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" }, { "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" }, { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll }, @@ -3456,10 +3629,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" }, { "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" }, - { "DAC1 MIXL", NULL, "dac stereo1 filter" }, { "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" }, { "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" }, - { "DAC1 MIXR", NULL, "dac stereo1 filter" }, { "DAC1 FS", NULL, "DAC1 MIXL" }, { "DAC1 FS", NULL, "DAC1 MIXR" }, @@ -3526,35 +3697,46 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, { "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" }, { "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" }, { "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, { "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" }, { "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" }, - { "Mono DAC MIXL", NULL, "dac mono left filter" }, + { "Mono DAC MIXL", NULL, "dac mono2 left filter" }, + { "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" }, { "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" }, { "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" }, { "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" }, - { "Mono DAC MIXR", NULL, "dac mono right filter" }, + { "Mono DAC MIXR", NULL, "dac mono2 right filter" }, + { "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" }, + { "DD1 MIXL", NULL, "dac mono3 left filter" }, + { "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" }, { "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" }, + { "DD1 MIXR", NULL, "dac mono3 right filter" }, + { "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, { "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" }, { "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" }, + { "DD2 MIXL", NULL, "dac mono4 left filter" }, + { "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll }, { "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, { "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" }, { "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" }, { "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" }, + { "DD2 MIXR", NULL, "dac mono4 right filter" }, + { "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXL" }, { "Stereo DAC MIX", NULL, "Stereo DAC MIXR" }, @@ -3576,11 +3758,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" }, { "DAC 1", NULL, "DAC12 SRC Mux" }, - { "DAC 1", NULL, "PLL1", is_sys_clk_from_pll }, { "DAC 2", NULL, "DAC12 SRC Mux" }, - { "DAC 2", NULL, "PLL1", is_sys_clk_from_pll }, { "DAC 3", NULL, "DAC3 SRC Mux" }, - { "DAC 3", NULL, "PLL1", is_sys_clk_from_pll }, { "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" }, { "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" }, @@ -3927,7 +4106,8 @@ static int rt5677_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; - unsigned int val = 0; + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0, slot_width_25 = 0; if (rx_mask || tx_mask) val |= (1 << 12); @@ -3951,6 +4131,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, case 20: val |= (1 << 8); break; + case 25: + slot_width_25 = 0x8080; case 24: val |= (2 << 8); break; @@ -3964,10 +4146,16 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, switch (dai->id) { case RT5677_AIF1: - snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val); + regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, 0x1f00, + val); + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x8000, + slot_width_25); break; case RT5677_AIF2: - snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val); + regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, 0x1f00, + val); + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x80, + slot_width_25); break; default: break; @@ -4752,6 +4940,11 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, RT5677_GPIO5_DIR_OUT); } + if (rt5677->pdata.micbias1_vdd_3v3) + regmap_update_bits(rt5677->regmap, RT5677_MICBIAS, + RT5677_MICBIAS1_CTRL_VDD_MASK, + RT5677_MICBIAS1_CTRL_VDD_3_3V); + rt5677_init_gpio(i2c); rt5677_init_irq(i2c); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 29cf7ce610f..e182e6569bb 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -155,18 +155,19 @@ struct sgtl5000_priv { static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: /* change mic bias resistor */ - snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, SGTL5000_BIAS_R_MASK, sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, SGTL5000_BIAS_R_MASK, 0); break; } @@ -181,11 +182,12 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, static int power_vag_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); const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP; switch (event) { case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, + snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); break; @@ -195,9 +197,9 @@ static int power_vag_event(struct snd_soc_dapm_widget *w, * operational to prevent inadvertently starving the * other one of them. */ - if ((snd_soc_read(w->codec, SGTL5000_CHIP_ANA_POWER) & + if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) & mask) != mask) { - snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, + snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_VAG_POWERUP, 0); msleep(400); } @@ -483,21 +485,21 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) /* setting i2s data format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: - i2sctl |= SGTL5000_I2S_MODE_PCM; + i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT; break; case SND_SOC_DAIFMT_DSP_B: - i2sctl |= SGTL5000_I2S_MODE_PCM; + i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT; i2sctl |= SGTL5000_I2S_LRALIGN; break; case SND_SOC_DAIFMT_I2S: - i2sctl |= SGTL5000_I2S_MODE_I2S_LJ; + i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT; break; case SND_SOC_DAIFMT_RIGHT_J: - i2sctl |= SGTL5000_I2S_MODE_RJ; + i2sctl |= SGTL5000_I2S_MODE_RJ << SGTL5000_I2S_MODE_SHIFT; i2sctl |= SGTL5000_I2S_LRPOL; break; case SND_SOC_DAIFMT_LEFT_J: - i2sctl |= SGTL5000_I2S_MODE_I2S_LJ; + i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT; i2sctl |= SGTL5000_I2S_LRALIGN; break; default: @@ -1462,6 +1464,9 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, if (ret) return ret; + /* Need 8 clocks before I2C accesses */ + udelay(1); + /* read chip information */ ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, ®); if (ret) diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 1f451a1946e..47b257e4180 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -233,16 +233,18 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, static int sn95031_vhs_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); + if (SND_SOC_DAPM_EVENT_ON(event)) { pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); /* power up the rail */ - snd_soc_write(w->codec, SN95031_VHSP, 0x3D); - snd_soc_write(w->codec, SN95031_VHSN, 0x3F); + snd_soc_write(codec, SN95031_VHSP, 0x3D); + snd_soc_write(codec, SN95031_VHSN, 0x3F); msleep(1); } else if (SND_SOC_DAPM_EVENT_OFF(event)) { pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); - snd_soc_write(w->codec, SN95031_VHSP, 0xC4); - snd_soc_write(w->codec, SN95031_VHSN, 0x04); + snd_soc_write(codec, SN95031_VHSP, 0xC4); + snd_soc_write(codec, SN95031_VHSN, 0x04); } return 0; } @@ -250,14 +252,16 @@ static int sn95031_vhs_event(struct snd_soc_dapm_widget *w, static int sn95031_vihf_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); + if (SND_SOC_DAPM_EVENT_ON(event)) { pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); /* power up the rail */ - snd_soc_write(w->codec, SN95031_VIHF, 0x27); + snd_soc_write(codec, SN95031_VIHF, 0x27); msleep(1); } else if (SND_SOC_DAPM_EVENT_OFF(event)) { pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); - snd_soc_write(w->codec, SN95031_VIHF, 0x24); + snd_soc_write(codec, SN95031_VIHF, 0x24); } return 0; } @@ -265,6 +269,7 @@ static int sn95031_vihf_event(struct snd_soc_dapm_widget *w, static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int ldo = 0, clk_dir = 0, data_dir = 0; if (SND_SOC_DAPM_EVENT_ON(event)) { @@ -273,15 +278,16 @@ static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w, data_dir = BIT(7); } /* program DMIC LDO, clock and set clock */ - snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); - snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir); - snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir); + snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); + snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir); + snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir); return 0; } static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int ldo = 0, clk_dir = 0, data_dir = 0; if (SND_SOC_DAPM_EVENT_ON(event)) { @@ -290,22 +296,23 @@ static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w, data_dir = BIT(1); } /* program DMIC LDO, clock and set clock */ - snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); - snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir); - snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir); + snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); + snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir); + snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir); return 0; } static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int ldo = 0; if (SND_SOC_DAPM_EVENT_ON(event)) ldo = BIT(7)|BIT(6); /* program DMIC LDO */ - snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo); + snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo); return 0; } diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 7e18200dd6a..3a1343fa109 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -24,8 +24,11 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <sound/core.h> @@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = { { 0x2c, 0x0c }, }; +static const struct regmap_range sta32x_write_regs_range[] = { + regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), + regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), +}; + +static const struct regmap_range sta32x_read_regs_range[] = { + regmap_reg_range(STA32X_CONFA, STA32X_AUTO2), + regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2), +}; + +static const struct regmap_range sta32x_volatile_regs_range[] = { + regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD), +}; + +static const struct regmap_access_table sta32x_write_regs = { + .yes_ranges = sta32x_write_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta32x_write_regs_range), +}; + +static const struct regmap_access_table sta32x_read_regs = { + .yes_ranges = sta32x_read_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta32x_read_regs_range), +}; + +static const struct regmap_access_table sta32x_volatile_regs = { + .yes_ranges = sta32x_volatile_regs_range, + .n_yes_ranges = ARRAY_SIZE(sta32x_volatile_regs_range), +}; + /* regulator power supply names */ static const char *sta32x_supply_names[] = { "Vdda", /* analog supply, 3.3VV */ @@ -122,6 +154,8 @@ struct sta32x_priv { u32 coef_shadow[STA32X_COEF_COUNT]; struct delayed_work watchdog_work; int shutdown; + struct gpio_desc *gpiod_nreset; + struct mutex coeff_lock; }; static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); @@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = { "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", "0.0134", "0.0117", "0.0110", "0.0104" }; - -static const unsigned int sta32x_limiter_ac_attack_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv, 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), -}; +); -static const unsigned int sta32x_limiter_ac_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv, 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), -}; +); -static const unsigned int sta32x_limiter_drc_attack_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv, 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), -}; +); -static const unsigned int sta32x_limiter_drc_release_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv, 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), -}; +); static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, @@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; - unsigned int cfud; - int i; + unsigned int cfud, val; + int i, ret = 0; + + mutex_lock(&sta32x->coeff_lock); /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); + regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta32x->regmap, STA32X_CFUD, cfud); - snd_soc_write(codec, STA32X_CFADDR2, index); - if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); - else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); - else - return -EINVAL; - for (i = 0; i < 3 * numcoef; i++) - ucontrol->value.bytes.data[i] = - snd_soc_read(codec, STA32X_B1CF1 + i); + regmap_write(sta32x->regmap, STA32X_CFADDR2, index); + if (numcoef == 1) { + regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04); + } else if (numcoef == 5) { + regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08); + } else { + ret = -EINVAL; + goto exit_unlock; + } - return 0; + for (i = 0; i < 3 * numcoef; i++) { + regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val); + ucontrol->value.bytes.data[i] = val; + } + +exit_unlock: + mutex_unlock(&sta32x->coeff_lock); + + return ret; } static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, @@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, int i; /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; - /* chip documentation does not say if the bits are self clearing, - * so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); + regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); + cfud &= 0xf0; + /* + * chip documentation does not say if the bits are self clearing, + * so do it explicitly + */ + regmap_write(sta32x->regmap, STA32X_CFUD, cfud); - snd_soc_write(codec, STA32X_CFADDR2, index); + regmap_write(sta32x->regmap, STA32X_CFADDR2, index); for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++) sta32x->coef_shadow[index + i] = (ucontrol->value.bytes.data[3 * i] << 16) | (ucontrol->value.bytes.data[3 * i + 1] << 8) | (ucontrol->value.bytes.data[3 * i + 2]); for (i = 0; i < 3 * numcoef; i++) - snd_soc_write(codec, STA32X_B1CF1 + i, - ucontrol->value.bytes.data[i]); + regmap_write(sta32x->regmap, STA32X_B1CF1 + i, + ucontrol->value.bytes.data[i]); if (numcoef == 1) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); + regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01); else if (numcoef == 5) - snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); + regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02); else return -EINVAL; @@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) int i; /* preserve reserved bits in STA32X_CFUD */ - cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; + regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); + cfud &= 0xf0; for (i = 0; i < STA32X_COEF_COUNT; i++) { - snd_soc_write(codec, STA32X_CFADDR2, i); - snd_soc_write(codec, STA32X_B1CF1, - (sta32x->coef_shadow[i] >> 16) & 0xff); - snd_soc_write(codec, STA32X_B1CF2, - (sta32x->coef_shadow[i] >> 8) & 0xff); - snd_soc_write(codec, STA32X_B1CF3, - (sta32x->coef_shadow[i]) & 0xff); - /* chip documentation does not say if the bits are - * self-clearing, so do it explicitly */ - snd_soc_write(codec, STA32X_CFUD, cfud); - snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); + regmap_write(sta32x->regmap, STA32X_CFADDR2, i); + regmap_write(sta32x->regmap, STA32X_B1CF1, + (sta32x->coef_shadow[i] >> 16) & 0xff); + regmap_write(sta32x->regmap, STA32X_B1CF2, + (sta32x->coef_shadow[i] >> 8) & 0xff); + regmap_write(sta32x->regmap, STA32X_B1CF3, + (sta32x->coef_shadow[i]) & 0xff); + /* + * chip documentation does not say if the bits are + * self-clearing, so do it explicitly + */ + regmap_write(sta32x->regmap, STA32X_CFUD, cfud); + regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01); } return 0; } @@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec) int rc; /* mute during register sync */ - mute = snd_soc_read(codec, STA32X_MMUTE); - snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE); + regmap_read(sta32x->regmap, STA32X_MMUTE, &mute); + regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE); sta32x_sync_coef_shadow(codec); rc = regcache_sync(sta32x->regmap); - snd_soc_write(codec, STA32X_MMUTE, mute); + regmap_write(sta32x->regmap, STA32X_MMUTE, mute); return rc; } @@ -508,17 +556,12 @@ static struct { }; /* MCLK to fs clock ratios */ -static struct { - int ratio; - int mcs; -} mclk_ratios[3][7] = { - { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, - { 128, 4 }, { 576, 5 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, - { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, +static int mcs_ratio_table[3][7] = { + { 768, 512, 384, 256, 128, 576, 0 }, + { 384, 256, 192, 128, 64, 0 }, + { 384, 256, 192, 128, 64, 0 }, }; - /** * sta32x_set_dai_sysclk - configure MCLK * @codec_dai: the codec DAI @@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - int i, j, ir, fs; - unsigned int rates = 0; - unsigned int rate_min = -1; - unsigned int rate_max = 0; - pr_debug("mclk=%u\n", freq); + dev_dbg(codec->dev, "mclk=%u\n", freq); sta32x->mclk = freq; - if (sta32x->mclk) { - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { - ir = interpolation_ratios[i].ir; - fs = interpolation_ratios[i].fs; - for (j = 0; mclk_ratios[ir][j].ratio; j++) { - if (mclk_ratios[ir][j].ratio * fs == freq) { - rates |= snd_pcm_rate_to_rate_bit(fs); - if (fs < rate_min) - rate_min = fs; - if (fs > rate_max) - rate_max = fs; - break; - } - } - } - /* FIXME: soc should support a rate list */ - rates &= ~SNDRV_PCM_RATE_KNOT; - - if (!rates) { - dev_err(codec->dev, "could not find a valid sample rate\n"); - return -EINVAL; - } - } else { - /* enable all possible rates */ - rates = STA32X_RATES; - rate_min = 32000; - rate_max = 192000; - } - - codec_dai->driver->playback.rates = rates; - codec_dai->driver->playback.rate_min = rate_min; - codec_dai->driver->playback.rate_max = rate_max; return 0; } @@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - u8 confb = snd_soc_read(codec, STA32X_CONFB); - - pr_debug("\n"); - confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); + u8 confb = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: @@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, STA32X_CONFB, confb); - return 0; + return regmap_update_bits(sta32x->regmap, STA32X_CONFB, + STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb); } /** @@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - unsigned int rate; - int i, mcs = -1, ir = -1; - u8 confa, confb; + int i, mcs = -EINVAL, ir = -EINVAL; + unsigned int confa, confb; + unsigned int rate, ratio; + int ret; + + if (!sta32x->mclk) { + dev_err(codec->dev, + "sta32x->mclk is unset. Unable to determine ratio\n"); + return -EIO; + } rate = params_rate(params); - pr_debug("rate: %u\n", rate); - for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) + ratio = sta32x->mclk / rate; + dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio); + + for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { if (interpolation_ratios[i].fs == rate) { ir = interpolation_ratios[i].ir; break; } - if (ir < 0) + } + + if (ir < 0) { + dev_err(codec->dev, "Unsupported samplerate: %u\n", rate); return -EINVAL; - for (i = 0; mclk_ratios[ir][i].ratio; i++) - if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) { - mcs = mclk_ratios[ir][i].mcs; + } + + for (i = 0; i < 6; i++) { + if (mcs_ratio_table[ir][i] == ratio) { + mcs = i; break; } - if (mcs < 0) + } + + if (mcs < 0) { + dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio); return -EINVAL; + } - confa = snd_soc_read(codec, STA32X_CONFA); - confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); - confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); + confa = (ir << STA32X_CONFA_IR_SHIFT) | + (mcs << STA32X_CONFA_MCS_SHIFT); + confb = 0; - confb = snd_soc_read(codec, STA32X_CONFB); - confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); switch (params_width(params)) { case 24: - pr_debug("24bit\n"); + dev_dbg(codec->dev, "24bit\n"); /* fall through */ case 32: - pr_debug("24bit or 32bit\n"); + dev_dbg(codec->dev, "24bit or 32bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x0; @@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, break; case 20: - pr_debug("20bit\n"); + dev_dbg(codec->dev, "20bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x4; @@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, break; case 18: - pr_debug("18bit\n"); + dev_dbg(codec->dev, "18bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x8; @@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, break; case 16: - pr_debug("16bit\n"); + dev_dbg(codec->dev, "16bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x0; @@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_write(codec, STA32X_CONFA, confa); - snd_soc_write(codec, STA32X_CONFB, confb); + ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA, + STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK, + confa); + if (ret < 0) + return ret; + + ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB, + STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB, + confb); + if (ret < 0) + return ret; + + return 0; +} + +static int sta32x_startup_sequence(struct sta32x_priv *sta32x) +{ + if (sta32x->gpiod_nreset) { + gpiod_set_value(sta32x->gpiod_nreset, 0); + mdelay(1); + gpiod_set_value(sta32x->gpiod_nreset, 1); + mdelay(1); + } + return 0; } @@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, int ret; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); - pr_debug("level = %d\n", level); + dev_dbg(codec->dev, "level = %d\n", level); switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: /* Full power on */ - snd_soc_update_bits(codec, STA32X_CONFF, + regmap_update_bits(sta32x->regmap, STA32X_CONFF, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); break; @@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, return ret; } + sta32x_startup_sequence(sta32x); sta32x_cache_sync(codec); sta32x_watchdog_start(sta32x); } - /* Power up to mute */ - /* FIXME */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); + /* Power down */ + regmap_update_bits(sta32x->regmap, STA32X_CONFF, + STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, + 0); break; case SND_SOC_BIAS_OFF: /* The chip runs through the power down sequence for us. */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, - STA32X_CONFF_PWDN); + regmap_update_bits(sta32x->regmap, STA32X_CONFF, + STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0); msleep(300); sta32x_watchdog_stop(sta32x); + + if (sta32x->gpiod_nreset) + gpiod_set_value(sta32x->gpiod_nreset, 0); + regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); break; @@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = { }; static struct snd_soc_dai_driver sta32x_dai = { - .name = "STA32X", + .name = "sta32x-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, @@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = { static int sta32x_probe(struct snd_soc_codec *codec) { struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); + struct sta32x_platform_data *pdata = sta32x->pdata; int i, ret = 0, thermal = 0; - - sta32x->codec = codec; - sta32x->pdata = dev_get_platdata(codec->dev); - ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { @@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec) return ret; } - /* Chip documentation explicitly requires that the reset values - * of reserved register bits are left untouched. - * Write the register default value to cache for reserved registers, - * so the write to the these registers are suppressed by the cache - * restore code when it skips writes of default registers. - */ - regcache_cache_only(sta32x->regmap, true); - snd_soc_write(codec, STA32X_CONFC, 0xc2); - snd_soc_write(codec, STA32X_CONFE, 0xc2); - snd_soc_write(codec, STA32X_CONFF, 0x5c); - snd_soc_write(codec, STA32X_MMUTE, 0x10); - snd_soc_write(codec, STA32X_AUTO1, 0x60); - snd_soc_write(codec, STA32X_AUTO3, 0x00); - snd_soc_write(codec, STA32X_C3CFG, 0x40); - regcache_cache_only(sta32x->regmap, false); - - /* set thermal warning adjustment and recovery */ - if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE)) + ret = sta32x_startup_sequence(sta32x); + if (ret < 0) { + dev_err(codec->dev, "Failed to startup device\n"); + return ret; + } + + /* CONFA */ + if (!pdata->thermal_warning_recovery) thermal |= STA32X_CONFA_TWAB; - if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE)) + if (!pdata->thermal_warning_adjustment) thermal |= STA32X_CONFA_TWRB; - snd_soc_update_bits(codec, STA32X_CONFA, - STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, - thermal); + if (!pdata->fault_detect_recovery) + thermal |= STA32X_CONFA_FDRB; + regmap_update_bits(sta32x->regmap, STA32X_CONFA, + STA32X_CONFA_TWAB | STA32X_CONFA_TWRB | + STA32X_CONFA_FDRB, + thermal); + + /* CONFC */ + regmap_update_bits(sta32x->regmap, STA32X_CONFC, + STA32X_CONFC_CSZ_MASK, + pdata->drop_compensation_ns + << STA32X_CONFC_CSZ_SHIFT); + + /* CONFE */ + regmap_update_bits(sta32x->regmap, STA32X_CONFE, + STA32X_CONFE_MPCV, + pdata->max_power_use_mpcc ? + STA32X_CONFE_MPCV : 0); + regmap_update_bits(sta32x->regmap, STA32X_CONFE, + STA32X_CONFE_MPC, + pdata->max_power_correction ? + STA32X_CONFE_MPC : 0); + regmap_update_bits(sta32x->regmap, STA32X_CONFE, + STA32X_CONFE_AME, + pdata->am_reduction_mode ? + STA32X_CONFE_AME : 0); + regmap_update_bits(sta32x->regmap, STA32X_CONFE, + STA32X_CONFE_PWMS, + pdata->odd_pwm_speed_mode ? + STA32X_CONFE_PWMS : 0); + + /* CONFF */ + regmap_update_bits(sta32x->regmap, STA32X_CONFF, + STA32X_CONFF_IDE, + pdata->invalid_input_detect_mute ? + STA32X_CONFF_IDE : 0); /* select output configuration */ - snd_soc_update_bits(codec, STA32X_CONFF, - STA32X_CONFF_OCFG_MASK, - sta32x->pdata->output_conf - << STA32X_CONFF_OCFG_SHIFT); + regmap_update_bits(sta32x->regmap, STA32X_CONFF, + STA32X_CONFF_OCFG_MASK, + pdata->output_conf + << STA32X_CONFF_OCFG_SHIFT); /* channel to output mapping */ - snd_soc_update_bits(codec, STA32X_C1CFG, - STA32X_CxCFG_OM_MASK, - sta32x->pdata->ch1_output_mapping - << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C2CFG, - STA32X_CxCFG_OM_MASK, - sta32x->pdata->ch2_output_mapping - << STA32X_CxCFG_OM_SHIFT); - snd_soc_update_bits(codec, STA32X_C3CFG, - STA32X_CxCFG_OM_MASK, - sta32x->pdata->ch3_output_mapping - << STA32X_CxCFG_OM_SHIFT); + regmap_update_bits(sta32x->regmap, STA32X_C1CFG, + STA32X_CxCFG_OM_MASK, + pdata->ch1_output_mapping + << STA32X_CxCFG_OM_SHIFT); + regmap_update_bits(sta32x->regmap, STA32X_C2CFG, + STA32X_CxCFG_OM_MASK, + pdata->ch2_output_mapping + << STA32X_CxCFG_OM_SHIFT); + regmap_update_bits(sta32x->regmap, STA32X_C3CFG, + STA32X_CxCFG_OM_MASK, + pdata->ch3_output_mapping + << STA32X_CxCFG_OM_SHIFT); /* initialize coefficient shadow RAM with reset values */ for (i = 4; i <= 49; i += 5) @@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec) return 0; } -static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case STA32X_CONFA ... STA32X_L2ATRT: - case STA32X_MPCC1 ... STA32X_FDRC2: - return 0; - } - return 1; -} - static const struct snd_soc_codec_driver sta32x_codec = { .probe = sta32x_probe, .remove = sta32x_remove, @@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = { .reg_defaults = sta32x_regs, .num_reg_defaults = ARRAY_SIZE(sta32x_regs), .cache_type = REGCACHE_RBTREE, - .volatile_reg = sta32x_reg_is_volatile, + .wr_table = &sta32x_write_regs, + .rd_table = &sta32x_read_regs, + .volatile_table = &sta32x_volatile_regs, }; +#ifdef CONFIG_OF +static const struct of_device_id st32x_dt_ids[] = { + { .compatible = "st,sta32x", }, + { } +}; +MODULE_DEVICE_TABLE(of, st32x_dt_ids); + +static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x) +{ + struct device_node *np = dev->of_node; + struct sta32x_platform_data *pdata; + u16 tmp; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + of_property_read_u8(np, "st,output-conf", + &pdata->output_conf); + of_property_read_u8(np, "st,ch1-output-mapping", + &pdata->ch1_output_mapping); + of_property_read_u8(np, "st,ch2-output-mapping", + &pdata->ch2_output_mapping); + of_property_read_u8(np, "st,ch3-output-mapping", + &pdata->ch3_output_mapping); + + if (of_get_property(np, "st,thermal-warning-recovery", NULL)) + pdata->thermal_warning_recovery = 1; + if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) + pdata->thermal_warning_adjustment = 1; + if (of_get_property(np, "st,needs_esd_watchdog", NULL)) + pdata->needs_esd_watchdog = 1; + + tmp = 140; + of_property_read_u16(np, "st,drop-compensation-ns", &tmp); + pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20; + + /* CONFE */ + if (of_get_property(np, "st,max-power-use-mpcc", NULL)) + pdata->max_power_use_mpcc = 1; + + if (of_get_property(np, "st,max-power-correction", NULL)) + pdata->max_power_correction = 1; + + if (of_get_property(np, "st,am-reduction-mode", NULL)) + pdata->am_reduction_mode = 1; + + if (of_get_property(np, "st,odd-pwm-speed-mode", NULL)) + pdata->odd_pwm_speed_mode = 1; + + /* CONFF */ + if (of_get_property(np, "st,invalid-input-detect-mute", NULL)) + pdata->invalid_input_detect_mute = 1; + + sta32x->pdata = pdata; + + return 0; +} +#endif + static int sta32x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct device *dev = &i2c->dev; struct sta32x_priv *sta32x; int ret, i; @@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, if (!sta32x) return -ENOMEM; + mutex_init(&sta32x->coeff_lock); + sta32x->pdata = dev_get_platdata(dev); + +#ifdef CONFIG_OF + if (dev->of_node) { + ret = sta32x_probe_dt(dev, sta32x); + if (ret < 0) + return ret; + } +#endif + + /* GPIOs */ + sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset"); + if (IS_ERR(sta32x->gpiod_nreset)) { + ret = PTR_ERR(sta32x->gpiod_nreset); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + sta32x->gpiod_nreset = NULL; + } else { + gpiod_direction_output(sta32x->gpiod_nreset, 0); + } + /* regulators */ for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) sta32x->supplies[i].supply = sta32x_supply_names[i]; @@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap); if (IS_ERR(sta32x->regmap)) { ret = PTR_ERR(sta32x->regmap); - dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); + dev_err(dev, "Failed to init regmap: %d\n", ret); return ret; } i2c_set_clientdata(i2c, sta32x); - ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); - if (ret != 0) - dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); + ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1); + if (ret < 0) + dev_err(dev, "Failed to register codec (%d)\n", ret); return ret; } @@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = { .driver = { .name = "sta32x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(st32x_dt_ids), }, .probe = sta32x_i2c_probe, .remove = sta32x_i2c_remove, diff --git a/sound/soc/codecs/sta32x.h b/sound/soc/codecs/sta32x.h index d8e32a6262e..d3191c983d7 100644 --- a/sound/soc/codecs/sta32x.h +++ b/sound/soc/codecs/sta32x.h @@ -131,7 +131,7 @@ #define STA32X_CONFF_OCFG_MASK 0x03 #define STA32X_CONFF_OCFG_SHIFT 0 #define STA32X_CONFF_IDE 0x04 -#define STA32X_CONFF_IDE_SHIFT 3 +#define STA32X_CONFF_IDE_SHIFT 2 #define STA32X_CONFF_BCLE 0x08 #define STA32X_CONFF_ECLE 0x20 #define STA32X_CONFF_PWDN 0x40 diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index dc3223d6eca..c86dd9aae15 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -349,7 +349,8 @@ static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg, static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); unsigned int reg = AIC31XX_DACFLAG1; unsigned int mask; @@ -377,7 +378,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, reg = AIC31XX_ADCFLAG; break; default: - dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n", + dev_err(codec->dev, "Unknown widget '%s' calling %s\n", w->name, __func__); return -EINVAL; } @@ -388,7 +389,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100); default: - dev_dbg(w->codec->dev, + dev_dbg(codec->dev, "Unhandled dapm widget event %d from %s\n", event, w->name); } @@ -433,7 +434,7 @@ static const struct snd_kcontrol_new aic31xx_dapm_spr_switch = static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); switch (event) { diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b7ebce054b4..51c4713ac6e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -87,6 +87,7 @@ struct aic3x_priv { #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 +#define AIC3X_MODEL_3104 3 u16 model; /* Selects the micbias voltage */ @@ -197,7 +198,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -316,52 +317,37 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { * only for swapped L-to-R and R-to-L routes. See below stereo controls * for direct L-to-L and R-to-R routes. */ - SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume", - LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume", PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume", DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume", - LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume", PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume", DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume", - LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume", PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume", DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume", - LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume", PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume", DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume", - LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume", PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume", DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume", - LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume", PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume", DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), /* Stereo output controls for direct L-to-L and R-to-R routes */ - SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume", - LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("Line PGA Bypass Volume", PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), @@ -369,9 +355,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", - LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("HP PGA Bypass Volume", PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), @@ -379,9 +362,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", - LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume", PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), @@ -424,6 +404,45 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum), }; +/* For other than tlv320aic3104 */ +static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = { + /* + * Output controls that map to output mixer switches. Note these are + * only for swapped L-to-R and R-to-L routes. See below stereo controls + * for direct L-to-L and R-to-R routes. + */ + SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume", + LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume", + LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume", + LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume", + LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume", + LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume", + LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), + + /* Stereo output controls for direct L-to-L and R-to-R routes */ + SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume", + LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, + 0, 118, 1, output_stage_tlv), + + SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", + LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, + 0, 118, 1, output_stage_tlv), + + SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", + LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, + 0, 118, 1, output_stage_tlv), +}; + static const struct snd_kcontrol_new aic3x_mono_controls[] = { SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, @@ -464,22 +483,24 @@ SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum); /* Left Line Mixer */ static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), }; /* Right Line Mixer */ static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), }; /* Mono Mixer */ @@ -494,42 +515,46 @@ static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = { /* Left HP Mixer */ static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0), }; /* Right HP Mixer */ static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), }; /* Left HPCOM Mixer */ static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0), }; /* Right HPCOM Mixer */ static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; /* Left PGA Mixer */ @@ -550,6 +575,22 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; +/* Left PGA Mixer for tlv320aic3104 */ +static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = { + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), +}; + +/* Right PGA Mixer for tlv320aic3104 */ +static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = { + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), +}; + /* Left Line1 Mux */ static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum); @@ -593,26 +634,56 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), - SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_left_pga_mixer_controls[0], - ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1l_mux_controls), SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1r_mux_controls), - SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line2_mux_controls), /* Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), - SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_right_pga_mixer_controls[0], - ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1l_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1r_mux_controls), + + /* Mic Bias */ + SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, + mic_bias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("LLOUT"), + SND_SOC_DAPM_OUTPUT("RLOUT"), + SND_SOC_DAPM_OUTPUT("HPLOUT"), + SND_SOC_DAPM_OUTPUT("HPROUT"), + SND_SOC_DAPM_OUTPUT("HPLCOM"), + SND_SOC_DAPM_OUTPUT("HPRCOM"), + + SND_SOC_DAPM_INPUT("LINE1L"), + SND_SOC_DAPM_INPUT("LINE1R"), + + /* + * Virtual output pin to detection block inside codec. This can be + * used to keep codec bias on if gpio or detection features are needed. + * Force pin on or construct a path with an input jack and mic bias + * widgets. + */ + SND_SOC_DAPM_OUTPUT("Detection"), +}; + +/* For other than tlv320aic3104 */ +static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = { + /* Inputs to Left ADC */ + SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_pga_mixer_controls[0], + ARRAY_SIZE(aic3x_left_pga_mixer_controls)), + SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, + &aic3x_left_line2_mux_controls), + + /* Inputs to Right ADC */ + SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_pga_mixer_controls[0], + ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line2_mux_controls), @@ -637,11 +708,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), - /* Mic Bias */ - SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, - mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - /* Output mixers */ SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_line_mixer_controls[0], @@ -662,27 +728,46 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_right_hpcom_mixer_controls[0], ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)), - SND_SOC_DAPM_OUTPUT("LLOUT"), - SND_SOC_DAPM_OUTPUT("RLOUT"), - SND_SOC_DAPM_OUTPUT("HPLOUT"), - SND_SOC_DAPM_OUTPUT("HPROUT"), - SND_SOC_DAPM_OUTPUT("HPLCOM"), - SND_SOC_DAPM_OUTPUT("HPRCOM"), - SND_SOC_DAPM_INPUT("MIC3L"), SND_SOC_DAPM_INPUT("MIC3R"), - SND_SOC_DAPM_INPUT("LINE1L"), - SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), SND_SOC_DAPM_INPUT("LINE2R"), +}; - /* - * Virtual output pin to detection block inside codec. This can be - * used to keep codec bias on if gpio or detection features are needed. - * Force pin on or construct a path with an input jack and mic bias - * widgets. - */ - SND_SOC_DAPM_OUTPUT("Detection"), +/* For tlv320aic3104 */ +static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = { + /* Inputs to Left ADC */ + SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3104_left_pga_mixer_controls[0], + ARRAY_SIZE(aic3104_left_pga_mixer_controls)), + + /* Inputs to Right ADC */ + SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3104_right_pga_mixer_controls[0], + ARRAY_SIZE(aic3104_right_pga_mixer_controls)), + + /* Output mixers */ + SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_line_mixer_controls[0], + ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_line_mixer_controls[0], + ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_hp_mixer_controls[0], + ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_hp_mixer_controls[0], + ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_hpcom_mixer_controls[0], + ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_hpcom_mixer_controls[0], + ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2), + + SND_SOC_DAPM_INPUT("MIC2L"), + SND_SOC_DAPM_INPUT("MIC2R"), }; static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = { @@ -712,17 +797,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line1R Mux", "single-ended", "LINE1R"}, {"Left Line1R Mux", "differential", "LINE1R"}, - {"Left Line2L Mux", "single-ended", "LINE2L"}, - {"Left Line2L Mux", "differential", "LINE2L"}, - {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, - {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, - {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, - {"Left ADC", NULL, "GPIO1 dmic modclk"}, /* Right Input */ {"Right Line1R Mux", "single-ended", "LINE1R"}, @@ -730,25 +808,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line1L Mux", "single-ended", "LINE1L"}, {"Right Line1L Mux", "differential", "LINE1L"}, - {"Right Line2R Mux", "single-ended", "LINE2R"}, - {"Right Line2R Mux", "differential", "LINE2R"}, - {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, - {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, - {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, - {"Right ADC", NULL, "GPIO1 dmic modclk"}, - - /* - * Logical path between digital mic enable and GPIO1 modulator clock - * output function - */ - {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, /* Left DAC Output */ {"Left DAC Mux", "DAC_L1", "Left DAC"}, @@ -761,10 +824,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R3", "Right DAC"}, /* Left Line Output */ - {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -773,10 +834,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LLOUT", NULL, "Left Line Out"}, /* Right Line Output */ - {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -785,10 +844,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"RLOUT", NULL, "Right Line Out"}, /* Left HP Output */ - {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -797,10 +854,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPLOUT", NULL, "Left HP Out"}, /* Right HP Output */ - {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -809,10 +864,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPROUT", NULL, "Right HP Out"}, /* Left HPCOM Output */ - {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -823,10 +876,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPLCOM", NULL, "Left HP Com"}, /* Right HPCOM Output */ - {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -839,6 +890,72 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPRCOM", NULL, "Right HP Com"}, }; +/* For other than tlv320aic3104 */ +static const struct snd_soc_dapm_route intercon_extra[] = { + /* Left Input */ + {"Left Line2L Mux", "single-ended", "LINE2L"}, + {"Left Line2L Mux", "differential", "LINE2L"}, + + {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, + {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, + + {"Left ADC", NULL, "GPIO1 dmic modclk"}, + + /* Right Input */ + {"Right Line2R Mux", "single-ended", "LINE2R"}, + {"Right Line2R Mux", "differential", "LINE2R"}, + + {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, + {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, + + {"Right ADC", NULL, "GPIO1 dmic modclk"}, + + /* + * Logical path between digital mic enable and GPIO1 modulator clock + * output function + */ + {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, + {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, + {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, + + /* Left Line Output */ + {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right Line Output */ + {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Left HP Output */ + {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right HP Output */ + {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Left HPCOM Output */ + {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right HPCOM Output */ + {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, +}; + +/* For tlv320aic3104 */ +static const struct snd_soc_dapm_route intercon_extra_3104[] = { + /* Left Input */ + {"Left PGA Mixer", "Mic2L Switch", "MIC2L"}, + {"Left PGA Mixer", "Mic2R Switch", "MIC2R"}, + + /* Right Input */ + {"Right PGA Mixer", "Mic2L Switch", "MIC2L"}, + {"Right PGA Mixer", "Mic2R Switch", "MIC2R"}, +}; + static const struct snd_soc_dapm_route intercon_mono[] = { /* Mono Output */ {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, @@ -867,17 +984,31 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets, + ARRAY_SIZE(aic3x_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra, + ARRAY_SIZE(intercon_extra)); snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets, ARRAY_SIZE(aic3x_dapm_mono_widgets)); snd_soc_dapm_add_routes(dapm, intercon_mono, ARRAY_SIZE(intercon_mono)); break; case AIC3X_MODEL_3007: + snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets, + ARRAY_SIZE(aic3x_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra, + ARRAY_SIZE(intercon_extra)); snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets, ARRAY_SIZE(aic3007_dapm_widgets)); snd_soc_dapm_add_routes(dapm, intercon_3007, ARRAY_SIZE(intercon_3007)); break; + case AIC3X_MODEL_3104: + snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets, + ARRAY_SIZE(aic3104_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra_3104, + ARRAY_SIZE(intercon_extra_3104)); + break; } return 0; @@ -1046,7 +1177,7 @@ static int aic3x_prepare(struct snd_pcm_substream *substream, delay += aic3x->tdm_delay; /* Configure data delay */ - snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay); + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } @@ -1438,23 +1569,33 @@ static int aic3x_probe(struct snd_soc_codec *codec) aic3x_init(codec); if (aic3x->setup) { - /* setup GPIO functions */ - snd_soc_write(codec, AIC3X_GPIO1_REG, - (aic3x->setup->gpio_func[0] & 0xf) << 4); - snd_soc_write(codec, AIC3X_GPIO2_REG, - (aic3x->setup->gpio_func[1] & 0xf) << 4); + if (aic3x->model != AIC3X_MODEL_3104) { + /* setup GPIO functions */ + snd_soc_write(codec, AIC3X_GPIO1_REG, + (aic3x->setup->gpio_func[0] & 0xf) << 4); + snd_soc_write(codec, AIC3X_GPIO2_REG, + (aic3x->setup->gpio_func[1] & 0xf) << 4); + } else { + dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n"); + } } switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls, + ARRAY_SIZE(aic3x_extra_snd_controls)); snd_soc_add_codec_controls(codec, aic3x_mono_controls, ARRAY_SIZE(aic3x_mono_controls)); break; case AIC3X_MODEL_3007: + snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls, + ARRAY_SIZE(aic3x_extra_snd_controls)); snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); break; + case AIC3X_MODEL_3104: + break; } /* set mic bias voltage */ @@ -1522,6 +1663,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic33", AIC3X_MODEL_33 }, { "tlv320aic3007", AIC3X_MODEL_3007 }, { "tlv320aic3106", AIC3X_MODEL_3X }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -1673,6 +1815,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = { { .compatible = "ti,tlv320aic33" }, { .compatible = "ti,tlv320aic3007" }, { .compatible = "ti,tlv320aic3106" }, + { .compatible = "ti,tlv320aic3104" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 0fe2ced5b09..4e3e607dec1 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -423,17 +423,18 @@ exit: static int dac33_playback_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (likely(dac33->substream)) { - dac33_calculate_times(dac33->substream, w->codec); - dac33_prepare_chip(dac33->substream, w->codec); + dac33_calculate_times(dac33->substream, codec); + dac33_prepare_chip(dac33->substream, codec); } break; case SND_SOC_DAPM_POST_PMD: - dac33_disable_digital(w->codec); + dac33_disable_digital(codec); break; } return 0; diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 1d1205702d2..9fd80ac1897 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -20,6 +20,8 @@ #include <sound/jack.h> #include <sound/soc.h> +#include "ts3a227e.h" + struct ts3a227e { struct regmap *regmap; struct snd_soc_jack *jack; @@ -79,6 +81,10 @@ static const int ts3a227e_buttons[] = { /* TS3A227E_REG_SETTING_2 0x05 */ #define KP_ENABLE 0x04 +/* TS3A227E_REG_SETTING_3 0x06 */ +#define MICBIAS_SETTING_SFT (3) +#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT) + /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ #define TYPE_3_POLE 0x01 #define TYPE_4_POLE_OMTP 0x02 @@ -221,9 +227,9 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component, struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); ts3a227e->jack = jack; ts3a227e_jack_report(ts3a227e); @@ -248,12 +254,28 @@ static const struct regmap_config ts3a227e_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), }; +static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np) +{ + u32 micbias; + int err; + + err = of_property_read_u32(np, "ti,micbias", &micbias); + if (!err) { + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, + MICBIAS_SETTING_MASK, + (micbias & 0x07) << MICBIAS_SETTING_SFT); + } + + return 0; +} + static int ts3a227e_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct ts3a227e *ts3a227e; struct device *dev = &i2c->dev; int ret; + unsigned int acc_reg; ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL); if (ts3a227e == NULL) @@ -265,6 +287,14 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, if (IS_ERR(ts3a227e->regmap)) return PTR_ERR(ts3a227e->regmap); + if (dev->of_node) { + ret = ts3a227e_parse_dt(ts3a227e, dev->of_node); + if (ret) { + dev_err(dev, "Failed to parse device tree: %d\n", ret); + return ret; + } + } + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "TS3A227E", ts3a227e); @@ -283,6 +313,11 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, INTB_DISABLE | ADC_COMPLETE_INT_DISABLE, ADC_COMPLETE_INT_DISABLE); + /* Read jack status because chip might not trigger interrupt at boot. */ + regmap_read(ts3a227e->regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); + ts3a227e_new_jack_state(ts3a227e, acc_reg); + ts3a227e_jack_report(ts3a227e); + return 0; } diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 44af3188afb..d04693e9cf9 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -567,12 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ struct snd_kcontrol *kcontrol, int event) \ { \ - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); \ + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \ \ switch (event) { \ case SND_SOC_DAPM_POST_PMU: \ twl4030->pin_name##_enabled = 1; \ - twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \ + twl4030_write(codec, reg, twl4030_read(codec, reg)); \ break; \ case SND_SOC_DAPM_POST_PMD: \ twl4030->pin_name##_enabled = 0; \ @@ -621,12 +622,14 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) static int handsfreelpga_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); + switch (event) { case SND_SOC_DAPM_POST_PMU: - handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1); + handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1); break; case SND_SOC_DAPM_POST_PMD: - handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0); + handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0); break; } return 0; @@ -635,12 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w, static int handsfreerpga_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); + switch (event) { case SND_SOC_DAPM_POST_PMU: - handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1); + handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1); break; case SND_SOC_DAPM_POST_PMD: - handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0); + handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0); break; } return 0; @@ -649,19 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w, static int vibramux_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff); return 0; } static int apll_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); + switch (event) { case SND_SOC_DAPM_PRE_PMU: - twl4030_apll_enable(w->codec, 1); + twl4030_apll_enable(codec, 1); break; case SND_SOC_DAPM_POST_PMD: - twl4030_apll_enable(w->codec, 0); + twl4030_apll_enable(codec, 0); break; } return 0; @@ -670,23 +679,24 @@ static int apll_event(struct snd_soc_dapm_widget *w, static int aif_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); u8 audio_if; - audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF); + audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Enable AIF */ /* enable the PLL before we use it to clock the DAI */ - twl4030_apll_enable(w->codec, 1); + twl4030_apll_enable(codec, 1); - twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, + twl4030_write(codec, TWL4030_REG_AUDIO_IF, audio_if | TWL4030_AIF_EN); break; case SND_SOC_DAPM_POST_PMD: /* disable the DAI before we stop it's source PLL */ - twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, + twl4030_write(codec, TWL4030_REG_AUDIO_IF, audio_if & ~TWL4030_AIF_EN); - twl4030_apll_enable(w->codec, 0); + twl4030_apll_enable(codec, 0); break; } return 0; @@ -758,20 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) static int headsetlpga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: /* Do the ramp-up only once */ if (!twl4030->hsr_enabled) - headset_ramp(w->codec, 1); + headset_ramp(codec, 1); twl4030->hsl_enabled = 1; break; case SND_SOC_DAPM_POST_PMD: /* Do the ramp-down only if both headsetL/R is disabled */ if (!twl4030->hsr_enabled) - headset_ramp(w->codec, 0); + headset_ramp(codec, 0); twl4030->hsl_enabled = 0; break; @@ -782,20 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w, static int headsetrpga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: /* Do the ramp-up only once */ if (!twl4030->hsl_enabled) - headset_ramp(w->codec, 1); + headset_ramp(codec, 1); twl4030->hsr_enabled = 1; break; case SND_SOC_DAPM_POST_PMD: /* Do the ramp-down only if both headsetL/R is disabled */ if (!twl4030->hsl_enabled) - headset_ramp(w->codec, 0); + headset_ramp(codec, 0); twl4030->hsr_enabled = 0; break; @@ -806,7 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w, static int digimic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); struct twl4030_codec_data *pdata = twl4030->pdata; if (pdata && pdata->digimic_delay) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 90f47f988b3..aeec27b6f1a 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -234,7 +234,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u8 hslctl, hsrctl; /* @@ -261,7 +261,7 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int ret = 0; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 34ef65c52a7..8d9de49a505 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -683,7 +683,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = { static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); int ret; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index b80970dc2d2..ea09db585aa 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -775,7 +775,8 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); switch (w->reg) { case WM5100_CHANNEL_ENABLES_1: @@ -839,7 +840,7 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); int ret; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index f439ae05212..6d0fe0ac95a 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -28,6 +28,7 @@ #include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/registers.h> +#include <asm/unaligned.h> #include "arizona.h" #include "wm5102.h" @@ -580,7 +581,7 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = { static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; @@ -617,11 +618,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - uint16_t data; mutex_lock(&arizona->dac_comp_lock); - data = cpu_to_be16(arizona->dac_comp_coeff); - memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); + put_unaligned_be16(arizona->dac_comp_coeff, + ucontrol->value.bytes.data); mutex_unlock(&arizona->dac_comp_lock); return 0; @@ -1272,19 +1272,24 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 4456b38a3ef..fbaeddb3e90 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -134,7 +134,7 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = { static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; @@ -905,22 +905,28 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 574579b9887..c81a9eab3e3 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -259,7 +259,7 @@ static void wm8350_pga_work(struct work_struct *work) static int pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out; diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 8ee446987aa..b0d84e552fc 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -324,6 +324,7 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, static int outmixer_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 soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; u32 reg_shift = mc->shift; @@ -332,7 +333,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w, switch (reg_shift) { case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) : - reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1); + reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER1); if (reg & WM8400_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -340,7 +341,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w, } break; case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8): - reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2); + reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER2); if (reg & WM8400_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -348,7 +349,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w, } break; case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8): - reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER); if (reg & WM8400_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -356,7 +357,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w, } break; case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8): - reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER); if (reg & WM8400_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index b9211b42f6e..098c143f44d 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -217,7 +217,8 @@ SND_SOC_DAPM_INPUT("LLINEIN"), static int wm8731_check_osc(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); return wm8731->sysclk_type == WM8731_SYSCLK_XTAL; } @@ -717,6 +718,8 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, if (wm8731 == NULL) return -ENOMEM; + mutex_init(&wm8731->lock); + wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index f6847fdd6dd..eb0a1644ba1 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -323,7 +323,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("ROUT2"), SND_SOC_DAPM_OUTPUT("MONO1"), SND_SOC_DAPM_OUTPUT("OUT3"), - SND_SOC_DAPM_OUTPUT("VREF"), + SND_SOC_DAPM_VMID("VREF"), SND_SOC_DAPM_INPUT("LINPUT1"), SND_SOC_DAPM_INPUT("LINPUT2"), diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 180e7a09872..53e977da2f8 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -308,9 +308,7 @@ static const struct snd_soc_dapm_route wm8770_intercon[] = { static int vout12supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec; - - codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -327,9 +325,7 @@ static int vout12supply_event(struct snd_soc_dapm_widget *w, static int vout34supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec; - - codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 1315f764250..b2b0e68f707 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -648,7 +648,7 @@ static struct snd_soc_dai_driver wm8804_dai = { .symmetric_rates = 1 }; -static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .probe = wm8804_probe, .remove = wm8804_remove, .set_bias_level = wm8804_set_bias_level, @@ -664,7 +664,7 @@ static const struct of_device_id wm8804_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8804_of_match); -static struct regmap_config wm8804_regmap_config = { +static const struct regmap_config wm8804_regmap_config = { .reg_bits = 8, .val_bits = 8, diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3a0d4b7d692..2eb986c19b8 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -224,7 +224,7 @@ static void wm8900_reset(struct snd_soc_codec *codec) static int wm8900_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1); switch (event) { diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index cc6b0ef98a3..dde462c082b 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -260,7 +260,7 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w, static int wm8903_dcs_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); switch (event) { diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 4d2d2b1380d..d3b3f57668c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -673,7 +673,7 @@ static int cp_event(struct snd_soc_dapm_widget *w, static int sysclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -711,7 +711,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, static int out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); int reg, val; int dcs_mask; @@ -1076,10 +1076,13 @@ static const struct snd_soc_dapm_route adc_intercon[] = { { "Right Capture PGA", NULL, "Right Capture Mux" }, { "Right Capture PGA", NULL, "Right Capture Inverting Mux" }, - { "AIFOUTL", "Left", "ADCL" }, - { "AIFOUTL", "Right", "ADCR" }, - { "AIFOUTR", "Left", "ADCL" }, - { "AIFOUTR", "Right", "ADCR" }, + { "AIFOUTL Mux", "Left", "ADCL" }, + { "AIFOUTL Mux", "Right", "ADCR" }, + { "AIFOUTR Mux", "Left", "ADCL" }, + { "AIFOUTR Mux", "Right", "ADCR" }, + + { "AIFOUTL", NULL, "AIFOUTL Mux" }, + { "AIFOUTR", NULL, "AIFOUTR Mux" }, { "ADCL", NULL, "CLK_DSP" }, { "ADCL", NULL, "Left Capture PGA" }, @@ -1089,12 +1092,16 @@ static const struct snd_soc_dapm_route adc_intercon[] = { }; static const struct snd_soc_dapm_route dac_intercon[] = { - { "DACL", "Right", "AIFINR" }, - { "DACL", "Left", "AIFINL" }, + { "DACL Mux", "Left", "AIFINL" }, + { "DACL Mux", "Right", "AIFINR" }, + + { "DACR Mux", "Left", "AIFINL" }, + { "DACR Mux", "Right", "AIFINR" }, + + { "DACL", NULL, "DACL Mux" }, { "DACL", NULL, "CLK_DSP" }, - { "DACR", "Right", "AIFINR" }, - { "DACR", "Left", "AIFINL" }, + { "DACR", NULL, "DACR Mux" }, { "DACR", NULL, "CLK_DSP" }, { "Charge pump", NULL, "SYSCLK" }, @@ -2098,6 +2105,24 @@ static const struct regmap_config wm8904_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), }; +#ifdef CONFIG_OF +static enum wm8904_type wm8904_data = WM8904; +static enum wm8904_type wm8912_data = WM8912; + +static const struct of_device_id wm8904_of_match[] = { + { + .compatible = "wlf,wm8904", + .data = &wm8904_data, + }, { + .compatible = "wlf,wm8912", + .data = &wm8912_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, wm8904_of_match); +#endif + static int wm8904_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2125,7 +2150,17 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, return ret; } - wm8904->devtype = id->driver_data; + if (i2c->dev.of_node) { + const struct of_device_id *match; + + match = of_match_node(wm8904_of_match, i2c->dev.of_node); + if (match == NULL) + return -EINVAL; + wm8904->devtype = *((enum wm8904_type *)match->data); + } else { + wm8904->devtype = id->driver_data; + } + i2c_set_clientdata(i2c, wm8904); wm8904->pdata = i2c->dev.platform_data; @@ -2259,6 +2294,7 @@ static struct i2c_driver wm8904_i2c_driver = { .driver = { .name = "wm8904", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wm8904_of_match), }, .probe = wm8904_i2c_probe, .remove = wm8904_i2c_remove, diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 1173f7fef5a..1ab2d462afa 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -333,7 +333,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec) static int wm8955_sysclk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int ret = 0; /* Always disable the clocks - if we're doing reconfiguration this diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 3cbc82b3329..c799cca5abe 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -418,7 +418,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start) int wm8958_aif_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int i; switch (event) { diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 031a1ae71d9..cf8fecf97f2 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/slab.h> #include <sound/core.h> @@ -117,6 +118,7 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg) } struct wm8960_priv { + struct clk *mclk; struct regmap *regmap; int (*set_bias_level)(struct snd_soc_codec *, enum snd_soc_bias_level level); @@ -556,7 +558,7 @@ static struct { { 22050, 2 }, { 24000, 2 }, { 16000, 3 }, - { 11250, 4 }, + { 11025, 4 }, { 12000, 4 }, { 8000, 5 }, }; @@ -618,14 +620,38 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + int ret; switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: - /* Set VMID to 2x50k */ - snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_STANDBY: + if (!IS_ERR(wm8960->mclk)) { + ret = clk_prepare_enable(wm8960->mclk); + if (ret) { + dev_err(codec->dev, + "Failed to enable MCLK: %d\n", + ret); + return ret; + } + } + + /* Set VMID to 2x50k */ + snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); + break; + + case SND_SOC_BIAS_ON: + if (!IS_ERR(wm8960->mclk)) + clk_disable_unprepare(wm8960->mclk); + break; + + default: + break; + } + break; case SND_SOC_BIAS_STANDBY: @@ -674,7 +700,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - int reg; + int reg, ret; switch (level) { case SND_SOC_BIAS_ON: @@ -715,9 +741,22 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, WM8960_VREF, WM8960_VREF); msleep(100); + + if (!IS_ERR(wm8960->mclk)) { + ret = clk_prepare_enable(wm8960->mclk); + if (ret) { + dev_err(codec->dev, + "Failed to enable MCLK: %d\n", + ret); + return ret; + } + } break; case SND_SOC_BIAS_ON: + if (!IS_ERR(wm8960->mclk)) + clk_disable_unprepare(wm8960->mclk); + /* Enable anti-pop mode */ snd_soc_update_bits(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | @@ -1002,6 +1041,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, if (wm8960 == NULL) return -ENOMEM; + wm8960->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(wm8960->mclk)) { + if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } + wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index eeffd05384b..95e2c1bfc80 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -194,7 +194,7 @@ static bool wm8961_readable(struct device *dev, unsigned int reg) static int wm8961_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0); u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1); u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); @@ -286,7 +286,7 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, static int wm8961_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index d32d554f5b3..118b0034ba2 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1866,7 +1866,7 @@ static int cp_event(struct snd_soc_dapm_widget *w, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int timeout; int reg; int expected = (WM8962_DCS_STARTUP_DONE_HP1L | @@ -1960,7 +1960,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, static int out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int reg; switch (w->shift) { @@ -1993,7 +1993,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, static int dsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); switch (event) { diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index e418199155a..24968aa8618 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -244,7 +244,7 @@ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V, static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2); /* Use the DAC to gate LRC if active, otherwise use ADC */ @@ -813,7 +813,7 @@ static int wm8988_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .probe = wm8988_probe, .set_bias_level = wm8988_set_bias_level, .suspend_bias_off = true, @@ -826,7 +826,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), }; -static struct regmap_config wm8988_regmap = { +static const struct regmap_config wm8988_regmap = { .reg_bits = 7, .val_bits = 9, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 8a584229310..c93bffcb3cf 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -374,13 +374,14 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, static int outmixer_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); u32 reg_shift = kcontrol->private_value & 0xfff; int ret = 0; u16 reg; switch (reg_shift) { case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1); + reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER1); if (reg & WM8990_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -388,7 +389,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2); + reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER2); if (reg & WM8990_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -396,7 +397,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -404,7 +405,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index b0ac2c3e31b..49df0dc607e 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -382,13 +382,14 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = { static int outmixer_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); u32 reg_shift = kcontrol->private_value & 0xfff; int ret = 0; u16 reg; switch (reg_shift) { case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8): - reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1); + reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER1); if (reg & WM8991_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -397,7 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, break; case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8): - reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2); + reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER2); if (reg & WM8991_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -406,7 +407,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, break; case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8): - reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER); if (reg & WM8991_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -415,7 +416,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, break; case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8): - reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER); + reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER); if (reg & WM8991_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 53c6fe35949..2e70a270eb2 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -810,7 +810,7 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv), static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1b97de2e4e6..4fbc7689339 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -249,7 +249,8 @@ static int configure_clock(struct snd_soc_codec *codec) static int check_clk_sys(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + int reg = snd_soc_read(codec, WM8994_CLOCKING_1); const char *clk; /* Check what we're currently using for CLK_SYS */ @@ -806,7 +807,7 @@ static void active_dereference(struct snd_soc_codec *codec) static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -981,7 +982,7 @@ static void vmid_dereference(struct snd_soc_codec *codec) static int vmid_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1037,7 +1038,7 @@ static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec) static int aif1clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA; @@ -1135,7 +1136,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, static int aif2clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int i; int dac; int adc; @@ -1220,7 +1221,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, static int aif1clk_late_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1238,7 +1239,7 @@ static int aif1clk_late_ev(struct snd_soc_dapm_widget *w, static int aif2clk_late_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1256,7 +1257,7 @@ static int aif2clk_late_ev(struct snd_soc_dapm_widget *w, static int late_enable_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1289,7 +1290,7 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w, static int late_disable_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -1331,7 +1332,7 @@ static int micbias_ev(struct snd_soc_dapm_widget *w, static int dac_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int mask = 1 << w->shift; snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, @@ -1372,7 +1373,7 @@ SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0), static int post_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); dev_dbg(codec->dev, "SRC status: %x\n", snd_soc_read(codec, WM8994_RATE_STATUS)); diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index c280f0a3a42..66103c2b012 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -44,7 +44,7 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = { "MICVDD" }; -static struct reg_default wm8995_reg_defaults[] = { +static const struct reg_default wm8995_reg_defaults[] = { { 0, 0x8995 }, { 5, 0x0100 }, { 16, 0x000b }, @@ -534,10 +534,11 @@ static void wm8995_update_class_w(struct snd_soc_codec *codec) static int check_clk_sys(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); unsigned int reg; const char *clk; - reg = snd_soc_read(source->codec, WM8995_CLOCKING_1); + reg = snd_soc_read(codec, WM8995_CLOCKING_1); /* Check what we're currently using for CLK_SYS */ if (reg & WM8995_SYSCLK_SRC) clk = "AIF2CLK"; @@ -560,9 +561,7 @@ static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, static int hp_supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec; - - codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -611,10 +610,9 @@ static void dc_servo_cmd(struct snd_soc_codec *codec, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int reg; - codec = w->codec; reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1); switch (event) { @@ -761,9 +759,7 @@ static int configure_clock(struct snd_soc_codec *codec) static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec; - - codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -2190,7 +2186,7 @@ static struct snd_soc_dai_driver wm8995_dai[] = { } }; -static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { +static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .probe = wm8995_probe, .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, @@ -2204,7 +2200,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), }; -static struct regmap_config wm8995_regmap = { +static const struct regmap_config wm8995_regmap = { .reg_bits = 16, .val_bits = 16, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index b1dcc11c1b2..dc92d5e4e94 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -599,7 +599,7 @@ static void wm8996_bg_disable(struct snd_soc_codec *codec) static int bg_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int ret = 0; switch (event) { @@ -634,7 +634,8 @@ static int cp_event(struct snd_soc_dapm_widget *w, static int rmv_short_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); /* Record which outputs we enabled */ switch (event) { @@ -758,7 +759,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, static int dcs_start(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 7e8bfe27566..a4d11770630 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -84,7 +84,7 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = { static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct regmap *regmap = arizona->regmap; const struct reg_default *patch = NULL; @@ -610,13 +610,16 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index b1d946facd5..13a3f335ea5 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -734,7 +734,7 @@ static int configure_clock(struct snd_soc_codec *codec) static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); /* This should be done on init() for bypass paths */ diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 6ffe8dc4f3f..60d243c904f 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -254,7 +254,7 @@ SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1, static int hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0); switch (event) { diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 3eddb18fefd..5cc457ef889 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -344,23 +344,27 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) struct snd_ac97 *ac97; int ret = 0; - ac97 = snd_soc_new_ac97_codec(codec); + ac97 = snd_soc_alloc_ac97_codec(codec); if (IS_ERR(ac97)) { ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; } - snd_soc_codec_set_drvdata(codec, ac97); - ret = wm9705_reset(codec); if (ret) - goto reset_err; + goto err_put_device; + + ret = device_add(&ac97->dev); + if (ret) + goto err_put_device; + + snd_soc_codec_set_drvdata(codec, ac97); return 0; -reset_err: - snd_soc_free_ac97_codec(ac97); +err_put_device: + put_device(&ac97->dev); return ret; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index e04643d2bb2..9517571e820 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -666,7 +666,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); int ret = 0; - wm9712->ac97 = snd_soc_new_ac97_codec(codec); + wm9712->ac97 = snd_soc_alloc_ac97_codec(codec); if (IS_ERR(wm9712->ac97)) { ret = PTR_ERR(wm9712->ac97); dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); @@ -675,15 +675,19 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) ret = wm9712_reset(codec, 0); if (ret < 0) - goto reset_err; + goto err_put_device; + + ret = device_add(&wm9712->ac97->dev); + if (ret) + goto err_put_device; /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); return 0; -reset_err: - snd_soc_free_ac97_codec(wm9712->ac97); +err_put_device: + put_device(&wm9712->ac97->dev); return ret; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 71b9d5b0734..68222917b39 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -217,7 +217,7 @@ SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 status, rate; if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD)) @@ -1225,7 +1225,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); int ret = 0, reg; - wm9713->ac97 = snd_soc_new_ac97_codec(codec); + wm9713->ac97 = snd_soc_alloc_ac97_codec(codec); if (IS_ERR(wm9713->ac97)) return PTR_ERR(wm9713->ac97); @@ -1234,7 +1234,11 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); if (ret < 0) - goto reset_err; + goto err_put_device; + + ret = device_add(&wm9713->ac97->dev); + if (ret) + goto err_put_device; /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; @@ -1242,8 +1246,8 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) return 0; -reset_err: - snd_soc_free_ac97_codec(wm9713->ac97); +err_put_device: + put_device(&wm9713->ac97->dev); return ret; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 720d6e85298..ff67b334065 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1373,7 +1373,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; struct wm_adsp_alg_region *alg_region; @@ -1605,7 +1605,7 @@ err: int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; @@ -1626,7 +1626,7 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event); int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; struct wm_adsp_alg_region *alg_region; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 374537d5e17..8366e19657a 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -500,7 +500,7 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, static int hp_supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -542,7 +542,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0); switch (event) { @@ -594,7 +594,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, static int earpiece_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA; switch (event) { @@ -619,7 +619,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w, static int lineout_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); bool *flag; @@ -649,7 +649,7 @@ static int lineout_event(struct snd_soc_dapm_widget *w, static int micbias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); switch (w->shift) { |