871 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// tegra210_admaif.c - Tegra ADMAIF driver4//5// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.6 7#include <linux/clk.h>8#include <linux/device.h>9#include <linux/module.h>10#include <linux/of_platform.h>11#include <linux/platform_device.h>12#include <linux/pm_runtime.h>13#include <linux/regmap.h>14#include <sound/pcm_params.h>15#include <sound/soc.h>16#include "tegra210_admaif.h"17#include "tegra_cif.h"18#include "tegra_pcm.h"19 20#define CH_REG(offset, reg, id) \21 ((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))22 23#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)24 25#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)26 27#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base) \28 { CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 }, \29 { CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 }, \30 { CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl }, \31 { CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 }, \32 { CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 }, \33 { CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }34 35#define ADMAIF_REG_DEFAULTS(id, chip) \36 REG_DEFAULTS((id) - 1, \37 chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT, \38 chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT, \39 chip ## _ADMAIF_TX_BASE, \40 chip ## _ADMAIF_RX_BASE)41 42static const struct reg_default tegra186_admaif_reg_defaults[] = {43 {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},44 ADMAIF_REG_DEFAULTS(1, TEGRA186),45 ADMAIF_REG_DEFAULTS(2, TEGRA186),46 ADMAIF_REG_DEFAULTS(3, TEGRA186),47 ADMAIF_REG_DEFAULTS(4, TEGRA186),48 ADMAIF_REG_DEFAULTS(5, TEGRA186),49 ADMAIF_REG_DEFAULTS(6, TEGRA186),50 ADMAIF_REG_DEFAULTS(7, TEGRA186),51 ADMAIF_REG_DEFAULTS(8, TEGRA186),52 ADMAIF_REG_DEFAULTS(9, TEGRA186),53 ADMAIF_REG_DEFAULTS(10, TEGRA186),54 ADMAIF_REG_DEFAULTS(11, TEGRA186),55 ADMAIF_REG_DEFAULTS(12, TEGRA186),56 ADMAIF_REG_DEFAULTS(13, TEGRA186),57 ADMAIF_REG_DEFAULTS(14, TEGRA186),58 ADMAIF_REG_DEFAULTS(15, TEGRA186),59 ADMAIF_REG_DEFAULTS(16, TEGRA186),60 ADMAIF_REG_DEFAULTS(17, TEGRA186),61 ADMAIF_REG_DEFAULTS(18, TEGRA186),62 ADMAIF_REG_DEFAULTS(19, TEGRA186),63 ADMAIF_REG_DEFAULTS(20, TEGRA186)64};65 66static const struct reg_default tegra210_admaif_reg_defaults[] = {67 {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},68 ADMAIF_REG_DEFAULTS(1, TEGRA210),69 ADMAIF_REG_DEFAULTS(2, TEGRA210),70 ADMAIF_REG_DEFAULTS(3, TEGRA210),71 ADMAIF_REG_DEFAULTS(4, TEGRA210),72 ADMAIF_REG_DEFAULTS(5, TEGRA210),73 ADMAIF_REG_DEFAULTS(6, TEGRA210),74 ADMAIF_REG_DEFAULTS(7, TEGRA210),75 ADMAIF_REG_DEFAULTS(8, TEGRA210),76 ADMAIF_REG_DEFAULTS(9, TEGRA210),77 ADMAIF_REG_DEFAULTS(10, TEGRA210)78};79 80static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)81{82 struct tegra_admaif *admaif = dev_get_drvdata(dev);83 unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;84 unsigned int num_ch = admaif->soc_data->num_ch;85 unsigned int rx_base = admaif->soc_data->rx_base;86 unsigned int tx_base = admaif->soc_data->tx_base;87 unsigned int global_base = admaif->soc_data->global_base;88 unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;89 unsigned int rx_max = rx_base + (num_ch * ch_stride);90 unsigned int tx_max = tx_base + (num_ch * ch_stride);91 92 if ((reg >= rx_base) && (reg < rx_max)) {93 reg = (reg - rx_base) % ch_stride;94 if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||95 (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||96 (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||97 (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))98 return true;99 } else if ((reg >= tx_base) && (reg < tx_max)) {100 reg = (reg - tx_base) % ch_stride;101 if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||102 (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||103 (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||104 (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))105 return true;106 } else if ((reg >= global_base) && (reg < reg_max)) {107 if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))108 return true;109 }110 111 return false;112}113 114static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)115{116 struct tegra_admaif *admaif = dev_get_drvdata(dev);117 unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;118 unsigned int num_ch = admaif->soc_data->num_ch;119 unsigned int rx_base = admaif->soc_data->rx_base;120 unsigned int tx_base = admaif->soc_data->tx_base;121 unsigned int global_base = admaif->soc_data->global_base;122 unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;123 unsigned int rx_max = rx_base + (num_ch * ch_stride);124 unsigned int tx_max = tx_base + (num_ch * ch_stride);125 126 if ((reg >= rx_base) && (reg < rx_max)) {127 reg = (reg - rx_base) % ch_stride;128 if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||129 (reg == TEGRA_ADMAIF_RX_STATUS) ||130 (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||131 (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||132 (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||133 (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))134 return true;135 } else if ((reg >= tx_base) && (reg < tx_max)) {136 reg = (reg - tx_base) % ch_stride;137 if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||138 (reg == TEGRA_ADMAIF_TX_STATUS) ||139 (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||140 (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||141 (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||142 (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))143 return true;144 } else if ((reg >= global_base) && (reg < reg_max)) {145 if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||146 (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||147 (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||148 (reg == (global_base +149 TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||150 (reg == (global_base +151 TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))152 return true;153 }154 155 return false;156}157 158static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)159{160 struct tegra_admaif *admaif = dev_get_drvdata(dev);161 unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;162 unsigned int num_ch = admaif->soc_data->num_ch;163 unsigned int rx_base = admaif->soc_data->rx_base;164 unsigned int tx_base = admaif->soc_data->tx_base;165 unsigned int global_base = admaif->soc_data->global_base;166 unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;167 unsigned int rx_max = rx_base + (num_ch * ch_stride);168 unsigned int tx_max = tx_base + (num_ch * ch_stride);169 170 if ((reg >= rx_base) && (reg < rx_max)) {171 reg = (reg - rx_base) % ch_stride;172 if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||173 (reg == TEGRA_ADMAIF_RX_STATUS) ||174 (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||175 (reg == TEGRA_ADMAIF_RX_SOFT_RESET))176 return true;177 } else if ((reg >= tx_base) && (reg < tx_max)) {178 reg = (reg - tx_base) % ch_stride;179 if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||180 (reg == TEGRA_ADMAIF_TX_STATUS) ||181 (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||182 (reg == TEGRA_ADMAIF_TX_SOFT_RESET))183 return true;184 } else if ((reg >= global_base) && (reg < reg_max)) {185 if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||186 (reg == (global_base +187 TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||188 (reg == (global_base +189 TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))190 return true;191 }192 193 return false;194}195 196static const struct regmap_config tegra210_admaif_regmap_config = {197 .reg_bits = 32,198 .reg_stride = 4,199 .val_bits = 32,200 .max_register = TEGRA210_ADMAIF_LAST_REG,201 .writeable_reg = tegra_admaif_wr_reg,202 .readable_reg = tegra_admaif_rd_reg,203 .volatile_reg = tegra_admaif_volatile_reg,204 .reg_defaults = tegra210_admaif_reg_defaults,205 .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,206 .cache_type = REGCACHE_FLAT,207};208 209static const struct regmap_config tegra186_admaif_regmap_config = {210 .reg_bits = 32,211 .reg_stride = 4,212 .val_bits = 32,213 .max_register = TEGRA186_ADMAIF_LAST_REG,214 .writeable_reg = tegra_admaif_wr_reg,215 .readable_reg = tegra_admaif_rd_reg,216 .volatile_reg = tegra_admaif_volatile_reg,217 .reg_defaults = tegra186_admaif_reg_defaults,218 .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,219 .cache_type = REGCACHE_FLAT,220};221 222static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)223{224 struct tegra_admaif *admaif = dev_get_drvdata(dev);225 226 regcache_cache_only(admaif->regmap, true);227 regcache_mark_dirty(admaif->regmap);228 229 return 0;230}231 232static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)233{234 struct tegra_admaif *admaif = dev_get_drvdata(dev);235 236 regcache_cache_only(admaif->regmap, false);237 regcache_sync(admaif->regmap);238 239 return 0;240}241 242static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,243 int valid_bit)244{245 switch (valid_bit) {246 case DATA_8BIT:247 regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);248 regmap_update_bits(map, reg, PACK16_EN_MASK, 0);249 break;250 case DATA_16BIT:251 regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);252 regmap_update_bits(map, reg, PACK8_EN_MASK, 0);253 break;254 case DATA_32BIT:255 regmap_update_bits(map, reg, PACK16_EN_MASK, 0);256 regmap_update_bits(map, reg, PACK8_EN_MASK, 0);257 break;258 default:259 return -EINVAL;260 }261 262 return 0;263}264 265static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,266 struct snd_pcm_hw_params *params,267 struct snd_soc_dai *dai)268{269 struct device *dev = dai->dev;270 struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);271 struct tegra_cif_conf cif_conf;272 unsigned int reg, path;273 int valid_bit, channels;274 275 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));276 277 switch (params_format(params)) {278 case SNDRV_PCM_FORMAT_S8:279 cif_conf.audio_bits = TEGRA_ACIF_BITS_8;280 cif_conf.client_bits = TEGRA_ACIF_BITS_8;281 valid_bit = DATA_8BIT;282 break;283 case SNDRV_PCM_FORMAT_S16_LE:284 cif_conf.audio_bits = TEGRA_ACIF_BITS_16;285 cif_conf.client_bits = TEGRA_ACIF_BITS_16;286 valid_bit = DATA_16BIT;287 break;288 case SNDRV_PCM_FORMAT_S32_LE:289 cif_conf.audio_bits = TEGRA_ACIF_BITS_32;290 cif_conf.client_bits = TEGRA_ACIF_BITS_32;291 valid_bit = DATA_32BIT;292 break;293 default:294 dev_err(dev, "unsupported format!\n");295 return -EOPNOTSUPP;296 }297 298 channels = params_channels(params);299 cif_conf.client_ch = channels;300 cif_conf.audio_ch = channels;301 302 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {303 path = ADMAIF_TX_PATH;304 reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);305 } else {306 path = ADMAIF_RX_PATH;307 reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);308 }309 310 cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];311 cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];312 313 tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);314 315 tegra_set_cif(admaif->regmap, reg, &cif_conf);316 317 return 0;318}319 320static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)321{322 struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);323 unsigned int reg, mask, val;324 325 switch (direction) {326 case SNDRV_PCM_STREAM_PLAYBACK:327 mask = TX_ENABLE_MASK;328 val = TX_ENABLE;329 reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);330 break;331 case SNDRV_PCM_STREAM_CAPTURE:332 mask = RX_ENABLE_MASK;333 val = RX_ENABLE;334 reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);335 break;336 default:337 return -EINVAL;338 }339 340 regmap_update_bits(admaif->regmap, reg, mask, val);341 342 return 0;343}344 345static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)346{347 struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);348 unsigned int enable_reg, status_reg, reset_reg, mask, val;349 char *dir_name;350 int err, enable;351 352 switch (direction) {353 case SNDRV_PCM_STREAM_PLAYBACK:354 mask = TX_ENABLE_MASK;355 enable = TX_ENABLE;356 dir_name = "TX";357 enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);358 status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);359 reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);360 break;361 case SNDRV_PCM_STREAM_CAPTURE:362 mask = RX_ENABLE_MASK;363 enable = RX_ENABLE;364 dir_name = "RX";365 enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);366 status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);367 reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);368 break;369 default:370 return -EINVAL;371 }372 373 /* Disable TX/RX channel */374 regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);375 376 /* Wait until ADMAIF TX/RX status is disabled */377 err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,378 !(val & enable), 10, 10000);379 if (err < 0)380 dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",381 dai->id + 1, dir_name);382 383 /* SW reset */384 regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);385 386 /* Wait till SW reset is complete */387 err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,388 !(val & SW_RESET_MASK & SW_RESET),389 10, 10000);390 if (err) {391 dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",392 dai->id + 1, dir_name);393 return err;394 }395 396 return 0;397}398 399static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,400 struct snd_soc_dai *dai)401{402 int err;403 404 err = snd_dmaengine_pcm_trigger(substream, cmd);405 if (err)406 return err;407 408 switch (cmd) {409 case SNDRV_PCM_TRIGGER_START:410 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:411 case SNDRV_PCM_TRIGGER_RESUME:412 return tegra_admaif_start(dai, substream->stream);413 case SNDRV_PCM_TRIGGER_STOP:414 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:415 case SNDRV_PCM_TRIGGER_SUSPEND:416 return tegra_admaif_stop(dai, substream->stream);417 default:418 return -EINVAL;419 }420}421 422static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,423 struct snd_ctl_elem_value *ucontrol)424{425 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);426 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);427 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;428 429 ucontrol->value.enumerated.item[0] =430 admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];431 432 return 0;433}434 435static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,436 struct snd_ctl_elem_value *ucontrol)437{438 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);439 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);440 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;441 unsigned int value = ucontrol->value.enumerated.item[0];442 443 if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])444 return 0;445 446 admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;447 448 return 1;449}450 451static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,452 struct snd_ctl_elem_value *ucontrol)453{454 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);455 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);456 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;457 458 ucontrol->value.enumerated.item[0] =459 admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];460 461 return 0;462}463 464static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,465 struct snd_ctl_elem_value *ucontrol)466{467 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);468 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);469 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;470 unsigned int value = ucontrol->value.enumerated.item[0];471 472 if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])473 return 0;474 475 admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;476 477 return 1;478}479 480static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,481 struct snd_ctl_elem_value *ucontrol)482{483 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);484 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);485 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;486 487 ucontrol->value.enumerated.item[0] =488 admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];489 490 return 0;491}492 493static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,494 struct snd_ctl_elem_value *ucontrol)495{496 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);497 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);498 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;499 unsigned int value = ucontrol->value.enumerated.item[0];500 501 if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])502 return 0;503 504 admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;505 506 return 1;507}508 509static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,510 struct snd_ctl_elem_value *ucontrol)511{512 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);513 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);514 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;515 516 ucontrol->value.enumerated.item[0] =517 admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];518 519 return 0;520}521 522static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,523 struct snd_ctl_elem_value *ucontrol)524{525 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);526 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);527 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;528 unsigned int value = ucontrol->value.enumerated.item[0];529 530 if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])531 return 0;532 533 admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;534 535 return 1;536}537 538static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)539{540 struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);541 542 snd_soc_dai_init_dma_data(dai, &admaif->playback_dma_data[dai->id],543 &admaif->capture_dma_data[dai->id]);544 545 return 0;546}547 548static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {549 .probe = tegra_admaif_dai_probe,550 .hw_params = tegra_admaif_hw_params,551 .trigger = tegra_admaif_trigger,552};553 554#define DAI(dai_name) \555 { \556 .name = dai_name, \557 .playback = { \558 .stream_name = dai_name " Playback", \559 .channels_min = 1, \560 .channels_max = 16, \561 .rates = SNDRV_PCM_RATE_8000_192000, \562 .formats = SNDRV_PCM_FMTBIT_S8 | \563 SNDRV_PCM_FMTBIT_S16_LE | \564 SNDRV_PCM_FMTBIT_S32_LE, \565 }, \566 .capture = { \567 .stream_name = dai_name " Capture", \568 .channels_min = 1, \569 .channels_max = 16, \570 .rates = SNDRV_PCM_RATE_8000_192000, \571 .formats = SNDRV_PCM_FMTBIT_S8 | \572 SNDRV_PCM_FMTBIT_S16_LE | \573 SNDRV_PCM_FMTBIT_S32_LE, \574 }, \575 .ops = &tegra_admaif_dai_ops, \576 }577 578static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {579 DAI("ADMAIF1"),580 DAI("ADMAIF2"),581 DAI("ADMAIF3"),582 DAI("ADMAIF4"),583 DAI("ADMAIF5"),584 DAI("ADMAIF6"),585 DAI("ADMAIF7"),586 DAI("ADMAIF8"),587 DAI("ADMAIF9"),588 DAI("ADMAIF10"),589};590 591static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {592 DAI("ADMAIF1"),593 DAI("ADMAIF2"),594 DAI("ADMAIF3"),595 DAI("ADMAIF4"),596 DAI("ADMAIF5"),597 DAI("ADMAIF6"),598 DAI("ADMAIF7"),599 DAI("ADMAIF8"),600 DAI("ADMAIF9"),601 DAI("ADMAIF10"),602 DAI("ADMAIF11"),603 DAI("ADMAIF12"),604 DAI("ADMAIF13"),605 DAI("ADMAIF14"),606 DAI("ADMAIF15"),607 DAI("ADMAIF16"),608 DAI("ADMAIF17"),609 DAI("ADMAIF18"),610 DAI("ADMAIF19"),611 DAI("ADMAIF20"),612};613 614static const char * const tegra_admaif_stereo_conv_text[] = {615 "CH0", "CH1", "AVG",616};617 618static const char * const tegra_admaif_mono_conv_text[] = {619 "Zero", "Copy",620};621 622/*623 * Below macro is added to avoid looping over all ADMAIFx controls related624 * to mono/stereo conversions in get()/put() callbacks.625 */626#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \627{ \628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \629 .info = snd_soc_info_enum_double, \630 .name = xname, \631 .get = xhandler_get, \632 .put = xhandler_put, \633 .private_value = (unsigned long)&(struct soc_enum) \634 SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text) \635}636 637#define TEGRA_ADMAIF_CIF_CTRL(reg) \638 NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1, \639 tegra210_admaif_pget_mono_to_stereo, \640 tegra210_admaif_pput_mono_to_stereo, \641 tegra_admaif_mono_conv_text), \642 NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1, \643 tegra210_admaif_pget_stereo_to_mono, \644 tegra210_admaif_pput_stereo_to_mono, \645 tegra_admaif_stereo_conv_text), \646 NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \647 tegra210_admaif_cget_mono_to_stereo, \648 tegra210_admaif_cput_mono_to_stereo, \649 tegra_admaif_mono_conv_text), \650 NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \651 tegra210_admaif_cget_stereo_to_mono, \652 tegra210_admaif_cput_stereo_to_mono, \653 tegra_admaif_stereo_conv_text)654 655static struct snd_kcontrol_new tegra210_admaif_controls[] = {656 TEGRA_ADMAIF_CIF_CTRL(1),657 TEGRA_ADMAIF_CIF_CTRL(2),658 TEGRA_ADMAIF_CIF_CTRL(3),659 TEGRA_ADMAIF_CIF_CTRL(4),660 TEGRA_ADMAIF_CIF_CTRL(5),661 TEGRA_ADMAIF_CIF_CTRL(6),662 TEGRA_ADMAIF_CIF_CTRL(7),663 TEGRA_ADMAIF_CIF_CTRL(8),664 TEGRA_ADMAIF_CIF_CTRL(9),665 TEGRA_ADMAIF_CIF_CTRL(10),666};667 668static struct snd_kcontrol_new tegra186_admaif_controls[] = {669 TEGRA_ADMAIF_CIF_CTRL(1),670 TEGRA_ADMAIF_CIF_CTRL(2),671 TEGRA_ADMAIF_CIF_CTRL(3),672 TEGRA_ADMAIF_CIF_CTRL(4),673 TEGRA_ADMAIF_CIF_CTRL(5),674 TEGRA_ADMAIF_CIF_CTRL(6),675 TEGRA_ADMAIF_CIF_CTRL(7),676 TEGRA_ADMAIF_CIF_CTRL(8),677 TEGRA_ADMAIF_CIF_CTRL(9),678 TEGRA_ADMAIF_CIF_CTRL(10),679 TEGRA_ADMAIF_CIF_CTRL(11),680 TEGRA_ADMAIF_CIF_CTRL(12),681 TEGRA_ADMAIF_CIF_CTRL(13),682 TEGRA_ADMAIF_CIF_CTRL(14),683 TEGRA_ADMAIF_CIF_CTRL(15),684 TEGRA_ADMAIF_CIF_CTRL(16),685 TEGRA_ADMAIF_CIF_CTRL(17),686 TEGRA_ADMAIF_CIF_CTRL(18),687 TEGRA_ADMAIF_CIF_CTRL(19),688 TEGRA_ADMAIF_CIF_CTRL(20),689};690 691static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {692 .controls = tegra210_admaif_controls,693 .num_controls = ARRAY_SIZE(tegra210_admaif_controls),694 .pcm_construct = tegra_pcm_construct,695 .open = tegra_pcm_open,696 .close = tegra_pcm_close,697 .hw_params = tegra_pcm_hw_params,698 .pointer = tegra_pcm_pointer,699};700 701static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {702 .controls = tegra186_admaif_controls,703 .num_controls = ARRAY_SIZE(tegra186_admaif_controls),704 .pcm_construct = tegra_pcm_construct,705 .open = tegra_pcm_open,706 .close = tegra_pcm_close,707 .hw_params = tegra_pcm_hw_params,708 .pointer = tegra_pcm_pointer,709};710 711static const struct tegra_admaif_soc_data soc_data_tegra210 = {712 .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT,713 .cmpnt = &tegra210_admaif_cmpnt,714 .dais = tegra210_admaif_cmpnt_dais,715 .regmap_conf = &tegra210_admaif_regmap_config,716 .global_base = TEGRA210_ADMAIF_GLOBAL_BASE,717 .tx_base = TEGRA210_ADMAIF_TX_BASE,718 .rx_base = TEGRA210_ADMAIF_RX_BASE,719};720 721static const struct tegra_admaif_soc_data soc_data_tegra186 = {722 .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT,723 .cmpnt = &tegra186_admaif_cmpnt,724 .dais = tegra186_admaif_cmpnt_dais,725 .regmap_conf = &tegra186_admaif_regmap_config,726 .global_base = TEGRA186_ADMAIF_GLOBAL_BASE,727 .tx_base = TEGRA186_ADMAIF_TX_BASE,728 .rx_base = TEGRA186_ADMAIF_RX_BASE,729};730 731static const struct of_device_id tegra_admaif_of_match[] = {732 { .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },733 { .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },734 {},735};736MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);737 738static int tegra_admaif_probe(struct platform_device *pdev)739{740 struct tegra_admaif *admaif;741 void __iomem *regs;742 struct resource *res;743 int err, i;744 745 admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);746 if (!admaif)747 return -ENOMEM;748 749 admaif->soc_data = of_device_get_match_data(&pdev->dev);750 751 dev_set_drvdata(&pdev->dev, admaif);752 753 admaif->capture_dma_data =754 devm_kcalloc(&pdev->dev,755 admaif->soc_data->num_ch,756 sizeof(struct snd_dmaengine_dai_dma_data),757 GFP_KERNEL);758 if (!admaif->capture_dma_data)759 return -ENOMEM;760 761 admaif->playback_dma_data =762 devm_kcalloc(&pdev->dev,763 admaif->soc_data->num_ch,764 sizeof(struct snd_dmaengine_dai_dma_data),765 GFP_KERNEL);766 if (!admaif->playback_dma_data)767 return -ENOMEM;768 769 for (i = 0; i < ADMAIF_PATHS; i++) {770 admaif->mono_to_stereo[i] =771 devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,772 sizeof(unsigned int), GFP_KERNEL);773 if (!admaif->mono_to_stereo[i])774 return -ENOMEM;775 776 admaif->stereo_to_mono[i] =777 devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,778 sizeof(unsigned int), GFP_KERNEL);779 if (!admaif->stereo_to_mono[i])780 return -ENOMEM;781 }782 783 regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);784 if (IS_ERR(regs))785 return PTR_ERR(regs);786 787 admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,788 admaif->soc_data->regmap_conf);789 if (IS_ERR(admaif->regmap)) {790 dev_err(&pdev->dev, "regmap init failed\n");791 return PTR_ERR(admaif->regmap);792 }793 794 regcache_cache_only(admaif->regmap, true);795 796 regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +797 TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);798 799 for (i = 0; i < admaif->soc_data->num_ch; i++) {800 admaif->playback_dma_data[i].addr = res->start +801 CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);802 803 admaif->capture_dma_data[i].addr = res->start +804 CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);805 806 admaif->playback_dma_data[i].addr_width = 32;807 808 if (of_property_read_string_index(pdev->dev.of_node,809 "dma-names", (i * 2) + 1,810 &admaif->playback_dma_data[i].chan_name) < 0) {811 dev_err(&pdev->dev,812 "missing property nvidia,dma-names\n");813 814 return -ENODEV;815 }816 817 admaif->capture_dma_data[i].addr_width = 32;818 819 if (of_property_read_string_index(pdev->dev.of_node,820 "dma-names",821 (i * 2),822 &admaif->capture_dma_data[i].chan_name) < 0) {823 dev_err(&pdev->dev,824 "missing property nvidia,dma-names\n");825 826 return -ENODEV;827 }828 }829 830 err = devm_snd_soc_register_component(&pdev->dev,831 admaif->soc_data->cmpnt,832 admaif->soc_data->dais,833 admaif->soc_data->num_ch);834 if (err) {835 dev_err(&pdev->dev,836 "can't register ADMAIF component, err: %d\n", err);837 return err;838 }839 840 pm_runtime_enable(&pdev->dev);841 842 return 0;843}844 845static void tegra_admaif_remove(struct platform_device *pdev)846{847 pm_runtime_disable(&pdev->dev);848}849 850static const struct dev_pm_ops tegra_admaif_pm_ops = {851 SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,852 tegra_admaif_runtime_resume, NULL)853 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,854 pm_runtime_force_resume)855};856 857static struct platform_driver tegra_admaif_driver = {858 .probe = tegra_admaif_probe,859 .remove = tegra_admaif_remove,860 .driver = {861 .name = "tegra210-admaif",862 .of_match_table = tegra_admaif_of_match,863 .pm = &tegra_admaif_pm_ops,864 },865};866module_platform_driver(tegra_admaif_driver);867 868MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");869MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");870MODULE_LICENSE("GPL v2");871