aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Yushchenko <nikita.yoush@cogentembedded.com>2016-09-23 07:52:52 -0400
committerMark Brown <broonie@kernel.org>2016-09-26 12:42:27 -0400
commitef9656b6936fb7f66e7e25d284c955f4893ac421 (patch)
treedaadc3a815e6b5ca88b7373445ff25e1ab3349a1
parent8180bd56bdd1dcade8d1b2a0b6f70b2397bec372 (diff)
ASoC: tlv320aic31xx: add explicit support for tlv320dac31xx
tlv320dac31xx is a subset of tlv320aic31xx: - it does not have MIC inputs and ADC, thus capture is not supported, - it has analog inputs AIN1/AIN2 that can be mixed into output. Although tlv320dac31xx does work with tlv320aic31xx driver, this setup does register non-existent widgets and non-existent capture stream. Thus userspace lists non-existent objects in user interfaces, an can access these, causing operations with device registers that are declared as "reserved" in tlv320dac31xx datasheet. This patch fixes this situation by separating controls/widgets/routes into common, aic31xx-specific, and dac31xx-specific parts. Only parts that match actual hardware (as declared in "compatible" device tree property) are registered. Changes from v1: - update device tree binding documentation, - rebased on top of "ASoC: codec duplicated callback function goes to component on tlv320aic31xx" commit. Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic31xx.txt9
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c212
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h2
3 files changed, 164 insertions, 59 deletions
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
index eff12be5e789..9340d2ddcc54 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -11,6 +11,7 @@ Required properties:
11 "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP) 11 "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
12 "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP) 12 "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
13 "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP) 13 "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
14 "ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP)
14 15
15- reg - <int> - I2C slave address 16- reg - <int> - I2C slave address
16- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply, 17- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
@@ -37,9 +38,11 @@ CODEC output pins:
37 * MICBIAS 38 * MICBIAS
38 39
39CODEC input pins: 40CODEC input pins:
40 * MIC1LP 41 * MIC1LP, devices with ADC
41 * MIC1RP 42 * MIC1RP, devices with ADC
42 * MIC1LM 43 * MIC1LM, devices with ADC
44 * AIN1, devices without ADC
45 * AIN2, devices without ADC
43 46
44The pins can be used in referring sound node's audio-routing property. 47The pins can be used in referring sound node's audio-routing property.
45 48
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index e46fb472e48d..725173b12725 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -273,10 +273,20 @@ static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
273/* 273/*
274 * controls to be exported to the user space 274 * controls to be exported to the user space
275 */ 275 */
276static const struct snd_kcontrol_new aic31xx_snd_controls[] = { 276static const struct snd_kcontrol_new common31xx_snd_controls[] = {
277 SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL, 277 SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
278 AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv), 278 AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
279 279
280 SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
281 AIC31XX_HPRGAIN, 2, 1, 0),
282 SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
283 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
284
285 SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
286 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
287};
288
289static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
280 SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1, 290 SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
281 adc_fgain_tlv), 291 adc_fgain_tlv),
282 292
@@ -286,14 +296,6 @@ static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
286 296
287 SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0, 297 SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
288 119, 0, mic_pga_tlv), 298 119, 0, mic_pga_tlv),
289
290 SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
291 AIC31XX_HPRGAIN, 2, 1, 0),
292 SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
293 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
294
295 SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
296 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
297}; 299};
298 300
299static const struct snd_kcontrol_new aic311x_snd_controls[] = { 301static const struct snd_kcontrol_new aic311x_snd_controls[] = {
@@ -397,17 +399,28 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
397 return 0; 399 return 0;
398} 400}
399 401
400static const struct snd_kcontrol_new left_output_switches[] = { 402static const struct snd_kcontrol_new aic31xx_left_output_switches[] = {
401 SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0), 403 SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
402 SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0), 404 SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
403 SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0), 405 SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
404}; 406};
405 407
406static const struct snd_kcontrol_new right_output_switches[] = { 408static const struct snd_kcontrol_new aic31xx_right_output_switches[] = {
407 SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0), 409 SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
408 SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0), 410 SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
409}; 411};
410 412
413static const struct snd_kcontrol_new dac31xx_left_output_switches[] = {
414 SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
415 SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0),
416 SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0),
417};
418
419static const struct snd_kcontrol_new dac31xx_right_output_switches[] = {
420 SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
421 SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 1, 1, 0),
422};
423
411static const struct snd_kcontrol_new p_term_mic1lp = 424static const struct snd_kcontrol_new p_term_mic1lp =
412 SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum); 425 SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
413 426
@@ -457,7 +470,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
457 return 0; 470 return 0;
458} 471}
459 472
460static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = { 473static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
461 SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), 474 SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
462 475
463 SND_SOC_DAPM_MUX("DAC Left Input", 476 SND_SOC_DAPM_MUX("DAC Left Input",
@@ -473,14 +486,7 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
473 AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event, 486 AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
474 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 487 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
475 488
476 /* Output Mixers */ 489 /* HP */
477 SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
478 left_output_switches,
479 ARRAY_SIZE(left_output_switches)),
480 SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
481 right_output_switches,
482 ARRAY_SIZE(right_output_switches)),
483
484 SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0, 490 SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
485 &aic31xx_dapm_hpl_switch), 491 &aic31xx_dapm_hpl_switch),
486 SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0, 492 SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
@@ -494,10 +500,34 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
494 NULL, 0, aic31xx_dapm_power_event, 500 NULL, 0, aic31xx_dapm_power_event,
495 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), 501 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
496 502
497 /* ADC */ 503 /* Mic Bias */
498 SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0, 504 SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
499 aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU | 505 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
500 SND_SOC_DAPM_POST_PMD), 506
507 /* Outputs */
508 SND_SOC_DAPM_OUTPUT("HPL"),
509 SND_SOC_DAPM_OUTPUT("HPR"),
510};
511
512static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = {
513 /* Inputs */
514 SND_SOC_DAPM_INPUT("AIN1"),
515 SND_SOC_DAPM_INPUT("AIN2"),
516
517 /* Output Mixers */
518 SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
519 dac31xx_left_output_switches,
520 ARRAY_SIZE(dac31xx_left_output_switches)),
521 SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
522 dac31xx_right_output_switches,
523 ARRAY_SIZE(dac31xx_right_output_switches)),
524};
525
526static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
527 /* Inputs */
528 SND_SOC_DAPM_INPUT("MIC1LP"),
529 SND_SOC_DAPM_INPUT("MIC1RP"),
530 SND_SOC_DAPM_INPUT("MIC1LM"),
501 531
502 /* Input Selection to MIC_PGA */ 532 /* Input Selection to MIC_PGA */
503 SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0, 533 SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
@@ -507,24 +537,25 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
507 SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0, 537 SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
508 &p_term_mic1lm), 538 &p_term_mic1lm),
509 539
540 /* ADC */
541 SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
542 aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
543 SND_SOC_DAPM_POST_PMD),
544
510 SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0, 545 SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
511 &m_term_mic1lm), 546 &m_term_mic1lm),
547
512 /* Enabling & Disabling MIC Gain Ctl */ 548 /* Enabling & Disabling MIC Gain Ctl */
513 SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA, 549 SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
514 7, 1, NULL, 0), 550 7, 1, NULL, 0),
515 551
516 /* Mic Bias */ 552 /* Output Mixers */
517 SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event, 553 SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
518 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 554 aic31xx_left_output_switches,
519 555 ARRAY_SIZE(aic31xx_left_output_switches)),
520 /* Outputs */ 556 SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
521 SND_SOC_DAPM_OUTPUT("HPL"), 557 aic31xx_right_output_switches,
522 SND_SOC_DAPM_OUTPUT("HPR"), 558 ARRAY_SIZE(aic31xx_right_output_switches)),
523
524 /* Inputs */
525 SND_SOC_DAPM_INPUT("MIC1LP"),
526 SND_SOC_DAPM_INPUT("MIC1RP"),
527 SND_SOC_DAPM_INPUT("MIC1LM"),
528}; 559};
529 560
530static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = { 561static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
@@ -554,7 +585,7 @@ static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
554}; 585};
555 586
556static const struct snd_soc_dapm_route 587static const struct snd_soc_dapm_route
557aic31xx_audio_map[] = { 588common31xx_audio_map[] = {
558 /* DAC Input Routing */ 589 /* DAC Input Routing */
559 {"DAC Left Input", "Left Data", "DAC IN"}, 590 {"DAC Left Input", "Left Data", "DAC IN"},
560 {"DAC Left Input", "Right Data", "DAC IN"}, 591 {"DAC Left Input", "Right Data", "DAC IN"},
@@ -565,6 +596,31 @@ aic31xx_audio_map[] = {
565 {"DAC Left", NULL, "DAC Left Input"}, 596 {"DAC Left", NULL, "DAC Left Input"},
566 {"DAC Right", NULL, "DAC Right Input"}, 597 {"DAC Right", NULL, "DAC Right Input"},
567 598
599 /* HPL path */
600 {"HP Left", "Switch", "Output Left"},
601 {"HPL Driver", NULL, "HP Left"},
602 {"HPL", NULL, "HPL Driver"},
603
604 /* HPR path */
605 {"HP Right", "Switch", "Output Right"},
606 {"HPR Driver", NULL, "HP Right"},
607 {"HPR", NULL, "HPR Driver"},
608};
609
610static const struct snd_soc_dapm_route
611dac31xx_audio_map[] = {
612 /* Left Output */
613 {"Output Left", "From Left DAC", "DAC Left"},
614 {"Output Left", "From AIN1", "AIN1"},
615 {"Output Left", "From AIN2", "AIN2"},
616
617 /* Right Output */
618 {"Output Right", "From Right DAC", "DAC Right"},
619 {"Output Right", "From AIN2", "AIN2"},
620};
621
622static const struct snd_soc_dapm_route
623aic31xx_audio_map[] = {
568 /* Mic input */ 624 /* Mic input */
569 {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"}, 625 {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
570 {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"}, 626 {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
@@ -595,16 +651,6 @@ aic31xx_audio_map[] = {
595 /* Right Output */ 651 /* Right Output */
596 {"Output Right", "From Right DAC", "DAC Right"}, 652 {"Output Right", "From Right DAC", "DAC Right"},
597 {"Output Right", "From MIC1RP", "MIC1RP"}, 653 {"Output Right", "From MIC1RP", "MIC1RP"},
598
599 /* HPL path */
600 {"HP Left", "Switch", "Output Left"},
601 {"HPL Driver", NULL, "HP Left"},
602 {"HPL", NULL, "HPL Driver"},
603
604 /* HPR path */
605 {"HP Right", "Switch", "Output Right"},
606 {"HPR Driver", NULL, "HP Right"},
607 {"HPR", NULL, "HPR Driver"},
608}; 654};
609 655
610static const struct snd_soc_dapm_route 656static const struct snd_soc_dapm_route
@@ -633,6 +679,13 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
633 int ret = 0; 679 int ret = 0;
634 struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); 680 struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
635 681
682 if (!(aic31xx->pdata.codec_type & DAC31XX_BIT))
683 ret = snd_soc_add_codec_controls(
684 codec, aic31xx_snd_controls,
685 ARRAY_SIZE(aic31xx_snd_controls));
686 if (ret)
687 return ret;
688
636 if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) 689 if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
637 ret = snd_soc_add_codec_controls( 690 ret = snd_soc_add_codec_controls(
638 codec, aic311x_snd_controls, 691 codec, aic311x_snd_controls,
@@ -651,6 +704,30 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
651 struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); 704 struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
652 int ret = 0; 705 int ret = 0;
653 706
707 if (aic31xx->pdata.codec_type & DAC31XX_BIT) {
708 ret = snd_soc_dapm_new_controls(
709 dapm, dac31xx_dapm_widgets,
710 ARRAY_SIZE(dac31xx_dapm_widgets));
711 if (ret)
712 return ret;
713
714 ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map,
715 ARRAY_SIZE(dac31xx_audio_map));
716 if (ret)
717 return ret;
718 } else {
719 ret = snd_soc_dapm_new_controls(
720 dapm, aic31xx_dapm_widgets,
721 ARRAY_SIZE(aic31xx_dapm_widgets));
722 if (ret)
723 return ret;
724
725 ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map,
726 ARRAY_SIZE(aic31xx_audio_map));
727 if (ret)
728 return ret;
729 }
730
654 if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { 731 if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
655 ret = snd_soc_dapm_new_controls( 732 ret = snd_soc_dapm_new_controls(
656 dapm, aic311x_dapm_widgets, 733 dapm, aic311x_dapm_widgets,
@@ -1115,12 +1192,12 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
1115 .suspend_bias_off = true, 1192 .suspend_bias_off = true,
1116 1193
1117 .component_driver = { 1194 .component_driver = {
1118 .controls = aic31xx_snd_controls, 1195 .controls = common31xx_snd_controls,
1119 .num_controls = ARRAY_SIZE(aic31xx_snd_controls), 1196 .num_controls = ARRAY_SIZE(common31xx_snd_controls),
1120 .dapm_widgets = aic31xx_dapm_widgets, 1197 .dapm_widgets = common31xx_dapm_widgets,
1121 .num_dapm_widgets = ARRAY_SIZE(aic31xx_dapm_widgets), 1198 .num_dapm_widgets = ARRAY_SIZE(common31xx_dapm_widgets),
1122 .dapm_routes = aic31xx_audio_map, 1199 .dapm_routes = common31xx_audio_map,
1123 .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map), 1200 .num_dapm_routes = ARRAY_SIZE(common31xx_audio_map),
1124 }, 1201 },
1125}; 1202};
1126 1203
@@ -1131,6 +1208,21 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = {
1131 .digital_mute = aic31xx_dac_mute, 1208 .digital_mute = aic31xx_dac_mute,
1132}; 1209};
1133 1210
1211static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
1212 {
1213 .name = "tlv32dac31xx-hifi",
1214 .playback = {
1215 .stream_name = "Playback",
1216 .channels_min = 1,
1217 .channels_max = 2,
1218 .rates = AIC31XX_RATES,
1219 .formats = AIC31XX_FORMATS,
1220 },
1221 .ops = &aic31xx_dai_ops,
1222 .symmetric_rates = 1,
1223 }
1224};
1225
1134static struct snd_soc_dai_driver aic31xx_dai_driver[] = { 1226static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
1135 { 1227 {
1136 .name = "tlv320aic31xx-hifi", 1228 .name = "tlv320aic31xx-hifi",
@@ -1261,9 +1353,16 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
1261 if (ret) 1353 if (ret)
1262 return ret; 1354 return ret;
1263 1355
1264 return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, 1356 if (aic31xx->pdata.codec_type & DAC31XX_BIT)
1265 aic31xx_dai_driver, 1357 return snd_soc_register_codec(&i2c->dev,
1266 ARRAY_SIZE(aic31xx_dai_driver)); 1358 &soc_codec_driver_aic31xx,
1359 dac31xx_dai_driver,
1360 ARRAY_SIZE(dac31xx_dai_driver));
1361 else
1362 return snd_soc_register_codec(&i2c->dev,
1363 &soc_codec_driver_aic31xx,
1364 aic31xx_dai_driver,
1365 ARRAY_SIZE(aic31xx_dai_driver));
1267} 1366}
1268 1367
1269static int aic31xx_i2c_remove(struct i2c_client *i2c) 1368static int aic31xx_i2c_remove(struct i2c_client *i2c)
@@ -1279,6 +1378,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
1279 { "tlv320aic3110", AIC3110 }, 1378 { "tlv320aic3110", AIC3110 },
1280 { "tlv320aic3120", AIC3120 }, 1379 { "tlv320aic3120", AIC3120 },
1281 { "tlv320aic3111", AIC3111 }, 1380 { "tlv320aic3111", AIC3111 },
1381 { "tlv320dac3100", DAC3100 },
1282 { } 1382 { }
1283}; 1383};
1284MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); 1384MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index ac9b146526eb..5acd5b69fb83 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -24,12 +24,14 @@
24 24
25#define AIC31XX_STEREO_CLASS_D_BIT 0x1 25#define AIC31XX_STEREO_CLASS_D_BIT 0x1
26#define AIC31XX_MINIDSP_BIT 0x2 26#define AIC31XX_MINIDSP_BIT 0x2
27#define DAC31XX_BIT 0x4
27 28
28enum aic31xx_type { 29enum aic31xx_type {
29 AIC3100 = 0, 30 AIC3100 = 0,
30 AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, 31 AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
31 AIC3120 = AIC31XX_MINIDSP_BIT, 32 AIC3120 = AIC31XX_MINIDSP_BIT,
32 AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), 33 AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
34 DAC3100 = DAC31XX_BIT,
33}; 35};
34 36
35struct aic31xx_pdata { 37struct aic31xx_pdata {