diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-10 03:24:50 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-10 03:24:50 -0400 |
commit | 1209842af4db98ffd7364ec9cf7d1a59293aa74c (patch) | |
tree | 33202a5468dc66456b67764eb6a272bd7e8c5af5 | |
parent | f0a2b0cb71e652ae9f0feeea91e5320e4faf25dc (diff) | |
parent | f3eee00da39cba3c8a4db7048458969c620ac6d8 (diff) |
Merge branch 'for-2.6.40' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
-rw-r--r-- | include/sound/soc-dapm.h | 78 | ||||
-rw-r--r-- | sound/soc/codecs/88pm860x-codec.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ssm2602.c | 302 | ||||
-rw-r--r-- | sound/soc/codecs/ssm2602.h | 6 | ||||
-rw-r--r-- | sound/soc/codecs/uda134x.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8915.c | 46 | ||||
-rw-r--r-- | sound/soc/jz4740/jz4740-i2s.c | 2 | ||||
-rw-r--r-- | sound/soc/mid-x86/sst_platform.c | 6 | ||||
-rw-r--r-- | sound/soc/soc-cache.c | 11 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 38 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 373 | ||||
-rw-r--r-- | sound/soc/tegra/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/tegra/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/tegra/trimslice.c | 228 |
14 files changed, 780 insertions, 324 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index d5f1b9a9b8ff..c46e7d89561d 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -39,30 +39,30 @@ | |||
39 | 39 | ||
40 | /* codec domain */ | 40 | /* codec domain */ |
41 | #define SND_SOC_DAPM_VMID(wname) \ | 41 | #define SND_SOC_DAPM_VMID(wname) \ |
42 | { .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \ | 42 | { .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ |
43 | .num_kcontrols = 0} | 43 | .num_kcontrols = 0} |
44 | 44 | ||
45 | /* platform domain */ | 45 | /* platform domain */ |
46 | #define SND_SOC_DAPM_INPUT(wname) \ | 46 | #define SND_SOC_DAPM_INPUT(wname) \ |
47 | { .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \ | 47 | { .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ |
48 | .num_kcontrols = 0, .reg = SND_SOC_NOPM } | 48 | .num_kcontrols = 0, .reg = SND_SOC_NOPM } |
49 | #define SND_SOC_DAPM_OUTPUT(wname) \ | 49 | #define SND_SOC_DAPM_OUTPUT(wname) \ |
50 | { .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \ | 50 | { .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ |
51 | .num_kcontrols = 0, .reg = SND_SOC_NOPM } | 51 | .num_kcontrols = 0, .reg = SND_SOC_NOPM } |
52 | #define SND_SOC_DAPM_MIC(wname, wevent) \ | 52 | #define SND_SOC_DAPM_MIC(wname, wevent) \ |
53 | { .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \ | 53 | { .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ |
54 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 54 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
55 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} | 55 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} |
56 | #define SND_SOC_DAPM_HP(wname, wevent) \ | 56 | #define SND_SOC_DAPM_HP(wname, wevent) \ |
57 | { .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \ | 57 | { .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ |
58 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 58 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
59 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | 59 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} |
60 | #define SND_SOC_DAPM_SPK(wname, wevent) \ | 60 | #define SND_SOC_DAPM_SPK(wname, wevent) \ |
61 | { .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \ | 61 | { .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ |
62 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 62 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
63 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | 63 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} |
64 | #define SND_SOC_DAPM_LINE(wname, wevent) \ | 64 | #define SND_SOC_DAPM_LINE(wname, wevent) \ |
65 | { .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \ | 65 | { .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ |
66 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 66 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
67 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | 67 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} |
68 | 68 | ||
@@ -70,91 +70,91 @@ | |||
70 | #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ | 70 | #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ |
71 | wcontrols, wncontrols) \ | 71 | wcontrols, wncontrols) \ |
72 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 72 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ |
73 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | 73 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} |
74 | #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ | 74 | #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ |
75 | wcontrols, wncontrols) \ | 75 | wcontrols, wncontrols) \ |
76 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ | 76 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ |
77 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | 77 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} |
78 | #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ | 78 | #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ |
79 | wcontrols, wncontrols)\ | 79 | wcontrols, wncontrols)\ |
80 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 80 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
81 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | 81 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} |
82 | #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ | 82 | #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ |
83 | wcontrols, wncontrols)\ | 83 | wcontrols, wncontrols)\ |
84 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ | 84 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ |
85 | .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ | 85 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ |
86 | .num_kcontrols = wncontrols} | 86 | .num_kcontrols = wncontrols} |
87 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ | 87 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ |
88 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | 88 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ |
89 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} | 89 | .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0} |
90 | #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ | 90 | #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ |
91 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | 91 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ |
92 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | 92 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} |
93 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 93 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
94 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 94 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ |
95 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | 95 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} |
96 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 96 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
97 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 97 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ |
98 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | 98 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} |
99 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 99 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
100 | { .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ | 100 | { .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ |
101 | .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ | 101 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ |
102 | .num_kcontrols = 1} | 102 | .num_kcontrols = 1} |
103 | 103 | ||
104 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ | 104 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ |
105 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ | 105 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ |
106 | wcontrols) \ | 106 | wcontrols) \ |
107 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 107 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ |
108 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | 108 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} |
109 | #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ | 109 | #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ |
110 | wcontrols)\ | 110 | wcontrols)\ |
111 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 111 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
112 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | 112 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} |
113 | #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ | 113 | #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ |
114 | wcontrols)\ | 114 | wcontrols)\ |
115 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ | 115 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ |
116 | .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ | 116 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ |
117 | .num_kcontrols = ARRAY_SIZE(wcontrols)} | 117 | .num_kcontrols = ARRAY_SIZE(wcontrols)} |
118 | 118 | ||
119 | /* path domain with event - event handler must return 0 for success */ | 119 | /* path domain with event - event handler must return 0 for success */ |
120 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ | 120 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ |
121 | wncontrols, wevent, wflags) \ | 121 | wncontrols, wevent, wflags) \ |
122 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 122 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ |
123 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | 123 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ |
124 | .event = wevent, .event_flags = wflags} | 124 | .event = wevent, .event_flags = wflags} |
125 | #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ | 125 | #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ |
126 | wncontrols, wevent, wflags) \ | 126 | wncontrols, wevent, wflags) \ |
127 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ | 127 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ |
128 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | 128 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ |
129 | .event = wevent, .event_flags = wflags} | 129 | .event = wevent, .event_flags = wflags} |
130 | #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ | 130 | #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ |
131 | wncontrols, wevent, wflags) \ | 131 | wncontrols, wevent, wflags) \ |
132 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 132 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
133 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | 133 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ |
134 | .event = wevent, .event_flags = wflags} | 134 | .event = wevent, .event_flags = wflags} |
135 | #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ | 135 | #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ |
136 | wcontrols, wncontrols, wevent, wflags) \ | 136 | wcontrols, wncontrols, wevent, wflags) \ |
137 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 137 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
138 | .invert = winvert, .kcontrols = wcontrols, \ | 138 | .invert = winvert, .kcontrol_news = wcontrols, \ |
139 | .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} | 139 | .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} |
140 | #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ | 140 | #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ |
141 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | 141 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ |
142 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \ | 142 | .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \ |
143 | .event = wevent, .event_flags = wflags} | 143 | .event = wevent, .event_flags = wflags} |
144 | #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ | 144 | #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ |
145 | wevent, wflags) \ | 145 | wevent, wflags) \ |
146 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | 146 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ |
147 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ | 147 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ |
148 | .event = wevent, .event_flags = wflags} | 148 | .event = wevent, .event_flags = wflags} |
149 | #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | 149 | #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ |
150 | wevent, wflags) \ | 150 | wevent, wflags) \ |
151 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 151 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ |
152 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ | 152 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ |
153 | .event = wevent, .event_flags = wflags} | 153 | .event = wevent, .event_flags = wflags} |
154 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | 154 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ |
155 | wevent, wflags) \ | 155 | wevent, wflags) \ |
156 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 156 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ |
157 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ | 157 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ |
158 | .event = wevent, .event_flags = wflags} | 158 | .event = wevent, .event_flags = wflags} |
159 | 159 | ||
160 | /* additional sequencing control within an event type */ | 160 | /* additional sequencing control within an event type */ |
@@ -173,26 +173,26 @@ | |||
173 | #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ | 173 | #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ |
174 | wevent, wflags) \ | 174 | wevent, wflags) \ |
175 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 175 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ |
176 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | 176 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ |
177 | .event = wevent, .event_flags = wflags} | 177 | .event = wevent, .event_flags = wflags} |
178 | #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ | 178 | #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ |
179 | wevent, wflags) \ | 179 | wevent, wflags) \ |
180 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 180 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
181 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | 181 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ |
182 | .event = wevent, .event_flags = wflags} | 182 | .event = wevent, .event_flags = wflags} |
183 | #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ | 183 | #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ |
184 | wcontrols, wevent, wflags) \ | 184 | wcontrols, wevent, wflags) \ |
185 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 185 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
186 | .invert = winvert, .kcontrols = wcontrols, \ | 186 | .invert = winvert, .kcontrol_news = wcontrols, \ |
187 | .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags} | 187 | .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags} |
188 | 188 | ||
189 | /* events that are pre and post DAPM */ | 189 | /* events that are pre and post DAPM */ |
190 | #define SND_SOC_DAPM_PRE(wname, wevent) \ | 190 | #define SND_SOC_DAPM_PRE(wname, wevent) \ |
191 | { .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ | 191 | { .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \ |
192 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 192 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
193 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} | 193 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} |
194 | #define SND_SOC_DAPM_POST(wname, wevent) \ | 194 | #define SND_SOC_DAPM_POST(wname, wevent) \ |
195 | { .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \ | 195 | { .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \ |
196 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 196 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
197 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} | 197 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} |
198 | 198 | ||
@@ -232,7 +232,7 @@ | |||
232 | 232 | ||
233 | /* generic widgets */ | 233 | /* generic widgets */ |
234 | #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ | 234 | #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ |
235 | { .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \ | 235 | { .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ |
236 | .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ | 236 | .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ |
237 | .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ | 237 | .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ |
238 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} | 238 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} |
@@ -356,7 +356,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card); | |||
356 | 356 | ||
357 | /* dapm sys fs - used by the core */ | 357 | /* dapm sys fs - used by the core */ |
358 | int snd_soc_dapm_sys_add(struct device *dev); | 358 | int snd_soc_dapm_sys_add(struct device *dev); |
359 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm); | 359 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, |
360 | struct dentry *parent); | ||
360 | 361 | ||
361 | /* dapm audio pin control and status */ | 362 | /* dapm audio pin control and status */ |
362 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, | 363 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, |
@@ -472,7 +473,8 @@ struct snd_soc_dapm_widget { | |||
472 | 473 | ||
473 | /* kcontrols that relate to this widget */ | 474 | /* kcontrols that relate to this widget */ |
474 | int num_kcontrols; | 475 | int num_kcontrols; |
475 | const struct snd_kcontrol_new *kcontrols; | 476 | const struct snd_kcontrol_new *kcontrol_news; |
477 | struct snd_kcontrol **kcontrols; | ||
476 | 478 | ||
477 | /* widget input and outputs */ | 479 | /* widget input and outputs */ |
478 | struct list_head sources; | 480 | struct list_head sources; |
@@ -516,4 +518,10 @@ struct snd_soc_dapm_context { | |||
516 | #endif | 518 | #endif |
517 | }; | 519 | }; |
518 | 520 | ||
521 | /* A list of widgets associated with an object, typically a snd_kcontrol */ | ||
522 | struct snd_soc_dapm_widget_list { | ||
523 | int num_widgets; | ||
524 | struct snd_soc_dapm_widget *widgets[0]; | ||
525 | }; | ||
526 | |||
519 | #endif | 527 | #endif |
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 06b6981b8d6d..19241576b6b5 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
@@ -120,7 +120,7 @@ | |||
120 | */ | 120 | */ |
121 | #define PM860X_DAPM_OUTPUT(wname, wevent) \ | 121 | #define PM860X_DAPM_OUTPUT(wname, wevent) \ |
122 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ | 122 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ |
123 | .shift = 0, .invert = 0, .kcontrols = NULL, \ | 123 | .shift = 0, .invert = 0, .kcontrol_news = NULL, \ |
124 | .num_kcontrols = 0, .event = wevent, \ | 124 | .num_kcontrols = 0, .event = wevent, \ |
125 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, } | 125 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, } |
126 | 126 | ||
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 7e2194975360..70099c9d63c7 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -40,17 +40,25 @@ | |||
40 | #include <sound/pcm_params.h> | 40 | #include <sound/pcm_params.h> |
41 | #include <sound/soc.h> | 41 | #include <sound/soc.h> |
42 | #include <sound/initval.h> | 42 | #include <sound/initval.h> |
43 | #include <sound/tlv.h> | ||
43 | 44 | ||
44 | #include "ssm2602.h" | 45 | #include "ssm2602.h" |
45 | 46 | ||
46 | #define SSM2602_VERSION "0.1" | 47 | #define SSM2602_VERSION "0.1" |
47 | 48 | ||
49 | enum ssm2602_type { | ||
50 | SSM2602, | ||
51 | SSM2604, | ||
52 | }; | ||
53 | |||
48 | /* codec private data */ | 54 | /* codec private data */ |
49 | struct ssm2602_priv { | 55 | struct ssm2602_priv { |
50 | unsigned int sysclk; | 56 | unsigned int sysclk; |
51 | enum snd_soc_control_type control_type; | 57 | enum snd_soc_control_type control_type; |
52 | struct snd_pcm_substream *master_substream; | 58 | struct snd_pcm_substream *master_substream; |
53 | struct snd_pcm_substream *slave_substream; | 59 | struct snd_pcm_substream *slave_substream; |
60 | |||
61 | enum ssm2602_type type; | ||
54 | }; | 62 | }; |
55 | 63 | ||
56 | /* | 64 | /* |
@@ -60,8 +68,8 @@ struct ssm2602_priv { | |||
60 | * There is no point in caching the reset register | 68 | * There is no point in caching the reset register |
61 | */ | 69 | */ |
62 | static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | 70 | static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { |
63 | 0x0017, 0x0017, 0x0079, 0x0079, | 71 | 0x0097, 0x0097, 0x0079, 0x0079, |
64 | 0x0000, 0x0000, 0x0000, 0x000a, | 72 | 0x000a, 0x0008, 0x009f, 0x000a, |
65 | 0x0000, 0x0000 | 73 | 0x0000, 0x0000 |
66 | }; | 74 | }; |
67 | 75 | ||
@@ -80,172 +88,186 @@ static const struct soc_enum ssm2602_enum[] = { | |||
80 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), | 88 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), |
81 | }; | 89 | }; |
82 | 90 | ||
83 | static const struct snd_kcontrol_new ssm2602_snd_controls[] = { | 91 | static const unsigned int ssm260x_outmix_tlv[] = { |
92 | TLV_DB_RANGE_HEAD(2), | ||
93 | 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
94 | 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0), | ||
95 | }; | ||
84 | 96 | ||
85 | SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, | 97 | static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0); |
86 | 0, 127, 0), | 98 | static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0); |
87 | SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
88 | 7, 1, 0), | ||
89 | 99 | ||
90 | SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), | 100 | static const struct snd_kcontrol_new ssm260x_snd_controls[] = { |
101 | SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0, | ||
102 | ssm260x_inpga_tlv), | ||
91 | SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), | 103 | SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), |
92 | 104 | ||
93 | SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), | ||
94 | SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0), | ||
95 | SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), | ||
96 | |||
97 | SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), | ||
98 | |||
99 | SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), | 105 | SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), |
100 | SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), | 106 | SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), |
101 | 107 | ||
102 | SOC_ENUM("Capture Source", ssm2602_enum[0]), | ||
103 | |||
104 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | 108 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), |
105 | }; | 109 | }; |
106 | 110 | ||
111 | static const struct snd_kcontrol_new ssm2602_snd_controls[] = { | ||
112 | SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
113 | 0, 127, 0, ssm260x_outmix_tlv), | ||
114 | SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
115 | 7, 1, 0), | ||
116 | SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1, | ||
117 | ssm260x_sidetone_tlv), | ||
118 | |||
119 | SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), | ||
120 | SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), | ||
121 | SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), | ||
122 | }; | ||
123 | |||
107 | /* Output Mixer */ | 124 | /* Output Mixer */ |
108 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | 125 | static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = { |
109 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | 126 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), |
110 | SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), | ||
111 | SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), | 127 | SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), |
128 | SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), | ||
112 | }; | 129 | }; |
113 | 130 | ||
114 | /* Input mux */ | 131 | /* Input mux */ |
115 | static const struct snd_kcontrol_new ssm2602_input_mux_controls = | 132 | static const struct snd_kcontrol_new ssm2602_input_mux_controls = |
116 | SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); | 133 | SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); |
117 | 134 | ||
118 | static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { | 135 | static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = { |
119 | SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, | ||
120 | &ssm2602_output_mixer_controls[0], | ||
121 | ARRAY_SIZE(ssm2602_output_mixer_controls)), | ||
122 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), | 136 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), |
137 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), | ||
138 | SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), | ||
139 | |||
140 | SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, 0, 0), | ||
141 | |||
123 | SND_SOC_DAPM_OUTPUT("LOUT"), | 142 | SND_SOC_DAPM_OUTPUT("LOUT"), |
124 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
125 | SND_SOC_DAPM_OUTPUT("ROUT"), | 143 | SND_SOC_DAPM_OUTPUT("ROUT"), |
126 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | 144 | SND_SOC_DAPM_INPUT("RLINEIN"), |
127 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), | 145 | SND_SOC_DAPM_INPUT("LLINEIN"), |
146 | }; | ||
147 | |||
148 | static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { | ||
149 | SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, | ||
150 | ssm260x_output_mixer_controls, | ||
151 | ARRAY_SIZE(ssm260x_output_mixer_controls)), | ||
152 | |||
128 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), | 153 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), |
129 | SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), | ||
130 | SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), | 154 | SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), |
155 | |||
156 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
157 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
131 | SND_SOC_DAPM_INPUT("MICIN"), | 158 | SND_SOC_DAPM_INPUT("MICIN"), |
132 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
133 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
134 | }; | 159 | }; |
135 | 160 | ||
136 | static const struct snd_soc_dapm_route audio_conn[] = { | 161 | static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = { |
137 | /* output mixer */ | 162 | SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, |
163 | ssm260x_output_mixer_controls, | ||
164 | ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */ | ||
165 | }; | ||
166 | |||
167 | static const struct snd_soc_dapm_route ssm260x_routes[] = { | ||
168 | {"DAC", NULL, "Digital Core Power"}, | ||
169 | {"ADC", NULL, "Digital Core Power"}, | ||
170 | |||
138 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 171 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
139 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | 172 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
173 | |||
174 | {"ROUT", NULL, "Output Mixer"}, | ||
175 | {"LOUT", NULL, "Output Mixer"}, | ||
176 | |||
177 | {"Line Input", NULL, "LLINEIN"}, | ||
178 | {"Line Input", NULL, "RLINEIN"}, | ||
179 | }; | ||
180 | |||
181 | static const struct snd_soc_dapm_route ssm2602_routes[] = { | ||
140 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | 182 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, |
141 | 183 | ||
142 | /* outputs */ | ||
143 | {"RHPOUT", NULL, "Output Mixer"}, | 184 | {"RHPOUT", NULL, "Output Mixer"}, |
144 | {"ROUT", NULL, "Output Mixer"}, | ||
145 | {"LHPOUT", NULL, "Output Mixer"}, | 185 | {"LHPOUT", NULL, "Output Mixer"}, |
146 | {"LOUT", NULL, "Output Mixer"}, | ||
147 | 186 | ||
148 | /* input mux */ | ||
149 | {"Input Mux", "Line", "Line Input"}, | 187 | {"Input Mux", "Line", "Line Input"}, |
150 | {"Input Mux", "Mic", "Mic Bias"}, | 188 | {"Input Mux", "Mic", "Mic Bias"}, |
151 | {"ADC", NULL, "Input Mux"}, | 189 | {"ADC", NULL, "Input Mux"}, |
152 | 190 | ||
153 | /* inputs */ | ||
154 | {"Line Input", NULL, "LLINEIN"}, | ||
155 | {"Line Input", NULL, "RLINEIN"}, | ||
156 | {"Mic Bias", NULL, "MICIN"}, | 191 | {"Mic Bias", NULL, "MICIN"}, |
157 | }; | 192 | }; |
158 | 193 | ||
159 | static int ssm2602_add_widgets(struct snd_soc_codec *codec) | 194 | static const struct snd_soc_dapm_route ssm2604_routes[] = { |
160 | { | 195 | {"ADC", NULL, "Line Input"}, |
161 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 196 | }; |
162 | |||
163 | snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets, | ||
164 | ARRAY_SIZE(ssm2602_dapm_widgets)); | ||
165 | snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn)); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | 197 | ||
170 | struct _coeff_div { | 198 | struct ssm2602_coeff { |
171 | u32 mclk; | 199 | u32 mclk; |
172 | u32 rate; | 200 | u32 rate; |
173 | u16 fs; | 201 | u8 srate; |
174 | u8 sr:4; | ||
175 | u8 bosr:1; | ||
176 | u8 usb:1; | ||
177 | }; | 202 | }; |
178 | 203 | ||
179 | /* codec mclk clock divider coefficients */ | 204 | #define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb)) |
180 | static const struct _coeff_div coeff_div[] = { | 205 | |
206 | /* codec mclk clock coefficients */ | ||
207 | static const struct ssm2602_coeff ssm2602_coeff_table[] = { | ||
181 | /* 48k */ | 208 | /* 48k */ |
182 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | 209 | {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)}, |
183 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | 210 | {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)}, |
184 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | 211 | {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)}, |
185 | 212 | ||
186 | /* 32k */ | 213 | /* 32k */ |
187 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | 214 | {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)}, |
188 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | 215 | {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)}, |
189 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | 216 | {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)}, |
190 | 217 | ||
191 | /* 8k */ | 218 | /* 8k */ |
192 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | 219 | {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)}, |
193 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | 220 | {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)}, |
194 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | 221 | {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)}, |
195 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | 222 | {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)}, |
196 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | 223 | {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)}, |
197 | 224 | ||
198 | /* 96k */ | 225 | /* 96k */ |
199 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | 226 | {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)}, |
200 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | 227 | {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, |
201 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | 228 | {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, |
202 | 229 | ||
203 | /* 44.1k */ | 230 | /* 44.1k */ |
204 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | 231 | {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, |
205 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | 232 | {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, |
206 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | 233 | {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)}, |
207 | 234 | ||
208 | /* 88.2k */ | 235 | /* 88.2k */ |
209 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | 236 | {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)}, |
210 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | 237 | {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)}, |
211 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | 238 | {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)}, |
212 | }; | 239 | }; |
213 | 240 | ||
214 | static inline int get_coeff(int mclk, int rate) | 241 | static inline int ssm2602_get_coeff(int mclk, int rate) |
215 | { | 242 | { |
216 | int i; | 243 | int i; |
217 | 244 | ||
218 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | 245 | for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) { |
219 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | 246 | if (ssm2602_coeff_table[i].rate == rate && |
220 | return i; | 247 | ssm2602_coeff_table[i].mclk == mclk) |
248 | return ssm2602_coeff_table[i].srate; | ||
221 | } | 249 | } |
222 | return i; | 250 | return -EINVAL; |
223 | } | 251 | } |
224 | 252 | ||
225 | static int ssm2602_hw_params(struct snd_pcm_substream *substream, | 253 | static int ssm2602_hw_params(struct snd_pcm_substream *substream, |
226 | struct snd_pcm_hw_params *params, | 254 | struct snd_pcm_hw_params *params, |
227 | struct snd_soc_dai *dai) | 255 | struct snd_soc_dai *dai) |
228 | { | 256 | { |
229 | u16 srate; | ||
230 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 257 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
231 | struct snd_soc_codec *codec = rtd->codec; | 258 | struct snd_soc_codec *codec = rtd->codec; |
232 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 259 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
233 | u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3; | 260 | u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3; |
234 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); | 261 | int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params)); |
235 | 262 | ||
236 | if (substream == ssm2602->slave_substream) { | 263 | if (substream == ssm2602->slave_substream) { |
237 | dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); | 264 | dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); |
238 | return 0; | 265 | return 0; |
239 | } | 266 | } |
240 | 267 | ||
241 | /*no match is found*/ | 268 | if (srate < 0) |
242 | if (i == ARRAY_SIZE(coeff_div)) | 269 | return srate; |
243 | return -EINVAL; | ||
244 | 270 | ||
245 | srate = (coeff_div[i].sr << 2) | | ||
246 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
247 | |||
248 | snd_soc_write(codec, SSM2602_ACTIVE, 0); | ||
249 | snd_soc_write(codec, SSM2602_SRATE, srate); | 271 | snd_soc_write(codec, SSM2602_SRATE, srate); |
250 | 272 | ||
251 | /* bit size */ | 273 | /* bit size */ |
@@ -263,7 +285,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
263 | break; | 285 | break; |
264 | } | 286 | } |
265 | snd_soc_write(codec, SSM2602_IFACE, iface); | 287 | snd_soc_write(codec, SSM2602_IFACE, iface); |
266 | snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
267 | return 0; | 288 | return 0; |
268 | } | 289 | } |
269 | 290 | ||
@@ -305,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, | |||
305 | return 0; | 326 | return 0; |
306 | } | 327 | } |
307 | 328 | ||
308 | static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, | ||
309 | struct snd_soc_dai *dai) | ||
310 | { | ||
311 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
312 | struct snd_soc_codec *codec = rtd->codec; | ||
313 | /* set active */ | ||
314 | snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static void ssm2602_shutdown(struct snd_pcm_substream *substream, | 329 | static void ssm2602_shutdown(struct snd_pcm_substream *substream, |
320 | struct snd_soc_dai *dai) | 330 | struct snd_soc_dai *dai) |
321 | { | 331 | { |
@@ -323,16 +333,13 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
323 | struct snd_soc_codec *codec = rtd->codec; | 333 | struct snd_soc_codec *codec = rtd->codec; |
324 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 334 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
325 | 335 | ||
326 | /* deactivate */ | ||
327 | if (!codec->active) | ||
328 | snd_soc_write(codec, SSM2602_ACTIVE, 0); | ||
329 | |||
330 | if (ssm2602->master_substream == substream) | 336 | if (ssm2602->master_substream == substream) |
331 | ssm2602->master_substream = ssm2602->slave_substream; | 337 | ssm2602->master_substream = ssm2602->slave_substream; |
332 | 338 | ||
333 | ssm2602->slave_substream = NULL; | 339 | ssm2602->slave_substream = NULL; |
334 | } | 340 | } |
335 | 341 | ||
342 | |||
336 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | 343 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) |
337 | { | 344 | { |
338 | struct snd_soc_codec *codec = dai->codec; | 345 | struct snd_soc_codec *codec = dai->codec; |
@@ -439,7 +446,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | |||
439 | break; | 446 | break; |
440 | case SND_SOC_BIAS_OFF: | 447 | case SND_SOC_BIAS_OFF: |
441 | /* everything off, dac mute, inactive */ | 448 | /* everything off, dac mute, inactive */ |
442 | snd_soc_write(codec, SSM2602_ACTIVE, 0); | ||
443 | snd_soc_write(codec, SSM2602_PWR, 0xffff); | 449 | snd_soc_write(codec, SSM2602_PWR, 0xffff); |
444 | break; | 450 | break; |
445 | 451 | ||
@@ -457,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | |||
457 | 463 | ||
458 | static struct snd_soc_dai_ops ssm2602_dai_ops = { | 464 | static struct snd_soc_dai_ops ssm2602_dai_ops = { |
459 | .startup = ssm2602_startup, | 465 | .startup = ssm2602_startup, |
460 | .prepare = ssm2602_pcm_prepare, | ||
461 | .hw_params = ssm2602_hw_params, | 466 | .hw_params = ssm2602_hw_params, |
462 | .shutdown = ssm2602_shutdown, | 467 | .shutdown = ssm2602_shutdown, |
463 | .digital_mute = ssm2602_mute, | 468 | .digital_mute = ssm2602_mute, |
@@ -499,8 +504,46 @@ static int ssm2602_resume(struct snd_soc_codec *codec) | |||
499 | 504 | ||
500 | static int ssm2602_probe(struct snd_soc_codec *codec) | 505 | static int ssm2602_probe(struct snd_soc_codec *codec) |
501 | { | 506 | { |
507 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
508 | int ret, reg; | ||
509 | |||
510 | reg = snd_soc_read(codec, SSM2602_LOUT1V); | ||
511 | snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | ||
512 | reg = snd_soc_read(codec, SSM2602_ROUT1V); | ||
513 | snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | ||
514 | |||
515 | ret = snd_soc_add_controls(codec, ssm2602_snd_controls, | ||
516 | ARRAY_SIZE(ssm2602_snd_controls)); | ||
517 | if (ret) | ||
518 | return ret; | ||
519 | |||
520 | ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets, | ||
521 | ARRAY_SIZE(ssm2602_dapm_widgets)); | ||
522 | if (ret) | ||
523 | return ret; | ||
524 | |||
525 | return snd_soc_dapm_add_routes(dapm, ssm2602_routes, | ||
526 | ARRAY_SIZE(ssm2602_routes)); | ||
527 | } | ||
528 | |||
529 | static int ssm2604_probe(struct snd_soc_codec *codec) | ||
530 | { | ||
531 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
532 | int ret; | ||
533 | |||
534 | ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets, | ||
535 | ARRAY_SIZE(ssm2604_dapm_widgets)); | ||
536 | if (ret) | ||
537 | return ret; | ||
538 | |||
539 | return snd_soc_dapm_add_routes(dapm, ssm2604_routes, | ||
540 | ARRAY_SIZE(ssm2604_routes)); | ||
541 | } | ||
542 | |||
543 | static int ssm260x_probe(struct snd_soc_codec *codec) | ||
544 | { | ||
502 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 545 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
503 | int ret = 0, reg; | 546 | int ret, reg; |
504 | 547 | ||
505 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | 548 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); |
506 | 549 | ||
@@ -516,27 +559,25 @@ static int ssm2602_probe(struct snd_soc_codec *codec) | |||
516 | return ret; | 559 | return ret; |
517 | } | 560 | } |
518 | 561 | ||
519 | /*power on device*/ | ||
520 | snd_soc_write(codec, SSM2602_ACTIVE, 0); | ||
521 | /* set the update bits */ | 562 | /* set the update bits */ |
522 | reg = snd_soc_read(codec, SSM2602_LINVOL); | 563 | reg = snd_soc_read(codec, SSM2602_LINVOL); |
523 | snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | 564 | snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); |
524 | reg = snd_soc_read(codec, SSM2602_RINVOL); | 565 | reg = snd_soc_read(codec, SSM2602_RINVOL); |
525 | snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | 566 | snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); |
526 | reg = snd_soc_read(codec, SSM2602_LOUT1V); | ||
527 | snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | ||
528 | reg = snd_soc_read(codec, SSM2602_ROUT1V); | ||
529 | snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | ||
530 | /*select Line in as default input*/ | 567 | /*select Line in as default input*/ |
531 | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | | 568 | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | |
532 | APANA_ENABLE_MIC_BOOST); | 569 | APANA_ENABLE_MIC_BOOST); |
533 | snd_soc_write(codec, SSM2602_PWR, 0); | ||
534 | 570 | ||
535 | snd_soc_add_controls(codec, ssm2602_snd_controls, | 571 | switch (ssm2602->type) { |
536 | ARRAY_SIZE(ssm2602_snd_controls)); | 572 | case SSM2602: |
537 | ssm2602_add_widgets(codec); | 573 | ret = ssm2602_probe(codec); |
574 | break; | ||
575 | case SSM2604: | ||
576 | ret = ssm2604_probe(codec); | ||
577 | break; | ||
578 | } | ||
538 | 579 | ||
539 | return 0; | 580 | return ret; |
540 | } | 581 | } |
541 | 582 | ||
542 | /* remove everything here */ | 583 | /* remove everything here */ |
@@ -547,14 +588,21 @@ static int ssm2602_remove(struct snd_soc_codec *codec) | |||
547 | } | 588 | } |
548 | 589 | ||
549 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { | 590 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { |
550 | .probe = ssm2602_probe, | 591 | .probe = ssm260x_probe, |
551 | .remove = ssm2602_remove, | 592 | .remove = ssm2602_remove, |
552 | .suspend = ssm2602_suspend, | 593 | .suspend = ssm2602_suspend, |
553 | .resume = ssm2602_resume, | 594 | .resume = ssm2602_resume, |
554 | .set_bias_level = ssm2602_set_bias_level, | 595 | .set_bias_level = ssm2602_set_bias_level, |
555 | .reg_cache_size = sizeof(ssm2602_reg), | 596 | .reg_cache_size = ARRAY_SIZE(ssm2602_reg), |
556 | .reg_word_size = sizeof(u16), | 597 | .reg_word_size = sizeof(u16), |
557 | .reg_cache_default = ssm2602_reg, | 598 | .reg_cache_default = ssm2602_reg, |
599 | |||
600 | .controls = ssm260x_snd_controls, | ||
601 | .num_controls = ARRAY_SIZE(ssm260x_snd_controls), | ||
602 | .dapm_widgets = ssm260x_dapm_widgets, | ||
603 | .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets), | ||
604 | .dapm_routes = ssm260x_routes, | ||
605 | .num_dapm_routes = ARRAY_SIZE(ssm260x_routes), | ||
558 | }; | 606 | }; |
559 | 607 | ||
560 | #if defined(CONFIG_SPI_MASTER) | 608 | #if defined(CONFIG_SPI_MASTER) |
@@ -569,6 +617,7 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi) | |||
569 | 617 | ||
570 | spi_set_drvdata(spi, ssm2602); | 618 | spi_set_drvdata(spi, ssm2602); |
571 | ssm2602->control_type = SND_SOC_SPI; | 619 | ssm2602->control_type = SND_SOC_SPI; |
620 | ssm2602->type = SSM2602; | ||
572 | 621 | ||
573 | ret = snd_soc_register_codec(&spi->dev, | 622 | ret = snd_soc_register_codec(&spi->dev, |
574 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | 623 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); |
@@ -601,7 +650,7 @@ static struct spi_driver ssm2602_spi_driver = { | |||
601 | * low = 0x1a | 650 | * low = 0x1a |
602 | * high = 0x1b | 651 | * high = 0x1b |
603 | */ | 652 | */ |
604 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | 653 | static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c, |
605 | const struct i2c_device_id *id) | 654 | const struct i2c_device_id *id) |
606 | { | 655 | { |
607 | struct ssm2602_priv *ssm2602; | 656 | struct ssm2602_priv *ssm2602; |
@@ -613,6 +662,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, | |||
613 | 662 | ||
614 | i2c_set_clientdata(i2c, ssm2602); | 663 | i2c_set_clientdata(i2c, ssm2602); |
615 | ssm2602->control_type = SND_SOC_I2C; | 664 | ssm2602->control_type = SND_SOC_I2C; |
665 | ssm2602->type = id->driver_data; | ||
616 | 666 | ||
617 | ret = snd_soc_register_codec(&i2c->dev, | 667 | ret = snd_soc_register_codec(&i2c->dev, |
618 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | 668 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); |
@@ -621,7 +671,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, | |||
621 | return ret; | 671 | return ret; |
622 | } | 672 | } |
623 | 673 | ||
624 | static int ssm2602_i2c_remove(struct i2c_client *client) | 674 | static int __devexit ssm2602_i2c_remove(struct i2c_client *client) |
625 | { | 675 | { |
626 | snd_soc_unregister_codec(&client->dev); | 676 | snd_soc_unregister_codec(&client->dev); |
627 | kfree(i2c_get_clientdata(client)); | 677 | kfree(i2c_get_clientdata(client)); |
@@ -629,7 +679,9 @@ static int ssm2602_i2c_remove(struct i2c_client *client) | |||
629 | } | 679 | } |
630 | 680 | ||
631 | static const struct i2c_device_id ssm2602_i2c_id[] = { | 681 | static const struct i2c_device_id ssm2602_i2c_id[] = { |
632 | { "ssm2602", 0 }, | 682 | { "ssm2602", SSM2602 }, |
683 | { "ssm2603", SSM2602 }, | ||
684 | { "ssm2604", SSM2604 }, | ||
633 | { } | 685 | { } |
634 | }; | 686 | }; |
635 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | 687 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); |
@@ -641,7 +693,7 @@ static struct i2c_driver ssm2602_i2c_driver = { | |||
641 | .owner = THIS_MODULE, | 693 | .owner = THIS_MODULE, |
642 | }, | 694 | }, |
643 | .probe = ssm2602_i2c_probe, | 695 | .probe = ssm2602_i2c_probe, |
644 | .remove = ssm2602_i2c_remove, | 696 | .remove = __devexit_p(ssm2602_i2c_remove), |
645 | .id_table = ssm2602_i2c_id, | 697 | .id_table = ssm2602_i2c_id, |
646 | }; | 698 | }; |
647 | #endif | 699 | #endif |
@@ -679,6 +731,6 @@ static void __exit ssm2602_exit(void) | |||
679 | } | 731 | } |
680 | module_exit(ssm2602_exit); | 732 | module_exit(ssm2602_exit); |
681 | 733 | ||
682 | MODULE_DESCRIPTION("ASoC ssm2602 driver"); | 734 | MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); |
683 | MODULE_AUTHOR("Cliff Cai"); | 735 | MODULE_AUTHOR("Cliff Cai"); |
684 | MODULE_LICENSE("GPL"); | 736 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h index 42a47d0f8e25..b98c69168036 100644 --- a/sound/soc/codecs/ssm2602.h +++ b/sound/soc/codecs/ssm2602.h | |||
@@ -117,11 +117,5 @@ | |||
117 | #define SSM2602_CACHEREGNUM 10 | 117 | #define SSM2602_CACHEREGNUM 10 |
118 | 118 | ||
119 | #define SSM2602_SYSCLK 0 | 119 | #define SSM2602_SYSCLK 0 |
120 | #define SSM2602_DAI 0 | ||
121 | |||
122 | struct ssm2602_setup_data { | ||
123 | int i2c_bus; | ||
124 | unsigned short i2c_address; | ||
125 | }; | ||
126 | 120 | ||
127 | #endif | 121 | #endif |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 48ffd406a71d..a7b8f301bad3 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { | |||
601 | .reg_cache_step = 1, | 601 | .reg_cache_step = 1, |
602 | .read = uda134x_read_reg_cache, | 602 | .read = uda134x_read_reg_cache, |
603 | .write = uda134x_write, | 603 | .write = uda134x_write, |
604 | #ifdef POWER_OFF_ON_STANDBY | ||
605 | .set_bias_level = uda134x_set_bias_level, | 604 | .set_bias_level = uda134x_set_bias_level, |
606 | #endif | ||
607 | }; | 605 | }; |
608 | 606 | ||
609 | static int __devinit uda134x_codec_probe(struct platform_device *pdev) | 607 | static int __devinit uda134x_codec_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c index 4a3c5cc77e55..ccc9bd832794 100644 --- a/sound/soc/codecs/wm8915.c +++ b/sound/soc/codecs/wm8915.c | |||
@@ -991,17 +991,16 @@ SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0), | |||
991 | SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0), | 991 | SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0), |
992 | SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0), | 992 | SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0), |
993 | 993 | ||
994 | SND_SOC_DAPM_PGA("ADC", SND_SOC_NOPM, 0, 0, NULL, 0), | 994 | SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux), |
995 | 995 | SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux), | |
996 | SND_SOC_DAPM_MUX("IN1 Mux", SND_SOC_NOPM, 0, 0, &in1_mux), | 996 | SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux), |
997 | SND_SOC_DAPM_MUX("IN2 Mux", SND_SOC_NOPM, 0, 0, &in2_mux), | 997 | SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux), |
998 | 998 | ||
999 | SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0), | 999 | SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0), |
1000 | SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0), | 1000 | SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0), |
1001 | SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0), | 1001 | SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0), |
1002 | SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0), | 1002 | SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0), |
1003 | 1003 | ||
1004 | /* FIXME - these need to be concentrator widgets */ | ||
1005 | SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0), | 1004 | SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0), |
1006 | SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0), | 1005 | SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0), |
1007 | 1006 | ||
@@ -1172,28 +1171,33 @@ static const struct snd_soc_dapm_route wm8915_dapm_routes[] = { | |||
1172 | { "DMIC1L", NULL, "DMIC1" }, | 1171 | { "DMIC1L", NULL, "DMIC1" }, |
1173 | { "DMIC1R", NULL, "DMIC1" }, | 1172 | { "DMIC1R", NULL, "DMIC1" }, |
1174 | 1173 | ||
1175 | { "ADC", NULL, "ADCL" }, | 1174 | { "IN1L Mux", "ADC", "ADCL" }, |
1176 | { "ADC", NULL, "ADCR" }, | 1175 | { "IN1L Mux", "DMIC1", "DMIC1L" }, |
1176 | { "IN1L Mux", "DMIC2", "DMIC2L" }, | ||
1177 | |||
1178 | { "IN1R Mux", "ADC", "ADCR" }, | ||
1179 | { "IN1R Mux", "DMIC1", "DMIC1R" }, | ||
1180 | { "IN1R Mux", "DMIC2", "DMIC2R" }, | ||
1177 | 1181 | ||
1178 | { "IN1 Mux", "ADC", "ADC" }, | 1182 | { "IN2L Mux", "ADC", "ADCL" }, |
1179 | { "IN1 Mux", "DMIC1", "DMIC1" }, | 1183 | { "IN2L Mux", "DMIC1", "DMIC1L" }, |
1180 | { "IN1 Mux", "DMIC2", "DMIC2" }, | 1184 | { "IN2L Mux", "DMIC2", "DMIC2L" }, |
1181 | 1185 | ||
1182 | { "IN2 Mux", "ADC", "ADC" }, | 1186 | { "IN2R Mux", "ADC", "ADCR" }, |
1183 | { "IN2 Mux", "DMIC1", "DMIC1" }, | 1187 | { "IN2R Mux", "DMIC1", "DMIC1R" }, |
1184 | { "IN2 Mux", "DMIC2", "DMIC2" }, | 1188 | { "IN2R Mux", "DMIC2", "DMIC2R" }, |
1185 | 1189 | ||
1186 | { "Left Sidetone", "IN1", "IN1 Mux" }, | 1190 | { "Left Sidetone", "IN1", "IN1L Mux" }, |
1187 | { "Left Sidetone", "IN2", "IN2 Mux" }, | 1191 | { "Left Sidetone", "IN2", "IN2L Mux" }, |
1188 | 1192 | ||
1189 | { "Right Sidetone", "IN1", "IN1 Mux" }, | 1193 | { "Right Sidetone", "IN1", "IN1R Mux" }, |
1190 | { "Right Sidetone", "IN2", "IN2 Mux" }, | 1194 | { "Right Sidetone", "IN2", "IN2R Mux" }, |
1191 | 1195 | ||
1192 | { "DSP1TXL", "IN1 Switch", "IN1 Mux" }, | 1196 | { "DSP1TXL", "IN1 Switch", "IN1L Mux" }, |
1193 | { "DSP1TXR", "IN1 Switch", "IN1 Mux" }, | 1197 | { "DSP1TXR", "IN1 Switch", "IN1R Mux" }, |
1194 | 1198 | ||
1195 | { "DSP2TXL", "IN1 Switch", "IN2 Mux" }, | 1199 | { "DSP2TXL", "IN1 Switch", "IN2L Mux" }, |
1196 | { "DSP2TXR", "IN1 Switch", "IN2 Mux" }, | 1200 | { "DSP2TXR", "IN1 Switch", "IN2R Mux" }, |
1197 | 1201 | ||
1198 | { "AIF1TX0", NULL, "DSP1TXL" }, | 1202 | { "AIF1TX0", NULL, "DSP1TXL" }, |
1199 | { "AIF1TX1", NULL, "DSP1TXR" }, | 1203 | { "AIF1TX1", NULL, "DSP1TXR" }, |
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 419bf4f5534a..cd22a54b2f14 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c | |||
@@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, | |||
133 | struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 133 | struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
134 | uint32_t conf; | 134 | uint32_t conf; |
135 | 135 | ||
136 | if (!dai->active) | 136 | if (dai->active) |
137 | return; | 137 | return; |
138 | 138 | ||
139 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); | 139 | conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); |
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index 9765fb81a5e3..5a946b4115a2 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c | |||
@@ -380,6 +380,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | |||
380 | return 0; | 380 | return 0; |
381 | } | 381 | } |
382 | 382 | ||
383 | static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) | ||
384 | { | ||
385 | return snd_pcm_lib_free_pages(substream); | ||
386 | } | ||
387 | |||
383 | static struct snd_pcm_ops sst_platform_ops = { | 388 | static struct snd_pcm_ops sst_platform_ops = { |
384 | .open = sst_platform_open, | 389 | .open = sst_platform_open, |
385 | .close = sst_platform_close, | 390 | .close = sst_platform_close, |
@@ -388,6 +393,7 @@ static struct snd_pcm_ops sst_platform_ops = { | |||
388 | .trigger = sst_platform_pcm_trigger, | 393 | .trigger = sst_platform_pcm_trigger, |
389 | .pointer = sst_platform_pcm_pointer, | 394 | .pointer = sst_platform_pcm_pointer, |
390 | .hw_params = sst_platform_pcm_hw_params, | 395 | .hw_params = sst_platform_pcm_hw_params, |
396 | .hw_free = sst_platform_pcm_hw_free, | ||
391 | }; | 397 | }; |
392 | 398 | ||
393 | static void sst_pcm_free(struct snd_pcm *pcm) | 399 | static void sst_pcm_free(struct snd_pcm *pcm) |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index a217db256700..687beec56476 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -404,12 +404,13 @@ static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int r | |||
404 | { | 404 | { |
405 | int ret; | 405 | int ret; |
406 | 406 | ||
407 | /* Ensure that the base register is volatile. Subsequently | 407 | /* To ensure that we don't get out of sync with the cache, check |
408 | * any other register that is touched by this routine should be | 408 | * whether the base register is volatile or if we've directly asked |
409 | * volatile as well to ensure that we don't get out of sync with | 409 | * to bypass the cache. Out of bounds registers are considered |
410 | * the cache. | 410 | * volatile. |
411 | */ | 411 | */ |
412 | if (!snd_soc_codec_volatile_register(codec, reg) | 412 | if (!codec->cache_bypass |
413 | && !snd_soc_codec_volatile_register(codec, reg) | ||
413 | && reg < codec->driver->reg_cache_size) | 414 | && reg < codec->driver->reg_cache_size) |
414 | return -EINVAL; | 415 | return -EINVAL; |
415 | 416 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a823654ef367..a477e218aa28 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -302,13 +302,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
302 | printk(KERN_WARNING | 302 | printk(KERN_WARNING |
303 | "ASoC: Failed to create codec register debugfs file\n"); | 303 | "ASoC: Failed to create codec register debugfs file\n"); |
304 | 304 | ||
305 | codec->dapm.debugfs_dapm = debugfs_create_dir("dapm", | 305 | snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); |
306 | codec->debugfs_codec_root); | ||
307 | if (!codec->dapm.debugfs_dapm) | ||
308 | printk(KERN_WARNING | ||
309 | "Failed to create DAPM debugfs directory\n"); | ||
310 | |||
311 | snd_soc_dapm_debugfs_init(&codec->dapm); | ||
312 | } | 306 | } |
313 | 307 | ||
314 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 308 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
@@ -1499,6 +1493,12 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1499 | if (!try_module_get(codec->dev->driver->owner)) | 1493 | if (!try_module_get(codec->dev->driver->owner)) |
1500 | return -ENODEV; | 1494 | return -ENODEV; |
1501 | 1495 | ||
1496 | soc_init_codec_debugfs(codec); | ||
1497 | |||
1498 | if (driver->dapm_widgets) | ||
1499 | snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, | ||
1500 | driver->num_dapm_widgets); | ||
1501 | |||
1502 | if (driver->probe) { | 1502 | if (driver->probe) { |
1503 | ret = driver->probe(codec); | 1503 | ret = driver->probe(codec); |
1504 | if (ret < 0) { | 1504 | if (ret < 0) { |
@@ -1512,15 +1512,10 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1512 | if (driver->controls) | 1512 | if (driver->controls) |
1513 | snd_soc_add_controls(codec, driver->controls, | 1513 | snd_soc_add_controls(codec, driver->controls, |
1514 | driver->num_controls); | 1514 | driver->num_controls); |
1515 | if (driver->dapm_widgets) | ||
1516 | snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, | ||
1517 | driver->num_dapm_widgets); | ||
1518 | if (driver->dapm_routes) | 1515 | if (driver->dapm_routes) |
1519 | snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, | 1516 | snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, |
1520 | driver->num_dapm_routes); | 1517 | driver->num_dapm_routes); |
1521 | 1518 | ||
1522 | soc_init_codec_debugfs(codec); | ||
1523 | |||
1524 | /* mark codec as probed and add to card codec list */ | 1519 | /* mark codec as probed and add to card codec list */ |
1525 | codec->probed = 1; | 1520 | codec->probed = 1; |
1526 | list_add(&codec->card_list, &card->codec_dev_list); | 1521 | list_add(&codec->card_list, &card->codec_dev_list); |
@@ -1529,6 +1524,7 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1529 | return 0; | 1524 | return 0; |
1530 | 1525 | ||
1531 | err_probe: | 1526 | err_probe: |
1527 | soc_cleanup_codec_debugfs(codec); | ||
1532 | module_put(codec->dev->driver->owner); | 1528 | module_put(codec->dev->driver->owner); |
1533 | 1529 | ||
1534 | return ret; | 1530 | return ret; |
@@ -1879,6 +1875,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1879 | card->dapm.card = card; | 1875 | card->dapm.card = card; |
1880 | list_add(&card->dapm.list, &card->dapm_list); | 1876 | list_add(&card->dapm.list, &card->dapm_list); |
1881 | 1877 | ||
1878 | #ifdef CONFIG_DEBUG_FS | ||
1879 | snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); | ||
1880 | #endif | ||
1881 | |||
1882 | #ifdef CONFIG_PM_SLEEP | 1882 | #ifdef CONFIG_PM_SLEEP |
1883 | /* deferred resume work */ | 1883 | /* deferred resume work */ |
1884 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); | 1884 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); |
@@ -1925,16 +1925,6 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1925 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, | 1925 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, |
1926 | card->num_dapm_routes); | 1926 | card->num_dapm_routes); |
1927 | 1927 | ||
1928 | #ifdef CONFIG_DEBUG_FS | ||
1929 | card->dapm.debugfs_dapm = debugfs_create_dir("dapm", | ||
1930 | card->debugfs_card_root); | ||
1931 | if (!card->dapm.debugfs_dapm) | ||
1932 | printk(KERN_WARNING | ||
1933 | "Failed to create card DAPM debugfs directory\n"); | ||
1934 | |||
1935 | snd_soc_dapm_debugfs_init(&card->dapm); | ||
1936 | #endif | ||
1937 | |||
1938 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), | 1928 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), |
1939 | "%s", card->name); | 1929 | "%s", card->name); |
1940 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), | 1930 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), |
@@ -2047,6 +2037,8 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) | |||
2047 | if (card->remove) | 2037 | if (card->remove) |
2048 | card->remove(card); | 2038 | card->remove(card); |
2049 | 2039 | ||
2040 | snd_soc_dapm_free(&card->dapm); | ||
2041 | |||
2050 | kfree(card->rtd); | 2042 | kfree(card->rtd); |
2051 | snd_card_free(card->snd_card); | 2043 | snd_card_free(card->snd_card); |
2052 | return 0; | 2044 | return 0; |
@@ -3365,6 +3357,8 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3365 | if (!card->name || !card->dev) | 3357 | if (!card->name || !card->dev) |
3366 | return -EINVAL; | 3358 | return -EINVAL; |
3367 | 3359 | ||
3360 | dev_set_drvdata(card->dev, card); | ||
3361 | |||
3368 | snd_soc_initialize_card_lists(card); | 3362 | snd_soc_initialize_card_lists(card); |
3369 | 3363 | ||
3370 | soc_init_card_debugfs(card); | 3364 | soc_init_card_debugfs(card); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 378f08adee56..456617e63789 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -187,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
187 | case snd_soc_dapm_mixer_named_ctl: { | 187 | case snd_soc_dapm_mixer_named_ctl: { |
188 | int val; | 188 | int val; |
189 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 189 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
190 | w->kcontrols[i].private_value; | 190 | w->kcontrol_news[i].private_value; |
191 | unsigned int reg = mc->reg; | 191 | unsigned int reg = mc->reg; |
192 | unsigned int shift = mc->shift; | 192 | unsigned int shift = mc->shift; |
193 | int max = mc->max; | 193 | int max = mc->max; |
@@ -204,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
204 | } | 204 | } |
205 | break; | 205 | break; |
206 | case snd_soc_dapm_mux: { | 206 | case snd_soc_dapm_mux: { |
207 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; | 207 | struct soc_enum *e = (struct soc_enum *) |
208 | w->kcontrol_news[i].private_value; | ||
208 | int val, item, bitmask; | 209 | int val, item, bitmask; |
209 | 210 | ||
210 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 211 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
@@ -220,7 +221,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
220 | } | 221 | } |
221 | break; | 222 | break; |
222 | case snd_soc_dapm_virt_mux: { | 223 | case snd_soc_dapm_virt_mux: { |
223 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; | 224 | struct soc_enum *e = (struct soc_enum *) |
225 | w->kcontrol_news[i].private_value; | ||
224 | 226 | ||
225 | p->connect = 0; | 227 | p->connect = 0; |
226 | /* since a virtual mux has no backing registers to | 228 | /* since a virtual mux has no backing registers to |
@@ -235,7 +237,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
235 | break; | 237 | break; |
236 | case snd_soc_dapm_value_mux: { | 238 | case snd_soc_dapm_value_mux: { |
237 | struct soc_enum *e = (struct soc_enum *) | 239 | struct soc_enum *e = (struct soc_enum *) |
238 | w->kcontrols[i].private_value; | 240 | w->kcontrol_news[i].private_value; |
239 | int val, item; | 241 | int val, item; |
240 | 242 | ||
241 | val = snd_soc_read(w->codec, e->reg); | 243 | val = snd_soc_read(w->codec, e->reg); |
@@ -310,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | |||
310 | 312 | ||
311 | /* search for mixer kcontrol */ | 313 | /* search for mixer kcontrol */ |
312 | for (i = 0; i < dest->num_kcontrols; i++) { | 314 | for (i = 0; i < dest->num_kcontrols; i++) { |
313 | if (!strcmp(control_name, dest->kcontrols[i].name)) { | 315 | if (!strcmp(control_name, dest->kcontrol_news[i].name)) { |
314 | list_add(&path->list, &dapm->card->paths); | 316 | list_add(&path->list, &dapm->card->paths); |
315 | list_add(&path->list_sink, &dest->sources); | 317 | list_add(&path->list_sink, &dest->sources); |
316 | list_add(&path->list_source, &src->sinks); | 318 | list_add(&path->list_source, &src->sinks); |
317 | path->name = dest->kcontrols[i].name; | 319 | path->name = dest->kcontrol_news[i].name; |
318 | dapm_set_path_status(dest, path, i); | 320 | dapm_set_path_status(dest, path, i); |
319 | return 0; | 321 | return 0; |
320 | } | 322 | } |
@@ -322,6 +324,28 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | |||
322 | return -ENODEV; | 324 | return -ENODEV; |
323 | } | 325 | } |
324 | 326 | ||
327 | static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, | ||
328 | const struct snd_kcontrol_new *kcontrol_new, | ||
329 | struct snd_kcontrol **kcontrol) | ||
330 | { | ||
331 | struct snd_soc_dapm_widget *w; | ||
332 | int i; | ||
333 | |||
334 | *kcontrol = NULL; | ||
335 | |||
336 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
337 | for (i = 0; i < w->num_kcontrols; i++) { | ||
338 | if (&w->kcontrol_news[i] == kcontrol_new) { | ||
339 | if (w->kcontrols) | ||
340 | *kcontrol = w->kcontrols[i]; | ||
341 | return 1; | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
325 | /* create new dapm mixer control */ | 349 | /* create new dapm mixer control */ |
326 | static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | 350 | static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, |
327 | struct snd_soc_dapm_widget *w) | 351 | struct snd_soc_dapm_widget *w) |
@@ -331,6 +355,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
331 | struct snd_soc_dapm_path *path; | 355 | struct snd_soc_dapm_path *path; |
332 | struct snd_card *card = dapm->card->snd_card; | 356 | struct snd_card *card = dapm->card->snd_card; |
333 | const char *prefix; | 357 | const char *prefix; |
358 | struct snd_soc_dapm_widget_list *wlist; | ||
359 | size_t wlistsize; | ||
334 | 360 | ||
335 | if (dapm->codec) | 361 | if (dapm->codec) |
336 | prefix = dapm->codec->name_prefix; | 362 | prefix = dapm->codec->name_prefix; |
@@ -349,23 +375,37 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
349 | list_for_each_entry(path, &w->sources, list_sink) { | 375 | list_for_each_entry(path, &w->sources, list_sink) { |
350 | 376 | ||
351 | /* mixer/mux paths name must match control name */ | 377 | /* mixer/mux paths name must match control name */ |
352 | if (path->name != (char*)w->kcontrols[i].name) | 378 | if (path->name != (char *)w->kcontrol_news[i].name) |
353 | continue; | 379 | continue; |
354 | 380 | ||
381 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
382 | sizeof(struct snd_soc_dapm_widget *), | ||
383 | wlist = kzalloc(wlistsize, GFP_KERNEL); | ||
384 | if (wlist == NULL) { | ||
385 | dev_err(dapm->dev, | ||
386 | "asoc: can't allocate widget list for %s\n", | ||
387 | w->name); | ||
388 | return -ENOMEM; | ||
389 | } | ||
390 | wlist->num_widgets = 1; | ||
391 | wlist->widgets[0] = w; | ||
392 | |||
355 | /* add dapm control with long name. | 393 | /* add dapm control with long name. |
356 | * for dapm_mixer this is the concatenation of the | 394 | * for dapm_mixer this is the concatenation of the |
357 | * mixer and kcontrol name. | 395 | * mixer and kcontrol name. |
358 | * for dapm_mixer_named_ctl this is simply the | 396 | * for dapm_mixer_named_ctl this is simply the |
359 | * kcontrol name. | 397 | * kcontrol name. |
360 | */ | 398 | */ |
361 | name_len = strlen(w->kcontrols[i].name) + 1; | 399 | name_len = strlen(w->kcontrol_news[i].name) + 1; |
362 | if (w->id != snd_soc_dapm_mixer_named_ctl) | 400 | if (w->id != snd_soc_dapm_mixer_named_ctl) |
363 | name_len += 1 + strlen(w->name); | 401 | name_len += 1 + strlen(w->name); |
364 | 402 | ||
365 | path->long_name = kmalloc(name_len, GFP_KERNEL); | 403 | path->long_name = kmalloc(name_len, GFP_KERNEL); |
366 | 404 | ||
367 | if (path->long_name == NULL) | 405 | if (path->long_name == NULL) { |
406 | kfree(wlist); | ||
368 | return -ENOMEM; | 407 | return -ENOMEM; |
408 | } | ||
369 | 409 | ||
370 | switch (w->id) { | 410 | switch (w->id) { |
371 | default: | 411 | default: |
@@ -377,27 +417,30 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
377 | */ | 417 | */ |
378 | snprintf(path->long_name, name_len, "%s %s", | 418 | snprintf(path->long_name, name_len, "%s %s", |
379 | w->name + prefix_len, | 419 | w->name + prefix_len, |
380 | w->kcontrols[i].name); | 420 | w->kcontrol_news[i].name); |
381 | break; | 421 | break; |
382 | case snd_soc_dapm_mixer_named_ctl: | 422 | case snd_soc_dapm_mixer_named_ctl: |
383 | snprintf(path->long_name, name_len, "%s", | 423 | snprintf(path->long_name, name_len, "%s", |
384 | w->kcontrols[i].name); | 424 | w->kcontrol_news[i].name); |
385 | break; | 425 | break; |
386 | } | 426 | } |
387 | 427 | ||
388 | path->long_name[name_len - 1] = '\0'; | 428 | path->long_name[name_len - 1] = '\0'; |
389 | 429 | ||
390 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 430 | path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], |
391 | path->long_name, prefix); | 431 | wlist, path->long_name, |
432 | prefix); | ||
392 | ret = snd_ctl_add(card, path->kcontrol); | 433 | ret = snd_ctl_add(card, path->kcontrol); |
393 | if (ret < 0) { | 434 | if (ret < 0) { |
394 | dev_err(dapm->dev, | 435 | dev_err(dapm->dev, |
395 | "asoc: failed to add dapm kcontrol %s: %d\n", | 436 | "asoc: failed to add dapm kcontrol %s: %d\n", |
396 | path->long_name, ret); | 437 | path->long_name, ret); |
438 | kfree(wlist); | ||
397 | kfree(path->long_name); | 439 | kfree(path->long_name); |
398 | path->long_name = NULL; | 440 | path->long_name = NULL; |
399 | return ret; | 441 | return ret; |
400 | } | 442 | } |
443 | w->kcontrols[i] = path->kcontrol; | ||
401 | } | 444 | } |
402 | } | 445 | } |
403 | return ret; | 446 | return ret; |
@@ -412,42 +455,80 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, | |||
412 | struct snd_card *card = dapm->card->snd_card; | 455 | struct snd_card *card = dapm->card->snd_card; |
413 | const char *prefix; | 456 | const char *prefix; |
414 | size_t prefix_len; | 457 | size_t prefix_len; |
415 | int ret = 0; | 458 | int ret; |
416 | 459 | struct snd_soc_dapm_widget_list *wlist; | |
417 | if (!w->num_kcontrols) { | 460 | int shared, wlistentries; |
418 | dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name); | 461 | size_t wlistsize; |
462 | char *name; | ||
463 | |||
464 | if (w->num_kcontrols != 1) { | ||
465 | dev_err(dapm->dev, | ||
466 | "asoc: mux %s has incorrect number of controls\n", | ||
467 | w->name); | ||
419 | return -EINVAL; | 468 | return -EINVAL; |
420 | } | 469 | } |
421 | 470 | ||
422 | if (dapm->codec) | 471 | shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0], |
423 | prefix = dapm->codec->name_prefix; | 472 | &kcontrol); |
424 | else | 473 | if (kcontrol) { |
425 | prefix = NULL; | 474 | wlist = kcontrol->private_data; |
475 | wlistentries = wlist->num_widgets + 1; | ||
476 | } else { | ||
477 | wlist = NULL; | ||
478 | wlistentries = 1; | ||
479 | } | ||
480 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
481 | wlistentries * sizeof(struct snd_soc_dapm_widget *), | ||
482 | wlist = krealloc(wlist, wlistsize, GFP_KERNEL); | ||
483 | if (wlist == NULL) { | ||
484 | dev_err(dapm->dev, | ||
485 | "asoc: can't allocate widget list for %s\n", w->name); | ||
486 | return -ENOMEM; | ||
487 | } | ||
488 | wlist->num_widgets = wlistentries; | ||
489 | wlist->widgets[wlistentries - 1] = w; | ||
426 | 490 | ||
427 | if (prefix) | 491 | if (!kcontrol) { |
428 | prefix_len = strlen(prefix) + 1; | 492 | if (dapm->codec) |
429 | else | 493 | prefix = dapm->codec->name_prefix; |
430 | prefix_len = 0; | 494 | else |
495 | prefix = NULL; | ||
496 | |||
497 | if (shared) { | ||
498 | name = w->kcontrol_news[0].name; | ||
499 | prefix_len = 0; | ||
500 | } else { | ||
501 | name = w->name; | ||
502 | if (prefix) | ||
503 | prefix_len = strlen(prefix) + 1; | ||
504 | else | ||
505 | prefix_len = 0; | ||
506 | } | ||
431 | 507 | ||
432 | /* The control will get a prefix from the control creation | 508 | /* |
433 | * process but we're also using the same prefix for widgets so | 509 | * The control will get a prefix from the control creation |
434 | * cut the prefix off the front of the widget name. | 510 | * process but we're also using the same prefix for widgets so |
435 | */ | 511 | * cut the prefix off the front of the widget name. |
436 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len, | 512 | */ |
437 | prefix); | 513 | kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, |
438 | ret = snd_ctl_add(card, kcontrol); | 514 | name + prefix_len, prefix); |
515 | ret = snd_ctl_add(card, kcontrol); | ||
516 | if (ret < 0) { | ||
517 | dev_err(dapm->dev, | ||
518 | "asoc: failed to add kcontrol %s\n", w->name); | ||
519 | kfree(wlist); | ||
520 | return ret; | ||
521 | } | ||
522 | } | ||
439 | 523 | ||
440 | if (ret < 0) | 524 | kcontrol->private_data = wlist; |
441 | goto err; | 525 | |
526 | w->kcontrols[0] = kcontrol; | ||
442 | 527 | ||
443 | list_for_each_entry(path, &w->sources, list_sink) | 528 | list_for_each_entry(path, &w->sources, list_sink) |
444 | path->kcontrol = kcontrol; | 529 | path->kcontrol = kcontrol; |
445 | 530 | ||
446 | return ret; | 531 | return 0; |
447 | |||
448 | err: | ||
449 | dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name); | ||
450 | return ret; | ||
451 | } | 532 | } |
452 | 533 | ||
453 | /* create new dapm volume control */ | 534 | /* create new dapm volume control */ |
@@ -1254,13 +1335,18 @@ static const struct file_operations dapm_bias_fops = { | |||
1254 | .llseek = default_llseek, | 1335 | .llseek = default_llseek, |
1255 | }; | 1336 | }; |
1256 | 1337 | ||
1257 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) | 1338 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, |
1339 | struct dentry *parent) | ||
1258 | { | 1340 | { |
1259 | struct snd_soc_dapm_widget *w; | ||
1260 | struct dentry *d; | 1341 | struct dentry *d; |
1261 | 1342 | ||
1262 | if (!dapm->debugfs_dapm) | 1343 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); |
1344 | |||
1345 | if (!dapm->debugfs_dapm) { | ||
1346 | printk(KERN_WARNING | ||
1347 | "Failed to create DAPM debugfs directory\n"); | ||
1263 | return; | 1348 | return; |
1349 | } | ||
1264 | 1350 | ||
1265 | d = debugfs_create_file("bias_level", 0444, | 1351 | d = debugfs_create_file("bias_level", 0444, |
1266 | dapm->debugfs_dapm, dapm, | 1352 | dapm->debugfs_dapm, dapm, |
@@ -1268,24 +1354,44 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) | |||
1268 | if (!d) | 1354 | if (!d) |
1269 | dev_warn(dapm->dev, | 1355 | dev_warn(dapm->dev, |
1270 | "ASoC: Failed to create bias level debugfs file\n"); | 1356 | "ASoC: Failed to create bias level debugfs file\n"); |
1357 | } | ||
1271 | 1358 | ||
1272 | list_for_each_entry(w, &dapm->card->widgets, list) { | 1359 | static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) |
1273 | if (!w->name || w->dapm != dapm) | 1360 | { |
1274 | continue; | 1361 | struct snd_soc_dapm_context *dapm = w->dapm; |
1362 | struct dentry *d; | ||
1275 | 1363 | ||
1276 | d = debugfs_create_file(w->name, 0444, | 1364 | if (!dapm->debugfs_dapm || !w->name) |
1277 | dapm->debugfs_dapm, w, | 1365 | return; |
1278 | &dapm_widget_power_fops); | 1366 | |
1279 | if (!d) | 1367 | d = debugfs_create_file(w->name, 0444, |
1280 | dev_warn(w->dapm->dev, | 1368 | dapm->debugfs_dapm, w, |
1281 | "ASoC: Failed to create %s debugfs file\n", | 1369 | &dapm_widget_power_fops); |
1282 | w->name); | 1370 | if (!d) |
1283 | } | 1371 | dev_warn(w->dapm->dev, |
1372 | "ASoC: Failed to create %s debugfs file\n", | ||
1373 | w->name); | ||
1284 | } | 1374 | } |
1375 | |||
1376 | static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | ||
1377 | { | ||
1378 | debugfs_remove_recursive(dapm->debugfs_dapm); | ||
1379 | } | ||
1380 | |||
1285 | #else | 1381 | #else |
1286 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) | 1382 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, |
1383 | struct dentry *parent) | ||
1287 | { | 1384 | { |
1288 | } | 1385 | } |
1386 | |||
1387 | static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) | ||
1388 | { | ||
1389 | } | ||
1390 | |||
1391 | static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | ||
1392 | { | ||
1393 | } | ||
1394 | |||
1289 | #endif | 1395 | #endif |
1290 | 1396 | ||
1291 | /* test and update the power status of a mux widget */ | 1397 | /* test and update the power status of a mux widget */ |
@@ -1453,6 +1559,7 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) | |||
1453 | kfree(p->long_name); | 1559 | kfree(p->long_name); |
1454 | kfree(p); | 1560 | kfree(p); |
1455 | } | 1561 | } |
1562 | kfree(w->kcontrols); | ||
1456 | kfree(w->name); | 1563 | kfree(w->name); |
1457 | kfree(w); | 1564 | kfree(w); |
1458 | } | 1565 | } |
@@ -1623,7 +1730,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
1623 | case snd_soc_dapm_virt_mux: | 1730 | case snd_soc_dapm_virt_mux: |
1624 | case snd_soc_dapm_value_mux: | 1731 | case snd_soc_dapm_value_mux: |
1625 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | 1732 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, |
1626 | &wsink->kcontrols[0]); | 1733 | &wsink->kcontrol_news[0]); |
1627 | if (ret != 0) | 1734 | if (ret != 0) |
1628 | goto err; | 1735 | goto err; |
1629 | break; | 1736 | break; |
@@ -1703,6 +1810,14 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
1703 | if (w->new) | 1810 | if (w->new) |
1704 | continue; | 1811 | continue; |
1705 | 1812 | ||
1813 | if (w->num_kcontrols) { | ||
1814 | w->kcontrols = kzalloc(w->num_kcontrols * | ||
1815 | sizeof(struct snd_kcontrol *), | ||
1816 | GFP_KERNEL); | ||
1817 | if (!w->kcontrols) | ||
1818 | return -ENOMEM; | ||
1819 | } | ||
1820 | |||
1706 | switch(w->id) { | 1821 | switch(w->id) { |
1707 | case snd_soc_dapm_switch: | 1822 | case snd_soc_dapm_switch: |
1708 | case snd_soc_dapm_mixer: | 1823 | case snd_soc_dapm_mixer: |
@@ -1758,6 +1873,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
1758 | } | 1873 | } |
1759 | 1874 | ||
1760 | w->new = 1; | 1875 | w->new = 1; |
1876 | |||
1877 | dapm_debugfs_add_widget(w); | ||
1761 | } | 1878 | } |
1762 | 1879 | ||
1763 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 1880 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); |
@@ -1777,7 +1894,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
1777 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 1894 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
1778 | struct snd_ctl_elem_value *ucontrol) | 1895 | struct snd_ctl_elem_value *ucontrol) |
1779 | { | 1896 | { |
1780 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1897 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
1898 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1781 | struct soc_mixer_control *mc = | 1899 | struct soc_mixer_control *mc = |
1782 | (struct soc_mixer_control *)kcontrol->private_value; | 1900 | (struct soc_mixer_control *)kcontrol->private_value; |
1783 | unsigned int reg = mc->reg; | 1901 | unsigned int reg = mc->reg; |
@@ -1816,7 +1934,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
1816 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 1934 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
1817 | struct snd_ctl_elem_value *ucontrol) | 1935 | struct snd_ctl_elem_value *ucontrol) |
1818 | { | 1936 | { |
1819 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1937 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
1938 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1939 | struct snd_soc_codec *codec = widget->codec; | ||
1820 | struct soc_mixer_control *mc = | 1940 | struct soc_mixer_control *mc = |
1821 | (struct soc_mixer_control *)kcontrol->private_value; | 1941 | (struct soc_mixer_control *)kcontrol->private_value; |
1822 | unsigned int reg = mc->reg; | 1942 | unsigned int reg = mc->reg; |
@@ -1827,6 +1947,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1827 | unsigned int val; | 1947 | unsigned int val; |
1828 | int connect, change; | 1948 | int connect, change; |
1829 | struct snd_soc_dapm_update update; | 1949 | struct snd_soc_dapm_update update; |
1950 | int wi; | ||
1830 | 1951 | ||
1831 | val = (ucontrol->value.integer.value[0] & mask); | 1952 | val = (ucontrol->value.integer.value[0] & mask); |
1832 | 1953 | ||
@@ -1835,31 +1956,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1835 | mask = mask << shift; | 1956 | mask = mask << shift; |
1836 | val = val << shift; | 1957 | val = val << shift; |
1837 | 1958 | ||
1838 | mutex_lock(&widget->codec->mutex); | 1959 | if (val) |
1839 | widget->value = val; | 1960 | /* new connection */ |
1961 | connect = invert ? 0 : 1; | ||
1962 | else | ||
1963 | /* old connection must be powered down */ | ||
1964 | connect = invert ? 1 : 0; | ||
1965 | |||
1966 | mutex_lock(&codec->mutex); | ||
1840 | 1967 | ||
1841 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 1968 | change = snd_soc_test_bits(widget->codec, reg, mask, val); |
1842 | if (change) { | 1969 | if (change) { |
1843 | if (val) | 1970 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1844 | /* new connection */ | 1971 | widget = wlist->widgets[wi]; |
1845 | connect = invert ? 0:1; | ||
1846 | else | ||
1847 | /* old connection must be powered down */ | ||
1848 | connect = invert ? 1:0; | ||
1849 | 1972 | ||
1850 | update.kcontrol = kcontrol; | 1973 | widget->value = val; |
1851 | update.widget = widget; | ||
1852 | update.reg = reg; | ||
1853 | update.mask = mask; | ||
1854 | update.val = val; | ||
1855 | widget->dapm->update = &update; | ||
1856 | 1974 | ||
1857 | dapm_mixer_update_power(widget, kcontrol, connect); | 1975 | update.kcontrol = kcontrol; |
1976 | update.widget = widget; | ||
1977 | update.reg = reg; | ||
1978 | update.mask = mask; | ||
1979 | update.val = val; | ||
1980 | widget->dapm->update = &update; | ||
1858 | 1981 | ||
1859 | widget->dapm->update = NULL; | 1982 | dapm_mixer_update_power(widget, kcontrol, connect); |
1983 | |||
1984 | widget->dapm->update = NULL; | ||
1985 | } | ||
1860 | } | 1986 | } |
1861 | 1987 | ||
1862 | mutex_unlock(&widget->codec->mutex); | 1988 | mutex_unlock(&codec->mutex); |
1863 | return 0; | 1989 | return 0; |
1864 | } | 1990 | } |
1865 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | 1991 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); |
@@ -1876,7 +2002,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
1876 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2002 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
1877 | struct snd_ctl_elem_value *ucontrol) | 2003 | struct snd_ctl_elem_value *ucontrol) |
1878 | { | 2004 | { |
1879 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2005 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2006 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1880 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2007 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1881 | unsigned int val, bitmask; | 2008 | unsigned int val, bitmask; |
1882 | 2009 | ||
@@ -1904,11 +2031,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
1904 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2031 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
1905 | struct snd_ctl_elem_value *ucontrol) | 2032 | struct snd_ctl_elem_value *ucontrol) |
1906 | { | 2033 | { |
1907 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2034 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2035 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2036 | struct snd_soc_codec *codec = widget->codec; | ||
1908 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2037 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1909 | unsigned int val, mux, change; | 2038 | unsigned int val, mux, change; |
1910 | unsigned int mask, bitmask; | 2039 | unsigned int mask, bitmask; |
1911 | struct snd_soc_dapm_update update; | 2040 | struct snd_soc_dapm_update update; |
2041 | int wi; | ||
1912 | 2042 | ||
1913 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 2043 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1914 | ; | 2044 | ; |
@@ -1924,22 +2054,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1924 | mask |= (bitmask - 1) << e->shift_r; | 2054 | mask |= (bitmask - 1) << e->shift_r; |
1925 | } | 2055 | } |
1926 | 2056 | ||
1927 | mutex_lock(&widget->codec->mutex); | 2057 | mutex_lock(&codec->mutex); |
1928 | widget->value = val; | 2058 | |
1929 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2059 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
2060 | if (change) { | ||
2061 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2062 | widget = wlist->widgets[wi]; | ||
2063 | |||
2064 | widget->value = val; | ||
1930 | 2065 | ||
1931 | update.kcontrol = kcontrol; | 2066 | update.kcontrol = kcontrol; |
1932 | update.widget = widget; | 2067 | update.widget = widget; |
1933 | update.reg = e->reg; | 2068 | update.reg = e->reg; |
1934 | update.mask = mask; | 2069 | update.mask = mask; |
1935 | update.val = val; | 2070 | update.val = val; |
1936 | widget->dapm->update = &update; | 2071 | widget->dapm->update = &update; |
1937 | 2072 | ||
1938 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2073 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1939 | 2074 | ||
1940 | widget->dapm->update = NULL; | 2075 | widget->dapm->update = NULL; |
2076 | } | ||
2077 | } | ||
1941 | 2078 | ||
1942 | mutex_unlock(&widget->codec->mutex); | 2079 | mutex_unlock(&codec->mutex); |
1943 | return change; | 2080 | return change; |
1944 | } | 2081 | } |
1945 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 2082 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
@@ -1954,7 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | |||
1954 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | 2091 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, |
1955 | struct snd_ctl_elem_value *ucontrol) | 2092 | struct snd_ctl_elem_value *ucontrol) |
1956 | { | 2093 | { |
1957 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2094 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2095 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1958 | 2096 | ||
1959 | ucontrol->value.enumerated.item[0] = widget->value; | 2097 | ucontrol->value.enumerated.item[0] = widget->value; |
1960 | 2098 | ||
@@ -1972,22 +2110,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | |||
1972 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | 2110 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, |
1973 | struct snd_ctl_elem_value *ucontrol) | 2111 | struct snd_ctl_elem_value *ucontrol) |
1974 | { | 2112 | { |
1975 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2113 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2114 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2115 | struct snd_soc_codec *codec = widget->codec; | ||
1976 | struct soc_enum *e = | 2116 | struct soc_enum *e = |
1977 | (struct soc_enum *)kcontrol->private_value; | 2117 | (struct soc_enum *)kcontrol->private_value; |
1978 | int change; | 2118 | int change; |
1979 | int ret = 0; | 2119 | int ret = 0; |
2120 | int wi; | ||
1980 | 2121 | ||
1981 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2122 | if (ucontrol->value.enumerated.item[0] >= e->max) |
1982 | return -EINVAL; | 2123 | return -EINVAL; |
1983 | 2124 | ||
1984 | mutex_lock(&widget->codec->mutex); | 2125 | mutex_lock(&codec->mutex); |
1985 | 2126 | ||
1986 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2127 | change = widget->value != ucontrol->value.enumerated.item[0]; |
1987 | widget->value = ucontrol->value.enumerated.item[0]; | 2128 | if (change) { |
1988 | dapm_mux_update_power(widget, kcontrol, change, widget->value, e); | 2129 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
2130 | widget = wlist->widgets[wi]; | ||
2131 | |||
2132 | widget->value = ucontrol->value.enumerated.item[0]; | ||
1989 | 2133 | ||
1990 | mutex_unlock(&widget->codec->mutex); | 2134 | dapm_mux_update_power(widget, kcontrol, change, |
2135 | widget->value, e); | ||
2136 | } | ||
2137 | } | ||
2138 | |||
2139 | mutex_unlock(&codec->mutex); | ||
1991 | return ret; | 2140 | return ret; |
1992 | } | 2141 | } |
1993 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | 2142 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); |
@@ -2008,7 +2157,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | |||
2008 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | 2157 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, |
2009 | struct snd_ctl_elem_value *ucontrol) | 2158 | struct snd_ctl_elem_value *ucontrol) |
2010 | { | 2159 | { |
2011 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2160 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2161 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2012 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2162 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2013 | unsigned int reg_val, val, mux; | 2163 | unsigned int reg_val, val, mux; |
2014 | 2164 | ||
@@ -2048,11 +2198,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | |||
2048 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2198 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, |
2049 | struct snd_ctl_elem_value *ucontrol) | 2199 | struct snd_ctl_elem_value *ucontrol) |
2050 | { | 2200 | { |
2051 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2201 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2202 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2203 | struct snd_soc_codec *codec = widget->codec; | ||
2052 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2204 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2053 | unsigned int val, mux, change; | 2205 | unsigned int val, mux, change; |
2054 | unsigned int mask; | 2206 | unsigned int mask; |
2055 | struct snd_soc_dapm_update update; | 2207 | struct snd_soc_dapm_update update; |
2208 | int wi; | ||
2056 | 2209 | ||
2057 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2210 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2058 | return -EINVAL; | 2211 | return -EINVAL; |
@@ -2066,22 +2219,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2066 | mask |= e->mask << e->shift_r; | 2219 | mask |= e->mask << e->shift_r; |
2067 | } | 2220 | } |
2068 | 2221 | ||
2069 | mutex_lock(&widget->codec->mutex); | 2222 | mutex_lock(&codec->mutex); |
2070 | widget->value = val; | 2223 | |
2071 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2224 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
2225 | if (change) { | ||
2226 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2227 | widget = wlist->widgets[wi]; | ||
2228 | |||
2229 | widget->value = val; | ||
2072 | 2230 | ||
2073 | update.kcontrol = kcontrol; | 2231 | update.kcontrol = kcontrol; |
2074 | update.widget = widget; | 2232 | update.widget = widget; |
2075 | update.reg = e->reg; | 2233 | update.reg = e->reg; |
2076 | update.mask = mask; | 2234 | update.mask = mask; |
2077 | update.val = val; | 2235 | update.val = val; |
2078 | widget->dapm->update = &update; | 2236 | widget->dapm->update = &update; |
2079 | 2237 | ||
2080 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2238 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
2081 | 2239 | ||
2082 | widget->dapm->update = NULL; | 2240 | widget->dapm->update = NULL; |
2241 | } | ||
2242 | } | ||
2083 | 2243 | ||
2084 | mutex_unlock(&widget->codec->mutex); | 2244 | mutex_unlock(&codec->mutex); |
2085 | return change; | 2245 | return change; |
2086 | } | 2246 | } |
2087 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2247 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); |
@@ -2427,6 +2587,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); | |||
2427 | void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) | 2587 | void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) |
2428 | { | 2588 | { |
2429 | snd_soc_dapm_sys_remove(dapm->dev); | 2589 | snd_soc_dapm_sys_remove(dapm->dev); |
2590 | dapm_debugfs_cleanup(dapm); | ||
2430 | dapm_free_widgets(dapm); | 2591 | dapm_free_widgets(dapm); |
2431 | list_del(&dapm->list); | 2592 | list_del(&dapm->list); |
2432 | } | 2593 | } |
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 0f5bd8298a0a..035d39a4beb4 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -30,3 +30,11 @@ config SND_SOC_TEGRA_WM8903 | |||
30 | boards using the WM8093 codec. Currently, the supported boards are | 30 | boards using the WM8093 codec. Currently, the supported boards are |
31 | Harmony, Ventana, Seaboard, Kaen, and Aebl. | 31 | Harmony, Ventana, Seaboard, Kaen, and Aebl. |
32 | 32 | ||
33 | config SND_SOC_TEGRA_TRIMSLICE | ||
34 | tristate "SoC Audio support for TrimSlice board" | ||
35 | depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C | ||
36 | select SND_SOC_TEGRA_I2S | ||
37 | select SND_SOC_TLV320AIC23 | ||
38 | help | ||
39 | Say Y or M here if you want to add support for SoC audio on the | ||
40 | TrimSlice platform. | ||
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 13bef8d572c9..fa6574d92a31 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile | |||
@@ -11,5 +11,7 @@ obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o | |||
11 | 11 | ||
12 | # Tegra machine Support | 12 | # Tegra machine Support |
13 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o | 13 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o |
14 | snd-soc-tegra-trimslice-objs := trimslice.o | ||
14 | 15 | ||
15 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o | 16 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o |
17 | obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o | ||
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c new file mode 100644 index 000000000000..8fc07e9adf2e --- /dev/null +++ b/sound/soc/tegra/trimslice.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * trimslice.c - TrimSlice machine ASoC driver | ||
3 | * | ||
4 | * Copyright (C) 2011 - CompuLab, Ltd. | ||
5 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * Author: Stephen Warren <swarren@nvidia.com> | ||
9 | * Copyright (C) 2010-2011 - NVIDIA, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
23 | * 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #include <sound/core.h> | ||
34 | #include <sound/jack.h> | ||
35 | #include <sound/pcm.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #include <sound/soc.h> | ||
38 | |||
39 | #include "../codecs/tlv320aic23.h" | ||
40 | |||
41 | #include "tegra_das.h" | ||
42 | #include "tegra_i2s.h" | ||
43 | #include "tegra_pcm.h" | ||
44 | #include "tegra_asoc_utils.h" | ||
45 | |||
46 | #define DRV_NAME "tegra-snd-trimslice" | ||
47 | |||
48 | struct tegra_trimslice { | ||
49 | struct tegra_asoc_utils_data util_data; | ||
50 | }; | ||
51 | |||
52 | static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, | ||
53 | struct snd_pcm_hw_params *params) | ||
54 | { | ||
55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
56 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
57 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
58 | struct snd_soc_codec *codec = rtd->codec; | ||
59 | struct snd_soc_card *card = codec->card; | ||
60 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | ||
61 | int srate, mclk; | ||
62 | int err; | ||
63 | |||
64 | srate = params_rate(params); | ||
65 | mclk = 128 * srate; | ||
66 | |||
67 | err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); | ||
68 | if (err < 0) { | ||
69 | dev_err(card->dev, "Can't configure clocks\n"); | ||
70 | return err; | ||
71 | } | ||
72 | |||
73 | err = snd_soc_dai_set_fmt(codec_dai, | ||
74 | SND_SOC_DAIFMT_I2S | | ||
75 | SND_SOC_DAIFMT_NB_NF | | ||
76 | SND_SOC_DAIFMT_CBS_CFS); | ||
77 | if (err < 0) { | ||
78 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
79 | return err; | ||
80 | } | ||
81 | |||
82 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
83 | SND_SOC_DAIFMT_I2S | | ||
84 | SND_SOC_DAIFMT_NB_NF | | ||
85 | SND_SOC_DAIFMT_CBS_CFS); | ||
86 | if (err < 0) { | ||
87 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
88 | return err; | ||
89 | } | ||
90 | |||
91 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
92 | SND_SOC_CLOCK_IN); | ||
93 | if (err < 0) { | ||
94 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
95 | return err; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static struct snd_soc_ops trimslice_asoc_ops = { | ||
102 | .hw_params = trimslice_asoc_hw_params, | ||
103 | }; | ||
104 | |||
105 | static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { | ||
106 | SND_SOC_DAPM_HP("Line Out", NULL), | ||
107 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
108 | }; | ||
109 | |||
110 | static const struct snd_soc_dapm_route trimslice_audio_map[] = { | ||
111 | {"Line Out", NULL, "LOUT"}, | ||
112 | {"Line Out", NULL, "ROUT"}, | ||
113 | |||
114 | {"LLINEIN", NULL, "Line In"}, | ||
115 | {"RLINEIN", NULL, "Line In"}, | ||
116 | }; | ||
117 | |||
118 | static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) | ||
119 | { | ||
120 | struct snd_soc_codec *codec = rtd->codec; | ||
121 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
122 | |||
123 | snd_soc_dapm_nc_pin(dapm, "LHPOUT"); | ||
124 | snd_soc_dapm_nc_pin(dapm, "RHPOUT"); | ||
125 | snd_soc_dapm_nc_pin(dapm, "MICIN"); | ||
126 | |||
127 | snd_soc_dapm_sync(dapm); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { | ||
133 | .name = "TLV320AIC23", | ||
134 | .stream_name = "AIC23", | ||
135 | .codec_name = "tlv320aic23-codec.2-001a", | ||
136 | .platform_name = "tegra-pcm-audio", | ||
137 | .cpu_dai_name = "tegra-i2s.0", | ||
138 | .codec_dai_name = "tlv320aic23-hifi", | ||
139 | .init = trimslice_asoc_init, | ||
140 | .ops = &trimslice_asoc_ops, | ||
141 | }; | ||
142 | |||
143 | static struct snd_soc_card snd_soc_trimslice = { | ||
144 | .name = "tegra-trimslice", | ||
145 | .dai_link = &trimslice_tlv320aic23_dai, | ||
146 | .num_links = 1, | ||
147 | |||
148 | .dapm_widgets = trimslice_dapm_widgets, | ||
149 | .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), | ||
150 | .dapm_routes = trimslice_audio_map, | ||
151 | .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), | ||
152 | }; | ||
153 | |||
154 | static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) | ||
155 | { | ||
156 | struct snd_soc_card *card = &snd_soc_trimslice; | ||
157 | struct tegra_trimslice *trimslice; | ||
158 | int ret; | ||
159 | |||
160 | trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL); | ||
161 | if (!trimslice) { | ||
162 | dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | |||
166 | ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); | ||
167 | if (ret) | ||
168 | goto err_free_trimslice; | ||
169 | |||
170 | card->dev = &pdev->dev; | ||
171 | platform_set_drvdata(pdev, card); | ||
172 | snd_soc_card_set_drvdata(card, trimslice); | ||
173 | |||
174 | ret = snd_soc_register_card(card); | ||
175 | if (ret) { | ||
176 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
177 | ret); | ||
178 | goto err_fini_utils; | ||
179 | } | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | err_fini_utils: | ||
184 | tegra_asoc_utils_fini(&trimslice->util_data); | ||
185 | err_free_trimslice: | ||
186 | kfree(trimslice); | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) | ||
191 | { | ||
192 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
193 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | ||
194 | |||
195 | snd_soc_unregister_card(card); | ||
196 | |||
197 | tegra_asoc_utils_fini(&trimslice->util_data); | ||
198 | |||
199 | kfree(trimslice); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static struct platform_driver tegra_snd_trimslice_driver = { | ||
205 | .driver = { | ||
206 | .name = DRV_NAME, | ||
207 | .owner = THIS_MODULE, | ||
208 | }, | ||
209 | .probe = tegra_snd_trimslice_probe, | ||
210 | .remove = __devexit_p(tegra_snd_trimslice_remove), | ||
211 | }; | ||
212 | |||
213 | static int __init snd_tegra_trimslice_init(void) | ||
214 | { | ||
215 | return platform_driver_register(&tegra_snd_trimslice_driver); | ||
216 | } | ||
217 | module_init(snd_tegra_trimslice_init); | ||
218 | |||
219 | static void __exit snd_tegra_trimslice_exit(void) | ||
220 | { | ||
221 | platform_driver_unregister(&tegra_snd_trimslice_driver); | ||
222 | } | ||
223 | module_exit(snd_tegra_trimslice_exit); | ||
224 | |||
225 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | ||
226 | MODULE_DESCRIPTION("Trimslice machine ASoC driver"); | ||
227 | MODULE_LICENSE("GPL"); | ||
228 | MODULE_ALIAS("platform:" DRV_NAME); | ||