aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-10 03:24:50 -0400
committerTakashi Iwai <tiwai@suse.de>2011-05-10 03:24:50 -0400
commit1209842af4db98ffd7364ec9cf7d1a59293aa74c (patch)
tree33202a5468dc66456b67764eb6a272bd7e8c5af5
parentf0a2b0cb71e652ae9f0feeea91e5320e4faf25dc (diff)
parentf3eee00da39cba3c8a4db7048458969c620ac6d8 (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.h78
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/ssm2602.c302
-rw-r--r--sound/soc/codecs/ssm2602.h6
-rw-r--r--sound/soc/codecs/uda134x.c2
-rw-r--r--sound/soc/codecs/wm8915.c46
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c2
-rw-r--r--sound/soc/mid-x86/sst_platform.c6
-rw-r--r--sound/soc/soc-cache.c11
-rw-r--r--sound/soc/soc-core.c38
-rw-r--r--sound/soc/soc-dapm.c373
-rw-r--r--sound/soc/tegra/Kconfig8
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/trimslice.c228
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 */
358int snd_soc_dapm_sys_add(struct device *dev); 358int snd_soc_dapm_sys_add(struct device *dev);
359void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm); 359void 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 */
362int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, 363int 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 */
522struct 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
49enum ssm2602_type {
50 SSM2602,
51 SSM2604,
52};
53
48/* codec private data */ 54/* codec private data */
49struct ssm2602_priv { 55struct 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 */
62static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { 70static 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
83static const struct snd_kcontrol_new ssm2602_snd_controls[] = { 91static 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
85SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, 97static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
86 0, 127, 0), 98static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
87SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
88 7, 1, 0),
89 99
90SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), 100static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
101SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
102 ssm260x_inpga_tlv),
91SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), 103SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
92 104
93SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
94SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
95SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
96
97SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
98
99SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), 105SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
100SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), 106SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
101 107
102SOC_ENUM("Capture Source", ssm2602_enum[0]),
103
104SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), 108SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
105}; 109};
106 110
111static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
112SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
113 0, 127, 0, ssm260x_outmix_tlv),
114SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
115 7, 1, 0),
116SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
117 ssm260x_sidetone_tlv),
118
119SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
120SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
121SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
122};
123
107/* Output Mixer */ 124/* Output Mixer */
108static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { 125static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
109SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), 126SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
110SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
111SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), 127SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
128SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
112}; 129};
113 130
114/* Input mux */ 131/* Input mux */
115static const struct snd_kcontrol_new ssm2602_input_mux_controls = 132static const struct snd_kcontrol_new ssm2602_input_mux_controls =
116SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); 133SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
117 134
118static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { 135static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
119SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
120 &ssm2602_output_mixer_controls[0],
121 ARRAY_SIZE(ssm2602_output_mixer_controls)),
122SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), 136SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
137SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
138SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
139
140SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, 0, 0),
141
123SND_SOC_DAPM_OUTPUT("LOUT"), 142SND_SOC_DAPM_OUTPUT("LOUT"),
124SND_SOC_DAPM_OUTPUT("LHPOUT"),
125SND_SOC_DAPM_OUTPUT("ROUT"), 143SND_SOC_DAPM_OUTPUT("ROUT"),
126SND_SOC_DAPM_OUTPUT("RHPOUT"), 144SND_SOC_DAPM_INPUT("RLINEIN"),
127SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), 145SND_SOC_DAPM_INPUT("LLINEIN"),
146};
147
148static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
149SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
150 ssm260x_output_mixer_controls,
151 ARRAY_SIZE(ssm260x_output_mixer_controls)),
152
128SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), 153SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
129SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
130SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), 154SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
155
156SND_SOC_DAPM_OUTPUT("LHPOUT"),
157SND_SOC_DAPM_OUTPUT("RHPOUT"),
131SND_SOC_DAPM_INPUT("MICIN"), 158SND_SOC_DAPM_INPUT("MICIN"),
132SND_SOC_DAPM_INPUT("RLINEIN"),
133SND_SOC_DAPM_INPUT("LLINEIN"),
134}; 159};
135 160
136static const struct snd_soc_dapm_route audio_conn[] = { 161static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
137 /* output mixer */ 162SND_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
167static 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
181static 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
159static int ssm2602_add_widgets(struct snd_soc_codec *codec) 194static 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
170struct _coeff_div { 198struct 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))
180static const struct _coeff_div coeff_div[] = { 205
206/* codec mclk clock coefficients */
207static 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
214static inline int get_coeff(int mclk, int rate) 241static 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
225static int ssm2602_hw_params(struct snd_pcm_substream *substream, 253static 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
308static 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
319static void ssm2602_shutdown(struct snd_pcm_substream *substream, 329static 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
336static int ssm2602_mute(struct snd_soc_dai *dai, int mute) 343static 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
458static struct snd_soc_dai_ops ssm2602_dai_ops = { 464static 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
500static int ssm2602_probe(struct snd_soc_codec *codec) 505static 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
529static 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
543static 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
549static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { 590static 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 */
604static int ssm2602_i2c_probe(struct i2c_client *i2c, 653static 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
624static int ssm2602_i2c_remove(struct i2c_client *client) 674static 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
631static const struct i2c_device_id ssm2602_i2c_id[] = { 681static const struct i2c_device_id ssm2602_i2c_id[] = {
632 { "ssm2602", 0 }, 682 { "ssm2602", SSM2602 },
683 { "ssm2603", SSM2602 },
684 { "ssm2604", SSM2604 },
633 { } 685 { }
634}; 686};
635MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); 687MODULE_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}
680module_exit(ssm2602_exit); 732module_exit(ssm2602_exit);
681 733
682MODULE_DESCRIPTION("ASoC ssm2602 driver"); 734MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
683MODULE_AUTHOR("Cliff Cai"); 735MODULE_AUTHOR("Cliff Cai");
684MODULE_LICENSE("GPL"); 736MODULE_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
122struct 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
609static int __devinit uda134x_codec_probe(struct platform_device *pdev) 607static 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),
991SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0), 991SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
992SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0), 992SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
993 993
994SND_SOC_DAPM_PGA("ADC", SND_SOC_NOPM, 0, 0, NULL, 0), 994SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
995 995SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
996SND_SOC_DAPM_MUX("IN1 Mux", SND_SOC_NOPM, 0, 0, &in1_mux), 996SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
997SND_SOC_DAPM_MUX("IN2 Mux", SND_SOC_NOPM, 0, 0, &in2_mux), 997SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
998 998
999SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0), 999SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
1000SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0), 1000SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
1001SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0), 1001SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
1002SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0), 1002SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
1003 1003
1004/* FIXME - these need to be concentrator widgets */
1005SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0), 1004SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
1006SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0), 1005SND_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
383static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
384{
385 return snd_pcm_lib_free_pages(substream);
386}
387
383static struct snd_pcm_ops sst_platform_ops = { 388static 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
393static void sst_pcm_free(struct snd_pcm *pcm) 399static 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
314static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) 308static 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
1531err_probe: 1526err_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
327static 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 */
326static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, 350static 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
448err:
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
1257void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) 1338void 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) { 1359static 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
1376static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1377{
1378 debugfs_remove_recursive(dapm->debugfs_dapm);
1379}
1380
1285#else 1381#else
1286void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) 1382void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1383 struct dentry *parent)
1287{ 1384{
1288} 1385}
1386
1387static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1388{
1389}
1390
1391static 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);
1777int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, 1894int 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);
1816int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, 1934int 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}
1865EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); 1991EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -1876,7 +2002,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1876int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, 2002int 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);
1904int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, 2031int 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}
1945EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); 2082EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -1954,7 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1954int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, 2091int 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);
1972int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, 2110int 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}
1993EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); 2142EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2008,7 +2157,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
2008int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, 2157int 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);
2048int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, 2198int 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}
2087EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); 2247EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2427,6 +2587,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
2427void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) 2587void 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
33config 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
13snd-soc-tegra-wm8903-objs := tegra_wm8903.o 13snd-soc-tegra-wm8903-objs := tegra_wm8903.o
14snd-soc-tegra-trimslice-objs := trimslice.o
14 15
15obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o 16obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
17obj-$(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
48struct tegra_trimslice {
49 struct tegra_asoc_utils_data util_data;
50};
51
52static 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
101static struct snd_soc_ops trimslice_asoc_ops = {
102 .hw_params = trimslice_asoc_hw_params,
103};
104
105static 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
110static 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
118static 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
132static 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
143static 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
154static __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
183err_fini_utils:
184 tegra_asoc_utils_fini(&trimslice->util_data);
185err_free_trimslice:
186 kfree(trimslice);
187 return ret;
188}
189
190static 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
204static 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
213static int __init snd_tegra_trimslice_init(void)
214{
215 return platform_driver_register(&tegra_snd_trimslice_driver);
216}
217module_init(snd_tegra_trimslice_init);
218
219static void __exit snd_tegra_trimslice_exit(void)
220{
221 platform_driver_unregister(&tegra_snd_trimslice_driver);
222}
223module_exit(snd_tegra_trimslice_exit);
224
225MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
226MODULE_DESCRIPTION("Trimslice machine ASoC driver");
227MODULE_LICENSE("GPL");
228MODULE_ALIAS("platform:" DRV_NAME);