^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Jyri Sarha <jsarha@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/dmaengine_pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <uapi/sound/asound.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/asoundef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sound/omap-hdmi-audio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "sdma-pcm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define DRV_NAME "omap-hdmi-audio"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct hdmi_audio_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) const struct omap_hdmi_audio_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct device *dssdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct snd_dmaengine_dai_dma_data dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct omap_dss_audio dss_audio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct snd_aes_iec958 iec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct snd_cea_861_aud_if cea;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct mutex current_stream_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct snd_pcm_substream *current_stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct snd_soc_pcm_runtime *rtd = ss->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return snd_soc_card_get_drvdata(rtd->card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static void hdmi_dai_abort(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct hdmi_audio_data *ad = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) mutex_lock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (ad->current_stream && ad->current_stream->runtime &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) snd_pcm_running(ad->current_stream)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) dev_err(dev, "HDMI display disabled, aborting playback\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) snd_pcm_stream_lock_irq(ad->current_stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) snd_pcm_stream_unlock_irq(ad->current_stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) mutex_unlock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static int hdmi_dai_startup(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct hdmi_audio_data *ad = card_drvdata_substream(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * Make sure that the period bytes are multiple of the DMA packet size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * Largest packet size we use is 32 32-bit words = 128 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) dev_err(dai->dev, "Could not apply period constraint: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) dev_err(dai->dev, "Could not apply buffer constraint: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) mutex_lock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ad->current_stream = substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) mutex_unlock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) mutex_lock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) ad->current_stream = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) mutex_unlock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct snd_pcm_hw_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct hdmi_audio_data *ad = card_drvdata_substream(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct snd_aes_iec958 *iec = &ad->iec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct snd_cea_861_aud_if *cea = &ad->cea;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) WARN_ON(ad->current_stream != substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) case SNDRV_PCM_FORMAT_S16_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ad->dma_data.maxburst = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case SNDRV_PCM_FORMAT_S24_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ad->dma_data.maxburst = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dev_err(dai->dev, "format not supported!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ad->dss_audio.iec = iec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ad->dss_audio.cea = cea;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * fill the IEC-60958 channel status word
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* initialize the word bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) memset(iec->status, 0, sizeof(iec->status));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* specify IEC-60958-3 (commercial use) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* specify that the audio is LPCM*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) iec->status[0] &= ~IEC958_AES0_NONAUDIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) iec->status[1] = IEC958_AES1_CON_GENERAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) switch (params_rate(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) case 32000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) iec->status[3] |= IEC958_AES3_CON_FS_32000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) case 44100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) iec->status[3] |= IEC958_AES3_CON_FS_44100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) case 48000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) iec->status[3] |= IEC958_AES3_CON_FS_48000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case 88200:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) iec->status[3] |= IEC958_AES3_CON_FS_88200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case 96000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) iec->status[3] |= IEC958_AES3_CON_FS_96000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case 176400:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) iec->status[3] |= IEC958_AES3_CON_FS_176400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case 192000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) iec->status[3] |= IEC958_AES3_CON_FS_192000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) dev_err(dai->dev, "rate not supported!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /* specify the clock accuracy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * specify the word length. The same word length value can mean
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * two different lengths. Hence, we need to specify the maximum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * word length as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case SNDRV_PCM_FORMAT_S16_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) case SNDRV_PCM_FORMAT_S24_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) dev_err(dai->dev, "format not supported!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * Fill the CEA-861 audio infoframe (see spec for details)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) cea->db1_ct_cc = (params_channels(params) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) & CEA861_AUDIO_INFOFRAME_DB1CC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) cea->db3 = 0; /* not used, all zeros */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (params_channels(params) == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) cea->db4_ca = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) else if (params_channels(params) == 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) cea->db4_ca = 0xb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) cea->db4_ca = 0x13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (cea->db4_ca == 0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* the expression is trivial but makes clear what we are doing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct hdmi_audio_data *ad = card_drvdata_substream(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) WARN_ON(ad->current_stream != substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) err = ad->ops->audio_start(ad->dssdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ad->ops->audio_stop(ad->dssdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct hdmi_audio_data *ad = card_drvdata_substream(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) WARN_ON(ad->current_stream != substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) ad->ops->audio_shutdown(ad->dssdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) mutex_lock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ad->current_stream = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) mutex_unlock(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static const struct snd_soc_dai_ops hdmi_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .startup = hdmi_dai_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .hw_params = hdmi_dai_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .trigger = hdmi_dai_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .shutdown = hdmi_dai_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static const struct snd_soc_component_driver omap_hdmi_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) .name = "omapdss_hdmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static struct snd_soc_dai_driver omap5_hdmi_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .name = "omap5-hdmi-dai",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .channels_max = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) SNDRV_PCM_RATE_192000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) .ops = &hdmi_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static struct snd_soc_dai_driver omap4_hdmi_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .name = "omap4-hdmi-dai",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .channels_max = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) SNDRV_PCM_RATE_192000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .ops = &hdmi_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int omap_hdmi_audio_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct hdmi_audio_data *ad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct snd_soc_dai_driver *dai_drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) struct snd_soc_dai_link_component *compnent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (!ha) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) dev_err(dev, "No platform data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (!ad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ad->dssdev = ha->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ad->ops = ha->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) ad->dma_data.addr = ha->audio_dma_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) ad->dma_data.filter_data = "audio_tx";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) mutex_init(&ad->current_stream_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) switch (ha->version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) dai_drv = &omap4_hdmi_dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) dai_drv = &omap5_hdmi_dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) dai_drv, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ret = sdma_pcm_platform_register(ad->dssdev, "audio_tx", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (!card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) card->name = devm_kasprintf(dev, GFP_KERNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) "HDMI %s", dev_name(ad->dssdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (!card->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) card->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) card->dai_link =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (!card->dai_link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) compnent = devm_kzalloc(dev, 3 * sizeof(*compnent), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (!compnent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) card->dai_link->cpus = &compnent[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) card->dai_link->num_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) card->dai_link->codecs = &compnent[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) card->dai_link->num_codecs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) card->dai_link->platforms = &compnent[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) card->dai_link->num_platforms = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) card->dai_link->name = card->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) card->dai_link->stream_name = card->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) card->dai_link->cpus->dai_name = dev_name(ad->dssdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) card->dai_link->platforms->name = dev_name(ad->dssdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) card->dai_link->codecs->name = "snd-soc-dummy";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) card->dai_link->codecs->dai_name = "snd-soc-dummy-dai";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) card->num_links = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) card->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) ret = snd_soc_register_card(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) ad->card = card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) snd_soc_card_set_drvdata(card, ad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_set_drvdata(dev, ad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static int omap_hdmi_audio_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) snd_soc_unregister_card(ad->card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static struct platform_driver hdmi_audio_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .probe = omap_hdmi_audio_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .remove = omap_hdmi_audio_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) module_platform_driver(hdmi_audio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) MODULE_ALIAS("platform:" DRV_NAME);