From ca8c7f233fa2c40e2a23f982dc33d947f28ad207 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 6 Dec 2016 20:22:37 +0100 Subject: ASoC: atmel: tse850: rely on the ssc to register as a cpu dai by itself This breaks devicetree compatibility, but in this case that is ok. All affected units are either on my desk, or running an even older version of the driver that is not compatible with the upstreamed version anyway (and when these other units are eventually updated, they will get a fresh dtb as well, so that is not a significant problem either). All of that is of course assuming that noone else has managed to build something that can use this driver, but that seems extremely improbable. Signed-off-by: Peter Rosin Acked-by: Rob Herring Signed-off-by: Mark Brown --- sound/soc/atmel/tse850-pcm5142.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index ac6a814c8ecf..a72c7d642026 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -51,11 +51,7 @@ #include #include -#include "atmel_ssc_dai.h" - struct tse850_priv { - int ssc_id; - struct gpio_desc *add; struct gpio_desc *loop1; struct gpio_desc *loop2; @@ -329,23 +325,20 @@ static int tse850_dt_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *codec_np, *cpu_np; - struct snd_soc_card *card = &tse850_card; struct snd_soc_dai_link *dailink = &tse850_dailink; - struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); if (!np) { dev_err(&pdev->dev, "only device tree supported\n"); return -EINVAL; } - cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0); + cpu_np = of_parse_phandle(np, "axentia,cpu-dai", 0); if (!cpu_np) { - dev_err(&pdev->dev, "failed to get dai and pcm info\n"); + dev_err(&pdev->dev, "failed to get cpu dai\n"); return -EINVAL; } dailink->cpu_of_node = cpu_np; dailink->platform_of_node = cpu_np; - tse850->ssc_id = of_alias_get_id(cpu_np, "ssc"); of_node_put(cpu_np); codec_np = of_parse_phandle(np, "axentia,audio-codec", 0); @@ -415,23 +408,14 @@ static int tse850_probe(struct platform_device *pdev) return ret; } - ret = atmel_ssc_set_audio(tse850->ssc_id); - if (ret != 0) { - dev_err(dev, - "failed to set SSC %d for audio\n", tse850->ssc_id); - goto err_disable_ana; - } - ret = snd_soc_register_card(card); if (ret) { dev_err(dev, "snd_soc_register_card failed\n"); - goto err_put_audio; + goto err_disable_ana; } return 0; -err_put_audio: - atmel_ssc_put_audio(tse850->ssc_id); err_disable_ana: regulator_disable(tse850->ana); return ret; @@ -443,7 +427,6 @@ static int tse850_remove(struct platform_device *pdev) struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); snd_soc_unregister_card(card); - atmel_ssc_put_audio(tse850->ssc_id); regulator_disable(tse850->ana); return 0; -- cgit v1.2.3 From ac29a8f41740186aee601de99c729530e37ca77c Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Fri, 16 Dec 2016 11:05:02 +0000 Subject: ASoC: da7218: Set DAI output pin high impedance when not in use For TDM mode, the I2S data out line can be shared between mutliple codecs. In this scenario, only the active codec should be using the line, and all others should be high impedance. However, currently in the driver this configuration isn't set when capture is inactive, and the line remains driven. This patch updates the AIF_OUT widget to set the DAI output pin of the device as high impedance when not in use. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index c69e97654fc6..d256ebf9e309 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1634,7 +1634,8 @@ static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = { SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* DAI */ - SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7218_DAI_TDM_CTRL, + DA7218_DAI_OE_SHIFT, DA7218_NO_INVERT), SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), /* Output Mixers */ -- cgit v1.2.3 From 25f7b701c20db3e9ae09e28dd652949bd977e5cd Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Jan 2017 16:52:51 +0100 Subject: ASoC: core: add optional pcm_new callback for DAI driver During probe, DAIs can need to perform some actions that requests the knowledge of the pcm runtime handle. The callback is called during DAIs linking, after PCM device creation. For instance this can be used to add relationship between a DAI pcm control and the pcm device. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f1901bb1466e..32b8c42be796 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1593,6 +1593,27 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) return 0; } +static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, + struct snd_soc_pcm_runtime *rtd) +{ + int i, ret = 0; + + for (i = 0; i < num_dais; ++i) { + struct snd_soc_dai_driver *drv = dais[i]->driver; + + if (!rtd->dai_link->no_pcm && drv->pcm_new) + ret = drv->pcm_new(rtd, dais[i]); + if (ret < 0) { + dev_err(dais[i]->dev, + "ASoC: Failed to bind %s with pcm device\n", + dais[i]->name); + return ret; + } + } + + return 0; +} + static int soc_link_dai_widgets(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link, struct snd_soc_pcm_runtime *rtd) @@ -1704,6 +1725,13 @@ static int soc_probe_link_dais(struct snd_soc_card *card, dai_link->stream_name, ret); return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; } else { INIT_DELAYED_WORK(&rtd->delayed_work, codec2codec_close_delayed_work); -- cgit v1.2.3 From cd6111b26280a2f38a9fb8e6630c63a96477e4bf Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 3 Jan 2017 16:52:52 +0100 Subject: ASoC: hdmi-codec: add channel mapping control Add user interface to provide channel mapping. In a first step this control is read only. As TLV type, the control provides all configuration available for HDMI sink(ELD), and provides current channel mapping selected by codec based on ELD and number of channels specified by user on open. When control is called before the number of the channel is specified (i.e. hw_params is set), it returns all channels set to UNKNOWN. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 380 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 379 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 90b5948e0ff3..dc6715a804a1 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,258 @@ struct hdmi_device { LIST_HEAD(hdmi_device_list); #define DAI_NAME_SIZE 16 + +#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 + +struct hdmi_codec_channel_map_table { + unsigned char map; /* ALSA API channel map position */ + unsigned long spk_mask; /* speaker position bit mask */ +}; + +/* + * CEA speaker placement for HDMI 1.4: + * + * FL FLC FC FRC FR FRW + * + * LFE + * + * RL RLC RC RRC RR + * + * Speaker placement has to be extended to support HDMI 2.0 + */ +enum hdmi_codec_cea_spk_placement { + FL = BIT(0), /* Front Left */ + FC = BIT(1), /* Front Center */ + FR = BIT(2), /* Front Right */ + FLC = BIT(3), /* Front Left Center */ + FRC = BIT(4), /* Front Right Center */ + RL = BIT(5), /* Rear Left */ + RC = BIT(6), /* Rear Center */ + RR = BIT(7), /* Rear Right */ + RLC = BIT(8), /* Rear Left Center */ + RRC = BIT(9), /* Rear Right Center */ + LFE = BIT(10), /* Low Frequency Effect */ +}; + +/* + * cea Speaker allocation structure + */ +struct hdmi_codec_cea_spk_alloc { + const int ca_id; + unsigned int n_ch; + unsigned long mask; +}; + +/* Channel maps stereo HDMI */ +const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { } +}; + +/* Channel maps for multi-channel playbacks, up to 8 n_ch */ +const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { + { .channels = 2, /* CA_ID 0x00 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, /* CA_ID 0x01 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA } }, + { .channels = 4, /* CA_ID 0x02 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC } }, + { .channels = 4, /* CA_ID 0x03 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC } }, + { .channels = 6, /* CA_ID 0x04 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x05 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x06 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x07 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x08 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x09 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 8, /* CA_ID 0x0C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x10 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x11 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x12 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x13 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x14 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x15 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x16 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x17 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x18 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x19 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { } +}; + +/* + * hdmi_codec_channel_alloc: speaker configuration available for CEA + * + * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct + * The preceding ones have better chances to be selected by + * hdmi_codec_get_ch_alloc_table_idx(). + */ +static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + { .ca_id = 0x00, .n_ch = 2, + .mask = FL | FR}, + /* 2.1 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE}, + /* Dolby Surround */ + { .ca_id = 0x02, .n_ch = 4, + .mask = FL | FR | FC }, + /* surround51 */ + { .ca_id = 0x0b, .n_ch = 6, + .mask = FL | FR | LFE | FC | RL | RR}, + /* surround40 */ + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + /* surround41 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + /* surround50 */ + { .ca_id = 0x0a, .n_ch = 6, + .mask = FL | FR | FC | RL | RR }, + /* 6.1 */ + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + /* surround71 */ + { .ca_id = 0x13, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, + /* others */ + { .ca_id = 0x03, .n_ch = 8, + .mask = FL | FR | LFE | FC }, + { .ca_id = 0x04, .n_ch = 8, + .mask = FL | FR | RC}, + { .ca_id = 0x05, .n_ch = 8, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x06, .n_ch = 8, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x07, .n_ch = 8, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x12, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RLC | RRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x1e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, +}; + struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; struct snd_soc_dai_driver *daidrv; @@ -41,6 +294,8 @@ struct hdmi_codec_priv { struct snd_pcm_substream *current_stream; struct snd_pcm_hw_constraint_list ratec; uint8_t eld[MAX_ELD_BYTES]; + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -79,6 +334,83 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc) +{ + int i; + const unsigned long hdmi_codec_eld_spk_alloc_bits[] = { + [0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR, + [4] = RC, [5] = FLC | FRC, [6] = RLC | RRC, + }; + unsigned long spk_mask = 0; + + for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) { + if (spk_alloc & (1 << i)) + spk_mask |= hdmi_codec_eld_spk_alloc_bits[i]; + } + + return spk_mask; +} + +void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp) +{ + u8 spk_alloc; + unsigned long spk_mask; + + spk_alloc = drm_eld_get_spk_alloc(hcp->eld); + spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc); + + /* Detect if only stereo supported, else return 8 channels mappings */ + if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2) + hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps; + else + hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; +} + +static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp, + unsigned char channels) +{ + int i; + u8 spk_alloc; + unsigned long spk_mask; + const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc; + + spk_alloc = drm_eld_get_spk_alloc(hcp->eld); + spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc); + + for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) { + /* If spk_alloc == 0, HDMI is unplugged return stereo config*/ + if (!spk_alloc && cap->ca_id == 0) + return i; + if (cap->n_ch != channels) + continue; + if (!(cap->mask == (spk_mask & cap->mask))) + continue; + return i; + } + + return -EINVAL; +} +static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned const char *map; + unsigned int i; + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = info->private_data; + + map = info->chmap[hcp->chmap_idx].map; + + for (i = 0; i < info->max_channels; i++) { + if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) + ucontrol->value.integer.value[i] = 0; + else + ucontrol->value.integer.value[i] = map[i]; + } + + return 0; +} + + static const struct snd_kcontrol_new hdmi_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ | @@ -140,6 +472,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (ret) return ret; } + /* Select chmap supported */ + hdmi_codec_eld_chmap(hcp); } return 0; } @@ -153,6 +487,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, WARN_ON(hcp->current_stream != substream); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); mutex_lock(&hcp->current_stream_lock); @@ -173,7 +508,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, .dig_subframe = { 0 }, } }; - int ret; + int ret, idx; dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, params_width(params), params_rate(params), @@ -200,6 +535,17 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + /* Select a channel allocation that matches with ELD and pcm channels */ + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); + if (idx < 0) { + dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", + idx); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + return idx; + } + hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; + hp.sample_width = params_width(params); hp.sample_rate = params_rate(params); hp.channels = params_channels(params); @@ -328,6 +674,32 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) +static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + struct snd_soc_dai_driver *drv = dai->driver; + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int ret; + + dev_dbg(dai->dev, "%s()\n", __func__); + + ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, drv->playback.channels_max, 0, + &hcp->chmap_info); + if (ret < 0) + return ret; + + /* override handlers */ + hcp->chmap_info->private_data = hcp; + hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get; + + /* default chmap supported is stereo */ + hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + + return 0; +} + static struct snd_soc_dai_driver hdmi_i2s_dai = { .id = DAI_ID_I2S, .playback = { @@ -339,6 +711,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_dai_ops, + .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { @@ -351,6 +724,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_dai_ops, + .pcm_new = hdmi_codec_pcm_new, }; static char hdmi_dai_name[][DAI_NAME_SIZE] = { @@ -479,6 +853,10 @@ static int hdmi_codec_probe(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev) { + struct hdmi_codec_priv *hcp; + + hcp = dev_get_drvdata(&pdev->dev); + kfree(hcp->chmap_info); snd_soc_unregister_codec(&pdev->dev); return 0; } -- cgit v1.2.3 From 31489c0b1d8b33e5b696ba18feb880617e937554 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 25 Jan 2017 00:51:04 +0000 Subject: ASoC: cq93vc: remove MFD_DAVINCI_VOICECODEC dependency from CQ0093VC CQ0093VC is no longer dependent on MFD_DAVINCI_VOICECODEC, let's remove it. Otherwise, we can't compile it by COMPILE_TEST on non-DAVINCE platform Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9e1718a8cb1c..928baa69de91 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -45,7 +45,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_BT_SCO - select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC + select SND_SOC_CQ0093VC select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C -- cgit v1.2.3 From 8480ac567959eecdc694cf4f9c02d6fa687384b6 Mon Sep 17 00:00:00 2001 From: Vincent Abriou Date: Wed, 8 Feb 2017 10:47:01 +0100 Subject: ASoC: hdmi-codec: remove HDMI device unregister While unregistering the hdmi-codec, the hdmi device list must be cleaned up. It avoid kernel page fault when registering again the hdmi-codec. Signed-off-by: Vincent Abriou Reviewed-by: Philipp Zabel Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index dc6715a804a1..8c5ae1fc23a9 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -32,6 +32,7 @@ struct hdmi_device { }; #define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list) LIST_HEAD(hdmi_device_list); +static DEFINE_MUTEX(hdmi_mutex); #define DAI_NAME_SIZE 16 @@ -794,6 +795,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) return -ENOMEM; hd = NULL; + mutex_lock(&hdmi_mutex); list_for_each(pos, &hdmi_device_list) { struct hdmi_device *tmp = pos_to_hdmi_device(pos); @@ -805,13 +807,16 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (!hd) { hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL); - if (!hd) + if (!hd) { + mutex_unlock(&hdmi_mutex); return -ENOMEM; + } hd->dev = dev->parent; list_add_tail(&hd->list, &hdmi_device_list); } + mutex_unlock(&hdmi_mutex); if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) { dev_err(dev, "too many hdmi codec are deteced\n"); @@ -853,11 +858,25 @@ static int hdmi_codec_probe(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct list_head *pos; struct hdmi_codec_priv *hcp; - hcp = dev_get_drvdata(&pdev->dev); + mutex_lock(&hdmi_mutex); + list_for_each(pos, &hdmi_device_list) { + struct hdmi_device *tmp = pos_to_hdmi_device(pos); + + if (tmp->dev == dev->parent) { + list_del(pos); + break; + } + } + mutex_unlock(&hdmi_mutex); + + hcp = dev_get_drvdata(dev); kfree(hcp->chmap_info); - snd_soc_unregister_codec(&pdev->dev); + snd_soc_unregister_codec(dev); + return 0; } -- cgit v1.2.3