1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a96d2ba2SJiri Prchal /* ALSA SoC TLV320AIC3X codec driver
344d0a879SVladimir Barinov *
4d6b52039SVladimir Barinov * Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
544d0a879SVladimir Barinov * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
644d0a879SVladimir Barinov *
744d0a879SVladimir Barinov * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
844d0a879SVladimir Barinov *
944d0a879SVladimir Barinov * Notes:
1044d0a879SVladimir Barinov * The AIC3X is a driver for a low power stereo audio
116184f105SRandolph Chung * codecs aic31, aic32, aic33, aic3007.
1244d0a879SVladimir Barinov *
1344d0a879SVladimir Barinov * It supports full aic33 codec functionality.
146184f105SRandolph Chung * The compatibility with aic32, aic31 and aic3007 is as follows:
156184f105SRandolph Chung * aic32/aic3007 | aic31
1644d0a879SVladimir Barinov * ---------------------------------------
1744d0a879SVladimir Barinov * MONO_LOUT -> N/A | MONO_LOUT -> N/A
1844d0a879SVladimir Barinov * | IN1L -> LINE1L
1944d0a879SVladimir Barinov * | IN1R -> LINE1R
2044d0a879SVladimir Barinov * | IN2L -> LINE2L
2144d0a879SVladimir Barinov * | IN2R -> LINE2R
2244d0a879SVladimir Barinov * | MIC3L/R -> N/A
2344d0a879SVladimir Barinov * truncated internal functionality in
2444d0a879SVladimir Barinov * accordance with documentation
2544d0a879SVladimir Barinov * ---------------------------------------
2644d0a879SVladimir Barinov *
2744d0a879SVladimir Barinov * Hence the machine layer should disable unsupported inputs/outputs by
28a5302181SLiam Girdwood * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc.
2944d0a879SVladimir Barinov */
3044d0a879SVladimir Barinov
3144d0a879SVladimir Barinov #include <linux/module.h>
3244d0a879SVladimir Barinov #include <linux/moduleparam.h>
3344d0a879SVladimir Barinov #include <linux/init.h>
3444d0a879SVladimir Barinov #include <linux/delay.h>
35*a984d833SDmitry Torokhov #include <linux/err.h>
3644d0a879SVladimir Barinov #include <linux/pm.h>
3744d0a879SVladimir Barinov #include <linux/i2c.h>
38*a984d833SDmitry Torokhov #include <linux/gpio/consumer.h>
3907779fddSJarkko Nikula #include <linux/regulator/consumer.h>
40b3b70786SSachin Kamat #include <linux/of.h>
415a0e3ad6STejun Heo #include <linux/slab.h>
4244d0a879SVladimir Barinov #include <sound/core.h>
4344d0a879SVladimir Barinov #include <sound/pcm.h>
4444d0a879SVladimir Barinov #include <sound/pcm_params.h>
4544d0a879SVladimir Barinov #include <sound/soc.h>
4644d0a879SVladimir Barinov #include <sound/initval.h>
477565fc38SJarkko Nikula #include <sound/tlv.h>
4844d0a879SVladimir Barinov
4944d0a879SVladimir Barinov #include "tlv320aic3x.h"
5044d0a879SVladimir Barinov
5107779fddSJarkko Nikula #define AIC3X_NUM_SUPPLIES 4
5207779fddSJarkko Nikula static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
5307779fddSJarkko Nikula "IOVDD", /* I/O Voltage */
5407779fddSJarkko Nikula "DVDD", /* Digital Core Voltage */
5507779fddSJarkko Nikula "AVDD", /* Analog DAC Voltage */
5607779fddSJarkko Nikula "DRVDD", /* ADC Analog and Output Driver Voltage */
5707779fddSJarkko Nikula };
5844d0a879SVladimir Barinov
595a895f8aSJarkko Nikula struct aic3x_priv;
605a895f8aSJarkko Nikula
615a895f8aSJarkko Nikula struct aic3x_disable_nb {
625a895f8aSJarkko Nikula struct notifier_block nb;
635a895f8aSJarkko Nikula struct aic3x_priv *aic3x;
645a895f8aSJarkko Nikula };
655a895f8aSJarkko Nikula
66426c7bf4SDmitry Torokhov struct aic3x_setup_data {
67426c7bf4SDmitry Torokhov unsigned int gpio_func[2];
68426c7bf4SDmitry Torokhov };
69426c7bf4SDmitry Torokhov
7044d0a879SVladimir Barinov /* codec private data */
7144d0a879SVladimir Barinov struct aic3x_priv {
72749ad545SKuninori Morimoto struct snd_soc_component *component;
732a6fedecSMark Brown struct regmap *regmap;
7407779fddSJarkko Nikula struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
755a895f8aSJarkko Nikula struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
76f0fba2adSLiam Girdwood struct aic3x_setup_data *setup;
7744d0a879SVladimir Barinov unsigned int sysclk;
7836849409SPeter Ujfalusi unsigned int dai_fmt;
7936849409SPeter Ujfalusi unsigned int tdm_delay;
803e8f5263SJyri Sarha unsigned int slot_width;
8144d0a879SVladimir Barinov int master;
82*a984d833SDmitry Torokhov struct gpio_desc *gpio_reset;
83*a984d833SDmitry Torokhov bool shared_reset;
846c1a7d40SJarkko Nikula int power;
856184f105SRandolph Chung u16 model;
86e2e8bfdfSHebbar Gururaja
87e2e8bfdfSHebbar Gururaja /* Selects the micbias voltage */
88e2e8bfdfSHebbar Gururaja enum aic3x_micbias_voltage micbias_vg;
8919b0fa11SPeter Ujfalusi /* Output Common-Mode Voltage */
9019b0fa11SPeter Ujfalusi u8 ocmv;
9144d0a879SVladimir Barinov };
9244d0a879SVladimir Barinov
932a6fedecSMark Brown static const struct reg_default aic3x_reg[] = {
942a6fedecSMark Brown { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x10 },
952a6fedecSMark Brown { 4, 0x04 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
962a6fedecSMark Brown { 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x01 },
972a6fedecSMark Brown { 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x80 },
982a6fedecSMark Brown { 16, 0x80 }, { 17, 0xff }, { 18, 0xff }, { 19, 0x78 },
992a6fedecSMark Brown { 20, 0x78 }, { 21, 0x78 }, { 22, 0x78 }, { 23, 0x78 },
1002a6fedecSMark Brown { 24, 0x78 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0xfe },
1012a6fedecSMark Brown { 28, 0x00 }, { 29, 0x00 }, { 30, 0xfe }, { 31, 0x00 },
1022a6fedecSMark Brown { 32, 0x18 }, { 33, 0x18 }, { 34, 0x00 }, { 35, 0x00 },
1032a6fedecSMark Brown { 36, 0x00 }, { 37, 0x00 }, { 38, 0x00 }, { 39, 0x00 },
1042a6fedecSMark Brown { 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x80 },
1052a6fedecSMark Brown { 44, 0x80 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 },
1062a6fedecSMark Brown { 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x04 },
1072a6fedecSMark Brown { 52, 0x00 }, { 53, 0x00 }, { 54, 0x00 }, { 55, 0x00 },
1082a6fedecSMark Brown { 56, 0x00 }, { 57, 0x00 }, { 58, 0x04 }, { 59, 0x00 },
1092a6fedecSMark Brown { 60, 0x00 }, { 61, 0x00 }, { 62, 0x00 }, { 63, 0x00 },
1102a6fedecSMark Brown { 64, 0x00 }, { 65, 0x04 }, { 66, 0x00 }, { 67, 0x00 },
1112a6fedecSMark Brown { 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 },
1122a6fedecSMark Brown { 72, 0x04 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 },
1132a6fedecSMark Brown { 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 },
1142a6fedecSMark Brown { 80, 0x00 }, { 81, 0x00 }, { 82, 0x00 }, { 83, 0x00 },
1152a6fedecSMark Brown { 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 },
1162a6fedecSMark Brown { 88, 0x00 }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 },
1172a6fedecSMark Brown { 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 },
1182a6fedecSMark Brown { 96, 0x00 }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 },
1192a6fedecSMark Brown { 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 },
1202a6fedecSMark Brown { 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 },
1212a6fedecSMark Brown { 108, 0x00 }, { 109, 0x00 },
1222a6fedecSMark Brown };
1232a6fedecSMark Brown
aic3x_volatile_reg(struct device * dev,unsigned int reg)12463c3194bSPeter Ujfalusi static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
12563c3194bSPeter Ujfalusi {
12663c3194bSPeter Ujfalusi switch (reg) {
12763c3194bSPeter Ujfalusi case AIC3X_RESET:
12863c3194bSPeter Ujfalusi return true;
12963c3194bSPeter Ujfalusi default:
13063c3194bSPeter Ujfalusi return false;
13163c3194bSPeter Ujfalusi }
13263c3194bSPeter Ujfalusi }
13363c3194bSPeter Ujfalusi
134a96d2ba2SJiri Prchal const struct regmap_config aic3x_regmap = {
1352a6fedecSMark Brown .max_register = DAC_ICC_ADJ,
1362a6fedecSMark Brown .reg_defaults = aic3x_reg,
1372a6fedecSMark Brown .num_reg_defaults = ARRAY_SIZE(aic3x_reg),
13863c3194bSPeter Ujfalusi
13963c3194bSPeter Ujfalusi .volatile_reg = aic3x_volatile_reg,
14063c3194bSPeter Ujfalusi
1412a6fedecSMark Brown .cache_type = REGCACHE_RBTREE,
14244d0a879SVladimir Barinov };
143a96d2ba2SJiri Prchal EXPORT_SYMBOL_GPL(aic3x_regmap);
14444d0a879SVladimir Barinov
14544d0a879SVladimir Barinov #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
1461476f66fSLars-Peter Clausen SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
1471476f66fSLars-Peter Clausen snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x)
14844d0a879SVladimir Barinov
14944d0a879SVladimir Barinov /*
15044d0a879SVladimir Barinov * All input lines are connected when !0xf and disconnected with 0xf bit field,
15144d0a879SVladimir Barinov * so we have to use specific dapm_put call for input mixer
15244d0a879SVladimir Barinov */
snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)15344d0a879SVladimir Barinov static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
15444d0a879SVladimir Barinov struct snd_ctl_elem_value *ucontrol)
15544d0a879SVladimir Barinov {
156749ad545SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
157749ad545SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
1584453dba5SEero Nurkkala struct soc_mixer_control *mc =
1594453dba5SEero Nurkkala (struct soc_mixer_control *)kcontrol->private_value;
1604453dba5SEero Nurkkala unsigned int reg = mc->reg;
1614453dba5SEero Nurkkala unsigned int shift = mc->shift;
1624453dba5SEero Nurkkala int max = mc->max;
1634453dba5SEero Nurkkala unsigned int mask = (1 << fls(max)) - 1;
1644453dba5SEero Nurkkala unsigned int invert = mc->invert;
1655d99d778SLars-Peter Clausen unsigned short val;
16668fb425bSFabio Estevam struct snd_soc_dapm_update update = {};
1675d99d778SLars-Peter Clausen int connect, change;
16844d0a879SVladimir Barinov
16944d0a879SVladimir Barinov val = (ucontrol->value.integer.value[0] & mask);
17044d0a879SVladimir Barinov
17144d0a879SVladimir Barinov mask = 0xf;
17244d0a879SVladimir Barinov if (val)
17344d0a879SVladimir Barinov val = mask;
17444d0a879SVladimir Barinov
1755d99d778SLars-Peter Clausen connect = !!val;
1765d99d778SLars-Peter Clausen
17744d0a879SVladimir Barinov if (invert)
17844d0a879SVladimir Barinov val = mask - val;
17944d0a879SVladimir Barinov
1805d99d778SLars-Peter Clausen mask <<= shift;
1815d99d778SLars-Peter Clausen val <<= shift;
18244d0a879SVladimir Barinov
183749ad545SKuninori Morimoto change = snd_soc_component_test_bits(component, reg, mask, val);
1845d99d778SLars-Peter Clausen if (change) {
1855d99d778SLars-Peter Clausen update.kcontrol = kcontrol;
1865d99d778SLars-Peter Clausen update.reg = reg;
1875d99d778SLars-Peter Clausen update.mask = mask;
1885d99d778SLars-Peter Clausen update.val = val;
18944d0a879SVladimir Barinov
190650a18acSLars-Peter Clausen snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect,
1915d99d778SLars-Peter Clausen &update);
1922894770eSAndreas Irestål }
1932894770eSAndreas Irestål
1945d99d778SLars-Peter Clausen return change;
19544d0a879SVladimir Barinov }
19644d0a879SVladimir Barinov
197e2e8bfdfSHebbar Gururaja /*
198e2e8bfdfSHebbar Gururaja * mic bias power on/off share the same register bits with
199e2e8bfdfSHebbar Gururaja * output voltage of mic bias. when power on mic bias, we
200e2e8bfdfSHebbar Gururaja * need reclaim it to voltage value.
201e2e8bfdfSHebbar Gururaja * 0x0 = Powered off
202e2e8bfdfSHebbar Gururaja * 0x1 = MICBIAS output is powered to 2.0V,
203e2e8bfdfSHebbar Gururaja * 0x2 = MICBIAS output is powered to 2.5V
204e2e8bfdfSHebbar Gururaja * 0x3 = MICBIAS output is connected to AVDD
205e2e8bfdfSHebbar Gururaja */
mic_bias_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)206e2e8bfdfSHebbar Gururaja static int mic_bias_event(struct snd_soc_dapm_widget *w,
207e2e8bfdfSHebbar Gururaja struct snd_kcontrol *kcontrol, int event)
208e2e8bfdfSHebbar Gururaja {
209749ad545SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
210749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
211e2e8bfdfSHebbar Gururaja
212e2e8bfdfSHebbar Gururaja switch (event) {
213e2e8bfdfSHebbar Gururaja case SND_SOC_DAPM_POST_PMU:
214e2e8bfdfSHebbar Gururaja /* change mic bias voltage to user defined */
215749ad545SKuninori Morimoto snd_soc_component_update_bits(component, MICBIAS_CTRL,
216e2e8bfdfSHebbar Gururaja MICBIAS_LEVEL_MASK,
217e2e8bfdfSHebbar Gururaja aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
218e2e8bfdfSHebbar Gururaja break;
219e2e8bfdfSHebbar Gururaja
220e2e8bfdfSHebbar Gururaja case SND_SOC_DAPM_PRE_PMD:
221749ad545SKuninori Morimoto snd_soc_component_update_bits(component, MICBIAS_CTRL,
222e2e8bfdfSHebbar Gururaja MICBIAS_LEVEL_MASK, 0);
223e2e8bfdfSHebbar Gururaja break;
224e2e8bfdfSHebbar Gururaja }
225e2e8bfdfSHebbar Gururaja return 0;
226e2e8bfdfSHebbar Gururaja }
227e2e8bfdfSHebbar Gururaja
228a60e654bSPeter Ujfalusi static const char * const aic3x_left_dac_mux[] = {
229a60e654bSPeter Ujfalusi "DAC_L1", "DAC_L3", "DAC_L2" };
230a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6,
231a60e654bSPeter Ujfalusi aic3x_left_dac_mux);
232a60e654bSPeter Ujfalusi
233a60e654bSPeter Ujfalusi static const char * const aic3x_right_dac_mux[] = {
234a60e654bSPeter Ujfalusi "DAC_R1", "DAC_R3", "DAC_R2" };
235a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4,
236a60e654bSPeter Ujfalusi aic3x_right_dac_mux);
237a60e654bSPeter Ujfalusi
238a60e654bSPeter Ujfalusi static const char * const aic3x_left_hpcom_mux[] = {
239a60e654bSPeter Ujfalusi "differential of HPLOUT", "constant VCM", "single-ended" };
240a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4,
241a60e654bSPeter Ujfalusi aic3x_left_hpcom_mux);
242a60e654bSPeter Ujfalusi
243a60e654bSPeter Ujfalusi static const char * const aic3x_right_hpcom_mux[] = {
244a60e654bSPeter Ujfalusi "differential of HPROUT", "constant VCM", "single-ended",
24544d0a879SVladimir Barinov "differential of HPLCOM", "external feedback" };
246a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3,
247a60e654bSPeter Ujfalusi aic3x_right_hpcom_mux);
24844d0a879SVladimir Barinov
249a60e654bSPeter Ujfalusi static const char * const aic3x_linein_mode_mux[] = {
250a60e654bSPeter Ujfalusi "single-ended", "differential" };
251a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7,
252a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
253a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7,
254a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
255a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7,
256a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
257a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7,
258a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
259a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7,
260a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
261a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7,
262a60e654bSPeter Ujfalusi aic3x_linein_mode_mux);
26344d0a879SVladimir Barinov
264a60e654bSPeter Ujfalusi static const char * const aic3x_adc_hpf[] = {
265a60e654bSPeter Ujfalusi "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
266a60e654bSPeter Ujfalusi static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4,
267a60e654bSPeter Ujfalusi aic3x_adc_hpf);
26844d0a879SVladimir Barinov
269a60e654bSPeter Ujfalusi static const char * const aic3x_agc_level[] = {
270a60e654bSPeter Ujfalusi "-5.5dB", "-8dB", "-10dB", "-12dB",
271a60e654bSPeter Ujfalusi "-14dB", "-17dB", "-20dB", "-24dB" };
272a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4,
273a60e654bSPeter Ujfalusi aic3x_agc_level);
274a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4,
275a60e654bSPeter Ujfalusi aic3x_agc_level);
276bb1daa80SJiri Prchal
277a60e654bSPeter Ujfalusi static const char * const aic3x_agc_attack[] = {
278a60e654bSPeter Ujfalusi "8ms", "11ms", "16ms", "20ms" };
279a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2,
280a60e654bSPeter Ujfalusi aic3x_agc_attack);
281a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2,
282a60e654bSPeter Ujfalusi aic3x_agc_attack);
283bb1daa80SJiri Prchal
284a60e654bSPeter Ujfalusi static const char * const aic3x_agc_decay[] = {
285a60e654bSPeter Ujfalusi "100ms", "200ms", "400ms", "500ms" };
286a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0,
287a60e654bSPeter Ujfalusi aic3x_agc_decay);
288a60e654bSPeter Ujfalusi static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0,
289a60e654bSPeter Ujfalusi aic3x_agc_decay);
290bb1daa80SJiri Prchal
29168d66269SMisael Lopez Cruz static const char * const aic3x_poweron_time[] = {
29268d66269SMisael Lopez Cruz "0us", "10us", "100us", "1ms", "10ms", "50ms",
29368d66269SMisael Lopez Cruz "100ms", "200ms", "400ms", "800ms", "2s", "4s" };
29468d66269SMisael Lopez Cruz static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4,
29568d66269SMisael Lopez Cruz aic3x_poweron_time);
29668d66269SMisael Lopez Cruz
29768d66269SMisael Lopez Cruz static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" };
29868d66269SMisael Lopez Cruz static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2,
29968d66269SMisael Lopez Cruz aic3x_rampup_step);
30068d66269SMisael Lopez Cruz
3017565fc38SJarkko Nikula /*
3027565fc38SJarkko Nikula * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
3037565fc38SJarkko Nikula */
3047565fc38SJarkko Nikula static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
3057565fc38SJarkko Nikula /* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */
3067565fc38SJarkko Nikula static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
3077565fc38SJarkko Nikula /*
3087565fc38SJarkko Nikula * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB.
3097565fc38SJarkko Nikula * Step size is approximately 0.5 dB over most of the scale but increasing
3107565fc38SJarkko Nikula * near the very low levels.
3117565fc38SJarkko Nikula * Define dB scale so that it is mostly correct for range about -55 to 0 dB
3127565fc38SJarkko Nikula * but having increasing dB difference below that (and where it doesn't count
3137565fc38SJarkko Nikula * so much). This setting shows -50 dB (actual is -50.3 dB) for register
3147565fc38SJarkko Nikula * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117.
3157565fc38SJarkko Nikula */
3167565fc38SJarkko Nikula static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
3177565fc38SJarkko Nikula
318bfa8130fSSaravanan Sekar /* Output volumes. From 0 to 9 dB in 1 dB steps */
319bfa8130fSSaravanan Sekar static const DECLARE_TLV_DB_SCALE(out_tlv, 0, 100, 0);
320bfa8130fSSaravanan Sekar
32144d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_snd_controls[] = {
32244d0a879SVladimir Barinov /* Output */
3237565fc38SJarkko Nikula SOC_DOUBLE_R_TLV("PCM Playback Volume",
3247565fc38SJarkko Nikula LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
32544d0a879SVladimir Barinov
326098b1718SJarkko Nikula /*
327098b1718SJarkko Nikula * Output controls that map to output mixer switches. Note these are
328098b1718SJarkko Nikula * only for swapped L-to-R and R-to-L routes. See below stereo controls
329098b1718SJarkko Nikula * for direct L-to-L and R-to-R routes.
330098b1718SJarkko Nikula */
331098b1718SJarkko Nikula SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
332098b1718SJarkko Nikula PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
333098b1718SJarkko Nikula SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
334098b1718SJarkko Nikula DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
335098b1718SJarkko Nikula
336098b1718SJarkko Nikula SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
337098b1718SJarkko Nikula PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
338098b1718SJarkko Nikula SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
339098b1718SJarkko Nikula DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
340098b1718SJarkko Nikula
341098b1718SJarkko Nikula SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
342098b1718SJarkko Nikula PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
343098b1718SJarkko Nikula SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
344098b1718SJarkko Nikula DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
345098b1718SJarkko Nikula
346098b1718SJarkko Nikula SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
347098b1718SJarkko Nikula PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
348098b1718SJarkko Nikula SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
349098b1718SJarkko Nikula DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
350098b1718SJarkko Nikula
351098b1718SJarkko Nikula SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
352098b1718SJarkko Nikula PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
353098b1718SJarkko Nikula SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
354098b1718SJarkko Nikula DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
355098b1718SJarkko Nikula
356098b1718SJarkko Nikula SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
357098b1718SJarkko Nikula PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
358098b1718SJarkko Nikula SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
359098b1718SJarkko Nikula DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
360098b1718SJarkko Nikula
361098b1718SJarkko Nikula /* Stereo output controls for direct L-to-L and R-to-R routes */
362098b1718SJarkko Nikula SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
363098b1718SJarkko Nikula PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
364098b1718SJarkko Nikula 0, 118, 1, output_stage_tlv),
3657565fc38SJarkko Nikula SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
3667565fc38SJarkko Nikula DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
3677565fc38SJarkko Nikula 0, 118, 1, output_stage_tlv),
36844d0a879SVladimir Barinov
369098b1718SJarkko Nikula SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
370098b1718SJarkko Nikula PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
371098b1718SJarkko Nikula 0, 118, 1, output_stage_tlv),
3727565fc38SJarkko Nikula SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
3737565fc38SJarkko Nikula DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
3747565fc38SJarkko Nikula 0, 118, 1, output_stage_tlv),
37544d0a879SVladimir Barinov
376098b1718SJarkko Nikula SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
377098b1718SJarkko Nikula PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
378098b1718SJarkko Nikula 0, 118, 1, output_stage_tlv),
3797565fc38SJarkko Nikula SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
3807565fc38SJarkko Nikula DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
3817565fc38SJarkko Nikula 0, 118, 1, output_stage_tlv),
382098b1718SJarkko Nikula
383bfa8130fSSaravanan Sekar /* Output pin controls */
384bfa8130fSSaravanan Sekar SOC_DOUBLE_R_TLV("Line Playback Volume", LLOPM_CTRL, RLOPM_CTRL, 4,
385bfa8130fSSaravanan Sekar 9, 0, out_tlv),
386098b1718SJarkko Nikula SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
387098b1718SJarkko Nikula 0x01, 0),
388bfa8130fSSaravanan Sekar SOC_DOUBLE_R_TLV("HP Playback Volume", HPLOUT_CTRL, HPROUT_CTRL, 4,
389bfa8130fSSaravanan Sekar 9, 0, out_tlv),
390098b1718SJarkko Nikula SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
391098b1718SJarkko Nikula 0x01, 0),
392bfa8130fSSaravanan Sekar SOC_DOUBLE_R_TLV("HPCOM Playback Volume", HPLCOM_CTRL, HPRCOM_CTRL,
393bfa8130fSSaravanan Sekar 4, 9, 0, out_tlv),
394f9bc0297SJarkko Nikula SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
39544d0a879SVladimir Barinov 0x01, 0),
39644d0a879SVladimir Barinov
39744d0a879SVladimir Barinov /*
39844d0a879SVladimir Barinov * Note: enable Automatic input Gain Controller with care. It can
39944d0a879SVladimir Barinov * adjust PGA to max value when ADC is on and will never go back.
40044d0a879SVladimir Barinov */
40144d0a879SVladimir Barinov SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
402a60e654bSPeter Ujfalusi SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum),
403a60e654bSPeter Ujfalusi SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum),
404a60e654bSPeter Ujfalusi SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum),
405a60e654bSPeter Ujfalusi SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum),
406a60e654bSPeter Ujfalusi SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum),
407a60e654bSPeter Ujfalusi SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum),
40844d0a879SVladimir Barinov
40977444191SJiri Prchal /* De-emphasis */
41077444191SJiri Prchal SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0),
41144d0a879SVladimir Barinov
41244d0a879SVladimir Barinov /* Input */
4137565fc38SJarkko Nikula SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
4147565fc38SJarkko Nikula 0, 119, 0, adc_tlv),
41544d0a879SVladimir Barinov SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
4164d20f70aSJarkko Nikula
417a60e654bSPeter Ujfalusi SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum),
41868d66269SMisael Lopez Cruz
41968d66269SMisael Lopez Cruz /* Pop reduction */
42068d66269SMisael Lopez Cruz SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum),
42168d66269SMisael Lopez Cruz SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
42244d0a879SVladimir Barinov };
42344d0a879SVladimir Barinov
4249503112dSJyri Sarha /* For other than tlv320aic3104 */
4259503112dSJyri Sarha static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = {
4269503112dSJyri Sarha /*
4279503112dSJyri Sarha * Output controls that map to output mixer switches. Note these are
4289503112dSJyri Sarha * only for swapped L-to-R and R-to-L routes. See below stereo controls
4299503112dSJyri Sarha * for direct L-to-L and R-to-R routes.
4309503112dSJyri Sarha */
4319503112dSJyri Sarha SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
4329503112dSJyri Sarha LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
4339503112dSJyri Sarha
4349503112dSJyri Sarha SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
4359503112dSJyri Sarha LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
4369503112dSJyri Sarha
4379503112dSJyri Sarha SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
4389503112dSJyri Sarha LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
4399503112dSJyri Sarha
4409503112dSJyri Sarha SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
4419503112dSJyri Sarha LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
4429503112dSJyri Sarha
4439503112dSJyri Sarha SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
4449503112dSJyri Sarha LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
4459503112dSJyri Sarha
4469503112dSJyri Sarha SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
4479503112dSJyri Sarha LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
4489503112dSJyri Sarha
4499503112dSJyri Sarha /* Stereo output controls for direct L-to-L and R-to-R routes */
4509503112dSJyri Sarha SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
4519503112dSJyri Sarha LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
4529503112dSJyri Sarha 0, 118, 1, output_stage_tlv),
4539503112dSJyri Sarha
4549503112dSJyri Sarha SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
4559503112dSJyri Sarha LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
4569503112dSJyri Sarha 0, 118, 1, output_stage_tlv),
4579503112dSJyri Sarha
4589503112dSJyri Sarha SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
4599503112dSJyri Sarha LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
4609503112dSJyri Sarha 0, 118, 1, output_stage_tlv),
4619503112dSJyri Sarha };
4629503112dSJyri Sarha
46358381da6SJan Weitzel static const struct snd_kcontrol_new aic3x_mono_controls[] = {
46458381da6SJan Weitzel SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
46558381da6SJan Weitzel LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
46658381da6SJan Weitzel 0, 118, 1, output_stage_tlv),
46758381da6SJan Weitzel SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
46858381da6SJan Weitzel PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
46958381da6SJan Weitzel 0, 118, 1, output_stage_tlv),
47058381da6SJan Weitzel SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
47158381da6SJan Weitzel DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
47258381da6SJan Weitzel 0, 118, 1, output_stage_tlv),
47358381da6SJan Weitzel
47458381da6SJan Weitzel SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
475bfa8130fSSaravanan Sekar SOC_SINGLE_TLV("Mono Playback Volume", MONOLOPM_CTRL, 4, 9, 0,
476bfa8130fSSaravanan Sekar out_tlv),
477bfa8130fSSaravanan Sekar
47858381da6SJan Weitzel };
47958381da6SJan Weitzel
4806184f105SRandolph Chung /*
4816184f105SRandolph Chung * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
4826184f105SRandolph Chung */
4836184f105SRandolph Chung static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
4846184f105SRandolph Chung
4856184f105SRandolph Chung static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
48614a95fe8SJarkko Nikula SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
4876184f105SRandolph Chung
48844d0a879SVladimir Barinov /* Left DAC Mux */
48944d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
490a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_left_dac_enum);
49144d0a879SVladimir Barinov
49244d0a879SVladimir Barinov /* Right DAC Mux */
49344d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
494a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_right_dac_enum);
49544d0a879SVladimir Barinov
49644d0a879SVladimir Barinov /* Left HPCOM Mux */
49744d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
498a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum);
49944d0a879SVladimir Barinov
50044d0a879SVladimir Barinov /* Right HPCOM Mux */
50144d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
502a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
50344d0a879SVladimir Barinov
504c3b79e05SJarkko Nikula /* Left Line Mixer */
505c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
506c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
507c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
508c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
509c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
5109503112dSJyri Sarha /* Not on tlv320aic3104 */
5119503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
5129503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
51344d0a879SVladimir Barinov };
51444d0a879SVladimir Barinov
515c3b79e05SJarkko Nikula /* Right Line Mixer */
516c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
517c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
518c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
519c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
520c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
5219503112dSJyri Sarha /* Not on tlv320aic3104 */
5229503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
5239503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
524c3b79e05SJarkko Nikula };
525c3b79e05SJarkko Nikula
526c3b79e05SJarkko Nikula /* Mono Mixer */
527c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
528c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
529c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
530c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
531c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
532c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
533c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
534c3b79e05SJarkko Nikula };
535c3b79e05SJarkko Nikula
536c3b79e05SJarkko Nikula /* Left HP Mixer */
537c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
538c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
539c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
540c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
541c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
5429503112dSJyri Sarha /* Not on tlv320aic3104 */
5439503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
5449503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
545c3b79e05SJarkko Nikula };
546c3b79e05SJarkko Nikula
547c3b79e05SJarkko Nikula /* Right HP Mixer */
548c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
549c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
550c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
551c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
552c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
5539503112dSJyri Sarha /* Not on tlv320aic3104 */
5549503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
5559503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
556c3b79e05SJarkko Nikula };
557c3b79e05SJarkko Nikula
558c3b79e05SJarkko Nikula /* Left HPCOM Mixer */
559c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
560c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
561c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
562c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
563c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
5649503112dSJyri Sarha /* Not on tlv320aic3104 */
5659503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
5669503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
567c3b79e05SJarkko Nikula };
568c3b79e05SJarkko Nikula
569c3b79e05SJarkko Nikula /* Right HPCOM Mixer */
570c3b79e05SJarkko Nikula static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
571c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
572c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
573c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
574c3b79e05SJarkko Nikula SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
5759503112dSJyri Sarha /* Not on tlv320aic3104 */
5769503112dSJyri Sarha SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
5779503112dSJyri Sarha SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
57844d0a879SVladimir Barinov };
57944d0a879SVladimir Barinov
58044d0a879SVladimir Barinov /* Left PGA Mixer */
58144d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
58244d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
58354f01916SDaniel Mack SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
58444d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
58544d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
58654f01916SDaniel Mack SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
58744d0a879SVladimir Barinov };
58844d0a879SVladimir Barinov
58944d0a879SVladimir Barinov /* Right PGA Mixer */
59044d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
59144d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
59254f01916SDaniel Mack SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
59344d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
59454f01916SDaniel Mack SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
59544d0a879SVladimir Barinov SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
59644d0a879SVladimir Barinov };
59744d0a879SVladimir Barinov
5989503112dSJyri Sarha /* Left PGA Mixer for tlv320aic3104 */
5999503112dSJyri Sarha static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = {
6009503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
6019503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
6029503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
6039503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
6049503112dSJyri Sarha };
6059503112dSJyri Sarha
6069503112dSJyri Sarha /* Right PGA Mixer for tlv320aic3104 */
6079503112dSJyri Sarha static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = {
6089503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
6099503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
6109503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
6119503112dSJyri Sarha SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
6129503112dSJyri Sarha };
6139503112dSJyri Sarha
61444d0a879SVladimir Barinov /* Left Line1 Mux */
615404b5665SJarkko Nikula static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
616a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
617404b5665SJarkko Nikula static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls =
618a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum);
61944d0a879SVladimir Barinov
62044d0a879SVladimir Barinov /* Right Line1 Mux */
621404b5665SJarkko Nikula static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls =
622a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum);
623404b5665SJarkko Nikula static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls =
624a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum);
62544d0a879SVladimir Barinov
62644d0a879SVladimir Barinov /* Left Line2 Mux */
62744d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
628a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum);
62944d0a879SVladimir Barinov
63044d0a879SVladimir Barinov /* Right Line2 Mux */
63144d0a879SVladimir Barinov static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
632a60e654bSPeter Ujfalusi SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum);
63344d0a879SVladimir Barinov
63444d0a879SVladimir Barinov static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
63544d0a879SVladimir Barinov /* Left DAC to Left Outputs */
63644d0a879SVladimir Barinov SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
63744d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
63844d0a879SVladimir Barinov &aic3x_left_dac_mux_controls),
63944d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
64044d0a879SVladimir Barinov &aic3x_left_hpcom_mux_controls),
64144d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
64244d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0),
64344d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0),
64444d0a879SVladimir Barinov
64544d0a879SVladimir Barinov /* Right DAC to Right Outputs */
64644d0a879SVladimir Barinov SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
64744d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
64844d0a879SVladimir Barinov &aic3x_right_dac_mux_controls),
64944d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
65044d0a879SVladimir Barinov &aic3x_right_hpcom_mux_controls),
65144d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
65244d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
65344d0a879SVladimir Barinov SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
65444d0a879SVladimir Barinov
65554f01916SDaniel Mack /* Inputs to Left ADC */
65644d0a879SVladimir Barinov SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
65744d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
658404b5665SJarkko Nikula &aic3x_left_line1l_mux_controls),
65954f01916SDaniel Mack SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
660404b5665SJarkko Nikula &aic3x_left_line1r_mux_controls),
66144d0a879SVladimir Barinov
66254f01916SDaniel Mack /* Inputs to Right ADC */
66344d0a879SVladimir Barinov SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
66444d0a879SVladimir Barinov LINE1R_2_RADC_CTRL, 2, 0),
66554f01916SDaniel Mack SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
666404b5665SJarkko Nikula &aic3x_right_line1l_mux_controls),
66744d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
668404b5665SJarkko Nikula &aic3x_right_line1r_mux_controls),
6699503112dSJyri Sarha
6709503112dSJyri Sarha /* Mic Bias */
6719503112dSJyri Sarha SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
6729503112dSJyri Sarha mic_bias_event,
6739503112dSJyri Sarha SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
6749503112dSJyri Sarha
6759503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("LLOUT"),
6769503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("RLOUT"),
6779503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("HPLOUT"),
6789503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("HPROUT"),
6799503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("HPLCOM"),
6809503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("HPRCOM"),
6819503112dSJyri Sarha
6829503112dSJyri Sarha SND_SOC_DAPM_INPUT("LINE1L"),
6839503112dSJyri Sarha SND_SOC_DAPM_INPUT("LINE1R"),
6849503112dSJyri Sarha
6859503112dSJyri Sarha /*
6869503112dSJyri Sarha * Virtual output pin to detection block inside codec. This can be
6879503112dSJyri Sarha * used to keep codec bias on if gpio or detection features are needed.
6889503112dSJyri Sarha * Force pin on or construct a path with an input jack and mic bias
6899503112dSJyri Sarha * widgets.
6909503112dSJyri Sarha */
6919503112dSJyri Sarha SND_SOC_DAPM_OUTPUT("Detection"),
6929503112dSJyri Sarha };
6939503112dSJyri Sarha
6949503112dSJyri Sarha /* For other than tlv320aic3104 */
6959503112dSJyri Sarha static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = {
6969503112dSJyri Sarha /* Inputs to Left ADC */
6979503112dSJyri Sarha SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
6989503112dSJyri Sarha &aic3x_left_pga_mixer_controls[0],
6999503112dSJyri Sarha ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
7009503112dSJyri Sarha SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
7019503112dSJyri Sarha &aic3x_left_line2_mux_controls),
7029503112dSJyri Sarha
7039503112dSJyri Sarha /* Inputs to Right ADC */
7049503112dSJyri Sarha SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
7059503112dSJyri Sarha &aic3x_right_pga_mixer_controls[0],
7069503112dSJyri Sarha ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
70744d0a879SVladimir Barinov SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
70844d0a879SVladimir Barinov &aic3x_right_line2_mux_controls),
70944d0a879SVladimir Barinov
710ee15ffdbSJarkko Nikula /*
711ee15ffdbSJarkko Nikula * Not a real mic bias widget but similar function. This is for dynamic
712ee15ffdbSJarkko Nikula * control of GPIO1 digital mic modulator clock output function when
713ee15ffdbSJarkko Nikula * using digital mic.
714ee15ffdbSJarkko Nikula */
715ee15ffdbSJarkko Nikula SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk",
716ee15ffdbSJarkko Nikula AIC3X_GPIO1_REG, 4, 0xf,
717ee15ffdbSJarkko Nikula AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK,
718ee15ffdbSJarkko Nikula AIC3X_GPIO1_FUNC_DISABLED),
719ee15ffdbSJarkko Nikula
720ee15ffdbSJarkko Nikula /*
721ee15ffdbSJarkko Nikula * Also similar function like mic bias. Selects digital mic with
722ee15ffdbSJarkko Nikula * configurable oversampling rate instead of ADC converter.
723ee15ffdbSJarkko Nikula */
724ee15ffdbSJarkko Nikula SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128",
725ee15ffdbSJarkko Nikula AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0),
726ee15ffdbSJarkko Nikula SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64",
727ee15ffdbSJarkko Nikula AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0),
728ee15ffdbSJarkko Nikula SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
729ee15ffdbSJarkko Nikula AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
730ee15ffdbSJarkko Nikula
731c3b79e05SJarkko Nikula /* Output mixers */
732c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
733c3b79e05SJarkko Nikula &aic3x_left_line_mixer_controls[0],
734c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_left_line_mixer_controls)),
735c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
736c3b79e05SJarkko Nikula &aic3x_right_line_mixer_controls[0],
737c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_right_line_mixer_controls)),
738c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
739c3b79e05SJarkko Nikula &aic3x_left_hp_mixer_controls[0],
740c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
741c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
742c3b79e05SJarkko Nikula &aic3x_right_hp_mixer_controls[0],
743c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
744c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
745c3b79e05SJarkko Nikula &aic3x_left_hpcom_mixer_controls[0],
746c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
747c3b79e05SJarkko Nikula SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
748c3b79e05SJarkko Nikula &aic3x_right_hpcom_mixer_controls[0],
749c3b79e05SJarkko Nikula ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
75044d0a879SVladimir Barinov
75144d0a879SVladimir Barinov SND_SOC_DAPM_INPUT("MIC3L"),
75244d0a879SVladimir Barinov SND_SOC_DAPM_INPUT("MIC3R"),
75344d0a879SVladimir Barinov SND_SOC_DAPM_INPUT("LINE2L"),
75444d0a879SVladimir Barinov SND_SOC_DAPM_INPUT("LINE2R"),
7559503112dSJyri Sarha };
75619f7ac50SJarkko Nikula
7579503112dSJyri Sarha /* For tlv320aic3104 */
7589503112dSJyri Sarha static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = {
7599503112dSJyri Sarha /* Inputs to Left ADC */
7609503112dSJyri Sarha SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
7619503112dSJyri Sarha &aic3104_left_pga_mixer_controls[0],
7629503112dSJyri Sarha ARRAY_SIZE(aic3104_left_pga_mixer_controls)),
7639503112dSJyri Sarha
7649503112dSJyri Sarha /* Inputs to Right ADC */
7659503112dSJyri Sarha SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
7669503112dSJyri Sarha &aic3104_right_pga_mixer_controls[0],
7679503112dSJyri Sarha ARRAY_SIZE(aic3104_right_pga_mixer_controls)),
7689503112dSJyri Sarha
7699503112dSJyri Sarha /* Output mixers */
7709503112dSJyri Sarha SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
7719503112dSJyri Sarha &aic3x_left_line_mixer_controls[0],
7729503112dSJyri Sarha ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2),
7739503112dSJyri Sarha SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
7749503112dSJyri Sarha &aic3x_right_line_mixer_controls[0],
7759503112dSJyri Sarha ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2),
7769503112dSJyri Sarha SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
7779503112dSJyri Sarha &aic3x_left_hp_mixer_controls[0],
7789503112dSJyri Sarha ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2),
7799503112dSJyri Sarha SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
7809503112dSJyri Sarha &aic3x_right_hp_mixer_controls[0],
7819503112dSJyri Sarha ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2),
7829503112dSJyri Sarha SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
7839503112dSJyri Sarha &aic3x_left_hpcom_mixer_controls[0],
7849503112dSJyri Sarha ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2),
7859503112dSJyri Sarha SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
7869503112dSJyri Sarha &aic3x_right_hpcom_mixer_controls[0],
7879503112dSJyri Sarha ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2),
7889503112dSJyri Sarha
7899503112dSJyri Sarha SND_SOC_DAPM_INPUT("MIC2L"),
7909503112dSJyri Sarha SND_SOC_DAPM_INPUT("MIC2R"),
79144d0a879SVladimir Barinov };
79244d0a879SVladimir Barinov
79358381da6SJan Weitzel static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
79458381da6SJan Weitzel /* Mono Output */
79558381da6SJan Weitzel SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
79658381da6SJan Weitzel
79758381da6SJan Weitzel SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
79858381da6SJan Weitzel &aic3x_mono_mixer_controls[0],
79958381da6SJan Weitzel ARRAY_SIZE(aic3x_mono_mixer_controls)),
80058381da6SJan Weitzel
80158381da6SJan Weitzel SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
80258381da6SJan Weitzel };
80358381da6SJan Weitzel
8046184f105SRandolph Chung static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
8056184f105SRandolph Chung /* Class-D outputs */
8066184f105SRandolph Chung SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
8076184f105SRandolph Chung SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
8086184f105SRandolph Chung
8096184f105SRandolph Chung SND_SOC_DAPM_OUTPUT("SPOP"),
8106184f105SRandolph Chung SND_SOC_DAPM_OUTPUT("SPOM"),
8116184f105SRandolph Chung };
8126184f105SRandolph Chung
813d0cc0d3aSMark Brown static const struct snd_soc_dapm_route intercon[] = {
81444d0a879SVladimir Barinov /* Left Input */
81544d0a879SVladimir Barinov {"Left Line1L Mux", "single-ended", "LINE1L"},
81644d0a879SVladimir Barinov {"Left Line1L Mux", "differential", "LINE1L"},
8176b2afee1SPeter Ujfalusi {"Left Line1R Mux", "single-ended", "LINE1R"},
8186b2afee1SPeter Ujfalusi {"Left Line1R Mux", "differential", "LINE1R"},
81944d0a879SVladimir Barinov
82044d0a879SVladimir Barinov {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
82154f01916SDaniel Mack {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
82244d0a879SVladimir Barinov
82344d0a879SVladimir Barinov {"Left ADC", NULL, "Left PGA Mixer"},
82444d0a879SVladimir Barinov
82544d0a879SVladimir Barinov /* Right Input */
82644d0a879SVladimir Barinov {"Right Line1R Mux", "single-ended", "LINE1R"},
82744d0a879SVladimir Barinov {"Right Line1R Mux", "differential", "LINE1R"},
8286b2afee1SPeter Ujfalusi {"Right Line1L Mux", "single-ended", "LINE1L"},
8296b2afee1SPeter Ujfalusi {"Right Line1L Mux", "differential", "LINE1L"},
83044d0a879SVladimir Barinov
83154f01916SDaniel Mack {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
83244d0a879SVladimir Barinov {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
83344d0a879SVladimir Barinov
83444d0a879SVladimir Barinov {"Right ADC", NULL, "Right PGA Mixer"},
835c3b79e05SJarkko Nikula
836c3b79e05SJarkko Nikula /* Left DAC Output */
837c3b79e05SJarkko Nikula {"Left DAC Mux", "DAC_L1", "Left DAC"},
838c3b79e05SJarkko Nikula {"Left DAC Mux", "DAC_L2", "Left DAC"},
839c3b79e05SJarkko Nikula {"Left DAC Mux", "DAC_L3", "Left DAC"},
840c3b79e05SJarkko Nikula
841c3b79e05SJarkko Nikula /* Right DAC Output */
842c3b79e05SJarkko Nikula {"Right DAC Mux", "DAC_R1", "Right DAC"},
843c3b79e05SJarkko Nikula {"Right DAC Mux", "DAC_R2", "Right DAC"},
844c3b79e05SJarkko Nikula {"Right DAC Mux", "DAC_R3", "Right DAC"},
845c3b79e05SJarkko Nikula
846c3b79e05SJarkko Nikula /* Left Line Output */
847c3b79e05SJarkko Nikula {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
848c3b79e05SJarkko Nikula {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
849c3b79e05SJarkko Nikula {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
850c3b79e05SJarkko Nikula {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
851c3b79e05SJarkko Nikula
852c3b79e05SJarkko Nikula {"Left Line Out", NULL, "Left Line Mixer"},
853c3b79e05SJarkko Nikula {"Left Line Out", NULL, "Left DAC Mux"},
854c3b79e05SJarkko Nikula {"LLOUT", NULL, "Left Line Out"},
855c3b79e05SJarkko Nikula
856c3b79e05SJarkko Nikula /* Right Line Output */
857c3b79e05SJarkko Nikula {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
858c3b79e05SJarkko Nikula {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
859c3b79e05SJarkko Nikula {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
860c3b79e05SJarkko Nikula {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
861c3b79e05SJarkko Nikula
862c3b79e05SJarkko Nikula {"Right Line Out", NULL, "Right Line Mixer"},
863c3b79e05SJarkko Nikula {"Right Line Out", NULL, "Right DAC Mux"},
864c3b79e05SJarkko Nikula {"RLOUT", NULL, "Right Line Out"},
865c3b79e05SJarkko Nikula
866c3b79e05SJarkko Nikula /* Left HP Output */
867c3b79e05SJarkko Nikula {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
868c3b79e05SJarkko Nikula {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
869c3b79e05SJarkko Nikula {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
870c3b79e05SJarkko Nikula {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
871c3b79e05SJarkko Nikula
872c3b79e05SJarkko Nikula {"Left HP Out", NULL, "Left HP Mixer"},
873c3b79e05SJarkko Nikula {"Left HP Out", NULL, "Left DAC Mux"},
874c3b79e05SJarkko Nikula {"HPLOUT", NULL, "Left HP Out"},
875c3b79e05SJarkko Nikula
876c3b79e05SJarkko Nikula /* Right HP Output */
877c3b79e05SJarkko Nikula {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
878c3b79e05SJarkko Nikula {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
879c3b79e05SJarkko Nikula {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
880c3b79e05SJarkko Nikula {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
881c3b79e05SJarkko Nikula
882c3b79e05SJarkko Nikula {"Right HP Out", NULL, "Right HP Mixer"},
883c3b79e05SJarkko Nikula {"Right HP Out", NULL, "Right DAC Mux"},
884c3b79e05SJarkko Nikula {"HPROUT", NULL, "Right HP Out"},
885c3b79e05SJarkko Nikula
886c3b79e05SJarkko Nikula /* Left HPCOM Output */
887c3b79e05SJarkko Nikula {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
888c3b79e05SJarkko Nikula {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
889c3b79e05SJarkko Nikula {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
890c3b79e05SJarkko Nikula {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
891c3b79e05SJarkko Nikula
892c3b79e05SJarkko Nikula {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
893c3b79e05SJarkko Nikula {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
894c3b79e05SJarkko Nikula {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
895c3b79e05SJarkko Nikula {"Left HP Com", NULL, "Left HPCOM Mux"},
896c3b79e05SJarkko Nikula {"HPLCOM", NULL, "Left HP Com"},
897c3b79e05SJarkko Nikula
898c3b79e05SJarkko Nikula /* Right HPCOM Output */
899c3b79e05SJarkko Nikula {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
900c3b79e05SJarkko Nikula {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
901c3b79e05SJarkko Nikula {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
902c3b79e05SJarkko Nikula {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
903c3b79e05SJarkko Nikula
904c3b79e05SJarkko Nikula {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
905c3b79e05SJarkko Nikula {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
906c3b79e05SJarkko Nikula {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
907c3b79e05SJarkko Nikula {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
908c3b79e05SJarkko Nikula {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
909c3b79e05SJarkko Nikula {"Right HP Com", NULL, "Right HPCOM Mux"},
910c3b79e05SJarkko Nikula {"HPRCOM", NULL, "Right HP Com"},
91144d0a879SVladimir Barinov };
91244d0a879SVladimir Barinov
9139503112dSJyri Sarha /* For other than tlv320aic3104 */
9149503112dSJyri Sarha static const struct snd_soc_dapm_route intercon_extra[] = {
9159503112dSJyri Sarha /* Left Input */
9169503112dSJyri Sarha {"Left Line2L Mux", "single-ended", "LINE2L"},
9179503112dSJyri Sarha {"Left Line2L Mux", "differential", "LINE2L"},
9189503112dSJyri Sarha
9199503112dSJyri Sarha {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
9209503112dSJyri Sarha {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
9219503112dSJyri Sarha {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
9229503112dSJyri Sarha
9239503112dSJyri Sarha {"Left ADC", NULL, "GPIO1 dmic modclk"},
9249503112dSJyri Sarha
9259503112dSJyri Sarha /* Right Input */
9269503112dSJyri Sarha {"Right Line2R Mux", "single-ended", "LINE2R"},
9279503112dSJyri Sarha {"Right Line2R Mux", "differential", "LINE2R"},
9289503112dSJyri Sarha
9299503112dSJyri Sarha {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
9309503112dSJyri Sarha {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
9319503112dSJyri Sarha {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
9329503112dSJyri Sarha
9339503112dSJyri Sarha {"Right ADC", NULL, "GPIO1 dmic modclk"},
9349503112dSJyri Sarha
9359503112dSJyri Sarha /*
9369503112dSJyri Sarha * Logical path between digital mic enable and GPIO1 modulator clock
9379503112dSJyri Sarha * output function
9389503112dSJyri Sarha */
9399503112dSJyri Sarha {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
9409503112dSJyri Sarha {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
9419503112dSJyri Sarha {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
9429503112dSJyri Sarha
9439503112dSJyri Sarha /* Left Line Output */
9449503112dSJyri Sarha {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9459503112dSJyri Sarha {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9469503112dSJyri Sarha
9479503112dSJyri Sarha /* Right Line Output */
9489503112dSJyri Sarha {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9499503112dSJyri Sarha {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9509503112dSJyri Sarha
9519503112dSJyri Sarha /* Left HP Output */
9529503112dSJyri Sarha {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9539503112dSJyri Sarha {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9549503112dSJyri Sarha
9559503112dSJyri Sarha /* Right HP Output */
9569503112dSJyri Sarha {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9579503112dSJyri Sarha {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9589503112dSJyri Sarha
9599503112dSJyri Sarha /* Left HPCOM Output */
9609503112dSJyri Sarha {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9619503112dSJyri Sarha {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9629503112dSJyri Sarha
9639503112dSJyri Sarha /* Right HPCOM Output */
9649503112dSJyri Sarha {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
9659503112dSJyri Sarha {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
9669503112dSJyri Sarha };
9679503112dSJyri Sarha
968b8255930SJyri Sarha /* For tlv320aic3104 */
9699503112dSJyri Sarha static const struct snd_soc_dapm_route intercon_extra_3104[] = {
9709503112dSJyri Sarha /* Left Input */
9719503112dSJyri Sarha {"Left PGA Mixer", "Mic2L Switch", "MIC2L"},
9729503112dSJyri Sarha {"Left PGA Mixer", "Mic2R Switch", "MIC2R"},
9739503112dSJyri Sarha
9749503112dSJyri Sarha /* Right Input */
9759503112dSJyri Sarha {"Right PGA Mixer", "Mic2L Switch", "MIC2L"},
9769503112dSJyri Sarha {"Right PGA Mixer", "Mic2R Switch", "MIC2R"},
9779503112dSJyri Sarha };
9789503112dSJyri Sarha
97958381da6SJan Weitzel static const struct snd_soc_dapm_route intercon_mono[] = {
98058381da6SJan Weitzel /* Mono Output */
98158381da6SJan Weitzel {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
98258381da6SJan Weitzel {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
98358381da6SJan Weitzel {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
98458381da6SJan Weitzel {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
98558381da6SJan Weitzel {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
98658381da6SJan Weitzel {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
98758381da6SJan Weitzel {"Mono Out", NULL, "Mono Mixer"},
98858381da6SJan Weitzel {"MONO_LOUT", NULL, "Mono Out"},
98958381da6SJan Weitzel };
99058381da6SJan Weitzel
9916184f105SRandolph Chung static const struct snd_soc_dapm_route intercon_3007[] = {
9926184f105SRandolph Chung /* Class-D outputs */
9936184f105SRandolph Chung {"Left Class-D Out", NULL, "Left Line Out"},
9946184f105SRandolph Chung {"Right Class-D Out", NULL, "Left Line Out"},
9956184f105SRandolph Chung {"SPOP", NULL, "Left Class-D Out"},
9966184f105SRandolph Chung {"SPOM", NULL, "Right Class-D Out"},
9976184f105SRandolph Chung };
9986184f105SRandolph Chung
aic3x_add_widgets(struct snd_soc_component * component)999749ad545SKuninori Morimoto static int aic3x_add_widgets(struct snd_soc_component *component)
100044d0a879SVladimir Barinov {
1001749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
1002749ad545SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
10036184f105SRandolph Chung
100458381da6SJan Weitzel switch (aic3x->model) {
100558381da6SJan Weitzel case AIC3X_MODEL_3X:
100658381da6SJan Weitzel case AIC3X_MODEL_33:
1007a0bc855fSJiri Prchal case AIC3X_MODEL_3106:
10089503112dSJyri Sarha snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
10099503112dSJyri Sarha ARRAY_SIZE(aic3x_extra_dapm_widgets));
10109503112dSJyri Sarha snd_soc_dapm_add_routes(dapm, intercon_extra,
10119503112dSJyri Sarha ARRAY_SIZE(intercon_extra));
101258381da6SJan Weitzel snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
101358381da6SJan Weitzel ARRAY_SIZE(aic3x_dapm_mono_widgets));
101458381da6SJan Weitzel snd_soc_dapm_add_routes(dapm, intercon_mono,
101558381da6SJan Weitzel ARRAY_SIZE(intercon_mono));
101658381da6SJan Weitzel break;
101758381da6SJan Weitzel case AIC3X_MODEL_3007:
10189503112dSJyri Sarha snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
10199503112dSJyri Sarha ARRAY_SIZE(aic3x_extra_dapm_widgets));
10209503112dSJyri Sarha snd_soc_dapm_add_routes(dapm, intercon_extra,
10219503112dSJyri Sarha ARRAY_SIZE(intercon_extra));
1022ce6120ccSLiam Girdwood snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
10236184f105SRandolph Chung ARRAY_SIZE(aic3007_dapm_widgets));
1024ce6120ccSLiam Girdwood snd_soc_dapm_add_routes(dapm, intercon_3007,
1025ce6120ccSLiam Girdwood ARRAY_SIZE(intercon_3007));
102658381da6SJan Weitzel break;
10279503112dSJyri Sarha case AIC3X_MODEL_3104:
10289503112dSJyri Sarha snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets,
10299503112dSJyri Sarha ARRAY_SIZE(aic3104_extra_dapm_widgets));
10309503112dSJyri Sarha snd_soc_dapm_add_routes(dapm, intercon_extra_3104,
10319503112dSJyri Sarha ARRAY_SIZE(intercon_extra_3104));
10329503112dSJyri Sarha break;
10336184f105SRandolph Chung }
10346184f105SRandolph Chung
103544d0a879SVladimir Barinov return 0;
103644d0a879SVladimir Barinov }
103744d0a879SVladimir Barinov
aic3x_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)103844d0a879SVladimir Barinov static int aic3x_hw_params(struct snd_pcm_substream *substream,
1039dee89c4dSMark Brown struct snd_pcm_hw_params *params,
1040dee89c4dSMark Brown struct snd_soc_dai *dai)
104144d0a879SVladimir Barinov {
1042749ad545SKuninori Morimoto struct snd_soc_component *component = dai->component;
1043749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
10444f9c16ccSDaniel Mack int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
1045255173b4SPeter Meerwald u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
1046255173b4SPeter Meerwald u16 d, pll_d = 1;
1047255173b4SPeter Meerwald int clk;
10483e8f5263SJyri Sarha int width = aic3x->slot_width;
10493e8f5263SJyri Sarha
10503e8f5263SJyri Sarha if (!width)
10513e8f5263SJyri Sarha width = params_width(params);
105244d0a879SVladimir Barinov
105344d0a879SVladimir Barinov /* select data word length */
1054e348cf54SKuninori Morimoto data = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
10553e8f5263SJyri Sarha switch (width) {
10563e3e2922SMark Brown case 16:
105744d0a879SVladimir Barinov break;
10583e3e2922SMark Brown case 20:
105944d0a879SVladimir Barinov data |= (0x01 << 4);
106044d0a879SVladimir Barinov break;
10613e3e2922SMark Brown case 24:
106244d0a879SVladimir Barinov data |= (0x02 << 4);
106344d0a879SVladimir Barinov break;
10643e3e2922SMark Brown case 32:
106544d0a879SVladimir Barinov data |= (0x03 << 4);
106644d0a879SVladimir Barinov break;
106744d0a879SVladimir Barinov }
1068749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, data);
106944d0a879SVladimir Barinov
10704f9c16ccSDaniel Mack /* Fsref can be 44100 or 48000 */
10714f9c16ccSDaniel Mack fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
10724f9c16ccSDaniel Mack
10734f9c16ccSDaniel Mack /* Try to find a value for Q which allows us to bypass the PLL and
10744f9c16ccSDaniel Mack * generate CODEC_CLK directly. */
10754f9c16ccSDaniel Mack for (pll_q = 2; pll_q < 18; pll_q++)
10764f9c16ccSDaniel Mack if (aic3x->sysclk / (128 * pll_q) == fsref) {
10774f9c16ccSDaniel Mack bypass_pll = 1;
10784f9c16ccSDaniel Mack break;
10794f9c16ccSDaniel Mack }
10804f9c16ccSDaniel Mack
10814f9c16ccSDaniel Mack if (bypass_pll) {
10824f9c16ccSDaniel Mack pll_q &= 0xf;
1083749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
1084749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
108506c71282SChaithrika U S /* disable PLL if it is bypassed */
1086749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLL_ENABLE, 0);
108706c71282SChaithrika U S
108806c71282SChaithrika U S } else {
1089749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
109006c71282SChaithrika U S /* enable PLL when it is used */
1091749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
10929c173d15SAxel Lin PLL_ENABLE, PLL_ENABLE);
109306c71282SChaithrika U S }
10944f9c16ccSDaniel Mack
10954f9c16ccSDaniel Mack /* Route Left DAC to left channel input and
10964f9c16ccSDaniel Mack * right DAC to right channel input */
10974f9c16ccSDaniel Mack data = (LDAC2LCH | RDAC2RCH);
10984f9c16ccSDaniel Mack data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
10994f9c16ccSDaniel Mack if (params_rate(params) >= 64000)
11004f9c16ccSDaniel Mack data |= DUAL_RATE_MODE;
1101749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
11024f9c16ccSDaniel Mack
11034f9c16ccSDaniel Mack /* codec sample rate select */
11044f9c16ccSDaniel Mack data = (fsref * 20) / params_rate(params);
11054f9c16ccSDaniel Mack if (params_rate(params) < 64000)
11064f9c16ccSDaniel Mack data /= 2;
11074f9c16ccSDaniel Mack data /= 5;
11084f9c16ccSDaniel Mack data -= 2;
11094f9c16ccSDaniel Mack data |= (data << 4);
1110749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_SAMPLE_RATE_SEL_REG, data);
11114f9c16ccSDaniel Mack
11124f9c16ccSDaniel Mack if (bypass_pll)
11134f9c16ccSDaniel Mack return 0;
11144f9c16ccSDaniel Mack
111525985edcSLucas De Marchi /* Use PLL, compute appropriate setup for j, d, r and p, the closest
1116255173b4SPeter Meerwald * one wins the game. Try with d==0 first, next with d!=0.
1117255173b4SPeter Meerwald * Constraints for j are according to the datasheet.
11184f9c16ccSDaniel Mack * The sysclk is divided by 1000 to prevent integer overflows.
11194f9c16ccSDaniel Mack */
1120255173b4SPeter Meerwald
11214f9c16ccSDaniel Mack codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
11224f9c16ccSDaniel Mack
11234f9c16ccSDaniel Mack for (r = 1; r <= 16; r++)
11244f9c16ccSDaniel Mack for (p = 1; p <= 8; p++) {
1125255173b4SPeter Meerwald for (j = 4; j <= 55; j++) {
11264f9c16ccSDaniel Mack /* This is actually 1000*((j+(d/10000))*r)/p
1127255173b4SPeter Meerwald * The term had to be converted to get
1128255173b4SPeter Meerwald * rid of the division by 10000; d = 0 here
1129255173b4SPeter Meerwald */
11305baf8315SMark Brown int tmp_clk = (1000 * j * r) / p;
11314f9c16ccSDaniel Mack
1132255173b4SPeter Meerwald /* Check whether this values get closer than
1133255173b4SPeter Meerwald * the best ones we had before
1134255173b4SPeter Meerwald */
11355baf8315SMark Brown if (abs(codec_clk - tmp_clk) <
1136255173b4SPeter Meerwald abs(codec_clk - last_clk)) {
1137255173b4SPeter Meerwald pll_j = j; pll_d = 0;
1138255173b4SPeter Meerwald pll_r = r; pll_p = p;
11395baf8315SMark Brown last_clk = tmp_clk;
11404f9c16ccSDaniel Mack }
11414f9c16ccSDaniel Mack
11424f9c16ccSDaniel Mack /* Early exit for exact matches */
11435baf8315SMark Brown if (tmp_clk == codec_clk)
1144255173b4SPeter Meerwald goto found;
1145255173b4SPeter Meerwald }
1146255173b4SPeter Meerwald }
1147255173b4SPeter Meerwald
1148255173b4SPeter Meerwald /* try with d != 0 */
1149255173b4SPeter Meerwald for (p = 1; p <= 8; p++) {
1150255173b4SPeter Meerwald j = codec_clk * p / 1000;
1151255173b4SPeter Meerwald
1152255173b4SPeter Meerwald if (j < 4 || j > 11)
1153255173b4SPeter Meerwald continue;
1154255173b4SPeter Meerwald
1155255173b4SPeter Meerwald /* do not use codec_clk here since we'd loose precision */
1156255173b4SPeter Meerwald d = ((2048 * p * fsref) - j * aic3x->sysclk)
1157255173b4SPeter Meerwald * 100 / (aic3x->sysclk/100);
1158255173b4SPeter Meerwald
1159255173b4SPeter Meerwald clk = (10000 * j + d) / (10 * p);
1160255173b4SPeter Meerwald
1161255173b4SPeter Meerwald /* check whether this values get closer than the best
1162255173b4SPeter Meerwald * ones we had before */
1163255173b4SPeter Meerwald if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
1164255173b4SPeter Meerwald pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
1165255173b4SPeter Meerwald last_clk = clk;
1166255173b4SPeter Meerwald }
1167255173b4SPeter Meerwald
1168255173b4SPeter Meerwald /* Early exit for exact matches */
1169255173b4SPeter Meerwald if (clk == codec_clk)
1170255173b4SPeter Meerwald goto found;
11714f9c16ccSDaniel Mack }
11724f9c16ccSDaniel Mack
11734f9c16ccSDaniel Mack if (last_clk == 0) {
11744f9c16ccSDaniel Mack printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
11754f9c16ccSDaniel Mack return -EINVAL;
11764f9c16ccSDaniel Mack }
11774f9c16ccSDaniel Mack
1178255173b4SPeter Meerwald found:
1179749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
1180749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_OVRF_STATUS_AND_PLLR_REG,
1181e18eca43SJarkko Nikula pll_r << PLLR_SHIFT);
1182749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
1183749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGC_REG,
1184e18eca43SJarkko Nikula (pll_d >> 6) << PLLD_MSB_SHIFT);
1185749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGD_REG,
11864f9c16ccSDaniel Mack (pll_d & 0x3F) << PLLD_LSB_SHIFT);
11874f9c16ccSDaniel Mack
118844d0a879SVladimir Barinov return 0;
118944d0a879SVladimir Barinov }
119044d0a879SVladimir Barinov
aic3x_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)119136849409SPeter Ujfalusi static int aic3x_prepare(struct snd_pcm_substream *substream,
119236849409SPeter Ujfalusi struct snd_soc_dai *dai)
119336849409SPeter Ujfalusi {
1194749ad545SKuninori Morimoto struct snd_soc_component *component = dai->component;
1195749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
119636849409SPeter Ujfalusi int delay = 0;
11973e8f5263SJyri Sarha int width = aic3x->slot_width;
11983e8f5263SJyri Sarha
11993e8f5263SJyri Sarha if (!width)
12003e8f5263SJyri Sarha width = substream->runtime->sample_bits;
120136849409SPeter Ujfalusi
120236849409SPeter Ujfalusi /* TDM slot selection only valid in DSP_A/_B mode */
120336849409SPeter Ujfalusi if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A)
12043e8f5263SJyri Sarha delay += (aic3x->tdm_delay*width + 1);
120536849409SPeter Ujfalusi else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B)
12063e8f5263SJyri Sarha delay += aic3x->tdm_delay*width;
120736849409SPeter Ujfalusi
120836849409SPeter Ujfalusi /* Configure data delay */
1209749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLC, delay);
121036849409SPeter Ujfalusi
121136849409SPeter Ujfalusi return 0;
121236849409SPeter Ujfalusi }
121336849409SPeter Ujfalusi
aic3x_mute(struct snd_soc_dai * dai,int mute,int direction)1214960af79dSKuninori Morimoto static int aic3x_mute(struct snd_soc_dai *dai, int mute, int direction)
121544d0a879SVladimir Barinov {
1216749ad545SKuninori Morimoto struct snd_soc_component *component = dai->component;
1217e348cf54SKuninori Morimoto u8 ldac_reg = snd_soc_component_read(component, LDAC_VOL) & ~MUTE_ON;
1218e348cf54SKuninori Morimoto u8 rdac_reg = snd_soc_component_read(component, RDAC_VOL) & ~MUTE_ON;
121944d0a879SVladimir Barinov
122044d0a879SVladimir Barinov if (mute) {
1221749ad545SKuninori Morimoto snd_soc_component_write(component, LDAC_VOL, ldac_reg | MUTE_ON);
1222749ad545SKuninori Morimoto snd_soc_component_write(component, RDAC_VOL, rdac_reg | MUTE_ON);
122344d0a879SVladimir Barinov } else {
1224749ad545SKuninori Morimoto snd_soc_component_write(component, LDAC_VOL, ldac_reg);
1225749ad545SKuninori Morimoto snd_soc_component_write(component, RDAC_VOL, rdac_reg);
122644d0a879SVladimir Barinov }
122744d0a879SVladimir Barinov
122844d0a879SVladimir Barinov return 0;
122944d0a879SVladimir Barinov }
123044d0a879SVladimir Barinov
aic3x_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)1231e550e17fSLiam Girdwood static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
123244d0a879SVladimir Barinov int clk_id, unsigned int freq, int dir)
123344d0a879SVladimir Barinov {
1234749ad545SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
1235749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
123644d0a879SVladimir Barinov
1237a1f34af0SJiri Prchal /* set clock on MCLK or GPIO2 or BCLK */
1238749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
1239a1f34af0SJiri Prchal clk_id << PLLCLK_IN_SHIFT);
1240749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
1241a1f34af0SJiri Prchal clk_id << CLKDIV_IN_SHIFT);
1242a1f34af0SJiri Prchal
124344d0a879SVladimir Barinov aic3x->sysclk = freq;
124444d0a879SVladimir Barinov return 0;
124544d0a879SVladimir Barinov }
124644d0a879SVladimir Barinov
aic3x_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1247e550e17fSLiam Girdwood static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
124844d0a879SVladimir Barinov unsigned int fmt)
124944d0a879SVladimir Barinov {
1250749ad545SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
1251749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
125281971a14SJarkko Nikula u8 iface_areg, iface_breg;
125381971a14SJarkko Nikula
1254e348cf54SKuninori Morimoto iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f;
1255e348cf54SKuninori Morimoto iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f;
125644d0a879SVladimir Barinov
125783a5f869SMark Brown switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
125883a5f869SMark Brown case SND_SOC_DAIFMT_CBP_CFP:
125944d0a879SVladimir Barinov aic3x->master = 1;
126044d0a879SVladimir Barinov iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
126144d0a879SVladimir Barinov break;
126283a5f869SMark Brown case SND_SOC_DAIFMT_CBC_CFC:
126344d0a879SVladimir Barinov aic3x->master = 0;
126468e47981SAxel Lin iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
126544d0a879SVladimir Barinov break;
126683a5f869SMark Brown case SND_SOC_DAIFMT_CBP_CFC:
12674647598cSPeter Ujfalusi aic3x->master = 1;
12684647598cSPeter Ujfalusi iface_areg |= BIT_CLK_MASTER;
12694647598cSPeter Ujfalusi iface_areg &= ~WORD_CLK_MASTER;
12704647598cSPeter Ujfalusi break;
127183a5f869SMark Brown case SND_SOC_DAIFMT_CBC_CFP:
12724647598cSPeter Ujfalusi aic3x->master = 1;
12734647598cSPeter Ujfalusi iface_areg |= WORD_CLK_MASTER;
12744647598cSPeter Ujfalusi iface_areg &= ~BIT_CLK_MASTER;
12754647598cSPeter Ujfalusi break;
127644d0a879SVladimir Barinov default:
127744d0a879SVladimir Barinov return -EINVAL;
127844d0a879SVladimir Barinov }
127944d0a879SVladimir Barinov
12804b7d2831SJarkko Nikula /*
12814b7d2831SJarkko Nikula * match both interface format and signal polarities since they
12824b7d2831SJarkko Nikula * are fixed
12834b7d2831SJarkko Nikula */
12844b7d2831SJarkko Nikula switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
12854b7d2831SJarkko Nikula SND_SOC_DAIFMT_INV_MASK)) {
12864b7d2831SJarkko Nikula case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
128744d0a879SVladimir Barinov break;
1288a24f4f68STroy Kisky case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
12894b7d2831SJarkko Nikula case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
129044d0a879SVladimir Barinov iface_breg |= (0x01 << 6);
129144d0a879SVladimir Barinov break;
12924b7d2831SJarkko Nikula case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
129344d0a879SVladimir Barinov iface_breg |= (0x02 << 6);
129444d0a879SVladimir Barinov break;
12954b7d2831SJarkko Nikula case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
129644d0a879SVladimir Barinov iface_breg |= (0x03 << 6);
129744d0a879SVladimir Barinov break;
129844d0a879SVladimir Barinov default:
129944d0a879SVladimir Barinov return -EINVAL;
130044d0a879SVladimir Barinov }
130144d0a879SVladimir Barinov
130236849409SPeter Ujfalusi aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
130336849409SPeter Ujfalusi
130444d0a879SVladimir Barinov /* set iface */
1305749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLA, iface_areg);
1306749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, iface_breg);
130736849409SPeter Ujfalusi
130836849409SPeter Ujfalusi return 0;
130936849409SPeter Ujfalusi }
131036849409SPeter Ujfalusi
aic3x_set_dai_tdm_slot(struct snd_soc_dai * codec_dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)131136849409SPeter Ujfalusi static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
131236849409SPeter Ujfalusi unsigned int tx_mask, unsigned int rx_mask,
131336849409SPeter Ujfalusi int slots, int slot_width)
131436849409SPeter Ujfalusi {
1315749ad545SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
1316749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
131736849409SPeter Ujfalusi unsigned int lsb;
131836849409SPeter Ujfalusi
131936849409SPeter Ujfalusi if (tx_mask != rx_mask) {
1320749ad545SKuninori Morimoto dev_err(component->dev, "tx and rx masks must be symmetric\n");
132136849409SPeter Ujfalusi return -EINVAL;
132236849409SPeter Ujfalusi }
132336849409SPeter Ujfalusi
132436849409SPeter Ujfalusi if (unlikely(!tx_mask)) {
1325749ad545SKuninori Morimoto dev_err(component->dev, "tx and rx masks need to be non 0\n");
132636849409SPeter Ujfalusi return -EINVAL;
132736849409SPeter Ujfalusi }
132836849409SPeter Ujfalusi
132936849409SPeter Ujfalusi /* TDM based on DSP mode requires slots to be adjacent */
133036849409SPeter Ujfalusi lsb = __ffs(tx_mask);
133136849409SPeter Ujfalusi if ((lsb + 1) != __fls(tx_mask)) {
1332749ad545SKuninori Morimoto dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
133336849409SPeter Ujfalusi return -EINVAL;
133436849409SPeter Ujfalusi }
133536849409SPeter Ujfalusi
13363e8f5263SJyri Sarha switch (slot_width) {
13373e8f5263SJyri Sarha case 16:
13383e8f5263SJyri Sarha case 20:
13393e8f5263SJyri Sarha case 24:
13403e8f5263SJyri Sarha case 32:
13413e8f5263SJyri Sarha break;
13423e8f5263SJyri Sarha default:
1343749ad545SKuninori Morimoto dev_err(component->dev, "Unsupported slot width %d\n", slot_width);
13443e8f5263SJyri Sarha return -EINVAL;
13453e8f5263SJyri Sarha }
13463e8f5263SJyri Sarha
13473e8f5263SJyri Sarha
13483e8f5263SJyri Sarha aic3x->tdm_delay = lsb;
13493e8f5263SJyri Sarha aic3x->slot_width = slot_width;
135036849409SPeter Ujfalusi
135136849409SPeter Ujfalusi /* DOUT in high-impedance on inactive bit clocks */
1352749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_ASD_INTF_CTRLA,
135336849409SPeter Ujfalusi DOUT_TRISTATE, DOUT_TRISTATE);
135444d0a879SVladimir Barinov
135544d0a879SVladimir Barinov return 0;
135644d0a879SVladimir Barinov }
135744d0a879SVladimir Barinov
aic3x_regulator_event(struct notifier_block * nb,unsigned long event,void * data)13585a895f8aSJarkko Nikula static int aic3x_regulator_event(struct notifier_block *nb,
13595a895f8aSJarkko Nikula unsigned long event, void *data)
13605a895f8aSJarkko Nikula {
13615a895f8aSJarkko Nikula struct aic3x_disable_nb *disable_nb =
13625a895f8aSJarkko Nikula container_of(nb, struct aic3x_disable_nb, nb);
13635a895f8aSJarkko Nikula struct aic3x_priv *aic3x = disable_nb->aic3x;
13645a895f8aSJarkko Nikula
13655a895f8aSJarkko Nikula if (event & REGULATOR_EVENT_DISABLE) {
13665a895f8aSJarkko Nikula /*
13675a895f8aSJarkko Nikula * Put codec to reset and require cache sync as at least one
13685a895f8aSJarkko Nikula * of the supplies was disabled
13695a895f8aSJarkko Nikula */
1370*a984d833SDmitry Torokhov if (aic3x->gpio_reset)
1371*a984d833SDmitry Torokhov gpiod_set_value(aic3x->gpio_reset, 1);
13722a6fedecSMark Brown regcache_mark_dirty(aic3x->regmap);
13735a895f8aSJarkko Nikula }
13745a895f8aSJarkko Nikula
13755a895f8aSJarkko Nikula return 0;
13765a895f8aSJarkko Nikula }
13775a895f8aSJarkko Nikula
aic3x_set_power(struct snd_soc_component * component,int power)1378749ad545SKuninori Morimoto static int aic3x_set_power(struct snd_soc_component *component, int power)
13796c1a7d40SJarkko Nikula {
1380749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
138131d9f8faSDmitry Lavnikevich unsigned int pll_c, pll_d;
13822a6fedecSMark Brown int ret;
13836c1a7d40SJarkko Nikula
13846c1a7d40SJarkko Nikula if (power) {
13856c1a7d40SJarkko Nikula ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
13866c1a7d40SJarkko Nikula aic3x->supplies);
13876c1a7d40SJarkko Nikula if (ret)
13886c1a7d40SJarkko Nikula goto out;
13896c1a7d40SJarkko Nikula aic3x->power = 1;
13905a895f8aSJarkko Nikula
1391*a984d833SDmitry Torokhov if (aic3x->gpio_reset) {
13926c1a7d40SJarkko Nikula udelay(1);
1393*a984d833SDmitry Torokhov gpiod_set_value(aic3x->gpio_reset, 0);
13946c1a7d40SJarkko Nikula }
13956c1a7d40SJarkko Nikula
13966c1a7d40SJarkko Nikula /* Sync reg_cache with the hardware */
13972a6fedecSMark Brown regcache_cache_only(aic3x->regmap, false);
13982a6fedecSMark Brown regcache_sync(aic3x->regmap);
139931d9f8faSDmitry Lavnikevich
140031d9f8faSDmitry Lavnikevich /* Rewrite paired PLL D registers in case cached sync skipped
140131d9f8faSDmitry Lavnikevich * writing one of them and thus caused other one also not
140231d9f8faSDmitry Lavnikevich * being written
140331d9f8faSDmitry Lavnikevich */
1404e348cf54SKuninori Morimoto pll_c = snd_soc_component_read(component, AIC3X_PLL_PROGC_REG);
1405e348cf54SKuninori Morimoto pll_d = snd_soc_component_read(component, AIC3X_PLL_PROGD_REG);
140631d9f8faSDmitry Lavnikevich if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
140731d9f8faSDmitry Lavnikevich pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
1408749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGC_REG, pll_c);
1409749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PLL_PROGD_REG, pll_d);
141031d9f8faSDmitry Lavnikevich }
141103303da5SPeter Ujfalusi
141203303da5SPeter Ujfalusi /*
141303303da5SPeter Ujfalusi * Delay is needed to reduce pop-noise after syncing back the
141403303da5SPeter Ujfalusi * registers
141503303da5SPeter Ujfalusi */
141603303da5SPeter Ujfalusi mdelay(50);
14176c1a7d40SJarkko Nikula } else {
14189fb352b1SJarkko Nikula /*
14199fb352b1SJarkko Nikula * Do soft reset to this codec instance in order to clear
14209fb352b1SJarkko Nikula * possible VDD leakage currents in case the supply regulators
14219fb352b1SJarkko Nikula * remain on
14229fb352b1SJarkko Nikula */
1423749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
14242a6fedecSMark Brown regcache_mark_dirty(aic3x->regmap);
14256c1a7d40SJarkko Nikula aic3x->power = 0;
14265a895f8aSJarkko Nikula /* HW writes are needless when bias is off */
14272a6fedecSMark Brown regcache_cache_only(aic3x->regmap, true);
14286c1a7d40SJarkko Nikula ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
14296c1a7d40SJarkko Nikula aic3x->supplies);
14306c1a7d40SJarkko Nikula }
14316c1a7d40SJarkko Nikula out:
14326c1a7d40SJarkko Nikula return ret;
14336c1a7d40SJarkko Nikula }
14346c1a7d40SJarkko Nikula
aic3x_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)1435749ad545SKuninori Morimoto static int aic3x_set_bias_level(struct snd_soc_component *component,
14360be9898aSMark Brown enum snd_soc_bias_level level)
143744d0a879SVladimir Barinov {
1438749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
143944d0a879SVladimir Barinov
14400be9898aSMark Brown switch (level) {
14410be9898aSMark Brown case SND_SOC_BIAS_ON:
1442db13802eSJarkko Nikula break;
1443db13802eSJarkko Nikula case SND_SOC_BIAS_PREPARE:
1444749ad545SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY &&
1445c23fd751SJarkko Nikula aic3x->master) {
144644d0a879SVladimir Barinov /* enable pll */
1447749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
14489c173d15SAxel Lin PLL_ENABLE, PLL_ENABLE);
144944d0a879SVladimir Barinov }
145044d0a879SVladimir Barinov break;
14510be9898aSMark Brown case SND_SOC_BIAS_STANDBY:
14526c1a7d40SJarkko Nikula if (!aic3x->power)
1453749ad545SKuninori Morimoto aic3x_set_power(component, 1);
1454749ad545SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE &&
1455c23fd751SJarkko Nikula aic3x->master) {
145644d0a879SVladimir Barinov /* disable pll */
1457749ad545SKuninori Morimoto snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
14589c173d15SAxel Lin PLL_ENABLE, 0);
145944d0a879SVladimir Barinov }
146044d0a879SVladimir Barinov break;
1461c23fd751SJarkko Nikula case SND_SOC_BIAS_OFF:
14626c1a7d40SJarkko Nikula if (aic3x->power)
1463749ad545SKuninori Morimoto aic3x_set_power(component, 0);
1464c23fd751SJarkko Nikula break;
146544d0a879SVladimir Barinov }
146644d0a879SVladimir Barinov
146744d0a879SVladimir Barinov return 0;
146844d0a879SVladimir Barinov }
146944d0a879SVladimir Barinov
147044d0a879SVladimir Barinov #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000
147144d0a879SVladimir Barinov #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
14722a11a10aSPeter Ujfalusi SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
14732a11a10aSPeter Ujfalusi SNDRV_PCM_FMTBIT_S32_LE)
147444d0a879SVladimir Barinov
147585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops aic3x_dai_ops = {
14766335d055SEric Miao .hw_params = aic3x_hw_params,
147736849409SPeter Ujfalusi .prepare = aic3x_prepare,
1478960af79dSKuninori Morimoto .mute_stream = aic3x_mute,
14796335d055SEric Miao .set_sysclk = aic3x_set_dai_sysclk,
14806335d055SEric Miao .set_fmt = aic3x_set_dai_fmt,
148136849409SPeter Ujfalusi .set_tdm_slot = aic3x_set_dai_tdm_slot,
1482960af79dSKuninori Morimoto .no_capture_mute = 1,
14836335d055SEric Miao };
14846335d055SEric Miao
1485f0fba2adSLiam Girdwood static struct snd_soc_dai_driver aic3x_dai = {
1486f0fba2adSLiam Girdwood .name = "tlv320aic3x-hifi",
148744d0a879SVladimir Barinov .playback = {
148844d0a879SVladimir Barinov .stream_name = "Playback",
148906378da4SBenoît Thébaudeau .channels_min = 2,
149044d0a879SVladimir Barinov .channels_max = 2,
149144d0a879SVladimir Barinov .rates = AIC3X_RATES,
149244d0a879SVladimir Barinov .formats = AIC3X_FORMATS,},
149344d0a879SVladimir Barinov .capture = {
149444d0a879SVladimir Barinov .stream_name = "Capture",
149506378da4SBenoît Thébaudeau .channels_min = 2,
149644d0a879SVladimir Barinov .channels_max = 2,
149744d0a879SVladimir Barinov .rates = AIC3X_RATES,
149844d0a879SVladimir Barinov .formats = AIC3X_FORMATS,},
14996335d055SEric Miao .ops = &aic3x_dai_ops,
1500a9aef184SKuninori Morimoto .symmetric_rate = 1,
150144d0a879SVladimir Barinov };
150244d0a879SVladimir Barinov
aic3x_mono_init(struct snd_soc_component * component)1503749ad545SKuninori Morimoto static void aic3x_mono_init(struct snd_soc_component *component)
150458381da6SJan Weitzel {
150558381da6SJan Weitzel /* DAC to Mono Line Out default volume and route to Output mixer */
1506749ad545SKuninori Morimoto snd_soc_component_write(component, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1507749ad545SKuninori Morimoto snd_soc_component_write(component, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
150858381da6SJan Weitzel
150958381da6SJan Weitzel /* unmute all outputs */
1510749ad545SKuninori Morimoto snd_soc_component_update_bits(component, MONOLOPM_CTRL, UNMUTE, UNMUTE);
151158381da6SJan Weitzel
151258381da6SJan Weitzel /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
1513749ad545SKuninori Morimoto snd_soc_component_write(component, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
1514749ad545SKuninori Morimoto snd_soc_component_write(component, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
151558381da6SJan Weitzel
151658381da6SJan Weitzel /* Line2 to Mono Out default volume, disconnect from Output Mixer */
1517749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
1518749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
151958381da6SJan Weitzel }
152058381da6SJan Weitzel
152144d0a879SVladimir Barinov /*
152244d0a879SVladimir Barinov * initialise the AIC3X driver
152344d0a879SVladimir Barinov * register the mixer and dsp interfaces with the kernel
152444d0a879SVladimir Barinov */
aic3x_init(struct snd_soc_component * component)1525749ad545SKuninori Morimoto static int aic3x_init(struct snd_soc_component *component)
152644d0a879SVladimir Barinov {
1527749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
1528cb3826f5SBen Dooks
1529749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_PAGE_SELECT, PAGE0_SELECT);
1530749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
153144d0a879SVladimir Barinov
153244d0a879SVladimir Barinov /* DAC default volume and mute */
1533749ad545SKuninori Morimoto snd_soc_component_write(component, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
1534749ad545SKuninori Morimoto snd_soc_component_write(component, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
153544d0a879SVladimir Barinov
153644d0a879SVladimir Barinov /* DAC to HP default volume and route to Output mixer */
1537749ad545SKuninori Morimoto snd_soc_component_write(component, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
1538749ad545SKuninori Morimoto snd_soc_component_write(component, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
1539749ad545SKuninori Morimoto snd_soc_component_write(component, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
1540749ad545SKuninori Morimoto snd_soc_component_write(component, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
154144d0a879SVladimir Barinov /* DAC to Line Out default volume and route to Output mixer */
1542749ad545SKuninori Morimoto snd_soc_component_write(component, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1543749ad545SKuninori Morimoto snd_soc_component_write(component, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
154444d0a879SVladimir Barinov
154544d0a879SVladimir Barinov /* unmute all outputs */
1546749ad545SKuninori Morimoto snd_soc_component_update_bits(component, LLOPM_CTRL, UNMUTE, UNMUTE);
1547749ad545SKuninori Morimoto snd_soc_component_update_bits(component, RLOPM_CTRL, UNMUTE, UNMUTE);
1548749ad545SKuninori Morimoto snd_soc_component_update_bits(component, HPLOUT_CTRL, UNMUTE, UNMUTE);
1549749ad545SKuninori Morimoto snd_soc_component_update_bits(component, HPROUT_CTRL, UNMUTE, UNMUTE);
1550749ad545SKuninori Morimoto snd_soc_component_update_bits(component, HPLCOM_CTRL, UNMUTE, UNMUTE);
1551749ad545SKuninori Morimoto snd_soc_component_update_bits(component, HPRCOM_CTRL, UNMUTE, UNMUTE);
155244d0a879SVladimir Barinov
155344d0a879SVladimir Barinov /* ADC default volume and unmute */
1554749ad545SKuninori Morimoto snd_soc_component_write(component, LADC_VOL, DEFAULT_GAIN);
1555749ad545SKuninori Morimoto snd_soc_component_write(component, RADC_VOL, DEFAULT_GAIN);
155644d0a879SVladimir Barinov /* By default route Line1 to ADC PGA mixer */
1557749ad545SKuninori Morimoto snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x0);
1558749ad545SKuninori Morimoto snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x0);
155944d0a879SVladimir Barinov
156044d0a879SVladimir Barinov /* PGA to HP Bypass default volume, disconnect from Output Mixer */
1561749ad545SKuninori Morimoto snd_soc_component_write(component, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
1562749ad545SKuninori Morimoto snd_soc_component_write(component, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
1563749ad545SKuninori Morimoto snd_soc_component_write(component, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
1564749ad545SKuninori Morimoto snd_soc_component_write(component, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
156544d0a879SVladimir Barinov /* PGA to Line Out default volume, disconnect from Output Mixer */
1566749ad545SKuninori Morimoto snd_soc_component_write(component, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
1567749ad545SKuninori Morimoto snd_soc_component_write(component, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
156844d0a879SVladimir Barinov
15692d1180e3SRick Mann /* On tlv320aic3104, these registers are reserved and must not be written */
15702d1180e3SRick Mann if (aic3x->model != AIC3X_MODEL_3104) {
157144d0a879SVladimir Barinov /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
1572749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
1573749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
1574749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
1575749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
157644d0a879SVladimir Barinov /* Line2 Line Out default volume, disconnect from Output Mixer */
1577749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
1578749ad545SKuninori Morimoto snd_soc_component_write(component, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
15792d1180e3SRick Mann }
158044d0a879SVladimir Barinov
158158381da6SJan Weitzel switch (aic3x->model) {
158258381da6SJan Weitzel case AIC3X_MODEL_3X:
158358381da6SJan Weitzel case AIC3X_MODEL_33:
1584a0bc855fSJiri Prchal case AIC3X_MODEL_3106:
1585749ad545SKuninori Morimoto aic3x_mono_init(component);
158658381da6SJan Weitzel break;
158758381da6SJan Weitzel case AIC3X_MODEL_3007:
1588749ad545SKuninori Morimoto snd_soc_component_write(component, CLASSD_CTRL, 0);
158958381da6SJan Weitzel break;
15906184f105SRandolph Chung }
15916184f105SRandolph Chung
159219b0fa11SPeter Ujfalusi /* Output common-mode voltage = 1.5 V */
1593749ad545SKuninori Morimoto snd_soc_component_update_bits(component, HPOUT_SC, HPOUT_SC_OCMV_MASK,
159419b0fa11SPeter Ujfalusi aic3x->ocmv << HPOUT_SC_OCMV_SHIFT);
159519b0fa11SPeter Ujfalusi
1596cb3826f5SBen Dooks return 0;
1597cb3826f5SBen Dooks }
159854e7e616SDaniel Mack
aic3x_component_probe(struct snd_soc_component * component)1599b015df6aSJiri Prchal static int aic3x_component_probe(struct snd_soc_component *component)
1600cb3826f5SBen Dooks {
1601749ad545SKuninori Morimoto struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
16022f24111aSJarkko Nikula int ret, i;
1603cb3826f5SBen Dooks
1604749ad545SKuninori Morimoto aic3x->component = component;
1605f0fba2adSLiam Girdwood
16065a895f8aSJarkko Nikula for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
16075a895f8aSJarkko Nikula aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
16085a895f8aSJarkko Nikula aic3x->disable_nb[i].aic3x = aic3x;
16090bb423f2SGuennadi Liakhovetski ret = devm_regulator_register_notifier(
16100bb423f2SGuennadi Liakhovetski aic3x->supplies[i].consumer,
16115a895f8aSJarkko Nikula &aic3x->disable_nb[i].nb);
16125a895f8aSJarkko Nikula if (ret) {
1613749ad545SKuninori Morimoto dev_err(component->dev,
16145a895f8aSJarkko Nikula "Failed to request regulator notifier: %d\n",
16155a895f8aSJarkko Nikula ret);
16160bb423f2SGuennadi Liakhovetski return ret;
16175a895f8aSJarkko Nikula }
16185a895f8aSJarkko Nikula }
16192f24111aSJarkko Nikula
16202a6fedecSMark Brown regcache_mark_dirty(aic3x->regmap);
1621749ad545SKuninori Morimoto aic3x_init(component);
162237b47656SJarkko Nikula
1623f0fba2adSLiam Girdwood if (aic3x->setup) {
16249503112dSJyri Sarha if (aic3x->model != AIC3X_MODEL_3104) {
1625f0fba2adSLiam Girdwood /* setup GPIO functions */
1626749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_GPIO1_REG,
1627f0fba2adSLiam Girdwood (aic3x->setup->gpio_func[0] & 0xf) << 4);
1628749ad545SKuninori Morimoto snd_soc_component_write(component, AIC3X_GPIO2_REG,
1629f0fba2adSLiam Girdwood (aic3x->setup->gpio_func[1] & 0xf) << 4);
16309503112dSJyri Sarha } else {
1631749ad545SKuninori Morimoto dev_warn(component->dev, "GPIO functionality is not supported on tlv320aic3104\n");
16329503112dSJyri Sarha }
163344d0a879SVladimir Barinov }
163444d0a879SVladimir Barinov
163558381da6SJan Weitzel switch (aic3x->model) {
163658381da6SJan Weitzel case AIC3X_MODEL_3X:
163758381da6SJan Weitzel case AIC3X_MODEL_33:
1638a0bc855fSJiri Prchal case AIC3X_MODEL_3106:
1639749ad545SKuninori Morimoto snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
16409503112dSJyri Sarha ARRAY_SIZE(aic3x_extra_snd_controls));
1641749ad545SKuninori Morimoto snd_soc_add_component_controls(component, aic3x_mono_controls,
164258381da6SJan Weitzel ARRAY_SIZE(aic3x_mono_controls));
164358381da6SJan Weitzel break;
164458381da6SJan Weitzel case AIC3X_MODEL_3007:
1645749ad545SKuninori Morimoto snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
16469503112dSJyri Sarha ARRAY_SIZE(aic3x_extra_snd_controls));
1647749ad545SKuninori Morimoto snd_soc_add_component_controls(component,
164858381da6SJan Weitzel &aic3x_classd_amp_gain_ctrl, 1);
164958381da6SJan Weitzel break;
16509503112dSJyri Sarha case AIC3X_MODEL_3104:
16519503112dSJyri Sarha break;
165258381da6SJan Weitzel }
1653cb3826f5SBen Dooks
1654e2e8bfdfSHebbar Gururaja /* set mic bias voltage */
1655e2e8bfdfSHebbar Gururaja switch (aic3x->micbias_vg) {
1656e2e8bfdfSHebbar Gururaja case AIC3X_MICBIAS_2_0V:
1657e2e8bfdfSHebbar Gururaja case AIC3X_MICBIAS_2_5V:
1658e2e8bfdfSHebbar Gururaja case AIC3X_MICBIAS_AVDDV:
1659749ad545SKuninori Morimoto snd_soc_component_update_bits(component, MICBIAS_CTRL,
1660e2e8bfdfSHebbar Gururaja MICBIAS_LEVEL_MASK,
1661e2e8bfdfSHebbar Gururaja (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
1662e2e8bfdfSHebbar Gururaja break;
1663e2e8bfdfSHebbar Gururaja case AIC3X_MICBIAS_OFF:
1664e2e8bfdfSHebbar Gururaja /*
1665e2e8bfdfSHebbar Gururaja * noting to do. target won't enter here. This is just to avoid
1666e2e8bfdfSHebbar Gururaja * compile time warning "warning: enumeration value
1667e2e8bfdfSHebbar Gururaja * 'AIC3X_MICBIAS_OFF' not handled in switch"
1668e2e8bfdfSHebbar Gururaja */
1669e2e8bfdfSHebbar Gururaja break;
1670e2e8bfdfSHebbar Gururaja }
1671e2e8bfdfSHebbar Gururaja
1672749ad545SKuninori Morimoto aic3x_add_widgets(component);
1673cb3826f5SBen Dooks
1674cb3826f5SBen Dooks return 0;
1675cb3826f5SBen Dooks }
167644d0a879SVladimir Barinov
1677749ad545SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_aic3x = {
1678f0fba2adSLiam Girdwood .set_bias_level = aic3x_set_bias_level,
1679b015df6aSJiri Prchal .probe = aic3x_component_probe,
1680f9df1ae6SMark Brown .controls = aic3x_snd_controls,
1681f9df1ae6SMark Brown .num_controls = ARRAY_SIZE(aic3x_snd_controls),
168258a63fbdSMark Brown .dapm_widgets = aic3x_dapm_widgets,
168358a63fbdSMark Brown .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
168458a63fbdSMark Brown .dapm_routes = intercon,
168558a63fbdSMark Brown .num_dapm_routes = ARRAY_SIZE(intercon),
1686749ad545SKuninori Morimoto .use_pmdown_time = 1,
1687749ad545SKuninori Morimoto .endianness = 1,
1688f0fba2adSLiam Girdwood };
1689f0fba2adSLiam Girdwood
aic3x_configure_ocmv(struct device * dev,struct aic3x_priv * aic3x)1690a96d2ba2SJiri Prchal static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x)
169119b0fa11SPeter Ujfalusi {
1692a96d2ba2SJiri Prchal struct device_node *np = dev->of_node;
169319b0fa11SPeter Ujfalusi u32 value;
169419b0fa11SPeter Ujfalusi int dvdd, avdd;
169519b0fa11SPeter Ujfalusi
169619b0fa11SPeter Ujfalusi if (np && !of_property_read_u32(np, "ai3x-ocmv", &value)) {
169719b0fa11SPeter Ujfalusi /* OCMV setting is forced by DT */
169819b0fa11SPeter Ujfalusi if (value <= 3) {
169919b0fa11SPeter Ujfalusi aic3x->ocmv = value;
170019b0fa11SPeter Ujfalusi return;
170119b0fa11SPeter Ujfalusi }
170219b0fa11SPeter Ujfalusi }
170319b0fa11SPeter Ujfalusi
170419b0fa11SPeter Ujfalusi dvdd = regulator_get_voltage(aic3x->supplies[1].consumer);
170519b0fa11SPeter Ujfalusi avdd = regulator_get_voltage(aic3x->supplies[2].consumer);
170619b0fa11SPeter Ujfalusi
170719b0fa11SPeter Ujfalusi if (avdd > 3600000 || dvdd > 1950000) {
1708a96d2ba2SJiri Prchal dev_warn(dev,
170919b0fa11SPeter Ujfalusi "Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
171019b0fa11SPeter Ujfalusi avdd, dvdd);
171119b0fa11SPeter Ujfalusi } else if (avdd == 3600000 && dvdd == 1950000) {
171219b0fa11SPeter Ujfalusi aic3x->ocmv = HPOUT_SC_OCMV_1_8V;
171319b0fa11SPeter Ujfalusi } else if (avdd > 3300000 && dvdd > 1800000) {
171419b0fa11SPeter Ujfalusi aic3x->ocmv = HPOUT_SC_OCMV_1_65V;
171519b0fa11SPeter Ujfalusi } else if (avdd > 3000000 && dvdd > 1650000) {
171619b0fa11SPeter Ujfalusi aic3x->ocmv = HPOUT_SC_OCMV_1_5V;
171719b0fa11SPeter Ujfalusi } else if (avdd >= 2700000 && dvdd >= 1525000) {
171819b0fa11SPeter Ujfalusi aic3x->ocmv = HPOUT_SC_OCMV_1_35V;
171919b0fa11SPeter Ujfalusi } else {
1720a96d2ba2SJiri Prchal dev_warn(dev,
172119b0fa11SPeter Ujfalusi "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
172219b0fa11SPeter Ujfalusi avdd, dvdd);
172319b0fa11SPeter Ujfalusi }
172419b0fa11SPeter Ujfalusi }
172519b0fa11SPeter Ujfalusi
17266184f105SRandolph Chung
17278019ff6cSNariman Poushin static const struct reg_sequence aic3007_class_d[] = {
17282a6fedecSMark Brown /* Class-D speaker driver init; datasheet p. 46 */
17292a6fedecSMark Brown { AIC3X_PAGE_SELECT, 0x0D },
17302a6fedecSMark Brown { 0xD, 0x0D },
17312a6fedecSMark Brown { 0x8, 0x5C },
17322a6fedecSMark Brown { 0x8, 0x5D },
17332a6fedecSMark Brown { 0x8, 0x5C },
17342a6fedecSMark Brown { AIC3X_PAGE_SELECT, 0x00 },
17352a6fedecSMark Brown };
17362a6fedecSMark Brown
aic3x_probe(struct device * dev,struct regmap * regmap,kernel_ulong_t driver_data)1737a96d2ba2SJiri Prchal int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
173844d0a879SVladimir Barinov {
1739f0fba2adSLiam Girdwood struct aic3x_priv *aic3x;
1740c24fdc88SHebbar, Gururaja struct aic3x_setup_data *ai3x_setup;
1741a96d2ba2SJiri Prchal struct device_node *np = dev->of_node;
17426f818e04SMark Brown int ret, i;
1743e2e8bfdfSHebbar Gururaja u32 value;
174444d0a879SVladimir Barinov
1745a96d2ba2SJiri Prchal aic3x = devm_kzalloc(dev, sizeof(struct aic3x_priv), GFP_KERNEL);
1746b1117f52SSachin Kamat if (!aic3x)
1747cb3826f5SBen Dooks return -ENOMEM;
1748cb3826f5SBen Dooks
1749a96d2ba2SJiri Prchal aic3x->regmap = regmap;
17502a6fedecSMark Brown if (IS_ERR(aic3x->regmap)) {
17512a6fedecSMark Brown ret = PTR_ERR(aic3x->regmap);
17522a6fedecSMark Brown return ret;
17532a6fedecSMark Brown }
17542a6fedecSMark Brown
17552a6fedecSMark Brown regcache_cache_only(aic3x->regmap, true);
1756a84a441bSJarkko Nikula
1757a96d2ba2SJiri Prchal dev_set_drvdata(dev, aic3x);
1758426c7bf4SDmitry Torokhov if (np) {
1759a96d2ba2SJiri Prchal ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL);
1760b1117f52SSachin Kamat if (!ai3x_setup)
1761c24fdc88SHebbar, Gururaja return -ENOMEM;
1762c24fdc88SHebbar, Gururaja
1763c24fdc88SHebbar, Gururaja if (of_property_read_u32_array(np, "ai3x-gpio-func",
1764c24fdc88SHebbar, Gururaja ai3x_setup->gpio_func, 2) >= 0) {
1765c24fdc88SHebbar, Gururaja aic3x->setup = ai3x_setup;
1766c24fdc88SHebbar, Gururaja }
1767c24fdc88SHebbar, Gururaja
1768e2e8bfdfSHebbar Gururaja if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
1769e2e8bfdfSHebbar Gururaja switch (value) {
1770e2e8bfdfSHebbar Gururaja case 1 :
1771e2e8bfdfSHebbar Gururaja aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
1772e2e8bfdfSHebbar Gururaja break;
1773e2e8bfdfSHebbar Gururaja case 2 :
1774e2e8bfdfSHebbar Gururaja aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
1775e2e8bfdfSHebbar Gururaja break;
1776e2e8bfdfSHebbar Gururaja case 3 :
1777e2e8bfdfSHebbar Gururaja aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
1778e2e8bfdfSHebbar Gururaja break;
1779e2e8bfdfSHebbar Gururaja default :
1780e2e8bfdfSHebbar Gururaja aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
1781a96d2ba2SJiri Prchal dev_err(dev, "Unsuitable MicBias voltage "
1782e2e8bfdfSHebbar Gururaja "found in DT\n");
1783e2e8bfdfSHebbar Gururaja }
1784e2e8bfdfSHebbar Gururaja } else {
1785e2e8bfdfSHebbar Gururaja aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
1786e2e8bfdfSHebbar Gururaja }
1787c776357eSJarkko Nikula }
1788c776357eSJarkko Nikula
1789a96d2ba2SJiri Prchal aic3x->model = driver_data;
17906184f105SRandolph Chung
1791*a984d833SDmitry Torokhov aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
1792*a984d833SDmitry Torokhov GPIOD_OUT_HIGH);
1793*a984d833SDmitry Torokhov ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
1794*a984d833SDmitry Torokhov if (ret) {
1795*a984d833SDmitry Torokhov if (ret != -EBUSY)
1796*a984d833SDmitry Torokhov return ret;
1797*a984d833SDmitry Torokhov
1798*a984d833SDmitry Torokhov /*
1799*a984d833SDmitry Torokhov * Apparently there are setups where the codec is sharing
1800*a984d833SDmitry Torokhov * its reset line. Try to get it non-exclusively, although
1801*a984d833SDmitry Torokhov * the utility of this is unclear: how do we make sure that
1802*a984d833SDmitry Torokhov * resetting one chip will not disturb the others that share
1803*a984d833SDmitry Torokhov * the same line?
1804*a984d833SDmitry Torokhov */
1805*a984d833SDmitry Torokhov aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
1806*a984d833SDmitry Torokhov GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
1807*a984d833SDmitry Torokhov ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
1808*a984d833SDmitry Torokhov if (ret)
1809*a984d833SDmitry Torokhov return ret;
1810*a984d833SDmitry Torokhov
1811*a984d833SDmitry Torokhov aic3x->shared_reset = true;
18126f818e04SMark Brown }
18136f818e04SMark Brown
1814*a984d833SDmitry Torokhov gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
1815*a984d833SDmitry Torokhov
18166f818e04SMark Brown for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
18176f818e04SMark Brown aic3x->supplies[i].supply = aic3x_supply_names[i];
18186f818e04SMark Brown
1819a96d2ba2SJiri Prchal ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
18206f818e04SMark Brown aic3x->supplies);
1821*a984d833SDmitry Torokhov if (ret) {
1822a96d2ba2SJiri Prchal dev_err(dev, "Failed to request supplies: %d\n", ret);
1823*a984d833SDmitry Torokhov return ret;
18246f818e04SMark Brown }
18256f818e04SMark Brown
1826a96d2ba2SJiri Prchal aic3x_configure_ocmv(dev, aic3x);
182719b0fa11SPeter Ujfalusi
18282a6fedecSMark Brown if (aic3x->model == AIC3X_MODEL_3007) {
18292a6fedecSMark Brown ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
18302a6fedecSMark Brown ARRAY_SIZE(aic3007_class_d));
18312a6fedecSMark Brown if (ret != 0)
1832*a984d833SDmitry Torokhov dev_err(dev, "Failed to init class D: %d\n", ret);
18332a6fedecSMark Brown }
18342a6fedecSMark Brown
1835a96d2ba2SJiri Prchal ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
1836*a984d833SDmitry Torokhov if (ret)
1837*a984d833SDmitry Torokhov return ret;
18383b5b2431SSebastian Reichel
18393b5b2431SSebastian Reichel return 0;
184044d0a879SVladimir Barinov }
1841a96d2ba2SJiri Prchal EXPORT_SYMBOL(aic3x_probe);
184244d0a879SVladimir Barinov
aic3x_remove(struct device * dev)18432a798513SUwe Kleine-König void aic3x_remove(struct device *dev)
184444d0a879SVladimir Barinov {
1845a96d2ba2SJiri Prchal struct aic3x_priv *aic3x = dev_get_drvdata(dev);
18466f818e04SMark Brown
1847*a984d833SDmitry Torokhov /* Leave the codec in reset state */
1848*a984d833SDmitry Torokhov if (aic3x->gpio_reset && !aic3x->shared_reset)
1849*a984d833SDmitry Torokhov gpiod_set_value(aic3x->gpio_reset, 1);
185044d0a879SVladimir Barinov }
1851a96d2ba2SJiri Prchal EXPORT_SYMBOL(aic3x_remove);
185264089b84SMark Brown
185344d0a879SVladimir Barinov MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
185444d0a879SVladimir Barinov MODULE_AUTHOR("Vladimir Barinov");
185544d0a879SVladimir Barinov MODULE_LICENSE("GPL");
1856