Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 //
0003 // cs35l45.c - CS35L45 ALSA SoC audio driver
0004 //
0005 // Copyright 2019-2022 Cirrus Logic, Inc.
0006 //
0007 // Author: James Schulman <james.schulman@cirrus.com>
0008 
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/module.h>
0011 #include <linux/pm_runtime.h>
0012 #include <linux/property.h>
0013 #include <linux/regulator/consumer.h>
0014 #include <sound/core.h>
0015 #include <sound/pcm.h>
0016 #include <sound/pcm_params.h>
0017 #include <sound/soc.h>
0018 #include <sound/tlv.h>
0019 
0020 #include "cs35l45.h"
0021 
0022 static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w,
0023                 struct snd_kcontrol *kcontrol, int event)
0024 {
0025     struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
0026     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
0027 
0028     dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event);
0029 
0030     switch (event) {
0031     case SND_SOC_DAPM_POST_PMU:
0032         regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES,
0033                  CS35L45_GLOBAL_EN_MASK);
0034 
0035         usleep_range(CS35L45_POST_GLOBAL_EN_US, CS35L45_POST_GLOBAL_EN_US + 100);
0036         break;
0037     case SND_SOC_DAPM_PRE_PMD:
0038         usleep_range(CS35L45_PRE_GLOBAL_DIS_US, CS35L45_PRE_GLOBAL_DIS_US + 100);
0039 
0040         regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 0);
0041         break;
0042     default:
0043         break;
0044     }
0045 
0046     return 0;
0047 }
0048 
0049 static const char * const cs35l45_asp_tx_txt[] = {
0050     "Zero", "ASP_RX1", "ASP_RX2",
0051     "VMON", "IMON", "ERR_VOL",
0052     "VDD_BATTMON", "VDD_BSTMON",
0053     "Interpolator", "IL_TARGET",
0054 };
0055 
0056 static const unsigned int cs35l45_asp_tx_val[] = {
0057     CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,
0058     CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,
0059     CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON,
0060     CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET,
0061 };
0062 
0063 static const struct soc_enum cs35l45_asp_tx_enums[] = {
0064     SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK,
0065                   ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
0066                   cs35l45_asp_tx_val),
0067     SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK,
0068                   ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
0069                   cs35l45_asp_tx_val),
0070     SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT, 0, CS35L45_PCM_SRC_MASK,
0071                   ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
0072                   cs35l45_asp_tx_val),
0073     SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK,
0074                   ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
0075                   cs35l45_asp_tx_val),
0076     SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK,
0077                   ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
0078                   cs35l45_asp_tx_val),
0079 };
0080 
0081 static const char * const cs35l45_dac_txt[] = {
0082     "Zero", "ASP_RX1", "ASP_RX2"
0083 };
0084 
0085 static const unsigned int cs35l45_dac_val[] = {
0086     CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2
0087 };
0088 
0089 static const struct soc_enum cs35l45_dacpcm_enums[] = {
0090     SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK,
0091                   ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt,
0092                   cs35l45_dac_val),
0093 };
0094 
0095 static const struct snd_kcontrol_new cs35l45_asp_muxes[] = {
0096     SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]),
0097     SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]),
0098     SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]),
0099     SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]),
0100     SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]),
0101 };
0102 
0103 static const struct snd_kcontrol_new cs35l45_dac_muxes[] = {
0104     SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]),
0105 };
0106 
0107 static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
0108     SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0,
0109                 cs35l45_global_en_ev,
0110                 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
0111     SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0),
0112 
0113     SND_SOC_DAPM_SIGGEN("VMON_SRC"),
0114     SND_SOC_DAPM_SIGGEN("IMON_SRC"),
0115     SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),
0116     SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"),
0117     SND_SOC_DAPM_SIGGEN("ERR_VOL"),
0118     SND_SOC_DAPM_SIGGEN("AMP_INTP"),
0119     SND_SOC_DAPM_SIGGEN("IL_TARGET"),
0120     SND_SOC_DAPM_ADC("VMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0),
0121     SND_SOC_DAPM_ADC("IMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0),
0122     SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, CS35L45_BLOCK_ENABLES,
0123              CS35L45_VDD_BATTMON_EN_SHIFT, 0),
0124     SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, CS35L45_BLOCK_ENABLES,
0125              CS35L45_VDD_BSTMON_EN_SHIFT, 0),
0126 
0127     SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0),
0128     SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0),
0129 
0130     SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX1_EN_SHIFT, 0),
0131     SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX2_EN_SHIFT, 0),
0132     SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL, 2, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX3_EN_SHIFT, 0),
0133     SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX4_EN_SHIFT, 0),
0134     SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0),
0135 
0136     SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]),
0137     SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]),
0138     SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]),
0139     SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]),
0140     SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]),
0141 
0142     SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),
0143 
0144     SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0),
0145 
0146     SND_SOC_DAPM_OUTPUT("SPK"),
0147 };
0148 
0149 #define CS35L45_ASP_MUX_ROUTE(name) \
0150     { name" Source", "ASP_RX1",  "ASP_RX1" }, \
0151     { name" Source", "ASP_RX2",  "ASP_RX2" }, \
0152     { name" Source", "VMON",     "VMON" }, \
0153     { name" Source", "IMON",     "IMON" }, \
0154     { name" Source", "ERR_VOL",  "ERR_VOL" }, \
0155     { name" Source", "VDD_BATTMON",  "VDD_BATTMON" }, \
0156     { name" Source", "VDD_BSTMON",   "VDD_BSTMON" }, \
0157     { name" Source", "Interpolator", "AMP_INTP" }, \
0158     { name" Source", "IL_TARGET",    "IL_TARGET" }
0159 
0160 #define CS35L45_DAC_MUX_ROUTE(name) \
0161     { name" Source", "ASP_RX1", "ASP_RX1" }, \
0162     { name" Source", "ASP_RX2", "ASP_RX2" }
0163 
0164 static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
0165     /* Feedback */
0166     { "VMON", NULL, "VMON_SRC" },
0167     { "IMON", NULL, "IMON_SRC" },
0168     { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" },
0169     { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" },
0170 
0171     { "Capture", NULL, "ASP_TX1"},
0172     { "Capture", NULL, "ASP_TX2"},
0173     { "Capture", NULL, "ASP_TX3"},
0174     { "Capture", NULL, "ASP_TX4"},
0175     { "Capture", NULL, "ASP_TX5"},
0176     { "ASP_TX1", NULL, "ASP_TX1 Source"},
0177     { "ASP_TX2", NULL, "ASP_TX2 Source"},
0178     { "ASP_TX3", NULL, "ASP_TX3 Source"},
0179     { "ASP_TX4", NULL, "ASP_TX4 Source"},
0180     { "ASP_TX5", NULL, "ASP_TX5 Source"},
0181 
0182     { "ASP_TX1", NULL, "ASP_EN" },
0183     { "ASP_TX2", NULL, "ASP_EN" },
0184     { "ASP_TX3", NULL, "ASP_EN" },
0185     { "ASP_TX4", NULL, "ASP_EN" },
0186     { "ASP_TX1", NULL, "GLOBAL_EN" },
0187     { "ASP_TX2", NULL, "GLOBAL_EN" },
0188     { "ASP_TX3", NULL, "GLOBAL_EN" },
0189     { "ASP_TX4", NULL, "GLOBAL_EN" },
0190     { "ASP_TX5", NULL, "GLOBAL_EN" },
0191 
0192     CS35L45_ASP_MUX_ROUTE("ASP_TX1"),
0193     CS35L45_ASP_MUX_ROUTE("ASP_TX2"),
0194     CS35L45_ASP_MUX_ROUTE("ASP_TX3"),
0195     CS35L45_ASP_MUX_ROUTE("ASP_TX4"),
0196     CS35L45_ASP_MUX_ROUTE("ASP_TX5"),
0197 
0198     /* Playback */
0199     { "ASP_RX1", NULL, "Playback" },
0200     { "ASP_RX2", NULL, "Playback" },
0201     { "ASP_RX1", NULL, "ASP_EN" },
0202     { "ASP_RX2", NULL, "ASP_EN" },
0203 
0204     { "AMP", NULL, "DACPCM1 Source"},
0205     { "AMP", NULL, "GLOBAL_EN"},
0206 
0207     CS35L45_DAC_MUX_ROUTE("DACPCM1"),
0208 
0209     { "SPK", NULL, "AMP"},
0210 };
0211 
0212 static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);
0213 
0214 static const struct snd_kcontrol_new cs35l45_controls[] = {
0215     /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
0216     SOC_SINGLE_S_TLV("Digital PCM Volume",
0217              CS35L45_AMP_PCM_CONTROL,
0218              CS35L45_AMP_VOL_PCM_SHIFT + 1,
0219              -409, 48,
0220              (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1,
0221              0, cs35l45_dig_pcm_vol_tlv),
0222 };
0223 
0224 static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq)
0225 {
0226     unsigned int val;
0227     int freq_id;
0228 
0229     freq_id = cs35l45_get_clk_freq_id(freq);
0230     if (freq_id < 0) {
0231         dev_err(cs35l45->dev, "Invalid freq: %u\n", freq);
0232         return -EINVAL;
0233     }
0234 
0235     regmap_read(cs35l45->regmap, CS35L45_REFCLK_INPUT, &val);
0236     val = (val & CS35L45_PLL_REFCLK_FREQ_MASK) >> CS35L45_PLL_REFCLK_FREQ_SHIFT;
0237     if (val == freq_id)
0238         return 0;
0239 
0240     regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK);
0241     regmap_update_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT,
0242                CS35L45_PLL_REFCLK_FREQ_MASK,
0243                freq_id << CS35L45_PLL_REFCLK_FREQ_SHIFT);
0244     regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK);
0245     regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK);
0246     regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK);
0247 
0248     return 0;
0249 }
0250 
0251 static int cs35l45_asp_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
0252 {
0253     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(codec_dai->component);
0254     unsigned int asp_fmt, fsync_inv, bclk_inv;
0255 
0256     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0257     case SND_SOC_DAIFMT_CBC_CFC:
0258         break;
0259     default:
0260         dev_err(cs35l45->dev, "Invalid DAI clocking\n");
0261         return -EINVAL;
0262     }
0263 
0264     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0265     case SND_SOC_DAIFMT_DSP_A:
0266         asp_fmt = CS35l45_ASP_FMT_DSP_A;
0267         break;
0268     case SND_SOC_DAIFMT_I2S:
0269         asp_fmt = CS35L45_ASP_FMT_I2S;
0270         break;
0271     default:
0272         dev_err(cs35l45->dev, "Invalid DAI format\n");
0273         return -EINVAL;
0274     }
0275 
0276     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0277     case SND_SOC_DAIFMT_NB_IF:
0278         fsync_inv = 1;
0279         bclk_inv = 0;
0280         break;
0281     case SND_SOC_DAIFMT_IB_NF:
0282         fsync_inv = 0;
0283         bclk_inv = 1;
0284         break;
0285     case SND_SOC_DAIFMT_IB_IF:
0286         fsync_inv = 1;
0287         bclk_inv = 1;
0288         break;
0289     case SND_SOC_DAIFMT_NB_NF:
0290         fsync_inv = 0;
0291         bclk_inv = 0;
0292         break;
0293     default:
0294         dev_warn(cs35l45->dev, "Invalid DAI clock polarity\n");
0295         return -EINVAL;
0296     }
0297 
0298     regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,
0299                CS35L45_ASP_FMT_MASK |
0300                CS35L45_ASP_FSYNC_INV_MASK |
0301                CS35L45_ASP_BCLK_INV_MASK,
0302                (asp_fmt << CS35L45_ASP_FMT_SHIFT) |
0303                (fsync_inv << CS35L45_ASP_FSYNC_INV_SHIFT) |
0304                (bclk_inv << CS35L45_ASP_BCLK_INV_SHIFT));
0305 
0306     return 0;
0307 }
0308 
0309 static int cs35l45_asp_hw_params(struct snd_pcm_substream *substream,
0310                  struct snd_pcm_hw_params *params,
0311                  struct snd_soc_dai *dai)
0312 {
0313     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);
0314     unsigned int asp_width, asp_wl, global_fs, slot_multiple, asp_fmt;
0315     int bclk;
0316 
0317     switch (params_rate(params)) {
0318     case 44100:
0319         global_fs = CS35L45_44P100_KHZ;
0320         break;
0321     case 48000:
0322         global_fs = CS35L45_48P0_KHZ;
0323         break;
0324     case 88200:
0325         global_fs = CS35L45_88P200_KHZ;
0326         break;
0327     case 96000:
0328         global_fs = CS35L45_96P0_KHZ;
0329         break;
0330     default:
0331         dev_warn(cs35l45->dev, "Unsupported sample rate (%d)\n",
0332              params_rate(params));
0333         return -EINVAL;
0334     }
0335 
0336     regmap_update_bits(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE,
0337                CS35L45_GLOBAL_FS_MASK,
0338                global_fs << CS35L45_GLOBAL_FS_SHIFT);
0339 
0340     asp_wl = params_width(params);
0341 
0342     if (cs35l45->slot_width)
0343         asp_width = cs35l45->slot_width;
0344     else
0345         asp_width = params_width(params);
0346 
0347     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0348         regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,
0349                    CS35L45_ASP_WIDTH_RX_MASK,
0350                    asp_width << CS35L45_ASP_WIDTH_RX_SHIFT);
0351 
0352         regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL5,
0353                    CS35L45_ASP_WL_MASK,
0354                    asp_wl << CS35L45_ASP_WL_SHIFT);
0355     } else {
0356         regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2,
0357                    CS35L45_ASP_WIDTH_TX_MASK,
0358                    asp_width << CS35L45_ASP_WIDTH_TX_SHIFT);
0359 
0360         regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL1,
0361                    CS35L45_ASP_WL_MASK,
0362                    asp_wl << CS35L45_ASP_WL_SHIFT);
0363     }
0364 
0365     if (cs35l45->sysclk_set)
0366         return 0;
0367 
0368     /* I2S always has an even number of channels */
0369     regmap_read(cs35l45->regmap, CS35L45_ASP_CONTROL2, &asp_fmt);
0370     asp_fmt = (asp_fmt & CS35L45_ASP_FMT_MASK) >> CS35L45_ASP_FMT_SHIFT;
0371     if (asp_fmt == CS35L45_ASP_FMT_I2S)
0372         slot_multiple = 2;
0373     else
0374         slot_multiple = 1;
0375 
0376     bclk = snd_soc_tdm_params_to_bclk(params, asp_width,
0377                       cs35l45->slot_count, slot_multiple);
0378 
0379     return cs35l45_set_pll(cs35l45, bclk);
0380 }
0381 
0382 static int cs35l45_asp_set_tdm_slot(struct snd_soc_dai *dai,
0383                     unsigned int tx_mask, unsigned int rx_mask,
0384                     int slots, int slot_width)
0385 {
0386     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);
0387 
0388     if (slot_width && ((slot_width < 16) || (slot_width > 128)))
0389         return -EINVAL;
0390 
0391     cs35l45->slot_width = slot_width;
0392     cs35l45->slot_count = slots;
0393 
0394     return 0;
0395 }
0396 
0397 static int cs35l45_asp_set_sysclk(struct snd_soc_dai *dai,
0398                   int clk_id, unsigned int freq, int dir)
0399 {
0400     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);
0401     int ret;
0402 
0403     if (clk_id != 0) {
0404         dev_err(cs35l45->dev, "Invalid clk_id %d\n", clk_id);
0405         return -EINVAL;
0406     }
0407 
0408     cs35l45->sysclk_set = false;
0409     if (freq == 0)
0410         return 0;
0411 
0412     ret = cs35l45_set_pll(cs35l45, freq);
0413     if (ret < 0)
0414         return -EINVAL;
0415 
0416     cs35l45->sysclk_set = true;
0417 
0418     return 0;
0419 }
0420 
0421 static int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
0422 {
0423     struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component);
0424     unsigned int global_fs, val, hpf_tune;
0425 
0426     if (mute)
0427         return 0;
0428 
0429     regmap_read(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, &global_fs);
0430     global_fs = (global_fs & CS35L45_GLOBAL_FS_MASK) >> CS35L45_GLOBAL_FS_SHIFT;
0431     switch (global_fs) {
0432     case CS35L45_44P100_KHZ:
0433         hpf_tune = CS35L45_HPF_44P1;
0434         break;
0435     case CS35L45_88P200_KHZ:
0436         hpf_tune = CS35L45_HPF_88P2;
0437         break;
0438     default:
0439         hpf_tune = CS35l45_HPF_DEFAULT;
0440         break;
0441     }
0442 
0443     regmap_read(cs35l45->regmap, CS35L45_AMP_PCM_HPF_TST, &val);
0444     if (val != hpf_tune) {
0445         struct reg_sequence hpf_override_seq[] = {
0446             { 0x00000040,           0x00000055 },
0447             { 0x00000040,           0x000000AA },
0448             { 0x00000044,           0x00000055 },
0449             { 0x00000044,           0x000000AA },
0450             { CS35L45_AMP_PCM_HPF_TST,  hpf_tune },
0451             { 0x00000040,           0x00000000 },
0452             { 0x00000044,           0x00000000 },
0453         };
0454         regmap_multi_reg_write(cs35l45->regmap, hpf_override_seq,
0455                        ARRAY_SIZE(hpf_override_seq));
0456     }
0457 
0458     return 0;
0459 }
0460 
0461 static const struct snd_soc_dai_ops cs35l45_asp_dai_ops = {
0462     .set_fmt = cs35l45_asp_set_fmt,
0463     .hw_params = cs35l45_asp_hw_params,
0464     .set_tdm_slot = cs35l45_asp_set_tdm_slot,
0465     .set_sysclk = cs35l45_asp_set_sysclk,
0466     .mute_stream = cs35l45_mute_stream,
0467 };
0468 
0469 static struct snd_soc_dai_driver cs35l45_dai[] = {
0470     {
0471         .name = "cs35l45",
0472         .playback = {
0473             .stream_name = "Playback",
0474             .channels_min = 1,
0475             .channels_max = 2,
0476             .rates = CS35L45_RATES,
0477             .formats = CS35L45_FORMATS,
0478         },
0479         .capture = {
0480             .stream_name = "Capture",
0481             .channels_min = 1,
0482             .channels_max = 5,
0483             .rates = CS35L45_RATES,
0484             .formats = CS35L45_FORMATS,
0485         },
0486         .symmetric_rate = true,
0487         .symmetric_sample_bits = true,
0488         .ops = &cs35l45_asp_dai_ops,
0489     },
0490 };
0491 
0492 static const struct snd_soc_component_driver cs35l45_component = {
0493     .dapm_widgets = cs35l45_dapm_widgets,
0494     .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets),
0495 
0496     .dapm_routes = cs35l45_dapm_routes,
0497     .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes),
0498 
0499     .controls = cs35l45_controls,
0500     .num_controls = ARRAY_SIZE(cs35l45_controls),
0501 
0502     .name = "cs35l45",
0503 
0504     .endianness = 1,
0505 };
0506 
0507 static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
0508 {
0509     struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
0510 
0511     regcache_cache_only(cs35l45->regmap, true);
0512 
0513     dev_dbg(cs35l45->dev, "Runtime suspended\n");
0514 
0515     return 0;
0516 }
0517 
0518 static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
0519 {
0520     struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
0521     int ret;
0522 
0523     dev_dbg(cs35l45->dev, "Runtime resume\n");
0524 
0525     regcache_cache_only(cs35l45->regmap, false);
0526     ret = regcache_sync(cs35l45->regmap);
0527     if (ret != 0)
0528         dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);
0529 
0530     /* Clear global error status */
0531     regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
0532     regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
0533     regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
0534     return ret;
0535 }
0536 
0537 static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
0538 {
0539     unsigned int val;
0540 
0541     if (device_property_read_u32(cs35l45->dev,
0542                      "cirrus,asp-sdout-hiz-ctrl", &val) == 0) {
0543         regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3,
0544                    CS35L45_ASP_DOUT_HIZ_CTRL_MASK,
0545                    val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT);
0546     }
0547 
0548     return 0;
0549 }
0550 
0551 static int cs35l45_initialize(struct cs35l45_private *cs35l45)
0552 {
0553     struct device *dev = cs35l45->dev;
0554     unsigned int dev_id[5];
0555     unsigned int sts;
0556     int ret;
0557 
0558     ret = regmap_read_poll_timeout(cs35l45->regmap, CS35L45_IRQ1_EINT_4, sts,
0559                        (sts & CS35L45_OTP_BOOT_DONE_STS_MASK),
0560                        1000, 5000);
0561     if (ret < 0) {
0562         dev_err(cs35l45->dev, "Timeout waiting for OTP boot\n");
0563         return ret;
0564     }
0565 
0566     ret = regmap_bulk_read(cs35l45->regmap, CS35L45_DEVID, dev_id, ARRAY_SIZE(dev_id));
0567     if (ret) {
0568         dev_err(cs35l45->dev, "Get Device ID failed: %d\n", ret);
0569         return ret;
0570     }
0571 
0572     switch (dev_id[0]) {
0573     case 0x35A450:
0574         break;
0575     default:
0576         dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]);
0577         return -ENODEV;
0578     }
0579 
0580     dev_info(cs35l45->dev, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n",
0581          dev_id[1], dev_id[4]);
0582 
0583     regmap_write(cs35l45->regmap, CS35L45_IRQ1_EINT_4,
0584              CS35L45_OTP_BOOT_DONE_STS_MASK | CS35L45_OTP_BUSY_MASK);
0585 
0586     ret = cs35l45_apply_patch(cs35l45);
0587     if (ret < 0) {
0588         dev_err(dev, "Failed to apply init patch %d\n", ret);
0589         return ret;
0590     }
0591 
0592     ret = cs35l45_apply_property_config(cs35l45);
0593     if (ret < 0)
0594         return ret;
0595 
0596     pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000);
0597     pm_runtime_use_autosuspend(cs35l45->dev);
0598     pm_runtime_set_active(cs35l45->dev);
0599     pm_runtime_enable(cs35l45->dev);
0600 
0601     return 0;
0602 }
0603 
0604 int cs35l45_probe(struct cs35l45_private *cs35l45)
0605 {
0606     struct device *dev = cs35l45->dev;
0607     int ret;
0608 
0609     cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt");
0610     if (IS_ERR(cs35l45->vdd_batt))
0611         return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_batt),
0612                      "Failed to request vdd-batt\n");
0613 
0614     cs35l45->vdd_a = devm_regulator_get(dev, "vdd-a");
0615     if (IS_ERR(cs35l45->vdd_a))
0616         return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_a),
0617                      "Failed to request vdd-a\n");
0618 
0619     /* VDD_BATT must always be enabled before other supplies */
0620     ret = regulator_enable(cs35l45->vdd_batt);
0621     if (ret < 0)
0622         return dev_err_probe(dev, ret, "Failed to enable vdd-batt\n");
0623 
0624     ret = regulator_enable(cs35l45->vdd_a);
0625     if (ret < 0)
0626         return dev_err_probe(dev, ret, "Failed to enable vdd-a\n");
0627 
0628     /* If reset is shared only one instance can claim it */
0629     cs35l45->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
0630     if (IS_ERR(cs35l45->reset_gpio)) {
0631         ret = PTR_ERR(cs35l45->reset_gpio);
0632         cs35l45->reset_gpio = NULL;
0633         if (ret == -EBUSY) {
0634             dev_dbg(dev, "Reset line busy, assuming shared reset\n");
0635         } else {
0636             dev_err_probe(dev, ret, "Failed to get reset GPIO\n");
0637             goto err;
0638         }
0639     }
0640 
0641     if (cs35l45->reset_gpio) {
0642         usleep_range(CS35L45_RESET_HOLD_US, CS35L45_RESET_HOLD_US + 100);
0643         gpiod_set_value_cansleep(cs35l45->reset_gpio, 1);
0644     }
0645 
0646     usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100);
0647 
0648     ret = cs35l45_initialize(cs35l45);
0649     if (ret < 0)
0650         goto err_reset;
0651 
0652     ret = devm_snd_soc_register_component(dev, &cs35l45_component,
0653                           cs35l45_dai,
0654                           ARRAY_SIZE(cs35l45_dai));
0655     if (ret < 0)
0656         goto err_reset;
0657 
0658     return 0;
0659 
0660 err_reset:
0661     gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
0662 err:
0663     regulator_disable(cs35l45->vdd_a);
0664     regulator_disable(cs35l45->vdd_batt);
0665 
0666     return ret;
0667 }
0668 EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
0669 
0670 void cs35l45_remove(struct cs35l45_private *cs35l45)
0671 {
0672     pm_runtime_disable(cs35l45->dev);
0673 
0674     gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
0675     regulator_disable(cs35l45->vdd_a);
0676     /* VDD_BATT must be the last to power-off */
0677     regulator_disable(cs35l45->vdd_batt);
0678 }
0679 EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
0680 
0681 const struct dev_pm_ops cs35l45_pm_ops = {
0682     SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
0683 };
0684 EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
0685 
0686 MODULE_DESCRIPTION("ASoC CS35L45 driver");
0687 MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
0688 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
0689 MODULE_LICENSE("Dual BSD/GPL");
0690 MODULE_IMPORT_NS(SND_SOC_CS35L45_TABLES);