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;
100 }
103 static int tas2770_codec_suspend(struct snd_soc_codec *codec)
104 {
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__);
111 pTAS2770->runtime_suspend(pTAS2770);
113 mutex_unlock(&pTAS2770->codec_lock);
114 return ret;
115 }
117 static int tas2770_codec_resume(struct snd_soc_codec *codec)
118 {
119 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
120 int ret = 0;
122 mutex_lock(&pTAS2770->codec_lock);
124 dev_dbg(pTAS2770->dev, "%s\n", __func__);
125 pTAS2770->runtime_resume(pTAS2770);
127 mutex_unlock(&pTAS2770->codec_lock);
128 return ret;
129 }
131 static const char * const tas2770_ASI1_src[] = {
132 "I2C offset", "Left", "Right", "LeftRightDiv2",
133 };
135 static SOC_ENUM_SINGLE_DECL(
136 tas2770_ASI1_src_enum, TAS2770_TDMConfigurationReg2,
137 4, tas2770_ASI1_src);
139 static const struct snd_kcontrol_new tas2770_asi1_mux =
140 SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum);
142 static int tas2770_set_power_state(struct tas2770_priv *pTAS2770, int state)
143 {
144 struct snd_soc_codec *codec = pTAS2770->codec;
146 switch (state) {
147 case TAS2770_POWER_ACTIVE:
148 snd_soc_update_bits(codec, TAS2770_PowerControl,
149 TAS2770_PowerControl_OperationalMode10_Mask,
150 TAS2770_PowerControl_OperationalMode10_Active);
151 pTAS2770->mnPowerState = TAS2770_POWER_ACTIVE;
152 pTAS2770->enableIRQ(pTAS2770, true);
153 break;
155 case TAS2770_POWER_MUTE:
156 snd_soc_update_bits(codec, TAS2770_PowerControl,
157 TAS2770_PowerControl_OperationalMode10_Mask,
158 TAS2770_PowerControl_OperationalMode10_Mute);
159 pTAS2770->mnPowerState = TAS2770_POWER_MUTE;
160 break;
162 case TAS2770_POWER_SHUTDOWN:
163 snd_soc_update_bits(codec, TAS2770_PowerControl,
164 TAS2770_PowerControl_OperationalMode10_Mask,
165 TAS2770_PowerControl_OperationalMode10_Shutdown);
166 pTAS2770->enableIRQ(pTAS2770, false);
167 pTAS2770->mnPowerState = TAS2770_POWER_SHUTDOWN;
168 break;
170 default:
171 dev_err(pTAS2770->dev, "wrong power state setting %d\n", state);
173 }
175 return 0;
176 }
178 static int tas2770_dac_event(struct snd_soc_dapm_widget *w,
179 struct snd_kcontrol *kcontrol, int event)
180 {
181 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
182 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
184 mutex_lock(&pTAS2770->codec_lock);
186 switch (event) {
187 case SND_SOC_DAPM_POST_PMU:
188 tas2770_set_power_state(pTAS2770, TAS2770_POWER_MUTE);
189 break;
190 case SND_SOC_DAPM_PRE_PMD:
191 tas2770_set_power_state(pTAS2770, TAS2770_POWER_SHUTDOWN);
192 break;
194 }
196 mutex_unlock(&pTAS2770->codec_lock);
197 return 0;
198 }
200 static const struct snd_kcontrol_new isense_switch =
201 SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 3, 1, 1);
202 static const struct snd_kcontrol_new vsense_switch =
203 SOC_DAPM_SINGLE("Switch", TAS2770_PowerControl, 2, 1, 1);
205 static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
206 SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
207 SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0,
208 &tas2770_asi1_mux),
209 SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PowerControl, 3, 1,
210 &isense_switch),
211 SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PowerControl, 2, 1,
212 &vsense_switch),
213 SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
214 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
215 SND_SOC_DAPM_OUTPUT("OUT"),
216 SND_SOC_DAPM_SIGGEN("VMON"),
217 SND_SOC_DAPM_SIGGEN("IMON")
218 };
220 static const struct snd_soc_dapm_route tas2770_audio_map[] = {
221 {"ASI1 Sel", "I2C offset", "ASI1"},
222 {"ASI1 Sel", "Left", "ASI1"},
223 {"ASI1 Sel", "Right", "ASI1"},
224 {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
225 {"DAC", NULL, "ASI1 Sel"},
226 {"OUT", NULL, "DAC"},
227 {"ISENSE", "Switch", "IMON"},
228 {"VSENSE", "Switch", "VMON"},
229 };
232 static int tas2770_mute(struct snd_soc_dai *dai, int mute)
233 {
234 struct snd_soc_codec *codec = dai->codec;
235 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
236 dev_dbg(pTAS2770->dev, "%s\n", __func__);
238 mutex_lock(&pTAS2770->codec_lock);
239 if (mute) {
240 tas2770_set_power_state(pTAS2770, TAS2770_POWER_MUTE);
241 } else {
242 tas2770_set_power_state(pTAS2770, TAS2770_POWER_ACTIVE);
243 }
244 mutex_unlock(&pTAS2770->codec_lock);
245 return 0;
246 }
248 static int tas2770_set_bitwidth(struct tas2770_priv *pTAS2770, int bitwidth)
249 {
250 switch (bitwidth) {
251 case SNDRV_PCM_FORMAT_S16_LE:
252 snd_soc_update_bits(pTAS2770->codec,
253 TAS2770_TDMConfigurationReg2,
254 TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
255 TAS2770_TDMConfigurationReg2_RXWLEN32_16Bits);
256 /* If machine driver did not call set slot width */
257 if (pTAS2770->mnSlot_width == 0)
258 tas2770_set_slot(pTAS2770->codec, 16);
259 pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 2;
260 break;
261 case SNDRV_PCM_FORMAT_S24_LE:
262 snd_soc_update_bits(pTAS2770->codec,
263 TAS2770_TDMConfigurationReg2,
264 TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
265 TAS2770_TDMConfigurationReg2_RXWLEN32_24Bits);
266 if (pTAS2770->mnSlot_width == 0)
267 tas2770_set_slot(pTAS2770->codec, 32);
268 pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 4;
269 break;
270 case SNDRV_PCM_FORMAT_S32_LE:
271 snd_soc_update_bits(pTAS2770->codec,
272 TAS2770_TDMConfigurationReg2,
273 TAS2770_TDMConfigurationReg2_RXWLEN32_Mask,
274 TAS2770_TDMConfigurationReg2_RXWLEN32_32Bits);
275 if (pTAS2770->mnSlot_width == 0)
276 tas2770_set_slot(pTAS2770->codec, 32);
277 pTAS2770->mnVmon_slot_no = pTAS2770->mnImon_slot_no + 4;
278 break;
280 default:
281 dev_dbg(pTAS2770->dev, "Not supported params format\n");
282 return -EINVAL;
283 }
285 pTAS2770->mnCh_size = bitwidth;
286 dev_dbg(pTAS2770->dev, "mnCh_size: %d\n", pTAS2770->mnCh_size);
288 snd_soc_update_bits(pTAS2770->codec,
289 TAS2770_TDMConfigurationReg5,
290 TAS2770_TDMConfigurationReg5_VSNSTX_Mask |
291 TAS2770_TDMConfigurationReg5_VSNSSLOT50_Mask,
292 TAS2770_TDMConfigurationReg5_VSNSTX_Enable |
293 pTAS2770->mnVmon_slot_no);
294 snd_soc_update_bits(pTAS2770->codec,
295 TAS2770_TDMConfigurationReg6,
296 TAS2770_TDMConfigurationReg6_ISNSTX_Mask |
297 TAS2770_TDMConfigurationReg6_ISNSSLOT50_Mask,
298 TAS2770_TDMConfigurationReg6_ISNSTX_Enable |
299 pTAS2770->mnImon_slot_no);
301 return 0;
302 }
304 static int tas2770_set_samplerate(struct tas2770_priv *pTAS2770, int samplerate)
305 {
306 switch (samplerate) {
307 case 48000:
308 snd_soc_update_bits(pTAS2770->codec,
309 TAS2770_TDMConfigurationReg0,
310 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
311 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
312 snd_soc_update_bits(pTAS2770->codec,
313 TAS2770_TDMConfigurationReg0,
314 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
315 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
316 break;
317 case 44100:
318 snd_soc_update_bits(pTAS2770->codec,
319 TAS2770_TDMConfigurationReg0,
320 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
321 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
322 snd_soc_update_bits(pTAS2770->codec,
323 TAS2770_TDMConfigurationReg0,
324 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
325 TAS2770_TDMConfigurationReg0_SAMPRATE31_44_1_48kHz);
326 break;
327 case 96000:
328 snd_soc_update_bits(pTAS2770->codec,
329 TAS2770_TDMConfigurationReg0,
330 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
331 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
332 snd_soc_update_bits(pTAS2770->codec,
333 TAS2770_TDMConfigurationReg0,
334 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
335 TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
336 break;
337 case 88200:
338 snd_soc_update_bits(pTAS2770->codec,
339 TAS2770_TDMConfigurationReg0,
340 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
341 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
342 snd_soc_update_bits(pTAS2770->codec,
343 TAS2770_TDMConfigurationReg0,
344 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
345 TAS2770_TDMConfigurationReg0_SAMPRATE31_88_2_96kHz);
346 break;
347 case 19200:
348 snd_soc_update_bits(pTAS2770->codec,
349 TAS2770_TDMConfigurationReg0,
350 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
351 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_48KHz);
352 snd_soc_update_bits(pTAS2770->codec,
353 TAS2770_TDMConfigurationReg0,
354 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
355 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
356 break;
357 case 17640:
358 snd_soc_update_bits(pTAS2770->codec,
359 TAS2770_TDMConfigurationReg0,
360 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_Mask,
361 TAS2770_TDMConfigurationReg0_SAMPRATERAMP_44_1KHz);
362 snd_soc_update_bits(pTAS2770->codec,
363 TAS2770_TDMConfigurationReg0,
364 TAS2770_TDMConfigurationReg0_SAMPRATE31_Mask,
365 TAS2770_TDMConfigurationReg0_SAMPRATE31_176_4_192kHz);
366 break;
367 default:
368 dev_dbg(pTAS2770->dev, "%s, unsupported sample rate\n", __func__);
370 }
372 pTAS2770->mnSamplingRate = samplerate;
373 return 0;
374 }
376 static int tas2770_hw_params(struct snd_pcm_substream *substream,
377 struct snd_pcm_hw_params *params,
378 struct snd_soc_dai *dai)
379 {
380 struct snd_soc_codec *codec = dai->codec;
381 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
382 int ret = 0;
384 dev_dbg(pTAS2770->dev, "%s, format: %d\n", __func__,
385 params_format(params));
387 mutex_lock(&pTAS2770->codec_lock);
389 ret = tas2770_set_bitwidth(pTAS2770, params_format(params));
390 if(ret < 0)
391 return ret;
393 dev_dbg(pTAS2770->dev, "%s, sample rate: %d\n", __func__,
394 params_rate(params));
396 ret = tas2770_set_samplerate(pTAS2770, params_rate(params));
398 mutex_unlock(&pTAS2770->codec_lock);
399 return ret;
400 }
402 static int tas2770_set_fmt(struct tas2770_priv *pTAS2770, unsigned int fmt)
403 {
404 u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
405 int ret = 0;
406 int value = 0;
408 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
409 case SND_SOC_DAIFMT_CBS_CFS:
410 asi_cfg_1 = 0x00;
411 break;
412 default:
413 dev_err(pTAS2770->dev, "ASI format master is not found\n");
414 ret = -EINVAL;
415 }
417 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
418 case SND_SOC_DAIFMT_NB_NF:
419 dev_dbg(pTAS2770->dev, "INV format: NBNF\n");
420 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Rising;
421 break;
422 case SND_SOC_DAIFMT_IB_NF:
423 dev_dbg(pTAS2770->dev, "INV format: IBNF\n");
424 asi_cfg_1 |= TAS2770_TDMConfigurationReg1_RXEDGE_Falling;
425 break;
426 default:
427 dev_err(pTAS2770->dev, "ASI format Inverse is not found\n");
428 ret = -EINVAL;
429 }
431 snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg1,
432 TAS2770_TDMConfigurationReg1_RXEDGE_Mask,
433 asi_cfg_1);
435 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
436 case (SND_SOC_DAIFMT_I2S):
437 tdm_rx_start_slot = 1;
438 break;
439 case (SND_SOC_DAIFMT_DSP_A):
440 case (SND_SOC_DAIFMT_DSP_B):
441 tdm_rx_start_slot = 1;
442 break;
443 case (SND_SOC_DAIFMT_LEFT_J):
444 tdm_rx_start_slot = 0;
445 break;
446 default:
447 dev_err(pTAS2770->dev, "DAI Format is not found, fmt=0x%x\n", fmt);
448 ret = -EINVAL;
449 break;
450 }
452 snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg1,
453 TAS2770_TDMConfigurationReg1_RXOFFSET51_Mask,
454 (tdm_rx_start_slot << TAS2770_TDMConfigurationReg1_RXOFFSET51_Shift));
456 snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
457 TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Mask,
458 (pTAS2770->mnLeftSlot << TAS2770_TDMConfigurationReg3_RXSLOTLeft30_Shift));
459 snd_soc_update_bits(pTAS2770->codec, TAS2770_TDMConfigurationReg3,
460 TAS2770_TDMConfigurationReg3_RXSLOTRight74_Mask,
461 (pTAS2770->mnRightSlot << TAS2770_TDMConfigurationReg3_RXSLOTRight74_Shift));
463 value = snd_soc_read(pTAS2770->codec, TAS2770_TDMConfigurationReg3);
464 dev_dbg(pTAS2770->dev, "slot value: 0x%x", value);
466 pTAS2770->mnASIFormat = fmt;
468 return 0;
469 }
471 static int tas2770_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
472 {
473 struct snd_soc_codec *codec = dai->codec;
474 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
475 int ret = 0;
477 dev_dbg(pTAS2770->dev, "%s, format=0x%x\n", __func__, fmt);
478 mutex_lock(&pTAS2770->codec_lock);
480 ret = tas2770_set_fmt(pTAS2770, fmt);
482 mutex_unlock(&pTAS2770->codec_lock);
483 return ret;
484 }
486 static int tas2770_set_slot(struct snd_soc_codec *codec, int slot_width)
487 {
488 int ret = 0;
489 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
491 switch (slot_width) {
492 case 16:
493 ret = snd_soc_update_bits(codec,
494 TAS2770_TDMConfigurationReg2,
495 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
496 TAS2770_TDMConfigurationReg2_RXSLEN10_16Bits);
497 break;
499 case 24:
500 ret = snd_soc_update_bits(codec,
501 TAS2770_TDMConfigurationReg2,
502 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
503 TAS2770_TDMConfigurationReg2_RXSLEN10_24Bits);
504 break;
506 case 32:
507 ret = snd_soc_update_bits(codec,
508 TAS2770_TDMConfigurationReg2,
509 TAS2770_TDMConfigurationReg2_RXSLEN10_Mask,
510 TAS2770_TDMConfigurationReg2_RXSLEN10_32Bits);
511 break;
513 case 0:
514 /* Do not change slot width */
515 break;
517 default:
518 dev_dbg(pTAS2770->dev, "slot width not supported");
519 ret = -EINVAL;
520 }
522 if (ret >= 0)
523 pTAS2770->mnSlot_width = slot_width;
525 return ret;
526 }
528 static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai,
529 unsigned int tx_mask, unsigned int rx_mask,
530 int slots, int slot_width)
531 {
532 int ret = 0;
533 struct snd_soc_codec *codec = dai->codec;
534 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
536 dev_dbg(pTAS2770->dev, "%s, tx_mask:%d, rx_mask:%d, slots:%d, slot_width:%d",
537 __func__, tx_mask, rx_mask, slots, slot_width);
539 mutex_lock(&pTAS2770->codec_lock);
540 ret = tas2770_set_slot(codec, slot_width);
541 mutex_unlock(&pTAS2770->codec_lock);
543 return ret;
544 }
546 static struct snd_soc_dai_ops tas2770_dai_ops = {
547 .digital_mute = tas2770_mute,
548 .hw_params = tas2770_hw_params,
549 .set_fmt = tas2770_set_dai_fmt,
550 .set_tdm_slot = tas2770_set_dai_tdm_slot,
551 };
553 #define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
554 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
556 #define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
557 SNDRV_PCM_RATE_96000 |\
558 SNDRV_PCM_RATE_192000\
559 )
561 static struct snd_soc_dai_driver tas2770_dai_driver[] = {
562 {
563 .name = "tas2770 ASI1",
564 .id = 0,
565 .playback = {
566 .stream_name = "ASI1 Playback",
567 .channels_min = 2,
568 .channels_max = 2,
569 .rates = TAS2770_RATES,
570 .formats = TAS2770_FORMATS,
571 },
572 .capture = {
573 .stream_name = "ASI1 Capture",
574 .channels_min = 0,
575 .channels_max = 2,
576 .rates = TAS2770_RATES,
577 .formats = TAS2770_FORMATS,
578 },
579 .ops = &tas2770_dai_ops,
580 .symmetric_rates = 1,
581 },
582 };
584 static int tas2770_codec_probe(struct snd_soc_codec *codec)
585 {
586 struct tas2770_priv *pTAS2770 = snd_soc_codec_get_drvdata(codec);
588 dev_err(pTAS2770->dev, "%s\n", __func__);
589 pTAS2770->codec = codec;
591 return 0;
592 }
594 static int tas2770_codec_remove(struct snd_soc_codec *codec)
595 {
596 return 0;
597 }
599 static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
600 static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);
602 static const struct snd_kcontrol_new tas2770_snd_controls[] = {
603 SOC_SINGLE_TLV("Amp Output Level", TAS2770_PlaybackConfigurationReg0,
604 0, 0x14, 0,
605 tas2770_digital_tlv),
606 SOC_SINGLE_TLV("Playback Volume", TAS2770_PlaybackConfigurationReg2,
607 0, TAS2770_PlaybackConfigurationReg2_VOLMAX, 1,
608 tas2770_playback_volume),
609 };
611 static struct snd_soc_codec_driver soc_codec_driver_tas2770 = {
612 .probe = tas2770_codec_probe,
613 .remove = tas2770_codec_remove,
614 .read = tas2770_codec_read,
615 .write = tas2770_codec_write,
616 .suspend = tas2770_codec_suspend,
617 .resume = tas2770_codec_resume,
618 .component_driver = {
619 .controls = tas2770_snd_controls,
620 .num_controls = ARRAY_SIZE(tas2770_snd_controls),
621 .dapm_widgets = tas2770_dapm_widgets,
622 .num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets),
623 .dapm_routes = tas2770_audio_map,
624 .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map),
625 },
626 };
628 int tas2770_register_codec(struct tas2770_priv *pTAS2770)
629 {
630 int nResult = 0;
632 dev_info(pTAS2770->dev, "%s, enter\n", __func__);
633 nResult = snd_soc_register_codec(pTAS2770->dev,
634 &soc_codec_driver_tas2770,
635 tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver));
637 return nResult;
638 }
640 int tas2770_deregister_codec(struct tas2770_priv *pTAS2770)
641 {
642 snd_soc_unregister_codec(pTAS2770->dev);
644 return 0;
645 }
647 void tas2770_LoadConfig(struct tas2770_priv *pTAS2770)
648 {
649 int ret = 0;
651 pTAS2770->hw_reset(pTAS2770);
652 snd_soc_write(pTAS2770->codec, TAS2770_SoftwareReset,
653 TAS2770_SoftwareReset_SoftwareReset_Reset);
655 ret = tas2770_set_slot(pTAS2770->codec, pTAS2770->mnSlot_width);
656 if (ret < 0)
657 goto end;
659 ret = tas2770_set_fmt(pTAS2770, pTAS2770->mnASIFormat);
660 if (ret < 0)
661 goto end;
663 ret = tas2770_set_bitwidth(pTAS2770, pTAS2770->mnCh_size);
664 if (ret < 0)
665 goto end;
667 ret = tas2770_set_samplerate(pTAS2770, pTAS2770->mnSamplingRate);
668 if (ret < 0)
669 goto end;
671 ret = tas2770_set_power_state(pTAS2770, pTAS2770->mnPowerState);
673 end:
674 /* power up failed, restart later */
675 if (ret < 0)
676 schedule_delayed_work(&pTAS2770->irq_work,
677 msecs_to_jiffies(1000));
678 }
680 MODULE_AUTHOR("Texas Instruments Inc.");
681 MODULE_DESCRIPTION("TAS2770 ALSA SOC Smart Amplifier driver");
682 MODULE_LICENSE("GPL v2");
683 #endif /* CONFIG_TAS2770_CODEC */