| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 * wm8753.c -- WM8753 ALSA Soc Audio driver |
| 3 * | 3 * |
| 4 * Copyright 2003 Wolfson Microelectronics PLC. | 4 * Copyright 2003 Wolfson Microelectronics PLC. |
| 5 * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 5 * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
| 6 * | 6 * |
| 7 * This program is free software; you can redistribute it and/or modify it | 7 * This program is free software; you can redistribute it and/or modify it |
| 8 * under the terms of the GNU General Public License as published by the | 8 * under the terms of the GNU General Public License as published by the |
| 9 * Free Software Foundation; either version 2 of the License, or (at your | 9 * Free Software Foundation; either version 2 of the License, or (at your |
| 10 * option) any later version. | 10 * option) any later version. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 #include <linux/delay.h> | 38 #include <linux/delay.h> |
| 39 #include <linux/pm.h> | 39 #include <linux/pm.h> |
| 40 #include <linux/i2c.h> | 40 #include <linux/i2c.h> |
| 41 #include <linux/platform_device.h> | 41 #include <linux/platform_device.h> |
| 42 #include <linux/spi/spi.h> | 42 #include <linux/spi/spi.h> |
| 43 #include <linux/slab.h> | 43 #include <linux/slab.h> |
| 44 #include <sound/core.h> | 44 #include <sound/core.h> |
| 45 #include <sound/pcm.h> | 45 #include <sound/pcm.h> |
| 46 #include <sound/pcm_params.h> | 46 #include <sound/pcm_params.h> |
| 47 #include <sound/soc.h> | 47 #include <sound/soc.h> |
| 48 #include <sound/soc-dapm.h> | |
| 49 #include <sound/initval.h> | 48 #include <sound/initval.h> |
| 50 #include <sound/tlv.h> | 49 #include <sound/tlv.h> |
| 51 #include <asm/div64.h> | 50 #include <asm/div64.h> |
| 52 | 51 |
| 53 #include "wm8753.h" | 52 #include "wm8753.h" |
| 54 | 53 |
| 55 static int caps_charge = 2000; | 54 static int caps_charge = 2000; |
| 56 module_param(caps_charge, int, 0); | 55 module_param(caps_charge, int, 0); |
| 57 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 56 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
| 58 | 57 |
| 59 static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 58 static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, |
| 60 » » struct snd_soc_dai *dai, unsigned int hifi); | 59 » » unsigned int fmt); |
| 60 static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, |
| 61 » » unsigned int fmt); |
| 61 | 62 |
| 62 /* | 63 /* |
| 63 * wm8753 register cache | 64 * wm8753 register cache |
| 64 * We can't read the WM8753 register space when we | 65 * We can't read the WM8753 register space when we |
| 65 * are using 2 wire for device control, so we cache them instead. | 66 * are using 2 wire for device control, so we cache them instead. |
| 66 */ | 67 */ |
| 67 static const u16 wm8753_reg[] = { | 68 static const u16 wm8753_reg[] = { |
| 68 0x0000, 0x0008, 0x0000, 0x000a, | 69 0x0000, 0x0008, 0x0000, 0x000a, |
| 69 0x000a, 0x0033, 0x0000, 0x0007, | 70 0x000a, 0x0033, 0x0000, 0x0007, |
| 70 0x00ff, 0x00ff, 0x000f, 0x000f, | 71 0x00ff, 0x00ff, 0x000f, 0x000f, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 81 0x0004, 0x0000, 0x0083, 0x0024, | 82 0x0004, 0x0000, 0x0083, 0x0024, |
| 82 0x01ba, 0x0000, 0x0083, 0x0024, | 83 0x01ba, 0x0000, 0x0083, 0x0024, |
| 83 0x01ba, 0x0000, 0x0000, 0x0000 | 84 0x01ba, 0x0000, 0x0000, 0x0000 |
| 84 }; | 85 }; |
| 85 | 86 |
| 86 /* codec private data */ | 87 /* codec private data */ |
| 87 struct wm8753_priv { | 88 struct wm8753_priv { |
| 88 enum snd_soc_control_type control_type; | 89 enum snd_soc_control_type control_type; |
| 89 unsigned int sysclk; | 90 unsigned int sysclk; |
| 90 unsigned int pcmclk; | 91 unsigned int pcmclk; |
| 92 |
| 93 unsigned int voice_fmt; |
| 94 unsigned int hifi_fmt; |
| 95 |
| 91 int dai_func; | 96 int dai_func; |
| 92 }; | 97 }; |
| 93 | 98 |
| 94 #define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0) | 99 #define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0) |
| 95 | 100 |
| 96 /* | 101 /* |
| 97 * WM8753 Controls | 102 * WM8753 Controls |
| 98 */ | 103 */ |
| 99 static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"}; | 104 static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"}; |
| 100 static const char *wm8753_base_filter[] = | 105 static const char *wm8753_base_filter[] = |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode), | 169 SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode), |
| 165 SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel), | 170 SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel), |
| 166 SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), | 171 SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), |
| 167 }; | 172 }; |
| 168 | 173 |
| 169 | 174 |
| 170 static int wm8753_get_dai(struct snd_kcontrol *kcontrol, | 175 static int wm8753_get_dai(struct snd_kcontrol *kcontrol, |
| 171 struct snd_ctl_elem_value *ucontrol) | 176 struct snd_ctl_elem_value *ucontrol) |
| 172 { | 177 { |
| 173 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 178 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 174 » int mode = snd_soc_read(codec, WM8753_IOCTL); | 179 » struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 175 | 180 |
| 176 » ucontrol->value.integer.value[0] = (mode & 0xc) >> 2; | 181 » ucontrol->value.integer.value[0] = wm8753->dai_func; |
| 177 return 0; | 182 return 0; |
| 178 } | 183 } |
| 179 | 184 |
| 180 static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | 185 static int wm8753_set_dai(struct snd_kcontrol *kcontrol, |
| 181 struct snd_ctl_elem_value *ucontrol) | 186 struct snd_ctl_elem_value *ucontrol) |
| 182 { | 187 { |
| 183 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 188 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 184 int mode = snd_soc_read(codec, WM8753_IOCTL); | |
| 185 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 189 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 190 u16 ioctl; |
| 186 | 191 |
| 187 » if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) | 192 » if (codec->active) |
| 188 » » return 0; | 193 » » return -EBUSY; |
| 189 | 194 |
| 190 » mode &= 0xfff3; | 195 » ioctl = snd_soc_read(codec, WM8753_IOCTL); |
| 191 » mode |= (ucontrol->value.integer.value[0] << 2); | |
| 192 | 196 |
| 193 » wm8753->dai_func = ucontrol->value.integer.value[0]; | 197 » wm8753->dai_func = ucontrol->value.integer.value[0]; |
| 198 |
| 199 » if (((ioctl >> 2) & 0x3) == wm8753->dai_func) |
| 200 » » return 1; |
| 201 |
| 202 » ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2); |
| 203 » snd_soc_write(codec, WM8753_IOCTL, ioctl); |
| 204 |
| 205 |
| 206 » wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt); |
| 207 » wm8753_voice_write_dai_fmt(codec, wm8753->voice_fmt); |
| 208 |
| 194 return 1; | 209 return 1; |
| 195 } | 210 } |
| 196 | 211 |
| 197 static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); | 212 static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); |
| 198 static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); | 213 static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); |
| 199 static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | 214 static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); |
| 200 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | 215 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); |
| 201 static const unsigned int out_tlv[] = { | 216 static const unsigned int out_tlv[] = { |
| 202 TLV_DB_RANGE_HEAD(2), | 217 TLV_DB_RANGE_HEAD(2), |
| 203 /* 0000000 - 0101111 = "Analogue mute" */ | 218 /* 0000000 - 0101111 = "Analogue mute" */ |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 {"Mic Selection Mux", "Mic 1", "MIC1"}, | 631 {"Mic Selection Mux", "Mic 1", "MIC1"}, |
| 617 {"Mic Selection Mux", "Mic 2", "MIC2N"}, | 632 {"Mic Selection Mux", "Mic 2", "MIC2N"}, |
| 618 {"Mic Selection Mux", "Mic 3", "MIC2"}, | 633 {"Mic Selection Mux", "Mic 3", "MIC2"}, |
| 619 | 634 |
| 620 /* ACOP */ | 635 /* ACOP */ |
| 621 {"ACOP", NULL, "ALC Mixer"}, | 636 {"ACOP", NULL, "ALC Mixer"}, |
| 622 }; | 637 }; |
| 623 | 638 |
| 624 static int wm8753_add_widgets(struct snd_soc_codec *codec) | 639 static int wm8753_add_widgets(struct snd_soc_codec *codec) |
| 625 { | 640 { |
| 626 » snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, | 641 » struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 642 |
| 643 » snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, |
| 627 ARRAY_SIZE(wm8753_dapm_widgets)); | 644 ARRAY_SIZE(wm8753_dapm_widgets)); |
| 628 | 645 » snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
| 629 » snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | |
| 630 | 646 |
| 631 return 0; | 647 return 0; |
| 632 } | 648 } |
| 633 | 649 |
| 634 /* PLL divisors */ | 650 /* PLL divisors */ |
| 635 struct _pll_div { | 651 struct _pll_div { |
| 636 u32 div2:1; | 652 u32 div2:1; |
| 637 u32 n:4; | 653 u32 n:4; |
| 638 u32 k:24; | 654 u32 k:24; |
| 639 }; | 655 }; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 return 0; | 837 return 0; |
| 822 } | 838 } |
| 823 break; | 839 break; |
| 824 } | 840 } |
| 825 return -EINVAL; | 841 return -EINVAL; |
| 826 } | 842 } |
| 827 | 843 |
| 828 /* | 844 /* |
| 829 * Set's ADC and Voice DAC format. | 845 * Set's ADC and Voice DAC format. |
| 830 */ | 846 */ |
| 831 static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, | 847 static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec, |
| 832 unsigned int fmt) | 848 unsigned int fmt) |
| 833 { | 849 { |
| 834 struct snd_soc_codec *codec = codec_dai->codec; | |
| 835 u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec; | 850 u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec; |
| 836 | 851 |
| 837 /* interface format */ | 852 /* interface format */ |
| 838 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 853 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 839 case SND_SOC_DAIFMT_I2S: | 854 case SND_SOC_DAIFMT_I2S: |
| 840 voice |= 0x0002; | 855 voice |= 0x0002; |
| 841 break; | 856 break; |
| 842 case SND_SOC_DAIFMT_RIGHT_J: | 857 case SND_SOC_DAIFMT_RIGHT_J: |
| 843 break; | 858 break; |
| 844 case SND_SOC_DAIFMT_LEFT_J: | 859 case SND_SOC_DAIFMT_LEFT_J: |
| 845 voice |= 0x0001; | 860 voice |= 0x0001; |
| 846 break; | 861 break; |
| 847 case SND_SOC_DAIFMT_DSP_A: | 862 case SND_SOC_DAIFMT_DSP_A: |
| 848 voice |= 0x0003; | 863 voice |= 0x0003; |
| 849 break; | 864 break; |
| 850 case SND_SOC_DAIFMT_DSP_B: | 865 case SND_SOC_DAIFMT_DSP_B: |
| 851 voice |= 0x0013; | 866 voice |= 0x0013; |
| 852 break; | 867 break; |
| 853 default: | 868 default: |
| 854 return -EINVAL; | 869 return -EINVAL; |
| 855 } | 870 } |
| 856 | 871 |
| 857 snd_soc_write(codec, WM8753_PCM, voice); | 872 snd_soc_write(codec, WM8753_PCM, voice); |
| 858 return 0; | 873 return 0; |
| 859 } | 874 } |
| 860 | 875 |
| 861 static int wm8753_pcm_startup(struct snd_pcm_substream *substream, | |
| 862 struct snd_soc_dai *dai) | |
| 863 { | |
| 864 wm8753_set_dai_mode(dai->codec, dai, 0); | |
| 865 return 0; | |
| 866 } | |
| 867 | |
| 868 /* | 876 /* |
| 869 * Set PCM DAI bit size and sample rate. | 877 * Set PCM DAI bit size and sample rate. |
| 870 */ | 878 */ |
| 871 static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | 879 static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, |
| 872 struct snd_pcm_hw_params *params, | 880 struct snd_pcm_hw_params *params, |
| 873 struct snd_soc_dai *dai) | 881 struct snd_soc_dai *dai) |
| 874 { | 882 { |
| 875 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 883 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 876 struct snd_soc_codec *codec = rtd->codec; | 884 struct snd_soc_codec *codec = rtd->codec; |
| 877 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 885 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 898 srate |= 0x80; | 906 srate |= 0x80; |
| 899 snd_soc_write(codec, WM8753_SRATE1, srate); | 907 snd_soc_write(codec, WM8753_SRATE1, srate); |
| 900 | 908 |
| 901 snd_soc_write(codec, WM8753_PCM, voice); | 909 snd_soc_write(codec, WM8753_PCM, voice); |
| 902 return 0; | 910 return 0; |
| 903 } | 911 } |
| 904 | 912 |
| 905 /* | 913 /* |
| 906 * Set's PCM dai fmt and BCLK. | 914 * Set's PCM dai fmt and BCLK. |
| 907 */ | 915 */ |
| 908 static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, | 916 static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec, |
| 909 unsigned int fmt) | 917 unsigned int fmt) |
| 910 { | 918 { |
| 911 struct snd_soc_codec *codec = codec_dai->codec; | |
| 912 u16 voice, ioctl; | 919 u16 voice, ioctl; |
| 913 | 920 |
| 914 voice = snd_soc_read(codec, WM8753_PCM) & 0x011f; | 921 voice = snd_soc_read(codec, WM8753_PCM) & 0x011f; |
| 915 ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d; | 922 ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d; |
| 916 | 923 |
| 917 /* set master/slave audio interface */ | 924 /* set master/slave audio interface */ |
| 918 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 925 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| 919 case SND_SOC_DAIFMT_CBS_CFS: | 926 case SND_SOC_DAIFMT_CBS_CFS: |
| 920 break; | 927 break; |
| 921 case SND_SOC_DAIFMT_CBM_CFM: | 928 case SND_SOC_DAIFMT_CBM_CFM: |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 992 break; | 999 break; |
| 993 default: | 1000 default: |
| 994 return -EINVAL; | 1001 return -EINVAL; |
| 995 } | 1002 } |
| 996 return 0; | 1003 return 0; |
| 997 } | 1004 } |
| 998 | 1005 |
| 999 /* | 1006 /* |
| 1000 * Set's HiFi DAC format. | 1007 * Set's HiFi DAC format. |
| 1001 */ | 1008 */ |
| 1002 static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1009 static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec, |
| 1003 unsigned int fmt) | 1010 unsigned int fmt) |
| 1004 { | 1011 { |
| 1005 struct snd_soc_codec *codec = codec_dai->codec; | |
| 1006 u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0; | 1012 u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0; |
| 1007 | 1013 |
| 1008 /* interface format */ | 1014 /* interface format */ |
| 1009 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 1015 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 1010 case SND_SOC_DAIFMT_I2S: | 1016 case SND_SOC_DAIFMT_I2S: |
| 1011 hifi |= 0x0002; | 1017 hifi |= 0x0002; |
| 1012 break; | 1018 break; |
| 1013 case SND_SOC_DAIFMT_RIGHT_J: | 1019 case SND_SOC_DAIFMT_RIGHT_J: |
| 1014 break; | 1020 break; |
| 1015 case SND_SOC_DAIFMT_LEFT_J: | 1021 case SND_SOC_DAIFMT_LEFT_J: |
| 1016 hifi |= 0x0001; | 1022 hifi |= 0x0001; |
| 1017 break; | 1023 break; |
| 1018 case SND_SOC_DAIFMT_DSP_A: | 1024 case SND_SOC_DAIFMT_DSP_A: |
| 1019 hifi |= 0x0003; | 1025 hifi |= 0x0003; |
| 1020 break; | 1026 break; |
| 1021 case SND_SOC_DAIFMT_DSP_B: | 1027 case SND_SOC_DAIFMT_DSP_B: |
| 1022 hifi |= 0x0013; | 1028 hifi |= 0x0013; |
| 1023 break; | 1029 break; |
| 1024 default: | 1030 default: |
| 1025 return -EINVAL; | 1031 return -EINVAL; |
| 1026 } | 1032 } |
| 1027 | 1033 |
| 1028 snd_soc_write(codec, WM8753_HIFI, hifi); | 1034 snd_soc_write(codec, WM8753_HIFI, hifi); |
| 1029 return 0; | 1035 return 0; |
| 1030 } | 1036 } |
| 1031 | 1037 |
| 1032 /* | 1038 /* |
| 1033 * Set's I2S DAI format. | 1039 * Set's I2S DAI format. |
| 1034 */ | 1040 */ |
| 1035 static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1041 static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec, |
| 1036 unsigned int fmt) | 1042 unsigned int fmt) |
| 1037 { | 1043 { |
| 1038 struct snd_soc_codec *codec = codec_dai->codec; | |
| 1039 u16 ioctl, hifi; | 1044 u16 ioctl, hifi; |
| 1040 | 1045 |
| 1041 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f; | 1046 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f; |
| 1042 ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae; | 1047 ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae; |
| 1043 | 1048 |
| 1044 /* set master/slave audio interface */ | 1049 /* set master/slave audio interface */ |
| 1045 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1050 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| 1046 case SND_SOC_DAIFMT_CBS_CFS: | 1051 case SND_SOC_DAIFMT_CBS_CFS: |
| 1047 break; | 1052 break; |
| 1048 case SND_SOC_DAIFMT_CBM_CFM: | 1053 case SND_SOC_DAIFMT_CBM_CFM: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1091 break; | 1096 break; |
| 1092 default: | 1097 default: |
| 1093 return -EINVAL; | 1098 return -EINVAL; |
| 1094 } | 1099 } |
| 1095 | 1100 |
| 1096 snd_soc_write(codec, WM8753_HIFI, hifi); | 1101 snd_soc_write(codec, WM8753_HIFI, hifi); |
| 1097 snd_soc_write(codec, WM8753_IOCTL, ioctl); | 1102 snd_soc_write(codec, WM8753_IOCTL, ioctl); |
| 1098 return 0; | 1103 return 0; |
| 1099 } | 1104 } |
| 1100 | 1105 |
| 1101 static int wm8753_i2s_startup(struct snd_pcm_substream *substream, | |
| 1102 struct snd_soc_dai *dai) | |
| 1103 { | |
| 1104 wm8753_set_dai_mode(dai->codec, dai, 1); | |
| 1105 return 0; | |
| 1106 } | |
| 1107 | |
| 1108 /* | 1106 /* |
| 1109 * Set PCM DAI bit size and sample rate. | 1107 * Set PCM DAI bit size and sample rate. |
| 1110 */ | 1108 */ |
| 1111 static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | 1109 static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, |
| 1112 struct snd_pcm_hw_params *params, | 1110 struct snd_pcm_hw_params *params, |
| 1113 struct snd_soc_dai *dai) | 1111 struct snd_soc_dai *dai) |
| 1114 { | 1112 { |
| 1115 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1113 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 1116 struct snd_soc_codec *codec = rtd->codec; | 1114 struct snd_soc_codec *codec = rtd->codec; |
| 1117 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 1115 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1140 break; | 1138 break; |
| 1141 case SNDRV_PCM_FORMAT_S32_LE: | 1139 case SNDRV_PCM_FORMAT_S32_LE: |
| 1142 hifi |= 0x000c; | 1140 hifi |= 0x000c; |
| 1143 break; | 1141 break; |
| 1144 } | 1142 } |
| 1145 | 1143 |
| 1146 snd_soc_write(codec, WM8753_HIFI, hifi); | 1144 snd_soc_write(codec, WM8753_HIFI, hifi); |
| 1147 return 0; | 1145 return 0; |
| 1148 } | 1146 } |
| 1149 | 1147 |
| 1150 static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1148 static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec *codec, |
| 1151 unsigned int fmt) | 1149 unsigned int fmt) |
| 1152 { | 1150 { |
| 1153 struct snd_soc_codec *codec = codec_dai->codec; | |
| 1154 u16 clock; | 1151 u16 clock; |
| 1155 | 1152 |
| 1156 /* set clk source as pcmclk */ | 1153 /* set clk source as pcmclk */ |
| 1157 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1154 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
| 1158 snd_soc_write(codec, WM8753_CLOCK, clock); | 1155 snd_soc_write(codec, WM8753_CLOCK, clock); |
| 1159 | 1156 |
| 1160 » if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1157 » return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
| 1161 » » return -EINVAL; | |
| 1162 » return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | |
| 1163 } | 1158 } |
| 1164 | 1159 |
| 1165 static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1160 static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec *codec, |
| 1166 unsigned int fmt) | 1161 unsigned int fmt) |
| 1167 { | 1162 { |
| 1168 » if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1163 » return wm8753_hdac_set_dai_fmt(codec, fmt); |
| 1169 » » return -EINVAL; | |
| 1170 » return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | |
| 1171 } | 1164 } |
| 1172 | 1165 |
| 1173 static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1166 static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec *codec, |
| 1174 unsigned int fmt) | 1167 unsigned int fmt) |
| 1175 { | 1168 { |
| 1176 struct snd_soc_codec *codec = codec_dai->codec; | |
| 1177 u16 clock; | 1169 u16 clock; |
| 1178 | 1170 |
| 1179 /* set clk source as pcmclk */ | 1171 /* set clk source as pcmclk */ |
| 1180 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1172 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
| 1181 snd_soc_write(codec, WM8753_CLOCK, clock); | 1173 snd_soc_write(codec, WM8753_CLOCK, clock); |
| 1182 | 1174 |
| 1183 » if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1175 » return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
| 1184 » » return -EINVAL; | |
| 1185 » return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | |
| 1186 } | 1176 } |
| 1187 | 1177 |
| 1188 static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1178 static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec *codec, |
| 1189 unsigned int fmt) | 1179 unsigned int fmt) |
| 1190 { | 1180 { |
| 1191 struct snd_soc_codec *codec = codec_dai->codec; | |
| 1192 u16 clock; | 1181 u16 clock; |
| 1193 | 1182 |
| 1194 /* set clk source as mclk */ | 1183 /* set clk source as mclk */ |
| 1195 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1184 clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
| 1196 snd_soc_write(codec, WM8753_CLOCK, clock | 0x4); | 1185 snd_soc_write(codec, WM8753_CLOCK, clock | 0x4); |
| 1197 | 1186 |
| 1198 » if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1187 » if (wm8753_hdac_set_dai_fmt(codec, fmt) < 0) |
| 1199 return -EINVAL; | 1188 return -EINVAL; |
| 1200 » if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1189 » return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
| 1201 » » return -EINVAL; | |
| 1202 » return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | |
| 1203 } | 1190 } |
| 1204 | 1191 |
| 1192 static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, |
| 1193 unsigned int fmt) |
| 1194 { |
| 1195 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1196 int ret = 0; |
| 1197 |
| 1198 switch (wm8753->dai_func) { |
| 1199 case 0: |
| 1200 ret = wm8753_mode1h_set_dai_fmt(codec, fmt); |
| 1201 break; |
| 1202 case 1: |
| 1203 ret = wm8753_mode2_set_dai_fmt(codec, fmt); |
| 1204 break; |
| 1205 case 2: |
| 1206 case 3: |
| 1207 ret = wm8753_mode3_4_set_dai_fmt(codec, fmt); |
| 1208 break; |
| 1209 default: |
| 1210 break; |
| 1211 } |
| 1212 if (ret) |
| 1213 return ret; |
| 1214 |
| 1215 return wm8753_i2s_set_dai_fmt(codec, fmt); |
| 1216 } |
| 1217 |
| 1218 static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1219 unsigned int fmt) |
| 1220 { |
| 1221 struct snd_soc_codec *codec = codec_dai->codec; |
| 1222 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1223 |
| 1224 wm8753->hifi_fmt = fmt; |
| 1225 |
| 1226 return wm8753_hifi_write_dai_fmt(codec, fmt); |
| 1227 }; |
| 1228 |
| 1229 static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, |
| 1230 unsigned int fmt) |
| 1231 { |
| 1232 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1233 int ret = 0; |
| 1234 |
| 1235 if (wm8753->dai_func != 0) |
| 1236 return 0; |
| 1237 |
| 1238 ret = wm8753_mode1v_set_dai_fmt(codec, fmt); |
| 1239 if (ret) |
| 1240 return ret; |
| 1241 ret = wm8753_pcm_set_dai_fmt(codec, fmt); |
| 1242 if (ret) |
| 1243 return ret; |
| 1244 |
| 1245 return 0; |
| 1246 }; |
| 1247 |
| 1248 static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1249 unsigned int fmt) |
| 1250 { |
| 1251 struct snd_soc_codec *codec = codec_dai->codec; |
| 1252 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1253 |
| 1254 wm8753->voice_fmt = fmt; |
| 1255 |
| 1256 return wm8753_voice_write_dai_fmt(codec, fmt); |
| 1257 }; |
| 1258 |
| 1205 static int wm8753_mute(struct snd_soc_dai *dai, int mute) | 1259 static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
| 1206 { | 1260 { |
| 1207 struct snd_soc_codec *codec = dai->codec; | 1261 struct snd_soc_codec *codec = dai->codec; |
| 1208 u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7; | 1262 u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7; |
| 1209 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 1263 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1210 | 1264 |
| 1211 /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1265 /* the digital mute covers the HiFi and Voice DAC's on the WM8753. |
| 1212 * make sure we check if they are not both active when we mute */ | 1266 * make sure we check if they are not both active when we mute */ |
| 1213 if (mute && wm8753->dai_func == 1) { | 1267 if (mute && wm8753->dai_func == 1) { |
| 1214 if (!codec->active) | 1268 if (!codec->active) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1238 snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1292 snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
| 1239 break; | 1293 break; |
| 1240 case SND_SOC_BIAS_STANDBY: | 1294 case SND_SOC_BIAS_STANDBY: |
| 1241 /* mute dac and set vmid to 500k, enable VREF */ | 1295 /* mute dac and set vmid to 500k, enable VREF */ |
| 1242 snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141); | 1296 snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141); |
| 1243 break; | 1297 break; |
| 1244 case SND_SOC_BIAS_OFF: | 1298 case SND_SOC_BIAS_OFF: |
| 1245 snd_soc_write(codec, WM8753_PWR1, 0x0001); | 1299 snd_soc_write(codec, WM8753_PWR1, 0x0001); |
| 1246 break; | 1300 break; |
| 1247 } | 1301 } |
| 1248 » codec->bias_level = level; | 1302 » codec->dapm.bias_level = level; |
| 1249 return 0; | 1303 return 0; |
| 1250 } | 1304 } |
| 1251 | 1305 |
| 1252 #define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1306 #define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
| 1253 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 1307 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
| 1254 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ | 1308 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ |
| 1255 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 1309 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
| 1256 | 1310 |
| 1257 #define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1311 #define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 1258 SNDRV_PCM_FMTBIT_S24_LE) | 1312 SNDRV_PCM_FMTBIT_S24_LE) |
| 1259 | 1313 |
| 1260 /* | 1314 /* |
| 1261 * The WM8753 supports upto 4 different and mutually exclusive DAI | 1315 * The WM8753 supports upto 4 different and mutually exclusive DAI |
| 1262 * configurations. This gives 2 PCM's available for use, hifi and voice. | 1316 * configurations. This gives 2 PCM's available for use, hifi and voice. |
| 1263 * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI | 1317 * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI |
| 1264 * is connected between the wm8753 and a BT codec or GSM modem. | 1318 * is connected between the wm8753 and a BT codec or GSM modem. |
| 1265 * | 1319 * |
| 1266 * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI | 1320 * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI |
| 1267 * 2. Voice over HIFI DAI - HIFI disabled | 1321 * 2. Voice over HIFI DAI - HIFI disabled |
| 1268 * 3. Voice disabled - HIFI over HIFI | 1322 * 3. Voice disabled - HIFI over HIFI |
| 1269 * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1323 * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
| 1270 */ | 1324 */ |
| 1271 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | 1325 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = { |
| 1272 » .startup = wm8753_i2s_startup, | |
| 1273 .hw_params = wm8753_i2s_hw_params, | 1326 .hw_params = wm8753_i2s_hw_params, |
| 1274 .digital_mute = wm8753_mute, | 1327 .digital_mute = wm8753_mute, |
| 1275 » .set_fmt» = wm8753_mode1h_set_dai_fmt, | 1328 » .set_fmt» = wm8753_hifi_set_dai_fmt, |
| 1276 .set_clkdiv = wm8753_set_dai_clkdiv, | 1329 .set_clkdiv = wm8753_set_dai_clkdiv, |
| 1277 .set_pll = wm8753_set_dai_pll, | 1330 .set_pll = wm8753_set_dai_pll, |
| 1278 .set_sysclk = wm8753_set_dai_sysclk, | 1331 .set_sysclk = wm8753_set_dai_sysclk, |
| 1279 }; | 1332 }; |
| 1280 | 1333 |
| 1281 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | 1334 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = { |
| 1282 » .startup = wm8753_pcm_startup, | |
| 1283 .hw_params = wm8753_pcm_hw_params, | 1335 .hw_params = wm8753_pcm_hw_params, |
| 1284 .digital_mute = wm8753_mute, | 1336 .digital_mute = wm8753_mute, |
| 1285 » .set_fmt» = wm8753_mode1v_set_dai_fmt, | 1337 » .set_fmt» = wm8753_voice_set_dai_fmt, |
| 1286 .set_clkdiv = wm8753_set_dai_clkdiv, | 1338 .set_clkdiv = wm8753_set_dai_clkdiv, |
| 1287 .set_pll = wm8753_set_dai_pll, | 1339 .set_pll = wm8753_set_dai_pll, |
| 1288 .set_sysclk = wm8753_set_dai_sysclk, | 1340 .set_sysclk = wm8753_set_dai_sysclk, |
| 1289 }; | 1341 }; |
| 1290 | 1342 |
| 1291 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | 1343 static struct snd_soc_dai_driver wm8753_dai[] = { |
| 1292 » .startup = wm8753_pcm_startup, | |
| 1293 » .hw_params» = wm8753_pcm_hw_params, | |
| 1294 » .digital_mute» = wm8753_mute, | |
| 1295 » .set_fmt» = wm8753_mode2_set_dai_fmt, | |
| 1296 » .set_clkdiv» = wm8753_set_dai_clkdiv, | |
| 1297 » .set_pll» = wm8753_set_dai_pll, | |
| 1298 » .set_sysclk» = wm8753_set_dai_sysclk, | |
| 1299 }; | |
| 1300 | |
| 1301 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3»= { | |
| 1302 » .startup = wm8753_i2s_startup, | |
| 1303 » .hw_params» = wm8753_i2s_hw_params, | |
| 1304 » .digital_mute» = wm8753_mute, | |
| 1305 » .set_fmt» = wm8753_mode3_4_set_dai_fmt, | |
| 1306 » .set_clkdiv» = wm8753_set_dai_clkdiv, | |
| 1307 » .set_pll» = wm8753_set_dai_pll, | |
| 1308 » .set_sysclk» = wm8753_set_dai_sysclk, | |
| 1309 }; | |
| 1310 | |
| 1311 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4»= { | |
| 1312 » .startup = wm8753_i2s_startup, | |
| 1313 » .hw_params» = wm8753_i2s_hw_params, | |
| 1314 » .digital_mute» = wm8753_mute, | |
| 1315 » .set_fmt» = wm8753_mode3_4_set_dai_fmt, | |
| 1316 » .set_clkdiv» = wm8753_set_dai_clkdiv, | |
| 1317 » .set_pll» = wm8753_set_dai_pll, | |
| 1318 » .set_sysclk» = wm8753_set_dai_sysclk, | |
| 1319 }; | |
| 1320 | |
| 1321 static struct snd_soc_dai_driver wm8753_all_dai[] = { | |
| 1322 /* DAI HiFi mode 1 */ | 1344 /* DAI HiFi mode 1 */ |
| 1323 { .name = "wm8753-hifi", | 1345 { .name = "wm8753-hifi", |
| 1324 .playback = { | 1346 .playback = { |
| 1325 .stream_name = "HiFi Playback", | 1347 .stream_name = "HiFi Playback", |
| 1326 .channels_min = 1, | 1348 .channels_min = 1, |
| 1327 .channels_max = 2, | 1349 .channels_max = 2, |
| 1328 .rates = WM8753_RATES, | 1350 .rates = WM8753_RATES, |
| 1329 » » .formats = WM8753_FORMATS}, | 1351 » » .formats = WM8753_FORMATS |
| 1352 » }, |
| 1330 .capture = { /* dummy for fast DAI switching */ | 1353 .capture = { /* dummy for fast DAI switching */ |
| 1331 .stream_name = "Capture", | 1354 .stream_name = "Capture", |
| 1332 .channels_min = 1, | 1355 .channels_min = 1, |
| 1333 .channels_max = 2, | 1356 .channels_max = 2, |
| 1334 .rates = WM8753_RATES, | 1357 .rates = WM8753_RATES, |
| 1335 » » .formats = WM8753_FORMATS}, | 1358 » » .formats = WM8753_FORMATS |
| 1336 » .ops = &wm8753_dai_ops_hifi_mode1, | 1359 » }, |
| 1360 » .ops = &wm8753_dai_ops_hifi_mode, |
| 1337 }, | 1361 }, |
| 1338 /* DAI Voice mode 1 */ | 1362 /* DAI Voice mode 1 */ |
| 1339 { .name = "wm8753-voice", | 1363 { .name = "wm8753-voice", |
| 1340 .playback = { | 1364 .playback = { |
| 1341 .stream_name = "Voice Playback", | 1365 .stream_name = "Voice Playback", |
| 1342 .channels_min = 1, | 1366 .channels_min = 1, |
| 1343 .channels_max = 1, | 1367 .channels_max = 1, |
| 1344 .rates = WM8753_RATES, | 1368 .rates = WM8753_RATES, |
| 1345 » » .formats = WM8753_FORMATS,}, | 1369 » » .formats = WM8753_FORMATS, |
| 1370 » }, |
| 1346 .capture = { | 1371 .capture = { |
| 1347 .stream_name = "Capture", | 1372 .stream_name = "Capture", |
| 1348 .channels_min = 1, | 1373 .channels_min = 1, |
| 1349 .channels_max = 2, | 1374 .channels_max = 2, |
| 1350 .rates = WM8753_RATES, | 1375 .rates = WM8753_RATES, |
| 1351 » » .formats = WM8753_FORMATS,}, | 1376 » » .formats = WM8753_FORMATS, |
| 1352 » .ops = &wm8753_dai_ops_voice_mode1, | 1377 » }, |
| 1353 }, | 1378 » .ops = &wm8753_dai_ops_voice_mode, |
| 1354 /* DAI HiFi mode 2 - dummy */ | |
| 1355 {» .name = "wm8753-hifi", | |
| 1356 }, | |
| 1357 /* DAI Voice mode 2 */ | |
| 1358 {» .name = "wm8753-voice", | |
| 1359 » .playback = { | |
| 1360 » » .stream_name = "Voice Playback", | |
| 1361 » » .channels_min = 1, | |
| 1362 » » .channels_max = 1, | |
| 1363 » » .rates = WM8753_RATES, | |
| 1364 » » .formats = WM8753_FORMATS,}, | |
| 1365 » .capture = { | |
| 1366 » » .stream_name = "Capture", | |
| 1367 » » .channels_min = 1, | |
| 1368 » » .channels_max = 2, | |
| 1369 » » .rates = WM8753_RATES, | |
| 1370 » » .formats = WM8753_FORMATS,}, | |
| 1371 » .ops = &wm8753_dai_ops_voice_mode2, | |
| 1372 }, | |
| 1373 /* DAI HiFi mode 3 */ | |
| 1374 {» .name = "wm8753-hifi", | |
| 1375 » .playback = { | |
| 1376 » » .stream_name = "HiFi Playback", | |
| 1377 » » .channels_min = 1, | |
| 1378 » » .channels_max = 2, | |
| 1379 » » .rates = WM8753_RATES, | |
| 1380 » » .formats = WM8753_FORMATS,}, | |
| 1381 » .capture = { | |
| 1382 » » .stream_name = "Capture", | |
| 1383 » » .channels_min = 1, | |
| 1384 » » .channels_max = 2, | |
| 1385 » » .rates = WM8753_RATES, | |
| 1386 » » .formats = WM8753_FORMATS,}, | |
| 1387 » .ops = &wm8753_dai_ops_hifi_mode3, | |
| 1388 }, | |
| 1389 /* DAI Voice mode 3 - dummy */ | |
| 1390 {» .name = "wm8753-voice", | |
| 1391 }, | |
| 1392 /* DAI HiFi mode 4 */ | |
| 1393 {» .name = "wm8753-hifi", | |
| 1394 » .playback = { | |
| 1395 » » .stream_name = "HiFi Playback", | |
| 1396 » » .channels_min = 1, | |
| 1397 » » .channels_max = 2, | |
| 1398 » » .rates = WM8753_RATES, | |
| 1399 » » .formats = WM8753_FORMATS,}, | |
| 1400 » .capture = { | |
| 1401 » » .stream_name = "Capture", | |
| 1402 » » .channels_min = 1, | |
| 1403 » » .channels_max = 2, | |
| 1404 » » .rates = WM8753_RATES, | |
| 1405 » » .formats = WM8753_FORMATS,}, | |
| 1406 » .ops = &wm8753_dai_ops_hifi_mode4, | |
| 1407 }, | |
| 1408 /* DAI Voice mode 4 - dummy */ | |
| 1409 {» .name = "wm8753-voice", | |
| 1410 }, | 1379 }, |
| 1411 }; | 1380 }; |
| 1412 | 1381 |
| 1413 static struct snd_soc_dai_driver wm8753_dai[] = { | |
| 1414 { | |
| 1415 .name = "wm8753-aif0", | |
| 1416 }, | |
| 1417 { | |
| 1418 .name = "wm8753-aif1", | |
| 1419 }, | |
| 1420 }; | |
| 1421 | |
| 1422 static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | |
| 1423 struct snd_soc_dai *dai, unsigned int hifi) | |
| 1424 { | |
| 1425 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | |
| 1426 | |
| 1427 if (wm8753->dai_func < 4) { | |
| 1428 if (hifi) | |
| 1429 dai->driver = &wm8753_all_dai[wm8753->dai_func << 1]; | |
| 1430 else | |
| 1431 dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) +
1]; | |
| 1432 } | |
| 1433 snd_soc_write(codec, WM8753_IOCTL, wm8753->dai_func); | |
| 1434 } | |
| 1435 | |
| 1436 static void wm8753_work(struct work_struct *work) | 1382 static void wm8753_work(struct work_struct *work) |
| 1437 { | 1383 { |
| 1438 » struct snd_soc_codec *codec = | 1384 » struct snd_soc_dapm_context *dapm = |
| 1439 » » container_of(work, struct snd_soc_codec, delayed_work.work); | 1385 » » container_of(work, struct snd_soc_dapm_context, |
| 1440 » wm8753_set_bias_level(codec, codec->bias_level); | 1386 » » » delayed_work.work); |
| 1387 » struct snd_soc_codec *codec = dapm->codec; |
| 1388 » wm8753_set_bias_level(codec, dapm->bias_level); |
| 1441 } | 1389 } |
| 1442 | 1390 |
| 1443 static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state) | 1391 static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state) |
| 1444 { | 1392 { |
| 1445 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1393 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1446 return 0; | 1394 return 0; |
| 1447 } | 1395 } |
| 1448 | 1396 |
| 1449 static int wm8753_resume(struct snd_soc_codec *codec) | 1397 static int wm8753_resume(struct snd_soc_codec *codec) |
| 1450 { | 1398 { |
| 1451 u16 *reg_cache = codec->reg_cache; | 1399 u16 *reg_cache = codec->reg_cache; |
| 1452 int i; | 1400 int i; |
| 1453 | 1401 |
| 1454 /* Sync reg_cache with the hardware */ | 1402 /* Sync reg_cache with the hardware */ |
| 1455 for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) { | 1403 for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) { |
| 1456 if (i == WM8753_RESET) | 1404 if (i == WM8753_RESET) |
| 1457 continue; | 1405 continue; |
| 1458 | 1406 |
| 1459 /* No point in writing hardware default values back */ | 1407 /* No point in writing hardware default values back */ |
| 1460 if (reg_cache[i] == wm8753_reg[i]) | 1408 if (reg_cache[i] == wm8753_reg[i]) |
| 1461 continue; | 1409 continue; |
| 1462 | 1410 |
| 1463 snd_soc_write(codec, i, reg_cache[i]); | 1411 snd_soc_write(codec, i, reg_cache[i]); |
| 1464 } | 1412 } |
| 1465 | 1413 |
| 1466 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1414 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1467 | 1415 |
| 1468 /* charge wm8753 caps */ | 1416 /* charge wm8753 caps */ |
| 1469 » if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | 1417 » if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { |
| 1470 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1418 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 1471 » » codec->bias_level = SND_SOC_BIAS_ON; | 1419 » » codec->dapm.bias_level = SND_SOC_BIAS_ON; |
| 1472 » » schedule_delayed_work(&codec->delayed_work, | 1420 » » schedule_delayed_work(&codec->dapm.delayed_work, |
| 1473 msecs_to_jiffies(caps_charge)); | 1421 msecs_to_jiffies(caps_charge)); |
| 1474 } | 1422 } |
| 1475 | 1423 |
| 1476 return 0; | 1424 return 0; |
| 1477 } | 1425 } |
| 1478 | 1426 |
| 1479 /* | |
| 1480 * This function forces any delayed work to be queued and run. | |
| 1481 */ | |
| 1482 static int run_delayed_work(struct delayed_work *dwork) | |
| 1483 { | |
| 1484 int ret; | |
| 1485 | |
| 1486 /* cancel any work waiting to be queued. */ | |
| 1487 ret = cancel_delayed_work(dwork); | |
| 1488 | |
| 1489 /* if there was any work waiting then we run it now and | |
| 1490 * wait for it's completion */ | |
| 1491 if (ret) { | |
| 1492 schedule_delayed_work(dwork, 0); | |
| 1493 flush_scheduled_work(); | |
| 1494 } | |
| 1495 return ret; | |
| 1496 } | |
| 1497 | |
| 1498 static int wm8753_probe(struct snd_soc_codec *codec) | 1427 static int wm8753_probe(struct snd_soc_codec *codec) |
| 1499 { | 1428 { |
| 1500 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 1429 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
| 1501 int ret; | 1430 int ret; |
| 1502 | 1431 |
| 1503 » INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | 1432 » INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); |
| 1504 | 1433 |
| 1505 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); | 1434 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); |
| 1506 if (ret < 0) { | 1435 if (ret < 0) { |
| 1507 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1436 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 1508 return ret; | 1437 return ret; |
| 1509 } | 1438 } |
| 1510 | 1439 |
| 1511 ret = wm8753_reset(codec); | 1440 ret = wm8753_reset(codec); |
| 1512 if (ret < 0) { | 1441 if (ret < 0) { |
| 1513 dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | 1442 dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
| 1514 return ret; | 1443 return ret; |
| 1515 } | 1444 } |
| 1516 | 1445 |
| 1517 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1446 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1518 wm8753->dai_func = 0; | 1447 wm8753->dai_func = 0; |
| 1519 | 1448 |
| 1520 /* charge output caps */ | 1449 /* charge output caps */ |
| 1521 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1450 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 1522 » schedule_delayed_work(&codec->delayed_work, | 1451 » schedule_delayed_work(&codec->dapm.delayed_work, |
| 1523 msecs_to_jiffies(caps_charge)); | 1452 msecs_to_jiffies(caps_charge)); |
| 1524 | 1453 |
| 1525 /* set the update bits */ | 1454 /* set the update bits */ |
| 1526 snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); | 1455 snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); |
| 1527 snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); | 1456 snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); |
| 1528 snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); | 1457 snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); |
| 1529 snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); | 1458 snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); |
| 1530 snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100); | 1459 snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100); |
| 1531 snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100); | 1460 snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100); |
| 1532 snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100); | 1461 snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100); |
| 1533 snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100); | 1462 snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100); |
| 1534 snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100); | 1463 snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100); |
| 1535 snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100); | 1464 snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100); |
| 1536 | 1465 |
| 1537 snd_soc_add_controls(codec, wm8753_snd_controls, | 1466 snd_soc_add_controls(codec, wm8753_snd_controls, |
| 1538 ARRAY_SIZE(wm8753_snd_controls)); | 1467 ARRAY_SIZE(wm8753_snd_controls)); |
| 1539 wm8753_add_widgets(codec); | 1468 wm8753_add_widgets(codec); |
| 1540 | 1469 |
| 1541 return 0; | 1470 return 0; |
| 1542 } | 1471 } |
| 1543 | 1472 |
| 1544 /* power down chip */ | 1473 /* power down chip */ |
| 1545 static int wm8753_remove(struct snd_soc_codec *codec) | 1474 static int wm8753_remove(struct snd_soc_codec *codec) |
| 1546 { | 1475 { |
| 1547 » run_delayed_work(&codec->delayed_work); | 1476 » flush_delayed_work_sync(&codec->dapm.delayed_work); |
| 1548 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1477 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1549 | 1478 |
| 1550 return 0; | 1479 return 0; |
| 1551 } | 1480 } |
| 1552 | 1481 |
| 1553 static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { | 1482 static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { |
| 1554 .probe = wm8753_probe, | 1483 .probe = wm8753_probe, |
| 1555 .remove = wm8753_remove, | 1484 .remove = wm8753_remove, |
| 1556 .suspend = wm8753_suspend, | 1485 .suspend = wm8753_suspend, |
| 1557 .resume = wm8753_resume, | 1486 .resume = wm8753_resume, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1671 #endif | 1600 #endif |
| 1672 #if defined(CONFIG_SPI_MASTER) | 1601 #if defined(CONFIG_SPI_MASTER) |
| 1673 spi_unregister_driver(&wm8753_spi_driver); | 1602 spi_unregister_driver(&wm8753_spi_driver); |
| 1674 #endif | 1603 #endif |
| 1675 } | 1604 } |
| 1676 module_exit(wm8753_exit); | 1605 module_exit(wm8753_exit); |
| 1677 | 1606 |
| 1678 MODULE_DESCRIPTION("ASoC WM8753 driver"); | 1607 MODULE_DESCRIPTION("ASoC WM8753 driver"); |
| 1679 MODULE_AUTHOR("Liam Girdwood"); | 1608 MODULE_AUTHOR("Liam Girdwood"); |
| 1680 MODULE_LICENSE("GPL"); | 1609 MODULE_LICENSE("GPL"); |
| OLD | NEW |