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_mvc.h"
0022 #include "tegra_cif.h"
0023
0024 static const struct reg_default tegra210_mvc_reg_defaults[] = {
0025 { TEGRA210_MVC_RX_INT_MASK, 0x00000001},
0026 { TEGRA210_MVC_RX_CIF_CTRL, 0x00007700},
0027 { TEGRA210_MVC_TX_INT_MASK, 0x00000001},
0028 { TEGRA210_MVC_TX_CIF_CTRL, 0x00007700},
0029 { TEGRA210_MVC_CG, 0x1},
0030 { TEGRA210_MVC_CTRL, TEGRA210_MVC_CTRL_DEFAULT},
0031 { TEGRA210_MVC_INIT_VOL, 0x00800000},
0032 { TEGRA210_MVC_TARGET_VOL, 0x00800000},
0033 { TEGRA210_MVC_DURATION, 0x000012c0},
0034 { TEGRA210_MVC_DURATION_INV, 0x0006d3a0},
0035 { TEGRA210_MVC_POLY_N1, 0x0000007d},
0036 { TEGRA210_MVC_POLY_N2, 0x00000271},
0037 { TEGRA210_MVC_PEAK_CTRL, 0x000012c0},
0038 { TEGRA210_MVC_CFG_RAM_CTRL, 0x00004000},
0039 };
0040
0041 static const struct tegra210_mvc_gain_params gain_params = {
0042 .poly_coeff = { 23738319, 659403, -3680,
0043 15546680, 2530732, -120985,
0044 12048422, 5527252, -785042 },
0045 .poly_n1 = 16,
0046 .poly_n2 = 63,
0047 .duration = 150,
0048 .duration_inv = 14316558,
0049 };
0050
0051 static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev)
0052 {
0053 struct tegra210_mvc *mvc = dev_get_drvdata(dev);
0054
0055 regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &(mvc->ctrl_value));
0056
0057 regcache_cache_only(mvc->regmap, true);
0058 regcache_mark_dirty(mvc->regmap);
0059
0060 return 0;
0061 }
0062
0063 static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev)
0064 {
0065 struct tegra210_mvc *mvc = dev_get_drvdata(dev);
0066
0067 regcache_cache_only(mvc->regmap, false);
0068 regcache_sync(mvc->regmap);
0069
0070 regmap_write(mvc->regmap, TEGRA210_MVC_CTRL, mvc->ctrl_value);
0071 regmap_update_bits(mvc->regmap,
0072 TEGRA210_MVC_SWITCH,
0073 TEGRA210_MVC_VOLUME_SWITCH_MASK,
0074 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
0075
0076 return 0;
0077 }
0078
0079 static void tegra210_mvc_write_ram(struct regmap *regmap)
0080 {
0081 int i;
0082
0083 regmap_write(regmap, TEGRA210_MVC_CFG_RAM_CTRL,
0084 TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN |
0085 TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN |
0086 TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE);
0087
0088 for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++)
0089 regmap_write(regmap, TEGRA210_MVC_CFG_RAM_DATA,
0090 gain_params.poly_coeff[i]);
0091 }
0092
0093 static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val)
0094 {
0095
0096
0097
0098
0099
0100
0101 if (mvc->curve_type == CURVE_POLY) {
0102 if (val > 10000)
0103 val = 10000;
0104 mvc->volume[chan] = ((val * (1<<8)) / 100) << 16;
0105 } else {
0106 val -= 12000;
0107 mvc->volume[chan] = (val * (1<<8)) / 100;
0108 }
0109 }
0110
0111 static u32 tegra210_mvc_get_ctrl_reg(struct snd_kcontrol *kcontrol)
0112 {
0113 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0114 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0115 u32 val;
0116
0117 pm_runtime_get_sync(cmpnt->dev);
0118 regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &val);
0119 pm_runtime_put(cmpnt->dev);
0120
0121 return val;
0122 }
0123
0124 static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol,
0125 struct snd_ctl_elem_value *ucontrol)
0126 {
0127 u32 val = tegra210_mvc_get_ctrl_reg(kcontrol);
0128 u8 mute_mask = TEGRA210_GET_MUTE_VAL(val);
0129
0130
0131
0132
0133
0134
0135
0136
0137 if (val & TEGRA210_MVC_PER_CHAN_CTRL_EN) {
0138 ucontrol->value.integer.value[0] = mute_mask;
0139 } else {
0140 if (mute_mask & TEGRA210_MVC_CH0_MUTE_EN)
0141 ucontrol->value.integer.value[0] =
0142 TEGRA210_MUTE_MASK_EN;
0143 else
0144 ucontrol->value.integer.value[0] = 0;
0145 }
0146
0147 return 0;
0148 }
0149
0150 static int tegra210_mvc_get_master_mute(struct snd_kcontrol *kcontrol,
0151 struct snd_ctl_elem_value *ucontrol)
0152 {
0153 u32 val = tegra210_mvc_get_ctrl_reg(kcontrol);
0154 u8 mute_mask = TEGRA210_GET_MUTE_VAL(val);
0155
0156
0157
0158
0159
0160
0161
0162
0163 if (!(val & TEGRA210_MVC_PER_CHAN_CTRL_EN)) {
0164 ucontrol->value.integer.value[0] =
0165 mute_mask & TEGRA210_MVC_CH0_MUTE_EN;
0166 } else {
0167 if (mute_mask == TEGRA210_MUTE_MASK_EN)
0168 ucontrol->value.integer.value[0] =
0169 TEGRA210_MVC_CH0_MUTE_EN;
0170 else
0171 ucontrol->value.integer.value[0] = 0;
0172 }
0173
0174 return 0;
0175 }
0176
0177 static int tegra210_mvc_volume_switch_timeout(struct snd_soc_component *cmpnt)
0178 {
0179 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0180 u32 value;
0181 int err;
0182
0183 err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH,
0184 value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK),
0185 10, 10000);
0186 if (err < 0)
0187 dev_err(cmpnt->dev,
0188 "Volume switch trigger is still active, err = %d\n",
0189 err);
0190
0191 return err;
0192 }
0193
0194 static int tegra210_mvc_update_mute(struct snd_kcontrol *kcontrol,
0195 struct snd_ctl_elem_value *ucontrol,
0196 bool per_chan_ctrl)
0197 {
0198 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0199 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0200 u32 mute_val = ucontrol->value.integer.value[0];
0201 u32 per_ch_ctrl_val;
0202 bool change = false;
0203 int err;
0204
0205 pm_runtime_get_sync(cmpnt->dev);
0206
0207 err = tegra210_mvc_volume_switch_timeout(cmpnt);
0208 if (err < 0)
0209 goto end;
0210
0211 if (per_chan_ctrl) {
0212 per_ch_ctrl_val = TEGRA210_MVC_PER_CHAN_CTRL_EN;
0213 } else {
0214 per_ch_ctrl_val = 0;
0215
0216 if (mute_val)
0217 mute_val = TEGRA210_MUTE_MASK_EN;
0218 }
0219
0220 regmap_update_bits_check(mvc->regmap, TEGRA210_MVC_CTRL,
0221 TEGRA210_MVC_MUTE_MASK,
0222 mute_val << TEGRA210_MVC_MUTE_SHIFT,
0223 &change);
0224
0225 if (change) {
0226 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
0227 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
0228 per_ch_ctrl_val);
0229
0230 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
0231 TEGRA210_MVC_VOLUME_SWITCH_MASK,
0232 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
0233 }
0234
0235 end:
0236 pm_runtime_put(cmpnt->dev);
0237
0238 if (err < 0)
0239 return err;
0240
0241 if (change)
0242 return 1;
0243
0244 return 0;
0245 }
0246
0247 static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
0248 struct snd_ctl_elem_value *ucontrol)
0249 {
0250 return tegra210_mvc_update_mute(kcontrol, ucontrol, true);
0251 }
0252
0253 static int tegra210_mvc_put_master_mute(struct snd_kcontrol *kcontrol,
0254 struct snd_ctl_elem_value *ucontrol)
0255 {
0256 return tegra210_mvc_update_mute(kcontrol, ucontrol, false);
0257 }
0258
0259 static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol,
0260 struct snd_ctl_elem_value *ucontrol)
0261 {
0262 struct soc_mixer_control *mc =
0263 (struct soc_mixer_control *)kcontrol->private_value;
0264 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0265 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0266 u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL);
0267 s32 val = mvc->volume[chan];
0268
0269 if (mvc->curve_type == CURVE_POLY) {
0270 val = ((val >> 16) * 100) >> 8;
0271 } else {
0272 val = (val * 100) >> 8;
0273 val += 12000;
0274 }
0275
0276 ucontrol->value.integer.value[0] = val;
0277
0278 return 0;
0279 }
0280
0281 static int tegra210_mvc_get_master_vol(struct snd_kcontrol *kcontrol,
0282 struct snd_ctl_elem_value *ucontrol)
0283 {
0284 return tegra210_mvc_get_vol(kcontrol, ucontrol);
0285 }
0286
0287 static int tegra210_mvc_update_vol(struct snd_kcontrol *kcontrol,
0288 struct snd_ctl_elem_value *ucontrol,
0289 bool per_ch_enable)
0290 {
0291 struct soc_mixer_control *mc =
0292 (struct soc_mixer_control *)kcontrol->private_value;
0293 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0294 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0295 u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL);
0296 int old_volume = mvc->volume[chan];
0297 int err, i;
0298
0299 pm_runtime_get_sync(cmpnt->dev);
0300
0301 err = tegra210_mvc_volume_switch_timeout(cmpnt);
0302 if (err < 0)
0303 goto end;
0304
0305 tegra210_mvc_conv_vol(mvc, chan, ucontrol->value.integer.value[0]);
0306
0307 if (mvc->volume[chan] == old_volume) {
0308 err = 0;
0309 goto end;
0310 }
0311
0312 if (per_ch_enable) {
0313 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
0314 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
0315 TEGRA210_MVC_PER_CHAN_CTRL_EN);
0316 } else {
0317 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
0318 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, 0);
0319
0320 for (i = 1; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++)
0321 mvc->volume[i] = mvc->volume[chan];
0322 }
0323
0324
0325 regmap_write(mvc->regmap,
0326 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan),
0327 mvc->volume[chan]);
0328
0329 regmap_write(mvc->regmap, mc->reg, mvc->volume[chan]);
0330
0331 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
0332 TEGRA210_MVC_VOLUME_SWITCH_MASK,
0333 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
0334
0335 err = 1;
0336
0337 end:
0338 pm_runtime_put(cmpnt->dev);
0339
0340 return err;
0341 }
0342
0343 static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
0344 struct snd_ctl_elem_value *ucontrol)
0345 {
0346 return tegra210_mvc_update_vol(kcontrol, ucontrol, true);
0347 }
0348
0349 static int tegra210_mvc_put_master_vol(struct snd_kcontrol *kcontrol,
0350 struct snd_ctl_elem_value *ucontrol)
0351 {
0352 return tegra210_mvc_update_vol(kcontrol, ucontrol, false);
0353 }
0354
0355 static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc *mvc,
0356 struct device *dev)
0357 {
0358 int i;
0359
0360
0361 if (mvc->curve_type == CURVE_POLY) {
0362 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++)
0363 mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY;
0364 } else {
0365 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++)
0366 mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR;
0367 }
0368
0369 pm_runtime_get_sync(dev);
0370
0371
0372 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
0373 TEGRA210_MVC_CURVE_TYPE_MASK,
0374 mvc->curve_type <<
0375 TEGRA210_MVC_CURVE_TYPE_SHIFT);
0376
0377
0378 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) {
0379 regmap_write(mvc->regmap,
0380 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, i),
0381 mvc->volume[i]);
0382 regmap_write(mvc->regmap,
0383 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, i),
0384 mvc->volume[i]);
0385 }
0386
0387
0388 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
0389 TEGRA210_MVC_VOLUME_SWITCH_MASK,
0390 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
0391
0392 pm_runtime_put(dev);
0393 }
0394
0395 static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol,
0396 struct snd_ctl_elem_value *ucontrol)
0397 {
0398 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0399 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0400
0401 ucontrol->value.enumerated.item[0] = mvc->curve_type;
0402
0403 return 0;
0404 }
0405
0406 static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol,
0407 struct snd_ctl_elem_value *ucontrol)
0408 {
0409 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0410 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
0411 unsigned int value;
0412
0413 regmap_read(mvc->regmap, TEGRA210_MVC_ENABLE, &value);
0414 if (value & TEGRA210_MVC_EN) {
0415 dev_err(cmpnt->dev,
0416 "Curve type can't be set when MVC is running\n");
0417 return -EINVAL;
0418 }
0419
0420 if (mvc->curve_type == ucontrol->value.enumerated.item[0])
0421 return 0;
0422
0423 mvc->curve_type = ucontrol->value.enumerated.item[0];
0424
0425 tegra210_mvc_reset_vol_settings(mvc, cmpnt->dev);
0426
0427 return 1;
0428 }
0429
0430 static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc,
0431 struct snd_pcm_hw_params *params,
0432 unsigned int reg)
0433 {
0434 unsigned int channels, audio_bits;
0435 struct tegra_cif_conf cif_conf;
0436
0437 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
0438
0439 channels = params_channels(params);
0440
0441 switch (params_format(params)) {
0442 case SNDRV_PCM_FORMAT_S16_LE:
0443 audio_bits = TEGRA_ACIF_BITS_16;
0444 break;
0445 case SNDRV_PCM_FORMAT_S32_LE:
0446 audio_bits = TEGRA_ACIF_BITS_32;
0447 break;
0448 default:
0449 return -EINVAL;
0450 }
0451
0452 cif_conf.audio_ch = channels;
0453 cif_conf.client_ch = channels;
0454 cif_conf.audio_bits = audio_bits;
0455 cif_conf.client_bits = audio_bits;
0456
0457 tegra_set_cif(mvc->regmap, reg, &cif_conf);
0458
0459 return 0;
0460 }
0461
0462 static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream,
0463 struct snd_pcm_hw_params *params,
0464 struct snd_soc_dai *dai)
0465 {
0466 struct device *dev = dai->dev;
0467 struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai);
0468 int err, val;
0469
0470
0471
0472
0473
0474
0475
0476 regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
0477
0478 err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SOFT_RESET,
0479 val, !val, 10, 10000);
0480 if (err < 0) {
0481 dev_err(dev, "SW reset failed, err = %d\n", err);
0482 return err;
0483 }
0484
0485
0486 err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_RX_CIF_CTRL);
0487 if (err) {
0488 dev_err(dev, "Can't set MVC RX CIF: %d\n", err);
0489 return err;
0490 }
0491
0492
0493 err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_TX_CIF_CTRL);
0494 if (err) {
0495 dev_err(dev, "Can't set MVC TX CIF: %d\n", err);
0496 return err;
0497 }
0498
0499 tegra210_mvc_write_ram(mvc->regmap);
0500
0501
0502 regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, gain_params.poly_n1);
0503 regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N2, gain_params.poly_n2);
0504 regmap_write(mvc->regmap, TEGRA210_MVC_DURATION, gain_params.duration);
0505
0506
0507 regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV,
0508 gain_params.duration_inv);
0509
0510 return 0;
0511 }
0512
0513 static const struct snd_soc_dai_ops tegra210_mvc_dai_ops = {
0514 .hw_params = tegra210_mvc_hw_params,
0515 };
0516
0517 static const char * const tegra210_mvc_curve_type_text[] = {
0518 "Poly",
0519 "Linear",
0520 };
0521
0522 static const struct soc_enum tegra210_mvc_curve_type_ctrl =
0523 SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text);
0524
0525 #define TEGRA210_MVC_VOL_CTRL(chan) \
0526 SOC_SINGLE_EXT("Channel" #chan " Volume", \
0527 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, \
0528 (chan - 1)), \
0529 0, 16000, 0, tegra210_mvc_get_vol, \
0530 tegra210_mvc_put_vol)
0531
0532 static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = {
0533
0534 TEGRA210_MVC_VOL_CTRL(1),
0535 TEGRA210_MVC_VOL_CTRL(2),
0536 TEGRA210_MVC_VOL_CTRL(3),
0537 TEGRA210_MVC_VOL_CTRL(4),
0538 TEGRA210_MVC_VOL_CTRL(5),
0539 TEGRA210_MVC_VOL_CTRL(6),
0540 TEGRA210_MVC_VOL_CTRL(7),
0541 TEGRA210_MVC_VOL_CTRL(8),
0542
0543
0544 SOC_SINGLE_EXT("Per Chan Mute Mask",
0545 TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0,
0546 tegra210_mvc_get_mute, tegra210_mvc_put_mute),
0547
0548
0549 SOC_SINGLE_EXT("Volume", TEGRA210_MVC_TARGET_VOL, 0, 16000, 0,
0550 tegra210_mvc_get_master_vol,
0551 tegra210_mvc_put_master_vol),
0552
0553
0554 SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL, 0, 1, 0,
0555 tegra210_mvc_get_master_mute,
0556 tegra210_mvc_put_master_mute),
0557
0558 SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl,
0559 tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type),
0560 };
0561
0562 static struct snd_soc_dai_driver tegra210_mvc_dais[] = {
0563
0564 {
0565 .name = "MVC-RX-CIF",
0566 .playback = {
0567 .stream_name = "RX-CIF-Playback",
0568 .channels_min = 1,
0569 .channels_max = 8,
0570 .rates = SNDRV_PCM_RATE_8000_192000,
0571 .formats = SNDRV_PCM_FMTBIT_S8 |
0572 SNDRV_PCM_FMTBIT_S16_LE |
0573 SNDRV_PCM_FMTBIT_S32_LE,
0574 },
0575 .capture = {
0576 .stream_name = "RX-CIF-Capture",
0577 .channels_min = 1,
0578 .channels_max = 8,
0579 .rates = SNDRV_PCM_RATE_8000_192000,
0580 .formats = SNDRV_PCM_FMTBIT_S8 |
0581 SNDRV_PCM_FMTBIT_S16_LE |
0582 SNDRV_PCM_FMTBIT_S32_LE,
0583 },
0584 },
0585
0586
0587 {
0588 .name = "MVC-TX-CIF",
0589 .playback = {
0590 .stream_name = "TX-CIF-Playback",
0591 .channels_min = 1,
0592 .channels_max = 8,
0593 .rates = SNDRV_PCM_RATE_8000_192000,
0594 .formats = SNDRV_PCM_FMTBIT_S8 |
0595 SNDRV_PCM_FMTBIT_S16_LE |
0596 SNDRV_PCM_FMTBIT_S32_LE,
0597 },
0598 .capture = {
0599 .stream_name = "TX-CIF-Capture",
0600 .channels_min = 1,
0601 .channels_max = 8,
0602 .rates = SNDRV_PCM_RATE_8000_192000,
0603 .formats = SNDRV_PCM_FMTBIT_S8 |
0604 SNDRV_PCM_FMTBIT_S16_LE |
0605 SNDRV_PCM_FMTBIT_S32_LE,
0606 },
0607 .ops = &tegra210_mvc_dai_ops,
0608 }
0609 };
0610
0611 static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = {
0612 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0613 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_MVC_ENABLE,
0614 TEGRA210_MVC_EN_SHIFT, 0),
0615 };
0616
0617 #define MVC_ROUTES(sname) \
0618 { "RX XBAR-" sname, NULL, "XBAR-TX" }, \
0619 { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \
0620 { "RX", NULL, "RX-CIF-" sname }, \
0621 { "TX-CIF-" sname, NULL, "TX" }, \
0622 { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \
0623 { "XBAR-RX", NULL, "TX XBAR-" sname }
0624
0625 static const struct snd_soc_dapm_route tegra210_mvc_routes[] = {
0626 { "TX", NULL, "RX" },
0627 MVC_ROUTES("Playback"),
0628 MVC_ROUTES("Capture"),
0629 };
0630
0631 static const struct snd_soc_component_driver tegra210_mvc_cmpnt = {
0632 .dapm_widgets = tegra210_mvc_widgets,
0633 .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets),
0634 .dapm_routes = tegra210_mvc_routes,
0635 .num_dapm_routes = ARRAY_SIZE(tegra210_mvc_routes),
0636 .controls = tegra210_mvc_vol_ctrl,
0637 .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl),
0638 };
0639
0640 static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg)
0641 {
0642 switch (reg) {
0643 case TEGRA210_MVC_RX_STATUS ... TEGRA210_MVC_CONFIG_ERR_TYPE:
0644 return true;
0645 default:
0646 return false;
0647 };
0648 }
0649
0650 static bool tegra210_mvc_wr_reg(struct device *dev, unsigned int reg)
0651 {
0652 switch (reg) {
0653 case TEGRA210_MVC_RX_INT_MASK ... TEGRA210_MVC_RX_CIF_CTRL:
0654 case TEGRA210_MVC_TX_INT_MASK ... TEGRA210_MVC_TX_CIF_CTRL:
0655 case TEGRA210_MVC_ENABLE ... TEGRA210_MVC_CG:
0656 case TEGRA210_MVC_CTRL ... TEGRA210_MVC_CFG_RAM_DATA:
0657 return true;
0658 default:
0659 return false;
0660 }
0661 }
0662
0663 static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg)
0664 {
0665 switch (reg) {
0666 case TEGRA210_MVC_RX_STATUS:
0667 case TEGRA210_MVC_RX_INT_STATUS:
0668 case TEGRA210_MVC_RX_INT_SET:
0669
0670 case TEGRA210_MVC_TX_STATUS:
0671 case TEGRA210_MVC_TX_INT_STATUS:
0672 case TEGRA210_MVC_TX_INT_SET:
0673
0674 case TEGRA210_MVC_SOFT_RESET:
0675 case TEGRA210_MVC_STATUS:
0676 case TEGRA210_MVC_INT_STATUS:
0677 case TEGRA210_MVC_SWITCH:
0678 case TEGRA210_MVC_CFG_RAM_CTRL:
0679 case TEGRA210_MVC_CFG_RAM_DATA:
0680 case TEGRA210_MVC_PEAK_VALUE:
0681 case TEGRA210_MVC_CTRL:
0682 return true;
0683 default:
0684 return false;
0685 }
0686 }
0687
0688 static const struct regmap_config tegra210_mvc_regmap_config = {
0689 .reg_bits = 32,
0690 .reg_stride = 4,
0691 .val_bits = 32,
0692 .max_register = TEGRA210_MVC_CONFIG_ERR_TYPE,
0693 .writeable_reg = tegra210_mvc_wr_reg,
0694 .readable_reg = tegra210_mvc_rd_reg,
0695 .volatile_reg = tegra210_mvc_volatile_reg,
0696 .reg_defaults = tegra210_mvc_reg_defaults,
0697 .num_reg_defaults = ARRAY_SIZE(tegra210_mvc_reg_defaults),
0698 .cache_type = REGCACHE_FLAT,
0699 };
0700
0701 static const struct of_device_id tegra210_mvc_of_match[] = {
0702 { .compatible = "nvidia,tegra210-mvc" },
0703 {},
0704 };
0705 MODULE_DEVICE_TABLE(of, tegra210_mvc_of_match);
0706
0707 static int tegra210_mvc_platform_probe(struct platform_device *pdev)
0708 {
0709 struct device *dev = &pdev->dev;
0710 struct tegra210_mvc *mvc;
0711 void __iomem *regs;
0712 int err;
0713
0714 mvc = devm_kzalloc(dev, sizeof(*mvc), GFP_KERNEL);
0715 if (!mvc)
0716 return -ENOMEM;
0717
0718 dev_set_drvdata(dev, mvc);
0719
0720 mvc->curve_type = CURVE_LINEAR;
0721 mvc->ctrl_value = TEGRA210_MVC_CTRL_DEFAULT;
0722
0723 regs = devm_platform_ioremap_resource(pdev, 0);
0724 if (IS_ERR(regs))
0725 return PTR_ERR(regs);
0726
0727 mvc->regmap = devm_regmap_init_mmio(dev, regs,
0728 &tegra210_mvc_regmap_config);
0729 if (IS_ERR(mvc->regmap)) {
0730 dev_err(dev, "regmap init failed\n");
0731 return PTR_ERR(mvc->regmap);
0732 }
0733
0734 regcache_cache_only(mvc->regmap, true);
0735
0736 err = devm_snd_soc_register_component(dev, &tegra210_mvc_cmpnt,
0737 tegra210_mvc_dais,
0738 ARRAY_SIZE(tegra210_mvc_dais));
0739 if (err) {
0740 dev_err(dev, "can't register MVC component, err: %d\n", err);
0741 return err;
0742 }
0743
0744 pm_runtime_enable(dev);
0745
0746 tegra210_mvc_reset_vol_settings(mvc, &pdev->dev);
0747
0748 return 0;
0749 }
0750
0751 static int tegra210_mvc_platform_remove(struct platform_device *pdev)
0752 {
0753 pm_runtime_disable(&pdev->dev);
0754
0755 return 0;
0756 }
0757
0758 static const struct dev_pm_ops tegra210_mvc_pm_ops = {
0759 SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
0760 tegra210_mvc_runtime_resume, NULL)
0761 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0762 pm_runtime_force_resume)
0763 };
0764
0765 static struct platform_driver tegra210_mvc_driver = {
0766 .driver = {
0767 .name = "tegra210-mvc",
0768 .of_match_table = tegra210_mvc_of_match,
0769 .pm = &tegra210_mvc_pm_ops,
0770 },
0771 .probe = tegra210_mvc_platform_probe,
0772 .remove = tegra210_mvc_platform_remove,
0773 };
0774 module_platform_driver(tegra210_mvc_driver)
0775
0776 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
0777 MODULE_DESCRIPTION("Tegra210 MVC ASoC driver");
0778 MODULE_LICENSE("GPL v2");