0001
0002
0003
0004
0005
0006
0007
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
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
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
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
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
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
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
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
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);