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 ** You should have received a copy of the GNU General Public License along with
14 ** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 ** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 **
17 ** File:
18 ** tas2555-codec.c
19 **
20 ** Description:
21 ** ALSA SoC driver for Texas Instruments TAS2555 High Performance 4W Smart Amplifier
22 **
23 ** =============================================================================
24 */
26 #ifdef CONFIG_TAS2555_CODEC_STEREO
28 #define DEBUG
29 #include <linux/module.h>
30 #include <linux/moduleparam.h>
31 #include <linux/init.h>
32 #include <linux/delay.h>
33 #include <linux/pm.h>
34 #include <linux/i2c.h>
35 #include <linux/gpio.h>
36 #include <linux/regulator/consumer.h>
37 #include <linux/firmware.h>
38 #include <linux/regmap.h>
39 #include <linux/of.h>
40 #include <linux/of_gpio.h>
41 #include <linux/slab.h>
42 #include <linux/syscalls.h>
43 #include <linux/fcntl.h>
44 #include <asm/uaccess.h>
45 #include <sound/core.h>
46 #include <sound/pcm.h>
47 #include <sound/pcm_params.h>
48 #include <sound/soc.h>
49 #include <sound/initval.h>
50 #include <sound/tlv.h>
52 #include "tas2555-core.h"
53 #include "tas2555-codec.h"
55 #define KCONTROL_CODEC
57 static unsigned int tas2555_codec_read(struct snd_soc_codec *pCodec,
58 unsigned int nRegister)
59 {
60 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
61 int ret = 0;
62 unsigned int Value = 0;
64 ret = pTAS2555->read(pTAS2555,
65 pTAS2555->mnCurrentChannel, nRegister, &Value);
67 if (ret < 0) {
68 dev_err(pTAS2555->dev, "%s, %d, ERROR happen=%d\n", __FUNCTION__,
69 __LINE__, ret);
70 return 0;
71 } else
72 return Value;
73 }
75 static int tas2555_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegister,
76 unsigned int nValue)
77 {
78 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
79 int ret = 0;
81 ret = pTAS2555->write(pTAS2555,
82 pTAS2555->mnCurrentChannel, nRegister, nValue);
84 return ret;
85 }
87 static const struct snd_soc_dapm_widget tas2555_dapm_widgets[] = {
88 SND_SOC_DAPM_AIF_IN("Stereo ASI1", "Stereo ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
89 SND_SOC_DAPM_AIF_IN("Stereo ASI2", "Stereo ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
90 SND_SOC_DAPM_AIF_IN("Stereo ASIM", "Stereo ASIM Playback", 0, SND_SOC_NOPM, 0, 0),
91 SND_SOC_DAPM_DAC("Stereo DAC", NULL, SND_SOC_NOPM, 0, 0),
93 SND_SOC_DAPM_OUT_DRV("Stereo ClassD", SND_SOC_NOPM, 0, 0, NULL, 0),
95 SND_SOC_DAPM_SUPPLY("Stereo PLL", SND_SOC_NOPM, 0, 0, NULL, 0),
96 SND_SOC_DAPM_SUPPLY("Stereo NDivider", SND_SOC_NOPM, 0, 0, NULL, 0),
98 SND_SOC_DAPM_OUTPUT("Stereo OUT")
99 };
101 static const struct snd_soc_dapm_route tas2555_audio_map[] = {
102 {"Stereo DAC", NULL, "Stereo ASI1"},
103 {"Stereo DAC", NULL, "Stereo ASI2"},
104 {"Stereo DAC", NULL, "Stereo ASIM"},
105 {"Stereo ClassD", NULL, "Stereo DAC"},
106 {"Stereo OUT", NULL, "Stereo ClassD"},
107 {"Stereo DAC", NULL, "Stereo PLL"},
108 {"Stereo DAC", NULL, "Stereo NDivider"},
109 };
111 static int tas2555_startup(struct snd_pcm_substream *substream,
112 struct snd_soc_dai *dai)
113 {
114 struct snd_soc_codec *codec = dai->codec;
115 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
117 dev_dbg(pTAS2555->dev, "%s\n", __func__);
119 return 0;
120 }
122 static void tas2555_shutdown(struct snd_pcm_substream *substream,
123 struct snd_soc_dai *dai)
124 {
125 struct snd_soc_codec *codec = dai->codec;
126 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
128 dev_dbg(pTAS2555->dev, "%s\n", __func__);
129 }
131 static int tas2555_mute(struct snd_soc_dai *dai, int mute)
132 {
133 struct snd_soc_codec *codec = dai->codec;
134 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
136 dev_dbg(pTAS2555->dev, "%s\n", __func__);
138 tas2555_enable(pTAS2555, !mute);
140 return 0;
141 }
143 static int tas2555_set_dai_sysclk(struct snd_soc_dai *pDAI,
144 int nClkID, unsigned int nFreqency, int nDir)
145 {
146 struct snd_soc_codec *pCodec = pDAI->codec;
147 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
149 dev_dbg(pTAS2555->dev, "tas2555_set_dai_sysclk: freq = %u\n", nFreqency);
151 return 0;
152 }
154 static int tas2555_hw_params(struct snd_pcm_substream *pSubstream,
155 struct snd_pcm_hw_params *pParams, struct snd_soc_dai *pDAI)
156 {
157 struct snd_soc_codec *pCodec = pDAI->codec;
158 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
160 dev_dbg(pTAS2555->dev, "%s\n", __func__);
162 tas2555_set_bit_rate(pTAS2555, channel_both,
163 snd_pcm_format_width(params_format(pParams)));
164 tas2555_set_sampling_rate(pTAS2555, params_rate(pParams));
166 return 0;
167 }
169 static int tas2555_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat)
170 {
171 struct snd_soc_codec *codec = pDAI->codec;
172 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
174 dev_dbg(pTAS2555->dev, "%s\n", __func__);
176 return 0;
177 }
179 static int tas2555_prepare(struct snd_pcm_substream *pSubstream,
180 struct snd_soc_dai *pDAI)
181 {
182 struct snd_soc_codec *codec = pDAI->codec;
183 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
185 dev_dbg(pTAS2555->dev, "%s\n", __func__);
187 return 0;
188 }
190 static int tas2555_set_bias_level(struct snd_soc_codec *pCodec,
191 enum snd_soc_bias_level eLevel)
192 {
193 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
195 dev_dbg(pTAS2555->dev, "%s: %d\n", __func__, eLevel);
197 return 0;
198 }
200 static int tas2555_codec_probe(struct snd_soc_codec *pCodec)
201 {
202 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(pCodec);
204 dev_dbg(pTAS2555->dev, "%s\n", __func__);
206 return 0;
207 }
209 static int tas2555_codec_remove(struct snd_soc_codec *pCodec)
210 {
211 return 0;
212 }
214 static int tas2555_power_ctrl_get(struct snd_kcontrol *pKcontrol,
215 struct snd_ctl_elem_value *pValue)
216 {
217 #ifdef KCONTROL_CODEC
218 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
219 #else
220 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
221 #endif
222 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
224 pValue->value.integer.value[0] = pTAS2555->mbPowerUp;
225 dev_dbg(pTAS2555->dev, "tas2555_power_ctrl_get = %d\n",
226 pTAS2555->mbPowerUp);
228 return 0;
229 }
231 static int tas2555_power_ctrl_put(struct snd_kcontrol *pKcontrol,
232 struct snd_ctl_elem_value *pValue)
233 {
234 #ifdef KCONTROL_CODEC
235 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
236 #else
237 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
238 #endif
239 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
241 pTAS2555->mbPowerUp = pValue->value.integer.value[0];
243 dev_dbg(pTAS2555->dev, "tas2555_power_ctrl_put = %d\n",
244 pTAS2555->mbPowerUp);
246 if (pTAS2555->mbPowerUp == 1)
247 tas2555_enable(pTAS2555, true);
248 if (pTAS2555->mbPowerUp == 0)
249 tas2555_enable(pTAS2555, false);
251 return 0;
252 }
254 static int tas2555_fs_get(struct snd_kcontrol *pKcontrol,
255 struct snd_ctl_elem_value *pValue)
256 {
257 #ifdef KCONTROL_CODEC
258 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
259 #else
260 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
261 #endif
262 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
264 int nFS = 48000;
266 if (pTAS2555->mpFirmware->mnConfigurations)
267 nFS = pTAS2555->mpFirmware->mpConfigurations[pTAS2555->mnCurrentConfiguration].mnSamplingRate;
269 pValue->value.integer.value[0] = nFS;
271 dev_dbg(pTAS2555->dev, "tas2555_fs_get = %d\n", nFS);
272 return 0;
273 }
275 static int tas2555_fs_put(struct snd_kcontrol *pKcontrol,
276 struct snd_ctl_elem_value *pValue)
277 {
278 #ifdef KCONTROL_CODEC
279 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
280 #else
281 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
282 #endif
283 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
284 int ret = 0;
285 int nFS = pValue->value.integer.value[0];
287 dev_info(pTAS2555->dev, "tas2555_fs_put = %d\n", nFS);
289 ret = tas2555_set_sampling_rate(pTAS2555, nFS);
291 return ret;
292 }
294 static int tas2555_program_get(struct snd_kcontrol *pKcontrol,
295 struct snd_ctl_elem_value *pValue)
296 {
297 #ifdef KCONTROL_CODEC
298 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
299 #else
300 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
301 #endif
302 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
304 pValue->value.integer.value[0] = pTAS2555->mnCurrentProgram;
305 dev_dbg(pTAS2555->dev, "tas2555_program_get = %d\n",
306 pTAS2555->mnCurrentProgram);
308 return 0;
309 }
311 static int tas2555_program_put(struct snd_kcontrol *pKcontrol,
312 struct snd_ctl_elem_value *pValue)
313 {
314 #ifdef KCONTROL_CODEC
315 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
316 #else
317 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
318 #endif
319 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
320 unsigned int nProgram = pValue->value.integer.value[0];
321 int ret = 0;
323 ret = tas2555_set_program(pTAS2555, nProgram);
325 return ret;
326 }
328 static int tas2555_configuration_get(struct snd_kcontrol *pKcontrol,
329 struct snd_ctl_elem_value *pValue)
330 {
331 #ifdef KCONTROL_CODEC
332 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
333 #else
334 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
335 #endif
336 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
338 pValue->value.integer.value[0] = pTAS2555->mnCurrentConfiguration;
339 dev_dbg(pTAS2555->dev, "tas2555_configuration_get = %d\n",
340 pTAS2555->mnCurrentConfiguration);
342 return 0;
343 }
345 static int tas2555_configuration_put(struct snd_kcontrol *pKcontrol,
346 struct snd_ctl_elem_value *pValue)
347 {
348 #ifdef KCONTROL_CODEC
349 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
350 #else
351 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
352 #endif
353 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
354 unsigned int nConfiguration = pValue->value.integer.value[0];
355 int ret = 0;
357 ret = tas2555_set_config(pTAS2555, nConfiguration);
359 return ret;
360 }
362 static int tas2555_calibration_get(struct snd_kcontrol *pKcontrol,
363 struct snd_ctl_elem_value *pValue)
364 {
365 #ifdef KCONTROL_CODEC
366 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
367 #else
368 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
369 #endif
370 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
372 pValue->value.integer.value[0] = pTAS2555->mnCurrentCalibration;
373 dev_info(pTAS2555->dev,
374 "tas2555_calibration_get = %d\n",
375 pTAS2555->mnCurrentCalibration);
377 return 0;
378 }
380 static int tas2555_calibration_put(struct snd_kcontrol *pKcontrol,
381 struct snd_ctl_elem_value *pValue)
382 {
383 #ifdef KCONTROL_CODEC
384 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
385 #else
386 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
387 #endif
388 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
389 unsigned int nCalibration = pValue->value.integer.value[0];
390 int ret = 0;
392 ret = tas2555_set_calibration(pTAS2555, nCalibration);
394 return ret;
395 }
397 static int tas2555_ldac_gain_get(struct snd_kcontrol *pKcontrol,
398 struct snd_ctl_elem_value *pValue)
399 {
400 #ifdef KCONTROL_CODEC
401 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
402 #else
403 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
404 #endif
405 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
406 unsigned char nGain = 0;
407 int ret = -1;
409 ret = tas2555_get_DAC_gain(pTAS2555, channel_left, &nGain);
410 if(ret >= 0){
411 pValue->value.integer.value[0] = nGain;
412 }
414 dev_dbg(pTAS2555->dev, "%s, ret = %d, %d\n", __func__, ret, nGain);
416 return ret;
417 }
419 static int tas2555_ldac_gain_put(struct snd_kcontrol *pKcontrol,
420 struct snd_ctl_elem_value *pValue)
421 {
422 #ifdef KCONTROL_CODEC
423 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
424 #else
425 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
426 #endif
427 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
428 unsigned int nGain = pValue->value.integer.value[0];
429 int ret = 0;
431 ret = tas2555_set_DAC_gain(pTAS2555, channel_left, nGain);
433 return ret;
434 }
436 static int tas2555_rdac_gain_get(struct snd_kcontrol *pKcontrol,
437 struct snd_ctl_elem_value *pValue)
438 {
439 #ifdef KCONTROL_CODEC
440 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
441 #else
442 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
443 #endif
444 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
445 unsigned char nGain = 0;
446 int ret = -1;
448 ret = tas2555_get_DAC_gain(pTAS2555, channel_right, &nGain);
449 if(ret >= 0){
450 pValue->value.integer.value[0] = nGain;
451 }
453 dev_dbg(pTAS2555->dev, "%s, ret = %d, %d\n", __func__, ret, nGain);
455 return ret;
456 }
458 static int tas2555_rdac_gain_put(struct snd_kcontrol *pKcontrol,
459 struct snd_ctl_elem_value *pValue)
460 {
461 #ifdef KCONTROL_CODEC
462 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol);
463 #else
464 struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol);
465 #endif
466 struct tas2555_priv *pTAS2555 = snd_soc_codec_get_drvdata(codec);
467 unsigned int nGain = pValue->value.integer.value[0];
468 int ret = 0;
470 ret = tas2555_set_DAC_gain(pTAS2555, channel_right, nGain);
472 return ret;
473 }
475 static const struct snd_kcontrol_new tas2555_snd_controls[] = {
476 SOC_SINGLE_EXT("Stereo LDAC Playback Volume", SND_SOC_NOPM, 0, 0x0f, 0,
477 tas2555_ldac_gain_get, tas2555_ldac_gain_put),
478 SOC_SINGLE_EXT("Stereo RDAC Playback Volume", SND_SOC_NOPM, 0, 0x0f, 0,
479 tas2555_rdac_gain_get, tas2555_rdac_gain_put),
480 SOC_SINGLE_EXT("Stereo PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
481 tas2555_power_ctrl_get, tas2555_power_ctrl_put),
482 SOC_SINGLE_EXT("Stereo Program", SND_SOC_NOPM, 0, 0x00FF, 0, tas2555_program_get,
483 tas2555_program_put),
484 SOC_SINGLE_EXT("Stereo Configuration", SND_SOC_NOPM, 0, 0x00FF, 0,
485 tas2555_configuration_get, tas2555_configuration_put),
486 SOC_SINGLE_EXT("Stereo FS", SND_SOC_NOPM, 8000, 48000, 0,
487 tas2555_fs_get, tas2555_fs_put),
488 SOC_SINGLE_EXT("Stereo Calibration", SND_SOC_NOPM, 0, 0x00FF, 0,
489 tas2555_calibration_get, tas2555_calibration_put),
490 };
492 static struct snd_soc_codec_driver soc_codec_driver_tas2555 = {
493 .probe = tas2555_codec_probe,
494 .remove = tas2555_codec_remove,
495 .read = tas2555_codec_read,
496 .write = tas2555_codec_write,
497 .set_bias_level = tas2555_set_bias_level,
498 .idle_bias_off = true,
499 //.ignore_pmdown_time = true,
500 .controls = tas2555_snd_controls,
501 .num_controls = ARRAY_SIZE(tas2555_snd_controls),
502 .dapm_widgets = tas2555_dapm_widgets,
503 .num_dapm_widgets = ARRAY_SIZE(tas2555_dapm_widgets),
504 .dapm_routes = tas2555_audio_map,
505 .num_dapm_routes = ARRAY_SIZE(tas2555_audio_map),
506 };
508 static struct snd_soc_dai_ops tas2555_dai_ops = {
509 .startup = tas2555_startup,
510 .shutdown = tas2555_shutdown,
511 .digital_mute = tas2555_mute,
512 .hw_params = tas2555_hw_params,
513 .prepare = tas2555_prepare,
514 .set_sysclk = tas2555_set_dai_sysclk,
515 .set_fmt = tas2555_set_dai_fmt,
516 };
518 #define TAS2555_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
519 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
520 static struct snd_soc_dai_driver tas2555_dai_driver[] = {
521 {
522 .name = "tas2555 Stereo ASI1",
523 .id = 0,
524 .playback = {
525 .stream_name = "Stereo ASI1 Playback",
526 .channels_min = 2,
527 .channels_max = 2,
528 .rates = SNDRV_PCM_RATE_8000_192000,
529 .formats = TAS2555_FORMATS,
530 },
531 .ops = &tas2555_dai_ops,
532 .symmetric_rates = 1,
533 },
534 {
535 .name = "tas2555 Stereo ASI2",
536 .id = 1,
537 .playback = {
538 .stream_name = "Stereo ASI2 Playback",
539 .channels_min = 2,
540 .channels_max = 2,
541 .rates = SNDRV_PCM_RATE_8000_192000,
542 .formats = TAS2555_FORMATS,
543 },
544 .ops = &tas2555_dai_ops,
545 .symmetric_rates = 1,
546 },
547 {
548 .name = "tas2555 Stereo ASIM",
549 .id = 2,
550 .playback = {
551 .stream_name = "Stereo ASIM Playback",
552 .channels_min = 2,
553 .channels_max = 2,
554 .rates = SNDRV_PCM_RATE_8000_192000,
555 .formats = TAS2555_FORMATS,
556 },
557 .ops = &tas2555_dai_ops,
558 .symmetric_rates = 1,
559 },
560 };
562 int tas2555_register_codec(struct tas2555_priv *pTAS2555)
563 {
564 int nResult = 0;
566 dev_info(pTAS2555->dev, "%s, enter\n", __FUNCTION__);
568 nResult = snd_soc_register_codec(pTAS2555->dev,
569 &soc_codec_driver_tas2555,
570 tas2555_dai_driver, ARRAY_SIZE(tas2555_dai_driver));
572 return nResult;
573 }
575 int tas2555_deregister_codec(struct tas2555_priv *pTAS2555)
576 {
577 snd_soc_unregister_codec(pTAS2555->dev);
579 return 0;
580 }
582 MODULE_AUTHOR("Texas Instruments Inc.");
583 MODULE_DESCRIPTION("TAS2555 ALSA SOC Smart Amplifier Stereo driver");
584 MODULE_LICENSE("GPLv2");
585 #endif