1 /*
2 ** =============================================================================
3 ** Copyright (c) 2016 Texas Instruments Inc.
4 **
5 ** This program is free software; you can redistribute it and/or modify it under
6 ** the terms of the GNU General Public License as published by the Free Software
7 ** Foundation; version 2.
8 **
9 ** This program is distributed in the hope that it will be useful, but WITHOUT
10 ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 ** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 **
13 ** File:
14 ** tas2557-codec.c
15 **
16 ** Description:
17 ** ALSA SoC driver for Texas Instruments TAS2557 High Performance 4W Smart Amplifier
18 **
19 ** =============================================================================
20 */
22 #ifdef CONFIG_TAS2557_CODEC
24 #define DEBUG
25 #include <linux/module.h>
26 #include <linux/moduleparam.h>
27 #include <linux/init.h>
28 #include <linux/delay.h>
29 #include <linux/pm.h>
30 #include <linux/i2c.h>
31 #include <linux/gpio.h>
32 #include <linux/regulator/consumer.h>
33 #include <linux/firmware.h>
34 #include <linux/regmap.h>
35 #include <linux/of.h>
36 #include <linux/of_gpio.h>
37 #include <linux/slab.h>
38 #include <linux/syscalls.h>
39 #include <linux/fcntl.h>
40 #include <linux/uaccess.h>
41 #include <sound/core.h>
42 #include <sound/pcm.h>
43 #include <sound/pcm_params.h>
44 #include <sound/soc.h>
45 #include <sound/initval.h>
46 #include <sound/tlv.h>
48 #include "tas2557-core.h"
49 #include "tas2557-codec.h"
51 #define KCONTROL_CODEC
53 static unsigned int tas2557_codec_read(struct snd_soc_codec *pCodec,
54 unsigned int nRegister)
55 {
56 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
57 int ret = 0;
58 unsigned int Value = 0;
60 mutex_lock(&pTAS2557->codec_lock);
62 ret = pTAS2557->read(pTAS2557, nRegister, &Value);
63 if (ret < 0)
64 dev_err(pTAS2557->dev, "%s, %d, ERROR happen=%d\n", __func__,
65 __LINE__, ret);
66 else
67 ret = Value;
69 mutex_unlock(&pTAS2557->codec_lock);
70 return ret;
71 }
73 static int tas2557_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegister,
74 unsigned int nValue)
75 {
76 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
77 int ret = 0;
79 mutex_lock(&pTAS2557->codec_lock);
81 ret = pTAS2557->write(pTAS2557, nRegister, nValue);
83 mutex_unlock(&pTAS2557->codec_lock);
84 return ret;
85 }
87 static int tas2557_codec_suspend(struct snd_soc_codec *pCodec)
88 {
89 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
90 int ret = 0;
92 mutex_lock(&pTAS2557->codec_lock);
94 dev_dbg(pTAS2557->dev, "%s\n", __func__);
95 pTAS2557->runtime_suspend(pTAS2557);
97 mutex_unlock(&pTAS2557->codec_lock);
98 return ret;
99 }
101 static int tas2557_codec_resume(struct snd_soc_codec *pCodec)
102 {
103 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
104 int ret = 0;
106 mutex_lock(&pTAS2557->codec_lock);
108 dev_dbg(pTAS2557->dev, "%s\n", __func__);
109 pTAS2557->runtime_resume(pTAS2557);
111 mutex_unlock(&pTAS2557->codec_lock);
112 return ret;
113 }
115 static const struct snd_soc_dapm_widget tas2557_dapm_widgets[] = {
116 SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
117 SND_SOC_DAPM_AIF_IN("ASI2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
118 SND_SOC_DAPM_AIF_IN("ASIM", "ASIM Playback", 0, SND_SOC_NOPM, 0, 0),
119 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
121 SND_SOC_DAPM_OUT_DRV("ClassD", SND_SOC_NOPM, 0, 0, NULL, 0),
123 SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, NULL, 0),
124 SND_SOC_DAPM_SUPPLY("NDivider", SND_SOC_NOPM, 0, 0, NULL, 0),
126 SND_SOC_DAPM_OUTPUT("OUT")
127 };
129 static const struct snd_soc_dapm_route tas2557_audio_map[] = {
130 {"DAC", NULL, "ASI1"},
131 {"DAC", NULL, "ASI2"},
132 {"DAC", NULL, "ASIM"},
133 {"ClassD", NULL, "DAC"},
134 {"OUT", NULL, "ClassD"},
135 {"DAC", NULL, "PLL"},
136 {"DAC", NULL, "NDivider"},
137 };
139 static int tas2557_startup(struct snd_pcm_substream *substream,
140 struct snd_soc_dai *dai)
141 {
142 struct snd_soc_codec *codec = dai->codec;
143 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
145 dev_dbg(pTAS2557->dev, "%s\n", __func__);
146 return 0;
147 }
149 static void tas2557_shutdown(struct snd_pcm_substream *substream,
150 struct snd_soc_dai *dai)
151 {
152 struct snd_soc_codec *codec = dai->codec;
153 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
155 dev_dbg(pTAS2557->dev, "%s\n", __func__);
156 }
158 static int tas2557_mute(struct snd_soc_dai *dai, int mute)
159 {
160 struct snd_soc_codec *codec = dai->codec;
161 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
163 mutex_lock(&pTAS2557->codec_lock);
165 dev_dbg(pTAS2557->dev, "%s\n", __func__);
166 tas2557_enable(pTAS2557, !mute);
168 mutex_unlock(&pTAS2557->codec_lock);
169 return 0;
170 }
172 static int tas2557_set_dai_sysclk(struct snd_soc_dai *pDAI,
173 int nClkID, unsigned int nFreqency, int nDir)
174 {
175 struct snd_soc_codec *pCodec = pDAI->codec;
176 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
178 dev_dbg(pTAS2557->dev, "tas2557_set_dai_sysclk: freq = %u\n", nFreqency);
180 return 0;
181 }
183 static int tas2557_hw_params(struct snd_pcm_substream *pSubstream,
184 struct snd_pcm_hw_params *pParams, struct snd_soc_dai *pDAI)
185 {
186 struct snd_soc_codec *pCodec = pDAI->codec;
187 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
189 mutex_lock(&pTAS2557->codec_lock);
191 dev_dbg(pTAS2557->dev, "%s\n", __func__);
192 /* do bit rate setting during platform data */
193 /* tas2557_set_bit_rate(pTAS2557, channel_both, snd_pcm_format_width(params_format(pParams))); */
194 tas2557_set_sampling_rate(pTAS2557, params_rate(pParams));
196 mutex_unlock(&pTAS2557->codec_lock);
197 return 0;
198 }
200 static int tas2557_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat)
201 {
202 struct snd_soc_codec *codec = pDAI->codec;
203 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
205 dev_dbg(pTAS2557->dev, "%s\n", __func__);
206 return 0;
207 }
209 static int tas2557_prepare(struct snd_pcm_substream *pSubstream,
210 struct snd_soc_dai *pDAI)
211 {
212 struct snd_soc_codec *codec = pDAI->codec;
213 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
215 dev_dbg(pTAS2557->dev, "%s\n", __func__);
216 return 0;
217 }
219 static int tas2557_set_bias_level(struct snd_soc_codec *pCodec,
220 enum snd_soc_bias_level eLevel)
221 {
222 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
224 dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, eLevel);
225 return 0;
226 }
228 static int tas2557_codec_probe(struct snd_soc_codec *pCodec)
229 {
230 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec);
232 dev_dbg(pTAS2557->dev, "%s\n", __func__);
233 return 0;
234 }
236 static int tas2557_codec_remove(struct snd_soc_codec *pCodec)
237 {
238 return 0;
239 }
241 static int tas2557_power_ctrl_get(struct snd_kcontrol *pKcontrol,
242 struct snd_ctl_elem_value *pValue)
243 {
244 #ifdef KCONTROL_CODEC
245 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
246 #else
247 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
248 #endif
249 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
251 mutex_lock(&pTAS2557->codec_lock);
253 pValue->value.integer.value[0] = pTAS2557->mbPowerUp;
254 dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_get = %d\n",
255 pTAS2557->mbPowerUp);
257 mutex_unlock(&pTAS2557->codec_lock);
258 return 0;
259 }
261 static int tas2557_power_ctrl_put(struct snd_kcontrol *pKcontrol,
262 struct snd_ctl_elem_value *pValue)
263 {
264 #ifdef KCONTROL_CODEC
265 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
266 #else
267 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
268 #endif
269 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
271 int nPowerOn = pValue->value.integer.value[0];
273 mutex_lock(&pTAS2557->codec_lock);
275 dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_put = %d\n", nPowerOn);
276 tas2557_enable(pTAS2557, (nPowerOn != 0));
278 mutex_unlock(&pTAS2557->codec_lock);
279 return 0;
280 }
282 static int tas2557_fs_get(struct snd_kcontrol *pKcontrol,
283 struct snd_ctl_elem_value *pValue)
284 {
285 #ifdef KCONTROL_CODEC
286 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
287 #else
288 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
289 #endif
290 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
291 int nFS = 48000;
293 mutex_lock(&pTAS2557->codec_lock);
295 if (pTAS2557->mpFirmware->mnConfigurations)
296 nFS = pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration].mnSamplingRate;
297 pValue->value.integer.value[0] = nFS;
298 dev_dbg(pTAS2557->dev, "tas2557_fs_get = %d\n", nFS);
300 mutex_unlock(&pTAS2557->codec_lock);
301 return 0;
302 }
304 static int tas2557_fs_put(struct snd_kcontrol *pKcontrol,
305 struct snd_ctl_elem_value *pValue)
306 {
307 #ifdef KCONTROL_CODEC
308 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
309 #else
310 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
311 #endif
312 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
313 int ret = 0;
314 int nFS = pValue->value.integer.value[0];
316 mutex_lock(&pTAS2557->codec_lock);
318 dev_info(pTAS2557->dev, "tas2557_fs_put = %d\n", nFS);
319 ret = tas2557_set_sampling_rate(pTAS2557, nFS);
321 mutex_unlock(&pTAS2557->codec_lock);
322 return ret;
323 }
325 static int tas2557_Cali_get(struct snd_kcontrol *pKcontrol,
326 struct snd_ctl_elem_value *pValue)
327 {
328 #ifdef KCONTROL_CODEC
329 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
330 #else
331 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
332 #endif
333 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
334 bool ret = 0;
335 int prm_r0 = 0;
337 mutex_lock(&pTAS2557->codec_lock);
339 ret = tas2557_get_Cali_prm_r0(pTAS2557, &prm_r0);
340 if (ret)
341 pValue->value.integer.value[0] = prm_r0;
344 mutex_unlock(&pTAS2557->codec_lock);
345 return 0;
346 }
348 static int tas2557_program_get(struct snd_kcontrol *pKcontrol,
349 struct snd_ctl_elem_value *pValue)
350 {
351 #ifdef KCONTROL_CODEC
352 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
353 #else
354 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
355 #endif
356 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
358 mutex_lock(&pTAS2557->codec_lock);
360 pValue->value.integer.value[0] = pTAS2557->mnCurrentProgram;
361 dev_dbg(pTAS2557->dev, "tas2557_program_get = %d\n",
362 pTAS2557->mnCurrentProgram);
364 mutex_unlock(&pTAS2557->codec_lock);
365 return 0;
366 }
368 static int tas2557_program_put(struct snd_kcontrol *pKcontrol,
369 struct snd_ctl_elem_value *pValue)
370 {
371 #ifdef KCONTROL_CODEC
372 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
373 #else
374 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
375 #endif
376 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
377 unsigned int nProgram = pValue->value.integer.value[0];
378 int ret = 0, nConfiguration = -1;
380 mutex_lock(&pTAS2557->codec_lock);
382 if (nProgram == pTAS2557->mnCurrentProgram)
383 nConfiguration = pTAS2557->mnCurrentConfiguration;
384 ret = tas2557_set_program(pTAS2557, nProgram, nConfiguration);
386 mutex_unlock(&pTAS2557->codec_lock);
387 return ret;
388 }
390 static int tas2557_configuration_get(struct snd_kcontrol *pKcontrol,
391 struct snd_ctl_elem_value *pValue)
392 {
393 #ifdef KCONTROL_CODEC
394 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
395 #else
396 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
397 #endif
398 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
400 mutex_lock(&pTAS2557->codec_lock);
402 pValue->value.integer.value[0] = pTAS2557->mnCurrentConfiguration;
403 dev_dbg(pTAS2557->dev, "tas2557_configuration_get = %d\n",
404 pTAS2557->mnCurrentConfiguration);
406 mutex_unlock(&pTAS2557->codec_lock);
407 return 0;
408 }
410 static int tas2557_configuration_put(struct snd_kcontrol *pKcontrol,
411 struct snd_ctl_elem_value *pValue)
412 {
413 #ifdef KCONTROL_CODEC
414 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
415 #else
416 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
417 #endif
418 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
419 unsigned int nConfiguration = pValue->value.integer.value[0];
420 int ret = 0;
422 mutex_lock(&pTAS2557->codec_lock);
424 dev_info(pTAS2557->dev, "%s = %d\n", __func__, nConfiguration);
425 ret = tas2557_set_config(pTAS2557, nConfiguration);
427 mutex_unlock(&pTAS2557->codec_lock);
428 return ret;
429 }
431 static int tas2557_calibration_get(struct snd_kcontrol *pKcontrol,
432 struct snd_ctl_elem_value *pValue)
433 {
434 #ifdef KCONTROL_CODEC
435 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
436 #else
437 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
438 #endif
439 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
441 mutex_lock(&pTAS2557->codec_lock);
443 pValue->value.integer.value[0] = pTAS2557->mnCurrentCalibration;
444 dev_info(pTAS2557->dev,
445 "tas2557_calibration_get = %d\n",
446 pTAS2557->mnCurrentCalibration);
448 mutex_unlock(&pTAS2557->codec_lock);
449 return 0;
450 }
452 static int tas2557_calibration_put(struct snd_kcontrol *pKcontrol,
453 struct snd_ctl_elem_value *pValue)
454 {
455 #ifdef KCONTROL_CODEC
456 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
457 #else
458 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
459 #endif
460 struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec);
461 unsigned int nCalibration = pValue->value.integer.value[0];
462 int ret = 0;
464 mutex_lock(&pTAS2557->codec_lock);
466 ret = tas2557_set_calibration(pTAS2557, nCalibration);
468 mutex_unlock(&pTAS2557->codec_lock);
469 return ret;
470 }
472 static const struct snd_kcontrol_new tas2557_snd_controls[] = {
473 SOC_SINGLE_EXT("PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
474 tas2557_power_ctrl_get, tas2557_power_ctrl_put),
475 SOC_SINGLE_EXT("Program", SND_SOC_NOPM, 0, 0x00FF, 0, tas2557_program_get,
476 tas2557_program_put),
477 SOC_SINGLE_EXT("Configuration", SND_SOC_NOPM, 0, 0x00FF, 0,
478 tas2557_configuration_get, tas2557_configuration_put),
479 SOC_SINGLE_EXT("FS", SND_SOC_NOPM, 8000, 48000, 0,
480 tas2557_fs_get, tas2557_fs_put),
481 SOC_SINGLE_EXT("Get Cali_Re", SND_SOC_NOPM, 0, 0x7f000000, 0,
482 tas2557_Cali_get, NULL),
483 SOC_SINGLE_EXT("Calibration", SND_SOC_NOPM, 0, 0x00FF, 0,
484 tas2557_calibration_get, tas2557_calibration_put),
485 };
487 static struct snd_soc_codec_driver soc_codec_driver_tas2557 = {
488 .probe = tas2557_codec_probe,
489 .remove = tas2557_codec_remove,
490 .read = tas2557_codec_read,
491 .write = tas2557_codec_write,
492 .suspend = tas2557_codec_suspend,
493 .resume = tas2557_codec_resume,
494 .set_bias_level = tas2557_set_bias_level,
495 .idle_bias_off = true,
496 .controls = tas2557_snd_controls,
497 .num_controls = ARRAY_SIZE(tas2557_snd_controls),
498 .dapm_widgets = tas2557_dapm_widgets,
499 .num_dapm_widgets = ARRAY_SIZE(tas2557_dapm_widgets),
500 .dapm_routes = tas2557_audio_map,
501 .num_dapm_routes = ARRAY_SIZE(tas2557_audio_map),
502 };
504 static struct snd_soc_dai_ops tas2557_dai_ops = {
505 .startup = tas2557_startup,
506 .shutdown = tas2557_shutdown,
507 .digital_mute = tas2557_mute,
508 .hw_params = tas2557_hw_params,
509 .prepare = tas2557_prepare,
510 .set_sysclk = tas2557_set_dai_sysclk,
511 .set_fmt = tas2557_set_dai_fmt,
512 };
514 #define TAS2557_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
515 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
516 static struct snd_soc_dai_driver tas2557_dai_driver[] = {
517 {
518 .name = "tas2557 ASI1",
519 .id = 0,
520 .playback = {
521 .stream_name = "ASI1 Playback",
522 .channels_min = 2,
523 .channels_max = 2,
524 .rates = SNDRV_PCM_RATE_8000_192000,
525 .formats = TAS2557_FORMATS,
526 },
527 .ops = &tas2557_dai_ops,
528 .symmetric_rates = 1,
529 },
530 {
531 .name = "tas2557 ASI2",
532 .id = 1,
533 .playback = {
534 .stream_name = "ASI2 Playback",
535 .channels_min = 2,
536 .channels_max = 2,
537 .rates = SNDRV_PCM_RATE_8000_192000,
538 .formats = TAS2557_FORMATS,
539 },
540 .ops = &tas2557_dai_ops,
541 .symmetric_rates = 1,
542 },
543 {
544 .name = "tas2557 ASIM",
545 .id = 2,
546 .playback = {
547 .stream_name = "ASIM Playback",
548 .channels_min = 2,
549 .channels_max = 2,
550 .rates = SNDRV_PCM_RATE_8000_192000,
551 .formats = TAS2557_FORMATS,
552 },
553 .ops = &tas2557_dai_ops,
554 .symmetric_rates = 1,
555 },
556 };
558 int tas2557_register_codec(struct tas2557_priv *pTAS2557)
559 {
560 int nResult = 0;
562 dev_info(pTAS2557->dev, "%s, enter\n", __func__);
563 nResult = snd_soc_register_codec(pTAS2557->dev,
564 &soc_codec_driver_tas2557,
565 tas2557_dai_driver, ARRAY_SIZE(tas2557_dai_driver));
566 return nResult;
567 }
569 int tas2557_deregister_codec(struct tas2557_priv *pTAS2557)
570 {
571 snd_soc_unregister_codec(pTAS2557->dev);
572 return 0;
573 }
575 MODULE_AUTHOR("Texas Instruments Inc.");
576 MODULE_DESCRIPTION("TAS2557 ALSA SOC Smart Amplifier driver");
577 MODULE_LICENSE("GPL v2");
578 #endif