diff options
Diffstat (limited to 'sound/soc/codecs/wm8580.c')
-rw-r--r-- | sound/soc/codecs/wm8580.c | 340 |
1 files changed, 161 insertions, 179 deletions
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 72deeabef4fe..4bbc0a79f01e 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
33 | #include <sound/soc.h> | 33 | #include <sound/soc.h> |
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/tlv.h> | 34 | #include <sound/tlv.h> |
36 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
37 | #include <asm/div64.h> | 36 | #include <asm/div64.h> |
@@ -94,6 +93,8 @@ | |||
94 | 93 | ||
95 | #define WM8580_MAX_REGISTER 0x35 | 94 | #define WM8580_MAX_REGISTER 0x35 |
96 | 95 | ||
96 | #define WM8580_DACOSR 0x40 | ||
97 | |||
97 | /* PLLB4 (register 7h) */ | 98 | /* PLLB4 (register 7h) */ |
98 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | 99 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 |
99 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | 100 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 |
@@ -112,19 +113,7 @@ | |||
112 | 113 | ||
113 | /* AIF control 1 (registers 9h-bh) */ | 114 | /* AIF control 1 (registers 9h-bh) */ |
114 | #define WM8580_AIF_RATE_MASK 0x7 | 115 | #define WM8580_AIF_RATE_MASK 0x7 |
115 | #define WM8580_AIF_RATE_128 0x0 | ||
116 | #define WM8580_AIF_RATE_192 0x1 | ||
117 | #define WM8580_AIF_RATE_256 0x2 | ||
118 | #define WM8580_AIF_RATE_384 0x3 | ||
119 | #define WM8580_AIF_RATE_512 0x4 | ||
120 | #define WM8580_AIF_RATE_768 0x5 | ||
121 | #define WM8580_AIF_RATE_1152 0x6 | ||
122 | |||
123 | #define WM8580_AIF_BCLKSEL_MASK 0x18 | 116 | #define WM8580_AIF_BCLKSEL_MASK 0x18 |
124 | #define WM8580_AIF_BCLKSEL_64 0x00 | ||
125 | #define WM8580_AIF_BCLKSEL_128 0x08 | ||
126 | #define WM8580_AIF_BCLKSEL_256 0x10 | ||
127 | #define WM8580_AIF_BCLKSEL_SYSCLK 0x18 | ||
128 | 117 | ||
129 | #define WM8580_AIF_MS 0x20 | 118 | #define WM8580_AIF_MS 0x20 |
130 | 119 | ||
@@ -171,7 +160,7 @@ | |||
171 | static const u16 wm8580_reg[] = { | 160 | static const u16 wm8580_reg[] = { |
172 | 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ | 161 | 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ |
173 | 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ | 162 | 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ |
174 | 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/ | 163 | 0x0010, 0x0002, 0x0002, 0x00c2, /*R11*/ |
175 | 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ | 164 | 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ |
176 | 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ | 165 | 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ |
177 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ | 166 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ |
@@ -199,11 +188,11 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { | |||
199 | 188 | ||
200 | /* codec private data */ | 189 | /* codec private data */ |
201 | struct wm8580_priv { | 190 | struct wm8580_priv { |
202 | struct snd_soc_codec codec; | 191 | enum snd_soc_control_type control_type; |
203 | struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; | 192 | struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; |
204 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; | ||
205 | struct pll_state a; | 193 | struct pll_state a; |
206 | struct pll_state b; | 194 | struct pll_state b; |
195 | int sysclk[2]; | ||
207 | }; | 196 | }; |
208 | 197 | ||
209 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | 198 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); |
@@ -273,8 +262,8 @@ SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1), | |||
273 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1), | 262 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1), |
274 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1), | 263 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1), |
275 | 264 | ||
276 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | 265 | SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1), |
277 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 266 | SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
278 | }; | 267 | }; |
279 | 268 | ||
280 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | 269 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { |
@@ -311,10 +300,11 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
311 | 300 | ||
312 | static int wm8580_add_widgets(struct snd_soc_codec *codec) | 301 | static int wm8580_add_widgets(struct snd_soc_codec *codec) |
313 | { | 302 | { |
314 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets, | 303 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
315 | ARRAY_SIZE(wm8580_dapm_widgets)); | ||
316 | 304 | ||
317 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 305 | snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets, |
306 | ARRAY_SIZE(wm8580_dapm_widgets)); | ||
307 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
318 | 308 | ||
319 | return 0; | 309 | return 0; |
320 | } | 310 | } |
@@ -476,6 +466,10 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | |||
476 | return 0; | 466 | return 0; |
477 | } | 467 | } |
478 | 468 | ||
469 | static const int wm8580_sysclk_ratios[] = { | ||
470 | 128, 192, 256, 384, 512, 768, 1152, | ||
471 | }; | ||
472 | |||
479 | /* | 473 | /* |
480 | * Set PCM DAI bit size and sample rate. | 474 | * Set PCM DAI bit size and sample rate. |
481 | */ | 475 | */ |
@@ -484,29 +478,68 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | |||
484 | struct snd_soc_dai *dai) | 478 | struct snd_soc_dai *dai) |
485 | { | 479 | { |
486 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 480 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
487 | struct snd_soc_device *socdev = rtd->socdev; | 481 | struct snd_soc_codec *codec = rtd->codec; |
488 | struct snd_soc_codec *codec = socdev->card->codec; | 482 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); |
489 | u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id); | 483 | u16 paifa = 0; |
484 | u16 paifb = 0; | ||
485 | int i, ratio, osr; | ||
490 | 486 | ||
491 | paifb &= ~WM8580_AIF_LENGTH_MASK; | ||
492 | /* bit size */ | 487 | /* bit size */ |
493 | switch (params_format(params)) { | 488 | switch (params_format(params)) { |
494 | case SNDRV_PCM_FORMAT_S16_LE: | 489 | case SNDRV_PCM_FORMAT_S16_LE: |
490 | paifa |= 0x8; | ||
495 | break; | 491 | break; |
496 | case SNDRV_PCM_FORMAT_S20_3LE: | 492 | case SNDRV_PCM_FORMAT_S20_3LE: |
493 | paifa |= 0x0; | ||
497 | paifb |= WM8580_AIF_LENGTH_20; | 494 | paifb |= WM8580_AIF_LENGTH_20; |
498 | break; | 495 | break; |
499 | case SNDRV_PCM_FORMAT_S24_LE: | 496 | case SNDRV_PCM_FORMAT_S24_LE: |
497 | paifa |= 0x0; | ||
500 | paifb |= WM8580_AIF_LENGTH_24; | 498 | paifb |= WM8580_AIF_LENGTH_24; |
501 | break; | 499 | break; |
502 | case SNDRV_PCM_FORMAT_S32_LE: | 500 | case SNDRV_PCM_FORMAT_S32_LE: |
503 | paifb |= WM8580_AIF_LENGTH_24; | 501 | paifa |= 0x0; |
502 | paifb |= WM8580_AIF_LENGTH_32; | ||
504 | break; | 503 | break; |
505 | default: | 504 | default: |
506 | return -EINVAL; | 505 | return -EINVAL; |
507 | } | 506 | } |
508 | 507 | ||
509 | snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb); | 508 | /* Look up the SYSCLK ratio; accept only exact matches */ |
509 | ratio = wm8580->sysclk[dai->driver->id] / params_rate(params); | ||
510 | for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++) | ||
511 | if (ratio == wm8580_sysclk_ratios[i]) | ||
512 | break; | ||
513 | if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) { | ||
514 | dev_err(codec->dev, "Invalid clock ratio %d/%d\n", | ||
515 | wm8580->sysclk[dai->driver->id], params_rate(params)); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | paifa |= i; | ||
519 | dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n", | ||
520 | wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]); | ||
521 | |||
522 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
523 | switch (ratio) { | ||
524 | case 128: | ||
525 | case 192: | ||
526 | osr = WM8580_DACOSR; | ||
527 | dev_dbg(codec->dev, "Selecting 64x OSR\n"); | ||
528 | break; | ||
529 | default: | ||
530 | osr = 0; | ||
531 | dev_dbg(codec->dev, "Selecting 128x OSR\n"); | ||
532 | break; | ||
533 | } | ||
534 | |||
535 | snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr); | ||
536 | } | ||
537 | |||
538 | snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id, | ||
539 | WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK, | ||
540 | paifa); | ||
541 | snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id, | ||
542 | WM8580_AIF_LENGTH_MASK, paifb); | ||
510 | return 0; | 543 | return 0; |
511 | } | 544 | } |
512 | 545 | ||
@@ -518,8 +551,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, | |||
518 | unsigned int aifb; | 551 | unsigned int aifb; |
519 | int can_invert_lrclk; | 552 | int can_invert_lrclk; |
520 | 553 | ||
521 | aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id); | 554 | aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id); |
522 | aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id); | 555 | aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id); |
523 | 556 | ||
524 | aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); | 557 | aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); |
525 | 558 | ||
@@ -585,8 +618,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, | |||
585 | return -EINVAL; | 618 | return -EINVAL; |
586 | } | 619 | } |
587 | 620 | ||
588 | snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); | 621 | snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa); |
589 | snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); | 622 | snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb); |
590 | 623 | ||
591 | return 0; | 624 | return 0; |
592 | } | 625 | } |
@@ -624,28 +657,6 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
624 | snd_soc_write(codec, WM8580_PLLB4, reg); | 657 | snd_soc_write(codec, WM8580_PLLB4, reg); |
625 | break; | 658 | break; |
626 | 659 | ||
627 | case WM8580_DAC_CLKSEL: | ||
628 | reg = snd_soc_read(codec, WM8580_CLKSEL); | ||
629 | reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; | ||
630 | |||
631 | switch (div) { | ||
632 | case WM8580_CLKSRC_MCLK: | ||
633 | break; | ||
634 | |||
635 | case WM8580_CLKSRC_PLLA: | ||
636 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA; | ||
637 | break; | ||
638 | |||
639 | case WM8580_CLKSRC_PLLB: | ||
640 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB; | ||
641 | break; | ||
642 | |||
643 | default: | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | snd_soc_write(codec, WM8580_CLKSEL, reg); | ||
647 | break; | ||
648 | |||
649 | case WM8580_CLKOUTSRC: | 660 | case WM8580_CLKOUTSRC: |
650 | reg = snd_soc_read(codec, WM8580_PLLB4); | 661 | reg = snd_soc_read(codec, WM8580_PLLB4); |
651 | reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; | 662 | reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; |
@@ -679,6 +690,55 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
679 | return 0; | 690 | return 0; |
680 | } | 691 | } |
681 | 692 | ||
693 | static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
694 | unsigned int freq, int dir) | ||
695 | { | ||
696 | struct snd_soc_codec *codec = dai->codec; | ||
697 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); | ||
698 | int sel, sel_mask, sel_shift; | ||
699 | |||
700 | switch (dai->driver->id) { | ||
701 | case WM8580_DAI_PAIFRX: | ||
702 | sel_mask = 0x3; | ||
703 | sel_shift = 0; | ||
704 | break; | ||
705 | |||
706 | case WM8580_DAI_PAIFTX: | ||
707 | sel_mask = 0xc; | ||
708 | sel_shift = 2; | ||
709 | break; | ||
710 | |||
711 | default: | ||
712 | BUG_ON("Unknown DAI driver ID\n"); | ||
713 | return -EINVAL; | ||
714 | } | ||
715 | |||
716 | switch (clk_id) { | ||
717 | case WM8580_CLKSRC_ADCMCLK: | ||
718 | if (dai->driver->id != WM8580_DAI_PAIFTX) | ||
719 | return -EINVAL; | ||
720 | sel = 0 << sel_shift; | ||
721 | break; | ||
722 | case WM8580_CLKSRC_PLLA: | ||
723 | sel = 1 << sel_shift; | ||
724 | break; | ||
725 | case WM8580_CLKSRC_PLLB: | ||
726 | sel = 2 << sel_shift; | ||
727 | break; | ||
728 | case WM8580_CLKSRC_MCLK: | ||
729 | sel = 3 << sel_shift; | ||
730 | break; | ||
731 | default: | ||
732 | dev_err(codec->dev, "Unknown clock %d\n", clk_id); | ||
733 | return -EINVAL; | ||
734 | } | ||
735 | |||
736 | /* We really should validate PLL settings but not yet */ | ||
737 | wm8580->sysclk[dai->driver->id] = freq; | ||
738 | |||
739 | return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel); | ||
740 | } | ||
741 | |||
682 | static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) | 742 | static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) |
683 | { | 743 | { |
684 | struct snd_soc_codec *codec = codec_dai->codec; | 744 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -706,13 +766,13 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
706 | break; | 766 | break; |
707 | 767 | ||
708 | case SND_SOC_BIAS_STANDBY: | 768 | case SND_SOC_BIAS_STANDBY: |
709 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 769 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
710 | /* Power up and get individual control of the DACs */ | 770 | /* Power up and get individual control of the DACs */ |
711 | reg = snd_soc_read(codec, WM8580_PWRDN1); | 771 | reg = snd_soc_read(codec, WM8580_PWRDN1); |
712 | reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); | 772 | reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); |
713 | snd_soc_write(codec, WM8580_PWRDN1, reg); | 773 | snd_soc_write(codec, WM8580_PWRDN1, reg); |
714 | 774 | ||
715 | /* Make VMID high impedence */ | 775 | /* Make VMID high impedance */ |
716 | reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); | 776 | reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); |
717 | reg &= ~0x100; | 777 | reg &= ~0x100; |
718 | snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); | 778 | snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); |
@@ -724,7 +784,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
724 | snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | 784 | snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); |
725 | break; | 785 | break; |
726 | } | 786 | } |
727 | codec->bias_level = level; | 787 | codec->dapm.bias_level = level; |
728 | return 0; | 788 | return 0; |
729 | } | 789 | } |
730 | 790 | ||
@@ -732,6 +792,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
732 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 792 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
733 | 793 | ||
734 | static struct snd_soc_dai_ops wm8580_dai_ops_playback = { | 794 | static struct snd_soc_dai_ops wm8580_dai_ops_playback = { |
795 | .set_sysclk = wm8580_set_sysclk, | ||
735 | .hw_params = wm8580_paif_hw_params, | 796 | .hw_params = wm8580_paif_hw_params, |
736 | .set_fmt = wm8580_set_paif_dai_fmt, | 797 | .set_fmt = wm8580_set_paif_dai_fmt, |
737 | .set_clkdiv = wm8580_set_dai_clkdiv, | 798 | .set_clkdiv = wm8580_set_dai_clkdiv, |
@@ -740,16 +801,17 @@ static struct snd_soc_dai_ops wm8580_dai_ops_playback = { | |||
740 | }; | 801 | }; |
741 | 802 | ||
742 | static struct snd_soc_dai_ops wm8580_dai_ops_capture = { | 803 | static struct snd_soc_dai_ops wm8580_dai_ops_capture = { |
804 | .set_sysclk = wm8580_set_sysclk, | ||
743 | .hw_params = wm8580_paif_hw_params, | 805 | .hw_params = wm8580_paif_hw_params, |
744 | .set_fmt = wm8580_set_paif_dai_fmt, | 806 | .set_fmt = wm8580_set_paif_dai_fmt, |
745 | .set_clkdiv = wm8580_set_dai_clkdiv, | 807 | .set_clkdiv = wm8580_set_dai_clkdiv, |
746 | .set_pll = wm8580_set_dai_pll, | 808 | .set_pll = wm8580_set_dai_pll, |
747 | }; | 809 | }; |
748 | 810 | ||
749 | struct snd_soc_dai wm8580_dai[] = { | 811 | static struct snd_soc_dai_driver wm8580_dai[] = { |
750 | { | 812 | { |
751 | .name = "WM8580 PAIFRX", | 813 | .name = "wm8580-hifi-playback", |
752 | .id = 0, | 814 | .id = WM8580_DAI_PAIFRX, |
753 | .playback = { | 815 | .playback = { |
754 | .stream_name = "Playback", | 816 | .stream_name = "Playback", |
755 | .channels_min = 1, | 817 | .channels_min = 1, |
@@ -760,8 +822,8 @@ struct snd_soc_dai wm8580_dai[] = { | |||
760 | .ops = &wm8580_dai_ops_playback, | 822 | .ops = &wm8580_dai_ops_playback, |
761 | }, | 823 | }, |
762 | { | 824 | { |
763 | .name = "WM8580 PAIFTX", | 825 | .name = "wm8580-hifi-capture", |
764 | .id = 1, | 826 | .id = WM8580_DAI_PAIFTX, |
765 | .capture = { | 827 | .capture = { |
766 | .stream_name = "Capture", | 828 | .stream_name = "Capture", |
767 | .channels_min = 2, | 829 | .channels_min = 2, |
@@ -772,90 +834,16 @@ struct snd_soc_dai wm8580_dai[] = { | |||
772 | .ops = &wm8580_dai_ops_capture, | 834 | .ops = &wm8580_dai_ops_capture, |
773 | }, | 835 | }, |
774 | }; | 836 | }; |
775 | EXPORT_SYMBOL_GPL(wm8580_dai); | ||
776 | |||
777 | static struct snd_soc_codec *wm8580_codec; | ||
778 | |||
779 | static int wm8580_probe(struct platform_device *pdev) | ||
780 | { | ||
781 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
782 | struct snd_soc_codec *codec; | ||
783 | int ret = 0; | ||
784 | |||
785 | if (wm8580_codec == NULL) { | ||
786 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
787 | return -ENODEV; | ||
788 | } | ||
789 | |||
790 | socdev->card->codec = wm8580_codec; | ||
791 | codec = wm8580_codec; | ||
792 | |||
793 | /* register pcms */ | ||
794 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
795 | if (ret < 0) { | ||
796 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
797 | goto pcm_err; | ||
798 | } | ||
799 | |||
800 | snd_soc_add_controls(codec, wm8580_snd_controls, | ||
801 | ARRAY_SIZE(wm8580_snd_controls)); | ||
802 | wm8580_add_widgets(codec); | ||
803 | |||
804 | return ret; | ||
805 | |||
806 | pcm_err: | ||
807 | return ret; | ||
808 | } | ||
809 | |||
810 | /* power down chip */ | ||
811 | static int wm8580_remove(struct platform_device *pdev) | ||
812 | { | ||
813 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
814 | |||
815 | snd_soc_free_pcms(socdev); | ||
816 | snd_soc_dapm_free(socdev); | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
822 | .probe = wm8580_probe, | ||
823 | .remove = wm8580_remove, | ||
824 | }; | ||
825 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
826 | 837 | ||
827 | static int wm8580_register(struct wm8580_priv *wm8580, | 838 | static int wm8580_probe(struct snd_soc_codec *codec) |
828 | enum snd_soc_control_type control) | ||
829 | { | 839 | { |
830 | int ret, i; | 840 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); |
831 | struct snd_soc_codec *codec = &wm8580->codec; | 841 | int ret = 0,i; |
832 | |||
833 | if (wm8580_codec) { | ||
834 | dev_err(codec->dev, "Another WM8580 is registered\n"); | ||
835 | ret = -EINVAL; | ||
836 | goto err; | ||
837 | } | ||
838 | |||
839 | mutex_init(&codec->mutex); | ||
840 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
841 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
842 | |||
843 | snd_soc_codec_set_drvdata(codec, wm8580); | ||
844 | codec->name = "WM8580"; | ||
845 | codec->owner = THIS_MODULE; | ||
846 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
847 | codec->set_bias_level = wm8580_set_bias_level; | ||
848 | codec->dai = wm8580_dai; | ||
849 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
850 | codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache); | ||
851 | codec->reg_cache = &wm8580->reg_cache; | ||
852 | |||
853 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); | ||
854 | 842 | ||
855 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 843 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type); |
856 | if (ret < 0) { | 844 | if (ret < 0) { |
857 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 845 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
858 | goto err; | 846 | return ret; |
859 | } | 847 | } |
860 | 848 | ||
861 | for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) | 849 | for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) |
@@ -865,7 +853,7 @@ static int wm8580_register(struct wm8580_priv *wm8580, | |||
865 | wm8580->supplies); | 853 | wm8580->supplies); |
866 | if (ret != 0) { | 854 | if (ret != 0) { |
867 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | 855 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); |
868 | goto err; | 856 | return ret; |
869 | } | 857 | } |
870 | 858 | ||
871 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), | 859 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), |
@@ -882,74 +870,68 @@ static int wm8580_register(struct wm8580_priv *wm8580, | |||
882 | goto err_regulator_enable; | 870 | goto err_regulator_enable; |
883 | } | 871 | } |
884 | 872 | ||
885 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) | ||
886 | wm8580_dai[i].dev = codec->dev; | ||
887 | |||
888 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 873 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
889 | 874 | ||
890 | wm8580_codec = codec; | 875 | snd_soc_add_controls(codec, wm8580_snd_controls, |
891 | 876 | ARRAY_SIZE(wm8580_snd_controls)); | |
892 | ret = snd_soc_register_codec(codec); | 877 | wm8580_add_widgets(codec); |
893 | if (ret != 0) { | ||
894 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
895 | goto err_regulator_enable; | ||
896 | } | ||
897 | |||
898 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
899 | if (ret != 0) { | ||
900 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
901 | goto err_codec; | ||
902 | } | ||
903 | 878 | ||
904 | return 0; | 879 | return 0; |
905 | 880 | ||
906 | err_codec: | ||
907 | snd_soc_unregister_codec(codec); | ||
908 | err_regulator_enable: | 881 | err_regulator_enable: |
909 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 882 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
910 | err_regulator_get: | 883 | err_regulator_get: |
911 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 884 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
912 | err: | ||
913 | kfree(wm8580); | ||
914 | return ret; | 885 | return ret; |
915 | } | 886 | } |
916 | 887 | ||
917 | static void wm8580_unregister(struct wm8580_priv *wm8580) | 888 | /* power down chip */ |
889 | static int wm8580_remove(struct snd_soc_codec *codec) | ||
918 | { | 890 | { |
919 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); | 891 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); |
920 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 892 | |
921 | snd_soc_unregister_codec(&wm8580->codec); | 893 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); |
894 | |||
922 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 895 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
923 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 896 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
924 | kfree(wm8580); | 897 | |
925 | wm8580_codec = NULL; | 898 | return 0; |
926 | } | 899 | } |
927 | 900 | ||
901 | static struct snd_soc_codec_driver soc_codec_dev_wm8580 = { | ||
902 | .probe = wm8580_probe, | ||
903 | .remove = wm8580_remove, | ||
904 | .set_bias_level = wm8580_set_bias_level, | ||
905 | .reg_cache_size = ARRAY_SIZE(wm8580_reg), | ||
906 | .reg_word_size = sizeof(u16), | ||
907 | .reg_cache_default = wm8580_reg, | ||
908 | }; | ||
909 | |||
928 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 910 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
929 | static int wm8580_i2c_probe(struct i2c_client *i2c, | 911 | static int wm8580_i2c_probe(struct i2c_client *i2c, |
930 | const struct i2c_device_id *id) | 912 | const struct i2c_device_id *id) |
931 | { | 913 | { |
932 | struct wm8580_priv *wm8580; | 914 | struct wm8580_priv *wm8580; |
933 | struct snd_soc_codec *codec; | 915 | int ret; |
934 | 916 | ||
935 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | 917 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); |
936 | if (wm8580 == NULL) | 918 | if (wm8580 == NULL) |
937 | return -ENOMEM; | 919 | return -ENOMEM; |
938 | 920 | ||
939 | codec = &wm8580->codec; | ||
940 | |||
941 | i2c_set_clientdata(i2c, wm8580); | 921 | i2c_set_clientdata(i2c, wm8580); |
942 | codec->control_data = i2c; | 922 | wm8580->control_type = SND_SOC_I2C; |
943 | 923 | ||
944 | codec->dev = &i2c->dev; | 924 | ret = snd_soc_register_codec(&i2c->dev, |
945 | 925 | &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); | |
946 | return wm8580_register(wm8580, SND_SOC_I2C); | 926 | if (ret < 0) |
927 | kfree(wm8580); | ||
928 | return ret; | ||
947 | } | 929 | } |
948 | 930 | ||
949 | static int wm8580_i2c_remove(struct i2c_client *client) | 931 | static int wm8580_i2c_remove(struct i2c_client *client) |
950 | { | 932 | { |
951 | struct wm8580_priv *wm8580 = i2c_get_clientdata(client); | 933 | snd_soc_unregister_codec(&client->dev); |
952 | wm8580_unregister(wm8580); | 934 | kfree(i2c_get_clientdata(client)); |
953 | return 0; | 935 | return 0; |
954 | } | 936 | } |
955 | 937 | ||
@@ -961,7 +943,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); | |||
961 | 943 | ||
962 | static struct i2c_driver wm8580_i2c_driver = { | 944 | static struct i2c_driver wm8580_i2c_driver = { |
963 | .driver = { | 945 | .driver = { |
964 | .name = "wm8580", | 946 | .name = "wm8580-codec", |
965 | .owner = THIS_MODULE, | 947 | .owner = THIS_MODULE, |
966 | }, | 948 | }, |
967 | .probe = wm8580_i2c_probe, | 949 | .probe = wm8580_i2c_probe, |
@@ -972,7 +954,7 @@ static struct i2c_driver wm8580_i2c_driver = { | |||
972 | 954 | ||
973 | static int __init wm8580_modinit(void) | 955 | static int __init wm8580_modinit(void) |
974 | { | 956 | { |
975 | int ret; | 957 | int ret = 0; |
976 | 958 | ||
977 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 959 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
978 | ret = i2c_add_driver(&wm8580_i2c_driver); | 960 | ret = i2c_add_driver(&wm8580_i2c_driver); |
@@ -981,7 +963,7 @@ static int __init wm8580_modinit(void) | |||
981 | } | 963 | } |
982 | #endif | 964 | #endif |
983 | 965 | ||
984 | return 0; | 966 | return ret; |
985 | } | 967 | } |
986 | module_init(wm8580_modinit); | 968 | module_init(wm8580_modinit); |
987 | 969 | ||