4 * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
6 * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
7 * Ricardo Neri <ricardo.neri@ti.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/device.h>
28 #include <sound/core.h>
29 #include <sound/pcm.h>
30 #include <sound/pcm_params.h>
31 #include <sound/initval.h>
32 #include <sound/soc.h>
33 #include <sound/asound.h>
34 #include <sound/asoundef.h>
35 #include <video/omapdss.h>
38 #include "omap-hdmi.h"
40 #define DRV_NAME "omap-hdmi-audio-dai"
43 struct omap_pcm_dma_data dma_params
;
44 struct omap_dss_audio dss_audio
;
45 struct snd_aes_iec958 iec
;
46 struct snd_cea_861_aud_if cea
;
47 struct omap_dss_device
*dssdev
;
50 static int omap_hdmi_dai_startup(struct snd_pcm_substream
*substream
,
51 struct snd_soc_dai
*dai
)
53 struct hdmi_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
56 * Make sure that the period bytes are multiple of the DMA packet size.
57 * Largest packet size we use is 32 32-bit words = 128 bytes
59 err
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
60 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, 128);
62 dev_err(dai
->dev
, "could not apply constraint\n");
66 if (!priv
->dssdev
->driver
->audio_supported(priv
->dssdev
)) {
67 dev_err(dai
->dev
, "audio not supported\n");
71 snd_soc_dai_set_dma_data(dai
, substream
, &priv
->dma_params
);
76 static int omap_hdmi_dai_prepare(struct snd_pcm_substream
*substream
,
77 struct snd_soc_dai
*dai
)
79 struct hdmi_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
81 return priv
->dssdev
->driver
->audio_enable(priv
->dssdev
);
84 static int omap_hdmi_dai_hw_params(struct snd_pcm_substream
*substream
,
85 struct snd_pcm_hw_params
*params
,
86 struct snd_soc_dai
*dai
)
88 struct hdmi_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
89 struct snd_aes_iec958
*iec
= &priv
->iec
;
90 struct snd_cea_861_aud_if
*cea
= &priv
->cea
;
91 struct omap_pcm_dma_data
*dma_data
;
94 dma_data
= snd_soc_dai_get_dma_data(dai
, substream
);
96 switch (params_format(params
)) {
97 case SNDRV_PCM_FORMAT_S16_LE
:
98 dma_data
->packet_size
= 16;
100 case SNDRV_PCM_FORMAT_S24_LE
:
101 dma_data
->packet_size
= 32;
104 dev_err(dai
->dev
, "format not supported!\n");
108 dma_data
->data_type
= 32;
111 * fill the IEC-60958 channel status word
113 /* initialize the word bytes */
114 memset(iec
->status
, 0, sizeof(iec
->status
));
116 /* specify IEC-60958-3 (commercial use) */
117 iec
->status
[0] &= ~IEC958_AES0_PROFESSIONAL
;
119 /* specify that the audio is LPCM*/
120 iec
->status
[0] &= ~IEC958_AES0_NONAUDIO
;
122 iec
->status
[0] |= IEC958_AES0_CON_NOT_COPYRIGHT
;
124 iec
->status
[0] |= IEC958_AES0_CON_EMPHASIS_NONE
;
126 iec
->status
[0] |= IEC958_AES1_PRO_MODE_NOTID
;
128 iec
->status
[1] = IEC958_AES1_CON_GENERAL
;
130 iec
->status
[2] |= IEC958_AES2_CON_SOURCE_UNSPEC
;
132 iec
->status
[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC
;
134 switch (params_rate(params
)) {
136 iec
->status
[3] |= IEC958_AES3_CON_FS_32000
;
139 iec
->status
[3] |= IEC958_AES3_CON_FS_44100
;
142 iec
->status
[3] |= IEC958_AES3_CON_FS_48000
;
145 iec
->status
[3] |= IEC958_AES3_CON_FS_88200
;
148 iec
->status
[3] |= IEC958_AES3_CON_FS_96000
;
151 iec
->status
[3] |= IEC958_AES3_CON_FS_176400
;
154 iec
->status
[3] |= IEC958_AES3_CON_FS_192000
;
157 dev_err(dai
->dev
, "rate not supported!\n");
161 /* specify the clock accuracy */
162 iec
->status
[3] |= IEC958_AES3_CON_CLOCK_1000PPM
;
165 * specify the word length. The same word length value can mean
166 * two different lengths. Hence, we need to specify the maximum
167 * word length as well.
169 switch (params_format(params
)) {
170 case SNDRV_PCM_FORMAT_S16_LE
:
171 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_20_16
;
172 iec
->status
[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24
;
174 case SNDRV_PCM_FORMAT_S24_LE
:
175 iec
->status
[4] |= IEC958_AES4_CON_WORDLEN_24_20
;
176 iec
->status
[4] |= IEC958_AES4_CON_MAX_WORDLEN_24
;
179 dev_err(dai
->dev
, "format not supported!\n");
184 * Fill the CEA-861 audio infoframe (see spec for details)
187 cea
->db1_ct_cc
= (params_channels(params
) - 1)
188 & CEA861_AUDIO_INFOFRAME_DB1CC
;
189 cea
->db1_ct_cc
|= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM
;
191 cea
->db2_sf_ss
= CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM
;
192 cea
->db2_sf_ss
|= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM
;
194 cea
->db3
= 0; /* not used, all zeros */
197 * The OMAP HDMI IP requires to use the 8-channel channel code when
198 * transmitting more than two channels.
200 if (params_channels(params
) == 2)
205 cea
->db5_dminh_lsv
= CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED
;
206 /* the expression is trivial but makes clear what we are doing */
207 cea
->db5_dminh_lsv
|= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV
);
209 priv
->dss_audio
.iec
= iec
;
210 priv
->dss_audio
.cea
= cea
;
212 err
= priv
->dssdev
->driver
->audio_config(priv
->dssdev
,
218 static int omap_hdmi_dai_trigger(struct snd_pcm_substream
*substream
, int cmd
,
219 struct snd_soc_dai
*dai
)
221 struct hdmi_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
225 case SNDRV_PCM_TRIGGER_START
:
226 case SNDRV_PCM_TRIGGER_RESUME
:
227 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
228 err
= priv
->dssdev
->driver
->audio_start(priv
->dssdev
);
230 case SNDRV_PCM_TRIGGER_STOP
:
231 case SNDRV_PCM_TRIGGER_SUSPEND
:
232 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
233 priv
->dssdev
->driver
->audio_stop(priv
->dssdev
);
241 static void omap_hdmi_dai_shutdown(struct snd_pcm_substream
*substream
,
242 struct snd_soc_dai
*dai
)
244 struct hdmi_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
246 priv
->dssdev
->driver
->audio_disable(priv
->dssdev
);
249 static const struct snd_soc_dai_ops omap_hdmi_dai_ops
= {
250 .startup
= omap_hdmi_dai_startup
,
251 .hw_params
= omap_hdmi_dai_hw_params
,
252 .prepare
= omap_hdmi_dai_prepare
,
253 .trigger
= omap_hdmi_dai_trigger
,
254 .shutdown
= omap_hdmi_dai_shutdown
,
257 static struct snd_soc_dai_driver omap_hdmi_dai
= {
261 .rates
= OMAP_HDMI_RATES
,
262 .formats
= OMAP_HDMI_FORMATS
,
264 .ops
= &omap_hdmi_dai_ops
,
267 static int omap_hdmi_probe(struct platform_device
*pdev
)
270 struct resource
*hdmi_rsrc
;
271 struct hdmi_priv
*hdmi_data
;
272 bool hdmi_dev_found
= false;
274 hdmi_data
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi_data
), GFP_KERNEL
);
275 if (hdmi_data
== NULL
) {
276 dev_err(&pdev
->dev
, "Cannot allocate memory for HDMI data\n");
280 hdmi_rsrc
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
282 dev_err(&pdev
->dev
, "Cannot obtain IORESOURCE_MEM HDMI\n");
286 hdmi_data
->dma_params
.port_addr
= hdmi_rsrc
->start
287 + OMAP_HDMI_AUDIO_DMA_PORT
;
289 hdmi_rsrc
= platform_get_resource(pdev
, IORESOURCE_DMA
, 0);
291 dev_err(&pdev
->dev
, "Cannot obtain IORESOURCE_DMA HDMI\n");
295 hdmi_data
->dma_params
.dma_req
= hdmi_rsrc
->start
;
296 hdmi_data
->dma_params
.name
= "HDMI playback";
299 * TODO: We assume that there is only one DSS HDMI device. Future
300 * OMAP implementations may support more than one HDMI devices and
301 * we should provided separate audio support for all of them.
303 /* Find an HDMI device. */
304 for_each_dss_dev(hdmi_data
->dssdev
) {
305 omap_dss_get_device(hdmi_data
->dssdev
);
307 if (!hdmi_data
->dssdev
->driver
) {
308 omap_dss_put_device(hdmi_data
->dssdev
);
312 if (hdmi_data
->dssdev
->type
== OMAP_DISPLAY_TYPE_HDMI
) {
313 hdmi_dev_found
= true;
318 if (!hdmi_dev_found
) {
319 dev_err(&pdev
->dev
, "no driver for HDMI display found\n");
323 dev_set_drvdata(&pdev
->dev
, hdmi_data
);
324 ret
= snd_soc_register_dai(&pdev
->dev
, &omap_hdmi_dai
);
329 static int omap_hdmi_remove(struct platform_device
*pdev
)
331 struct hdmi_priv
*hdmi_data
= dev_get_drvdata(&pdev
->dev
);
333 snd_soc_unregister_dai(&pdev
->dev
);
335 if (hdmi_data
== NULL
) {
336 dev_err(&pdev
->dev
, "cannot obtain HDMi data\n");
340 omap_dss_put_device(hdmi_data
->dssdev
);
344 static struct platform_driver hdmi_dai_driver
= {
347 .owner
= THIS_MODULE
,
349 .probe
= omap_hdmi_probe
,
350 .remove
= omap_hdmi_remove
,
353 module_platform_driver(hdmi_dai_driver
);
355 MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
356 MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
357 MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
358 MODULE_LICENSE("GPL");
359 MODULE_ALIAS("platform:" DRV_NAME
);