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_mbdrc.h"
0022 #include "tegra210_ope.h"
0023 #include "tegra210_peq.h"
0024 #include "tegra_cif.h"
0025
0026 static const struct reg_default tegra210_ope_reg_defaults[] = {
0027 { TEGRA210_OPE_RX_INT_MASK, 0x00000001},
0028 { TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
0029 { TEGRA210_OPE_TX_INT_MASK, 0x00000001},
0030 { TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
0031 { TEGRA210_OPE_CG, 0x1},
0032 };
0033
0034 static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
0035 struct snd_pcm_hw_params *params,
0036 unsigned int reg)
0037 {
0038 int channels, audio_bits;
0039 struct tegra_cif_conf cif_conf;
0040
0041 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
0042
0043 channels = params_channels(params);
0044 if (channels < 2)
0045 return -EINVAL;
0046
0047 switch (params_format(params)) {
0048 case SNDRV_PCM_FORMAT_S16_LE:
0049 audio_bits = TEGRA_ACIF_BITS_16;
0050 break;
0051 case SNDRV_PCM_FORMAT_S32_LE:
0052 audio_bits = TEGRA_ACIF_BITS_32;
0053 break;
0054 default:
0055 return -EINVAL;
0056 }
0057
0058 cif_conf.audio_ch = channels;
0059 cif_conf.client_ch = channels;
0060 cif_conf.audio_bits = audio_bits;
0061 cif_conf.client_bits = audio_bits;
0062
0063 tegra_set_cif(ope->regmap, reg, &cif_conf);
0064
0065 return 0;
0066 }
0067
0068 static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
0069 struct snd_pcm_hw_params *params,
0070 struct snd_soc_dai *dai)
0071 {
0072 struct device *dev = dai->dev;
0073 struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
0074 int err;
0075
0076
0077 err = tegra210_ope_set_audio_cif(ope, params,
0078 TEGRA210_OPE_RX_CIF_CTRL);
0079 if (err) {
0080 dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
0081 return err;
0082 }
0083
0084 err = tegra210_ope_set_audio_cif(ope, params,
0085 TEGRA210_OPE_TX_CIF_CTRL);
0086 if (err) {
0087 dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
0088 return err;
0089 }
0090
0091 tegra210_mbdrc_hw_params(dai->component);
0092
0093 return err;
0094 }
0095
0096 static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
0097 {
0098 struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
0099
0100 tegra210_peq_component_init(cmpnt);
0101 tegra210_mbdrc_component_init(cmpnt);
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 snd_soc_component_init_regmap(cmpnt, ope->regmap);
0115
0116 return 0;
0117 }
0118
0119 static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
0120 .hw_params = tegra210_ope_hw_params,
0121 };
0122
0123 static struct snd_soc_dai_driver tegra210_ope_dais[] = {
0124 {
0125 .name = "OPE-RX-CIF",
0126 .playback = {
0127 .stream_name = "RX-CIF-Playback",
0128 .channels_min = 1,
0129 .channels_max = 8,
0130 .rates = SNDRV_PCM_RATE_8000_192000,
0131 .formats = SNDRV_PCM_FMTBIT_S8 |
0132 SNDRV_PCM_FMTBIT_S16_LE |
0133 SNDRV_PCM_FMTBIT_S32_LE,
0134 },
0135 .capture = {
0136 .stream_name = "RX-CIF-Capture",
0137 .channels_min = 1,
0138 .channels_max = 8,
0139 .rates = SNDRV_PCM_RATE_8000_192000,
0140 .formats = SNDRV_PCM_FMTBIT_S8 |
0141 SNDRV_PCM_FMTBIT_S16_LE |
0142 SNDRV_PCM_FMTBIT_S32_LE,
0143 },
0144 },
0145 {
0146 .name = "OPE-TX-CIF",
0147 .playback = {
0148 .stream_name = "TX-CIF-Playback",
0149 .channels_min = 1,
0150 .channels_max = 8,
0151 .rates = SNDRV_PCM_RATE_8000_192000,
0152 .formats = SNDRV_PCM_FMTBIT_S8 |
0153 SNDRV_PCM_FMTBIT_S16_LE |
0154 SNDRV_PCM_FMTBIT_S32_LE,
0155 },
0156 .capture = {
0157 .stream_name = "TX-CIF-Capture",
0158 .channels_min = 1,
0159 .channels_max = 8,
0160 .rates = SNDRV_PCM_RATE_8000_192000,
0161 .formats = SNDRV_PCM_FMTBIT_S8 |
0162 SNDRV_PCM_FMTBIT_S16_LE |
0163 SNDRV_PCM_FMTBIT_S32_LE,
0164 },
0165 .ops = &tegra210_ope_dai_ops,
0166 }
0167 };
0168
0169 static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
0170 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0171 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
0172 TEGRA210_OPE_EN_SHIFT, 0),
0173 };
0174
0175 #define OPE_ROUTES(sname) \
0176 { "RX XBAR-" sname, NULL, "XBAR-TX" }, \
0177 { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \
0178 { "RX", NULL, "RX-CIF-" sname }, \
0179 { "TX-CIF-" sname, NULL, "TX" }, \
0180 { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \
0181 { "XBAR-RX", NULL, "TX XBAR-" sname }
0182
0183 static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
0184 { "TX", NULL, "RX" },
0185 OPE_ROUTES("Playback"),
0186 OPE_ROUTES("Capture"),
0187 };
0188
0189 static const char * const tegra210_ope_data_dir_text[] = {
0190 "MBDRC to PEQ",
0191 "PEQ to MBDRC"
0192 };
0193
0194 static const struct soc_enum tegra210_ope_data_dir_enum =
0195 SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
0196 2, tegra210_ope_data_dir_text);
0197
0198 static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
0199 struct snd_ctl_elem_value *ucontrol)
0200 {
0201 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0202 struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
0203
0204 ucontrol->value.enumerated.item[0] = ope->data_dir;
0205
0206 return 0;
0207 }
0208
0209 static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
0210 struct snd_ctl_elem_value *ucontrol)
0211 {
0212 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0213 struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
0214 unsigned int value = ucontrol->value.enumerated.item[0];
0215
0216 if (value == ope->data_dir)
0217 return 0;
0218
0219 ope->data_dir = value;
0220
0221 return 1;
0222 }
0223
0224 static const struct snd_kcontrol_new tegra210_ope_controls[] = {
0225 SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
0226 tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
0227 };
0228
0229 static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
0230 .probe = tegra210_ope_component_probe,
0231 .dapm_widgets = tegra210_ope_widgets,
0232 .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets),
0233 .dapm_routes = tegra210_ope_routes,
0234 .num_dapm_routes = ARRAY_SIZE(tegra210_ope_routes),
0235 .controls = tegra210_ope_controls,
0236 .num_controls = ARRAY_SIZE(tegra210_ope_controls),
0237 };
0238
0239 static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
0240 {
0241 switch (reg) {
0242 case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
0243 case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
0244 case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
0245 case TEGRA210_OPE_DIR:
0246 return true;
0247 default:
0248 return false;
0249 }
0250 }
0251
0252 static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
0253 {
0254 if (tegra210_ope_wr_reg(dev, reg))
0255 return true;
0256
0257 switch (reg) {
0258 case TEGRA210_OPE_RX_STATUS:
0259 case TEGRA210_OPE_RX_INT_STATUS:
0260 case TEGRA210_OPE_TX_STATUS:
0261 case TEGRA210_OPE_TX_INT_STATUS:
0262 case TEGRA210_OPE_STATUS:
0263 case TEGRA210_OPE_INT_STATUS:
0264 return true;
0265 default:
0266 return false;
0267 }
0268 }
0269
0270 static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
0271 {
0272 switch (reg) {
0273 case TEGRA210_OPE_RX_STATUS:
0274 case TEGRA210_OPE_RX_INT_STATUS:
0275 case TEGRA210_OPE_TX_STATUS:
0276 case TEGRA210_OPE_TX_INT_STATUS:
0277 case TEGRA210_OPE_SOFT_RESET:
0278 case TEGRA210_OPE_STATUS:
0279 case TEGRA210_OPE_INT_STATUS:
0280 return true;
0281 default:
0282 return false;
0283 }
0284 }
0285
0286 static const struct regmap_config tegra210_ope_regmap_config = {
0287 .reg_bits = 32,
0288 .reg_stride = 4,
0289 .val_bits = 32,
0290 .max_register = TEGRA210_OPE_DIR,
0291 .writeable_reg = tegra210_ope_wr_reg,
0292 .readable_reg = tegra210_ope_rd_reg,
0293 .volatile_reg = tegra210_ope_volatile_reg,
0294 .reg_defaults = tegra210_ope_reg_defaults,
0295 .num_reg_defaults = ARRAY_SIZE(tegra210_ope_reg_defaults),
0296 .cache_type = REGCACHE_FLAT,
0297 };
0298
0299 static int tegra210_ope_probe(struct platform_device *pdev)
0300 {
0301 struct device *dev = &pdev->dev;
0302 struct tegra210_ope *ope;
0303 void __iomem *regs;
0304 int err;
0305
0306 ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
0307 if (!ope)
0308 return -ENOMEM;
0309
0310 regs = devm_platform_ioremap_resource(pdev, 0);
0311 if (IS_ERR(regs))
0312 return PTR_ERR(regs);
0313
0314 ope->regmap = devm_regmap_init_mmio(dev, regs,
0315 &tegra210_ope_regmap_config);
0316 if (IS_ERR(ope->regmap)) {
0317 dev_err(dev, "regmap init failed\n");
0318 return PTR_ERR(ope->regmap);
0319 }
0320
0321 regcache_cache_only(ope->regmap, true);
0322
0323 dev_set_drvdata(dev, ope);
0324
0325 err = tegra210_peq_regmap_init(pdev);
0326 if (err < 0) {
0327 dev_err(dev, "PEQ init failed\n");
0328 return err;
0329 }
0330
0331 err = tegra210_mbdrc_regmap_init(pdev);
0332 if (err < 0) {
0333 dev_err(dev, "MBDRC init failed\n");
0334 return err;
0335 }
0336
0337 err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
0338 tegra210_ope_dais,
0339 ARRAY_SIZE(tegra210_ope_dais));
0340 if (err) {
0341 dev_err(dev, "can't register OPE component, err: %d\n", err);
0342 return err;
0343 }
0344
0345 pm_runtime_enable(dev);
0346
0347 return 0;
0348 }
0349
0350 static int tegra210_ope_remove(struct platform_device *pdev)
0351 {
0352 pm_runtime_disable(&pdev->dev);
0353
0354 return 0;
0355 }
0356
0357 static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
0358 {
0359 struct tegra210_ope *ope = dev_get_drvdata(dev);
0360
0361 tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
0362 ope->peq_biquad_shifts);
0363
0364 regcache_cache_only(ope->mbdrc_regmap, true);
0365 regcache_cache_only(ope->peq_regmap, true);
0366 regcache_cache_only(ope->regmap, true);
0367
0368 regcache_mark_dirty(ope->regmap);
0369 regcache_mark_dirty(ope->peq_regmap);
0370 regcache_mark_dirty(ope->mbdrc_regmap);
0371
0372 return 0;
0373 }
0374
0375 static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
0376 {
0377 struct tegra210_ope *ope = dev_get_drvdata(dev);
0378
0379 regcache_cache_only(ope->regmap, false);
0380 regcache_cache_only(ope->peq_regmap, false);
0381 regcache_cache_only(ope->mbdrc_regmap, false);
0382
0383 regcache_sync(ope->regmap);
0384 regcache_sync(ope->peq_regmap);
0385 regcache_sync(ope->mbdrc_regmap);
0386
0387 tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
0388 ope->peq_biquad_shifts);
0389
0390 return 0;
0391 }
0392
0393 static const struct dev_pm_ops tegra210_ope_pm_ops = {
0394 SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
0395 tegra210_ope_runtime_resume, NULL)
0396 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0397 pm_runtime_force_resume)
0398 };
0399
0400 static const struct of_device_id tegra210_ope_of_match[] = {
0401 { .compatible = "nvidia,tegra210-ope" },
0402 {},
0403 };
0404 MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
0405
0406 static struct platform_driver tegra210_ope_driver = {
0407 .driver = {
0408 .name = "tegra210-ope",
0409 .of_match_table = tegra210_ope_of_match,
0410 .pm = &tegra210_ope_pm_ops,
0411 },
0412 .probe = tegra210_ope_probe,
0413 .remove = tegra210_ope_remove,
0414 };
0415 module_platform_driver(tegra210_ope_driver)
0416
0417 MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
0418 MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
0419 MODULE_LICENSE("GPL");