Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2020 BayLibre, SAS.
0004 // Author: Jerome Brunet <jbrunet@baylibre.com>
0005 
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <sound/pcm_params.h>
0009 #include <sound/soc.h>
0010 #include <sound/soc-dai.h>
0011 
0012 #include "aiu.h"
0013 
0014 #define AIU_I2S_SOURCE_DESC_MODE_8CH    BIT(0)
0015 #define AIU_I2S_SOURCE_DESC_MODE_24BIT  BIT(5)
0016 #define AIU_I2S_SOURCE_DESC_MODE_32BIT  BIT(9)
0017 #define AIU_I2S_SOURCE_DESC_MODE_SPLIT  BIT(11)
0018 #define AIU_RST_SOFT_I2S_FAST       BIT(0)
0019 
0020 #define AIU_I2S_DAC_CFG_MSB_FIRST   BIT(2)
0021 #define AIU_CLK_CTRL_I2S_DIV_EN     BIT(0)
0022 #define AIU_CLK_CTRL_I2S_DIV        GENMASK(3, 2)
0023 #define AIU_CLK_CTRL_AOCLK_INVERT   BIT(6)
0024 #define AIU_CLK_CTRL_LRCLK_INVERT   BIT(7)
0025 #define AIU_CLK_CTRL_LRCLK_SKEW     GENMASK(9, 8)
0026 #define AIU_CLK_CTRL_MORE_HDMI_AMCLK    BIT(6)
0027 #define AIU_CLK_CTRL_MORE_I2S_DIV   GENMASK(5, 0)
0028 #define AIU_CODEC_DAC_LRCLK_CTRL_DIV    GENMASK(11, 0)
0029 
0030 static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
0031                        bool enable)
0032 {
0033     snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0034                       AIU_CLK_CTRL_I2S_DIV_EN,
0035                       enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
0036 }
0037 
0038 static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
0039                       struct snd_pcm_hw_params *params)
0040 {
0041     /* Always operate in split (classic interleaved) mode */
0042     unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
0043 
0044     /* Reset required to update the pipeline */
0045     snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
0046     snd_soc_component_read(component, AIU_I2S_SYNC);
0047 
0048     switch (params_physical_width(params)) {
0049     case 16: /* Nothing to do */
0050         break;
0051 
0052     case 32:
0053         desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
0054              AIU_I2S_SOURCE_DESC_MODE_32BIT);
0055         break;
0056 
0057     default:
0058         return -EINVAL;
0059     }
0060 
0061     switch (params_channels(params)) {
0062     case 2: /* Nothing to do */
0063         break;
0064     case 8:
0065         desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
0066         break;
0067     default:
0068         return -EINVAL;
0069     }
0070 
0071     snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
0072                       AIU_I2S_SOURCE_DESC_MODE_8CH |
0073                       AIU_I2S_SOURCE_DESC_MODE_24BIT |
0074                       AIU_I2S_SOURCE_DESC_MODE_32BIT |
0075                       AIU_I2S_SOURCE_DESC_MODE_SPLIT,
0076                       desc);
0077 
0078     return 0;
0079 }
0080 
0081 static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
0082                       struct snd_pcm_hw_params *params,
0083                       unsigned int bs)
0084 {
0085     switch (bs) {
0086     case 1:
0087     case 2:
0088     case 4:
0089     case 8:
0090         /* These are the only valid legacy dividers */
0091         break;
0092 
0093     default:
0094         dev_err(component->dev, "Unsupported i2s divider: %u\n", bs);
0095         return -EINVAL;
0096     }
0097 
0098     snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0099                       AIU_CLK_CTRL_I2S_DIV,
0100                       FIELD_PREP(AIU_CLK_CTRL_I2S_DIV,
0101                          __ffs(bs)));
0102 
0103     snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
0104                       AIU_CLK_CTRL_MORE_I2S_DIV,
0105                       FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV,
0106                          0));
0107 
0108     return 0;
0109 }
0110 
0111 static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
0112                     struct snd_pcm_hw_params *params,
0113                     unsigned int bs)
0114 {
0115     /*
0116      * NOTE: this HW is odd.
0117      * In most configuration, the i2s divider is 'mclk / blck'.
0118      * However, in 16 bits - 8ch mode, this factor needs to be
0119      * increased by 50% to get the correct output rate.
0120      * No idea why !
0121      */
0122     if (params_width(params) == 16 && params_channels(params) == 8) {
0123         if (bs % 2) {
0124             dev_err(component->dev,
0125                 "Cannot increase i2s divider by 50%%\n");
0126             return -EINVAL;
0127         }
0128         bs += bs / 2;
0129     }
0130 
0131     /* Use CLK_MORE for mclk to bclk divider */
0132     snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0133                       AIU_CLK_CTRL_I2S_DIV,
0134                       FIELD_PREP(AIU_CLK_CTRL_I2S_DIV, 0));
0135 
0136     snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
0137                       AIU_CLK_CTRL_MORE_I2S_DIV,
0138                       FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV,
0139                          bs - 1));
0140 
0141     return 0;
0142 }
0143 
0144 static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
0145                       struct snd_pcm_hw_params *params)
0146 {
0147     struct aiu *aiu = snd_soc_component_get_drvdata(component);
0148     unsigned int srate = params_rate(params);
0149     unsigned int fs, bs;
0150     int ret;
0151 
0152     /* Get the oversampling factor */
0153     fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
0154 
0155     if (fs % 64)
0156         return -EINVAL;
0157 
0158     /* Send data MSB first */
0159     snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
0160                       AIU_I2S_DAC_CFG_MSB_FIRST,
0161                       AIU_I2S_DAC_CFG_MSB_FIRST);
0162 
0163     /* Set bclk to lrlck ratio */
0164     snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
0165                       AIU_CODEC_DAC_LRCLK_CTRL_DIV,
0166                       FIELD_PREP(AIU_CODEC_DAC_LRCLK_CTRL_DIV,
0167                          64 - 1));
0168 
0169     bs = fs / 64;
0170 
0171     if (aiu->platform->has_clk_ctrl_more_i2s_div)
0172         ret = aiu_encoder_i2s_set_more_div(component, params, bs);
0173     else
0174         ret = aiu_encoder_i2s_set_legacy_div(component, params, bs);
0175 
0176     if (ret)
0177         return ret;
0178 
0179     /* Make sure amclk is used for HDMI i2s as well */
0180     snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
0181                       AIU_CLK_CTRL_MORE_HDMI_AMCLK,
0182                       AIU_CLK_CTRL_MORE_HDMI_AMCLK);
0183 
0184     return 0;
0185 }
0186 
0187 static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
0188                      struct snd_pcm_hw_params *params,
0189                      struct snd_soc_dai *dai)
0190 {
0191     struct snd_soc_component *component = dai->component;
0192     int ret;
0193 
0194     /* Disable the clock while changing the settings */
0195     aiu_encoder_i2s_divider_enable(component, false);
0196 
0197     ret = aiu_encoder_i2s_setup_desc(component, params);
0198     if (ret) {
0199         dev_err(dai->dev, "setting i2s desc failed\n");
0200         return ret;
0201     }
0202 
0203     ret = aiu_encoder_i2s_set_clocks(component, params);
0204     if (ret) {
0205         dev_err(dai->dev, "setting i2s clocks failed\n");
0206         return ret;
0207     }
0208 
0209     aiu_encoder_i2s_divider_enable(component, true);
0210 
0211     return 0;
0212 }
0213 
0214 static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
0215                    struct snd_soc_dai *dai)
0216 {
0217     struct snd_soc_component *component = dai->component;
0218 
0219     aiu_encoder_i2s_divider_enable(component, false);
0220 
0221     return 0;
0222 }
0223 
0224 static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0225 {
0226     struct snd_soc_component *component = dai->component;
0227     unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
0228     unsigned int val = 0;
0229     unsigned int skew;
0230 
0231     /* Only CPU Master / Codec Slave supported ATM */
0232     if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
0233         return -EINVAL;
0234 
0235     if (inv == SND_SOC_DAIFMT_NB_IF ||
0236         inv == SND_SOC_DAIFMT_IB_IF)
0237         val |= AIU_CLK_CTRL_LRCLK_INVERT;
0238 
0239     if (inv == SND_SOC_DAIFMT_IB_NF ||
0240         inv == SND_SOC_DAIFMT_IB_IF)
0241         val |= AIU_CLK_CTRL_AOCLK_INVERT;
0242 
0243     /* Signal skew */
0244     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0245     case SND_SOC_DAIFMT_I2S:
0246         /* Invert sample clock for i2s */
0247         val ^= AIU_CLK_CTRL_LRCLK_INVERT;
0248         skew = 1;
0249         break;
0250     case SND_SOC_DAIFMT_LEFT_J:
0251         skew = 0;
0252         break;
0253     default:
0254         return -EINVAL;
0255     }
0256 
0257     val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew);
0258     snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0259                       AIU_CLK_CTRL_LRCLK_INVERT |
0260                       AIU_CLK_CTRL_AOCLK_INVERT |
0261                       AIU_CLK_CTRL_LRCLK_SKEW,
0262                       val);
0263 
0264     return 0;
0265 }
0266 
0267 static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
0268                       unsigned int freq, int dir)
0269 {
0270     struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
0271     int ret;
0272 
0273     if (WARN_ON(clk_id != 0))
0274         return -EINVAL;
0275 
0276     if (dir == SND_SOC_CLOCK_IN)
0277         return 0;
0278 
0279     ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq);
0280     if (ret)
0281         dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
0282 
0283     return ret;
0284 }
0285 
0286 static const unsigned int hw_channels[] = {2, 8};
0287 static const struct snd_pcm_hw_constraint_list hw_channel_constraints = {
0288     .list = hw_channels,
0289     .count = ARRAY_SIZE(hw_channels),
0290     .mask = 0,
0291 };
0292 
0293 static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
0294                    struct snd_soc_dai *dai)
0295 {
0296     struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
0297     int ret;
0298 
0299     /* Make sure the encoder gets either 2 or 8 channels */
0300     ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
0301                      SNDRV_PCM_HW_PARAM_CHANNELS,
0302                      &hw_channel_constraints);
0303     if (ret) {
0304         dev_err(dai->dev, "adding channels constraints failed\n");
0305         return ret;
0306     }
0307 
0308     ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks);
0309     if (ret)
0310         dev_err(dai->dev, "failed to enable i2s clocks\n");
0311 
0312     return ret;
0313 }
0314 
0315 static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
0316                      struct snd_soc_dai *dai)
0317 {
0318     struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
0319 
0320     clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks);
0321 }
0322 
0323 const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
0324     .hw_params  = aiu_encoder_i2s_hw_params,
0325     .hw_free    = aiu_encoder_i2s_hw_free,
0326     .set_fmt    = aiu_encoder_i2s_set_fmt,
0327     .set_sysclk = aiu_encoder_i2s_set_sysclk,
0328     .startup    = aiu_encoder_i2s_startup,
0329     .shutdown   = aiu_encoder_i2s_shutdown,
0330 };
0331