Add slot width setting
[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 int tas2770_set_slot(struct snd_soc_codec *codec, int slot_width);
52 static unsigned int tas2770_codec_read(struct snd_soc_codec *codec,
53                 unsigned int reg)
54 {
55         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
56         int nResult = 0;
57         unsigned int value = 0;
59         mutex_lock(&pTAS2770->dev_lock);
61         nResult = regmap_read(pTAS2770->regmap, reg, &value);
63         if (nResult < 0)
64                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
65                         __func__, reg, nResult);
66         else
67                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, value: 0x%x\n",
68                                 __func__, reg, value);
70         mutex_unlock(&pTAS2770->dev_lock);
72         if (nResult >= 0)
73                 return value;
74         else
75                 return nResult;
76 }
79 static int tas2770_codec_write(struct snd_soc_codec *codec, unsigned int reg,
80         unsigned int value)
81 {
82         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
84         int nResult = 0;
86         mutex_lock(&pTAS2770->dev_lock);
88         nResult = regmap_write(pTAS2770->regmap, reg, value);
89         if (nResult < 0)
90                 dev_err(pTAS2770->dev, "%s, ERROR, reg=0x%x, E=%d\n",
91                         __func__, reg, nResult);
92         else
93                 dev_dbg(pTAS2770->dev, "%s, reg: 0x%x, 0x%x\n",
94                         __func__, reg, value);
96         mutex_unlock(&pTAS2770->dev_lock);
98         return nResult;
103 static int tas2770_codec_suspend(struct snd_soc_codec *codec)
105         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
106         int ret = 0;
108         mutex_lock(&pTAS2770->codec_lock);
110         dev_dbg(pTAS2770->dev, "%s\n", __func__);
112         mutex_unlock(&pTAS2770->codec_lock);
113         return ret;
116 static int tas2770_codec_resume(struct snd_soc_codec *codec)
118         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
119         int ret = 0;
121         mutex_lock(&pTAS2770->codec_lock);
123         dev_dbg(pTAS2770->dev, "%s\n", __func__);
125         mutex_unlock(&pTAS2770->codec_lock);
126         return ret;
129 static const char * const tas2770_ASI1_src[] = {
130         "I2C offset", "Left", "Right", "LeftRightDiv2",
131 };
133 static SOC_ENUM_SINGLE_DECL(
134         tas2770_ASI1_src_enum, TAS2770_TDMConfigurationReg2,
135         4, tas2770_ASI1_src);
137 static const struct snd_kcontrol_new tas2770_asi1_mux =
138         SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);
141 static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
142                         struct snd_kcontrol *kcontrol, int event)
144         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
146         switch (event) {
147         case SND_SOC_DAPM_POST_PMU:
148                 snd_soc_update_bits(codec, TAS2770_PowerControl,
149                         TAS2770_PowerControl_OperationalMode10_Mask,
150                         TAS2770_PowerControl_OperationalMode10_Mute);
151                 break;
152         case SND_SOC_DAPM_PRE_PMD:
153                 snd_soc_update_bits(codec, TAS2770_PowerControl,
154                         TAS2770_PowerControl_OperationalMode10_Mask,
155                         TAS2770_PowerControl_OperationalMode10_Shutdown);
156                 break;
158         }
159         return 0;
163 static const struct snd_kcontrol_new isense_switch =
164         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 3, 1, 1);
165 static const struct snd_kcontrol_new vsense_switch =
166         SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 2, 1, 1);
168 static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
169         SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
170         SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0,
171                                 &tas2770_asi1_mux),
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", "I2C offset", "ASI1"},
185         {"ASI1 Sel", "Left", "ASI1"},
186         {"ASI1 Sel", "Right", "ASI1"},
187         {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
188         {"DAC", NULL, "ASI1 Sel"},
189         {"OUT", NULL, "DAC"},
190         {"ISENSE", "Switch", "IMON"},
191         {"VSENSE", "Switch", "VMON"},
192 };
195 static int tas2770_mute(struct snd_soc_dai *dai, int mute)
197         struct snd_soc_codec *codec = dai->codec;
198         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
199         dev_dbg(pTAS2770->dev, "%s\n", __func__);
201         mutex_lock(&pTAS2770->codec_lock);
202         if (mute) {
203                 snd_soc_update_bits(codec, TAS2770_PowerControl,
204                         TAS2770_PowerControl_OperationalMode10_Mask,
205                         TAS2770_PowerControl_OperationalMode10_Mute);
206         } else {
207                 snd_soc_update_bits(codec, TAS2770_PowerControl,
208                         TAS2770_PowerControl_OperationalMode10_Mask,
209                         TAS2770_PowerControl_OperationalMode10_Active);
210         }
211         mutex_unlock(&pTAS2770->codec_lock);
212         return 0;
215 static int tas2770_hw_params(struct snd_pcm_substream *substream,
216                 struct snd_pcm_hw_params *params,
217                 struct snd_soc_dai *dai)
219         struct snd_soc_codec *codec = dai->codec;
220         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
221         int ret = 0;
222         int slot_width_tmp = 16;
224         dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
225                 params_format(params));
227         switch (params_format(params)) {
228         case SNDRV_PCM_FORMAT_S16_LE:
229                 snd_soc_update_bits(codec,
230                         TAS2770_TDMConfigurationReg2,
231                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
232                         TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits);
233                         pTAS2770->mnCh_size = 16;
234                         if (pTAS2770->mnSlot_width == 0)
235                                 slot_width_tmp = 16;
236                 break;
237         case SNDRV_PCM_FORMAT_S24_LE:
238                         snd_soc_update_bits(codec,
239                         TAS2770_TDMConfigurationReg2,
240                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
241                         TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
242                         pTAS2770->mnCh_size = 24;
243                         if (pTAS2770->mnSlot_width == 0)
244                                 slot_width_tmp = 32;
245                 break;
246         case SNDRV_PCM_FORMAT_S32_LE:
247                         snd_soc_update_bits(codec,
248                         TAS2770_TDMConfigurationReg2,
249                         TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
250                         TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
251                         pTAS2770->mnCh_size = 32;
252                         if (pTAS2770->mnSlot_width == 0)
253                                 slot_width_tmp = 32;
254                 break;
256         default:
257                 dev_dbg(pTAS2770->dev, "Not supported params format\n");
258                 return -EINVAL;
259         }
261         /* If machine driver did not call set slot width */
262         if (pTAS2770->mnSlot_width == 0)
263                 tas2770_set_slot(codec, slot_width_tmp);
265         dev_dbg(pTAS2770->dev, "mnCh_size: %d\n", pTAS2770->mnCh_size);
266         snd_soc_update_bits(codec,
267                 TAS2770_TDMConfigurationReg5,
268                 TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
269                 TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
270                 TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
271                 pTAS2770->mnVmon_slot_no);
272         snd_soc_update_bits(codec,
273                 TAS2770_TDMConfigurationReg6,
274                 TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
275                 TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
276                 TAS2770_TDMConfigurationReg6_ISNSTX_Enable |
277                 pTAS2770->mnImon_slot_no);
279         dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
280                 params_rate(params));
281         switch (params_rate(params)) {
282         case 48000:
283                         snd_soc_update_bits(codec,
284                                 TAS2770_TDMConfigurationReg0,
285                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
286                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
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 44100:
293                         snd_soc_update_bits(codec,
294                                 TAS2770_TDMConfigurationReg0,
295                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
296                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
297                         snd_soc_update_bits(codec,
298                                 TAS2770_TDMConfigurationReg0,
299                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
300                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
301                         break;
302         case 96000:
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_88_2_96kHz);
311                         break;
312         case 19200:
313                         snd_soc_update_bits(codec,
314                                 TAS2770_TDMConfigurationReg0,
315                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
316                                 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
317                         snd_soc_update_bits(codec,
318                                 TAS2770_TDMConfigurationReg0,
319                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
320                                 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
321                         break;
322         default:
323                         dev_dbg(pTAS2770->dev, "%s, unsupported sample rate\n", __func__);
325         }
326         return ret;
329 static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
331         u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
332         struct snd_soc_codec *codec = dai->codec;
333         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
334         int ret = 0;
335         int value = 0;
337         dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
339         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
340         case SND_SOC_DAIFMT_CBS_CFS:
341                 asi_cfg_1 = 0x00;
342                 break;
343         default:
344                 dev_err(pTAS2770->dev, "ASI format master is not found\n");
345                 ret = -EINVAL;
346         }
348         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
349         case SND_SOC_DAIFMT_NB_NF:
350                 dev_dbg(pTAS2770->dev, "INV format: NBNF\n");
351                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Rising;
352                 break;
353         case SND_SOC_DAIFMT_IB_NF:
354                 dev_dbg(pTAS2770->dev, "INV format: IBNF\n");
355                 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Falling;
356                 break;
357         default:
358                 dev_err(pTAS2770->dev, "ASI format Inverse is not found\n");
359                 ret = -EINVAL;
360         }
362         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
363                 TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
364                 asi_cfg_1);
366         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
367         case (SND_SOC_DAIFMT_I2S):
368                 tdm_rx_start_slot = 1;
369                 break;
370         case (SND_SOC_DAIFMT_DSP_A):
371         case (SND_SOC_DAIFMT_DSP_B):
372                 tdm_rx_start_slot = 1;
373                 break;
374         case (SND_SOC_DAIFMT_LEFT_J):
375                 tdm_rx_start_slot = 0;
376                 break;
377         default:
378         dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
379         ret = -EINVAL;
380                 break;
381         }
383         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg1,
384                 TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
385         (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
387         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
388                 TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Mask,
389                 (pTAS2770->mnLeftSlot << TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Shift));
390         snd_soc_update_bits(codec, TAS2770_TDMConfigurationReg3,
391                 TAS2770_TDMConfigurationReg3_RXSLOTRight74_Mask,
392         (pTAS2770->mnRightSlot << TAS2770_TDMConfigurationReg3_RXSLOTRight74_Shift));
394         value = snd_soc_read(codec, TAS2770_TDMConfigurationReg3);
395         dev_dbg(pTAS2770->dev, "slot value: 0x%x", value);
397         return ret;
400 static int tas2770_set_slot(struct snd_soc_codec *codec, int slot_width)
402         int ret = 0;
403         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
405         switch (slot_width) {
406         case 16:
407         ret = snd_soc_update_bits(codec,
408                 TAS2770_TDMConfigurationReg2,
409                 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
410                 TAS2770_TDMConfigurationReg2_RXSLEN10_16Bits);
411         break;
413         case 24:
414         ret = snd_soc_update_bits(codec,
415                 TAS2770_TDMConfigurationReg2,
416                 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
417                 TAS2770_TDMConfigurationReg2_RXSLEN10_24Bits);
418         break;
420         case 32:
421         ret = snd_soc_update_bits(codec,
422                 TAS2770_TDMConfigurationReg2,
423                 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
424                 TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
425         break;
427         case 0:
428         /* Do not change slot width */
429         break;
431         default:
432                 dev_dbg(pTAS2770->dev, "slot width not supported");
433                 ret = -EINVAL;
434         }
436         if (ret >= 0)
437                 pTAS2770->mnSlot_width = slot_width;
439         return ret;
442 static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
443                 unsigned int tx_mask, unsigned int rx_mask,
444                 int slots, int slot_width)
446         int ret = 0;
447         struct snd_soc_codec *codec = dai->codec;
448         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
450         dev_dbg(pTAS2770->dev, "%s, tx_mask:%d, rx_mask:%d, slots:%d, slot_width:%d",
451                         __func__, tx_mask, rx_mask, slots, slot_width);
453         ret = tas2770_set_slot(codec, slot_width);
455         return ret;
458 static struct snd_soc_dai_ops tas2770_dai_ops = {
459         .digital_mute = tas2770_mute,
460         .hw_params  = tas2770_hw_params,
461         .set_fmt    = tas2770_set_dai_fmt,
462         .set_tdm_slot = tas2770_set_dai_tdm_slot,
463 };
465 #define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
466                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
468 #define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
469                                                 SNDRV_PCM_RATE_96000 |\
470                                                 SNDRV_PCM_RATE_192000\
471                                                 )
473 static struct snd_soc_dai_driver tas2770_dai_driver[] = {
474         {
475                 .name = "tas2770 ASI1",
476                 .id = 0,
477                 .playback = {
478                         .stream_name    = "ASI1 Playback",
479                         .channels_min   = 2,
480                         .channels_max   = 2,
481                         .rates      = TAS2770_RATES,
482                         .formats    = TAS2770_FORMATS,
483                 },
484                 .capture = {
485                         .stream_name    = "ASI1 Capture",
486                         .channels_min   = 0,
487                         .channels_max   = 2,
488                         .rates          = TAS2770_RATES,
489                         .formats    = TAS2770_FORMATS,
490                 },
491                 .ops = &tas2770_dai_ops,
492                 .symmetric_rates = 1,
493         },
494 };
496 static int tas2770_codec_probe(struct snd_soc_codec *codec)
498         struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
500         dev_err(pTAS2770->dev, "%s\n", __func__);
502         return 0;
505 static int tas2770_codec_remove(struct snd_soc_codec *codec)
507         return 0;
510 static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
512 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
513         SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
514                 0, TAS2770_PlaybackConfigurationReg0_AmplifierLevel40_Mask, 0,
515                 tas2770_digital_tlv),
516 };
518 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
519         .probe                  = tas2770_codec_probe,
520         .remove                 = tas2770_codec_remove,
521         .read                   = tas2770_codec_read,
522         .write                  = tas2770_codec_write,
523         .suspend                = tas2770_codec_suspend,
524         .resume                 = tas2770_codec_resume,
525         .component_driver = {
526                 .controls               = tas2770_snd_controls,
527                 .num_controls           = ARRAY_SIZE(tas2770_snd_controls),
528                 .dapm_widgets           = tas2770_dapm_widgets,
529                 .num_dapm_widgets       = ARRAY_SIZE(tas2770_dapm_widgets),
530                 .dapm_routes            = tas2770_audio_map,
531                 .num_dapm_routes        = ARRAY_SIZE(tas2770_audio_map),
532         },
533 };
535 int tas2770_register_codec(struct tas2770_priv *pTAS2770)
537         int nResult = 0;
539         dev_info(pTAS2770->dev, "%s, enter\n", __func__);
540         nResult = snd_soc_register_codec(pTAS2770->dev,
541                 &soc_codec_driver_tas2770,
542                 tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
544         return nResult;
547 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770)
549         snd_soc_unregister_codec(pTAS2770->dev);
551         return 0;
554 MODULE_AUTHOR("Texas Instruments Inc.");
555 MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
556 MODULE_LICENSE("GPL v2");
557 #endif /* CONFIG_TAS2770_CODEC */