]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2770sw-android/tas2770sw-android.git/blob - tas2770-codec.c
6efab7a14d7f67c411510bc1afe67c99fc57be96
[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 TAS2770 20-W Digital Input Mono Class-D Audio Amplifier
18 **     with Speaker I/V Sense
19 **
20 ** =============================================================================
21 */
23 #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
50 static unsigned int tas2770_codec_read(struct snd_soc_codec *codec,
51                 unsigned int reg)
52 {
53         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
54         int nResult = 0;
55         unsigned int value = 0;
57         mutex_lock(&pTAS2770->dev_lock);
59         nResult = regmap_read(pTAS2770->regmap, reg, &value);
61         if (nResult < 0)
62                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
63                         __func__, reg, nResult);
64         else
65                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, value: 0x%x\n",
66                                 __func__, reg, value);
68         mutex_unlock(&pTAS2770->dev_lock);
70         if (nResult >= 0)
71                 return value;
72         else
73                 return nResult;
74 }
77 static int tas2770_codec_write(struct snd_soc_codec *codec, unsigned int reg,
78         unsigned int value)
79 {
80         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
82         int nResult = 0;
84         mutex_lock(&pTAS2770->dev_lock);
86         nResult = regmap_write(pTAS2770->regmap, reg, value);
87         if (nResult < 0)
88                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
89                         __func__, reg, nResult);
90         else
91                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, 0x%x\n",
92                         __func__, reg, value);
94         mutex_unlock(&pTAS2770->dev_lock);
96         return nResult;
98 }
101 static int tas2770_codec_suspend(struct snd_soc_codec *codec)
103         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
104         int ret = 0;
106         mutex_lock(&pTAS2770->codec_lock);
108         dev_dbg(pTAS2770->dev, "%s\n", __func__);
110         mutex_unlock(&pTAS2770->codec_lock);
111         return ret;
114 static int tas2770_codec_resume(struct snd_soc_codec *codec)
116         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
117         int ret = 0;
119         mutex_lock(&pTAS2770->codec_lock);
121         dev_dbg(pTAS2770->dev, "%s\n", __func__);
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         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
142         switch (event) {
143         case SND_SOC_DAPM_POST_PMU:
144                 snd_soc_update_bits(codec, TAS2770_PowerControl,
145                         TAS2770_PowerControl_OperationalMode10_Mask,
146                         TAS2770_PowerControl_OperationalMode10_Active);
147                 break;
148         case SND_SOC_DAPM_PRE_PMD:
149                 snd_soc_update_bits(codec, TAS2770_PowerControl,
150                         TAS2770_PowerControl_OperationalMode10_Mask,
151                         TAS2770_PowerControl_OperationalMode10_Shutdown);
152                 break;
154         }
155         return 0;
159 static const struct snd_kcontrol_new isense_switch =
160         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 3, 1, 1);
161 static const struct snd_kcontrol_new vsense_switch =
162         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 2, 1, 1);
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_SWITCH("ISENSE", TAS2770_PowerControl, 3, 1,
171                         &isense_switch),
172         SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PowerControl, 2, 1,
173                         &vsense_switch),
174         SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
175         SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
176         SND_SOC_DAPM_OUTPUT("OUT"),
177         SND_SOC_DAPM_SIGGEN("VMON"),
178         SND_SOC_DAPM_SIGGEN("IMON")
179 };
181 static const struct snd_soc_dapm_route tas2770_audio_map[] = {
182         {"ASI1 Sel", "Left", "ASI1"},
183         {"ASI1 Sel", "Right", "ASI1"},
184         {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
185         {"DAC", NULL, "ASI1 Sel"},
186         {"OUT", NULL, "DAC"},
187         {"ISENSE", "Switch", "IMON"},
188         {"VSENSE", "Switch", "VMON"},
189 };
192 static int tas2770_mute(struct snd_soc_dai *dai, int mute)
194         struct snd_soc_codec *codec = dai->codec;
195         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
196         dev_dbg(pTAS2770->dev, "%s\n", __func__);
198         mutex_lock(&pTAS2770->codec_lock);
199         if (mute) {
200                 snd_soc_update_bits(codec, TAS2770_PowerControl,
201                         TAS2770_PowerControl_OperationalMode10_Mask,
202                         TAS2770_PowerControl_OperationalMode10_Mute);
203         } else {
204                 snd_soc_update_bits(codec, TAS2770_PowerControl,
205                         TAS2770_PowerControl_OperationalMode10_Mask,
206                         TAS2770_PowerControl_OperationalMode10_Active);
207         }
208         mutex_unlock(&pTAS2770->codec_lock);
209         return 0;
212 static int tas2770_hw_params(struct snd_pcm_substream *substream,
213                 struct snd_pcm_hw_params *params,
214                 struct snd_soc_dai *dai)
216         struct snd_soc_codec *codec = dai->codec;
217         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
218         int ret = 0;
220         dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
221                 params_format(params));
223         switch (params_format(params)) {
224         case SNDRV_PCM_FORMAT_S16_LE:
225                 snd_soc_update_bits(codec,
226                         TAS2770_TDMConfigurationReg2,
227                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
228                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
229                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits |
230                         TAS2770_TDMConfigurationReg2_RXSLEN10_16Bits);
231                         pTAS2770->ch_size = 16;
232                 break;
233         case SNDRV_PCM_FORMAT_S24_LE:
234                         snd_soc_update_bits(codec,
235                         TAS2770_TDMConfigurationReg2,
236                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
237                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
238                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits  |
239                         TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
240                         pTAS2770->ch_size = 32;
241                 break;
242         case SNDRV_PCM_FORMAT_S32_LE:
243                         snd_soc_update_bits(codec,
244                         TAS2770_TDMConfigurationReg2,
245                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
246                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
247                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits |
248                         TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
249                         pTAS2770->ch_size = 32;
250                 break;
252         }
254         dev_dbg(pTAS2770->dev, "ch_size: %d\n", pTAS2770->ch_size);
255         snd_soc_update_bits(codec,
256                 TAS2770_TDMConfigurationReg5,
257                 TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
258                 TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
259                 TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
260                 (pTAS2770->ch_size >> 3));
261         snd_soc_update_bits(codec,
262                 TAS2770_TDMConfigurationReg6,
263                 TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
264                 TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
265                 TAS2770_TDMConfigurationReg6_ISNSTX_Enable);
267         dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
268                 params_rate(params));
269         switch (params_rate(params)) {
270         case 48000:
271                         snd_soc_update_bits(codec,
272                                 TAS2770_TDMConfigurationReg0,
273                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
274                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
275                         snd_soc_update_bits(codec,
276                                 TAS2770_TDMConfigurationReg0,
277                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
278                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
279                         break;
280         case 44100:
281                         snd_soc_update_bits(codec,
282                                 TAS2770_TDMConfigurationReg0,
283                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
284                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
285                         snd_soc_update_bits(codec,
286                                 TAS2770_TDMConfigurationReg0,
287                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
288                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
289                         break;
290         case 96000:
291                         snd_soc_update_bits(codec,
292                                 TAS2770_TDMConfigurationReg0,
293                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
294                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
295                         snd_soc_update_bits(codec,
296                                 TAS2770_TDMConfigurationReg0,
297                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
298                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
299                         break;
300         case 19200:
301                         snd_soc_update_bits(codec,
302                                 TAS2770_TDMConfigurationReg0,
303                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
304                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
305                         snd_soc_update_bits(codec,
306                                 TAS2770_TDMConfigurationReg0,
307                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
308                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
309                         break;
310         default:
311                         dev_dbg(pTAS2770->dev, "%s, unsupported sample rate\n", __func__);
313         }
314         return ret;
317 static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
319         u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
320         struct snd_soc_codec *codec = dai->codec;
321         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
322         int ret = 0;
324         dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
326         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
327         case SND_SOC_DAIFMT_CBS_CFS:
328                 asi_cfg_1 = 0x00;
329                 break;
330         default:
331                 dev_err(pTAS2770->dev, "ASI format master is not found\n");
332                 ret = -EINVAL;
333         }
335         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
336         case SND_SOC_DAIFMT_NB_NF:
337                 dev_dbg(pTAS2770->dev, "INV format: NBNF\n");
338                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Rising;
339                 break;
340         case SND_SOC_DAIFMT_IB_NF:
341                 dev_dbg(pTAS2770->dev, "INV format: IBNF\n");
342                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Falling;
343                 break;
344         default:
345                 dev_err(pTAS2770->dev, "ASI format Inverse is not found\n");
346                 ret = -EINVAL;
347         }
349         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
350                 TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
351                 asi_cfg_1);
353         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
354         case (SND_SOC_DAIFMT_I2S):
355                 tdm_rx_start_slot = 1;
356                 break;
357         case (SND_SOC_DAIFMT_DSP_A):
358         case (SND_SOC_DAIFMT_DSP_B):
359                 tdm_rx_start_slot = 1;
360                 break;
361         case (SND_SOC_DAIFMT_LEFT_J):
362                 tdm_rx_start_slot = 0;
363                 break;
364         default:
365         dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
366         ret = -EINVAL;
367                 break;
368         }
370         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
371                 TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
372         (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
373         return ret;
376 static struct snd_soc_dai_ops tas2770_dai_ops = {
377         .digital_mute = tas2770_mute,
378         .hw_params  = tas2770_hw_params,
379         .set_fmt    = tas2770_set_dai_fmt,
380 };
382 #define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
383                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
385 #define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
386                                                 SNDRV_PCM_RATE_96000 |\
387                                                 SNDRV_PCM_RATE_192000\
388                                                 )
390 static struct snd_soc_dai_driver tas2770_dai_driver[] = {
391         {
392                 .name = "tas2770 ASI1",
393                 .id = 0,
394                 .playback = {
395                         .stream_name    = "ASI1 Playback",
396                         .channels_min   = 2,
397                         .channels_max   = 2,
398                         .rates      = TAS2770_RATES,
399                         .formats    = TAS2770_FORMATS,
400                 },
401                 .capture = {
402                         .stream_name    = "ASI1 Capture",
403                         .channels_min   = 0,
404                         .channels_max   = 2,
405                         .rates          = TAS2770_RATES,
406                         .formats    = TAS2770_FORMATS,
407                 },
408                 .ops = &tas2770_dai_ops,
409                 .symmetric_rates = 1,
410         },
411 };
413 static int tas2770_codec_probe(struct snd_soc_codec *codec)
415         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
417         dev_err(pTAS2770->dev, "%s\n", __func__);
419         return 0;
422 static int tas2770_codec_remove(struct snd_soc_codec *codec)
424         return 0;
427 static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
429 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
430         SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
431                 0, TAS2770_PlaybackConfigurationReg0_AmplifierLevel40_Mask, 0,
432                 tas2770_digital_tlv),
433 };
435 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
436         .probe                  = tas2770_codec_probe,
437         .remove                 = tas2770_codec_remove,
438         .read                   = tas2770_codec_read,
439         .write                  = tas2770_codec_write,
440         .suspend                = tas2770_codec_suspend,
441         .resume                 = tas2770_codec_resume,
442         .component_driver = {
443                 .controls               = tas2770_snd_controls,
444                 .num_controls           = ARRAY_SIZE(tas2770_snd_controls),
445                 .dapm_widgets           = tas2770_dapm_widgets,
446                 .num_dapm_widgets       = ARRAY_SIZE(tas2770_dapm_widgets),
447                 .dapm_routes            = tas2770_audio_map,
448                 .num_dapm_routes        = ARRAY_SIZE(tas2770_audio_map),
449         },
450 };
452 int tas2770_register_codec(struct tas2770_priv *pTAS2770)
454         int nResult = 0;
456         dev_info(pTAS2770->dev, "%s, enter\n", __func__);
457         nResult = snd_soc_register_codec(pTAS2770->dev,
458                 &soc_codec_driver_tas2770,
459                 tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
461         return nResult;
464 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770)
466         snd_soc_unregister_codec(pTAS2770->dev);
468         return 0;
471 MODULE_AUTHOR("Texas Instruments Inc.");
472 MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
473 MODULE_LICENSE("GPL v2");
474 #endif /* CONFIG_TAS2770_CODEC */