2 * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
6 * Author: Jyri Sarha <jsarha@ti.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/err.h>
22 #include <linux/string.h>
23 #include <linux/platform_device.h>
24 #include <sound/soc.h>
25 #include <sound/pcm_params.h>
26 #include <sound/dmaengine_pcm.h>
27 #include <uapi/sound/asound.h>
28 #include <sound/asoundef.h>
29 #include <sound/omap-pcm.h>
30 #include <sound/omap-hdmi-audio.h>
32 #define DRV_NAME "omap-hdmi-audio"
34 struct hdmi_audio_data
{
35 struct snd_soc_card
*card
;
37 const struct omap_hdmi_audio_ops
*ops
;
38 struct device
*dssdev
;
39 struct snd_dmaengine_dai_dma_data dma_data
;
40 struct omap_dss_audio dss_audio
;
41 struct snd_aes_iec958 iec
;
42 struct snd_cea_861_aud_if cea
;
44 struct mutex current_stream_lock
;
45 struct snd_pcm_substream
*current_stream
;
49 struct hdmi_audio_data
*card_drvdata_substream(struct snd_pcm_substream
*ss
)
51 struct snd_soc_pcm_runtime
*rtd
= ss
->private_data
;
53 return snd_soc_card_get_drvdata(rtd
->card
);
56 static void hdmi_dai_abort(struct device
*dev
)
58 struct hdmi_audio_data
*ad
= dev_get_drvdata(dev
);
60 mutex_lock(&ad
->current_stream_lock
);
61 if (ad
->current_stream
&& ad
->current_stream
->runtime
&&
62 snd_pcm_running(ad
->current_stream
)) {
63 dev_err(dev
, "HDMI display disabled, aborting playback\n");
64 snd_pcm_stream_lock_irq(ad
->current_stream
);
65 snd_pcm_stop(ad
->current_stream
, SNDRV_PCM_STATE_DISCONNECTED
);
66 snd_pcm_stream_unlock_irq(ad
->current_stream
);
68 mutex_unlock(&ad
->current_stream_lock
);
71 static int hdmi_dai_startup(struct snd_pcm_substream
*substream
,
72 struct snd_soc_dai
*dai
)
74 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
77 * Make sure that the period bytes are multiple of the DMA packet size.
78 * Largest packet size we use is 32 32-bit words = 128 bytes
80 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
81 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, 128);
83 dev_err(dai
->dev
, "Could not apply period constraint: %d\n",
87 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
88 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, 128);
90 dev_err(dai
->dev
, "Could not apply buffer constraint: %d\n",
95 snd_soc_dai_set_dma_data(dai
, substream
, &ad
->dma_data
);
97 mutex_lock(&ad
->current_stream_lock
);
98 ad
->current_stream
= substream
;
99 mutex_unlock(&ad
->current_stream_lock
);
101 ret
= ad
->ops
->audio_startup(ad
->dssdev
, hdmi_dai_abort
);
104 mutex_lock(&ad
->current_stream_lock
);
105 ad
->current_stream
= NULL
;
106 mutex_unlock(&ad
->current_stream_lock
);
112 static int hdmi_dai_hw_params(struct snd_pcm_substream
*substream
,
113 struct snd_pcm_hw_params
*params
,
114 struct snd_soc_dai
*dai
)
116 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
117 struct snd_aes_iec958
*iec
= &ad
->iec
;
118 struct snd_cea_861_aud_if
*cea
= &ad
->cea
;
120 WARN_ON(ad
->current_stream
!= substream
);
122 switch (params_format(params
)) {
123 case SNDRV_PCM_FORMAT_S16_LE
:
124 ad
->dma_data
.maxburst
= 16;
126 case SNDRV_PCM_FORMAT_S24_LE
:
127 ad
->dma_data
.maxburst
= 32;
130 dev_err(dai
->dev
, "format not supported!\n");
134 ad
->dss_audio
.iec
= iec
;
135 ad
->dss_audio
.cea
= cea
;
137 * fill the IEC-60958 channel status word
139 /* initialize the word bytes */
140 memset(iec
->status
, 0, sizeof(iec
->status
));
142 /* specify IEC-60958-3 (commercial use) */
143 iec
->status
[0] &= ~IEC958_AES0_PROFESSIONAL
;
145 /* specify that the audio is LPCM*/
146 iec
->status
[0] &= ~IEC958_AES0_NONAUDIO
;
148 iec
->status
[0] |= IEC958_AES0_CON_NOT_COPYRIGHT
;
150 iec
->status
[0] |= IEC958_AES0_CON_EMPHASIS_NONE
;
152 iec
->status
[1] = IEC958_AES1_CON_GENERAL
;
154 iec
->status
[2] |= IEC958_AES2_CON_SOURCE_UNSPEC
;
156 iec
->status
[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC
;
158 switch (params_rate(params
)) {
160 iec
->status
[3] |= IEC958_AES3_CON_FS_32000
;
163 iec
->status
[3] |= IEC958_AES3_CON_FS_44100
;
166 iec
->status
[3] |= IEC958_AES3_CON_FS_48000
;
169 iec
->status
[3] |= IEC958_AES3_CON_FS_88200
;
172 iec
->status
[3] |= IEC958_AES3_CON_FS_96000
;
175 iec
->status
[3] |= IEC958_AES3_CON_FS_176400
;
178 iec
->status
[3] |= IEC958_AES3_CON_FS_192000
;
181 dev_err(dai
->dev
, "rate not supported!\n");
185 /* specify the clock accuracy */
186 iec
->status
[3] |= IEC958_AES3_CON_CLOCK_1000PPM
;
189 * specify the word length. The same word length value can mean
190 * two different lengths. Hence, we need to specify the maximum
191 * word length as well.
193 switch (params_format(params
)) {
194 case SNDRV_PCM_FORMAT_S16_LE
:
195 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_20_16
;
196 iec
->status
[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24
;
198 case SNDRV_PCM_FORMAT_S24_LE
:
199 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_24_20
;
200 iec
->status
[4] |= IEC958_AES4_CON_MAX_WORDLEN_24
;
203 dev_err(dai
->dev
, "format not supported!\n");
208 * Fill the CEA-861 audio infoframe (see spec for details)
211 cea
->db1_ct_cc
= (params_channels(params
) - 1)
212 & CEA861_AUDIO_INFOFRAME_DB1CC
;
213 cea
->db1_ct_cc
|= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM
;
215 cea
->db2_sf_ss
= CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM
;
216 cea
->db2_sf_ss
|= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM
;
218 cea
->db3
= 0; /* not used, all zeros */
220 if (params_channels(params
) == 2)
222 else if (params_channels(params
) == 6)
227 if (cea
->db4_ca
== 0x00)
228 cea
->db5_dminh_lsv
= CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED
;
230 cea
->db5_dminh_lsv
= CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED
;
232 /* the expression is trivial but makes clear what we are doing */
233 cea
->db5_dminh_lsv
|= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV
);
235 return ad
->ops
->audio_config(ad
->dssdev
, &ad
->dss_audio
);
238 static int hdmi_dai_trigger(struct snd_pcm_substream
*substream
, int cmd
,
239 struct snd_soc_dai
*dai
)
241 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
244 WARN_ON(ad
->current_stream
!= substream
);
247 case SNDRV_PCM_TRIGGER_START
:
248 case SNDRV_PCM_TRIGGER_RESUME
:
249 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
250 err
= ad
->ops
->audio_start(ad
->dssdev
);
252 case SNDRV_PCM_TRIGGER_STOP
:
253 case SNDRV_PCM_TRIGGER_SUSPEND
:
254 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
255 ad
->ops
->audio_stop(ad
->dssdev
);
263 static void hdmi_dai_shutdown(struct snd_pcm_substream
*substream
,
264 struct snd_soc_dai
*dai
)
266 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
268 WARN_ON(ad
->current_stream
!= substream
);
270 ad
->ops
->audio_shutdown(ad
->dssdev
);
272 mutex_lock(&ad
->current_stream_lock
);
273 ad
->current_stream
= NULL
;
274 mutex_unlock(&ad
->current_stream_lock
);
277 static const struct snd_soc_dai_ops hdmi_dai_ops
= {
278 .startup
= hdmi_dai_startup
,
279 .hw_params
= hdmi_dai_hw_params
,
280 .trigger
= hdmi_dai_trigger
,
281 .shutdown
= hdmi_dai_shutdown
,
284 static const struct snd_soc_component_driver omap_hdmi_component
= {
285 .name
= "omapdss_hdmi",
288 static struct snd_soc_dai_driver omap5_hdmi_dai
= {
289 .name
= "omap5-hdmi-dai",
293 .rates
= (SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
|
294 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
|
295 SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
|
296 SNDRV_PCM_RATE_192000
),
297 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
299 .ops
= &hdmi_dai_ops
,
302 static struct snd_soc_dai_driver omap4_hdmi_dai
= {
303 .name
= "omap4-hdmi-dai",
307 .rates
= (SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
|
308 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
|
309 SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
|
310 SNDRV_PCM_RATE_192000
),
311 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
,
313 .ops
= &hdmi_dai_ops
,
316 static int omap_hdmi_audio_probe(struct platform_device
*pdev
)
318 struct omap_hdmi_audio_pdata
*ha
= pdev
->dev
.platform_data
;
319 struct device
*dev
= &pdev
->dev
;
320 struct hdmi_audio_data
*ad
;
321 struct snd_soc_dai_driver
*dai_drv
;
322 struct snd_soc_card
*card
;
326 dev_err(dev
, "No platform data\n");
330 ad
= devm_kzalloc(dev
, sizeof(*ad
), GFP_KERNEL
);
333 ad
->dssdev
= ha
->dev
;
335 ad
->dma_data
.addr
= ha
->audio_dma_addr
;
336 ad
->dma_data
.filter_data
= "audio_tx";
337 ad
->dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
338 mutex_init(&ad
->current_stream_lock
);
340 switch (ha
->dss_version
) {
341 case OMAPDSS_VER_OMAP4430_ES1
:
342 case OMAPDSS_VER_OMAP4430_ES2
:
343 case OMAPDSS_VER_OMAP4
:
344 dai_drv
= &omap4_hdmi_dai
;
346 case OMAPDSS_VER_OMAP5
:
347 case OMAPDSS_VER_DRA7xx
:
348 dai_drv
= &omap5_hdmi_dai
;
353 ret
= snd_soc_register_component(ad
->dssdev
, &omap_hdmi_component
,
358 ret
= omap_pcm_platform_register(ad
->dssdev
);
362 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
366 card
->name
= devm_kasprintf(dev
, GFP_KERNEL
,
367 "HDMI %s", dev_name(ad
->dssdev
));
368 card
->owner
= THIS_MODULE
;
370 devm_kzalloc(dev
, sizeof(*(card
->dai_link
)), GFP_KERNEL
);
373 card
->dai_link
->name
= card
->name
;
374 card
->dai_link
->stream_name
= card
->name
;
375 card
->dai_link
->cpu_dai_name
= dev_name(ad
->dssdev
);
376 card
->dai_link
->platform_name
= dev_name(ad
->dssdev
);
377 card
->dai_link
->codec_name
= "snd-soc-dummy";
378 card
->dai_link
->codec_dai_name
= "snd-soc-dummy-dai";
382 ret
= snd_soc_register_card(card
);
384 dev_err(dev
, "snd_soc_register_card failed (%d)\n", ret
);
385 snd_soc_unregister_component(ad
->dssdev
);
390 snd_soc_card_set_drvdata(card
, ad
);
392 dev_set_drvdata(dev
, ad
);
397 static int omap_hdmi_audio_remove(struct platform_device
*pdev
)
399 struct hdmi_audio_data
*ad
= platform_get_drvdata(pdev
);
401 snd_soc_unregister_card(ad
->card
);
402 snd_soc_unregister_component(ad
->dssdev
);
406 static struct platform_driver hdmi_audio_driver
= {
410 .probe
= omap_hdmi_audio_probe
,
411 .remove
= omap_hdmi_audio_remove
,
414 module_platform_driver(hdmi_audio_driver
);
416 MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
417 MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
418 MODULE_LICENSE("GPL");
419 MODULE_ALIAS("platform:" DRV_NAME
);