diff options
Diffstat (limited to 'sound/soc/tegra/tegra210_adx.c')
-rw-r--r-- | sound/soc/tegra/tegra210_adx.c | 229 |
1 files changed, 218 insertions, 11 deletions
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index b6c798baedea..ad7cd8655047 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -9,6 +9,7 @@ #include <linux/io.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -32,21 +33,37 @@ static const struct reg_default tegra210_adx_reg_defaults[] = { { TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000}, }; +static const struct reg_default tegra264_adx_reg_defaults[] = { + { TEGRA210_ADX_RX_INT_MASK, 0x00000001}, + { TEGRA210_ADX_RX_CIF_CTRL, 0x00003800}, + { TEGRA210_ADX_TX_INT_MASK, 0x0000000f }, + { TEGRA210_ADX_TX1_CIF_CTRL, 0x00003800}, + { TEGRA210_ADX_TX2_CIF_CTRL, 0x00003800}, + { TEGRA210_ADX_TX3_CIF_CTRL, 0x00003800}, + { TEGRA210_ADX_TX4_CIF_CTRL, 0x00003800}, + { TEGRA210_ADX_CG, 0x1}, + { TEGRA264_ADX_CFG_RAM_CTRL, 0x00004000}, +}; + static void tegra210_adx_write_map_ram(struct tegra210_adx *adx) { int i; - regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL, + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL + + adx->soc_data->cya_offset, TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN | TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN | TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE); - for (i = 0; i < TEGRA210_ADX_RAM_DEPTH; i++) - regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA, + for (i = 0; i < adx->soc_data->ram_depth; i++) + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA + + adx->soc_data->cya_offset, adx->map[i]); - regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN0, adx->byte_mask[0]); - regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN1, adx->byte_mask[1]); + for (i = 0; i < adx->soc_data->byte_mask_size; i++) + regmap_write(adx->regmap, + TEGRA210_ADX_IN_BYTE_EN0 + (i * TEGRA210_ADX_AUDIOCIF_CH_STRIDE), + adx->byte_mask[i]); } static int tegra210_adx_startup(struct snd_pcm_substream *substream, @@ -117,7 +134,7 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); - if (channels < 1 || channels > 16) + if (channels < 1 || channels > adx->soc_data->max_ch) return -EINVAL; switch (format) { @@ -140,7 +157,10 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, cif_conf.audio_bits = audio_bits; cif_conf.client_bits = audio_bits; - tegra_set_cif(adx->regmap, reg, &cif_conf); + if (adx->soc_data->max_ch == 32) + tegra264_set_cif(adx->regmap, reg, &cif_conf); + else + tegra_set_cif(adx->regmap, reg, &cif_conf); return 0; } @@ -169,7 +189,7 @@ static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol, struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc; - unsigned char *bytes_map = (unsigned char *)&adx->map; + unsigned char *bytes_map = (unsigned char *)adx->map; int enabled; mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -198,7 +218,7 @@ static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol, { struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); - unsigned char *bytes_map = (unsigned char *)&adx->map; + unsigned char *bytes_map = (unsigned char *)adx->map; int value = ucontrol->value.integer.value[0]; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -402,7 +422,90 @@ static struct snd_kcontrol_new tegra210_adx_controls[] = { TEGRA210_ADX_BYTE_MAP_CTRL(63), }; +static struct snd_kcontrol_new tegra264_adx_controls[] = { + TEGRA210_ADX_BYTE_MAP_CTRL(64), + TEGRA210_ADX_BYTE_MAP_CTRL(65), + TEGRA210_ADX_BYTE_MAP_CTRL(66), + TEGRA210_ADX_BYTE_MAP_CTRL(67), + TEGRA210_ADX_BYTE_MAP_CTRL(68), + TEGRA210_ADX_BYTE_MAP_CTRL(69), + TEGRA210_ADX_BYTE_MAP_CTRL(70), + TEGRA210_ADX_BYTE_MAP_CTRL(71), + TEGRA210_ADX_BYTE_MAP_CTRL(72), + TEGRA210_ADX_BYTE_MAP_CTRL(73), + TEGRA210_ADX_BYTE_MAP_CTRL(74), + TEGRA210_ADX_BYTE_MAP_CTRL(75), + TEGRA210_ADX_BYTE_MAP_CTRL(76), + TEGRA210_ADX_BYTE_MAP_CTRL(77), + TEGRA210_ADX_BYTE_MAP_CTRL(78), + TEGRA210_ADX_BYTE_MAP_CTRL(79), + TEGRA210_ADX_BYTE_MAP_CTRL(80), + TEGRA210_ADX_BYTE_MAP_CTRL(81), + TEGRA210_ADX_BYTE_MAP_CTRL(82), + TEGRA210_ADX_BYTE_MAP_CTRL(83), + TEGRA210_ADX_BYTE_MAP_CTRL(84), + TEGRA210_ADX_BYTE_MAP_CTRL(85), + TEGRA210_ADX_BYTE_MAP_CTRL(86), + TEGRA210_ADX_BYTE_MAP_CTRL(87), + TEGRA210_ADX_BYTE_MAP_CTRL(88), + TEGRA210_ADX_BYTE_MAP_CTRL(89), + TEGRA210_ADX_BYTE_MAP_CTRL(90), + TEGRA210_ADX_BYTE_MAP_CTRL(91), + TEGRA210_ADX_BYTE_MAP_CTRL(92), + TEGRA210_ADX_BYTE_MAP_CTRL(93), + TEGRA210_ADX_BYTE_MAP_CTRL(94), + TEGRA210_ADX_BYTE_MAP_CTRL(95), + TEGRA210_ADX_BYTE_MAP_CTRL(96), + TEGRA210_ADX_BYTE_MAP_CTRL(97), + TEGRA210_ADX_BYTE_MAP_CTRL(98), + TEGRA210_ADX_BYTE_MAP_CTRL(99), + TEGRA210_ADX_BYTE_MAP_CTRL(100), + TEGRA210_ADX_BYTE_MAP_CTRL(101), + TEGRA210_ADX_BYTE_MAP_CTRL(102), + TEGRA210_ADX_BYTE_MAP_CTRL(103), + TEGRA210_ADX_BYTE_MAP_CTRL(104), + TEGRA210_ADX_BYTE_MAP_CTRL(105), + TEGRA210_ADX_BYTE_MAP_CTRL(106), + TEGRA210_ADX_BYTE_MAP_CTRL(107), + TEGRA210_ADX_BYTE_MAP_CTRL(108), + TEGRA210_ADX_BYTE_MAP_CTRL(109), + TEGRA210_ADX_BYTE_MAP_CTRL(110), + TEGRA210_ADX_BYTE_MAP_CTRL(111), + TEGRA210_ADX_BYTE_MAP_CTRL(112), + TEGRA210_ADX_BYTE_MAP_CTRL(113), + TEGRA210_ADX_BYTE_MAP_CTRL(114), + TEGRA210_ADX_BYTE_MAP_CTRL(115), + TEGRA210_ADX_BYTE_MAP_CTRL(116), + TEGRA210_ADX_BYTE_MAP_CTRL(117), + TEGRA210_ADX_BYTE_MAP_CTRL(118), + TEGRA210_ADX_BYTE_MAP_CTRL(119), + TEGRA210_ADX_BYTE_MAP_CTRL(120), + TEGRA210_ADX_BYTE_MAP_CTRL(121), + TEGRA210_ADX_BYTE_MAP_CTRL(122), + TEGRA210_ADX_BYTE_MAP_CTRL(123), + TEGRA210_ADX_BYTE_MAP_CTRL(124), + TEGRA210_ADX_BYTE_MAP_CTRL(125), + TEGRA210_ADX_BYTE_MAP_CTRL(126), + TEGRA210_ADX_BYTE_MAP_CTRL(127), +}; + +static int tegra210_adx_component_probe(struct snd_soc_component *component) +{ + struct tegra210_adx *adx = snd_soc_component_get_drvdata(component); + int err = 0; + + if (adx->soc_data->num_controls) { + err = snd_soc_add_component_controls(component, adx->soc_data->controls, + adx->soc_data->num_controls); + if (err) + dev_err(component->dev, "can't add ADX controls, err: %d\n", err); + } + + return err; +} + static const struct snd_soc_component_driver tegra210_adx_cmpnt = { + .probe = tegra210_adx_component_probe, .dapm_widgets = tegra210_adx_widgets, .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), .dapm_routes = tegra210_adx_routes, @@ -460,6 +563,58 @@ static bool tegra210_adx_volatile_reg(struct device *dev, return false; } +static bool tegra264_adx_wr_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL: + case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL: + case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG: + case TEGRA210_ADX_CTRL ... TEGRA264_ADX_CYA: + case TEGRA264_ADX_CFG_RAM_CTRL ... TEGRA264_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra264_adx_rd_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_RX_CIF_CTRL: + case TEGRA210_ADX_TX_STATUS ... TEGRA210_ADX_TX4_CIF_CTRL: + case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_INT_STATUS: + case TEGRA210_ADX_CTRL ... TEGRA264_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra264_adx_volatile_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS: + case TEGRA210_ADX_RX_INT_STATUS: + case TEGRA210_ADX_RX_INT_SET: + case TEGRA210_ADX_TX_STATUS: + case TEGRA210_ADX_TX_INT_STATUS: + case TEGRA210_ADX_TX_INT_SET: + case TEGRA210_ADX_SOFT_RESET: + case TEGRA210_ADX_STATUS: + case TEGRA210_ADX_INT_STATUS: + case TEGRA264_ADX_CFG_RAM_CTRL: + case TEGRA264_ADX_CFG_RAM_DATA: + return true; + default: + break; + } + + return false; +} + static const struct regmap_config tegra210_adx_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -473,8 +628,40 @@ static const struct regmap_config tegra210_adx_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static const struct regmap_config tegra264_adx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA264_ADX_CFG_RAM_DATA, + .writeable_reg = tegra264_adx_wr_reg, + .readable_reg = tegra264_adx_rd_reg, + .volatile_reg = tegra264_adx_volatile_reg, + .reg_defaults = tegra264_adx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra264_adx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct tegra210_adx_soc_data soc_data_tegra210 = { + .regmap_conf = &tegra210_adx_regmap_config, + .max_ch = TEGRA210_ADX_MAX_CHANNEL, + .ram_depth = TEGRA210_ADX_RAM_DEPTH, + .byte_mask_size = TEGRA210_ADX_BYTE_MASK_COUNT, + .cya_offset = TEGRA210_ADX_CYA_OFFSET, +}; + +static const struct tegra210_adx_soc_data soc_data_tegra264 = { + .regmap_conf = &tegra264_adx_regmap_config, + .max_ch = TEGRA264_ADX_MAX_CHANNEL, + .ram_depth = TEGRA264_ADX_RAM_DEPTH, + .byte_mask_size = TEGRA264_ADX_BYTE_MASK_COUNT, + .cya_offset = TEGRA264_ADX_CYA_OFFSET, + .controls = tegra264_adx_controls, + .num_controls = ARRAY_SIZE(tegra264_adx_controls), +}; + static const struct of_device_id tegra210_adx_of_match[] = { - { .compatible = "nvidia,tegra210-adx" }, + { .compatible = "nvidia,tegra210-adx", .data = &soc_data_tegra210 }, + { .compatible = "nvidia,tegra264-adx", .data = &soc_data_tegra264 }, {}, }; MODULE_DEVICE_TABLE(of, tegra210_adx_of_match); @@ -483,6 +670,8 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tegra210_adx *adx; + const struct of_device_id *match; + struct tegra210_adx_soc_data *soc_data; void __iomem *regs; int err; @@ -490,6 +679,10 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev) if (!adx) return -ENOMEM; + match = of_match_device(tegra210_adx_of_match, dev); + soc_data = (struct tegra210_adx_soc_data *)match->data; + adx->soc_data = soc_data; + dev_set_drvdata(dev, adx); regs = devm_platform_ioremap_resource(pdev, 0); @@ -497,7 +690,7 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev) return PTR_ERR(regs); adx->regmap = devm_regmap_init_mmio(dev, regs, - &tegra210_adx_regmap_config); + soc_data->regmap_conf); if (IS_ERR(adx->regmap)) { dev_err(dev, "regmap init failed\n"); return PTR_ERR(adx->regmap); @@ -505,6 +698,20 @@ static int tegra210_adx_platform_probe(struct platform_device *pdev) regcache_cache_only(adx->regmap, true); + adx->map = devm_kzalloc(dev, soc_data->ram_depth * sizeof(*adx->map), + GFP_KERNEL); + if (!adx->map) + return -ENOMEM; + + adx->byte_mask = devm_kzalloc(dev, + soc_data->byte_mask_size * sizeof(*adx->byte_mask), + GFP_KERNEL); + if (!adx->byte_mask) + return -ENOMEM; + + tegra210_adx_dais[TEGRA_ADX_IN_DAI_ID].playback.channels_max = + adx->soc_data->max_ch; + err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt, tegra210_adx_dais, ARRAY_SIZE(tegra210_adx_dais)); |