123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 |
- // SPDX-License-Identifier: GPL-2.0-only
- //
- // tegra210_admaif.c - Tegra ADMAIF driver
- //
- // Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
- #include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/module.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
- #include <linux/regmap.h>
- #include <sound/pcm_params.h>
- #include <sound/soc.h>
- #include "tegra210_admaif.h"
- #include "tegra_cif.h"
- #include "tegra_pcm.h"
- #define CH_REG(offset, reg, id) \
- ((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
- #define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
- #define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
- #define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base) \
- { CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 }, \
- { CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 }, \
- { CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl }, \
- { CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 }, \
- { CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 }, \
- { CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
- #define ADMAIF_REG_DEFAULTS(id, chip) \
- REG_DEFAULTS((id) - 1, \
- chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT, \
- chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT, \
- chip ## _ADMAIF_TX_BASE, \
- chip ## _ADMAIF_RX_BASE)
- static const struct reg_default tegra186_admaif_reg_defaults[] = {
- {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
- ADMAIF_REG_DEFAULTS(1, TEGRA186),
- ADMAIF_REG_DEFAULTS(2, TEGRA186),
- ADMAIF_REG_DEFAULTS(3, TEGRA186),
- ADMAIF_REG_DEFAULTS(4, TEGRA186),
- ADMAIF_REG_DEFAULTS(5, TEGRA186),
- ADMAIF_REG_DEFAULTS(6, TEGRA186),
- ADMAIF_REG_DEFAULTS(7, TEGRA186),
- ADMAIF_REG_DEFAULTS(8, TEGRA186),
- ADMAIF_REG_DEFAULTS(9, TEGRA186),
- ADMAIF_REG_DEFAULTS(10, TEGRA186),
- ADMAIF_REG_DEFAULTS(11, TEGRA186),
- ADMAIF_REG_DEFAULTS(12, TEGRA186),
- ADMAIF_REG_DEFAULTS(13, TEGRA186),
- ADMAIF_REG_DEFAULTS(14, TEGRA186),
- ADMAIF_REG_DEFAULTS(15, TEGRA186),
- ADMAIF_REG_DEFAULTS(16, TEGRA186),
- ADMAIF_REG_DEFAULTS(17, TEGRA186),
- ADMAIF_REG_DEFAULTS(18, TEGRA186),
- ADMAIF_REG_DEFAULTS(19, TEGRA186),
- ADMAIF_REG_DEFAULTS(20, TEGRA186)
- };
- static const struct reg_default tegra210_admaif_reg_defaults[] = {
- {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
- ADMAIF_REG_DEFAULTS(1, TEGRA210),
- ADMAIF_REG_DEFAULTS(2, TEGRA210),
- ADMAIF_REG_DEFAULTS(3, TEGRA210),
- ADMAIF_REG_DEFAULTS(4, TEGRA210),
- ADMAIF_REG_DEFAULTS(5, TEGRA210),
- ADMAIF_REG_DEFAULTS(6, TEGRA210),
- ADMAIF_REG_DEFAULTS(7, TEGRA210),
- ADMAIF_REG_DEFAULTS(8, TEGRA210),
- ADMAIF_REG_DEFAULTS(9, TEGRA210),
- ADMAIF_REG_DEFAULTS(10, TEGRA210)
- };
- static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
- {
- struct tegra_admaif *admaif = dev_get_drvdata(dev);
- unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
- unsigned int num_ch = admaif->soc_data->num_ch;
- unsigned int rx_base = admaif->soc_data->rx_base;
- unsigned int tx_base = admaif->soc_data->tx_base;
- unsigned int global_base = admaif->soc_data->global_base;
- unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
- unsigned int rx_max = rx_base + (num_ch * ch_stride);
- unsigned int tx_max = tx_base + (num_ch * ch_stride);
- if ((reg >= rx_base) && (reg < rx_max)) {
- reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
- return true;
- } else if ((reg >= tx_base) && (reg < tx_max)) {
- reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
- return true;
- } else if ((reg >= global_base) && (reg < reg_max)) {
- if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
- return true;
- }
- return false;
- }
- static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
- {
- struct tegra_admaif *admaif = dev_get_drvdata(dev);
- unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
- unsigned int num_ch = admaif->soc_data->num_ch;
- unsigned int rx_base = admaif->soc_data->rx_base;
- unsigned int tx_base = admaif->soc_data->tx_base;
- unsigned int global_base = admaif->soc_data->global_base;
- unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
- unsigned int rx_max = rx_base + (num_ch * ch_stride);
- unsigned int tx_max = tx_base + (num_ch * ch_stride);
- if ((reg >= rx_base) && (reg < rx_max)) {
- reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_RX_STATUS) ||
- (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
- return true;
- } else if ((reg >= tx_base) && (reg < tx_max)) {
- reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_TX_STATUS) ||
- (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
- return true;
- } else if ((reg >= global_base) && (reg < reg_max)) {
- if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
- (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
- (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
- (reg == (global_base +
- TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
- (reg == (global_base +
- TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
- return true;
- }
- return false;
- }
- static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
- {
- struct tegra_admaif *admaif = dev_get_drvdata(dev);
- unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
- unsigned int num_ch = admaif->soc_data->num_ch;
- unsigned int rx_base = admaif->soc_data->rx_base;
- unsigned int tx_base = admaif->soc_data->tx_base;
- unsigned int global_base = admaif->soc_data->global_base;
- unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
- unsigned int rx_max = rx_base + (num_ch * ch_stride);
- unsigned int tx_max = tx_base + (num_ch * ch_stride);
- if ((reg >= rx_base) && (reg < rx_max)) {
- reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_RX_STATUS) ||
- (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
- return true;
- } else if ((reg >= tx_base) && (reg < tx_max)) {
- reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_TX_STATUS) ||
- (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
- return true;
- } else if ((reg >= global_base) && (reg < reg_max)) {
- if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
- (reg == (global_base +
- TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
- (reg == (global_base +
- TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
- return true;
- }
- return false;
- }
- static const struct regmap_config tegra210_admaif_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA210_ADMAIF_LAST_REG,
- .writeable_reg = tegra_admaif_wr_reg,
- .readable_reg = tegra_admaif_rd_reg,
- .volatile_reg = tegra_admaif_volatile_reg,
- .reg_defaults = tegra210_admaif_reg_defaults,
- .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
- .cache_type = REGCACHE_FLAT,
- };
- static const struct regmap_config tegra186_admaif_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA186_ADMAIF_LAST_REG,
- .writeable_reg = tegra_admaif_wr_reg,
- .readable_reg = tegra_admaif_rd_reg,
- .volatile_reg = tegra_admaif_volatile_reg,
- .reg_defaults = tegra186_admaif_reg_defaults,
- .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
- .cache_type = REGCACHE_FLAT,
- };
- static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)
- {
- struct tegra_admaif *admaif = dev_get_drvdata(dev);
- regcache_cache_only(admaif->regmap, true);
- regcache_mark_dirty(admaif->regmap);
- return 0;
- }
- static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)
- {
- struct tegra_admaif *admaif = dev_get_drvdata(dev);
- regcache_cache_only(admaif->regmap, false);
- regcache_sync(admaif->regmap);
- return 0;
- }
- static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
- int valid_bit)
- {
- switch (valid_bit) {
- case DATA_8BIT:
- regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
- regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
- break;
- case DATA_16BIT:
- regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
- regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
- break;
- case DATA_32BIT:
- regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
- regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
- {
- struct device *dev = dai->dev;
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- struct tegra_cif_conf cif_conf;
- unsigned int reg, path;
- int valid_bit, channels;
- memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
- cif_conf.client_bits = TEGRA_ACIF_BITS_8;
- valid_bit = DATA_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
- cif_conf.client_bits = TEGRA_ACIF_BITS_16;
- valid_bit = DATA_16BIT;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
- cif_conf.client_bits = TEGRA_ACIF_BITS_32;
- valid_bit = DATA_32BIT;
- break;
- default:
- dev_err(dev, "unsupported format!\n");
- return -EOPNOTSUPP;
- }
- channels = params_channels(params);
- cif_conf.client_ch = channels;
- cif_conf.audio_ch = channels;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- path = ADMAIF_TX_PATH;
- reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
- } else {
- path = ADMAIF_RX_PATH;
- reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
- }
- cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
- cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
- tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
- tegra_set_cif(admaif->regmap, reg, &cif_conf);
- return 0;
- }
- static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
- {
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- unsigned int reg, mask, val;
- switch (direction) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- mask = TX_ENABLE_MASK;
- val = TX_ENABLE;
- reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
- break;
- case SNDRV_PCM_STREAM_CAPTURE:
- mask = RX_ENABLE_MASK;
- val = RX_ENABLE;
- reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
- break;
- default:
- return -EINVAL;
- }
- regmap_update_bits(admaif->regmap, reg, mask, val);
- return 0;
- }
- static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
- {
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- unsigned int enable_reg, status_reg, reset_reg, mask, val;
- char *dir_name;
- int err, enable;
- switch (direction) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- mask = TX_ENABLE_MASK;
- enable = TX_ENABLE;
- dir_name = "TX";
- enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
- status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
- reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
- break;
- case SNDRV_PCM_STREAM_CAPTURE:
- mask = RX_ENABLE_MASK;
- enable = RX_ENABLE;
- dir_name = "RX";
- enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
- status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
- reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
- break;
- default:
- return -EINVAL;
- }
- /* Disable TX/RX channel */
- regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
- /* Wait until ADMAIF TX/RX status is disabled */
- err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
- !(val & enable), 10, 10000);
- if (err < 0)
- dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
- dai->id + 1, dir_name);
- /* SW reset */
- regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
- /* Wait till SW reset is complete */
- err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
- !(val & SW_RESET_MASK & SW_RESET),
- 10, 10000);
- if (err) {
- dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
- dai->id + 1, dir_name);
- return err;
- }
- return 0;
- }
- static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
- {
- int err;
- err = snd_dmaengine_pcm_trigger(substream, cmd);
- if (err)
- return err;
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- return tegra_admaif_start(dai, substream->stream);
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- return tegra_admaif_stop(dai, substream->stream);
- default:
- return -EINVAL;
- }
- }
- static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
- .hw_params = tegra_admaif_hw_params,
- .trigger = tegra_admaif_trigger,
- };
- static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] =
- admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
- return 0;
- }
- static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- unsigned int value = ucontrol->value.enumerated.item[0];
- if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
- return 0;
- admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
- return 1;
- }
- static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] =
- admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
- return 0;
- }
- static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- unsigned int value = ucontrol->value.enumerated.item[0];
- if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
- return 0;
- admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
- return 1;
- }
- static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] =
- admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
- return 0;
- }
- static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- unsigned int value = ucontrol->value.enumerated.item[0];
- if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
- return 0;
- admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
- return 1;
- }
- static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- ucontrol->value.enumerated.item[0] =
- admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
- return 0;
- }
- static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- unsigned int value = ucontrol->value.enumerated.item[0];
- if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
- return 0;
- admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
- return 1;
- }
- static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
- {
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- dai->capture_dma_data = &admaif->capture_dma_data[dai->id];
- dai->playback_dma_data = &admaif->playback_dma_data[dai->id];
- return 0;
- }
- #define DAI(dai_name) \
- { \
- .name = dai_name, \
- .probe = tegra_admaif_dai_probe, \
- .playback = { \
- .stream_name = dai_name " Playback", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .capture = { \
- .stream_name = dai_name " Capture", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .ops = &tegra_admaif_dai_ops, \
- }
- static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
- DAI("ADMAIF1"),
- DAI("ADMAIF2"),
- DAI("ADMAIF3"),
- DAI("ADMAIF4"),
- DAI("ADMAIF5"),
- DAI("ADMAIF6"),
- DAI("ADMAIF7"),
- DAI("ADMAIF8"),
- DAI("ADMAIF9"),
- DAI("ADMAIF10"),
- };
- static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
- DAI("ADMAIF1"),
- DAI("ADMAIF2"),
- DAI("ADMAIF3"),
- DAI("ADMAIF4"),
- DAI("ADMAIF5"),
- DAI("ADMAIF6"),
- DAI("ADMAIF7"),
- DAI("ADMAIF8"),
- DAI("ADMAIF9"),
- DAI("ADMAIF10"),
- DAI("ADMAIF11"),
- DAI("ADMAIF12"),
- DAI("ADMAIF13"),
- DAI("ADMAIF14"),
- DAI("ADMAIF15"),
- DAI("ADMAIF16"),
- DAI("ADMAIF17"),
- DAI("ADMAIF18"),
- DAI("ADMAIF19"),
- DAI("ADMAIF20"),
- };
- static const char * const tegra_admaif_stereo_conv_text[] = {
- "CH0", "CH1", "AVG",
- };
- static const char * const tegra_admaif_mono_conv_text[] = {
- "Zero", "Copy",
- };
- /*
- * Below macro is added to avoid looping over all ADMAIFx controls related
- * to mono/stereo conversions in get()/put() callbacks.
- */
- #define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .info = snd_soc_info_enum_double, \
- .name = xname, \
- .get = xhandler_get, \
- .put = xhandler_put, \
- .private_value = (unsigned long)&(struct soc_enum) \
- SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text) \
- }
- #define TEGRA_ADMAIF_CIF_CTRL(reg) \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1, \
- tegra210_admaif_pget_mono_to_stereo, \
- tegra210_admaif_pput_mono_to_stereo, \
- tegra_admaif_mono_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1, \
- tegra210_admaif_pget_stereo_to_mono, \
- tegra210_admaif_pput_stereo_to_mono, \
- tegra_admaif_stereo_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
- tegra210_admaif_cget_mono_to_stereo, \
- tegra210_admaif_cput_mono_to_stereo, \
- tegra_admaif_mono_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
- tegra210_admaif_cget_stereo_to_mono, \
- tegra210_admaif_cput_stereo_to_mono, \
- tegra_admaif_stereo_conv_text)
- static struct snd_kcontrol_new tegra210_admaif_controls[] = {
- TEGRA_ADMAIF_CIF_CTRL(1),
- TEGRA_ADMAIF_CIF_CTRL(2),
- TEGRA_ADMAIF_CIF_CTRL(3),
- TEGRA_ADMAIF_CIF_CTRL(4),
- TEGRA_ADMAIF_CIF_CTRL(5),
- TEGRA_ADMAIF_CIF_CTRL(6),
- TEGRA_ADMAIF_CIF_CTRL(7),
- TEGRA_ADMAIF_CIF_CTRL(8),
- TEGRA_ADMAIF_CIF_CTRL(9),
- TEGRA_ADMAIF_CIF_CTRL(10),
- };
- static struct snd_kcontrol_new tegra186_admaif_controls[] = {
- TEGRA_ADMAIF_CIF_CTRL(1),
- TEGRA_ADMAIF_CIF_CTRL(2),
- TEGRA_ADMAIF_CIF_CTRL(3),
- TEGRA_ADMAIF_CIF_CTRL(4),
- TEGRA_ADMAIF_CIF_CTRL(5),
- TEGRA_ADMAIF_CIF_CTRL(6),
- TEGRA_ADMAIF_CIF_CTRL(7),
- TEGRA_ADMAIF_CIF_CTRL(8),
- TEGRA_ADMAIF_CIF_CTRL(9),
- TEGRA_ADMAIF_CIF_CTRL(10),
- TEGRA_ADMAIF_CIF_CTRL(11),
- TEGRA_ADMAIF_CIF_CTRL(12),
- TEGRA_ADMAIF_CIF_CTRL(13),
- TEGRA_ADMAIF_CIF_CTRL(14),
- TEGRA_ADMAIF_CIF_CTRL(15),
- TEGRA_ADMAIF_CIF_CTRL(16),
- TEGRA_ADMAIF_CIF_CTRL(17),
- TEGRA_ADMAIF_CIF_CTRL(18),
- TEGRA_ADMAIF_CIF_CTRL(19),
- TEGRA_ADMAIF_CIF_CTRL(20),
- };
- static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
- .controls = tegra210_admaif_controls,
- .num_controls = ARRAY_SIZE(tegra210_admaif_controls),
- .pcm_construct = tegra_pcm_construct,
- .open = tegra_pcm_open,
- .close = tegra_pcm_close,
- .hw_params = tegra_pcm_hw_params,
- .pointer = tegra_pcm_pointer,
- };
- static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
- .controls = tegra186_admaif_controls,
- .num_controls = ARRAY_SIZE(tegra186_admaif_controls),
- .pcm_construct = tegra_pcm_construct,
- .open = tegra_pcm_open,
- .close = tegra_pcm_close,
- .hw_params = tegra_pcm_hw_params,
- .pointer = tegra_pcm_pointer,
- };
- static const struct tegra_admaif_soc_data soc_data_tegra210 = {
- .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT,
- .cmpnt = &tegra210_admaif_cmpnt,
- .dais = tegra210_admaif_cmpnt_dais,
- .regmap_conf = &tegra210_admaif_regmap_config,
- .global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
- .tx_base = TEGRA210_ADMAIF_TX_BASE,
- .rx_base = TEGRA210_ADMAIF_RX_BASE,
- };
- static const struct tegra_admaif_soc_data soc_data_tegra186 = {
- .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT,
- .cmpnt = &tegra186_admaif_cmpnt,
- .dais = tegra186_admaif_cmpnt_dais,
- .regmap_conf = &tegra186_admaif_regmap_config,
- .global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
- .tx_base = TEGRA186_ADMAIF_TX_BASE,
- .rx_base = TEGRA186_ADMAIF_RX_BASE,
- };
- static const struct of_device_id tegra_admaif_of_match[] = {
- { .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
- { .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
- {},
- };
- MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
- static int tegra_admaif_probe(struct platform_device *pdev)
- {
- struct tegra_admaif *admaif;
- void __iomem *regs;
- struct resource *res;
- int err, i;
- admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
- if (!admaif)
- return -ENOMEM;
- admaif->soc_data = of_device_get_match_data(&pdev->dev);
- dev_set_drvdata(&pdev->dev, admaif);
- admaif->capture_dma_data =
- devm_kcalloc(&pdev->dev,
- admaif->soc_data->num_ch,
- sizeof(struct snd_dmaengine_dai_dma_data),
- GFP_KERNEL);
- if (!admaif->capture_dma_data)
- return -ENOMEM;
- admaif->playback_dma_data =
- devm_kcalloc(&pdev->dev,
- admaif->soc_data->num_ch,
- sizeof(struct snd_dmaengine_dai_dma_data),
- GFP_KERNEL);
- if (!admaif->playback_dma_data)
- return -ENOMEM;
- for (i = 0; i < ADMAIF_PATHS; i++) {
- admaif->mono_to_stereo[i] =
- devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
- sizeof(unsigned int), GFP_KERNEL);
- if (!admaif->mono_to_stereo[i])
- return -ENOMEM;
- admaif->stereo_to_mono[i] =
- devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
- sizeof(unsigned int), GFP_KERNEL);
- if (!admaif->stereo_to_mono[i])
- return -ENOMEM;
- }
- regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
- admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
- admaif->soc_data->regmap_conf);
- if (IS_ERR(admaif->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- return PTR_ERR(admaif->regmap);
- }
- regcache_cache_only(admaif->regmap, true);
- regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
- TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
- for (i = 0; i < admaif->soc_data->num_ch; i++) {
- admaif->playback_dma_data[i].addr = res->start +
- CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
- admaif->capture_dma_data[i].addr = res->start +
- CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
- admaif->playback_dma_data[i].addr_width = 32;
- if (of_property_read_string_index(pdev->dev.of_node,
- "dma-names", (i * 2) + 1,
- &admaif->playback_dma_data[i].chan_name) < 0) {
- dev_err(&pdev->dev,
- "missing property nvidia,dma-names\n");
- return -ENODEV;
- }
- admaif->capture_dma_data[i].addr_width = 32;
- if (of_property_read_string_index(pdev->dev.of_node,
- "dma-names",
- (i * 2),
- &admaif->capture_dma_data[i].chan_name) < 0) {
- dev_err(&pdev->dev,
- "missing property nvidia,dma-names\n");
- return -ENODEV;
- }
- }
- err = devm_snd_soc_register_component(&pdev->dev,
- admaif->soc_data->cmpnt,
- admaif->soc_data->dais,
- admaif->soc_data->num_ch);
- if (err) {
- dev_err(&pdev->dev,
- "can't register ADMAIF component, err: %d\n", err);
- return err;
- }
- pm_runtime_enable(&pdev->dev);
- return 0;
- }
- static int tegra_admaif_remove(struct platform_device *pdev)
- {
- pm_runtime_disable(&pdev->dev);
- return 0;
- }
- static const struct dev_pm_ops tegra_admaif_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
- tegra_admaif_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- };
- static struct platform_driver tegra_admaif_driver = {
- .probe = tegra_admaif_probe,
- .remove = tegra_admaif_remove,
- .driver = {
- .name = "tegra210-admaif",
- .of_match_table = tegra_admaif_of_match,
- .pm = &tegra_admaif_pm_ops,
- },
- };
- module_platform_driver(tegra_admaif_driver);
- MODULE_AUTHOR("Songhee Baek <[email protected]>");
- MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
- MODULE_LICENSE("GPL v2");
|