Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver of Inno codec for rk3036 by Rockchip Inc.
0004  *
0005  * Author: Rockchip Inc.
0006  * Author: Zheng ShunQian<zhengsq@rock-chips.com>
0007  */
0008 
0009 #include <sound/soc.h>
0010 #include <sound/tlv.h>
0011 #include <sound/soc-dapm.h>
0012 #include <sound/soc-dai.h>
0013 #include <sound/pcm.h>
0014 #include <sound/pcm_params.h>
0015 
0016 #include <linux/platform_device.h>
0017 #include <linux/of.h>
0018 #include <linux/clk.h>
0019 #include <linux/regmap.h>
0020 #include <linux/device.h>
0021 #include <linux/mfd/syscon.h>
0022 #include <linux/module.h>
0023 #include <linux/io.h>
0024 
0025 #include "inno_rk3036.h"
0026 
0027 struct rk3036_codec_priv {
0028     void __iomem *base;
0029     struct clk *pclk;
0030     struct regmap *regmap;
0031     struct device *dev;
0032 };
0033 
0034 static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
0035 
0036 static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol,
0037                      struct snd_ctl_elem_info *uinfo)
0038 {
0039     uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
0040     uinfo->count = 2;
0041     uinfo->value.integer.min = 0;
0042     uinfo->value.integer.max = 1;
0043 
0044     return 0;
0045 }
0046 
0047 static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol,
0048                     struct snd_ctl_elem_value *ucontrol)
0049 {
0050     struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
0051     int val, regval;
0052 
0053     regval = snd_soc_component_read(component, INNO_R09);
0054     val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) &
0055            INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
0056     ucontrol->value.integer.value[0] = val;
0057 
0058     val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) &
0059            INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
0060     ucontrol->value.integer.value[1] = val;
0061 
0062     return 0;
0063 }
0064 
0065 static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol,
0066                     struct snd_ctl_elem_value *ucontrol)
0067 {
0068     struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
0069     int val, ret, regmsk;
0070 
0071     val = (ucontrol->value.integer.value[0] ?
0072            INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
0073           INNO_R09_HPL_ANITPOP_SHIFT;
0074     val |= (ucontrol->value.integer.value[1] ?
0075         INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
0076            INNO_R09_HPR_ANITPOP_SHIFT;
0077 
0078     regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT |
0079          INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT;
0080 
0081     ret = snd_soc_component_update_bits(component, INNO_R09,
0082                         regmsk, val);
0083     if (ret < 0)
0084         return ret;
0085 
0086     return 0;
0087 }
0088 
0089 #define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \
0090 {   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
0091     .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \
0092     .put = rk3036_codec_antipop_put, }
0093 
0094 static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
0095     SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
0096         INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
0097         INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
0098     SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
0099         INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
0100     SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
0101         INNO_R09_HPR_MUTE_SHIFT, 1, 0),
0102     SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"),
0103 };
0104 
0105 static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
0106     SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
0107             INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
0108 };
0109 
0110 static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
0111     SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
0112             INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
0113 };
0114 
0115 static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
0116     SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
0117             INNO_R05_HPL_WORK_SHIFT, 1, 0),
0118 };
0119 
0120 static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
0121     SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
0122             INNO_R05_HPR_WORK_SHIFT, 1, 0),
0123 };
0124 
0125 static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
0126     SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
0127                   INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
0128     SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
0129                   INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
0130     SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04,
0131                   INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0),
0132     SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06,
0133                   INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0),
0134     SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06,
0135                   INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0),
0136     SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04,
0137                   INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0),
0138     SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04,
0139                   INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0),
0140 
0141     SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04,
0142              INNO_R04_DACL_SW_SHIFT, 0),
0143     SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04,
0144              INNO_R04_DACR_SW_SHIFT, 0),
0145 
0146     SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
0147         rk3036_codec_hpl_mixer_controls,
0148         ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)),
0149     SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
0150         rk3036_codec_hpr_mixer_controls,
0151         ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)),
0152 
0153     SND_SOC_DAPM_PGA("HP Left Out", INNO_R05,
0154              INNO_R05_HPL_EN_SHIFT, 0, NULL, 0),
0155     SND_SOC_DAPM_PGA("HP Right Out", INNO_R05,
0156              INNO_R05_HPR_EN_SHIFT, 0, NULL, 0),
0157 
0158     SND_SOC_DAPM_MIXER("HP Left Switch",  SND_SOC_NOPM, 0, 0,
0159                rk3036_codec_hpl_switch_controls,
0160                ARRAY_SIZE(rk3036_codec_hpl_switch_controls)),
0161     SND_SOC_DAPM_MIXER("HP Right Switch",  SND_SOC_NOPM, 0, 0,
0162                rk3036_codec_hpr_switch_controls,
0163                ARRAY_SIZE(rk3036_codec_hpr_switch_controls)),
0164 
0165     SND_SOC_DAPM_OUTPUT("HPL"),
0166     SND_SOC_DAPM_OUTPUT("HPR"),
0167 };
0168 
0169 static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
0170     {"DACL VREF", NULL, "DAC PWR"},
0171     {"DACR VREF", NULL, "DAC PWR"},
0172     {"DACL HiLo VREF", NULL, "DAC PWR"},
0173     {"DACR HiLo VREF", NULL, "DAC PWR"},
0174     {"DACL CLK", NULL, "DAC PWR"},
0175     {"DACR CLK", NULL, "DAC PWR"},
0176 
0177     {"DACL", NULL, "DACL VREF"},
0178     {"DACL", NULL, "DACL HiLo VREF"},
0179     {"DACL", NULL, "DACL CLK"},
0180     {"DACR", NULL, "DACR VREF"},
0181     {"DACR", NULL, "DACR HiLo VREF"},
0182     {"DACR", NULL, "DACR CLK"},
0183 
0184     {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"},
0185     {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"},
0186     {"HP Left Out", NULL, "Left Headphone Mixer"},
0187     {"HP Right Out", NULL, "Right Headphone Mixer"},
0188 
0189     {"HP Left Switch", "HP Left Out Switch", "HP Left Out"},
0190     {"HP Right Switch", "HP Right Out Switch", "HP Right Out"},
0191 
0192     {"HPL", NULL, "HP Left Switch"},
0193     {"HPR", NULL, "HP Right Switch"},
0194 };
0195 
0196 static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0197 {
0198     struct snd_soc_component *component = dai->component;
0199     unsigned int reg01_val = 0,  reg02_val = 0, reg03_val = 0;
0200 
0201     dev_dbg(component->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
0202 
0203     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0204     case SND_SOC_DAIFMT_CBC_CFC:
0205         reg01_val |= INNO_R01_PINDIR_IN_SLAVE |
0206                  INNO_R01_I2SMODE_SLAVE;
0207         break;
0208     case SND_SOC_DAIFMT_CBP_CFP:
0209         reg01_val |= INNO_R01_PINDIR_OUT_MASTER |
0210                  INNO_R01_I2SMODE_MASTER;
0211         break;
0212     default:
0213         dev_err(component->dev, "invalid fmt\n");
0214         return -EINVAL;
0215     }
0216 
0217     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0218     case SND_SOC_DAIFMT_DSP_A:
0219         reg02_val |= INNO_R02_DACM_PCM;
0220         break;
0221     case SND_SOC_DAIFMT_I2S:
0222         reg02_val |= INNO_R02_DACM_I2S;
0223         break;
0224     case SND_SOC_DAIFMT_RIGHT_J:
0225         reg02_val |= INNO_R02_DACM_RJM;
0226         break;
0227     case SND_SOC_DAIFMT_LEFT_J:
0228         reg02_val |= INNO_R02_DACM_LJM;
0229         break;
0230     default:
0231         dev_err(component->dev, "set dai format failed\n");
0232         return -EINVAL;
0233     }
0234 
0235     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0236     case SND_SOC_DAIFMT_NB_NF:
0237         reg02_val |= INNO_R02_LRCP_NORMAL;
0238         reg03_val |= INNO_R03_BCP_NORMAL;
0239         break;
0240     case SND_SOC_DAIFMT_IB_IF:
0241         reg02_val |= INNO_R02_LRCP_REVERSAL;
0242         reg03_val |= INNO_R03_BCP_REVERSAL;
0243         break;
0244     case SND_SOC_DAIFMT_IB_NF:
0245         reg02_val |= INNO_R02_LRCP_REVERSAL;
0246         reg03_val |= INNO_R03_BCP_NORMAL;
0247         break;
0248     case SND_SOC_DAIFMT_NB_IF:
0249         reg02_val |= INNO_R02_LRCP_NORMAL;
0250         reg03_val |= INNO_R03_BCP_REVERSAL;
0251         break;
0252     default:
0253         dev_err(component->dev, "set dai format failed\n");
0254         return -EINVAL;
0255     }
0256 
0257     snd_soc_component_update_bits(component, INNO_R01, INNO_R01_I2SMODE_MSK |
0258                 INNO_R01_PINDIR_MSK, reg01_val);
0259     snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
0260                 INNO_R02_DACM_MSK, reg02_val);
0261     snd_soc_component_update_bits(component, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
0262 
0263     return 0;
0264 }
0265 
0266 static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
0267                       struct snd_pcm_hw_params *hw_params,
0268                       struct snd_soc_dai *dai)
0269 {
0270     struct snd_soc_component *component = dai->component;
0271     unsigned int reg02_val = 0, reg03_val = 0;
0272 
0273     switch (params_format(hw_params)) {
0274     case SNDRV_PCM_FORMAT_S16_LE:
0275         reg02_val |= INNO_R02_VWL_16BIT;
0276         break;
0277     case SNDRV_PCM_FORMAT_S20_3LE:
0278         reg02_val |= INNO_R02_VWL_20BIT;
0279         break;
0280     case SNDRV_PCM_FORMAT_S24_LE:
0281         reg02_val |= INNO_R02_VWL_24BIT;
0282         break;
0283     case SNDRV_PCM_FORMAT_S32_LE:
0284         reg02_val |= INNO_R02_VWL_32BIT;
0285         break;
0286     default:
0287         return -EINVAL;
0288     }
0289 
0290     reg02_val |= INNO_R02_LRCP_NORMAL;
0291     reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
0292 
0293     snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
0294                 INNO_R02_VWL_MSK, reg02_val);
0295     snd_soc_component_update_bits(component, INNO_R03, INNO_R03_DACR_MSK |
0296                 INNO_R03_FWL_MSK, reg03_val);
0297     return 0;
0298 }
0299 
0300 #define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000  | \
0301                 SNDRV_PCM_RATE_16000 | \
0302                 SNDRV_PCM_RATE_32000 | \
0303                 SNDRV_PCM_RATE_44100 | \
0304                 SNDRV_PCM_RATE_48000 | \
0305                 SNDRV_PCM_RATE_96000)
0306 
0307 #define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE  | \
0308                SNDRV_PCM_FMTBIT_S20_3LE | \
0309                SNDRV_PCM_FMTBIT_S24_LE  | \
0310                SNDRV_PCM_FMTBIT_S32_LE)
0311 
0312 static const struct snd_soc_dai_ops rk3036_codec_dai_ops = {
0313     .set_fmt    = rk3036_codec_dai_set_fmt,
0314     .hw_params  = rk3036_codec_dai_hw_params,
0315 };
0316 
0317 static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
0318     {
0319         .name = "rk3036-codec-dai",
0320         .playback = {
0321             .stream_name = "Playback",
0322             .channels_min = 1,
0323             .channels_max = 2,
0324             .rates = RK3036_CODEC_RATES,
0325             .formats = RK3036_CODEC_FMTS,
0326         },
0327         .ops = &rk3036_codec_dai_ops,
0328         .symmetric_rate = 1,
0329     },
0330 };
0331 
0332 static void rk3036_codec_reset(struct snd_soc_component *component)
0333 {
0334     snd_soc_component_write(component, INNO_R00,
0335               INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
0336     snd_soc_component_write(component, INNO_R00,
0337               INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
0338 }
0339 
0340 static int rk3036_codec_probe(struct snd_soc_component *component)
0341 {
0342     rk3036_codec_reset(component);
0343     return 0;
0344 }
0345 
0346 static void rk3036_codec_remove(struct snd_soc_component *component)
0347 {
0348     rk3036_codec_reset(component);
0349 }
0350 
0351 static int rk3036_codec_set_bias_level(struct snd_soc_component *component,
0352                        enum snd_soc_bias_level level)
0353 {
0354     switch (level) {
0355     case SND_SOC_BIAS_STANDBY:
0356         /* set a big current for capacitor charging. */
0357         snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
0358         /* start precharge */
0359         snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_PRECHARGE);
0360 
0361         break;
0362 
0363     case SND_SOC_BIAS_OFF:
0364         /* set a big current for capacitor discharging. */
0365         snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
0366         /* start discharge. */
0367         snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_DISCHARGE);
0368 
0369         break;
0370     default:
0371         break;
0372     }
0373 
0374     return 0;
0375 }
0376 
0377 static const struct snd_soc_component_driver rk3036_codec_driver = {
0378     .probe          = rk3036_codec_probe,
0379     .remove         = rk3036_codec_remove,
0380     .set_bias_level     = rk3036_codec_set_bias_level,
0381     .controls       = rk3036_codec_dapm_controls,
0382     .num_controls       = ARRAY_SIZE(rk3036_codec_dapm_controls),
0383     .dapm_routes        = rk3036_codec_dapm_routes,
0384     .num_dapm_routes    = ARRAY_SIZE(rk3036_codec_dapm_routes),
0385     .dapm_widgets       = rk3036_codec_dapm_widgets,
0386     .num_dapm_widgets   = ARRAY_SIZE(rk3036_codec_dapm_widgets),
0387     .idle_bias_on       = 1,
0388     .use_pmdown_time    = 1,
0389     .endianness     = 1,
0390 };
0391 
0392 static const struct regmap_config rk3036_codec_regmap_config = {
0393     .reg_bits = 32,
0394     .reg_stride = 4,
0395     .val_bits = 32,
0396 };
0397 
0398 #define GRF_SOC_CON0        0x00140
0399 #define GRF_ACODEC_SEL      (BIT(10) | BIT(16 + 10))
0400 
0401 static int rk3036_codec_platform_probe(struct platform_device *pdev)
0402 {
0403     struct rk3036_codec_priv *priv;
0404     struct device_node *of_node = pdev->dev.of_node;
0405     void __iomem *base;
0406     struct regmap *grf;
0407     int ret;
0408 
0409     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0410     if (!priv)
0411         return -ENOMEM;
0412 
0413     base = devm_platform_ioremap_resource(pdev, 0);
0414     if (IS_ERR(base))
0415         return PTR_ERR(base);
0416 
0417     priv->base = base;
0418     priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base,
0419                          &rk3036_codec_regmap_config);
0420     if (IS_ERR(priv->regmap)) {
0421         dev_err(&pdev->dev, "init regmap failed\n");
0422         return PTR_ERR(priv->regmap);
0423     }
0424 
0425     grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf");
0426     if (IS_ERR(grf)) {
0427         dev_err(&pdev->dev, "needs 'rockchip,grf' property\n");
0428         return PTR_ERR(grf);
0429     }
0430     ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL);
0431     if (ret) {
0432         dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret);
0433         return ret;
0434     }
0435 
0436     priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk");
0437     if (IS_ERR(priv->pclk))
0438         return PTR_ERR(priv->pclk);
0439 
0440     ret = clk_prepare_enable(priv->pclk);
0441     if (ret < 0) {
0442         dev_err(&pdev->dev, "failed to enable clk\n");
0443         return ret;
0444     }
0445 
0446     priv->dev = &pdev->dev;
0447     dev_set_drvdata(&pdev->dev, priv);
0448 
0449     ret = devm_snd_soc_register_component(&pdev->dev, &rk3036_codec_driver,
0450                      rk3036_codec_dai_driver,
0451                      ARRAY_SIZE(rk3036_codec_dai_driver));
0452     if (ret) {
0453         clk_disable_unprepare(priv->pclk);
0454         dev_set_drvdata(&pdev->dev, NULL);
0455     }
0456 
0457     return ret;
0458 }
0459 
0460 static int rk3036_codec_platform_remove(struct platform_device *pdev)
0461 {
0462     struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
0463 
0464     clk_disable_unprepare(priv->pclk);
0465 
0466     return 0;
0467 }
0468 
0469 static const struct of_device_id rk3036_codec_of_match[] __maybe_unused = {
0470     { .compatible = "rockchip,rk3036-codec", },
0471     {}
0472 };
0473 MODULE_DEVICE_TABLE(of, rk3036_codec_of_match);
0474 
0475 static struct platform_driver rk3036_codec_platform_driver = {
0476     .driver = {
0477         .name = "rk3036-codec-platform",
0478         .of_match_table = of_match_ptr(rk3036_codec_of_match),
0479     },
0480     .probe = rk3036_codec_platform_probe,
0481     .remove = rk3036_codec_platform_remove,
0482 };
0483 
0484 module_platform_driver(rk3036_codec_platform_driver);
0485 
0486 MODULE_AUTHOR("Rockchip Inc.");
0487 MODULE_DESCRIPTION("Rockchip rk3036 codec driver");
0488 MODULE_LICENSE("GPL");