aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaud Pouliquen <arnaud.pouliquen@st.com>2017-01-03 10:52:52 -0500
committerMark Brown <broonie@kernel.org>2017-01-20 10:16:29 -0500
commitcd6111b26280a2f38a9fb8e6630c63a96477e4bf (patch)
tree9948312b6eba8f6be073e339148985e43dd1d5e4
parent25f7b701c20db3e9ae09e28dd652949bd977e5cd (diff)
ASoC: hdmi-codec: add channel mapping control
Add user interface to provide channel mapping. In a first step this control is read only. As TLV type, the control provides all configuration available for HDMI sink(ELD), and provides current channel mapping selected by codec based on ELD and number of channels specified by user on open. When control is called before the number of the channel is specified (i.e. hw_params is set), it returns all channels set to UNKNOWN. Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/hdmi-codec.c380
1 files changed, 379 insertions, 1 deletions
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 90b5948e0ff3..dc6715a804a1 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -18,6 +18,7 @@
18#include <sound/pcm.h> 18#include <sound/pcm.h>
19#include <sound/pcm_params.h> 19#include <sound/pcm_params.h>
20#include <sound/soc.h> 20#include <sound/soc.h>
21#include <sound/tlv.h>
21#include <sound/pcm_drm_eld.h> 22#include <sound/pcm_drm_eld.h>
22#include <sound/hdmi-codec.h> 23#include <sound/hdmi-codec.h>
23#include <sound/pcm_iec958.h> 24#include <sound/pcm_iec958.h>
@@ -33,6 +34,258 @@ struct hdmi_device {
33LIST_HEAD(hdmi_device_list); 34LIST_HEAD(hdmi_device_list);
34 35
35#define DAI_NAME_SIZE 16 36#define DAI_NAME_SIZE 16
37
38#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
39
40struct hdmi_codec_channel_map_table {
41 unsigned char map; /* ALSA API channel map position */
42 unsigned long spk_mask; /* speaker position bit mask */
43};
44
45/*
46 * CEA speaker placement for HDMI 1.4:
47 *
48 * FL FLC FC FRC FR FRW
49 *
50 * LFE
51 *
52 * RL RLC RC RRC RR
53 *
54 * Speaker placement has to be extended to support HDMI 2.0
55 */
56enum hdmi_codec_cea_spk_placement {
57 FL = BIT(0), /* Front Left */
58 FC = BIT(1), /* Front Center */
59 FR = BIT(2), /* Front Right */
60 FLC = BIT(3), /* Front Left Center */
61 FRC = BIT(4), /* Front Right Center */
62 RL = BIT(5), /* Rear Left */
63 RC = BIT(6), /* Rear Center */
64 RR = BIT(7), /* Rear Right */
65 RLC = BIT(8), /* Rear Left Center */
66 RRC = BIT(9), /* Rear Right Center */
67 LFE = BIT(10), /* Low Frequency Effect */
68};
69
70/*
71 * cea Speaker allocation structure
72 */
73struct hdmi_codec_cea_spk_alloc {
74 const int ca_id;
75 unsigned int n_ch;
76 unsigned long mask;
77};
78
79/* Channel maps stereo HDMI */
80const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
81 { .channels = 2,
82 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
83 { }
84};
85
86/* Channel maps for multi-channel playbacks, up to 8 n_ch */
87const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
88 { .channels = 2, /* CA_ID 0x00 */
89 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
90 { .channels = 4, /* CA_ID 0x01 */
91 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
92 SNDRV_CHMAP_NA } },
93 { .channels = 4, /* CA_ID 0x02 */
94 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
95 SNDRV_CHMAP_FC } },
96 { .channels = 4, /* CA_ID 0x03 */
97 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
98 SNDRV_CHMAP_FC } },
99 { .channels = 6, /* CA_ID 0x04 */
100 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
101 SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
102 { .channels = 6, /* CA_ID 0x05 */
103 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
104 SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
105 { .channels = 6, /* CA_ID 0x06 */
106 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
107 SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
108 { .channels = 6, /* CA_ID 0x07 */
109 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
110 SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
111 { .channels = 6, /* CA_ID 0x08 */
112 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
113 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
114 { .channels = 6, /* CA_ID 0x09 */
115 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
116 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
117 { .channels = 6, /* CA_ID 0x0A */
118 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
119 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
120 { .channels = 6, /* CA_ID 0x0B */
121 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
122 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
123 { .channels = 8, /* CA_ID 0x0C */
124 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
125 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
126 SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
127 { .channels = 8, /* CA_ID 0x0D */
128 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
129 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
130 SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
131 { .channels = 8, /* CA_ID 0x0E */
132 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
133 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
134 SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
135 { .channels = 8, /* CA_ID 0x0F */
136 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
137 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
138 SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
139 { .channels = 8, /* CA_ID 0x10 */
140 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
141 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
142 SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
143 { .channels = 8, /* CA_ID 0x11 */
144 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
145 SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
146 SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
147 { .channels = 8, /* CA_ID 0x12 */
148 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
149 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
150 SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
151 { .channels = 8, /* CA_ID 0x13 */
152 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
153 SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
154 SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
155 { .channels = 8, /* CA_ID 0x14 */
156 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
157 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
158 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
159 { .channels = 8, /* CA_ID 0x15 */
160 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
161 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
162 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
163 { .channels = 8, /* CA_ID 0x16 */
164 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
165 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
166 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
167 { .channels = 8, /* CA_ID 0x17 */
168 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
169 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
170 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
171 { .channels = 8, /* CA_ID 0x18 */
172 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
173 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
174 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
175 { .channels = 8, /* CA_ID 0x19 */
176 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
177 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
178 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
179 { .channels = 8, /* CA_ID 0x1A */
180 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
181 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
182 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
183 { .channels = 8, /* CA_ID 0x1B */
184 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
185 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
186 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
187 { .channels = 8, /* CA_ID 0x1C */
188 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
189 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
190 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
191 { .channels = 8, /* CA_ID 0x1D */
192 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
193 SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
194 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
195 { .channels = 8, /* CA_ID 0x1E */
196 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
197 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
198 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
199 { .channels = 8, /* CA_ID 0x1F */
200 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
201 SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
202 SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
203 { }
204};
205
206/*
207 * hdmi_codec_channel_alloc: speaker configuration available for CEA
208 *
209 * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
210 * The preceding ones have better chances to be selected by
211 * hdmi_codec_get_ch_alloc_table_idx().
212 */
213static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
214 { .ca_id = 0x00, .n_ch = 2,
215 .mask = FL | FR},
216 /* 2.1 */
217 { .ca_id = 0x01, .n_ch = 4,
218 .mask = FL | FR | LFE},
219 /* Dolby Surround */
220 { .ca_id = 0x02, .n_ch = 4,
221 .mask = FL | FR | FC },
222 /* surround51 */
223 { .ca_id = 0x0b, .n_ch = 6,
224 .mask = FL | FR | LFE | FC | RL | RR},
225 /* surround40 */
226 { .ca_id = 0x08, .n_ch = 6,
227 .mask = FL | FR | RL | RR },
228 /* surround41 */
229 { .ca_id = 0x09, .n_ch = 6,
230 .mask = FL | FR | LFE | RL | RR },
231 /* surround50 */
232 { .ca_id = 0x0a, .n_ch = 6,
233 .mask = FL | FR | FC | RL | RR },
234 /* 6.1 */
235 { .ca_id = 0x0f, .n_ch = 8,
236 .mask = FL | FR | LFE | FC | RL | RR | RC },
237 /* surround71 */
238 { .ca_id = 0x13, .n_ch = 8,
239 .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
240 /* others */
241 { .ca_id = 0x03, .n_ch = 8,
242 .mask = FL | FR | LFE | FC },
243 { .ca_id = 0x04, .n_ch = 8,
244 .mask = FL | FR | RC},
245 { .ca_id = 0x05, .n_ch = 8,
246 .mask = FL | FR | LFE | RC },
247 { .ca_id = 0x06, .n_ch = 8,
248 .mask = FL | FR | FC | RC },
249 { .ca_id = 0x07, .n_ch = 8,
250 .mask = FL | FR | LFE | FC | RC },
251 { .ca_id = 0x0c, .n_ch = 8,
252 .mask = FL | FR | RC | RL | RR },
253 { .ca_id = 0x0d, .n_ch = 8,
254 .mask = FL | FR | LFE | RL | RR | RC },
255 { .ca_id = 0x0e, .n_ch = 8,
256 .mask = FL | FR | FC | RL | RR | RC },
257 { .ca_id = 0x10, .n_ch = 8,
258 .mask = FL | FR | RL | RR | RLC | RRC },
259 { .ca_id = 0x11, .n_ch = 8,
260 .mask = FL | FR | LFE | RL | RR | RLC | RRC },
261 { .ca_id = 0x12, .n_ch = 8,
262 .mask = FL | FR | FC | RL | RR | RLC | RRC },
263 { .ca_id = 0x14, .n_ch = 8,
264 .mask = FL | FR | FLC | FRC },
265 { .ca_id = 0x15, .n_ch = 8,
266 .mask = FL | FR | LFE | FLC | FRC },
267 { .ca_id = 0x16, .n_ch = 8,
268 .mask = FL | FR | FC | FLC | FRC },
269 { .ca_id = 0x17, .n_ch = 8,
270 .mask = FL | FR | LFE | FC | FLC | FRC },
271 { .ca_id = 0x18, .n_ch = 8,
272 .mask = FL | FR | RC | FLC | FRC },
273 { .ca_id = 0x19, .n_ch = 8,
274 .mask = FL | FR | LFE | RC | FLC | FRC },
275 { .ca_id = 0x1a, .n_ch = 8,
276 .mask = FL | FR | RC | FC | FLC | FRC },
277 { .ca_id = 0x1b, .n_ch = 8,
278 .mask = FL | FR | LFE | RC | FC | FLC | FRC },
279 { .ca_id = 0x1c, .n_ch = 8,
280 .mask = FL | FR | RL | RR | FLC | FRC },
281 { .ca_id = 0x1d, .n_ch = 8,
282 .mask = FL | FR | LFE | RL | RR | FLC | FRC },
283 { .ca_id = 0x1e, .n_ch = 8,
284 .mask = FL | FR | FC | RL | RR | FLC | FRC },
285 { .ca_id = 0x1f, .n_ch = 8,
286 .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
287};
288
36struct hdmi_codec_priv { 289struct hdmi_codec_priv {
37 struct hdmi_codec_pdata hcd; 290 struct hdmi_codec_pdata hcd;
38 struct snd_soc_dai_driver *daidrv; 291 struct snd_soc_dai_driver *daidrv;
@@ -41,6 +294,8 @@ struct hdmi_codec_priv {
41 struct snd_pcm_substream *current_stream; 294 struct snd_pcm_substream *current_stream;
42 struct snd_pcm_hw_constraint_list ratec; 295 struct snd_pcm_hw_constraint_list ratec;
43 uint8_t eld[MAX_ELD_BYTES]; 296 uint8_t eld[MAX_ELD_BYTES];
297 struct snd_pcm_chmap *chmap_info;
298 unsigned int chmap_idx;
44}; 299};
45 300
46static const struct snd_soc_dapm_widget hdmi_widgets[] = { 301static const struct snd_soc_dapm_widget hdmi_widgets[] = {
@@ -79,6 +334,83 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
79 return 0; 334 return 0;
80} 335}
81 336
337static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
338{
339 int i;
340 const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
341 [0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
342 [4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
343 };
344 unsigned long spk_mask = 0;
345
346 for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) {
347 if (spk_alloc & (1 << i))
348 spk_mask |= hdmi_codec_eld_spk_alloc_bits[i];
349 }
350
351 return spk_mask;
352}
353
354void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
355{
356 u8 spk_alloc;
357 unsigned long spk_mask;
358
359 spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
360 spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
361
362 /* Detect if only stereo supported, else return 8 channels mappings */
363 if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2)
364 hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps;
365 else
366 hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
367}
368
369static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp,
370 unsigned char channels)
371{
372 int i;
373 u8 spk_alloc;
374 unsigned long spk_mask;
375 const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc;
376
377 spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
378 spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
379
380 for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) {
381 /* If spk_alloc == 0, HDMI is unplugged return stereo config*/
382 if (!spk_alloc && cap->ca_id == 0)
383 return i;
384 if (cap->n_ch != channels)
385 continue;
386 if (!(cap->mask == (spk_mask & cap->mask)))
387 continue;
388 return i;
389 }
390
391 return -EINVAL;
392}
393static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
394 struct snd_ctl_elem_value *ucontrol)
395{
396 unsigned const char *map;
397 unsigned int i;
398 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
399 struct hdmi_codec_priv *hcp = info->private_data;
400
401 map = info->chmap[hcp->chmap_idx].map;
402
403 for (i = 0; i < info->max_channels; i++) {
404 if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
405 ucontrol->value.integer.value[i] = 0;
406 else
407 ucontrol->value.integer.value[i] = map[i];
408 }
409
410 return 0;
411}
412
413
82static const struct snd_kcontrol_new hdmi_controls[] = { 414static const struct snd_kcontrol_new hdmi_controls[] = {
83 { 415 {
84 .access = SNDRV_CTL_ELEM_ACCESS_READ | 416 .access = SNDRV_CTL_ELEM_ACCESS_READ |
@@ -140,6 +472,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
140 if (ret) 472 if (ret)
141 return ret; 473 return ret;
142 } 474 }
475 /* Select chmap supported */
476 hdmi_codec_eld_chmap(hcp);
143 } 477 }
144 return 0; 478 return 0;
145} 479}
@@ -153,6 +487,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
153 487
154 WARN_ON(hcp->current_stream != substream); 488 WARN_ON(hcp->current_stream != substream);
155 489
490 hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
156 hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); 491 hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
157 492
158 mutex_lock(&hcp->current_stream_lock); 493 mutex_lock(&hcp->current_stream_lock);
@@ -173,7 +508,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
173 .dig_subframe = { 0 }, 508 .dig_subframe = { 0 },
174 } 509 }
175 }; 510 };
176 int ret; 511 int ret, idx;
177 512
178 dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, 513 dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
179 params_width(params), params_rate(params), 514 params_width(params), params_rate(params),
@@ -200,6 +535,17 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
200 hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; 535 hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
201 hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; 536 hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
202 537
538 /* Select a channel allocation that matches with ELD and pcm channels */
539 idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels);
540 if (idx < 0) {
541 dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
542 idx);
543 hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
544 return idx;
545 }
546 hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
547 hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
548
203 hp.sample_width = params_width(params); 549 hp.sample_width = params_width(params);
204 hp.sample_rate = params_rate(params); 550 hp.sample_rate = params_rate(params);
205 hp.channels = params_channels(params); 551 hp.channels = params_channels(params);
@@ -328,6 +674,32 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
328 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ 674 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
329 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) 675 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
330 676
677static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
678 struct snd_soc_dai *dai)
679{
680 struct snd_soc_dai_driver *drv = dai->driver;
681 struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
682 int ret;
683
684 dev_dbg(dai->dev, "%s()\n", __func__);
685
686 ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
687 NULL, drv->playback.channels_max, 0,
688 &hcp->chmap_info);
689 if (ret < 0)
690 return ret;
691
692 /* override handlers */
693 hcp->chmap_info->private_data = hcp;
694 hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get;
695
696 /* default chmap supported is stereo */
697 hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
698 hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
699
700 return 0;
701}
702
331static struct snd_soc_dai_driver hdmi_i2s_dai = { 703static struct snd_soc_dai_driver hdmi_i2s_dai = {
332 .id = DAI_ID_I2S, 704 .id = DAI_ID_I2S,
333 .playback = { 705 .playback = {
@@ -339,6 +711,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
339 .sig_bits = 24, 711 .sig_bits = 24,
340 }, 712 },
341 .ops = &hdmi_dai_ops, 713 .ops = &hdmi_dai_ops,
714 .pcm_new = hdmi_codec_pcm_new,
342}; 715};
343 716
344static const struct snd_soc_dai_driver hdmi_spdif_dai = { 717static const struct snd_soc_dai_driver hdmi_spdif_dai = {
@@ -351,6 +724,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
351 .formats = SPDIF_FORMATS, 724 .formats = SPDIF_FORMATS,
352 }, 725 },
353 .ops = &hdmi_dai_ops, 726 .ops = &hdmi_dai_ops,
727 .pcm_new = hdmi_codec_pcm_new,
354}; 728};
355 729
356static char hdmi_dai_name[][DAI_NAME_SIZE] = { 730static char hdmi_dai_name[][DAI_NAME_SIZE] = {
@@ -479,6 +853,10 @@ static int hdmi_codec_probe(struct platform_device *pdev)
479 853
480static int hdmi_codec_remove(struct platform_device *pdev) 854static int hdmi_codec_remove(struct platform_device *pdev)
481{ 855{
856 struct hdmi_codec_priv *hcp;
857
858 hcp = dev_get_drvdata(&pdev->dev);
859 kfree(hcp->chmap_info);
482 snd_soc_unregister_codec(&pdev->dev); 860 snd_soc_unregister_codec(&pdev->dev);
483 return 0; 861 return 0;
484} 862}