0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/device.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <sound/core.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020
0021 #include "tegra210_amx.h"
0022 #include "tegra_cif.h"
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #define TEGRA194_MAX_FRAME_IDLE_COUNT 0x1800
0035
0036 #define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE))
0037
0038 static const struct reg_default tegra210_amx_reg_defaults[] = {
0039 { TEGRA210_AMX_RX_INT_MASK, 0x0000000f},
0040 { TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000},
0041 { TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000},
0042 { TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000},
0043 { TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000},
0044 { TEGRA210_AMX_TX_INT_MASK, 0x00000001},
0045 { TEGRA210_AMX_TX_CIF_CTRL, 0x00007000},
0046 { TEGRA210_AMX_CG, 0x1},
0047 { TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000},
0048 };
0049
0050 static void tegra210_amx_write_map_ram(struct tegra210_amx *amx)
0051 {
0052 int i;
0053
0054 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL,
0055 TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
0056 TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN |
0057 TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE);
0058
0059 for (i = 0; i < TEGRA210_AMX_RAM_DEPTH; i++)
0060 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA,
0061 amx->map[i]);
0062
0063 regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN0, amx->byte_mask[0]);
0064 regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN1, amx->byte_mask[1]);
0065 }
0066
0067 static int tegra210_amx_startup(struct snd_pcm_substream *substream,
0068 struct snd_soc_dai *dai)
0069 {
0070 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
0071 unsigned int val;
0072 int err;
0073
0074
0075 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val,
0076 !(val & 0x1), 10, 10000);
0077 if (err < 0) {
0078 dev_err(dai->dev, "failed to stop AMX, err = %d\n", err);
0079 return err;
0080 }
0081
0082
0083
0084
0085
0086
0087
0088 regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
0089 TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
0090 TEGRA210_AMX_SOFT_RESET_SOFT_EN);
0091
0092 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET,
0093 val, !(val & 0x1), 10, 10000);
0094 if (err < 0) {
0095 dev_err(dai->dev, "failed to reset AMX, err = %d\n", err);
0096 return err;
0097 }
0098
0099 return 0;
0100 }
0101
0102 static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev)
0103 {
0104 struct tegra210_amx *amx = dev_get_drvdata(dev);
0105
0106 regcache_cache_only(amx->regmap, true);
0107 regcache_mark_dirty(amx->regmap);
0108
0109 return 0;
0110 }
0111
0112 static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev)
0113 {
0114 struct tegra210_amx *amx = dev_get_drvdata(dev);
0115
0116 regcache_cache_only(amx->regmap, false);
0117 regcache_sync(amx->regmap);
0118
0119 regmap_update_bits(amx->regmap,
0120 TEGRA210_AMX_CTRL,
0121 TEGRA210_AMX_CTRL_RX_DEP_MASK,
0122 TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT);
0123
0124 tegra210_amx_write_map_ram(amx);
0125
0126 return 0;
0127 }
0128
0129 static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai,
0130 struct snd_pcm_hw_params *params,
0131 unsigned int reg)
0132 {
0133 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
0134 int channels, audio_bits;
0135 struct tegra_cif_conf cif_conf;
0136
0137 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
0138
0139 channels = params_channels(params);
0140
0141 switch (params_format(params)) {
0142 case SNDRV_PCM_FORMAT_S8:
0143 audio_bits = TEGRA_ACIF_BITS_8;
0144 break;
0145 case SNDRV_PCM_FORMAT_S16_LE:
0146 audio_bits = TEGRA_ACIF_BITS_16;
0147 break;
0148 case SNDRV_PCM_FORMAT_S32_LE:
0149 audio_bits = TEGRA_ACIF_BITS_32;
0150 break;
0151 default:
0152 return -EINVAL;
0153 }
0154
0155 cif_conf.audio_ch = channels;
0156 cif_conf.client_ch = channels;
0157 cif_conf.audio_bits = audio_bits;
0158 cif_conf.client_bits = audio_bits;
0159
0160 tegra_set_cif(amx->regmap, reg, &cif_conf);
0161
0162 return 0;
0163 }
0164
0165 static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream,
0166 struct snd_pcm_hw_params *params,
0167 struct snd_soc_dai *dai)
0168 {
0169 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
0170
0171 if (amx->soc_data->auto_disable) {
0172 regmap_write(amx->regmap,
0173 AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD),
0174 TEGRA194_MAX_FRAME_IDLE_COUNT);
0175 regmap_write(amx->regmap, TEGRA210_AMX_CYA, 1);
0176 }
0177
0178 return tegra210_amx_set_audio_cif(dai, params,
0179 AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL));
0180 }
0181
0182 static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream,
0183 struct snd_pcm_hw_params *params,
0184 struct snd_soc_dai *dai)
0185 {
0186 return tegra210_amx_set_audio_cif(dai, params,
0187 TEGRA210_AMX_TX_CIF_CTRL);
0188 }
0189
0190 static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol,
0191 struct snd_ctl_elem_value *ucontrol)
0192 {
0193 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0194 struct soc_mixer_control *mc =
0195 (struct soc_mixer_control *)kcontrol->private_value;
0196 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt);
0197 unsigned char *bytes_map = (unsigned char *)&amx->map;
0198 int reg = mc->reg;
0199 int enabled;
0200
0201 if (reg > 31)
0202 enabled = amx->byte_mask[1] & (1 << (reg - 32));
0203 else
0204 enabled = amx->byte_mask[0] & (1 << reg);
0205
0206 if (enabled)
0207 ucontrol->value.integer.value[0] = bytes_map[reg];
0208 else
0209 ucontrol->value.integer.value[0] = 0;
0210
0211 return 0;
0212 }
0213
0214 static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol,
0215 struct snd_ctl_elem_value *ucontrol)
0216 {
0217 struct soc_mixer_control *mc =
0218 (struct soc_mixer_control *)kcontrol->private_value;
0219 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0220 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt);
0221 unsigned char *bytes_map = (unsigned char *)&amx->map;
0222 int reg = mc->reg;
0223 int value = ucontrol->value.integer.value[0];
0224
0225 if (value == bytes_map[reg])
0226 return 0;
0227
0228 if (value >= 0 && value <= 255) {
0229
0230 bytes_map[reg] = value;
0231 if (reg > 31)
0232 amx->byte_mask[1] |= (1 << (reg - 32));
0233 else
0234 amx->byte_mask[0] |= (1 << reg);
0235 } else {
0236
0237 bytes_map[reg] = 0;
0238 if (reg > 31)
0239 amx->byte_mask[1] &= ~(1 << (reg - 32));
0240 else
0241 amx->byte_mask[0] &= ~(1 << reg);
0242 }
0243
0244 return 1;
0245 }
0246
0247 static const struct snd_soc_dai_ops tegra210_amx_out_dai_ops = {
0248 .hw_params = tegra210_amx_out_hw_params,
0249 .startup = tegra210_amx_startup,
0250 };
0251
0252 static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = {
0253 .hw_params = tegra210_amx_in_hw_params,
0254 };
0255
0256 #define IN_DAI(id) \
0257 { \
0258 .name = "AMX-RX-CIF" #id, \
0259 .playback = { \
0260 .stream_name = "RX" #id "-CIF-Playback",\
0261 .channels_min = 1, \
0262 .channels_max = 16, \
0263 .rates = SNDRV_PCM_RATE_8000_192000, \
0264 .formats = SNDRV_PCM_FMTBIT_S8 | \
0265 SNDRV_PCM_FMTBIT_S16_LE | \
0266 SNDRV_PCM_FMTBIT_S32_LE, \
0267 }, \
0268 .capture = { \
0269 .stream_name = "RX" #id "-CIF-Capture", \
0270 .channels_min = 1, \
0271 .channels_max = 16, \
0272 .rates = SNDRV_PCM_RATE_8000_192000, \
0273 .formats = SNDRV_PCM_FMTBIT_S8 | \
0274 SNDRV_PCM_FMTBIT_S16_LE | \
0275 SNDRV_PCM_FMTBIT_S32_LE, \
0276 }, \
0277 .ops = &tegra210_amx_in_dai_ops, \
0278 }
0279
0280 #define OUT_DAI \
0281 { \
0282 .name = "AMX-TX-CIF", \
0283 .playback = { \
0284 .stream_name = "TX-CIF-Playback", \
0285 .channels_min = 1, \
0286 .channels_max = 16, \
0287 .rates = SNDRV_PCM_RATE_8000_192000, \
0288 .formats = SNDRV_PCM_FMTBIT_S8 | \
0289 SNDRV_PCM_FMTBIT_S16_LE | \
0290 SNDRV_PCM_FMTBIT_S32_LE, \
0291 }, \
0292 .capture = { \
0293 .stream_name = "TX-CIF-Capture", \
0294 .channels_min = 1, \
0295 .channels_max = 16, \
0296 .rates = SNDRV_PCM_RATE_8000_192000, \
0297 .formats = SNDRV_PCM_FMTBIT_S8 | \
0298 SNDRV_PCM_FMTBIT_S16_LE | \
0299 SNDRV_PCM_FMTBIT_S32_LE, \
0300 }, \
0301 .ops = &tegra210_amx_out_dai_ops, \
0302 }
0303
0304 static struct snd_soc_dai_driver tegra210_amx_dais[] = {
0305 IN_DAI(1),
0306 IN_DAI(2),
0307 IN_DAI(3),
0308 IN_DAI(4),
0309 OUT_DAI,
0310 };
0311
0312 static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = {
0313 SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0),
0314 SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0),
0315 SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0),
0316 SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0),
0317 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE,
0318 TEGRA210_AMX_ENABLE_SHIFT, 0),
0319 };
0320
0321 #define STREAM_ROUTES(id, sname) \
0322 { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \
0323 { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname },\
0324 { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \
0325 { "TX", NULL, "RX" #id }, \
0326 { "TX-CIF-" sname, NULL, "TX" }, \
0327 { "XBAR-" sname, NULL, "TX-CIF-" sname }, \
0328 { "XBAR-RX", NULL, "XBAR-" sname }
0329
0330 #define AMX_ROUTES(id) \
0331 STREAM_ROUTES(id, "Playback"), \
0332 STREAM_ROUTES(id, "Capture")
0333
0334 static const struct snd_soc_dapm_route tegra210_amx_routes[] = {
0335 AMX_ROUTES(1),
0336 AMX_ROUTES(2),
0337 AMX_ROUTES(3),
0338 AMX_ROUTES(4),
0339 };
0340
0341 #define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \
0342 SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \
0343 tegra210_amx_get_byte_map, \
0344 tegra210_amx_put_byte_map)
0345
0346 static struct snd_kcontrol_new tegra210_amx_controls[] = {
0347 TEGRA210_AMX_BYTE_MAP_CTRL(0),
0348 TEGRA210_AMX_BYTE_MAP_CTRL(1),
0349 TEGRA210_AMX_BYTE_MAP_CTRL(2),
0350 TEGRA210_AMX_BYTE_MAP_CTRL(3),
0351 TEGRA210_AMX_BYTE_MAP_CTRL(4),
0352 TEGRA210_AMX_BYTE_MAP_CTRL(5),
0353 TEGRA210_AMX_BYTE_MAP_CTRL(6),
0354 TEGRA210_AMX_BYTE_MAP_CTRL(7),
0355 TEGRA210_AMX_BYTE_MAP_CTRL(8),
0356 TEGRA210_AMX_BYTE_MAP_CTRL(9),
0357 TEGRA210_AMX_BYTE_MAP_CTRL(10),
0358 TEGRA210_AMX_BYTE_MAP_CTRL(11),
0359 TEGRA210_AMX_BYTE_MAP_CTRL(12),
0360 TEGRA210_AMX_BYTE_MAP_CTRL(13),
0361 TEGRA210_AMX_BYTE_MAP_CTRL(14),
0362 TEGRA210_AMX_BYTE_MAP_CTRL(15),
0363 TEGRA210_AMX_BYTE_MAP_CTRL(16),
0364 TEGRA210_AMX_BYTE_MAP_CTRL(17),
0365 TEGRA210_AMX_BYTE_MAP_CTRL(18),
0366 TEGRA210_AMX_BYTE_MAP_CTRL(19),
0367 TEGRA210_AMX_BYTE_MAP_CTRL(20),
0368 TEGRA210_AMX_BYTE_MAP_CTRL(21),
0369 TEGRA210_AMX_BYTE_MAP_CTRL(22),
0370 TEGRA210_AMX_BYTE_MAP_CTRL(23),
0371 TEGRA210_AMX_BYTE_MAP_CTRL(24),
0372 TEGRA210_AMX_BYTE_MAP_CTRL(25),
0373 TEGRA210_AMX_BYTE_MAP_CTRL(26),
0374 TEGRA210_AMX_BYTE_MAP_CTRL(27),
0375 TEGRA210_AMX_BYTE_MAP_CTRL(28),
0376 TEGRA210_AMX_BYTE_MAP_CTRL(29),
0377 TEGRA210_AMX_BYTE_MAP_CTRL(30),
0378 TEGRA210_AMX_BYTE_MAP_CTRL(31),
0379 TEGRA210_AMX_BYTE_MAP_CTRL(32),
0380 TEGRA210_AMX_BYTE_MAP_CTRL(33),
0381 TEGRA210_AMX_BYTE_MAP_CTRL(34),
0382 TEGRA210_AMX_BYTE_MAP_CTRL(35),
0383 TEGRA210_AMX_BYTE_MAP_CTRL(36),
0384 TEGRA210_AMX_BYTE_MAP_CTRL(37),
0385 TEGRA210_AMX_BYTE_MAP_CTRL(38),
0386 TEGRA210_AMX_BYTE_MAP_CTRL(39),
0387 TEGRA210_AMX_BYTE_MAP_CTRL(40),
0388 TEGRA210_AMX_BYTE_MAP_CTRL(41),
0389 TEGRA210_AMX_BYTE_MAP_CTRL(42),
0390 TEGRA210_AMX_BYTE_MAP_CTRL(43),
0391 TEGRA210_AMX_BYTE_MAP_CTRL(44),
0392 TEGRA210_AMX_BYTE_MAP_CTRL(45),
0393 TEGRA210_AMX_BYTE_MAP_CTRL(46),
0394 TEGRA210_AMX_BYTE_MAP_CTRL(47),
0395 TEGRA210_AMX_BYTE_MAP_CTRL(48),
0396 TEGRA210_AMX_BYTE_MAP_CTRL(49),
0397 TEGRA210_AMX_BYTE_MAP_CTRL(50),
0398 TEGRA210_AMX_BYTE_MAP_CTRL(51),
0399 TEGRA210_AMX_BYTE_MAP_CTRL(52),
0400 TEGRA210_AMX_BYTE_MAP_CTRL(53),
0401 TEGRA210_AMX_BYTE_MAP_CTRL(54),
0402 TEGRA210_AMX_BYTE_MAP_CTRL(55),
0403 TEGRA210_AMX_BYTE_MAP_CTRL(56),
0404 TEGRA210_AMX_BYTE_MAP_CTRL(57),
0405 TEGRA210_AMX_BYTE_MAP_CTRL(58),
0406 TEGRA210_AMX_BYTE_MAP_CTRL(59),
0407 TEGRA210_AMX_BYTE_MAP_CTRL(60),
0408 TEGRA210_AMX_BYTE_MAP_CTRL(61),
0409 TEGRA210_AMX_BYTE_MAP_CTRL(62),
0410 TEGRA210_AMX_BYTE_MAP_CTRL(63),
0411 };
0412
0413 static const struct snd_soc_component_driver tegra210_amx_cmpnt = {
0414 .dapm_widgets = tegra210_amx_widgets,
0415 .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets),
0416 .dapm_routes = tegra210_amx_routes,
0417 .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes),
0418 .controls = tegra210_amx_controls,
0419 .num_controls = ARRAY_SIZE(tegra210_amx_controls),
0420 };
0421
0422 static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg)
0423 {
0424 switch (reg) {
0425 case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL:
0426 case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG:
0427 case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA:
0428 case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA:
0429 return true;
0430 default:
0431 return false;
0432 }
0433 }
0434
0435 static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg)
0436 {
0437 switch (reg) {
0438 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD:
0439 return true;
0440 default:
0441 return tegra210_amx_wr_reg(dev, reg);
0442 }
0443 }
0444
0445 static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg)
0446 {
0447 switch (reg) {
0448 case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA:
0449 return true;
0450 default:
0451 return false;
0452 }
0453 }
0454
0455 static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg)
0456 {
0457 switch (reg) {
0458 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD:
0459 return true;
0460 default:
0461 return tegra210_amx_rd_reg(dev, reg);
0462 }
0463 }
0464
0465 static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg)
0466 {
0467 switch (reg) {
0468 case TEGRA210_AMX_RX_STATUS:
0469 case TEGRA210_AMX_RX_INT_STATUS:
0470 case TEGRA210_AMX_RX_INT_SET:
0471 case TEGRA210_AMX_TX_STATUS:
0472 case TEGRA210_AMX_TX_INT_STATUS:
0473 case TEGRA210_AMX_TX_INT_SET:
0474 case TEGRA210_AMX_SOFT_RESET:
0475 case TEGRA210_AMX_STATUS:
0476 case TEGRA210_AMX_INT_STATUS:
0477 case TEGRA210_AMX_CFG_RAM_CTRL:
0478 case TEGRA210_AMX_CFG_RAM_DATA:
0479 return true;
0480 default:
0481 break;
0482 }
0483
0484 return false;
0485 }
0486
0487 static const struct regmap_config tegra210_amx_regmap_config = {
0488 .reg_bits = 32,
0489 .reg_stride = 4,
0490 .val_bits = 32,
0491 .max_register = TEGRA210_AMX_CFG_RAM_DATA,
0492 .writeable_reg = tegra210_amx_wr_reg,
0493 .readable_reg = tegra210_amx_rd_reg,
0494 .volatile_reg = tegra210_amx_volatile_reg,
0495 .reg_defaults = tegra210_amx_reg_defaults,
0496 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults),
0497 .cache_type = REGCACHE_FLAT,
0498 };
0499
0500 static const struct regmap_config tegra194_amx_regmap_config = {
0501 .reg_bits = 32,
0502 .reg_stride = 4,
0503 .val_bits = 32,
0504 .max_register = TEGRA194_AMX_RX4_LAST_FRAME_PERIOD,
0505 .writeable_reg = tegra194_amx_wr_reg,
0506 .readable_reg = tegra194_amx_rd_reg,
0507 .volatile_reg = tegra210_amx_volatile_reg,
0508 .reg_defaults = tegra210_amx_reg_defaults,
0509 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults),
0510 .cache_type = REGCACHE_FLAT,
0511 };
0512
0513 static const struct tegra210_amx_soc_data soc_data_tegra210 = {
0514 .regmap_conf = &tegra210_amx_regmap_config,
0515 };
0516
0517 static const struct tegra210_amx_soc_data soc_data_tegra194 = {
0518 .regmap_conf = &tegra194_amx_regmap_config,
0519 .auto_disable = true,
0520 };
0521
0522 static const struct of_device_id tegra210_amx_of_match[] = {
0523 { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 },
0524 { .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 },
0525 {},
0526 };
0527 MODULE_DEVICE_TABLE(of, tegra210_amx_of_match);
0528
0529 static int tegra210_amx_platform_probe(struct platform_device *pdev)
0530 {
0531 struct device *dev = &pdev->dev;
0532 struct tegra210_amx *amx;
0533 void __iomem *regs;
0534 int err;
0535 const struct of_device_id *match;
0536 struct tegra210_amx_soc_data *soc_data;
0537
0538 match = of_match_device(tegra210_amx_of_match, dev);
0539
0540 soc_data = (struct tegra210_amx_soc_data *)match->data;
0541
0542 amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL);
0543 if (!amx)
0544 return -ENOMEM;
0545
0546 amx->soc_data = soc_data;
0547
0548 dev_set_drvdata(dev, amx);
0549
0550 regs = devm_platform_ioremap_resource(pdev, 0);
0551 if (IS_ERR(regs))
0552 return PTR_ERR(regs);
0553
0554 amx->regmap = devm_regmap_init_mmio(dev, regs,
0555 soc_data->regmap_conf);
0556 if (IS_ERR(amx->regmap)) {
0557 dev_err(dev, "regmap init failed\n");
0558 return PTR_ERR(amx->regmap);
0559 }
0560
0561 regcache_cache_only(amx->regmap, true);
0562
0563 err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt,
0564 tegra210_amx_dais,
0565 ARRAY_SIZE(tegra210_amx_dais));
0566 if (err) {
0567 dev_err(dev, "can't register AMX component, err: %d\n", err);
0568 return err;
0569 }
0570
0571 pm_runtime_enable(dev);
0572
0573 return 0;
0574 }
0575
0576 static int tegra210_amx_platform_remove(struct platform_device *pdev)
0577 {
0578 pm_runtime_disable(&pdev->dev);
0579
0580 return 0;
0581 }
0582
0583 static const struct dev_pm_ops tegra210_amx_pm_ops = {
0584 SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
0585 tegra210_amx_runtime_resume, NULL)
0586 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0587 pm_runtime_force_resume)
0588 };
0589
0590 static struct platform_driver tegra210_amx_driver = {
0591 .driver = {
0592 .name = "tegra210-amx",
0593 .of_match_table = tegra210_amx_of_match,
0594 .pm = &tegra210_amx_pm_ops,
0595 },
0596 .probe = tegra210_amx_platform_probe,
0597 .remove = tegra210_amx_platform_remove,
0598 };
0599 module_platform_driver(tegra210_amx_driver);
0600
0601 MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
0602 MODULE_DESCRIPTION("Tegra210 AMX ASoC driver");
0603 MODULE_LICENSE("GPL v2");