[alsa-devel] [PATCH v4 0/2] ASoC: tda998x: add a codec to the HDMI transmitter
The NXP TDA998x HDMI transmitter may transmit audio to the HDMI link from 2 different sources, I2S and S/PDIF.
This patch set adds a generic HDMI CODEC module which is used by the TDA998x driver to update the audio constraints from the display characteristics (EDID) and by the audio subsystem to connect the chosen audio source to the HDMI link.
v4: - remove all the TDA998x specific stuff from the CODEC - move the EDID scan from the CODEC to the TDA998x - move the CODEC to sound/soc (Mark Brown) - update the audio_sample_rate from the EDID (Andrew Jackson) v3: fix bad rate (Andrew Jackson) v2: check double stream start (Mark Brown)
Jean-Francois Moine (2): ASoC:codecs: Add a generic HDMI audio CODEC drm/i2c:tda998x: Use the HDMI2 audio CODEC
Documentation/devicetree/bindings/sound/hdmi2.txt | 32 ++++ drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 142 ++++++++++++++- include/sound/hdmi2.h | 24 +++ sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi2.c | 204 ++++++++++++++++++++++ 7 files changed, 400 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/hdmi2.txt create mode 100644 include/sound/hdmi2.h create mode 100644 sound/soc/codecs/hdmi2.c
This patch adds a generic audio CODEC function to HDMI transmitters.
The CODEC is implemented as a library in a kernel module.
It handles both I2S and S/PDIF input, maintaining the audio format and rates constraints according to the HDMI device parameters (EDID).
Audio source input switch is offered to the HDMI driver on start/stop of audio streaming.
Signed-off-by: Jean-Francois Moine moinejf@free.fr --- Documentation/devicetree/bindings/sound/hdmi2.txt | 32 ++++ include/sound/hdmi2.h | 24 +++ sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi2.c | 204 ++++++++++++++++++++++ 5 files changed, 265 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/hdmi2.txt create mode 100644 include/sound/hdmi2.h create mode 100644 sound/soc/codecs/hdmi2.c
diff --git a/Documentation/devicetree/bindings/sound/hdmi2.txt b/Documentation/devicetree/bindings/sound/hdmi2.txt new file mode 100644 index 0000000..5776370 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/hdmi2.txt @@ -0,0 +1,32 @@ +Device-Tree bindings for the generic HDMI2 CODEC + +The HDMI2 CODEC describes how the audio controller is connected to the +HDMI transmitter. +These definitions are included in the HDMI transmiter description. + +Required properties: + + - audio-ports: must contain one or two HDMI transmitter dependant + values identifying the audio sources. + The source type is given by the corresponding entry in + the audio-port-names property. + + - audio-port-names: must contain entries matching the entries in + the audio-ports property. + Each value may be "i2s" or "spdif", giving the type of + the associated audio port. + + - #sound-dai-cells: must be set to <1> for use with the simple-card. + The DAI 0 is the I2S input and the DAI 1 is the S/PDIF input. + +Example: + + hdmi: hdmi-encoder { + compatible = "nxp,tda998x"; + reg = <0x70>; + ... + + audio-ports = <0x03>, <0x04>; + audio-port-names = "i2s", "spdif"; + #sound-dai-cells = <1>; + }; diff --git a/include/sound/hdmi2.h b/include/sound/hdmi2.h new file mode 100644 index 0000000..59e4148 --- /dev/null +++ b/include/sound/hdmi2.h @@ -0,0 +1,24 @@ +#ifndef SND_HDMI2_H +#define SND_HDMI2_H +/* hdmi2 codec data */ +struct hdmi2_codec { + u8 ports[2]; + u16 source; /* audio DAI = index to ports[] */ +#define HDMI2_I2S 0 +#define HDMI2_SPDIF 1 + + unsigned sample_rate; /* current streaming values */ + int sample_format; + + u64 formats; /* HDMI (EDID) values */ + unsigned max_channels; + struct snd_pcm_hw_constraint_list rate_constraints; + + void (*start)(struct hdmi2_codec *audio, int full); + void (*stop)(struct hdmi2_codec *audio); +}; + +/* hdmi device -> hdmi2 codec */ +int hdmi2_codec_register(struct device *dev); +void hdmi2_codec_unregister(struct device *dev); +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8ab1547..1b8d81e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -424,6 +424,9 @@ config SND_SOC_ES8328_SPI tristate select SND_SOC_ES8328
+config SND_SOC_HDMI2 + tristate + config SND_SOC_ISABELLE tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index afba944..f59b1e6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -53,6 +53,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-hdmi2-objs := hdmi2.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -228,6 +229,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_HDMI2) += snd-soc-hdmi2.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/hdmi2.c b/sound/soc/codecs/hdmi2.c new file mode 100644 index 0000000..8ba8ba6 --- /dev/null +++ b/sound/soc/codecs/hdmi2.c @@ -0,0 +1,204 @@ +/* + * ALSA SoC generic HDMI CODEC + * + * Copyright (C) 2014 Jean-Francois Moine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/of.h> +#include <linux/i2c.h> +#include <sound/hdmi2.h> + +#define HDMI2_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static int hdmi2_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdmi2_codec *audio = snd_soc_codec_get_drvdata(dai->codec); + struct snd_pcm_runtime *runtime = substream->runtime; + + /* set the constraints */ + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &audio->rate_constraints); + snd_pcm_hw_constraint_mask64(runtime, + SNDRV_PCM_HW_PARAM_FORMAT, + audio->formats); + + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 1, audio->max_channels); + return 0; +} + +static int hdmi2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdmi2_codec *audio = snd_soc_codec_get_drvdata(dai->codec); + + /* if same input and same parameters, do not do a full switch */ + if (dai->id == audio->source && + params_format(params) == audio->sample_format && + params_rate(params) == audio->sample_rate) { + audio->start(audio, 0); + return 0; + } + + audio->source = dai->id; + audio->sample_format = params_format(params); + audio->sample_rate = params_rate(params); + audio->start(audio, 1); + return 0; +} + +static void hdmi2_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdmi2_codec *audio = snd_soc_codec_get_drvdata(dai->codec); + + audio->stop(audio); +} + +static const struct snd_soc_dai_ops hdmi2_ops = { + .startup = hdmi2_startup, + .hw_params = hdmi2_hw_params, + .shutdown = hdmi2_shutdown, +}; + +static struct snd_soc_dai_driver hdmi2_dai[] = { + { + .name = "i2s-hifi", + .id = HDMI2_I2S, + .playback = { + .stream_name = "HDMI I2S Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 192000, + .formats = HDMI2_FORMATS, + }, + .ops = &hdmi2_ops, + }, + { + .name = "spdif-hifi", + .id = HDMI2_SPDIF, + .playback = { + .stream_name = "HDMI SPDIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 22050, + .rate_max = 192000, + .formats = HDMI2_FORMATS, + }, + .ops = &hdmi2_ops, + }, +}; + +static const struct snd_soc_dapm_widget hdmi2_widgets[] = { + SND_SOC_DAPM_OUTPUT("hdmi-out"), +}; +static const struct snd_soc_dapm_route hdmi2_routes[] = { + { "hdmi-out", NULL, "HDMI I2S Playback" }, + { "hdmi-out", NULL, "HDMI SPDIF Playback" }, +}; + +/* + * The HDMI driver must set the i2c client data to the hdmi2_codec + */ +static int hdmi2_probe(struct snd_soc_codec *codec) +{ + struct i2c_client *i2c_client = to_i2c_client(codec->dev); + struct hdmi2_codec *audio = i2c_get_clientdata(i2c_client); + struct device_node *np = codec->dev->of_node; + int i, j, ret; + const char *p; + + if (!audio) + return -ENODEV; + snd_soc_codec_set_drvdata(codec, audio); + + if (!np) + return 0; + + /* get the audio input ports*/ + for (i = 0; i < 2; i++) { + u32 port; + + ret = of_property_read_u32_index(np, "audio-ports", i, &port); + if (ret) { + if (i == 0) + dev_err(codec->dev, + "bad or missing audio-ports\n"); + break; + } + ret = of_property_read_string_index(np, "audio-port-names", + i, &p); + if (ret) { + dev_err(codec->dev, + "missing audio-port-names[%d]\n", i); + break; + } + if (strcmp(p, "i2s") == 0) { + j = 0; + } else if (strcmp(p, "spdif") == 0) { + j = 1; + } else { + dev_err(codec->dev, + "bad audio-port-names '%s'\n", p); + break; + } + audio->ports[j] = port; + } + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_hdmi2 = { + .probe = hdmi2_probe, + .dapm_widgets = hdmi2_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdmi2_widgets), + .dapm_routes = hdmi2_routes, + .num_dapm_routes = ARRAY_SIZE(hdmi2_routes), +}; + +int hdmi2_codec_register(struct device *dev) +{ + return snd_soc_register_codec(dev, + &soc_codec_hdmi2, + hdmi2_dai, ARRAY_SIZE(hdmi2_dai)); +} +EXPORT_SYMBOL(hdmi2_codec_register); + +void hdmi2_codec_unregister(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} +EXPORT_SYMBOL(hdmi2_codec_unregister); + +/* -- module insert / remove -- */ +MODULE_AUTHOR("Jean-Francois Moine moinejf@free.fr"); +MODULE_DESCRIPTION("HDMI2 CODEC"); +MODULE_LICENSE("GPL"); + +static int __init hdmi2_codec_init(void) +{ + return 0; +} +static void __exit hdmi2_codec_exit(void) +{ +} + +module_init(hdmi2_codec_init); +module_exit(hdmi2_codec_exit);
On Sun, Aug 31, 2014 at 12:45:39PM +0200, Jean-Francois Moine wrote:
Documentation/devicetree/bindings/sound/hdmi2.txt | 32 ++++ include/sound/hdmi2.h | 24 +++ sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi2.c | 204 ++++++++++++++++++++++ 5 files changed, 265 insertions(+)
This is clearly not a good name and it's not clear what the difference between this and the existing HDMI stub CODEC is intended to be.
+Required properties:
- audio-ports: must contain one or two HDMI transmitter dependant
- values identifying the audio sources.
- The source type is given by the corresponding entry in
- the audio-port-names property.
- audio-port-names: must contain entries matching the entries in
- the audio-ports property.
- Each value may be "i2s" or "spdif", giving the type of
- the associated audio port.
It seems hard to see this binding as really generic - I'd expect to see other devices which are just able to have fixed audio ports for example.
+static int hdmi2_probe(struct snd_soc_codec *codec) +{
- struct i2c_client *i2c_client = to_i2c_client(codec->dev);
- struct hdmi2_codec *audio = i2c_get_clientdata(i2c_client);
- struct device_node *np = codec->dev->of_node;
- int i, j, ret;
- const char *p;
- if (!audio)
return -ENODEV;
- snd_soc_codec_set_drvdata(codec, audio);
The code also seems pretty device specific. I think it's probably better to leave the binding device specific for now and concentrate on sharing inside the kernel, making any generic binding additions be about how the devices interface rather than what's going on inside a specific device.
This patch adds an audio CODEC function to the NXP TDA998x transmitter.
Signed-off-by: Jean-Francois Moine moinejf@free.fr --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 142 +++++++++++++++++++++++++++++++++++--- 2 files changed, 135 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 4d341db..fa79cd3 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -22,6 +22,7 @@ config DRM_I2C_SIL164 config DRM_I2C_NXP_TDA998X tristate "NXP Semiconductors TDA998X HDMI encoder" default m if DRM_TILCDC + select SND_SOC_HDMI2 help Support for NXP Semiconductors TDA998X HDMI encoders.
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index d476279..5f86b4d 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,6 +27,9 @@ #include <drm/drm_edid.h> #include <drm/i2c/tda998x.h>
+#include <sound/pcm_params.h> +#include <sound/hdmi2.h> + #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
struct tda998x_priv { @@ -44,9 +47,13 @@ struct tda998x_priv { wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; + + struct hdmi2_codec audio; };
#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) +#define audio_priv(x) \ + container_of(audio, struct tda998x_priv, audio)
/* The TDA9988 series of devices use a paged register scheme.. to simplify * things we encode the page # in upper bits of the register #. To read/ @@ -639,27 +646,42 @@ static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { - uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; + uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv, aclk; uint32_t n;
/* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); - reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg);
/* Set audio input source */ - switch (p->audio_format) { - case AFMT_SPDIF: + switch (priv->audio.source) { + case HDMI2_SPDIF: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); clksel_aip = AIP_CLKSEL_AIP_SPDIF; clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; cts_n = CTS_N_M(3) | CTS_N_K(3); + aclk = 0; /* no clock */ break;
- case AFMT_I2S: + case HDMI2_I2S: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; cts_n = CTS_N_M(3) | CTS_N_K(3); + /* with I2S input, the CTS_N predivider depends on + * the sample width */ + switch (priv->audio.sample_format) { + case SNDRV_PCM_FORMAT_S16_LE: + cts_n = CTS_N_M(3) | CTS_N_K(1); + break; + case SNDRV_PCM_FORMAT_S24_LE: + cts_n = CTS_N_M(3) | CTS_N_K(2); + break; + default: + case SNDRV_PCM_FORMAT_S32_LE: + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + } + aclk = 1; /* clock enable */ break;
default: @@ -671,6 +693,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | AIP_CNTRL_0_ACR_MAN); /* auto CTS */ reg_write(priv, REG_CTS_N, cts_n); + reg_write(priv, REG_ENA_ACLK, aclk);
/* * Audio input somehow depends on HDMI line rate which is @@ -684,7 +707,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, adiv++; /* AUDIO_DIV_SERCLK_16 */
/* S/PDIF asks for a larger divider */ - if (p->audio_format == AFMT_SPDIF) + if (priv->audio.source == HDMI2_SPDIF) adiv++; /* AUDIO_DIV_SERCLK_16 or _32 */
reg_write(priv, REG_AUDIO_DIV, adiv); @@ -693,7 +716,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, * This is the approximate value of N, which happens to be * the recommended values for non-coherent clocks. */ - n = 128 * p->audio_sample_rate / 1000; + n = 128 * priv->audio.sample_rate / 1000;
/* Write the CTS and N values */ buf[0] = 0x44; @@ -727,6 +750,30 @@ tda998x_configure_audio(struct tda998x_priv *priv, tda998x_write_aif(priv, p); }
+/* hdmi2 codec interface */ +void tda998x_audio_start(struct hdmi2_codec *audio, + int full) +{ + struct tda998x_priv *priv = audio_priv(audio); + struct tda998x_encoder_params *p = &priv->params; + + if (!priv->encoder->crtc) + return; + p->audio_cfg = audio->ports[audio->source]; + if (!full) { + reg_write(priv, REG_ENA_AP, p->audio_cfg); + return; + } + tda998x_configure_audio(priv, &priv->encoder->crtc->hwmode, p); +} + +void tda998x_audio_stop(struct hdmi2_codec *audio) +{ + struct tda998x_priv *priv = audio_priv(audio); + + reg_write(priv, REG_ENA_AP, 0); +} + /* DRM encoder functions */
static void tda998x_encoder_set_config(struct tda998x_priv *priv, @@ -746,6 +793,9 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
priv->params = *p; + priv->audio.source = p->audio_format == AFMT_I2S ? + HDMI2_I2S : HDMI2_SPDIF; + priv->audio.sample_rate = p->audio_sample_rate; }
static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode) @@ -1128,6 +1178,64 @@ fail: return NULL; }
+static void tda998x_set_audio(struct hdmi2_codec *audio, + struct drm_connector *connector) +{ + u8 *eld = connector->eld; + u8 *sad; + int sad_count; + unsigned eld_ver, mnl, rate_mask; + unsigned max_channels, fmt; + u64 formats; + struct snd_pcm_hw_constraint_list *rate_constraints = + &audio->rate_constraints; + static const u32 hdmi_rates[] = { + 32000, 44100, 48000, 88200, 96000, 176400, 192000 + }; + + /* adjust the hw params from the ELD (EDID) */ + eld_ver = eld[0] >> 3; + if (eld_ver != 2 && eld_ver != 31) + return; + + mnl = eld[4] & 0x1f; + if (mnl > 16) + return; + + sad_count = eld[5] >> 4; + sad = eld + 20 + mnl; + + /* Start from the basic audio settings */ + max_channels = 2; + rate_mask = 0; + fmt = 0; + while (sad_count--) { + switch (sad[0] & 0x78) { + case 0x08: /* PCM */ + max_channels = max(max_channels, (sad[0] & 7) + 1u); + rate_mask |= sad[1]; + fmt |= sad[2] & 0x07; + break; + } + sad += 3; + } + + /* set the constraints */ + rate_constraints->list = hdmi_rates; + rate_constraints->count = ARRAY_SIZE(hdmi_rates); + rate_constraints->mask = rate_mask; + + formats = 0; + if (fmt & 1) + formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (fmt & 2) + formats |= SNDRV_PCM_FMTBIT_S20_3LE; + if (fmt & 4) + formats |= SNDRV_PCM_FMTBIT_S24_LE; + audio->formats = formats; + audio->max_channels = max_channels; +} + static int tda998x_encoder_get_modes(struct tda998x_priv *priv, struct drm_connector *connector) @@ -1139,6 +1247,13 @@ tda998x_encoder_get_modes(struct tda998x_priv *priv, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); + + /* set the audio parameters from the EDID */ + if (priv->is_hdmi_sink) { + drm_edid_to_eld(connector, edid); + tda998x_set_audio(&priv->audio, connector); + } + kfree(edid); }
@@ -1167,12 +1282,14 @@ tda998x_encoder_set_property(struct drm_encoder *encoder,
static void tda998x_destroy(struct tda998x_priv *priv) { + struct i2c_client *client = priv->hdmi; + /* disable all IRQs and free the IRQ handler */ cec_write(priv, REG_CEC_RXSHPDINTENA, 0); reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); if (priv->hdmi->irq) free_irq(priv->hdmi->irq, priv); - + hdmi2_codec_unregister(&client->dev); i2c_unregister_device(priv->cec); }
@@ -1260,6 +1377,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
+ priv->params.audio_frame[1] = 1; /* channels - 1 */ + priv->audio.sample_rate = 48000; /* 48kHz */ + priv->current_page = 0xff; priv->hdmi = client; priv->cec = i2c_new_dummy(client->adapter, 0x34); @@ -1351,6 +1471,12 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) /* enable EDID read irq: */ reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+ /* register the HDMI2 audio CODEC */ + priv->audio.start = tda998x_audio_start; + priv->audio.stop = tda998x_audio_stop; + i2c_set_clientdata(client, &priv->audio); + hdmi2_codec_register(&client->dev); + if (!np) return 0; /* non-DT */
participants (2)
-
Jean-Francois Moine
-
Mark Brown