Add machine driver support for BeagleBone-Black HDMI audio. BBB has NXP TDA998X HDMI transmitter connected to McASP port in I2S mode. The 44100 Hz sample-rate and it's multiples can not be accurately produced on BBB. The only supported sample format is SNDRV_PCM_FORMAT_S32_LE. The 8 least significant bits are ignored.
Signed-off-by: Jyri Sarha jsarha@ti.com --- .../bindings/sound/davinci-evm-audio.txt | 6 +- sound/soc/davinci/davinci-evm.c | 82 +++++++++++++++++++- 2 files changed, 84 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt index 963e100..7560146 100644 --- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt @@ -1,7 +1,9 @@ -* Texas Instruments SoC audio setups with TLV320AIC3X Codec +* TI SoC audio using McASP to connect to TLV320AIC3X or HDMI endcoder
Required properties: -- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx +- compatible: should contain one of: + * "ti,da830-evm-audio" for DM365/DA8xx/OMAPL1x/AM33xx with TLV320AIC3X + * "ti,beaglebone-black-audio" for Beaglebone-black HDMI audio - ti,model : The user-visible name of this sound complex. - ti,audio-codec : The phandle of the TLV320AIC3x audio codec - ti,mcasp-controller : The phandle of the McASP controller diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index a50010e..3d0acba2a 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -21,6 +21,7 @@ #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> +#include <sound/pcm_params.h>
#include <asm/dma.h> #include <asm/mach-types.h> @@ -83,12 +84,46 @@ static int evm_hw_params(struct snd_pcm_substream *substream, return 0; }
+/* If changing sample format the tda998x configuration (REG_CTS_N) needs + to be changed. */ +#define TDA998X_SAMPLE_FORMAT SNDRV_PCM_FORMAT_S32_LE +static int evm_tda998x_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_mask *fmt = constrs_mask(&runtime->hw_constraints, + SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(fmt); + snd_mask_set(fmt, TDA998X_SAMPLE_FORMAT); + + return evm_startup(substream); +} + +static int evm_tda998x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *soc_card = rtd->card; + struct snd_soc_card_drvdata_davinci *drvdata = + snd_soc_card_get_drvdata(soc_card); + + return snd_soc_dai_set_sysclk(cpu_dai, 0, drvdata->sysclk, + SND_SOC_CLOCK_IN); +} + static struct snd_soc_ops evm_ops = { .startup = evm_startup, .shutdown = evm_shutdown, .hw_params = evm_hw_params, };
+ +static struct snd_soc_ops evm_tda998x_ops = { + .startup = evm_tda998x_startup, + .shutdown = evm_shutdown, + .hw_params = evm_tda998x_hw_params, +}; + /* davinci-evm machine dapm widgets */ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), @@ -149,6 +184,35 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) return 0; }
+static const struct snd_soc_dapm_widget tda998x_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HDMI Out"), +}; + +static int evm_tda998x_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dapm_context *dapm = &rtd->codec->dapm; + struct snd_soc_card *soc_card = rtd->card; + int ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, 0, 1); + if (ret < 0) + return ret; + + snd_soc_dapm_new_controls(dapm, tda998x_dapm_widgets, + ARRAY_SIZE(tda998x_dapm_widgets)); + + ret = snd_soc_of_parse_audio_routing(soc_card, "ti,audio-routing"); + + /* not connected */ + snd_soc_dapm_disable_pin(dapm, "RX"); + + /* always connected */ + snd_soc_dapm_enable_pin(dapm, "HDMI Out"); + + return 0; +} + /* davinci-evm digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link dm6446_evm_dai = { .name = "TLV320AIC3X", @@ -334,7 +398,7 @@ static struct snd_soc_card da850_snd_soc_card = { #if defined(CONFIG_OF)
/* - * The struct is used as place holder. It will be completely + * The structs are used as place holders. They will be completely * filled with data from dt node. */ static struct snd_soc_dai_link evm_dai_tlv320aic3x = { @@ -347,10 +411,24 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = { SND_SOC_DAIFMT_IB_NF, };
+static struct snd_soc_dai_link evm_dai_tda998x_hdmi = { + .name = "NXP TDA998x HDMI Chip", + .stream_name = "HDMI", + .codec_dai_name = "hdmi-hifi", + .ops = &evm_tda998x_ops, + .init = evm_tda998x_init, + .dai_fmt = (SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_NF), +}; + static const struct of_device_id davinci_evm_dt_ids[] = { { .compatible = "ti,da830-evm-audio", - .data = (void *) &evm_dai_tlv320aic3x, + .data = &evm_dai_tlv320aic3x, + }, + { + .compatible = "ti,beaglebone-black-audio", + .data = &evm_dai_tda998x_hdmi, }, { /* sentinel */ } };