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>
31 #include <video/omapdss.h>
33 #define DRV_NAME "omap-hdmi-audio"
35 struct hdmi_audio_data
{
36 struct snd_soc_card
*card
;
38 const struct omap_hdmi_audio_ops
*ops
;
39 struct device
*dssdev
;
40 struct snd_dmaengine_dai_dma_data dma_data
;
41 struct omap_dss_audio dss_audio
;
42 struct snd_aes_iec958 iec
;
43 struct snd_cea_861_aud_if cea
;
45 struct mutex current_stream_lock
;
46 struct snd_pcm_substream
*current_stream
;
50 struct hdmi_audio_data
*card_drvdata_substream(struct snd_pcm_substream
*ss
)
52 struct snd_soc_pcm_runtime
*rtd
= ss
->private_data
;
54 return snd_soc_card_get_drvdata(rtd
->card
);
57 static void hdmi_dai_abort(struct device
*dev
)
59 struct hdmi_audio_data
*ad
= dev_get_drvdata(dev
);
61 mutex_lock(&ad
->current_stream_lock
);
62 if (ad
->current_stream
&& ad
->current_stream
->runtime
&&
63 snd_pcm_running(ad
->current_stream
)) {
64 dev_err(dev
, "HDMI display disabled, aborting playback\n");
65 snd_pcm_stream_lock_irq(ad
->current_stream
);
66 snd_pcm_stop(ad
->current_stream
, SNDRV_PCM_STATE_DISCONNECTED
);
67 snd_pcm_stream_unlock_irq(ad
->current_stream
);
69 mutex_unlock(&ad
->current_stream_lock
);
72 static int hdmi_dai_startup(struct snd_pcm_substream
*substream
,
73 struct snd_soc_dai
*dai
)
75 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
78 * Make sure that the period bytes are multiple of the DMA packet size.
79 * Largest packet size we use is 32 32-bit words = 128 bytes
81 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
82 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, 128);
84 dev_err(dai
->dev
, "Could not apply period constraint: %d\n",
88 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
89 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, 128);
91 dev_err(dai
->dev
, "Could not apply buffer constraint: %d\n",
96 snd_soc_dai_set_dma_data(dai
, substream
, &ad
->dma_data
);
98 mutex_lock(&ad
->current_stream_lock
);
99 ad
->current_stream
= substream
;
100 mutex_unlock(&ad
->current_stream_lock
);
102 ret
= ad
->ops
->audio_startup(ad
->dssdev
, hdmi_dai_abort
);
105 mutex_lock(&ad
->current_stream_lock
);
106 ad
->current_stream
= NULL
;
107 mutex_unlock(&ad
->current_stream_lock
);
113 static int hdmi_dai_hw_params(struct snd_pcm_substream
*substream
,
114 struct snd_pcm_hw_params
*params
,
115 struct snd_soc_dai
*dai
)
117 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
118 struct snd_aes_iec958
*iec
= &ad
->iec
;
119 struct snd_cea_861_aud_if
*cea
= &ad
->cea
;
121 WARN_ON(ad
->current_stream
!= substream
);
123 switch (params_format(params
)) {
124 case SNDRV_PCM_FORMAT_S16_LE
:
125 ad
->dma_data
.maxburst
= 16;
127 case SNDRV_PCM_FORMAT_S24_LE
:
128 ad
->dma_data
.maxburst
= 32;
131 dev_err(dai
->dev
, "format not supported!\n");
135 ad
->dss_audio
.iec
= iec
;
136 ad
->dss_audio
.cea
= cea
;
138 * fill the IEC-60958 channel status word
140 /* initialize the word bytes */
141 memset(iec
->status
, 0, sizeof(iec
->status
));
143 /* specify IEC-60958-3 (commercial use) */
144 iec
->status
[0] &= ~IEC958_AES0_PROFESSIONAL
;
146 /* specify that the audio is LPCM*/
147 iec
->status
[0] &= ~IEC958_AES0_NONAUDIO
;
149 iec
->status
[0] |= IEC958_AES0_CON_NOT_COPYRIGHT
;
151 iec
->status
[0] |= IEC958_AES0_CON_EMPHASIS_NONE
;
153 iec
->status
[1] = IEC958_AES1_CON_GENERAL
;
155 iec
->status
[2] |= IEC958_AES2_CON_SOURCE_UNSPEC
;
157 iec
->status
[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC
;
159 switch (params_rate(params
)) {
161 iec
->status
[3] |= IEC958_AES3_CON_FS_32000
;
164 iec
->status
[3] |= IEC958_AES3_CON_FS_44100
;
167 iec
->status
[3] |= IEC958_AES3_CON_FS_48000
;
170 iec
->status
[3] |= IEC958_AES3_CON_FS_88200
;
173 iec
->status
[3] |= IEC958_AES3_CON_FS_96000
;
176 iec
->status
[3] |= IEC958_AES3_CON_FS_176400
;
179 iec
->status
[3] |= IEC958_AES3_CON_FS_192000
;
182 dev_err(dai
->dev
, "rate not supported!\n");
186 /* specify the clock accuracy */
187 iec
->status
[3] |= IEC958_AES3_CON_CLOCK_1000PPM
;
190 * specify the word length. The same word length value can mean
191 * two different lengths. Hence, we need to specify the maximum
192 * word length as well.
194 switch (params_format(params
)) {
195 case SNDRV_PCM_FORMAT_S16_LE
:
196 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_20_16
;
197 iec
->status
[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24
;
199 case SNDRV_PCM_FORMAT_S24_LE
:
200 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_24_20
;
201 iec
->status
[4] |= IEC958_AES4_CON_MAX_WORDLEN_24
;
204 dev_err(dai
->dev
, "format not supported!\n");
209 * Fill the CEA-861 audio infoframe (see spec for details)
212 cea
->db1_ct_cc
= (params_channels(params
) - 1)
213 & CEA861_AUDIO_INFOFRAME_DB1CC
;
214 cea
->db1_ct_cc
|= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM
;
216 cea
->db2_sf_ss
= CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM
;
217 cea
->db2_sf_ss
|= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM
;
219 cea
->db3
= 0; /* not used, all zeros */
221 if (params_channels(params
) == 2)
223 else if (params_channels(params
) == 6)
228 if (cea
->db4_ca
== 0x00)
229 cea
->db5_dminh_lsv
= CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED
;
231 cea
->db5_dminh_lsv
= CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED
;
233 /* the expression is trivial but makes clear what we are doing */
234 cea
->db5_dminh_lsv
|= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV
);
236 return ad
->ops
->audio_config(ad
->dssdev
, &ad
->dss_audio
);
239 static int hdmi_dai_trigger(struct snd_pcm_substream
*substream
, int cmd
,
240 struct snd_soc_dai
*dai
)
242 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
245 WARN_ON(ad
->current_stream
!= substream
);
248 case SNDRV_PCM_TRIGGER_START
:
249 case SNDRV_PCM_TRIGGER_RESUME
:
250 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
251 err
= ad
->ops
->audio_start(ad
->dssdev
);
253 case SNDRV_PCM_TRIGGER_STOP
:
254 case SNDRV_PCM_TRIGGER_SUSPEND
:
255 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
256 ad
->ops
->audio_stop(ad
->dssdev
);
264 static void hdmi_dai_shutdown(struct snd_pcm_substream
*substream
,
265 struct snd_soc_dai
*dai
)
267 struct hdmi_audio_data
*ad
= card_drvdata_substream(substream
);
269 WARN_ON(ad
->current_stream
!= substream
);
271 ad
->ops
->audio_shutdown(ad
->dssdev
);
273 mutex_lock(&ad
->current_stream_lock
);
274 ad
->current_stream
= NULL
;
275 mutex_unlock(&ad
->current_stream_lock
);
278 static const struct snd_soc_dai_ops hdmi_dai_ops
= {
279 .startup
= hdmi_dai_startup
,
280 .hw_params
= hdmi_dai_hw_params
,
281 .trigger
= hdmi_dai_trigger
,
282 .shutdown
= hdmi_dai_shutdown
,
285 static const struct snd_soc_component_driver omap_hdmi_component
= {
286 .name
= "omapdss_hdmi",
289 static struct snd_soc_dai_driver omap5_hdmi_dai
= {
290 .name
= "omap5-hdmi-dai",
294 .rates
= (SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
|
295 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
|
296 SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
|
297 SNDRV_PCM_RATE_192000
),
298 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
300 .ops
= &hdmi_dai_ops
,
303 static struct snd_soc_dai_driver omap4_hdmi_dai
= {
304 .name
= "omap4-hdmi-dai",
308 .rates
= (SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
|
309 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
|
310 SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
|
311 SNDRV_PCM_RATE_192000
),
312 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
,
314 .ops
= &hdmi_dai_ops
,
317 static int omap_hdmi_audio_probe(struct platform_device
*pdev
)
319 struct omap_hdmi_audio_pdata
*ha
= pdev
->dev
.platform_data
;
320 struct device
*dev
= &pdev
->dev
;
321 struct hdmi_audio_data
*ad
;
322 struct snd_soc_dai_driver
*dai_drv
;
323 struct snd_soc_card
*card
;
327 dev_err(dev
, "No platform data\n");
331 ad
= devm_kzalloc(dev
, sizeof(*ad
), GFP_KERNEL
);
334 ad
->dssdev
= ha
->dev
;
336 ad
->dma_data
.addr
= ha
->audio_dma_addr
;
337 ad
->dma_data
.filter_data
= "audio_tx";
338 ad
->dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
339 mutex_init(&ad
->current_stream_lock
);
341 switch (ha
->dss_version
) {
342 case OMAPDSS_VER_OMAP4430_ES1
:
343 case OMAPDSS_VER_OMAP4430_ES2
:
344 case OMAPDSS_VER_OMAP4
:
345 dai_drv
= &omap4_hdmi_dai
;
347 case OMAPDSS_VER_OMAP5
:
348 case OMAPDSS_VER_DRA7xx
:
349 dai_drv
= &omap5_hdmi_dai
;
354 ret
= snd_soc_register_component(ad
->dssdev
, &omap_hdmi_component
,
359 ret
= omap_pcm_platform_register(ad
->dssdev
);
363 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
367 card
->name
= devm_kasprintf(dev
, GFP_KERNEL
,
368 "HDMI %s", dev_name(ad
->dssdev
));
369 card
->owner
= THIS_MODULE
;
371 devm_kzalloc(dev
, sizeof(*(card
->dai_link
)), GFP_KERNEL
);
374 card
->dai_link
->name
= card
->name
;
375 card
->dai_link
->stream_name
= card
->name
;
376 card
->dai_link
->cpu_dai_name
= dev_name(ad
->dssdev
);
377 card
->dai_link
->platform_name
= dev_name(ad
->dssdev
);
378 card
->dai_link
->codec_name
= "snd-soc-dummy";
379 card
->dai_link
->codec_dai_name
= "snd-soc-dummy-dai";
383 ret
= snd_soc_register_card(card
);
385 dev_err(dev
, "snd_soc_register_card failed (%d)\n", ret
);
386 snd_soc_unregister_component(ad
->dssdev
);
391 snd_soc_card_set_drvdata(card
, ad
);
393 dev_set_drvdata(dev
, ad
);
398 static int omap_hdmi_audio_remove(struct platform_device
*pdev
)
400 struct hdmi_audio_data
*ad
= platform_get_drvdata(pdev
);
402 snd_soc_unregister_card(ad
->card
);
403 snd_soc_unregister_component(ad
->dssdev
);
407 static struct platform_driver hdmi_audio_driver
= {
411 .probe
= omap_hdmi_audio_probe
,
412 .remove
= omap_hdmi_audio_remove
,
415 module_platform_driver(hdmi_audio_driver
);
417 MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
418 MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
419 MODULE_LICENSE("GPL");
420 MODULE_ALIAS("platform:" DRV_NAME
);