TAS2562 driver original release
[tas256xsw-android/tas2562-android-driver.git] / tas2562-codec.c
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 **     tas2562-codec.c
15 **
16 ** Description:
17 **     ALSA SoC driver for Texas Instruments TAS2562 High Performance 4W Smart
18 **     Amplifier
19 **
20 ** =============================================================================
21 */
23 #ifdef CONFIG_TAS2562_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 <sound/core.h>
39 #include <sound/pcm.h>
40 #include <sound/pcm_params.h>
41 #include <sound/soc.h>
42 #include <sound/initval.h>
43 #include <sound/tlv.h>
45 #include "tas2562.h"
48 #define TAS2562_MDELAY 0xFFFFFFFE
49 /* #define KCONTROL_CODEC */
50 static char const *iv_enable_text[] = {"Off", "On"};
51 static int tas2562iv_enable;
52 static const struct soc_enum tas2562_enum[] = {
53     SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(iv_enable_text), iv_enable_text),
54 };
56 static unsigned int tas2562_codec_read(struct snd_soc_codec *codec,
57                 unsigned int reg)
58 {
59         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
60         int nResult = 0;
61         unsigned int value = 0;
63         mutex_lock(&pTAS2562->dev_lock);
65         nResult = regmap_read(pTAS2562->regmap, reg, &value);
67         if (nResult < 0)
68                 dev_err(pTAS2562->dev, "%s, ERROR, reg=0x%x, E=%d\n",
69                         __func__, reg, nResult);
70         else
71                 dev_dbg(pTAS2562->dev, "%s, reg: 0x%x, value: 0x%x\n",
72                                 __func__, reg, value);
74         mutex_unlock(&pTAS2562->dev_lock);
76         if (nResult >= 0)
77                 return value;
78         else
79                 return nResult;
80 }
82 static int tas2562iv_put(struct snd_kcontrol *kcontrol,
83                                    struct snd_ctl_elem_value *ucontrol)
84 {
85     struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
87     if (codec == NULL) {
88                 pr_err("%s: codec is NULL \n",  __func__);
89                 return 0;
90     }
92     tas2562iv_enable = ucontrol->value.integer.value[0];
94         if (tas2562iv_enable) {
95                 pr_debug("%s: tas2562iv_enable \n", __func__);
96                 snd_soc_update_bits(codec, TAS2562_PowerControl,
97                         TAS2562_PowerControl_OperationalMode10_Mask |
98                     TAS2562_PowerControl_ISNSPower_Mask |
99                     TAS2562_PowerControl_VSNSPower_Mask,
100                     TAS2562_PowerControl_OperationalMode10_Active |
101                     TAS2562_PowerControl_VSNSPower_Active |
102                     TAS2562_PowerControl_ISNSPower_Active);
103         } else {
104                 pr_debug("%s: tas2562iv_disable \n", __func__);
105                 snd_soc_update_bits(codec, TAS2562_PowerControl,
106                         TAS2562_PowerControl_OperationalMode10_Mask |
107                         TAS2562_PowerControl_ISNSPower_Mask |
108                         TAS2562_PowerControl_VSNSPower_Mask,
109                         TAS2562_PowerControl_OperationalMode10_Active |
110                         TAS2562_PowerControl_VSNSPower_PoweredDown |
111                         TAS2562_PowerControl_ISNSPower_PoweredDown);
112         }
114         pr_debug("%s: tas2562iv_enable = %d\n", __func__, tas2562iv_enable);
116         return 0;
119 static int tas2562iv_get(struct snd_kcontrol *kcontrol,
120                                   struct snd_ctl_elem_value *ucontrol)
122    int value;
123    ucontrol->value.integer.value[0] = tas2562iv_enable;
124    value=gpio_get_value(37);
125    pr_debug("%s: tas2562iv_enable = %d\n", __func__, tas2562iv_enable);
126    pr_debug("%s: gpio37 value = %d\n", __func__, value);
127    return 0;
129 static const struct snd_kcontrol_new tas2562_controls[] = {
130 SOC_ENUM_EXT("TAS2562 IVSENSE ENABLE", tas2562_enum[0],
131                     tas2562iv_get, tas2562iv_put),
132 };
134 static int tas2562_codec_write(struct snd_soc_codec *codec, unsigned int reg,
135         unsigned int value)
137         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
139         int nResult = 0;
141         mutex_lock(&pTAS2562->dev_lock);
143         nResult = regmap_write(pTAS2562->regmap, reg, value);
144         if (nResult < 0)
145                 dev_err(pTAS2562->dev, "%s, ERROR, reg=0x%x, E=%d\n",
146                         __func__, reg, nResult);
147         else
148                 dev_dbg(pTAS2562->dev, "%s, reg: 0x%x, 0x%x\n",
149                         __func__, reg, value);
151         mutex_unlock(&pTAS2562->dev_lock);
153         return nResult;
158 static int tas2562_codec_suspend(struct snd_soc_codec *codec)
160         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
161         int ret = 0;
163         mutex_lock(&pTAS2562->codec_lock);
165         dev_dbg(pTAS2562->dev, "%s\n", __func__);
166         pTAS2562->runtime_suspend(pTAS2562);
168         mutex_unlock(&pTAS2562->codec_lock);
169         return ret;
172 static int tas2562_codec_resume(struct snd_soc_codec *codec)
174         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
175         int ret = 0;
177         mutex_lock(&pTAS2562->codec_lock);
179         dev_dbg(pTAS2562->dev, "%s\n", __func__);
180         pTAS2562->runtime_resume(pTAS2562);
182         mutex_unlock(&pTAS2562->codec_lock);
183         return ret;
186 static const struct snd_kcontrol_new tas2562_asi_controls[] = {
187         SOC_DAPM_SINGLE("Left", TAS2562_TDMConfigurationReg2,
188                 4, 1, 0),
189         SOC_DAPM_SINGLE("Right", TAS2562_TDMConfigurationReg2,
190                 4, 2, 0),
191         SOC_DAPM_SINGLE("LeftRightDiv2", TAS2562_TDMConfigurationReg2,
192                 4, 3, 0),
193 };
196 static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
197                         struct snd_kcontrol *kcontrol, int event)
199         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
201         switch (event) {
202         case SND_SOC_DAPM_POST_PMU:
203                 snd_soc_update_bits(codec, TAS2562_PowerControl,
204                         TAS2562_PowerControl_OperationalMode10_Mask |
205                         TAS2562_PowerControl_ISNSPower_Mask |
206                         TAS2562_PowerControl_VSNSPower_Mask,
207                         TAS2562_PowerControl_OperationalMode10_Active |
208                         TAS2562_PowerControl_VSNSPower_Active |
209                         TAS2562_PowerControl_ISNSPower_Active);
210                 break;
211         case SND_SOC_DAPM_PRE_PMD:
212                 snd_soc_update_bits(codec, TAS2562_PowerControl,
213                         TAS2562_PowerControl_OperationalMode10_Mask,
214                         TAS2562_PowerControl_OperationalMode10_Shutdown);
215                 break;
217         }
218         return 0;
222 static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = {
223         SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
224         SND_SOC_DAPM_AIF_OUT("Voltage Sense", "ASI1 Capture",  1, TAS2562_PowerControl, 2, 1),
225         SND_SOC_DAPM_AIF_OUT("Current Sense", "ASI1 Capture",  0, TAS2562_PowerControl, 3, 1),
226         SND_SOC_DAPM_MIXER("ASI1 Sel",
227                 TAS2562_TDMConfigurationReg2, 4, 0,
228                 &tas2562_asi_controls[0],
229                 ARRAY_SIZE(tas2562_asi_controls)),
230         SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event,
231         SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
232         SND_SOC_DAPM_OUTPUT("OUT"),
233         SND_SOC_DAPM_SIGGEN("VMON"),
234         SND_SOC_DAPM_SIGGEN("IMON")
235 };
237 static const struct snd_soc_dapm_route tas2562_audio_map[] = {
238         {"ASI1 Sel", "Left", "ASI1"},
239         {"ASI1 Sel", "Right", "ASI1"},
240         {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
241         {"DAC", NULL, "ASI1 Sel"},
242         {"OUT", NULL, "DAC"},
243         /*{"VMON", NULL, "Voltage Sense"},
244         {"IMON", NULL, "Current Sense"},*/
245         {"Voltage Sense", NULL, "VMON"},
246         {"Current Sense", NULL, "IMON"},
247 };
250 static int tas2562_mute(struct snd_soc_dai *dai, int mute)
252         struct snd_soc_codec *codec = dai->codec;
253         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
255         mutex_lock(&pTAS2562->codec_lock);
256         if (mute) {
257                 snd_soc_update_bits(codec, TAS2562_PowerControl,
258                         TAS2562_PowerControl_OperationalMode10_Mask,
259                         TAS2562_PowerControl_OperationalMode10_Mute);
260         } else {
261                 snd_soc_update_bits(codec, TAS2562_PowerControl,
262                         TAS2562_PowerControl_OperationalMode10_Mask,
263                         TAS2562_PowerControl_OperationalMode10_Active);
264         }
265         mutex_unlock(&pTAS2562->codec_lock);
266         return 0;
269 static int tas2562_slot_config(struct snd_soc_codec *codec, struct tas2562_priv *pTAS2562, int blr_clk_ratio)
271         int ret = 0;
272                 snd_soc_update_bits(codec,
273                         TAS2562_TDMConfigurationReg5, 0xff, 0x42);
275                 snd_soc_update_bits(codec,
276                         TAS2562_TDMConfigurationReg6, 0xff, 0x40);
278         return ret;
281 //Added/Mofified 060356-PP
282 //To avoid implicit decleration 
284 static int tas2562_set_slot(struct snd_soc_codec *codec, int slot_width)
286         int ret = 0;
287         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
289         switch (slot_width) {
290         case 16:
291         ret = snd_soc_update_bits(codec,
292                 TAS2562_TDMConfigurationReg2,
293                 TAS2562_TDMConfigurationReg2_RXSLEN10_Mask,
294                 TAS2562_TDMConfigurationReg2_RXSLEN10_16Bits);
295         break;
297         case 24:
298         ret = snd_soc_update_bits(codec,
299                 TAS2562_TDMConfigurationReg2,
300                 TAS2562_TDMConfigurationReg2_RXSLEN10_Mask,
301                 TAS2562_TDMConfigurationReg2_RXSLEN10_24Bits);
302         break;
304         case 32:
305         ret = snd_soc_update_bits(codec,
306                 TAS2562_TDMConfigurationReg2,
307                 TAS2562_TDMConfigurationReg2_RXSLEN10_Mask,
308                 TAS2562_TDMConfigurationReg2_RXSLEN10_32Bits);
309         break;
311         case 0:
312         /* Do not change slot width */
313         break;
315         default:
316                 dev_dbg(pTAS2562->dev, "slot width not supported");
317                 ret = -EINVAL;
318         }
320         if (ret >= 0)
321                 pTAS2562->mnSlot_width = slot_width;
323         return ret;
326 static int tas2562_hw_params(struct snd_pcm_substream *substream,
327                 struct snd_pcm_hw_params *params,
328                 struct snd_soc_dai *dai)
330         struct snd_soc_codec *codec = dai->codec;
331         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
332         int blr_clk_ratio;
333         int ret = 0;
334         int slot_width_tmp = 16;
336         dev_dbg(pTAS2562->dev, "%s, format: %d\n", __func__,
337                 params_format(params));
339         switch (params_format(params)) {
340         case SNDRV_PCM_FORMAT_S16_LE:
341                 snd_soc_update_bits(codec,
342                         TAS2562_TDMConfigurationReg2,
343                         TAS2562_TDMConfigurationReg2_RXWLEN32_Mask,
344                         TAS2562_TDMConfigurationReg2_RXWLEN32_16Bits);
345                         pTAS2562->ch_size = 16;
346                         if (pTAS2562->mnSlot_width == 0)
347                                 slot_width_tmp = 16;
348                 break;
349         case SNDRV_PCM_FMTBIT_S24_LE:
350                         snd_soc_update_bits(codec,
351                         TAS2562_TDMConfigurationReg2,
352                         TAS2562_TDMConfigurationReg2_RXWLEN32_Mask,
353                         TAS2562_TDMConfigurationReg2_RXWLEN32_24Bits);
354                         pTAS2562->ch_size = 24;
355                         if (pTAS2562->mnSlot_width == 0)
356                                 slot_width_tmp = 32;
357                 break;
358         case SNDRV_PCM_FMTBIT_S32_LE:
359                         snd_soc_update_bits(codec,
360                         TAS2562_TDMConfigurationReg2,
361                         TAS2562_TDMConfigurationReg2_RXWLEN32_Mask,
362                         TAS2562_TDMConfigurationReg2_RXWLEN32_32Bits);
363                         pTAS2562->ch_size = 32;
364                         if (pTAS2562->mnSlot_width == 0)
365                                 slot_width_tmp = 32;
366                 break;
368         }
370         /* If machine driver did not call set slot width */
371         if (pTAS2562->mnSlot_width == 0)
372                 tas2562_set_slot(codec, slot_width_tmp);
374         blr_clk_ratio = params_channels(params) * pTAS2562->ch_size;
375         dev_dbg(pTAS2562->dev, "blr_clk_ratio: %d\n", blr_clk_ratio);
376         tas2562_slot_config(codec, pTAS2562, blr_clk_ratio);
378         dev_dbg(pTAS2562->dev, "%s, sample rate: %d\n", __func__,
379                 params_rate(params));
380         switch (params_rate(params)) {
381         case 48000:
382                         snd_soc_update_bits(codec,
383                                 TAS2562_TDMConfigurationReg0,
384                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
385                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
386                         snd_soc_update_bits(codec,
387                                 TAS2562_TDMConfigurationReg0,
388                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
389                         TAS2562_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
390                         break;
391         case 44100:
392                         snd_soc_update_bits(codec,
393                                 TAS2562_TDMConfigurationReg0,
394                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
395                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
396                         snd_soc_update_bits(codec,
397                                 TAS2562_TDMConfigurationReg0,
398                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
399                         TAS2562_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
400                         break;
401         case 96000:
402                         snd_soc_update_bits(codec,
403                                 TAS2562_TDMConfigurationReg0,
404                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
405                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
406                         snd_soc_update_bits(codec,
407                                 TAS2562_TDMConfigurationReg0,
408                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
409                         TAS2562_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
410                         break;
411         case 88200:
412                         snd_soc_update_bits(codec,
413                                 TAS2562_TDMConfigurationReg0,
414                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
415                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
416                         snd_soc_update_bits(codec,
417                                 TAS2562_TDMConfigurationReg0,
418                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
419                         TAS2562_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
420                         break;
421         case 19200:
422                         snd_soc_update_bits(codec,
423                                 TAS2562_TDMConfigurationReg0,
424                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
425                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
426                         snd_soc_update_bits(codec,
427                                 TAS2562_TDMConfigurationReg0,
428                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
429                         TAS2562_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
430                         break;
431         case 17640:
432                         snd_soc_update_bits(codec,
433                                 TAS2562_TDMConfigurationReg0,
434                                 TAS2562_TDMConfigurationReg0_SAMPRATERAMP_Mask,
435                         TAS2562_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
436                         snd_soc_update_bits(codec,
437                                 TAS2562_TDMConfigurationReg0,
438                                 TAS2562_TDMConfigurationReg0_SAMPRATE31_Mask,
439                         TAS2562_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
440                         break;
441         default:
442         dev_dbg(pTAS2562->dev, "%s, unsupported sample rate\n", __func__);
444         }
445         return ret;
448 static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
450         u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
451         struct snd_soc_codec *codec = dai->codec;
452         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
453         int ret = 0;
455         dev_dbg(pTAS2562->dev, "%s, format=0x%x\n", __func__, fmt);
457         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
458         case SND_SOC_DAIFMT_CBS_CFS:
459                 asi_cfg_1 = 0x00;
460                 break;
461         default:
462                 dev_err(pTAS2562->dev, "ASI format master is not found\n");
463                 ret = -EINVAL;
464         }
466         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
467         case SND_SOC_DAIFMT_NB_NF:
468                 dev_dbg(pTAS2562->dev, "INV format: NBNF\n");
469                 asi_cfg_1 |= TAS2562_TDMConfigurationReg1_RXEDGE_Rising;
470                 break;
471         case SND_SOC_DAIFMT_IB_NF:
472                 dev_dbg(pTAS2562->dev, "INV format: IBNF\n");
473                 asi_cfg_1 |= TAS2562_TDMConfigurationReg1_RXEDGE_Falling;
474                 break;
475         default:
476                 dev_err(pTAS2562->dev, "ASI format Inverse is not found\n");
477                 ret = -EINVAL;
478         }
480         snd_soc_update_bits(codec, TAS2562_TDMConfigurationReg1,
481                 TAS2562_TDMConfigurationReg1_RXEDGE_Mask,
482                 asi_cfg_1);
484         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
485         case (SND_SOC_DAIFMT_I2S):
486                 tdm_rx_start_slot = 1;
487                 break;
488         case (SND_SOC_DAIFMT_DSP_A):
489         case (SND_SOC_DAIFMT_DSP_B):
490                 tdm_rx_start_slot = 1;
491                 break;
492         case (SND_SOC_DAIFMT_LEFT_J):
493                 tdm_rx_start_slot = 0;
494                 break;
495         default:
496         dev_err(pTAS2562->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
497         ret = -EINVAL;
498                 break;
499         }
501         snd_soc_update_bits(codec, TAS2562_TDMConfigurationReg1,
502                 TAS2562_TDMConfigurationReg1_RXOFFSET51_Mask,
503         (tdm_rx_start_slot << TAS2562_TDMConfigurationReg1_RXOFFSET51_Shift));
504         return ret;
507 static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai,
508                 unsigned int tx_mask, unsigned int rx_mask,
509                 int slots, int slot_width)
511         int ret = 0;
512         struct snd_soc_codec *codec = dai->codec;
513         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
515         dev_dbg(pTAS2562->dev, "%s, tx_mask:%d, rx_mask:%d, slots:%d, slot_width:%d",
516                         __func__, tx_mask, rx_mask, slots, slot_width);
518         ret = tas2562_set_slot(codec, slot_width);
520         return ret;
523 static struct snd_soc_dai_ops tas2562_dai_ops = {
524         .digital_mute = tas2562_mute,
525         .hw_params  = tas2562_hw_params,
526         .set_fmt    = tas2562_set_dai_fmt,
527         .set_tdm_slot = tas2562_set_dai_tdm_slot,
528 };
530 #define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
531                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
533 #define TAS2562_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 \
534                                                 SNDRV_PCM_RATE_88200 |\
535                                                 SNDRV_PCM_RATE_96000 |\
536                                                 SNDRV_PCM_RATE_176400 |\
537                                                 SNDRV_PCM_RATE_192000\
538                                                 )
540 static struct snd_soc_dai_driver tas2562_dai_driver[] = {
541         {
542                 .name = "tas2562 ASI1",
543                 .id = 0,
544                 .playback = {
545                         .stream_name    = "ASI1 Playback",
546                         .channels_min   = 2,
547                         .channels_max   = 2,
548                         .rates      = SNDRV_PCM_RATE_8000_192000,
549                         .formats    = TAS2562_FORMATS,
550                 },
551                 .capture = {
552                         .stream_name    = "ASI1 Capture",
553                         .channels_min   = 0,
554                         .channels_max   = 2,
555                         .rates          = SNDRV_PCM_RATE_8000_192000,
556                         .formats    = TAS2562_FORMATS,
557                 },
558                 .ops = &tas2562_dai_ops,
559                 .symmetric_rates = 1,
560         },
561 };
563 static int tas2562_codec_probe(struct snd_soc_codec *codec)
565         int ret;
566         struct tas2562_priv *pTAS2562 = snd_soc_codec_get_drvdata(codec);
568         ret = snd_soc_add_codec_controls(codec, tas2562_controls,
569                                          ARRAY_SIZE(tas2562_controls));
570         if (ret < 0) {
571                 pr_err("%s: add_codec_controls failed, err %d\n",
572                         __func__, ret);
573                 return ret;
574         }
577         dev_err(pTAS2562->dev, "%s\n", __func__);
579         return 0;
582 static int tas2562_codec_remove(struct snd_soc_codec *codec)
584         return 0;
587 /*static DECLARE_TLV_DB_SCALE(dac_tlv, 0, 100, 0);*/
588 static DECLARE_TLV_DB_SCALE(tas2562_digital_tlv, 1100, 50, 0);
589 static DECLARE_TLV_DB_SCALE(tas2562_playback_volume, -12750, 50, 0);
591 static const struct snd_kcontrol_new tas2562_snd_controls[] = {
592         SOC_SINGLE_TLV("Amp Output Level", TAS2562_PlaybackConfigurationReg0,
593                 0, 0x16, 0,
594                 tas2562_digital_tlv),
595         SOC_SINGLE_TLV("Playback Volume", TAS2562_PlaybackConfigurationReg2,
596                 0, TAS2562_PlaybackConfigurationReg2_DVCPCM70_Mask, 1,
597                 tas2562_playback_volume),
598 };
600 static struct snd_soc_codec_driver soc_codec_driver_tas2562 = {
601         .probe                  = tas2562_codec_probe,
602         .remove                 = tas2562_codec_remove,
603         .read                   = tas2562_codec_read,
604         .write                  = tas2562_codec_write,
605         .suspend                = tas2562_codec_suspend,
606         .resume                 = tas2562_codec_resume,
607         .component_driver = {
608         .controls               = tas2562_snd_controls,
609         .num_controls           = ARRAY_SIZE(tas2562_snd_controls),
610                 .dapm_widgets           = tas2562_dapm_widgets,
611                 .num_dapm_widgets       = ARRAY_SIZE(tas2562_dapm_widgets),
612                 .dapm_routes            = tas2562_audio_map,
613                 .num_dapm_routes        = ARRAY_SIZE(tas2562_audio_map),
614         },
615 };
617 int tas2562_register_codec(struct tas2562_priv *pTAS2562)
619         int nResult = 0;
621         dev_info(pTAS2562->dev, "%s, enter\n", __func__);
622         nResult = snd_soc_register_codec(pTAS2562->dev,
623                 &soc_codec_driver_tas2562,
624                 tas2562_dai_driver, ARRAY_SIZE(tas2562_dai_driver));
625         return nResult;
628 int tas2562_deregister_codec(struct tas2562_priv *pTAS2562)
630         snd_soc_unregister_codec(pTAS2562->dev);
632         return 0;
635 MODULE_AUTHOR("Texas Instruments Inc.");
636 MODULE_DESCRIPTION("TAS2562 ALSA SOC Smart Amplifier driver");
637 MODULE_LICENSE("GPL v2");
638 #endif /* CONFIG_TAS2562_CODEC */