1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ak4535.c -- AK4535 ALSA Soc Audio driver |
4 | * |
5 | * Copyright 2005 Openedhand Ltd. |
6 | * |
7 | * Author: Richard Purdie <richard@openedhand.com> |
8 | * |
9 | * Based on wm8753.c by Liam Girdwood |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> |
14 | #include <linux/init.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> |
20 | #include <sound/core.h> |
21 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> |
24 | #include <sound/initval.h> |
25 | |
26 | #include "ak4535.h" |
27 | |
28 | /* codec private data */ |
29 | struct ak4535_priv { |
30 | struct regmap *regmap; |
31 | unsigned int sysclk; |
32 | }; |
33 | |
34 | /* |
35 | * ak4535 register cache |
36 | */ |
37 | static const struct reg_default ak4535_reg_defaults[] = { |
38 | { 0, 0x00 }, |
39 | { 1, 0x80 }, |
40 | { 2, 0x00 }, |
41 | { 3, 0x03 }, |
42 | { 4, 0x02 }, |
43 | { 5, 0x00 }, |
44 | { 6, 0x11 }, |
45 | { 7, 0x01 }, |
46 | { 8, 0x00 }, |
47 | { 9, 0x40 }, |
48 | { 10, 0x36 }, |
49 | { 11, 0x10 }, |
50 | { 12, 0x00 }, |
51 | { 13, 0x00 }, |
52 | { 14, 0x57 }, |
53 | }; |
54 | |
55 | static bool ak4535_volatile(struct device *dev, unsigned int reg) |
56 | { |
57 | switch (reg) { |
58 | case AK4535_STATUS: |
59 | return true; |
60 | default: |
61 | return false; |
62 | } |
63 | } |
64 | |
65 | static const char *ak4535_mono_gain[] = {"+6dB" , "-17dB" }; |
66 | static const char *ak4535_mono_out[] = {"(L + R)/2" , "Hi-Z" }; |
67 | static const char *ak4535_hp_out[] = {"Stereo" , "Mono" }; |
68 | static const char *ak4535_deemp[] = {"44.1kHz" , "Off" , "48kHz" , "32kHz" }; |
69 | static const char *ak4535_mic_select[] = {"Internal" , "External" }; |
70 | |
71 | static const struct soc_enum ak4535_enum[] = { |
72 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), |
73 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), |
74 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), |
75 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), |
76 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), |
77 | }; |
78 | |
79 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { |
80 | SOC_SINGLE("ALC2 Switch" , AK4535_SIG1, 1, 1, 0), |
81 | SOC_ENUM("Mono 1 Output" , ak4535_enum[1]), |
82 | SOC_ENUM("Mono 1 Gain" , ak4535_enum[0]), |
83 | SOC_ENUM("Headphone Output" , ak4535_enum[2]), |
84 | SOC_ENUM("Playback Deemphasis" , ak4535_enum[3]), |
85 | SOC_SINGLE("Bass Volume" , AK4535_DAC, 2, 3, 0), |
86 | SOC_SINGLE("Mic Boost (+20dB) Switch" , AK4535_MIC, 0, 1, 0), |
87 | SOC_ENUM("Mic Select" , ak4535_enum[4]), |
88 | SOC_SINGLE("ALC Operation Time" , AK4535_TIMER, 0, 3, 0), |
89 | SOC_SINGLE("ALC Recovery Time" , AK4535_TIMER, 2, 3, 0), |
90 | SOC_SINGLE("ALC ZC Time" , AK4535_TIMER, 4, 3, 0), |
91 | SOC_SINGLE("ALC 1 Switch" , AK4535_ALC1, 5, 1, 0), |
92 | SOC_SINGLE("ALC 2 Switch" , AK4535_ALC1, 6, 1, 0), |
93 | SOC_SINGLE("ALC Volume" , AK4535_ALC2, 0, 127, 0), |
94 | SOC_SINGLE("Capture Volume" , AK4535_PGA, 0, 127, 0), |
95 | SOC_SINGLE("Left Playback Volume" , AK4535_LATT, 0, 127, 1), |
96 | SOC_SINGLE("Right Playback Volume" , AK4535_RATT, 0, 127, 1), |
97 | SOC_SINGLE("AUX Bypass Volume" , AK4535_VOL, 0, 15, 0), |
98 | SOC_SINGLE("Mic Sidetone Volume" , AK4535_VOL, 4, 7, 0), |
99 | }; |
100 | |
101 | /* Mono 1 Mixer */ |
102 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { |
103 | SOC_DAPM_SINGLE("Mic Sidetone Switch" , AK4535_SIG1, 4, 1, 0), |
104 | SOC_DAPM_SINGLE("Mono Playback Switch" , AK4535_SIG1, 5, 1, 0), |
105 | }; |
106 | |
107 | /* Stereo Mixer */ |
108 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { |
109 | SOC_DAPM_SINGLE("Mic Sidetone Switch" , AK4535_SIG2, 4, 1, 0), |
110 | SOC_DAPM_SINGLE("Playback Switch" , AK4535_SIG2, 7, 1, 0), |
111 | SOC_DAPM_SINGLE("Aux Bypass Switch" , AK4535_SIG2, 5, 1, 0), |
112 | }; |
113 | |
114 | /* Input Mixer */ |
115 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { |
116 | SOC_DAPM_SINGLE("Mic Capture Switch" , AK4535_MIC, 2, 1, 0), |
117 | SOC_DAPM_SINGLE("Aux Capture Switch" , AK4535_MIC, 5, 1, 0), |
118 | }; |
119 | |
120 | /* Input mux */ |
121 | static const struct snd_kcontrol_new ak4535_input_mux_control = |
122 | SOC_DAPM_ENUM("Input Select" , ak4535_enum[4]); |
123 | |
124 | /* HP L switch */ |
125 | static const struct snd_kcontrol_new ak4535_hpl_control = |
126 | SOC_DAPM_SINGLE("Switch" , AK4535_SIG2, 1, 1, 1); |
127 | |
128 | /* HP R switch */ |
129 | static const struct snd_kcontrol_new ak4535_hpr_control = |
130 | SOC_DAPM_SINGLE("Switch" , AK4535_SIG2, 0, 1, 1); |
131 | |
132 | /* mono 2 switch */ |
133 | static const struct snd_kcontrol_new ak4535_mono2_control = |
134 | SOC_DAPM_SINGLE("Switch" , AK4535_SIG1, 0, 1, 0); |
135 | |
136 | /* Line out switch */ |
137 | static const struct snd_kcontrol_new ak4535_line_control = |
138 | SOC_DAPM_SINGLE("Switch" , AK4535_SIG2, 6, 1, 0); |
139 | |
140 | /* ak4535 dapm widgets */ |
141 | static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { |
142 | SND_SOC_DAPM_MIXER("Stereo Mixer" , SND_SOC_NOPM, 0, 0, |
143 | &ak4535_stereo_mixer_controls[0], |
144 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), |
145 | SND_SOC_DAPM_MIXER("Mono1 Mixer" , SND_SOC_NOPM, 0, 0, |
146 | &ak4535_mono1_mixer_controls[0], |
147 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), |
148 | SND_SOC_DAPM_MIXER("Input Mixer" , SND_SOC_NOPM, 0, 0, |
149 | &ak4535_input_mixer_controls[0], |
150 | ARRAY_SIZE(ak4535_input_mixer_controls)), |
151 | SND_SOC_DAPM_MUX("Input Mux" , SND_SOC_NOPM, 0, 0, |
152 | &ak4535_input_mux_control), |
153 | SND_SOC_DAPM_DAC("DAC" , "Playback" , AK4535_PM2, 0, 0), |
154 | SND_SOC_DAPM_SWITCH("Mono 2 Enable" , SND_SOC_NOPM, 0, 0, |
155 | &ak4535_mono2_control), |
156 | /* speaker powersave bit */ |
157 | SND_SOC_DAPM_PGA("Speaker Enable" , AK4535_MODE2, 0, 0, NULL, 0), |
158 | SND_SOC_DAPM_SWITCH("Line Out Enable" , SND_SOC_NOPM, 0, 0, |
159 | &ak4535_line_control), |
160 | SND_SOC_DAPM_SWITCH("Left HP Enable" , SND_SOC_NOPM, 0, 0, |
161 | &ak4535_hpl_control), |
162 | SND_SOC_DAPM_SWITCH("Right HP Enable" , SND_SOC_NOPM, 0, 0, |
163 | &ak4535_hpr_control), |
164 | SND_SOC_DAPM_OUTPUT("LOUT" ), |
165 | SND_SOC_DAPM_OUTPUT("HPL" ), |
166 | SND_SOC_DAPM_OUTPUT("ROUT" ), |
167 | SND_SOC_DAPM_OUTPUT("HPR" ), |
168 | SND_SOC_DAPM_OUTPUT("SPP" ), |
169 | SND_SOC_DAPM_OUTPUT("SPN" ), |
170 | SND_SOC_DAPM_OUTPUT("MOUT1" ), |
171 | SND_SOC_DAPM_OUTPUT("MOUT2" ), |
172 | SND_SOC_DAPM_OUTPUT("MICOUT" ), |
173 | SND_SOC_DAPM_ADC("ADC" , "Capture" , AK4535_PM1, 0, 0), |
174 | SND_SOC_DAPM_PGA("Spk Amp" , AK4535_PM2, 3, 0, NULL, 0), |
175 | SND_SOC_DAPM_PGA("HP R Amp" , AK4535_PM2, 1, 0, NULL, 0), |
176 | SND_SOC_DAPM_PGA("HP L Amp" , AK4535_PM2, 2, 0, NULL, 0), |
177 | SND_SOC_DAPM_PGA("Mic" , AK4535_PM1, 1, 0, NULL, 0), |
178 | SND_SOC_DAPM_PGA("Line Out" , AK4535_PM1, 4, 0, NULL, 0), |
179 | SND_SOC_DAPM_PGA("Mono Out" , AK4535_PM1, 3, 0, NULL, 0), |
180 | SND_SOC_DAPM_PGA("AUX In" , AK4535_PM1, 2, 0, NULL, 0), |
181 | |
182 | SND_SOC_DAPM_MICBIAS("Mic Int Bias" , AK4535_MIC, 3, 0), |
183 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias" , AK4535_MIC, 4, 0), |
184 | SND_SOC_DAPM_INPUT("MICIN" ), |
185 | SND_SOC_DAPM_INPUT("MICEXT" ), |
186 | SND_SOC_DAPM_INPUT("AUX" ), |
187 | SND_SOC_DAPM_INPUT("MIN" ), |
188 | SND_SOC_DAPM_INPUT("AIN" ), |
189 | }; |
190 | |
191 | static const struct snd_soc_dapm_route ak4535_audio_map[] = { |
192 | /*stereo mixer */ |
193 | {"Stereo Mixer" , "Playback Switch" , "DAC" }, |
194 | {"Stereo Mixer" , "Mic Sidetone Switch" , "Mic" }, |
195 | {"Stereo Mixer" , "Aux Bypass Switch" , "AUX In" }, |
196 | |
197 | /* mono1 mixer */ |
198 | {"Mono1 Mixer" , "Mic Sidetone Switch" , "Mic" }, |
199 | {"Mono1 Mixer" , "Mono Playback Switch" , "DAC" }, |
200 | |
201 | /* Mic */ |
202 | {"Mic" , NULL, "AIN" }, |
203 | {"Input Mux" , "Internal" , "Mic Int Bias" }, |
204 | {"Input Mux" , "External" , "Mic Ext Bias" }, |
205 | {"Mic Int Bias" , NULL, "MICIN" }, |
206 | {"Mic Ext Bias" , NULL, "MICEXT" }, |
207 | {"MICOUT" , NULL, "Input Mux" }, |
208 | |
209 | /* line out */ |
210 | {"LOUT" , NULL, "Line Out Enable" }, |
211 | {"ROUT" , NULL, "Line Out Enable" }, |
212 | {"Line Out Enable" , "Switch" , "Line Out" }, |
213 | {"Line Out" , NULL, "Stereo Mixer" }, |
214 | |
215 | /* mono1 out */ |
216 | {"MOUT1" , NULL, "Mono Out" }, |
217 | {"Mono Out" , NULL, "Mono1 Mixer" }, |
218 | |
219 | /* left HP */ |
220 | {"HPL" , NULL, "Left HP Enable" }, |
221 | {"Left HP Enable" , "Switch" , "HP L Amp" }, |
222 | {"HP L Amp" , NULL, "Stereo Mixer" }, |
223 | |
224 | /* right HP */ |
225 | {"HPR" , NULL, "Right HP Enable" }, |
226 | {"Right HP Enable" , "Switch" , "HP R Amp" }, |
227 | {"HP R Amp" , NULL, "Stereo Mixer" }, |
228 | |
229 | /* speaker */ |
230 | {"SPP" , NULL, "Speaker Enable" }, |
231 | {"SPN" , NULL, "Speaker Enable" }, |
232 | {"Speaker Enable" , "Switch" , "Spk Amp" }, |
233 | {"Spk Amp" , NULL, "MIN" }, |
234 | |
235 | /* mono 2 */ |
236 | {"MOUT2" , NULL, "Mono 2 Enable" }, |
237 | {"Mono 2 Enable" , "Switch" , "Stereo Mixer" }, |
238 | |
239 | /* Aux In */ |
240 | {"Aux In" , NULL, "AUX" }, |
241 | |
242 | /* ADC */ |
243 | {"ADC" , NULL, "Input Mixer" }, |
244 | {"Input Mixer" , "Mic Capture Switch" , "Mic" }, |
245 | {"Input Mixer" , "Aux Capture Switch" , "Aux In" }, |
246 | }; |
247 | |
248 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
249 | int clk_id, unsigned int freq, int dir) |
250 | { |
251 | struct snd_soc_component *component = codec_dai->component; |
252 | struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(c: component); |
253 | |
254 | ak4535->sysclk = freq; |
255 | return 0; |
256 | } |
257 | |
258 | static int ak4535_hw_params(struct snd_pcm_substream *substream, |
259 | struct snd_pcm_hw_params *params, |
260 | struct snd_soc_dai *dai) |
261 | { |
262 | struct snd_soc_component *component = dai->component; |
263 | struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(c: component); |
264 | u8 mode2 = snd_soc_component_read(component, AK4535_MODE2) & ~(0x3 << 5); |
265 | int rate = params_rate(p: params), fs = 256; |
266 | |
267 | if (rate) |
268 | fs = ak4535->sysclk / rate; |
269 | |
270 | /* set fs */ |
271 | switch (fs) { |
272 | case 1024: |
273 | mode2 |= (0x2 << 5); |
274 | break; |
275 | case 512: |
276 | mode2 |= (0x1 << 5); |
277 | break; |
278 | case 256: |
279 | break; |
280 | } |
281 | |
282 | /* set rate */ |
283 | snd_soc_component_write(component, AK4535_MODE2, val: mode2); |
284 | return 0; |
285 | } |
286 | |
287 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, |
288 | unsigned int fmt) |
289 | { |
290 | struct snd_soc_component *component = codec_dai->component; |
291 | u8 mode1 = 0; |
292 | |
293 | /* interface format */ |
294 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
295 | case SND_SOC_DAIFMT_I2S: |
296 | mode1 = 0x0002; |
297 | break; |
298 | case SND_SOC_DAIFMT_LEFT_J: |
299 | mode1 = 0x0001; |
300 | break; |
301 | default: |
302 | return -EINVAL; |
303 | } |
304 | |
305 | /* use 32 fs for BCLK to save power */ |
306 | mode1 |= 0x4; |
307 | |
308 | snd_soc_component_write(component, AK4535_MODE1, val: mode1); |
309 | return 0; |
310 | } |
311 | |
312 | static int ak4535_mute(struct snd_soc_dai *dai, int mute, int direction) |
313 | { |
314 | struct snd_soc_component *component = dai->component; |
315 | u16 mute_reg = snd_soc_component_read(component, AK4535_DAC); |
316 | |
317 | if (!mute) |
318 | snd_soc_component_write(component, AK4535_DAC, val: mute_reg & ~0x20); |
319 | else |
320 | snd_soc_component_write(component, AK4535_DAC, val: mute_reg | 0x20); |
321 | return 0; |
322 | } |
323 | |
324 | static int ak4535_set_bias_level(struct snd_soc_component *component, |
325 | enum snd_soc_bias_level level) |
326 | { |
327 | switch (level) { |
328 | case SND_SOC_BIAS_ON: |
329 | snd_soc_component_update_bits(component, AK4535_DAC, mask: 0x20, val: 0); |
330 | break; |
331 | case SND_SOC_BIAS_PREPARE: |
332 | snd_soc_component_update_bits(component, AK4535_DAC, mask: 0x20, val: 0x20); |
333 | break; |
334 | case SND_SOC_BIAS_STANDBY: |
335 | snd_soc_component_update_bits(component, AK4535_PM1, mask: 0x80, val: 0x80); |
336 | snd_soc_component_update_bits(component, AK4535_PM2, mask: 0x80, val: 0); |
337 | break; |
338 | case SND_SOC_BIAS_OFF: |
339 | snd_soc_component_update_bits(component, AK4535_PM1, mask: 0x80, val: 0); |
340 | break; |
341 | } |
342 | return 0; |
343 | } |
344 | |
345 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
346 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
347 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
348 | |
349 | static const struct snd_soc_dai_ops ak4535_dai_ops = { |
350 | .hw_params = ak4535_hw_params, |
351 | .set_fmt = ak4535_set_dai_fmt, |
352 | .mute_stream = ak4535_mute, |
353 | .set_sysclk = ak4535_set_dai_sysclk, |
354 | .no_capture_mute = 1, |
355 | }; |
356 | |
357 | static struct snd_soc_dai_driver ak4535_dai = { |
358 | .name = "ak4535-hifi" , |
359 | .playback = { |
360 | .stream_name = "Playback" , |
361 | .channels_min = 1, |
362 | .channels_max = 2, |
363 | .rates = AK4535_RATES, |
364 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
365 | .capture = { |
366 | .stream_name = "Capture" , |
367 | .channels_min = 1, |
368 | .channels_max = 2, |
369 | .rates = AK4535_RATES, |
370 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
371 | .ops = &ak4535_dai_ops, |
372 | }; |
373 | |
374 | static int ak4535_resume(struct snd_soc_component *component) |
375 | { |
376 | snd_soc_component_cache_sync(component); |
377 | return 0; |
378 | } |
379 | |
380 | static const struct regmap_config ak4535_regmap = { |
381 | .reg_bits = 8, |
382 | .val_bits = 8, |
383 | |
384 | .max_register = AK4535_STATUS, |
385 | .volatile_reg = ak4535_volatile, |
386 | |
387 | .cache_type = REGCACHE_RBTREE, |
388 | .reg_defaults = ak4535_reg_defaults, |
389 | .num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults), |
390 | }; |
391 | |
392 | static const struct snd_soc_component_driver soc_component_dev_ak4535 = { |
393 | .resume = ak4535_resume, |
394 | .set_bias_level = ak4535_set_bias_level, |
395 | .controls = ak4535_snd_controls, |
396 | .num_controls = ARRAY_SIZE(ak4535_snd_controls), |
397 | .dapm_widgets = ak4535_dapm_widgets, |
398 | .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), |
399 | .dapm_routes = ak4535_audio_map, |
400 | .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map), |
401 | .suspend_bias_off = 1, |
402 | .idle_bias_on = 1, |
403 | .use_pmdown_time = 1, |
404 | .endianness = 1, |
405 | }; |
406 | |
407 | static int ak4535_i2c_probe(struct i2c_client *i2c) |
408 | { |
409 | struct ak4535_priv *ak4535; |
410 | int ret; |
411 | |
412 | ak4535 = devm_kzalloc(dev: &i2c->dev, size: sizeof(struct ak4535_priv), |
413 | GFP_KERNEL); |
414 | if (ak4535 == NULL) |
415 | return -ENOMEM; |
416 | |
417 | ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap); |
418 | if (IS_ERR(ptr: ak4535->regmap)) { |
419 | ret = PTR_ERR(ptr: ak4535->regmap); |
420 | dev_err(&i2c->dev, "Failed to init regmap: %d\n" , ret); |
421 | return ret; |
422 | } |
423 | |
424 | i2c_set_clientdata(client: i2c, data: ak4535); |
425 | |
426 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
427 | component_driver: &soc_component_dev_ak4535, dai_drv: &ak4535_dai, num_dai: 1); |
428 | |
429 | return ret; |
430 | } |
431 | |
432 | static const struct i2c_device_id ak4535_i2c_id[] = { |
433 | { "ak4535" , 0 }, |
434 | { } |
435 | }; |
436 | MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); |
437 | |
438 | static struct i2c_driver ak4535_i2c_driver = { |
439 | .driver = { |
440 | .name = "ak4535" , |
441 | }, |
442 | .probe = ak4535_i2c_probe, |
443 | .id_table = ak4535_i2c_id, |
444 | }; |
445 | |
446 | module_i2c_driver(ak4535_i2c_driver); |
447 | |
448 | MODULE_DESCRIPTION("Soc AK4535 driver" ); |
449 | MODULE_AUTHOR("Richard Purdie" ); |
450 | MODULE_LICENSE("GPL" ); |
451 | |