Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tegra20_i2s.c - Tegra20 I2S driver
0004  *
0005  * Author: Stephen Warren <swarren@nvidia.com>
0006  * Copyright (C) 2010,2012 - NVIDIA, Inc.
0007  *
0008  * Based on code copyright/by:
0009  *
0010  * Copyright (c) 2009-2010, NVIDIA Corporation.
0011  * Scott Peterson <speterson@nvidia.com>
0012  *
0013  * Copyright (C) 2010 Google, Inc.
0014  * Iliyan Malchev <malchev@google.com>
0015  */
0016 
0017 #include <linux/clk.h>
0018 #include <linux/device.h>
0019 #include <linux/io.h>
0020 #include <linux/module.h>
0021 #include <linux/of.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/pm_runtime.h>
0024 #include <linux/regmap.h>
0025 #include <linux/reset.h>
0026 #include <linux/slab.h>
0027 #include <sound/core.h>
0028 #include <sound/pcm.h>
0029 #include <sound/pcm_params.h>
0030 #include <sound/soc.h>
0031 #include <sound/dmaengine_pcm.h>
0032 
0033 #include "tegra20_i2s.h"
0034 
0035 #define DRV_NAME "tegra20-i2s"
0036 
0037 static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev)
0038 {
0039     struct tegra20_i2s *i2s = dev_get_drvdata(dev);
0040 
0041     regcache_cache_only(i2s->regmap, true);
0042 
0043     clk_disable_unprepare(i2s->clk_i2s);
0044 
0045     return 0;
0046 }
0047 
0048 static __maybe_unused int tegra20_i2s_runtime_resume(struct device *dev)
0049 {
0050     struct tegra20_i2s *i2s = dev_get_drvdata(dev);
0051     int ret;
0052 
0053     ret = reset_control_assert(i2s->reset);
0054     if (ret)
0055         return ret;
0056 
0057     ret = clk_prepare_enable(i2s->clk_i2s);
0058     if (ret) {
0059         dev_err(dev, "clk_enable failed: %d\n", ret);
0060         return ret;
0061     }
0062 
0063     usleep_range(10, 100);
0064 
0065     ret = reset_control_deassert(i2s->reset);
0066     if (ret)
0067         goto disable_clocks;
0068 
0069     regcache_cache_only(i2s->regmap, false);
0070     regcache_mark_dirty(i2s->regmap);
0071 
0072     ret = regcache_sync(i2s->regmap);
0073     if (ret)
0074         goto disable_clocks;
0075 
0076     return 0;
0077 
0078 disable_clocks:
0079     clk_disable_unprepare(i2s->clk_i2s);
0080 
0081     return ret;
0082 }
0083 
0084 static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
0085                 unsigned int fmt)
0086 {
0087     struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
0088     unsigned int mask = 0, val = 0;
0089 
0090     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0091     case SND_SOC_DAIFMT_NB_NF:
0092         break;
0093     default:
0094         return -EINVAL;
0095     }
0096 
0097     mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
0098     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0099     case SND_SOC_DAIFMT_BP_FP:
0100         val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
0101         break;
0102     case SND_SOC_DAIFMT_BC_FC:
0103         break;
0104     default:
0105         return -EINVAL;
0106     }
0107 
0108     mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
0109         TEGRA20_I2S_CTRL_LRCK_MASK;
0110     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0111     case SND_SOC_DAIFMT_DSP_A:
0112         val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
0113         val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
0114         break;
0115     case SND_SOC_DAIFMT_DSP_B:
0116         val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
0117         val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
0118         break;
0119     case SND_SOC_DAIFMT_I2S:
0120         val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
0121         val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
0122         break;
0123     case SND_SOC_DAIFMT_RIGHT_J:
0124         val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
0125         val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
0126         break;
0127     case SND_SOC_DAIFMT_LEFT_J:
0128         val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
0129         val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
0130         break;
0131     default:
0132         return -EINVAL;
0133     }
0134 
0135     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
0136 
0137     return 0;
0138 }
0139 
0140 static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
0141                  struct snd_pcm_hw_params *params,
0142                  struct snd_soc_dai *dai)
0143 {
0144     struct device *dev = dai->dev;
0145     struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
0146     unsigned int mask, val;
0147     int ret, sample_size, srate, i2sclock, bitcnt;
0148 
0149     mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
0150     switch (params_format(params)) {
0151     case SNDRV_PCM_FORMAT_S16_LE:
0152         val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
0153         sample_size = 16;
0154         break;
0155     case SNDRV_PCM_FORMAT_S24_LE:
0156         val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
0157         sample_size = 24;
0158         break;
0159     case SNDRV_PCM_FORMAT_S32_LE:
0160         val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
0161         sample_size = 32;
0162         break;
0163     default:
0164         return -EINVAL;
0165     }
0166 
0167     mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
0168     val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
0169 
0170     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
0171 
0172     srate = params_rate(params);
0173 
0174     /* Final "* 2" required by Tegra hardware */
0175     i2sclock = srate * params_channels(params) * sample_size * 2;
0176 
0177     ret = clk_set_rate(i2s->clk_i2s, i2sclock);
0178     if (ret) {
0179         dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
0180         return ret;
0181     }
0182 
0183     bitcnt = (i2sclock / (2 * srate)) - 1;
0184     if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
0185         return -EINVAL;
0186     val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
0187 
0188     if (i2sclock % (2 * srate))
0189         val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
0190 
0191     regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
0192 
0193     regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
0194              TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
0195              TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
0196 
0197     return 0;
0198 }
0199 
0200 static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
0201 {
0202     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
0203                TEGRA20_I2S_CTRL_FIFO1_ENABLE,
0204                TEGRA20_I2S_CTRL_FIFO1_ENABLE);
0205 }
0206 
0207 static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
0208 {
0209     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
0210                TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
0211 }
0212 
0213 static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
0214 {
0215     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
0216                TEGRA20_I2S_CTRL_FIFO2_ENABLE,
0217                TEGRA20_I2S_CTRL_FIFO2_ENABLE);
0218 }
0219 
0220 static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
0221 {
0222     regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
0223                TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
0224 }
0225 
0226 static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
0227                    struct snd_soc_dai *dai)
0228 {
0229     struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
0230 
0231     switch (cmd) {
0232     case SNDRV_PCM_TRIGGER_START:
0233     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0234     case SNDRV_PCM_TRIGGER_RESUME:
0235         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0236             tegra20_i2s_start_playback(i2s);
0237         else
0238             tegra20_i2s_start_capture(i2s);
0239         break;
0240     case SNDRV_PCM_TRIGGER_STOP:
0241     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0242     case SNDRV_PCM_TRIGGER_SUSPEND:
0243         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0244             tegra20_i2s_stop_playback(i2s);
0245         else
0246             tegra20_i2s_stop_capture(i2s);
0247         break;
0248     default:
0249         return -EINVAL;
0250     }
0251 
0252     return 0;
0253 }
0254 
0255 static int tegra20_i2s_probe(struct snd_soc_dai *dai)
0256 {
0257     struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
0258 
0259     dai->capture_dma_data = &i2s->capture_dma_data;
0260     dai->playback_dma_data = &i2s->playback_dma_data;
0261 
0262     return 0;
0263 }
0264 
0265 static const unsigned int tegra20_i2s_rates[] = {
0266     8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000
0267 };
0268 
0269 static int tegra20_i2s_filter_rates(struct snd_pcm_hw_params *params,
0270                     struct snd_pcm_hw_rule *rule)
0271 {
0272     struct snd_interval *r = hw_param_interval(params, rule->var);
0273     struct snd_soc_dai *dai = rule->private;
0274     struct tegra20_i2s *i2s = dev_get_drvdata(dai->dev);
0275     struct clk *parent = clk_get_parent(i2s->clk_i2s);
0276     long i, parent_rate, valid_rates = 0;
0277 
0278     parent_rate = clk_get_rate(parent);
0279     if (parent_rate <= 0) {
0280         dev_err(dai->dev, "Can't get parent clock rate: %ld\n",
0281             parent_rate);
0282         return parent_rate ?: -EINVAL;
0283     }
0284 
0285     for (i = 0; i < ARRAY_SIZE(tegra20_i2s_rates); i++) {
0286         if (parent_rate % (tegra20_i2s_rates[i] * 128) == 0)
0287             valid_rates |= BIT(i);
0288     }
0289 
0290     /*
0291      * At least one rate must be valid, otherwise the parent clock isn't
0292      * audio PLL. Nothing should be filtered in this case.
0293      */
0294     if (!valid_rates)
0295         valid_rates = BIT(ARRAY_SIZE(tegra20_i2s_rates)) - 1;
0296 
0297     return snd_interval_list(r, ARRAY_SIZE(tegra20_i2s_rates),
0298                  tegra20_i2s_rates, valid_rates);
0299 }
0300 
0301 static int tegra20_i2s_startup(struct snd_pcm_substream *substream,
0302                    struct snd_soc_dai *dai)
0303 {
0304     if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate"))
0305         return 0;
0306 
0307     return snd_pcm_hw_rule_add(substream->runtime, 0,
0308                    SNDRV_PCM_HW_PARAM_RATE,
0309                    tegra20_i2s_filter_rates, dai,
0310                    SNDRV_PCM_HW_PARAM_RATE, -1);
0311 }
0312 
0313 static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
0314     .set_fmt    = tegra20_i2s_set_fmt,
0315     .hw_params  = tegra20_i2s_hw_params,
0316     .trigger    = tegra20_i2s_trigger,
0317     .startup    = tegra20_i2s_startup,
0318 };
0319 
0320 static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
0321     .probe = tegra20_i2s_probe,
0322     .playback = {
0323         .stream_name = "Playback",
0324         .channels_min = 2,
0325         .channels_max = 2,
0326         .rates = SNDRV_PCM_RATE_8000_96000,
0327         .formats = SNDRV_PCM_FMTBIT_S16_LE,
0328     },
0329     .capture = {
0330         .stream_name = "Capture",
0331         .channels_min = 2,
0332         .channels_max = 2,
0333         .rates = SNDRV_PCM_RATE_8000_96000,
0334         .formats = SNDRV_PCM_FMTBIT_S16_LE,
0335     },
0336     .ops = &tegra20_i2s_dai_ops,
0337     .symmetric_rate = 1,
0338 };
0339 
0340 static const struct snd_soc_component_driver tegra20_i2s_component = {
0341     .name           = DRV_NAME,
0342     .legacy_dai_naming  = 1,
0343 };
0344 
0345 static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
0346 {
0347     switch (reg) {
0348     case TEGRA20_I2S_CTRL:
0349     case TEGRA20_I2S_STATUS:
0350     case TEGRA20_I2S_TIMING:
0351     case TEGRA20_I2S_FIFO_SCR:
0352     case TEGRA20_I2S_PCM_CTRL:
0353     case TEGRA20_I2S_NW_CTRL:
0354     case TEGRA20_I2S_TDM_CTRL:
0355     case TEGRA20_I2S_TDM_TX_RX_CTRL:
0356     case TEGRA20_I2S_FIFO1:
0357     case TEGRA20_I2S_FIFO2:
0358         return true;
0359     default:
0360         return false;
0361     }
0362 }
0363 
0364 static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
0365 {
0366     switch (reg) {
0367     case TEGRA20_I2S_STATUS:
0368     case TEGRA20_I2S_FIFO_SCR:
0369     case TEGRA20_I2S_FIFO1:
0370     case TEGRA20_I2S_FIFO2:
0371         return true;
0372     default:
0373         return false;
0374     }
0375 }
0376 
0377 static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
0378 {
0379     switch (reg) {
0380     case TEGRA20_I2S_FIFO1:
0381     case TEGRA20_I2S_FIFO2:
0382         return true;
0383     default:
0384         return false;
0385     }
0386 }
0387 
0388 static const struct regmap_config tegra20_i2s_regmap_config = {
0389     .reg_bits = 32,
0390     .reg_stride = 4,
0391     .val_bits = 32,
0392     .max_register = TEGRA20_I2S_FIFO2,
0393     .writeable_reg = tegra20_i2s_wr_rd_reg,
0394     .readable_reg = tegra20_i2s_wr_rd_reg,
0395     .volatile_reg = tegra20_i2s_volatile_reg,
0396     .precious_reg = tegra20_i2s_precious_reg,
0397     .cache_type = REGCACHE_FLAT,
0398 };
0399 
0400 static int tegra20_i2s_platform_probe(struct platform_device *pdev)
0401 {
0402     struct tegra20_i2s *i2s;
0403     struct resource *mem;
0404     void __iomem *regs;
0405     int ret;
0406 
0407     i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
0408     if (!i2s) {
0409         ret = -ENOMEM;
0410         goto err;
0411     }
0412     dev_set_drvdata(&pdev->dev, i2s);
0413 
0414     i2s->dai = tegra20_i2s_dai_template;
0415     i2s->dai.name = dev_name(&pdev->dev);
0416 
0417     i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, "i2s");
0418     if (IS_ERR(i2s->reset)) {
0419         dev_err(&pdev->dev, "Can't retrieve i2s reset\n");
0420         return PTR_ERR(i2s->reset);
0421     }
0422 
0423     i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL);
0424     if (IS_ERR(i2s->clk_i2s)) {
0425         dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
0426         ret = PTR_ERR(i2s->clk_i2s);
0427         goto err;
0428     }
0429 
0430     regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
0431     if (IS_ERR(regs)) {
0432         ret = PTR_ERR(regs);
0433         goto err;
0434     }
0435 
0436     i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
0437                         &tegra20_i2s_regmap_config);
0438     if (IS_ERR(i2s->regmap)) {
0439         dev_err(&pdev->dev, "regmap init failed\n");
0440         ret = PTR_ERR(i2s->regmap);
0441         goto err;
0442     }
0443 
0444     i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
0445     i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0446     i2s->capture_dma_data.maxburst = 4;
0447 
0448     i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
0449     i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0450     i2s->playback_dma_data.maxburst = 4;
0451 
0452     pm_runtime_enable(&pdev->dev);
0453 
0454     ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
0455                      &i2s->dai, 1);
0456     if (ret) {
0457         dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
0458         ret = -ENOMEM;
0459         goto err_pm_disable;
0460     }
0461 
0462     ret = tegra_pcm_platform_register(&pdev->dev);
0463     if (ret) {
0464         dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
0465         goto err_unregister_component;
0466     }
0467 
0468     return 0;
0469 
0470 err_unregister_component:
0471     snd_soc_unregister_component(&pdev->dev);
0472 err_pm_disable:
0473     pm_runtime_disable(&pdev->dev);
0474 err:
0475     return ret;
0476 }
0477 
0478 static int tegra20_i2s_platform_remove(struct platform_device *pdev)
0479 {
0480     tegra_pcm_platform_unregister(&pdev->dev);
0481     snd_soc_unregister_component(&pdev->dev);
0482     pm_runtime_disable(&pdev->dev);
0483 
0484     return 0;
0485 }
0486 
0487 static const struct of_device_id tegra20_i2s_of_match[] = {
0488     { .compatible = "nvidia,tegra20-i2s", },
0489     {},
0490 };
0491 
0492 static const struct dev_pm_ops tegra20_i2s_pm_ops = {
0493     SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
0494                tegra20_i2s_runtime_resume, NULL)
0495     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0496                 pm_runtime_force_resume)
0497 };
0498 
0499 static struct platform_driver tegra20_i2s_driver = {
0500     .driver = {
0501         .name = DRV_NAME,
0502         .of_match_table = tegra20_i2s_of_match,
0503         .pm = &tegra20_i2s_pm_ops,
0504     },
0505     .probe = tegra20_i2s_platform_probe,
0506     .remove = tegra20_i2s_platform_remove,
0507 };
0508 module_platform_driver(tegra20_i2s_driver);
0509 
0510 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0511 MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
0512 MODULE_LICENSE("GPL");
0513 MODULE_ALIAS("platform:" DRV_NAME);
0514 MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);