1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright (c) 2017, Maxim Integrated
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/acpi.h>
5*4882a593Smuzhiyun #include <linux/delay.h>
6*4882a593Smuzhiyun #include <linux/i2c.h>
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/regmap.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/cdev.h>
11*4882a593Smuzhiyun #include <sound/pcm.h>
12*4882a593Smuzhiyun #include <sound/pcm_params.h>
13*4882a593Smuzhiyun #include <sound/soc.h>
14*4882a593Smuzhiyun #include <linux/gpio.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/of_gpio.h>
17*4882a593Smuzhiyun #include <sound/tlv.h>
18*4882a593Smuzhiyun #include "max98373.h"
19*4882a593Smuzhiyun
max98373_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)20*4882a593Smuzhiyun static int max98373_dac_event(struct snd_soc_dapm_widget *w,
21*4882a593Smuzhiyun struct snd_kcontrol *kcontrol, int event)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
24*4882a593Smuzhiyun struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun switch (event) {
27*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMU:
28*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
29*4882a593Smuzhiyun MAX98373_R20FF_GLOBAL_SHDN,
30*4882a593Smuzhiyun MAX98373_GLOBAL_EN_MASK, 1);
31*4882a593Smuzhiyun usleep_range(30000, 31000);
32*4882a593Smuzhiyun break;
33*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMD:
34*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
35*4882a593Smuzhiyun MAX98373_R20FF_GLOBAL_SHDN,
36*4882a593Smuzhiyun MAX98373_GLOBAL_EN_MASK, 0);
37*4882a593Smuzhiyun usleep_range(30000, 31000);
38*4882a593Smuzhiyun max98373->tdm_mode = false;
39*4882a593Smuzhiyun break;
40*4882a593Smuzhiyun default:
41*4882a593Smuzhiyun return 0;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static const char * const max98373_switch_text[] = {
47*4882a593Smuzhiyun "Left", "Right", "LeftRight"};
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static const struct soc_enum dai_sel_enum =
50*4882a593Smuzhiyun SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
51*4882a593Smuzhiyun MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
52*4882a593Smuzhiyun 3, max98373_switch_text);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const struct snd_kcontrol_new max98373_dai_controls =
55*4882a593Smuzhiyun SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static const struct snd_kcontrol_new max98373_vi_control =
58*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", MAX98373_R202C_PCM_TX_EN, 0, 1, 0);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static const struct snd_kcontrol_new max98373_spkfb_control =
61*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", MAX98373_R2043_AMP_EN, 1, 1, 0);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = {
64*4882a593Smuzhiyun SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
65*4882a593Smuzhiyun MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event,
66*4882a593Smuzhiyun SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
67*4882a593Smuzhiyun SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
68*4882a593Smuzhiyun &max98373_dai_controls),
69*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("BE_OUT"),
70*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
71*4882a593Smuzhiyun MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0),
72*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
73*4882a593Smuzhiyun MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0),
74*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("Speaker FB Sense", "HiFi Capture", 0,
75*4882a593Smuzhiyun SND_SOC_NOPM, 0, 0),
76*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
77*4882a593Smuzhiyun &max98373_vi_control),
78*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SpkFB Sense", SND_SOC_NOPM, 0, 0,
79*4882a593Smuzhiyun &max98373_spkfb_control),
80*4882a593Smuzhiyun SND_SOC_DAPM_SIGGEN("VMON"),
81*4882a593Smuzhiyun SND_SOC_DAPM_SIGGEN("IMON"),
82*4882a593Smuzhiyun SND_SOC_DAPM_SIGGEN("FBMON"),
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1);
86*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
87*4882a593Smuzhiyun 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
88*4882a593Smuzhiyun 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
89*4882a593Smuzhiyun );
90*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv,
91*4882a593Smuzhiyun 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
92*4882a593Smuzhiyun );
93*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv,
94*4882a593Smuzhiyun 0, 1, TLV_DB_SCALE_ITEM(25, 25, 0),
95*4882a593Smuzhiyun 2, 4, TLV_DB_SCALE_ITEM(100, 100, 0),
96*4882a593Smuzhiyun );
97*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
98*4882a593Smuzhiyun 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
99*4882a593Smuzhiyun );
100*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
101*4882a593Smuzhiyun 0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0),
102*4882a593Smuzhiyun 2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0),
103*4882a593Smuzhiyun 5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0),
104*4882a593Smuzhiyun 7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0),
105*4882a593Smuzhiyun 10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0),
106*4882a593Smuzhiyun 14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0),
107*4882a593Smuzhiyun );
108*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
109*4882a593Smuzhiyun 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
110*4882a593Smuzhiyun );
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
113*4882a593Smuzhiyun 0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0),
114*4882a593Smuzhiyun );
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static const char * const max98373_output_voltage_lvl_text[] = {
117*4882a593Smuzhiyun "5.43V", "6.09V", "6.83V", "7.67V", "8.60V",
118*4882a593Smuzhiyun "9.65V", "10.83V", "12.15V", "13.63V", "15.29V"
119*4882a593Smuzhiyun };
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum,
122*4882a593Smuzhiyun MAX98373_R203E_AMP_PATH_GAIN, 0,
123*4882a593Smuzhiyun max98373_output_voltage_lvl_text);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun static const char * const max98373_dht_attack_rate_text[] = {
126*4882a593Smuzhiyun "17.5us", "35us", "70us", "140us",
127*4882a593Smuzhiyun "280us", "560us", "1120us", "2240us"
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum,
131*4882a593Smuzhiyun MAX98373_R20D2_DHT_ATTACK_CFG, 0,
132*4882a593Smuzhiyun max98373_dht_attack_rate_text);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun static const char * const max98373_dht_release_rate_text[] = {
135*4882a593Smuzhiyun "45ms", "225ms", "450ms", "1150ms",
136*4882a593Smuzhiyun "2250ms", "3100ms", "4500ms", "6750ms"
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum,
140*4882a593Smuzhiyun MAX98373_R20D3_DHT_RELEASE_CFG, 0,
141*4882a593Smuzhiyun max98373_dht_release_rate_text);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun static const char * const max98373_limiter_attack_rate_text[] = {
144*4882a593Smuzhiyun "10us", "20us", "40us", "80us",
145*4882a593Smuzhiyun "160us", "320us", "640us", "1.28ms",
146*4882a593Smuzhiyun "2.56ms", "5.12ms", "10.24ms", "20.48ms",
147*4882a593Smuzhiyun "40.96ms", "81.92ms", "16.384ms", "32.768ms"
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum,
151*4882a593Smuzhiyun MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4,
152*4882a593Smuzhiyun max98373_limiter_attack_rate_text);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun static const char * const max98373_limiter_release_rate_text[] = {
155*4882a593Smuzhiyun "40us", "80us", "160us", "320us",
156*4882a593Smuzhiyun "640us", "1.28ms", "2.56ms", "5.120ms",
157*4882a593Smuzhiyun "10.24ms", "20.48ms", "40.96ms", "81.92ms",
158*4882a593Smuzhiyun "163.84ms", "327.68ms", "655.36ms", "1310.72ms"
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum,
162*4882a593Smuzhiyun MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0,
163*4882a593Smuzhiyun max98373_limiter_release_rate_text);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun static const char * const max98373_ADC_samplerate_text[] = {
166*4882a593Smuzhiyun "333kHz", "192kHz", "64kHz", "48kHz"
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
170*4882a593Smuzhiyun MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
171*4882a593Smuzhiyun max98373_ADC_samplerate_text);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun static const struct snd_kcontrol_new max98373_snd_controls[] = {
174*4882a593Smuzhiyun SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
175*4882a593Smuzhiyun MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
176*4882a593Smuzhiyun SOC_SINGLE("Volume Location Switch", MAX98373_R203F_AMP_DSP_CFG,
177*4882a593Smuzhiyun MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
178*4882a593Smuzhiyun SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
179*4882a593Smuzhiyun MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
180*4882a593Smuzhiyun SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
181*4882a593Smuzhiyun MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
182*4882a593Smuzhiyun SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
183*4882a593Smuzhiyun MAX98373_CLOCK_MON_SHIFT, 1, 0),
184*4882a593Smuzhiyun SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
185*4882a593Smuzhiyun MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0),
186*4882a593Smuzhiyun SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
187*4882a593Smuzhiyun MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
188*4882a593Smuzhiyun SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
189*4882a593Smuzhiyun 0, 0x7F, 1, max98373_digital_tlv),
190*4882a593Smuzhiyun SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
191*4882a593Smuzhiyun MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
192*4882a593Smuzhiyun SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
193*4882a593Smuzhiyun MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv),
194*4882a593Smuzhiyun SOC_ENUM("Output Voltage", max98373_out_volt_enum),
195*4882a593Smuzhiyun /* Dynamic Headroom Tracking */
196*4882a593Smuzhiyun SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
197*4882a593Smuzhiyun MAX98373_DHT_EN_SHIFT, 1, 0),
198*4882a593Smuzhiyun SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
199*4882a593Smuzhiyun MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
200*4882a593Smuzhiyun SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
201*4882a593Smuzhiyun MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv),
202*4882a593Smuzhiyun SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
203*4882a593Smuzhiyun MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
204*4882a593Smuzhiyun SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
205*4882a593Smuzhiyun MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
206*4882a593Smuzhiyun SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum),
207*4882a593Smuzhiyun SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum),
208*4882a593Smuzhiyun /* ADC configuration */
209*4882a593Smuzhiyun SOC_SINGLE("ADC PVDD CH Switch", MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0),
210*4882a593Smuzhiyun SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
211*4882a593Smuzhiyun MAX98373_FLT_EN_SHIFT, 1, 0),
212*4882a593Smuzhiyun SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
213*4882a593Smuzhiyun MAX98373_FLT_EN_SHIFT, 1, 0),
214*4882a593Smuzhiyun SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
215*4882a593Smuzhiyun SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
216*4882a593Smuzhiyun SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
217*4882a593Smuzhiyun 0, 0x3, 0),
218*4882a593Smuzhiyun SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
219*4882a593Smuzhiyun 0, 0x3, 0),
220*4882a593Smuzhiyun SOC_ENUM("ADC SampleRate", max98373_adc_samplerate_enum),
221*4882a593Smuzhiyun /* Brownout Detection Engine */
222*4882a593Smuzhiyun SOC_SINGLE("BDE Switch", MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0),
223*4882a593Smuzhiyun SOC_SINGLE("BDE LVL4 Mute Switch", MAX98373_R20B2_BDE_L4_CFG_2,
224*4882a593Smuzhiyun MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0),
225*4882a593Smuzhiyun SOC_SINGLE("BDE LVL4 Hold Switch", MAX98373_R20B2_BDE_L4_CFG_2,
226*4882a593Smuzhiyun MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0),
227*4882a593Smuzhiyun SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
228*4882a593Smuzhiyun SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
229*4882a593Smuzhiyun SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
230*4882a593Smuzhiyun SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
231*4882a593Smuzhiyun SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
232*4882a593Smuzhiyun SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
233*4882a593Smuzhiyun SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
234*4882a593Smuzhiyun SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
235*4882a593Smuzhiyun SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
236*4882a593Smuzhiyun SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
237*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
238*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
239*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
240*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
241*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
242*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
243*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
244*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
245*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
246*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
247*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
248*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
249*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
250*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
251*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
252*4882a593Smuzhiyun 0, 0x3C, 1, max98373_bde_gain_tlv),
253*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
254*4882a593Smuzhiyun 0, 0xF, 1, max98373_limiter_thresh_tlv),
255*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
256*4882a593Smuzhiyun 0, 0xF, 1, max98373_limiter_thresh_tlv),
257*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
258*4882a593Smuzhiyun 0, 0xF, 1, max98373_limiter_thresh_tlv),
259*4882a593Smuzhiyun SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
260*4882a593Smuzhiyun 0, 0xF, 1, max98373_limiter_thresh_tlv),
261*4882a593Smuzhiyun /* Limiter */
262*4882a593Smuzhiyun SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
263*4882a593Smuzhiyun MAX98373_LIMITER_EN_SHIFT, 1, 0),
264*4882a593Smuzhiyun SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG,
265*4882a593Smuzhiyun MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0),
266*4882a593Smuzhiyun SOC_SINGLE_TLV("Limiter Thresh Volume", MAX98373_R20E0_LIMITER_THRESH_CFG,
267*4882a593Smuzhiyun MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv),
268*4882a593Smuzhiyun SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum),
269*4882a593Smuzhiyun SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum),
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun static const struct snd_soc_dapm_route max98373_audio_map[] = {
273*4882a593Smuzhiyun /* Plabyack */
274*4882a593Smuzhiyun {"DAI Sel Mux", "Left", "Amp Enable"},
275*4882a593Smuzhiyun {"DAI Sel Mux", "Right", "Amp Enable"},
276*4882a593Smuzhiyun {"DAI Sel Mux", "LeftRight", "Amp Enable"},
277*4882a593Smuzhiyun {"BE_OUT", NULL, "DAI Sel Mux"},
278*4882a593Smuzhiyun /* Capture */
279*4882a593Smuzhiyun { "VI Sense", "Switch", "VMON" },
280*4882a593Smuzhiyun { "VI Sense", "Switch", "IMON" },
281*4882a593Smuzhiyun { "SpkFB Sense", "Switch", "FBMON" },
282*4882a593Smuzhiyun { "Voltage Sense", NULL, "VI Sense" },
283*4882a593Smuzhiyun { "Current Sense", NULL, "VI Sense" },
284*4882a593Smuzhiyun { "Speaker FB Sense", NULL, "SpkFB Sense" },
285*4882a593Smuzhiyun };
286*4882a593Smuzhiyun
max98373_reset(struct max98373_priv * max98373,struct device * dev)287*4882a593Smuzhiyun void max98373_reset(struct max98373_priv *max98373, struct device *dev)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int ret, reg, count;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* Software Reset */
292*4882a593Smuzhiyun ret = regmap_update_bits(max98373->regmap,
293*4882a593Smuzhiyun MAX98373_R2000_SW_RESET,
294*4882a593Smuzhiyun MAX98373_SOFT_RESET,
295*4882a593Smuzhiyun MAX98373_SOFT_RESET);
296*4882a593Smuzhiyun if (ret)
297*4882a593Smuzhiyun dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun count = 0;
300*4882a593Smuzhiyun while (count < 3) {
301*4882a593Smuzhiyun usleep_range(10000, 11000);
302*4882a593Smuzhiyun /* Software Reset Verification */
303*4882a593Smuzhiyun ret = regmap_read(max98373->regmap,
304*4882a593Smuzhiyun MAX98373_R21FF_REV_ID, ®);
305*4882a593Smuzhiyun if (!ret) {
306*4882a593Smuzhiyun dev_info(dev, "Reset completed (retry:%d)\n", count);
307*4882a593Smuzhiyun return;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun count++;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun dev_err(dev, "Reset failed. (ret:%d)\n", ret);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(max98373_reset);
314*4882a593Smuzhiyun
max98373_probe(struct snd_soc_component * component)315*4882a593Smuzhiyun static int max98373_probe(struct snd_soc_component *component)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* Software Reset */
320*4882a593Smuzhiyun max98373_reset(max98373, component->dev);
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /* IV default slot configuration */
323*4882a593Smuzhiyun regmap_write(max98373->regmap,
324*4882a593Smuzhiyun MAX98373_R2020_PCM_TX_HIZ_EN_1,
325*4882a593Smuzhiyun 0xFF);
326*4882a593Smuzhiyun regmap_write(max98373->regmap,
327*4882a593Smuzhiyun MAX98373_R2021_PCM_TX_HIZ_EN_2,
328*4882a593Smuzhiyun 0xFF);
329*4882a593Smuzhiyun /* L/R mix configuration */
330*4882a593Smuzhiyun regmap_write(max98373->regmap,
331*4882a593Smuzhiyun MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
332*4882a593Smuzhiyun 0x80);
333*4882a593Smuzhiyun regmap_write(max98373->regmap,
334*4882a593Smuzhiyun MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
335*4882a593Smuzhiyun 0x1);
336*4882a593Smuzhiyun /* Enable DC blocker */
337*4882a593Smuzhiyun regmap_write(max98373->regmap,
338*4882a593Smuzhiyun MAX98373_R203F_AMP_DSP_CFG,
339*4882a593Smuzhiyun 0x3);
340*4882a593Smuzhiyun /* Enable IMON VMON DC blocker */
341*4882a593Smuzhiyun regmap_write(max98373->regmap,
342*4882a593Smuzhiyun MAX98373_R2046_IV_SENSE_ADC_DSP_CFG,
343*4882a593Smuzhiyun 0x7);
344*4882a593Smuzhiyun /* voltage, current slot configuration */
345*4882a593Smuzhiyun regmap_write(max98373->regmap,
346*4882a593Smuzhiyun MAX98373_R2022_PCM_TX_SRC_1,
347*4882a593Smuzhiyun (max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT |
348*4882a593Smuzhiyun max98373->v_slot) & 0xFF);
349*4882a593Smuzhiyun if (max98373->v_slot < 8)
350*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
351*4882a593Smuzhiyun MAX98373_R2020_PCM_TX_HIZ_EN_1,
352*4882a593Smuzhiyun 1 << max98373->v_slot, 0);
353*4882a593Smuzhiyun else
354*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
355*4882a593Smuzhiyun MAX98373_R2021_PCM_TX_HIZ_EN_2,
356*4882a593Smuzhiyun 1 << (max98373->v_slot - 8), 0);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (max98373->i_slot < 8)
359*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
360*4882a593Smuzhiyun MAX98373_R2020_PCM_TX_HIZ_EN_1,
361*4882a593Smuzhiyun 1 << max98373->i_slot, 0);
362*4882a593Smuzhiyun else
363*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
364*4882a593Smuzhiyun MAX98373_R2021_PCM_TX_HIZ_EN_2,
365*4882a593Smuzhiyun 1 << (max98373->i_slot - 8), 0);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /* speaker feedback slot configuration */
368*4882a593Smuzhiyun regmap_write(max98373->regmap,
369*4882a593Smuzhiyun MAX98373_R2023_PCM_TX_SRC_2,
370*4882a593Smuzhiyun max98373->spkfb_slot & 0xFF);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* Set interleave mode */
373*4882a593Smuzhiyun if (max98373->interleave_mode)
374*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
375*4882a593Smuzhiyun MAX98373_R2024_PCM_DATA_FMT_CFG,
376*4882a593Smuzhiyun MAX98373_PCM_TX_CH_INTERLEAVE_MASK,
377*4882a593Smuzhiyun MAX98373_PCM_TX_CH_INTERLEAVE_MASK);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* Speaker enable */
380*4882a593Smuzhiyun regmap_update_bits(max98373->regmap,
381*4882a593Smuzhiyun MAX98373_R2043_AMP_EN,
382*4882a593Smuzhiyun MAX98373_SPK_EN_MASK, 1);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun const struct snd_soc_component_driver soc_codec_dev_max98373 = {
388*4882a593Smuzhiyun .probe = max98373_probe,
389*4882a593Smuzhiyun .controls = max98373_snd_controls,
390*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(max98373_snd_controls),
391*4882a593Smuzhiyun .dapm_widgets = max98373_dapm_widgets,
392*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets),
393*4882a593Smuzhiyun .dapm_routes = max98373_audio_map,
394*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(max98373_audio_map),
395*4882a593Smuzhiyun .use_pmdown_time = 1,
396*4882a593Smuzhiyun .endianness = 1,
397*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(soc_codec_dev_max98373);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = {
402*4882a593Smuzhiyun .probe = NULL,
403*4882a593Smuzhiyun .controls = max98373_snd_controls,
404*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(max98373_snd_controls),
405*4882a593Smuzhiyun .dapm_widgets = max98373_dapm_widgets,
406*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets),
407*4882a593Smuzhiyun .dapm_routes = max98373_audio_map,
408*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(max98373_audio_map),
409*4882a593Smuzhiyun .use_pmdown_time = 1,
410*4882a593Smuzhiyun .endianness = 1,
411*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
412*4882a593Smuzhiyun };
413*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw);
414*4882a593Smuzhiyun
max98373_slot_config(struct device * dev,struct max98373_priv * max98373)415*4882a593Smuzhiyun void max98373_slot_config(struct device *dev,
416*4882a593Smuzhiyun struct max98373_priv *max98373)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun int value;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
421*4882a593Smuzhiyun max98373->v_slot = value & 0xF;
422*4882a593Smuzhiyun else
423*4882a593Smuzhiyun max98373->v_slot = 0;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
426*4882a593Smuzhiyun max98373->i_slot = value & 0xF;
427*4882a593Smuzhiyun else
428*4882a593Smuzhiyun max98373->i_slot = 1;
429*4882a593Smuzhiyun if (dev->of_node) {
430*4882a593Smuzhiyun max98373->reset_gpio = of_get_named_gpio(dev->of_node,
431*4882a593Smuzhiyun "maxim,reset-gpio", 0);
432*4882a593Smuzhiyun if (!gpio_is_valid(max98373->reset_gpio)) {
433*4882a593Smuzhiyun dev_err(dev, "Looking up %s property in node %s failed %d\n",
434*4882a593Smuzhiyun "maxim,reset-gpio", dev->of_node->full_name,
435*4882a593Smuzhiyun max98373->reset_gpio);
436*4882a593Smuzhiyun } else {
437*4882a593Smuzhiyun dev_dbg(dev, "maxim,reset-gpio=%d",
438*4882a593Smuzhiyun max98373->reset_gpio);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun } else {
441*4882a593Smuzhiyun /* this makes reset_gpio as invalid */
442*4882a593Smuzhiyun max98373->reset_gpio = -1;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
446*4882a593Smuzhiyun max98373->spkfb_slot = value & 0xF;
447*4882a593Smuzhiyun else
448*4882a593Smuzhiyun max98373->spkfb_slot = 2;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(max98373_slot_config);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun MODULE_DESCRIPTION("ALSA SoC MAX98373 driver");
453*4882a593Smuzhiyun MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
454*4882a593Smuzhiyun MODULE_LICENSE("GPL");
455