]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2770sw-android/tas2770sw-android.git/blob - tas2770-codec.c
5ba3efe1e58909a7e4642593a530c3724d29a49b
[tas2770sw-android/tas2770sw-android.git] / tas2770-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 **     tas2770-codec.c
15 **
16 ** Description:
17 **     ALSA SoC driver for Texas Instruments TAS2770 High Performance 4W Smart Amplifier
18 **
19 ** =============================================================================
20 */
22 #ifdef CONFIG_TAS2770_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 "tas2770.h"
48 #define TAS2770_MDELAY 0xFFFFFFFE
49 //#define KCONTROL_CODEC
51 #define DAPM_TO_CODEC
52 static unsigned int tas2770_codec_read(struct snd_soc_codec *codec,  unsigned int reg)
53 {
54         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
55         int nResult = 0;
56         unsigned int value = 0;
58         mutex_lock(&pTAS2770->dev_lock);
60         nResult = regmap_read(pTAS2770->regmap, reg, &value);
62         if (nResult < 0)
63                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
64                         __func__, reg, nResult);
65         else
66                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, value: 0x%x\n", __func__, reg, value);
68         mutex_unlock(&pTAS2770->dev_lock);
69         if(nResult >= 0)
70                 return value;
71         else
72                 return nResult;
73 }
76 static int tas2770_codec_write(struct snd_soc_codec *codec, unsigned int reg,
77         unsigned int value)
78 {
79         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
81         int nResult = 0;
83         mutex_lock(&pTAS2770->dev_lock);
85         nResult = regmap_write(pTAS2770->regmap, reg, value);
86         if(nResult < 0)
87                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
88                         __func__, reg, nResult);
89         else
90                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, 0x%x\n", __func__, reg, value);
92         mutex_unlock(&pTAS2770->dev_lock);
94         return nResult;
96 }
99 static int tas2770_codec_suspend(struct snd_soc_codec *codec)
101         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
102         int ret = 0;
104         mutex_lock(&pTAS2770->codec_lock);
106         dev_dbg(pTAS2770->dev, "%s\n", __func__);
107 //      pTAS2770->runtime_suspend(pTAS2770);
109         mutex_unlock(&pTAS2770->codec_lock);
110         return ret;
113 static int tas2770_codec_resume(struct snd_soc_codec *codec)
115         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
116         int ret = 0;
118         mutex_lock(&pTAS2770->codec_lock);
120         dev_dbg(pTAS2770->dev, "%s\n", __func__);
121 //      pTAS2770->runtime_resume(pTAS2770);
123         mutex_unlock(&pTAS2770->codec_lock);
124         return ret;
127 static const struct snd_kcontrol_new tas2770_asi_controls[] = {
128         SOC_DAPM_SINGLE("Left", TAS2770_TDMConfigurationReg2,
129                 4, 1, 0),
130         SOC_DAPM_SINGLE("Right", TAS2770_TDMConfigurationReg2,
131                 4, 2, 0),
132         SOC_DAPM_SINGLE("LeftRightDiv2", TAS2770_TDMConfigurationReg2,
133                 4, 3, 0),
134 };
137 static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
138                         struct snd_kcontrol *kcontrol, int event) 
140 #ifdef DAPM_TO_CODEC
141         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
142 #else
143         struct snd_soc_codec *codec = w->codec;
144 #endif
145 //      struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
146         pr_err("%s",__func__);
147         switch (event) {
148         case SND_SOC_DAPM_POST_PMU:
149                 snd_soc_update_bits(codec, TAS2770_PowerControl,
150                         TAS2770_PowerControl_OperationalMode10_Mask,
151                         TAS2770_PowerControl_OperationalMode10_Active);
152                 break;
153         case SND_SOC_DAPM_PRE_PMD:
154                 snd_soc_update_bits(codec, TAS2770_PowerControl,
155                         TAS2770_PowerControl_OperationalMode10_Mask,
156                         TAS2770_PowerControl_OperationalMode10_Shutdown);
157                 break;
158         
159         }
160         return 0;
164 static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
165         SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
166         SND_SOC_DAPM_MIXER("ASI1 Sel",
167                 TAS2770_TDMConfigurationReg2, 4, 0,
168                 &tas2770_asi_controls[0],
169                 ARRAY_SIZE(tas2770_asi_controls)),
170         SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
171                 tas2770_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
172         SND_SOC_DAPM_OUTPUT("OUT")
174 };
176 static const struct snd_soc_dapm_route tas2770_audio_map[] = {
177         {"ASI1 Sel", "Left", "ASI1"},
178         {"ASI1 Sel", "Right", "ASI1"},
179         {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
180         {"DAC", NULL, "ASI1 Sel"},
181         {"OUT", NULL, "DAC"},
182 };
185 static int tas2770_mute(struct snd_soc_dai *dai, int mute)
187         struct snd_soc_codec *codec = dai->codec;
188         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
190         dev_err(pTAS2770->dev, "%s mute %d",__func__, mute); 
192         mutex_lock(&pTAS2770->codec_lock);
193         if(mute) {
194                 snd_soc_update_bits(codec, TAS2770_PowerControl,
195                         TAS2770_PowerControl_OperationalMode10_Mask,
196                         TAS2770_PowerControl_OperationalMode10_Mute); 
197         } else {
198                 snd_soc_update_bits(codec, TAS2770_PowerControl,
199                         TAS2770_PowerControl_OperationalMode10_Mask,
200                         TAS2770_PowerControl_OperationalMode10_Active); 
201         }
202         mutex_unlock(&pTAS2770->codec_lock);
203         return 0;
208 static int tas2770_hw_params(struct snd_pcm_substream *substream,
209                 struct snd_pcm_hw_params *params,
210                 struct snd_soc_dai *dai)
212         struct snd_soc_codec *codec = dai->codec;
213         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
214         int ret = 0;
215         dev_err(pTAS2770->dev, "%s",__func__);
216         dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__, params_format(params));
218         switch(params_format(params)) {
219         case SNDRV_PCM_FORMAT_S16_LE:
220                 snd_soc_update_bits(codec,
221                         TAS2770_TDMConfigurationReg2,
222                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
223                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
224                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits |
225                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits );
226                         pTAS2770->ch_size = 16;
227                 break;
228         case SNDRV_PCM_FORMAT_S24_LE:
229                         snd_soc_update_bits(codec,
230                         TAS2770_TDMConfigurationReg2,
231                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
232                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
233                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits  |
234                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits );
235                         pTAS2770->ch_size = 24;
236                 break;
237         case SNDRV_PCM_FORMAT_S32_LE:
238                         snd_soc_update_bits(codec,
239                         TAS2770_TDMConfigurationReg2,
240                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
241                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
242                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits |
243                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits );
244                         pTAS2770->ch_size = 32;
245                 break;
247         }
249         dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__, params_rate(params));
250         switch(params_rate(params))
251         {
252                 case 48000:
253                         snd_soc_update_bits(codec,
254                                 TAS2770_TDMConfigurationReg0,
255                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
256                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
257                         snd_soc_update_bits(codec,
258                                 TAS2770_TDMConfigurationReg0,
259                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
260                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
261                         break;
262                 case 44100:
263                         snd_soc_update_bits(codec,
264                                 TAS2770_TDMConfigurationReg0,
265                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
266                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
267                         snd_soc_update_bits(codec,
268                                 TAS2770_TDMConfigurationReg0,
269                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
270                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
271                         break;
272                 case 96000:
273                         snd_soc_update_bits(codec,
274                                 TAS2770_TDMConfigurationReg0,
275                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
276                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
277                         snd_soc_update_bits(codec,
278                                 TAS2770_TDMConfigurationReg0,
279                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
280                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
281                         break;
282                 case 88200:
283                         snd_soc_update_bits(codec,
284                                 TAS2770_TDMConfigurationReg0,
285                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
286                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
287                         snd_soc_update_bits(codec,
288                                 TAS2770_TDMConfigurationReg0,
289                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
290                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
291                         break;
292                 case 19200:
293                         snd_soc_update_bits(codec,
294                                 TAS2770_TDMConfigurationReg0,
295                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
296                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
297                         snd_soc_update_bits(codec,
298                                 TAS2770_TDMConfigurationReg0,
299                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
300                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
301                         break;
302                 case 17640:
303                         snd_soc_update_bits(codec,
304                                 TAS2770_TDMConfigurationReg0,
305                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
306                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
307                         snd_soc_update_bits(codec,
308                                 TAS2770_TDMConfigurationReg0,
309                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
310                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
311                         break;
312                 default:
313                         dev_dbg(pTAS2770->dev, "%s, unsupported sample rate\n", __func__);
314                         
315         }
316         return ret;
319 static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
321         u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
322         struct snd_soc_codec *codec = dai->codec;
323         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
324         int ret = 0;
326         dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
328 #if 1
329         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
330         case SND_SOC_DAIFMT_CBS_CFS: 
331                 asi_cfg_1 = 0x00;
332                 break;
333         default:
334                 dev_err(pTAS2770->dev, "ASI format master is not found\n");
335                 ret = -EINVAL;
336         }
338         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
339         case SND_SOC_DAIFMT_NB_NF:
340                 dev_dbg(pTAS2770->dev, "INV format: NBNF\n");
341                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Rising;
342                 break;
343         case SND_SOC_DAIFMT_IB_NF:
344                 dev_dbg(pTAS2770->dev, "INV format: IBNF\n");
345                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Falling;
346                 break;
347         default:
348                 dev_err(pTAS2770->dev, "ASI format Inverse is not found\n");
349                 ret = -EINVAL;
350         }
352         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1, 
353                 TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
354                 asi_cfg_1);
356         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
357         case (SND_SOC_DAIFMT_I2S):
358                 tdm_rx_start_slot = 1;
359                 break;
360         case (SND_SOC_DAIFMT_DSP_A):
361         case (SND_SOC_DAIFMT_DSP_B):
362                 tdm_rx_start_slot = 1;
363                 break;
364         case (SND_SOC_DAIFMT_LEFT_J):
365                 tdm_rx_start_slot = 0;
366                 break;
367         default:
368                 dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
369                 ret = -EINVAL;
370                 break;
371         }
373         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1, 
374                 TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
375                 (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
376 #endif
377         return ret;
380 static struct snd_soc_dai_ops tas2770_dai_ops = {
381         .digital_mute = tas2770_mute,
382         .hw_params  = tas2770_hw_params,
383         .set_fmt    = tas2770_set_dai_fmt,
384 };
386 #define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
387                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
389 #define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 \
390                                                 SNDRV_PCM_RATE_88200 |\
391                                                 SNDRV_PCM_RATE_96000 |\
392                                                 SNDRV_PCM_RATE_176400 |\
393                                                 SNDRV_PCM_RATE_192000\
394                                                 )
396 static struct snd_soc_dai_driver tas2770_dai_driver[] = {
397         {
398                 .name = "tas2770 ASI1",
399                 .id = 0,
400                 .playback = {
401                         .stream_name    = "ASI1 Playback",
402                         .channels_min   = 2,
403                         .channels_max   = 2,
404                         .rates      = SNDRV_PCM_RATE_8000_192000,
405                         .formats    = TAS2770_FORMATS,
406                 },
407                 .capture = {
408                         .stream_name    = "ASI1 Capture",
409                         .channels_min   = 0,
410                         .channels_max   = 2,
411                         .rates          = SNDRV_PCM_RATE_8000_192000,
412                         .formats    = TAS2770_FORMATS,  
413                 },
414                 .ops = &tas2770_dai_ops,
415                 .symmetric_rates = 1,
416         },
417 };
419 static int tas2770_codec_probe(struct snd_soc_codec *codec)
421         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
423         dev_err(pTAS2770->dev, "%s\n", __func__);
425         return 0;
428 static int tas2770_codec_remove(struct snd_soc_codec *codec)
430         return 0;
433 #if 0
435 /*
436  * DAC digital volumes. From 0 to 31 dB in 1 dB steps
437  */
438 static DECLARE_TLV_DB_SCALE(dac_tlv, 0, 100, 0);
440 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
441         SOC_SINGLE_TLV("DAC Playback Volume", TAS2770_PlaybackConfigurationReg0, 0, 0x1f, 0,
442                         dac_tlv),
443 //      SOC_SINGLE_EXT("TAS2770 PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0,
444 //                      tas2770_power_ctrl_get, tas2770_power_ctrl_put),
445 };
446 #endif
448 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
449         .probe                  = tas2770_codec_probe,
450         .remove                 = tas2770_codec_remove,
451         .read                   = tas2770_codec_read,
452         .write                  = tas2770_codec_write,
453         .suspend                = tas2770_codec_suspend,
454         .resume                 = tas2770_codec_resume,
455         .component_driver = {
456 //              .controls               = tas2770_snd_controls,
457 //              .num_controls           = ARRAY_SIZE(tas2770_snd_controls),
458                 .dapm_widgets           = tas2770_dapm_widgets,
459                 .num_dapm_widgets       = ARRAY_SIZE(tas2770_dapm_widgets),
460                 .dapm_routes            = tas2770_audio_map,
461                 .num_dapm_routes        = ARRAY_SIZE(tas2770_audio_map),
462         },
463 };
465 int tas2770_register_codec(struct tas2770_priv *pTAS2770)
467         int nResult = 0;
469         dev_info(pTAS2770->dev, "%s, enter\n", __func__);
470         nResult = snd_soc_register_codec(pTAS2770->dev,
471                 &soc_codec_driver_tas2770,
472                 tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
473         dev_info(pTAS2770->dev, "%s, enter result %d\n", __func__,nResult);
474         return nResult;
477 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770)
479         snd_soc_unregister_codec(pTAS2770->dev);
481         return 0;
484 MODULE_AUTHOR("Texas Instruments Inc.");
485 MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
486 MODULE_LICENSE("GPL v2");
487 #endif /* CONFIG_TAS2770_CODEC */