1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2022, Analog Devices Inc. |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/delay.h> |
6 | #include <linux/gpio/consumer.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/module.h> |
9 | #include <linux/mod_devicetable.h> |
10 | #include <linux/of.h> |
11 | #include <linux/pm_runtime.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/cdev.h> |
15 | #include <sound/pcm.h> |
16 | #include <sound/pcm_params.h> |
17 | #include <sound/soc.h> |
18 | #include <sound/tlv.h> |
19 | #include "max98388.h" |
20 | |
21 | static struct reg_default max98388_reg[] = { |
22 | {MAX98388_R2000_SW_RESET, 0x00}, |
23 | {MAX98388_R2001_INT_RAW1, 0x00}, |
24 | {MAX98388_R2002_INT_RAW2, 0x00}, |
25 | {MAX98388_R2004_INT_STATE1, 0x00}, |
26 | {MAX98388_R2005_INT_STATE2, 0x00}, |
27 | {MAX98388_R2020_THERM_WARN_THRESH, 0x0A}, |
28 | {MAX98388_R2031_SPK_MON_THRESH, 0x58}, |
29 | {MAX98388_R2032_SPK_MON_LD_SEL, 0x08}, |
30 | {MAX98388_R2033_SPK_MON_DURATION, 0x02}, |
31 | {MAX98388_R2037_ERR_MON_CTRL, 0x01}, |
32 | {MAX98388_R2040_PCM_MODE_CFG, 0xC0}, |
33 | {MAX98388_R2041_PCM_CLK_SETUP, 0x04}, |
34 | {MAX98388_R2042_PCM_SR_SETUP, 0x88}, |
35 | {MAX98388_R2044_PCM_TX_CTRL1, 0x00}, |
36 | {MAX98388_R2045_PCM_TX_CTRL2, 0x00}, |
37 | {MAX98388_R2050_PCM_TX_HIZ_CTRL1, 0xFF}, |
38 | {MAX98388_R2051_PCM_TX_HIZ_CTRL2, 0xFF}, |
39 | {MAX98388_R2052_PCM_TX_HIZ_CTRL3, 0xFF}, |
40 | {MAX98388_R2053_PCM_TX_HIZ_CTRL4, 0xFF}, |
41 | {MAX98388_R2054_PCM_TX_HIZ_CTRL5, 0xFF}, |
42 | {MAX98388_R2055_PCM_TX_HIZ_CTRL6, 0xFF}, |
43 | {MAX98388_R2056_PCM_TX_HIZ_CTRL7, 0xFF}, |
44 | {MAX98388_R2057_PCM_TX_HIZ_CTRL8, 0xFF}, |
45 | {MAX98388_R2058_PCM_RX_SRC1, 0x00}, |
46 | {MAX98388_R2059_PCM_RX_SRC2, 0x01}, |
47 | {MAX98388_R205C_PCM_TX_DRIVE_STRENGTH, 0x00}, |
48 | {MAX98388_R205D_PCM_TX_SRC_EN, 0x00}, |
49 | {MAX98388_R205E_PCM_RX_EN, 0x00}, |
50 | {MAX98388_R205F_PCM_TX_EN, 0x00}, |
51 | {MAX98388_R2090_SPK_CH_VOL_CTRL, 0x00}, |
52 | {MAX98388_R2091_SPK_CH_CFG, 0x02}, |
53 | {MAX98388_R2092_SPK_AMP_OUT_CFG, 0x03}, |
54 | {MAX98388_R2093_SPK_AMP_SSM_CFG, 0x01}, |
55 | {MAX98388_R2094_SPK_AMP_ER_CTRL, 0x00}, |
56 | {MAX98388_R209E_SPK_CH_PINK_NOISE_EN, 0x00}, |
57 | {MAX98388_R209F_SPK_CH_AMP_EN, 0x00}, |
58 | {MAX98388_R20A0_IV_DATA_DSP_CTRL, 0x10}, |
59 | {MAX98388_R20A7_IV_DATA_EN, 0x00}, |
60 | {MAX98388_R20E0_BP_ALC_THRESH, 0x04}, |
61 | {MAX98388_R20E1_BP_ALC_RATES, 0x20}, |
62 | {MAX98388_R20E2_BP_ALC_ATTEN, 0x06}, |
63 | {MAX98388_R20E3_BP_ALC_REL, 0x02}, |
64 | {MAX98388_R20E4_BP_ALC_MUTE, 0x33}, |
65 | {MAX98388_R20EE_BP_INF_HOLD_REL, 0x00}, |
66 | {MAX98388_R20EF_BP_ALC_EN, 0x00}, |
67 | {MAX98388_R210E_AUTO_RESTART, 0x00}, |
68 | {MAX98388_R210F_GLOBAL_EN, 0x00}, |
69 | {MAX98388_R22FF_REV_ID, 0x00}, |
70 | }; |
71 | |
72 | static int max98388_dac_event(struct snd_soc_dapm_widget *w, |
73 | struct snd_kcontrol *kcontrol, int event) |
74 | { |
75 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
76 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
77 | |
78 | switch (event) { |
79 | case SND_SOC_DAPM_POST_PMU: |
80 | regmap_write(map: max98388->regmap, |
81 | MAX98388_R210F_GLOBAL_EN, val: 1); |
82 | usleep_range(min: 30000, max: 31000); |
83 | break; |
84 | case SND_SOC_DAPM_PRE_PMD: |
85 | regmap_write(map: max98388->regmap, |
86 | MAX98388_R210F_GLOBAL_EN, val: 0); |
87 | usleep_range(min: 30000, max: 31000); |
88 | max98388->tdm_mode = false; |
89 | break; |
90 | default: |
91 | return 0; |
92 | } |
93 | return 0; |
94 | } |
95 | |
96 | static const char * const max98388_monomix_switch_text[] = { |
97 | "Left" , "Right" , "LeftRight" }; |
98 | |
99 | static const struct soc_enum dai_sel_enum = |
100 | SOC_ENUM_SINGLE(MAX98388_R2058_PCM_RX_SRC1, |
101 | MAX98388_PCM_TO_SPK_MONOMIX_CFG_SHIFT, |
102 | 3, max98388_monomix_switch_text); |
103 | |
104 | static const struct snd_kcontrol_new max98388_dai_controls = |
105 | SOC_DAPM_ENUM("DAI Sel" , dai_sel_enum); |
106 | |
107 | static const struct snd_kcontrol_new max98388_vi_control = |
108 | SOC_DAPM_SINGLE("Switch" , MAX98388_R205F_PCM_TX_EN, 0, 1, 0); |
109 | |
110 | static const struct snd_soc_dapm_widget max98388_dapm_widgets[] = { |
111 | SND_SOC_DAPM_DAC_E("Amp Enable" , "HiFi Playback" , |
112 | MAX98388_R205E_PCM_RX_EN, 0, 0, max98388_dac_event, |
113 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
114 | SND_SOC_DAPM_MUX("DAI Sel Mux" , SND_SOC_NOPM, 0, 0, |
115 | &max98388_dai_controls), |
116 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
117 | SND_SOC_DAPM_AIF_OUT("Voltage Sense" , "HiFi Capture" , 0, |
118 | MAX98388_R20A7_IV_DATA_EN, 0, 0), |
119 | SND_SOC_DAPM_AIF_OUT("Current Sense" , "HiFi Capture" , 0, |
120 | MAX98388_R20A7_IV_DATA_EN, 1, 0), |
121 | SND_SOC_DAPM_ADC("ADC Voltage" , NULL, |
122 | MAX98388_R205D_PCM_TX_SRC_EN, 0, 0), |
123 | SND_SOC_DAPM_ADC("ADC Current" , NULL, |
124 | MAX98388_R205D_PCM_TX_SRC_EN, 1, 0), |
125 | SND_SOC_DAPM_SWITCH("VI Sense" , SND_SOC_NOPM, 0, 0, |
126 | &max98388_vi_control), |
127 | SND_SOC_DAPM_SIGGEN("VMON" ), |
128 | SND_SOC_DAPM_SIGGEN("IMON" ), |
129 | }; |
130 | |
131 | static DECLARE_TLV_DB_SCALE(max98388_digital_tlv, -6350, 50, 1); |
132 | static DECLARE_TLV_DB_SCALE(max98388_amp_gain_tlv, -300, 300, 0); |
133 | |
134 | static const char * const max98388_alc_max_atten_text[] = { |
135 | "0dBFS" , "-1dBFS" , "-2dBFS" , "-3dBFS" , "-4dBFS" , "-5dBFS" , |
136 | "-6dBFS" , "-7dBFS" , "-8dBFS" , "-9dBFS" , "-10dBFS" , "-11dBFS" , |
137 | "-12dBFS" , "-13dBFS" , "-14dBFS" , "-15dBFS" |
138 | }; |
139 | |
140 | static SOC_ENUM_SINGLE_DECL(max98388_alc_max_atten_enum, |
141 | MAX98388_R20E2_BP_ALC_ATTEN, |
142 | MAX98388_ALC_MAX_ATTEN_SHIFT, |
143 | max98388_alc_max_atten_text); |
144 | |
145 | static const char * const max98388_thermal_warn_text[] = { |
146 | "95C" , "105C" , "115C" , "125C" |
147 | }; |
148 | |
149 | static SOC_ENUM_SINGLE_DECL(max98388_thermal_warning_thresh_enum, |
150 | MAX98388_R2020_THERM_WARN_THRESH, |
151 | MAX98388_THERM_WARN_THRESH_SHIFT, |
152 | max98388_thermal_warn_text); |
153 | |
154 | static const char * const max98388_thermal_shutdown_text[] = { |
155 | "135C" , "145C" , "155C" , "165C" |
156 | }; |
157 | |
158 | static SOC_ENUM_SINGLE_DECL(max98388_thermal_shutdown_thresh_enum, |
159 | MAX98388_R2020_THERM_WARN_THRESH, |
160 | MAX98388_THERM_SHDN_THRESH_SHIFT, |
161 | max98388_thermal_shutdown_text); |
162 | |
163 | static const char * const max98388_alc_thresh_single_text[] = { |
164 | "3.625V" , "3.550V" , "3.475V" , "3.400V" , "3.325V" , "3.250V" , |
165 | "3.175V" , "3.100V" , "3.025V" , "2.950V" , "2.875V" , "2.800V" , |
166 | "2.725V" , "2.650V" , "2.575V" , "2.500V" |
167 | }; |
168 | |
169 | static SOC_ENUM_SINGLE_DECL(max98388_alc_thresh_single_enum, |
170 | MAX98388_R20E0_BP_ALC_THRESH, |
171 | MAX98388_ALC_THRESH_SHIFT, |
172 | max98388_alc_thresh_single_text); |
173 | |
174 | static const char * const max98388_alc_attack_rate_text[] = { |
175 | "0" , "10us" , "20us" , "40us" , "80us" , "160us" , |
176 | "320us" , "640us" , "1.28ms" , "2.56ms" , "5.12ms" , "10.24ms" , |
177 | "20.48ms" , "40.96ms" , "81.92ms" , "163.84ms" |
178 | }; |
179 | |
180 | static SOC_ENUM_SINGLE_DECL(max98388_alc_attack_rate_enum, |
181 | MAX98388_R20E1_BP_ALC_RATES, |
182 | MAX98388_ALC_ATTACK_RATE_SHIFT, |
183 | max98388_alc_attack_rate_text); |
184 | |
185 | static const char * const max98388_alc_release_rate_text[] = { |
186 | "20us" , "40us" , "80us" , "160us" , "320us" , "640us" , |
187 | "1.28ms" , "2.56ms" , "5.12ms" , "10.24ms" , "20.48ms" , "40.96ms" , |
188 | "81.92ms" , "163.84ms" , "327.68ms" , "655.36ms" |
189 | }; |
190 | |
191 | static SOC_ENUM_SINGLE_DECL(max98388_alc_release_rate_enum, |
192 | MAX98388_R20E1_BP_ALC_RATES, |
193 | MAX98388_ALC_RELEASE_RATE_SHIFT, |
194 | max98388_alc_release_rate_text); |
195 | |
196 | static const char * const max98388_alc_debounce_text[] = { |
197 | "0.01ms" , "0.1ms" , "1ms" , "10ms" , "100ms" , "250ms" , "500ms" , "hold" |
198 | }; |
199 | |
200 | static SOC_ENUM_SINGLE_DECL(max98388_alc_debouce_enum, |
201 | MAX98388_R20E3_BP_ALC_REL, |
202 | MAX98388_ALC_DEBOUNCE_TIME_SHIFT, |
203 | max98388_alc_debounce_text); |
204 | |
205 | static const char * const max98388_alc_mute_delay_text[] = { |
206 | "0.01ms" , "0.05ms" , "0.1ms" , "0.5ms" , "1ms" , "5ms" , "25ms" , "250ms" |
207 | }; |
208 | |
209 | static SOC_ENUM_SINGLE_DECL(max98388_alc_mute_delay_enum, |
210 | MAX98388_R20E4_BP_ALC_MUTE, |
211 | MAX98388_ALC_MUTE_DELAY_SHIFT, |
212 | max98388_alc_mute_delay_text); |
213 | |
214 | static const char * const max98388_spkmon_duration_text[] = { |
215 | "10ms" , "25ms" , "50ms" , "75ms" , "100ms" , "200ms" , "300ms" , "400ms" , |
216 | "500ms" , "600ms" , "700ms" , "800ms" , "900ms" , "1000ms" , "1100ms" , "1200ms" |
217 | }; |
218 | |
219 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_duration_enum, |
220 | MAX98388_R2033_SPK_MON_DURATION, |
221 | MAX98388_SPKMON_DURATION_SHIFT, |
222 | max98388_spkmon_duration_text); |
223 | |
224 | static const char * const max98388_spkmon_thresh_text[] = { |
225 | "0.03V" , "0.06V" , "0.09V" , "0.12V" , "0.15V" , "0.18V" , "0.20V" , "0.23V" , |
226 | "0.26V" , "0.29V" , "0.32V" , "0.35V" , "0.38V" , "0.41V" , "0.44V" , "0.47V" , |
227 | "0.50V" , "0.53V" , "0.56V" , "0.58V" , "0.61V" , "0.64V" , "0.67V" , "0.70V" , |
228 | "0.73V" , "0.76V" , "0.79V" , "0.82V" , "0.85V" , "0.88V" , "0.91V" , "0.94V" , |
229 | "0.96V" , "0.99V" , "1.02V" , "1.05V" , "1.08V" , "1.11V" , "1.14V" , "1.17V" , |
230 | "1.20V" , "1.23V" , "1.26V" , "1.29V" , "1.32V" , "1.35V" , "1.37V" , "1.40V" , |
231 | "1.43V" , "1.46V" , "1.49V" , "1.52V" , "1.55V" , "1.58V" , "1.61V" , "1.64V" , |
232 | "1.67V" , "1.70V" , "1.73V" , "1.75V" , "1.78V" , "1.81V" , "1.84V" , "1.87V" , |
233 | "1.90V" , "1.93V" , "1.96V" , "1.99V" , "2.02V" , "2.05V" , "2.08V" , "2.11V" , |
234 | "2.13V" , "2.16V" , "2.19V" , "2.22V" , "2.25V" , "2.28V" , "2.31V" , "2.34V" , |
235 | "2.37V" , "2.40V" , "2.43V" , "2.46V" , "2.49V" , "2.51V" , "2.54V" , "2.57V" , |
236 | "2.60V" , "2.63V" , "2.66V" , "2.69V" , "2.72V" , "2.75V" , "2.78V" , "2.81V" , |
237 | "2.84V" , "2.87V" , "2.89V" , "2.92V" , "2.95V" , "2.98V" , "3.01V" , "3.04V" , |
238 | "3.07V" , "3.10V" , "3.13V" , "3.16V" , "3.19V" , "3.22V" , "3.25V" , "3.27V" , |
239 | "3.30V" , "3.33V" , "3.36V" , "3.39V" , "3.42V" , "3.45V" , "3.48V" , "3.51V" , |
240 | "3.54V" , "3.57V" , "3.60V" , "3.63V" , "3.66V" , "3.68V" , "3.71V" , "3.74V" |
241 | }; |
242 | |
243 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_thresh_enum, |
244 | MAX98388_R2031_SPK_MON_THRESH, |
245 | MAX98388_SPKMON_THRESH_SHIFT, |
246 | max98388_spkmon_thresh_text); |
247 | |
248 | static const char * const max98388_spkmon_load_text[] = { |
249 | "2.00ohm" , "2.25ohm" , "2.50ohm" , "2.75ohm" , "3.00ohm" , "3.25ohm" , |
250 | "3.50ohm" , "3.75ohm" , "4.00ohm" , "4.25ohm" , "4.50ohm" , "4.75ohm" , |
251 | "5.00ohm" , "5.25ohm" , "5.50ohm" , "5.75ohm" , "6.00ohm" , "6.25ohm" , |
252 | "6.50ohm" , "6.75ohm" , "7.00ohm" , "7.25ohm" , "7.50ohm" , "7.75ohm" , |
253 | "8.00ohm" , "8.25ohm" , "8.50ohm" , "8.75ohm" , "9.00ohm" , "9.25ohm" , |
254 | "9.50ohm" , "9.75ohm" , "10.00ohm" , "10.25ohm" , "10.50ohm" , "10.75ohm" , |
255 | "11.00ohm" , "11.25ohm" , "11.50ohm" , "11.75ohm" , "12.00ohm" , "12.25ohm" , |
256 | "12.50ohm" , "12.75ohm" , "13.00ohm" , "13.25ohm" , "13.50ohm" , "13.75ohm" , |
257 | "14.00ohm" , "14.25ohm" , "14.50ohm" , "14.75ohm" , "15.00ohm" , "15.25ohm" , |
258 | "15.50ohm" , "15.75ohm" , "16.00ohm" , "16.25ohm" , "16.50ohm" , "16.75ohm" , |
259 | "17.00ohm" , "17.25ohm" , "17.50ohm" , "17.75ohm" , "18.00ohm" , "18.25ohm" , |
260 | "18.50ohm" , "18.75ohm" , "19.00ohm" , "19.25ohm" , "19.50ohm" , "19.75ohm" , |
261 | "20.00ohm" , "20.25ohm" , "20.50ohm" , "20.75ohm" , "21.00ohm" , "21.25ohm" , |
262 | "21.50ohm" , "21.75ohm" , "22.00ohm" , "22.25ohm" , "22.50ohm" , "22.75ohm" , |
263 | "23.00ohm" , "23.25ohm" , "23.50ohm" , "23.75ohm" , "24.00ohm" , "24.25ohm" , |
264 | "24.50ohm" , "24.75ohm" , "25.00ohm" , "25.25ohm" , "25.50ohm" , "25.75ohm" , |
265 | "26.00ohm" , "26.25ohm" , "26.50ohm" , "26.75ohm" , "27.00ohm" , "27.25ohm" , |
266 | "27.50ohm" , "27.75ohm" , "28.00ohm" , "28.25ohm" , "28.50ohm" , "28.75ohm" , |
267 | "29.00ohm" , "29.25ohm" , "29.50ohm" , "29.75ohm" , "30.00ohm" , "30.25ohm" , |
268 | "30.50ohm" , "30.75ohm" , "31.00ohm" , "31.25ohm" , "31.50ohm" , "31.75ohm" , |
269 | "32.00ohm" , "32.25ohm" , "32.50ohm" , "32.75ohm" , "33.00ohm" , "33.25ohm" , |
270 | "33.50ohm" , "33.75ohm" |
271 | }; |
272 | |
273 | static SOC_ENUM_SINGLE_DECL(max98388_spkmon_load_enum, |
274 | MAX98388_R2032_SPK_MON_LD_SEL, |
275 | MAX98388_SPKMON_LOAD_SHIFT, |
276 | max98388_spkmon_load_text); |
277 | |
278 | static const char * const max98388_edge_rate_text[] = { |
279 | "Normal" , "Reduced" , "Maximum" , "Increased" , |
280 | }; |
281 | |
282 | static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_falling_enum, |
283 | MAX98388_R2094_SPK_AMP_ER_CTRL, |
284 | MAX98388_EDGE_RATE_FALL_SHIFT, |
285 | max98388_edge_rate_text); |
286 | |
287 | static SOC_ENUM_SINGLE_DECL(max98388_edge_rate_rising_enum, |
288 | MAX98388_R2094_SPK_AMP_ER_CTRL, |
289 | MAX98388_EDGE_RATE_RISE_SHIFT, |
290 | max98388_edge_rate_text); |
291 | |
292 | static const char * const max98388_ssm_mod_text[] = { |
293 | "1.5%" , "3.0%" , "4.5%" , "6.0%" , |
294 | }; |
295 | |
296 | static SOC_ENUM_SINGLE_DECL(max98388_ssm_mod_enum, |
297 | MAX98388_R2093_SPK_AMP_SSM_CFG, |
298 | MAX98388_SPK_AMP_SSM_MOD_SHIFT, |
299 | max98388_ssm_mod_text); |
300 | |
301 | static const struct snd_kcontrol_new max98388_snd_controls[] = { |
302 | SOC_SINGLE("Ramp Up Switch" , MAX98388_R2091_SPK_CH_CFG, |
303 | MAX98388_SPK_CFG_VOL_RMPUP_SHIFT, 1, 0), |
304 | SOC_SINGLE("Ramp Down Switch" , MAX98388_R2091_SPK_CH_CFG, |
305 | MAX98388_SPK_CFG_VOL_RMPDN_SHIFT, 1, 0), |
306 | /* Two Cell Mode Enable */ |
307 | SOC_SINGLE("OP Mode Switch" , MAX98388_R2092_SPK_AMP_OUT_CFG, |
308 | MAX98388_SPK_AMP_OUT_MODE_SHIFT, 1, 0), |
309 | /* Speaker Amplifier Overcurrent Automatic Restart Enable */ |
310 | SOC_SINGLE("OVC Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
311 | MAX98388_OVC_AUTORESTART_SHIFT, 1, 0), |
312 | /* Thermal Shutdown Automatic Restart Enable */ |
313 | SOC_SINGLE("THERM Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
314 | MAX98388_THERM_AUTORESTART_SHIFT, 1, 0), |
315 | /* PVDD UVLO Auto Restart */ |
316 | SOC_SINGLE("UVLO Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
317 | MAX98388_PVDD_UVLO_AUTORESTART_SHIFT, 1, 0), |
318 | /* Clock Monitor Automatic Restart Enable */ |
319 | SOC_SINGLE("CMON Autorestart Switch" , MAX98388_R210E_AUTO_RESTART, |
320 | MAX98388_CMON_AUTORESTART_SHIFT, 1, 0), |
321 | SOC_SINGLE("CLK Monitor Switch" , MAX98388_R2037_ERR_MON_CTRL, |
322 | MAX98388_CLOCK_MON_SHIFT, 1, 0), |
323 | /* Pinknoise Generator Enable */ |
324 | SOC_SINGLE("Pinknoise Gen Switch" , MAX98388_R209E_SPK_CH_PINK_NOISE_EN, |
325 | MAX98388_PINK_NOISE_GEN_SHIFT, 1, 0), |
326 | /* Dither Enable */ |
327 | SOC_SINGLE("Dither Switch" , MAX98388_R2091_SPK_CH_CFG, |
328 | MAX98388_SPK_CFG_DITH_EN_SHIFT, 1, 0), |
329 | SOC_SINGLE("VI Dither Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
330 | MAX98388_AMP_DSP_CTRL_DITH_SHIFT, 1, 0), |
331 | /* DC Blocker Enable */ |
332 | SOC_SINGLE("DC Blocker Switch" , MAX98388_R2091_SPK_CH_CFG, |
333 | MAX98388_SPK_CFG_DCBLK_SHIFT, 1, 0), |
334 | SOC_SINGLE("Voltage DC Blocker Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
335 | MAX98388_AMP_DSP_CTRL_VOL_DCBLK_SHIFT, 1, 0), |
336 | SOC_SINGLE("Current DC Blocker Switch" , MAX98388_R20A0_IV_DATA_DSP_CTRL, |
337 | MAX98388_AMP_DSP_CTRL_CUR_DCBLK_SHIFT, 1, 0), |
338 | /* Digital Volume */ |
339 | SOC_SINGLE_TLV("Digital Volume" , MAX98388_R2090_SPK_CH_VOL_CTRL, |
340 | 0, 0x7F, 1, max98388_digital_tlv), |
341 | /* Speaker Volume */ |
342 | SOC_SINGLE_TLV("Speaker Volume" , MAX98388_R2092_SPK_AMP_OUT_CFG, |
343 | 0, 5, 0, max98388_amp_gain_tlv), |
344 | SOC_ENUM("Thermal Warn Thresh" , max98388_thermal_warning_thresh_enum), |
345 | SOC_ENUM("Thermal SHDN Thresh" , max98388_thermal_shutdown_thresh_enum), |
346 | /* Brownout Protection Automatic Level Control */ |
347 | SOC_SINGLE("ALC Switch" , MAX98388_R20EF_BP_ALC_EN, 0, 1, 0), |
348 | SOC_ENUM("ALC Thresh" , max98388_alc_thresh_single_enum), |
349 | SOC_ENUM("ALC Attack Rate" , max98388_alc_attack_rate_enum), |
350 | SOC_ENUM("ALC Release Rate" , max98388_alc_release_rate_enum), |
351 | SOC_ENUM("ALC Max Atten" , max98388_alc_max_atten_enum), |
352 | SOC_ENUM("ALC Debounce Time" , max98388_alc_debouce_enum), |
353 | SOC_SINGLE("ALC Unmute Ramp Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
354 | MAX98388_ALC_UNMUTE_RAMP_EN_SHIFT, 1, 0), |
355 | SOC_SINGLE("ALC Mute Ramp Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
356 | MAX98388_ALC_MUTE_RAMP_EN_SHIFT, 1, 0), |
357 | SOC_SINGLE("ALC Mute Switch" , MAX98388_R20E4_BP_ALC_MUTE, |
358 | MAX98388_ALC_MUTE_EN_SHIFT, 1, 0), |
359 | SOC_ENUM("ALC Mute Delay" , max98388_alc_mute_delay_enum), |
360 | /* Speaker Monitor */ |
361 | SOC_SINGLE("SPKMON Switch" , MAX98388_R2037_ERR_MON_CTRL, |
362 | MAX98388_SPK_MON_SHIFT, 1, 0), |
363 | SOC_ENUM("SPKMON Thresh" , max98388_spkmon_thresh_enum), |
364 | SOC_ENUM("SPKMON Load" , max98388_spkmon_load_enum), |
365 | SOC_ENUM("SPKMON Duration" , max98388_spkmon_duration_enum), |
366 | /* General Parameters */ |
367 | SOC_ENUM("Fall Slew Rate" , max98388_edge_rate_falling_enum), |
368 | SOC_ENUM("Rise Slew Rate" , max98388_edge_rate_rising_enum), |
369 | SOC_SINGLE("AMP SSM Switch" , MAX98388_R2093_SPK_AMP_SSM_CFG, |
370 | MAX98388_SPK_AMP_SSM_EN_SHIFT, 1, 0), |
371 | SOC_ENUM("AMP SSM Mod" , max98388_ssm_mod_enum), |
372 | }; |
373 | |
374 | static const struct snd_soc_dapm_route max98388_audio_map[] = { |
375 | /* Plabyack */ |
376 | {"DAI Sel Mux" , "Left" , "Amp Enable" }, |
377 | {"DAI Sel Mux" , "Right" , "Amp Enable" }, |
378 | {"DAI Sel Mux" , "LeftRight" , "Amp Enable" }, |
379 | {"BE_OUT" , NULL, "DAI Sel Mux" }, |
380 | /* Capture */ |
381 | { "ADC Voltage" , NULL, "VMON" }, |
382 | { "ADC Current" , NULL, "IMON" }, |
383 | { "VI Sense" , "Switch" , "ADC Voltage" }, |
384 | { "VI Sense" , "Switch" , "ADC Current" }, |
385 | { "Voltage Sense" , NULL, "VI Sense" }, |
386 | { "Current Sense" , NULL, "VI Sense" }, |
387 | }; |
388 | |
389 | static void max98388_reset(struct max98388_priv *max98388, struct device *dev) |
390 | { |
391 | int ret, reg, count; |
392 | |
393 | /* Software Reset */ |
394 | ret = regmap_update_bits(map: max98388->regmap, |
395 | MAX98388_R2000_SW_RESET, |
396 | MAX98388_SOFT_RESET, |
397 | MAX98388_SOFT_RESET); |
398 | if (ret) |
399 | dev_err(dev, "Reset command failed. (ret:%d)\n" , ret); |
400 | |
401 | count = 0; |
402 | while (count < 3) { |
403 | usleep_range(min: 10000, max: 11000); |
404 | /* Software Reset Verification */ |
405 | ret = regmap_read(map: max98388->regmap, |
406 | MAX98388_R22FF_REV_ID, val: ®); |
407 | if (!ret) { |
408 | dev_info(dev, "Reset completed (retry:%d)\n" , count); |
409 | return; |
410 | } |
411 | count++; |
412 | } |
413 | dev_err(dev, "Reset failed. (ret:%d)\n" , ret); |
414 | } |
415 | |
416 | static int max98388_probe(struct snd_soc_component *component) |
417 | { |
418 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
419 | |
420 | /* Software Reset */ |
421 | max98388_reset(max98388, dev: component->dev); |
422 | |
423 | /* General channel source configuration */ |
424 | regmap_write(map: max98388->regmap, |
425 | MAX98388_R2059_PCM_RX_SRC2, |
426 | val: 0x10); |
427 | |
428 | /* Enable DC blocker */ |
429 | regmap_write(map: max98388->regmap, |
430 | MAX98388_R2091_SPK_CH_CFG, |
431 | val: 0x1); |
432 | /* Enable IMON VMON DC blocker */ |
433 | regmap_write(map: max98388->regmap, |
434 | MAX98388_R20A0_IV_DATA_DSP_CTRL, |
435 | val: 0x3); |
436 | /* TX slot configuration */ |
437 | regmap_write(map: max98388->regmap, |
438 | MAX98388_R2044_PCM_TX_CTRL1, |
439 | val: max98388->v_slot); |
440 | |
441 | regmap_write(map: max98388->regmap, |
442 | MAX98388_R2045_PCM_TX_CTRL2, |
443 | val: max98388->i_slot); |
444 | /* Enable Auto-restart behavior by default */ |
445 | regmap_write(map: max98388->regmap, |
446 | MAX98388_R210E_AUTO_RESTART, val: 0xF); |
447 | /* Set interleave mode */ |
448 | if (max98388->interleave_mode) |
449 | regmap_update_bits(map: max98388->regmap, |
450 | MAX98388_R2040_PCM_MODE_CFG, |
451 | MAX98388_PCM_TX_CH_INTERLEAVE_MASK, |
452 | MAX98388_PCM_TX_CH_INTERLEAVE_MASK); |
453 | |
454 | /* Speaker Amplifier Channel Enable */ |
455 | regmap_update_bits(map: max98388->regmap, |
456 | MAX98388_R209F_SPK_CH_AMP_EN, |
457 | MAX98388_SPK_EN_MASK, val: 1); |
458 | |
459 | return 0; |
460 | } |
461 | |
462 | static int max98388_dai_set_fmt(struct snd_soc_dai *codec_dai, |
463 | unsigned int fmt) |
464 | { |
465 | struct snd_soc_component *component = codec_dai->component; |
466 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
467 | unsigned int format = 0; |
468 | unsigned int invert = 0; |
469 | |
470 | dev_dbg(component->dev, "%s: fmt 0x%08X\n" , __func__, fmt); |
471 | |
472 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
473 | case SND_SOC_DAIFMT_NB_NF: |
474 | break; |
475 | case SND_SOC_DAIFMT_IB_NF: |
476 | invert = MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE; |
477 | break; |
478 | default: |
479 | dev_err(component->dev, "DAI invert mode unsupported\n" ); |
480 | return -EINVAL; |
481 | } |
482 | |
483 | regmap_update_bits(map: max98388->regmap, |
484 | MAX98388_R2041_PCM_CLK_SETUP, |
485 | MAX98388_PCM_MODE_CFG_PCM_BCLKEDGE, |
486 | val: invert); |
487 | |
488 | /* interface format */ |
489 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
490 | case SND_SOC_DAIFMT_I2S: |
491 | format = MAX98388_PCM_FORMAT_I2S; |
492 | break; |
493 | case SND_SOC_DAIFMT_LEFT_J: |
494 | format = MAX98388_PCM_FORMAT_LJ; |
495 | break; |
496 | case SND_SOC_DAIFMT_DSP_A: |
497 | format = MAX98388_PCM_FORMAT_TDM_MODE1; |
498 | break; |
499 | case SND_SOC_DAIFMT_DSP_B: |
500 | format = MAX98388_PCM_FORMAT_TDM_MODE0; |
501 | break; |
502 | default: |
503 | return -EINVAL; |
504 | } |
505 | |
506 | regmap_update_bits(map: max98388->regmap, |
507 | MAX98388_R2040_PCM_MODE_CFG, |
508 | MAX98388_PCM_MODE_CFG_FORMAT_MASK, |
509 | val: format << MAX98388_PCM_MODE_CFG_FORMAT_SHIFT); |
510 | |
511 | return 0; |
512 | } |
513 | |
514 | /* BCLKs per LRCLK */ |
515 | static const int bclk_sel_table[] = { |
516 | 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, |
517 | }; |
518 | |
519 | static int max98388_get_bclk_sel(int bclk) |
520 | { |
521 | int i; |
522 | /* match BCLKs per LRCLK */ |
523 | for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { |
524 | if (bclk_sel_table[i] == bclk) |
525 | return i + 2; |
526 | } |
527 | return 0; |
528 | } |
529 | |
530 | static int max98388_set_clock(struct snd_soc_component *component, |
531 | struct snd_pcm_hw_params *params) |
532 | { |
533 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
534 | /* BCLK/LRCLK ratio calculation */ |
535 | int blr_clk_ratio = params_channels(p: params) * max98388->ch_size; |
536 | int value; |
537 | |
538 | if (!max98388->tdm_mode) { |
539 | /* BCLK configuration */ |
540 | value = max98388_get_bclk_sel(bclk: blr_clk_ratio); |
541 | if (!value) { |
542 | dev_err(component->dev, "format unsupported %d\n" , |
543 | params_format(params)); |
544 | return -EINVAL; |
545 | } |
546 | |
547 | regmap_update_bits(map: max98388->regmap, |
548 | MAX98388_R2041_PCM_CLK_SETUP, |
549 | MAX98388_PCM_CLK_SETUP_BSEL_MASK, |
550 | val: value); |
551 | } |
552 | return 0; |
553 | } |
554 | |
555 | static int max98388_dai_hw_params(struct snd_pcm_substream *substream, |
556 | struct snd_pcm_hw_params *params, |
557 | struct snd_soc_dai *dai) |
558 | { |
559 | struct snd_soc_component *component = dai->component; |
560 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
561 | unsigned int sampling_rate = 0; |
562 | unsigned int chan_sz = 0; |
563 | int ret, reg; |
564 | int status = 0; |
565 | |
566 | /* pcm mode configuration */ |
567 | switch (snd_pcm_format_width(format: params_format(p: params))) { |
568 | case 16: |
569 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; |
570 | break; |
571 | case 24: |
572 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; |
573 | break; |
574 | case 32: |
575 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; |
576 | break; |
577 | default: |
578 | dev_err(component->dev, "format unsupported %d\n" , |
579 | params_format(params)); |
580 | goto err; |
581 | } |
582 | |
583 | max98388->ch_size = snd_pcm_format_width(format: params_format(p: params)); |
584 | |
585 | ret = regmap_read(map: max98388->regmap, |
586 | MAX98388_R2040_PCM_MODE_CFG, val: ®); |
587 | if (ret < 0) |
588 | goto err; |
589 | |
590 | /* GLOBAL_EN OFF prior to the channel size re-configure */ |
591 | if (chan_sz != (reg & MAX98388_PCM_MODE_CFG_CHANSZ_MASK)) { |
592 | ret = regmap_read(map: max98388->regmap, |
593 | MAX98388_R210F_GLOBAL_EN, val: &status); |
594 | if (ret < 0) |
595 | goto err; |
596 | |
597 | if (status) { |
598 | regmap_write(map: max98388->regmap, |
599 | MAX98388_R210F_GLOBAL_EN, val: 0); |
600 | usleep_range(min: 30000, max: 31000); |
601 | } |
602 | regmap_update_bits(map: max98388->regmap, |
603 | MAX98388_R2040_PCM_MODE_CFG, |
604 | MAX98388_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
605 | } |
606 | dev_dbg(component->dev, "format supported %d" , |
607 | params_format(params)); |
608 | |
609 | /* sampling rate configuration */ |
610 | switch (params_rate(p: params)) { |
611 | case 8000: |
612 | sampling_rate = MAX98388_PCM_SR_8000; |
613 | break; |
614 | case 11025: |
615 | sampling_rate = MAX98388_PCM_SR_11025; |
616 | break; |
617 | case 12000: |
618 | sampling_rate = MAX98388_PCM_SR_12000; |
619 | break; |
620 | case 16000: |
621 | sampling_rate = MAX98388_PCM_SR_16000; |
622 | break; |
623 | case 22050: |
624 | sampling_rate = MAX98388_PCM_SR_22050; |
625 | break; |
626 | case 24000: |
627 | sampling_rate = MAX98388_PCM_SR_24000; |
628 | break; |
629 | case 32000: |
630 | sampling_rate = MAX98388_PCM_SR_32000; |
631 | break; |
632 | case 44100: |
633 | sampling_rate = MAX98388_PCM_SR_44100; |
634 | break; |
635 | case 48000: |
636 | sampling_rate = MAX98388_PCM_SR_48000; |
637 | break; |
638 | case 88200: |
639 | sampling_rate = MAX98388_PCM_SR_88200; |
640 | break; |
641 | case 96000: |
642 | sampling_rate = MAX98388_PCM_SR_96000; |
643 | break; |
644 | default: |
645 | dev_err(component->dev, "rate %d not supported\n" , |
646 | params_rate(params)); |
647 | goto err; |
648 | } |
649 | |
650 | /* set DAI_SR to correct LRCLK frequency */ |
651 | regmap_update_bits(map: max98388->regmap, |
652 | MAX98388_R2042_PCM_SR_SETUP, |
653 | MAX98388_PCM_SR_MASK, |
654 | val: sampling_rate); |
655 | |
656 | /* set sampling rate of IV */ |
657 | if (max98388->interleave_mode && |
658 | sampling_rate > MAX98388_PCM_SR_16000) |
659 | regmap_update_bits(map: max98388->regmap, |
660 | MAX98388_R2042_PCM_SR_SETUP, |
661 | MAX98388_PCM_SR_IV_MASK, |
662 | val: (sampling_rate - 3) << MAX98388_PCM_SR_IV_SHIFT); |
663 | else |
664 | regmap_update_bits(map: max98388->regmap, |
665 | MAX98388_R2042_PCM_SR_SETUP, |
666 | MAX98388_PCM_SR_IV_MASK, |
667 | val: sampling_rate << MAX98388_PCM_SR_IV_SHIFT); |
668 | |
669 | ret = max98388_set_clock(component, params); |
670 | |
671 | if (status) { |
672 | regmap_write(map: max98388->regmap, |
673 | MAX98388_R210F_GLOBAL_EN, val: 1); |
674 | usleep_range(min: 30000, max: 31000); |
675 | } |
676 | |
677 | return ret; |
678 | |
679 | err: |
680 | return -EINVAL; |
681 | } |
682 | |
683 | #define MAX_NUM_SLOTS 16 |
684 | #define MAX_NUM_CH 2 |
685 | |
686 | static int max98388_dai_tdm_slot(struct snd_soc_dai *dai, |
687 | unsigned int tx_mask, unsigned int rx_mask, |
688 | int slots, int slot_width) |
689 | { |
690 | struct snd_soc_component *component = dai->component; |
691 | struct max98388_priv *max98388 = snd_soc_component_get_drvdata(c: component); |
692 | int bsel = 0; |
693 | unsigned int chan_sz = 0; |
694 | unsigned int mask; |
695 | int cnt, slot_found; |
696 | int addr, bits; |
697 | |
698 | if (!tx_mask && !rx_mask && !slots && !slot_width) |
699 | max98388->tdm_mode = false; |
700 | else |
701 | max98388->tdm_mode = true; |
702 | |
703 | /* BCLK configuration */ |
704 | bsel = max98388_get_bclk_sel(bclk: slots * slot_width); |
705 | if (bsel == 0) { |
706 | dev_err(component->dev, "BCLK %d not supported\n" , |
707 | slots * slot_width); |
708 | return -EINVAL; |
709 | } |
710 | |
711 | regmap_update_bits(map: max98388->regmap, |
712 | MAX98388_R2041_PCM_CLK_SETUP, |
713 | MAX98388_PCM_CLK_SETUP_BSEL_MASK, |
714 | val: bsel); |
715 | |
716 | /* Channel size configuration */ |
717 | switch (slot_width) { |
718 | case 16: |
719 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_16; |
720 | break; |
721 | case 24: |
722 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_24; |
723 | break; |
724 | case 32: |
725 | chan_sz = MAX98388_PCM_MODE_CFG_CHANSZ_32; |
726 | break; |
727 | default: |
728 | dev_err(component->dev, "format unsupported %d\n" , |
729 | slot_width); |
730 | return -EINVAL; |
731 | } |
732 | |
733 | regmap_update_bits(map: max98388->regmap, |
734 | MAX98388_R2040_PCM_MODE_CFG, |
735 | MAX98388_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
736 | |
737 | /* Rx slot configuration */ |
738 | slot_found = 0; |
739 | mask = rx_mask; |
740 | for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { |
741 | if (mask & 0x1) { |
742 | if (slot_found == 0) |
743 | regmap_update_bits(map: max98388->regmap, |
744 | MAX98388_R2059_PCM_RX_SRC2, |
745 | MAX98388_RX_SRC_CH0_SHIFT, |
746 | val: cnt); |
747 | else |
748 | regmap_update_bits(map: max98388->regmap, |
749 | MAX98388_R2059_PCM_RX_SRC2, |
750 | MAX98388_RX_SRC_CH1_SHIFT, |
751 | val: cnt); |
752 | slot_found++; |
753 | if (slot_found >= MAX_NUM_CH) |
754 | break; |
755 | } |
756 | } |
757 | |
758 | /* speaker feedback slot configuration */ |
759 | slot_found = 0; |
760 | mask = tx_mask; |
761 | for (cnt = 0 ; cnt < MAX_NUM_SLOTS ; cnt++, mask >>= 1) { |
762 | if (mask & 0x1) { |
763 | addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8); |
764 | bits = cnt % 8; |
765 | regmap_update_bits(map: max98388->regmap, reg: addr, mask: bits, val: bits); |
766 | if (slot_found >= MAX_NUM_CH) |
767 | break; |
768 | } |
769 | } |
770 | |
771 | return 0; |
772 | } |
773 | |
774 | #define MAX98388_RATES SNDRV_PCM_RATE_8000_96000 |
775 | |
776 | #define MAX98388_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
777 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
778 | |
779 | static const struct snd_soc_dai_ops max98388_dai_ops = { |
780 | .set_fmt = max98388_dai_set_fmt, |
781 | .hw_params = max98388_dai_hw_params, |
782 | .set_tdm_slot = max98388_dai_tdm_slot, |
783 | }; |
784 | |
785 | static bool max98388_readable_register(struct device *dev, |
786 | unsigned int reg) |
787 | { |
788 | switch (reg) { |
789 | case MAX98388_R2001_INT_RAW1 ... MAX98388_R2002_INT_RAW2: |
790 | case MAX98388_R2004_INT_STATE1... MAX98388_R2005_INT_STATE2: |
791 | case MAX98388_R2020_THERM_WARN_THRESH: |
792 | case MAX98388_R2031_SPK_MON_THRESH |
793 | ... MAX98388_R2033_SPK_MON_DURATION: |
794 | case MAX98388_R2037_ERR_MON_CTRL: |
795 | case MAX98388_R2040_PCM_MODE_CFG |
796 | ... MAX98388_R2042_PCM_SR_SETUP: |
797 | case MAX98388_R2044_PCM_TX_CTRL1 |
798 | ... MAX98388_R2045_PCM_TX_CTRL2: |
799 | case MAX98388_R2050_PCM_TX_HIZ_CTRL1 |
800 | ... MAX98388_R2059_PCM_RX_SRC2: |
801 | case MAX98388_R205C_PCM_TX_DRIVE_STRENGTH |
802 | ... MAX98388_R205F_PCM_TX_EN: |
803 | case MAX98388_R2090_SPK_CH_VOL_CTRL |
804 | ... MAX98388_R2094_SPK_AMP_ER_CTRL: |
805 | case MAX98388_R209E_SPK_CH_PINK_NOISE_EN |
806 | ... MAX98388_R209F_SPK_CH_AMP_EN: |
807 | case MAX98388_R20A0_IV_DATA_DSP_CTRL: |
808 | case MAX98388_R20A7_IV_DATA_EN: |
809 | case MAX98388_R20E0_BP_ALC_THRESH ... MAX98388_R20E4_BP_ALC_MUTE: |
810 | case MAX98388_R20EE_BP_INF_HOLD_REL ... MAX98388_R20EF_BP_ALC_EN: |
811 | case MAX98388_R210E_AUTO_RESTART: |
812 | case MAX98388_R210F_GLOBAL_EN: |
813 | case MAX98388_R22FF_REV_ID: |
814 | return true; |
815 | default: |
816 | return false; |
817 | } |
818 | }; |
819 | |
820 | static bool max98388_volatile_reg(struct device *dev, unsigned int reg) |
821 | { |
822 | switch (reg) { |
823 | case MAX98388_R2001_INT_RAW1 ... MAX98388_R2005_INT_STATE2: |
824 | case MAX98388_R210F_GLOBAL_EN: |
825 | case MAX98388_R22FF_REV_ID: |
826 | return true; |
827 | default: |
828 | return false; |
829 | } |
830 | } |
831 | |
832 | static struct snd_soc_dai_driver max98388_dai[] = { |
833 | { |
834 | .name = "max98388-aif1" , |
835 | .playback = { |
836 | .stream_name = "HiFi Playback" , |
837 | .channels_min = 1, |
838 | .channels_max = 2, |
839 | .rates = MAX98388_RATES, |
840 | .formats = MAX98388_FORMATS, |
841 | }, |
842 | .capture = { |
843 | .stream_name = "HiFi Capture" , |
844 | .channels_min = 1, |
845 | .channels_max = 2, |
846 | .rates = MAX98388_RATES, |
847 | .formats = MAX98388_FORMATS, |
848 | }, |
849 | .ops = &max98388_dai_ops, |
850 | } |
851 | }; |
852 | |
853 | static int max98388_suspend(struct device *dev) |
854 | { |
855 | struct max98388_priv *max98388 = dev_get_drvdata(dev); |
856 | |
857 | regcache_cache_only(map: max98388->regmap, enable: true); |
858 | regcache_mark_dirty(map: max98388->regmap); |
859 | |
860 | return 0; |
861 | } |
862 | |
863 | static int max98388_resume(struct device *dev) |
864 | { |
865 | struct max98388_priv *max98388 = dev_get_drvdata(dev); |
866 | |
867 | regcache_cache_only(map: max98388->regmap, enable: false); |
868 | max98388_reset(max98388, dev); |
869 | regcache_sync(map: max98388->regmap); |
870 | |
871 | return 0; |
872 | } |
873 | |
874 | static const struct dev_pm_ops max98388_pm = { |
875 | SYSTEM_SLEEP_PM_OPS(max98388_suspend, max98388_resume) |
876 | }; |
877 | |
878 | static const struct regmap_config max98388_regmap = { |
879 | .reg_bits = 16, |
880 | .val_bits = 8, |
881 | .max_register = MAX98388_R22FF_REV_ID, |
882 | .reg_defaults = max98388_reg, |
883 | .num_reg_defaults = ARRAY_SIZE(max98388_reg), |
884 | .readable_reg = max98388_readable_register, |
885 | .volatile_reg = max98388_volatile_reg, |
886 | .cache_type = REGCACHE_RBTREE, |
887 | }; |
888 | |
889 | static const struct snd_soc_component_driver soc_codec_dev_max98388 = { |
890 | .probe = max98388_probe, |
891 | .controls = max98388_snd_controls, |
892 | .num_controls = ARRAY_SIZE(max98388_snd_controls), |
893 | .dapm_widgets = max98388_dapm_widgets, |
894 | .num_dapm_widgets = ARRAY_SIZE(max98388_dapm_widgets), |
895 | .dapm_routes = max98388_audio_map, |
896 | .num_dapm_routes = ARRAY_SIZE(max98388_audio_map), |
897 | .use_pmdown_time = 1, |
898 | .endianness = 1, |
899 | }; |
900 | |
901 | static void max98388_read_deveice_property(struct device *dev, |
902 | struct max98388_priv *max98388) |
903 | { |
904 | int value; |
905 | |
906 | if (!device_property_read_u32(dev, propname: "adi,vmon-slot-no" , val: &value)) |
907 | max98388->v_slot = value & 0xF; |
908 | else |
909 | max98388->v_slot = 0; |
910 | |
911 | if (!device_property_read_u32(dev, propname: "adi,imon-slot-no" , val: &value)) |
912 | max98388->i_slot = value & 0xF; |
913 | else |
914 | max98388->i_slot = 1; |
915 | |
916 | if (device_property_read_bool(dev, propname: "adi,interleave-mode" )) |
917 | max98388->interleave_mode = true; |
918 | else |
919 | max98388->interleave_mode = false; |
920 | } |
921 | |
922 | static int max98388_i2c_probe(struct i2c_client *i2c) |
923 | { |
924 | int ret = 0; |
925 | int reg = 0; |
926 | |
927 | struct max98388_priv *max98388 = NULL; |
928 | |
929 | max98388 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*max98388), GFP_KERNEL); |
930 | if (!max98388) |
931 | return -ENOMEM; |
932 | |
933 | i2c_set_clientdata(client: i2c, data: max98388); |
934 | |
935 | /* regmap initialization */ |
936 | max98388->regmap = devm_regmap_init_i2c(i2c, &max98388_regmap); |
937 | if (IS_ERR(ptr: max98388->regmap)) |
938 | return dev_err_probe(dev: &i2c->dev, err: PTR_ERR(ptr: max98388->regmap), |
939 | fmt: "Failed to allocate register map.\n" ); |
940 | |
941 | /* voltage/current slot & gpio configuration */ |
942 | max98388_read_deveice_property(dev: &i2c->dev, max98388); |
943 | |
944 | /* Device Reset */ |
945 | max98388->reset_gpio = devm_gpiod_get_optional(dev: &i2c->dev, |
946 | con_id: "reset" , flags: GPIOD_OUT_HIGH); |
947 | if (IS_ERR(ptr: max98388->reset_gpio)) |
948 | return dev_err_probe(dev: &i2c->dev, err: PTR_ERR(ptr: max98388->reset_gpio), |
949 | fmt: "Unable to request GPIO\n" ); |
950 | |
951 | if (max98388->reset_gpio) { |
952 | usleep_range(min: 5000, max: 6000); |
953 | gpiod_set_value_cansleep(desc: max98388->reset_gpio, value: 0); |
954 | /* Wait for the hw reset done */ |
955 | usleep_range(min: 5000, max: 6000); |
956 | } |
957 | |
958 | /* Read Revision ID */ |
959 | ret = regmap_read(map: max98388->regmap, |
960 | MAX98388_R22FF_REV_ID, val: ®); |
961 | if (ret < 0) |
962 | return dev_err_probe(dev: &i2c->dev, err: ret, |
963 | fmt: "Failed to read the revision ID\n" ); |
964 | |
965 | dev_info(&i2c->dev, "MAX98388 revisionID: 0x%02X\n" , reg); |
966 | |
967 | /* codec registration */ |
968 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
969 | component_driver: &soc_codec_dev_max98388, |
970 | dai_drv: max98388_dai, |
971 | ARRAY_SIZE(max98388_dai)); |
972 | if (ret < 0) |
973 | dev_err(&i2c->dev, "Failed to register codec: %d\n" , ret); |
974 | |
975 | return ret; |
976 | } |
977 | |
978 | static const struct i2c_device_id max98388_i2c_id[] = { |
979 | { "max98388" , 0}, |
980 | { }, |
981 | }; |
982 | |
983 | MODULE_DEVICE_TABLE(i2c, max98388_i2c_id); |
984 | |
985 | static const struct of_device_id max98388_of_match[] = { |
986 | { .compatible = "adi,max98388" , }, |
987 | { } |
988 | }; |
989 | MODULE_DEVICE_TABLE(of, max98388_of_match); |
990 | |
991 | static const struct acpi_device_id max98388_acpi_match[] = { |
992 | { "ADS8388" , 0 }, |
993 | {}, |
994 | }; |
995 | MODULE_DEVICE_TABLE(acpi, max98388_acpi_match); |
996 | |
997 | static struct i2c_driver max98388_i2c_driver = { |
998 | .driver = { |
999 | .name = "max98388" , |
1000 | .of_match_table = max98388_of_match, |
1001 | .acpi_match_table = max98388_acpi_match, |
1002 | .pm = pm_sleep_ptr(&max98388_pm), |
1003 | }, |
1004 | .probe = max98388_i2c_probe, |
1005 | .id_table = max98388_i2c_id, |
1006 | }; |
1007 | |
1008 | module_i2c_driver(max98388_i2c_driver) |
1009 | |
1010 | MODULE_DESCRIPTION("ALSA SoC MAX98388 driver" ); |
1011 | MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>" ); |
1012 | MODULE_LICENSE("GPL" ); |
1013 | |