Add IV data output, correct code style
[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
18 **     Amplifier
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__);
109         pTAS2770->runtime_suspend(pTAS2770);
111         mutex_unlock(&pTAS2770->codec_lock);
112         return ret;
115 static int tas2770_codec_resume(struct snd_soc_codec *codec)
117         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
118         int ret = 0;
120         mutex_lock(&pTAS2770->codec_lock);
122         dev_dbg(pTAS2770->dev, "%s\n", __func__);
123         pTAS2770->runtime_resume(pTAS2770);
125         mutex_unlock(&pTAS2770->codec_lock);
126         return ret;
129 static const struct snd_kcontrol_new tas2770_asi_controls[] = {
130         SOC_DAPM_SINGLE("Left", TAS2770_TDMConfigurationReg2,
131                 4, 1, 0),
132         SOC_DAPM_SINGLE("Right", TAS2770_TDMConfigurationReg2,
133                 4, 2, 0),
134         SOC_DAPM_SINGLE("LeftRightDiv2", TAS2770_TDMConfigurationReg2,
135                 4, 3, 0),
136 };
139 static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
140                         struct snd_kcontrol *kcontrol, int event)
142         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
144         switch (event) {
145         case SND_SOC_DAPM_POST_PMU:
146                 snd_soc_update_bits(codec, TAS2770_PowerControl,
147                         TAS2770_PowerControl_OperationalMode10_Mask,
148                         TAS2770_PowerControl_OperationalMode10_Active);
149                 break;
150         case SND_SOC_DAPM_PRE_PMD:
151                 snd_soc_update_bits(codec, TAS2770_PowerControl,
152                         TAS2770_PowerControl_OperationalMode10_Mask,
153                         TAS2770_PowerControl_OperationalMode10_Shutdown);
154                 break;
156         }
157         return 0;
161 static const struct snd_kcontrol_new isense_switch =
162         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 3, 1, 1);
163 static const struct snd_kcontrol_new vsense_switch =
164         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 2, 1, 1);
166 static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
167         SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
168         SND_SOC_DAPM_MIXER("ASI1 Sel",
169                 TAS2770_TDMConfigurationReg2, 4, 0,
170                 &tas2770_asi_controls[0],
171                 ARRAY_SIZE(tas2770_asi_controls)),
172         SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PowerControl, 3, 1,
173                         &isense_switch),
174         SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PowerControl, 2, 1,
175                         &vsense_switch),
176         SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
177         SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
178         SND_SOC_DAPM_OUTPUT("OUT"),
179         SND_SOC_DAPM_SIGGEN("VMON"),
180         SND_SOC_DAPM_SIGGEN("IMON")
181 };
183 static const struct snd_soc_dapm_route tas2770_audio_map[] = {
184         {"ASI1 Sel", "Left", "ASI1"},
185         {"ASI1 Sel", "Right", "ASI1"},
186         {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
187         {"DAC", NULL, "ASI1 Sel"},
188         {"OUT", NULL, "DAC"},
189         {"ISENSE", "Switch", "IMON"},
190         {"VSENSE", "Switch", "VMON"},
191 };
194 static int tas2770_mute(struct snd_soc_dai *dai, int mute)
196         struct snd_soc_codec *codec = dai->codec;
197         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
198         dev_dbg(pTAS2770->dev, "%s\n", __func__);
200         mutex_lock(&pTAS2770->codec_lock);
201         if (mute) {
202                 snd_soc_update_bits(codec, TAS2770_PowerControl,
203                         TAS2770_PowerControl_OperationalMode10_Mask,
204                         TAS2770_PowerControl_OperationalMode10_Mute);
205         } else {
206                 snd_soc_update_bits(codec, TAS2770_PowerControl,
207                         TAS2770_PowerControl_OperationalMode10_Mask,
208                         TAS2770_PowerControl_OperationalMode10_Active);
209         }
210         mutex_unlock(&pTAS2770->codec_lock);
211         return 0;
214 static int tas2770_hw_params(struct snd_pcm_substream *substream,
215                 struct snd_pcm_hw_params *params,
216                 struct snd_soc_dai *dai)
218         struct snd_soc_codec *codec = dai->codec;
219         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
220         int ret = 0;
222         dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
223                 params_format(params));
225         switch (params_format(params)) {
226         case SNDRV_PCM_FORMAT_S16_LE:
227                 snd_soc_update_bits(codec,
228                         TAS2770_TDMConfigurationReg2,
229                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
230                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
231                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits |
232                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits);
233                         pTAS2770->ch_size = 16;
234                 break;
235         case SNDRV_PCM_FORMAT_S24_LE:
236                         snd_soc_update_bits(codec,
237                         TAS2770_TDMConfigurationReg2,
238                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
239                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
240                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits  |
241                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
242                         pTAS2770->ch_size = 32;
243                 break;
244         case SNDRV_PCM_FORMAT_S32_LE:
245                         snd_soc_update_bits(codec,
246                         TAS2770_TDMConfigurationReg2,
247                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask |
248                         TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
249                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits |
250                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
251                         pTAS2770->ch_size = 32;
252                 break;
254         }
256         dev_dbg(pTAS2770->dev, "ch_size: %d\n", pTAS2770->ch_size);
257         snd_soc_update_bits(codec,
258                 TAS2770_TDMConfigurationReg5,
259                 TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
260                 TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
261                 TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
262                 (pTAS2770->ch_size >> 3));
263         snd_soc_update_bits(codec,
264                 TAS2770_TDMConfigurationReg6,
265                 TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
266                 TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
267                 TAS2770_TDMConfigurationReg6_ISNSTX_Enable);
269         dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
270                 params_rate(params));
271         switch (params_rate(params)) {
272         case 48000:
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_44_1_48kHz);
281                         break;
282         case 44100:
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_44_1_48kHz);
291                         break;
292         case 96000:
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_88_2_96kHz);
301                         break;
302         case 19200:
303                         snd_soc_update_bits(codec,
304                                 TAS2770_TDMConfigurationReg0,
305                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
306                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
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__);
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         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
329         case SND_SOC_DAIFMT_CBS_CFS:
330                 asi_cfg_1 = 0x00;
331                 break;
332         default:
333                 dev_err(pTAS2770->dev, "ASI format master is not found\n");
334                 ret = -EINVAL;
335         }
337         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
338         case SND_SOC_DAIFMT_NB_NF:
339                 dev_dbg(pTAS2770->dev, "INV format: NBNF\n");
340                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Rising;
341                 break;
342         case SND_SOC_DAIFMT_IB_NF:
343                 dev_dbg(pTAS2770->dev, "INV format: IBNF\n");
344                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Falling;
345                 break;
346         default:
347                 dev_err(pTAS2770->dev, "ASI format Inverse is not found\n");
348                 ret = -EINVAL;
349         }
351         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
352                 TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
353                 asi_cfg_1);
355         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
356         case (SND_SOC_DAIFMT_I2S):
357                 tdm_rx_start_slot = 1;
358                 break;
359         case (SND_SOC_DAIFMT_DSP_A):
360         case (SND_SOC_DAIFMT_DSP_B):
361                 tdm_rx_start_slot = 1;
362                 break;
363         case (SND_SOC_DAIFMT_LEFT_J):
364                 tdm_rx_start_slot = 0;
365                 break;
366         default:
367         dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
368         ret = -EINVAL;
369                 break;
370         }
372         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
373                 TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
374         (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
375         return ret;
378 static struct snd_soc_dai_ops tas2770_dai_ops = {
379         .digital_mute = tas2770_mute,
380         .hw_params  = tas2770_hw_params,
381         .set_fmt    = tas2770_set_dai_fmt,
382 };
384 #define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
385                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
387 #define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
388                                                 SNDRV_PCM_RATE_96000 |\
389                                                 SNDRV_PCM_RATE_192000\
390                                                 )
392 static struct snd_soc_dai_driver tas2770_dai_driver[] = {
393         {
394                 .name = "tas2770 ASI1",
395                 .id = 0,
396                 .playback = {
397                         .stream_name    = "ASI1 Playback",
398                         .channels_min   = 2,
399                         .channels_max   = 2,
400                         .rates      = TAS2770_RATES,
401                         .formats    = TAS2770_FORMATS,
402                 },
403                 .capture = {
404                         .stream_name    = "ASI1 Capture",
405                         .channels_min   = 0,
406                         .channels_max   = 2,
407                         .rates          = TAS2770_RATES,
408                         .formats    = TAS2770_FORMATS,
409                 },
410                 .ops = &tas2770_dai_ops,
411                 .symmetric_rates = 1,
412         },
413 };
415 static int tas2770_codec_probe(struct snd_soc_codec *codec)
417         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
419         dev_err(pTAS2770->dev, "%s\n", __func__);
421         return 0;
424 static int tas2770_codec_remove(struct snd_soc_codec *codec)
426         return 0;
429 static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
431 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
432         SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
433                 0, TAS2770_PlaybackConfigurationReg0_AmplifierLevel40_Mask, 0,
434                 tas2770_digital_tlv),
435 };
437 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
438         .probe                  = tas2770_codec_probe,
439         .remove                 = tas2770_codec_remove,
440         .read                   = tas2770_codec_read,
441         .write                  = tas2770_codec_write,
442         .suspend                = tas2770_codec_suspend,
443         .resume                 = tas2770_codec_resume,
444         .component_driver = {
445                 .controls               = tas2770_snd_controls,
446                 .num_controls           = ARRAY_SIZE(tas2770_snd_controls),
447                 .dapm_widgets           = tas2770_dapm_widgets,
448                 .num_dapm_widgets       = ARRAY_SIZE(tas2770_dapm_widgets),
449                 .dapm_routes            = tas2770_audio_map,
450                 .num_dapm_routes        = ARRAY_SIZE(tas2770_audio_map),
451         },
452 };
454 int tas2770_register_codec(struct tas2770_priv *pTAS2770)
456         int nResult = 0;
458         dev_info(pTAS2770->dev, "%s, enter\n", __func__);
459         nResult = snd_soc_register_codec(pTAS2770->dev,
460                 &soc_codec_driver_tas2770,
461                 tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
463         return nResult;
466 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770)
468         snd_soc_unregister_codec(pTAS2770->dev);
470         return 0;
473 MODULE_AUTHOR("Texas Instruments Inc.");
474 MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
475 MODULE_LICENSE("GPL v2");
476 #endif /* CONFIG_TAS2770_CODEC */