Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support Tegra I2S client format conversion

Merge series from Sameer Pujar <spujar@nvidia.com>:

The AHUB HW modules are interconnected with CIF which are capable of
supporting Channel and Sample bit format conversion. Due to this, the
I2S Client can have different Channel and Sample bit from the hw_params()
and this config is passed from CIF port of I2S DT node which can help to
perform this conversion.

- First change to split simple_fixup_sample_fmt to support returning
sample format value
- Second patch to support Tegra I2S client channel and sample format
programming based on CIF port from DT node.

+91 -10
+2
include/sound/simple_card_utils.h
··· 174 174 struct simple_util_data *data); 175 175 bool simple_util_is_convert_required(const struct simple_util_data *data); 176 176 177 + int simple_util_get_sample_fmt(struct simple_util_data *data); 178 + 177 179 int simple_util_parse_routing(struct snd_soc_card *card, 178 180 char *prefix); 179 181 int simple_util_parse_widgets(struct snd_soc_card *card,
+20 -6
sound/soc/generic/simple-card-utils.c
··· 13 13 #include <sound/pcm_params.h> 14 14 #include <sound/simple_card_utils.h> 15 15 16 - static void simple_fixup_sample_fmt(struct simple_util_data *data, 17 - struct snd_pcm_hw_params *params) 16 + int simple_util_get_sample_fmt(struct simple_util_data *data) 18 17 { 19 18 int i; 20 - struct snd_mask *mask = hw_param_mask(params, 21 - SNDRV_PCM_HW_PARAM_FORMAT); 19 + int val = -EINVAL; 20 + 22 21 struct { 23 22 char *fmt; 24 23 u32 val; ··· 32 33 for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) { 33 34 if (!strcmp(data->convert_sample_format, 34 35 of_sample_fmt_table[i].fmt)) { 35 - snd_mask_none(mask); 36 - snd_mask_set(mask, of_sample_fmt_table[i].val); 36 + val = of_sample_fmt_table[i].val; 37 37 break; 38 38 } 39 + } 40 + return val; 41 + } 42 + EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt); 43 + 44 + static void simple_fixup_sample_fmt(struct simple_util_data *data, 45 + struct snd_pcm_hw_params *params) 46 + { 47 + int val; 48 + struct snd_mask *mask = hw_param_mask(params, 49 + SNDRV_PCM_HW_PARAM_FORMAT); 50 + 51 + val = simple_util_get_sample_fmt(data); 52 + if (val >= 0) { 53 + snd_mask_none(mask); 54 + snd_mask_set(mask, val); 39 55 } 40 56 } 41 57
+67 -4
sound/soc/tegra/tegra210_i2s.c
··· 8 8 #include <linux/device.h> 9 9 #include <linux/mod_devicetable.h> 10 10 #include <linux/module.h> 11 + #include <linux/of_graph.h> 11 12 #include <linux/platform_device.h> 12 13 #include <linux/pm_runtime.h> 13 14 #include <linux/regmap.h> 14 15 #include <sound/core.h> 15 16 #include <sound/pcm_params.h> 17 + #include <sound/simple_card_utils.h> 16 18 #include <sound/soc.h> 17 19 #include "tegra210_i2s.h" 18 20 #include "tegra_cif.h" ··· 605 603 struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); 606 604 unsigned int sample_size, channels, srate, val, reg, path; 607 605 struct tegra_cif_conf cif_conf; 606 + snd_pcm_format_t sample_format; 608 607 609 608 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); 610 609 ··· 618 615 619 616 cif_conf.audio_ch = channels; 620 617 cif_conf.client_ch = channels; 618 + if (i2s->client_channels) 619 + cif_conf.client_ch = i2s->client_channels; 621 620 621 + /* AHUB CIF Audio bits configs */ 622 622 switch (params_format(params)) { 623 + case SNDRV_PCM_FORMAT_S8: 624 + cif_conf.audio_bits = TEGRA_ACIF_BITS_8; 625 + break; 626 + case SNDRV_PCM_FORMAT_S16_LE: 627 + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; 628 + break; 629 + case SNDRV_PCM_FORMAT_S32_LE: 630 + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; 631 + break; 632 + default: 633 + dev_err(dev, "unsupported params audio bit format!\n"); 634 + return -EOPNOTSUPP; 635 + } 636 + 637 + sample_format = params_format(params); 638 + if (i2s->client_sample_format >= 0) 639 + sample_format = (snd_pcm_format_t)i2s->client_sample_format; 640 + 641 + /* 642 + * Format of the I2S for sending/receiving the audio 643 + * to/from external device. 644 + */ 645 + switch (sample_format) { 623 646 case SNDRV_PCM_FORMAT_S8: 624 647 val = I2S_BITS_8; 625 648 sample_size = 8; 626 - cif_conf.audio_bits = TEGRA_ACIF_BITS_8; 627 649 cif_conf.client_bits = TEGRA_ACIF_BITS_8; 628 650 break; 629 651 case SNDRV_PCM_FORMAT_S16_LE: 630 652 val = I2S_BITS_16; 631 653 sample_size = 16; 632 - cif_conf.audio_bits = TEGRA_ACIF_BITS_16; 633 654 cif_conf.client_bits = TEGRA_ACIF_BITS_16; 634 655 break; 635 656 case SNDRV_PCM_FORMAT_S32_LE: 636 657 val = I2S_BITS_32; 637 658 sample_size = 32; 638 - cif_conf.audio_bits = TEGRA_ACIF_BITS_32; 639 659 cif_conf.client_bits = TEGRA_ACIF_BITS_32; 640 660 break; 641 661 default: 642 - dev_err(dev, "unsupported format!\n"); 662 + dev_err(dev, "unsupported client bit format!\n"); 643 663 return -EOPNOTSUPP; 644 664 } 645 665 ··· 898 872 .cache_type = REGCACHE_FLAT, 899 873 }; 900 874 875 + /* 876 + * The AHUB HW modules are interconnected with CIF which are capable of 877 + * supporting Channel and Sample bit format conversion. This needs different 878 + * CIF Audio and client configuration. As one of the config comes from 879 + * params_channels() or params_format(), the extra configuration is passed from 880 + * CIF Port of DT I2S node which can help to perform this conversion. 881 + * 882 + * 4ch audio = 4ch client = 2ch 2ch 883 + * -----> ADMAIF -----------> CIF -------------> I2S ----> 884 + */ 885 + static void tegra210_parse_client_convert(struct device *dev) 886 + { 887 + struct tegra210_i2s *i2s = dev_get_drvdata(dev); 888 + struct device_node *ports, *ep; 889 + struct simple_util_data data = {}; 890 + int cif_port = 0; 891 + 892 + ports = of_get_child_by_name(dev->of_node, "ports"); 893 + if (ports) { 894 + ep = of_graph_get_endpoint_by_regs(ports, cif_port, -1); 895 + if (ep) { 896 + simple_util_parse_convert(ep, NULL, &data); 897 + of_node_put(ep); 898 + } 899 + of_node_put(ports); 900 + } 901 + 902 + if (data.convert_channels) 903 + i2s->client_channels = data.convert_channels; 904 + 905 + if (data.convert_sample_format) 906 + i2s->client_sample_format = simple_util_get_sample_fmt(&data); 907 + } 908 + 901 909 static int tegra210_i2s_probe(struct platform_device *pdev) 902 910 { 903 911 struct device *dev = &pdev->dev; ··· 947 887 i2s->tx_mask = DEFAULT_I2S_SLOT_MASK; 948 888 i2s->rx_mask = DEFAULT_I2S_SLOT_MASK; 949 889 i2s->loopback = false; 890 + i2s->client_sample_format = -EINVAL; 950 891 951 892 dev_set_drvdata(dev, i2s); 952 893 ··· 976 915 dev_err(dev, "regmap init failed\n"); 977 916 return PTR_ERR(i2s->regmap); 978 917 } 918 + 919 + tegra210_parse_client_convert(dev); 979 920 980 921 regcache_cache_only(i2s->regmap, true); 981 922
+2
sound/soc/tegra/tegra210_i2s.h
··· 112 112 struct clk *clk_i2s; 113 113 struct clk *clk_sync_input; 114 114 struct regmap *regmap; 115 + int client_sample_format; 116 + unsigned int client_channels; 115 117 unsigned int stereo_to_mono[I2S_PATHS]; 116 118 unsigned int mono_to_stereo[I2S_PATHS]; 117 119 unsigned int dai_fmt;