0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/init.h>
0013 #include <linux/delay.h>
0014 #include <linux/pm.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/regulator/consumer.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019 #include <sound/core.h>
0020 #include <sound/pcm.h>
0021 #include <sound/pcm_params.h>
0022 #include <sound/soc.h>
0023 #include <sound/jack.h>
0024 #include <sound/initval.h>
0025 #include <sound/tlv.h>
0026
0027 #include "pcm186x.h"
0028
0029 static const char * const pcm186x_supply_names[] = {
0030 "avdd",
0031 "dvdd",
0032 "iovdd",
0033 };
0034 #define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
0035
0036 struct pcm186x_priv {
0037 struct regmap *regmap;
0038 struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
0039 unsigned int sysclk;
0040 unsigned int tdm_offset;
0041 bool is_tdm_mode;
0042 bool is_provider_mode;
0043 };
0044
0045 static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0);
0046
0047 static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
0048 SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
0049 PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
0050 pcm186x_pga_tlv),
0051 };
0052
0053 static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
0054 SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
0055 PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
0056 pcm186x_pga_tlv),
0057 SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
0058 PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
0059 pcm186x_pga_tlv),
0060 };
0061
0062 static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
0063 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0064 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0065 0x10, 0x20, 0x30
0066 };
0067
0068 static const char * const pcm186x_adcl_input_channel_sel_text[] = {
0069 "No Select",
0070 "VINL1[SE]",
0071 "VINL2[SE]",
0072 "VINL2[SE] + VINL1[SE]",
0073 "VINL3[SE]",
0074 "VINL3[SE] + VINL1[SE]",
0075 "VINL3[SE] + VINL2[SE]",
0076 "VINL3[SE] + VINL2[SE] + VINL1[SE]",
0077 "VINL4[SE]",
0078 "VINL4[SE] + VINL1[SE]",
0079 "VINL4[SE] + VINL2[SE]",
0080 "VINL4[SE] + VINL2[SE] + VINL1[SE]",
0081 "VINL4[SE] + VINL3[SE]",
0082 "VINL4[SE] + VINL3[SE] + VINL1[SE]",
0083 "VINL4[SE] + VINL3[SE] + VINL2[SE]",
0084 "VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
0085 "{VIN1P, VIN1M}[DIFF]",
0086 "{VIN4P, VIN4M}[DIFF]",
0087 "{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
0088 };
0089
0090 static const char * const pcm186x_adcr_input_channel_sel_text[] = {
0091 "No Select",
0092 "VINR1[SE]",
0093 "VINR2[SE]",
0094 "VINR2[SE] + VINR1[SE]",
0095 "VINR3[SE]",
0096 "VINR3[SE] + VINR1[SE]",
0097 "VINR3[SE] + VINR2[SE]",
0098 "VINR3[SE] + VINR2[SE] + VINR1[SE]",
0099 "VINR4[SE]",
0100 "VINR4[SE] + VINR1[SE]",
0101 "VINR4[SE] + VINR2[SE]",
0102 "VINR4[SE] + VINR2[SE] + VINR1[SE]",
0103 "VINR4[SE] + VINR3[SE]",
0104 "VINR4[SE] + VINR3[SE] + VINR1[SE]",
0105 "VINR4[SE] + VINR3[SE] + VINR2[SE]",
0106 "VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
0107 "{VIN2P, VIN2M}[DIFF]",
0108 "{VIN3P, VIN3M}[DIFF]",
0109 "{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
0110 };
0111
0112 static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
0113 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
0114 PCM186X_ADC_INPUT_SEL_MASK,
0115 ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
0116 pcm186x_adcl_input_channel_sel_text,
0117 pcm186x_adc_input_channel_sel_value),
0118 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
0119 PCM186X_ADC_INPUT_SEL_MASK,
0120 ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
0121 pcm186x_adcr_input_channel_sel_text,
0122 pcm186x_adc_input_channel_sel_value),
0123 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
0124 PCM186X_ADC_INPUT_SEL_MASK,
0125 ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
0126 pcm186x_adcl_input_channel_sel_text,
0127 pcm186x_adc_input_channel_sel_value),
0128 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
0129 PCM186X_ADC_INPUT_SEL_MASK,
0130 ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
0131 pcm186x_adcr_input_channel_sel_text,
0132 pcm186x_adc_input_channel_sel_value),
0133 };
0134
0135 static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
0136 SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
0137 SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
0138 SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
0139 SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
0140 };
0141
0142 static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
0143 SND_SOC_DAPM_INPUT("VINL1"),
0144 SND_SOC_DAPM_INPUT("VINR1"),
0145 SND_SOC_DAPM_INPUT("VINL2"),
0146 SND_SOC_DAPM_INPUT("VINR2"),
0147 SND_SOC_DAPM_INPUT("VINL3"),
0148 SND_SOC_DAPM_INPUT("VINR3"),
0149 SND_SOC_DAPM_INPUT("VINL4"),
0150 SND_SOC_DAPM_INPUT("VINR4"),
0151
0152 SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
0153 &pcm186x_adc_mux_controls[0]),
0154 SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
0155 &pcm186x_adc_mux_controls[1]),
0156
0157
0158
0159
0160
0161 SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 1),
0162 };
0163
0164 static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
0165 SND_SOC_DAPM_INPUT("VINL1"),
0166 SND_SOC_DAPM_INPUT("VINR1"),
0167 SND_SOC_DAPM_INPUT("VINL2"),
0168 SND_SOC_DAPM_INPUT("VINR2"),
0169 SND_SOC_DAPM_INPUT("VINL3"),
0170 SND_SOC_DAPM_INPUT("VINR3"),
0171 SND_SOC_DAPM_INPUT("VINL4"),
0172 SND_SOC_DAPM_INPUT("VINR4"),
0173
0174 SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
0175 &pcm186x_adc_mux_controls[0]),
0176 SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
0177 &pcm186x_adc_mux_controls[1]),
0178 SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
0179 &pcm186x_adc_mux_controls[2]),
0180 SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
0181 &pcm186x_adc_mux_controls[3]),
0182
0183
0184
0185
0186
0187 SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 1),
0188 SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 1),
0189 };
0190
0191 static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
0192 { "ADC Left Capture Source", NULL, "VINL1" },
0193 { "ADC Left Capture Source", NULL, "VINR1" },
0194 { "ADC Left Capture Source", NULL, "VINL2" },
0195 { "ADC Left Capture Source", NULL, "VINR2" },
0196 { "ADC Left Capture Source", NULL, "VINL3" },
0197 { "ADC Left Capture Source", NULL, "VINR3" },
0198 { "ADC Left Capture Source", NULL, "VINL4" },
0199 { "ADC Left Capture Source", NULL, "VINR4" },
0200
0201 { "ADC", NULL, "ADC Left Capture Source" },
0202
0203 { "ADC Right Capture Source", NULL, "VINL1" },
0204 { "ADC Right Capture Source", NULL, "VINR1" },
0205 { "ADC Right Capture Source", NULL, "VINL2" },
0206 { "ADC Right Capture Source", NULL, "VINR2" },
0207 { "ADC Right Capture Source", NULL, "VINL3" },
0208 { "ADC Right Capture Source", NULL, "VINR3" },
0209 { "ADC Right Capture Source", NULL, "VINL4" },
0210 { "ADC Right Capture Source", NULL, "VINR4" },
0211
0212 { "ADC", NULL, "ADC Right Capture Source" },
0213 };
0214
0215 static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
0216 { "ADC1 Left Capture Source", NULL, "VINL1" },
0217 { "ADC1 Left Capture Source", NULL, "VINR1" },
0218 { "ADC1 Left Capture Source", NULL, "VINL2" },
0219 { "ADC1 Left Capture Source", NULL, "VINR2" },
0220 { "ADC1 Left Capture Source", NULL, "VINL3" },
0221 { "ADC1 Left Capture Source", NULL, "VINR3" },
0222 { "ADC1 Left Capture Source", NULL, "VINL4" },
0223 { "ADC1 Left Capture Source", NULL, "VINR4" },
0224
0225 { "ADC1", NULL, "ADC1 Left Capture Source" },
0226
0227 { "ADC1 Right Capture Source", NULL, "VINL1" },
0228 { "ADC1 Right Capture Source", NULL, "VINR1" },
0229 { "ADC1 Right Capture Source", NULL, "VINL2" },
0230 { "ADC1 Right Capture Source", NULL, "VINR2" },
0231 { "ADC1 Right Capture Source", NULL, "VINL3" },
0232 { "ADC1 Right Capture Source", NULL, "VINR3" },
0233 { "ADC1 Right Capture Source", NULL, "VINL4" },
0234 { "ADC1 Right Capture Source", NULL, "VINR4" },
0235
0236 { "ADC1", NULL, "ADC1 Right Capture Source" },
0237
0238 { "ADC2 Left Capture Source", NULL, "VINL1" },
0239 { "ADC2 Left Capture Source", NULL, "VINR1" },
0240 { "ADC2 Left Capture Source", NULL, "VINL2" },
0241 { "ADC2 Left Capture Source", NULL, "VINR2" },
0242 { "ADC2 Left Capture Source", NULL, "VINL3" },
0243 { "ADC2 Left Capture Source", NULL, "VINR3" },
0244 { "ADC2 Left Capture Source", NULL, "VINL4" },
0245 { "ADC2 Left Capture Source", NULL, "VINR4" },
0246
0247 { "ADC2", NULL, "ADC2 Left Capture Source" },
0248
0249 { "ADC2 Right Capture Source", NULL, "VINL1" },
0250 { "ADC2 Right Capture Source", NULL, "VINR1" },
0251 { "ADC2 Right Capture Source", NULL, "VINL2" },
0252 { "ADC2 Right Capture Source", NULL, "VINR2" },
0253 { "ADC2 Right Capture Source", NULL, "VINL3" },
0254 { "ADC2 Right Capture Source", NULL, "VINR3" },
0255 { "ADC2 Right Capture Source", NULL, "VINL4" },
0256 { "ADC2 Right Capture Source", NULL, "VINR4" },
0257
0258 { "ADC2", NULL, "ADC2 Right Capture Source" },
0259 };
0260
0261 static int pcm186x_hw_params(struct snd_pcm_substream *substream,
0262 struct snd_pcm_hw_params *params,
0263 struct snd_soc_dai *dai)
0264 {
0265 struct snd_soc_component *component = dai->component;
0266 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0267 unsigned int rate = params_rate(params);
0268 snd_pcm_format_t format = params_format(params);
0269 unsigned int width = params_width(params);
0270 unsigned int channels = params_channels(params);
0271 unsigned int div_lrck;
0272 unsigned int div_bck;
0273 u8 tdm_tx_sel = 0;
0274 u8 pcm_cfg = 0;
0275
0276 dev_dbg(component->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
0277 __func__, rate, format, width, channels);
0278
0279 switch (width) {
0280 case 16:
0281 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
0282 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
0283 PCM186X_PCM_CFG_TX_WLEN_16 <<
0284 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
0285 break;
0286 case 20:
0287 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
0288 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
0289 PCM186X_PCM_CFG_TX_WLEN_20 <<
0290 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
0291 break;
0292 case 24:
0293 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
0294 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
0295 PCM186X_PCM_CFG_TX_WLEN_24 <<
0296 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
0297 break;
0298 case 32:
0299 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
0300 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
0301 PCM186X_PCM_CFG_TX_WLEN_32 <<
0302 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
0303 break;
0304 default:
0305 return -EINVAL;
0306 }
0307
0308 snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
0309 PCM186X_PCM_CFG_RX_WLEN_MASK |
0310 PCM186X_PCM_CFG_TX_WLEN_MASK,
0311 pcm_cfg);
0312
0313 div_lrck = width * channels;
0314
0315 if (priv->is_tdm_mode) {
0316
0317 switch (channels) {
0318 case 2:
0319 tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
0320 break;
0321 case 4:
0322 tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
0323 break;
0324 case 6:
0325 tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
0326 break;
0327 default:
0328 return -EINVAL;
0329 }
0330
0331 snd_soc_component_update_bits(component, PCM186X_TDM_TX_SEL,
0332 PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
0333
0334
0335 div_lrck = 256;
0336
0337
0338 snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
0339 PCM186X_PCM_CFG_TDM_LRCK_MODE,
0340 PCM186X_PCM_CFG_TDM_LRCK_MODE);
0341 }
0342
0343
0344 if (priv->is_provider_mode) {
0345 div_bck = priv->sysclk / (div_lrck * rate);
0346
0347 dev_dbg(component->dev,
0348 "%s() master_clk=%u div_bck=%u div_lrck=%u\n",
0349 __func__, priv->sysclk, div_bck, div_lrck);
0350
0351 snd_soc_component_write(component, PCM186X_BCK_DIV, div_bck - 1);
0352 snd_soc_component_write(component, PCM186X_LRK_DIV, div_lrck - 1);
0353 }
0354
0355 return 0;
0356 }
0357
0358 static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
0359 {
0360 struct snd_soc_component *component = dai->component;
0361 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0362 u8 clk_ctrl = 0;
0363 u8 pcm_cfg = 0;
0364
0365 dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format);
0366
0367 switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0368 case SND_SOC_DAIFMT_CBP_CFP:
0369 if (!priv->sysclk) {
0370 dev_err(component->dev, "operating in provider mode requires sysclock to be configured\n");
0371 return -EINVAL;
0372 }
0373 clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
0374 priv->is_provider_mode = true;
0375 break;
0376 case SND_SOC_DAIFMT_CBC_CFC:
0377 priv->is_provider_mode = false;
0378 break;
0379 default:
0380 dev_err(component->dev, "Invalid DAI master/slave interface\n");
0381 return -EINVAL;
0382 }
0383
0384
0385 switch (format & SND_SOC_DAIFMT_INV_MASK) {
0386 case SND_SOC_DAIFMT_NB_NF:
0387 break;
0388 default:
0389 dev_err(component->dev, "Inverted DAI clocks not supported\n");
0390 return -EINVAL;
0391 }
0392
0393
0394 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
0395 case SND_SOC_DAIFMT_I2S:
0396 pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
0397 break;
0398 case SND_SOC_DAIFMT_LEFT_J:
0399 pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
0400 break;
0401 case SND_SOC_DAIFMT_DSP_A:
0402 priv->tdm_offset += 1;
0403 fallthrough;
0404
0405
0406
0407 case SND_SOC_DAIFMT_DSP_B:
0408 priv->is_tdm_mode = true;
0409 pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
0410 break;
0411 default:
0412 dev_err(component->dev, "Invalid DAI format\n");
0413 return -EINVAL;
0414 }
0415
0416 snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
0417 PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
0418
0419 snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
0420
0421 snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
0422 PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
0423
0424 return 0;
0425 }
0426
0427 static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
0428 unsigned int rx_mask, int slots, int slot_width)
0429 {
0430 struct snd_soc_component *component = dai->component;
0431 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0432 unsigned int first_slot, last_slot, tdm_offset;
0433
0434 dev_dbg(component->dev,
0435 "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
0436 __func__, tx_mask, rx_mask, slots, slot_width);
0437
0438 if (!tx_mask) {
0439 dev_err(component->dev, "tdm tx mask must not be 0\n");
0440 return -EINVAL;
0441 }
0442
0443 first_slot = __ffs(tx_mask);
0444 last_slot = __fls(tx_mask);
0445
0446 if (last_slot - first_slot != hweight32(tx_mask) - 1) {
0447 dev_err(component->dev, "tdm tx mask must be contiguous\n");
0448 return -EINVAL;
0449 }
0450
0451 tdm_offset = first_slot * slot_width;
0452
0453 if (tdm_offset > 255) {
0454 dev_err(component->dev, "tdm tx slot selection out of bounds\n");
0455 return -EINVAL;
0456 }
0457
0458 priv->tdm_offset = tdm_offset;
0459
0460 return 0;
0461 }
0462
0463 static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
0464 unsigned int freq, int dir)
0465 {
0466 struct snd_soc_component *component = dai->component;
0467 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0468
0469 dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
0470 __func__, clk_id, freq, dir);
0471
0472 priv->sysclk = freq;
0473
0474 return 0;
0475 }
0476
0477 static const struct snd_soc_dai_ops pcm186x_dai_ops = {
0478 .set_sysclk = pcm186x_set_dai_sysclk,
0479 .set_tdm_slot = pcm186x_set_tdm_slot,
0480 .set_fmt = pcm186x_set_fmt,
0481 .hw_params = pcm186x_hw_params,
0482 };
0483
0484 static struct snd_soc_dai_driver pcm1863_dai = {
0485 .name = "pcm1863-aif",
0486 .capture = {
0487 .stream_name = "Capture",
0488 .channels_min = 1,
0489 .channels_max = 2,
0490 .rates = PCM186X_RATES,
0491 .formats = PCM186X_FORMATS,
0492 },
0493 .ops = &pcm186x_dai_ops,
0494 };
0495
0496 static struct snd_soc_dai_driver pcm1865_dai = {
0497 .name = "pcm1865-aif",
0498 .capture = {
0499 .stream_name = "Capture",
0500 .channels_min = 1,
0501 .channels_max = 4,
0502 .rates = PCM186X_RATES,
0503 .formats = PCM186X_FORMATS,
0504 },
0505 .ops = &pcm186x_dai_ops,
0506 };
0507
0508 static int pcm186x_power_on(struct snd_soc_component *component)
0509 {
0510 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0511 int ret = 0;
0512
0513 ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
0514 priv->supplies);
0515 if (ret)
0516 return ret;
0517
0518 regcache_cache_only(priv->regmap, false);
0519 ret = regcache_sync(priv->regmap);
0520 if (ret) {
0521 dev_err(component->dev, "Failed to restore cache\n");
0522 regcache_cache_only(priv->regmap, true);
0523 regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
0524 priv->supplies);
0525 return ret;
0526 }
0527
0528 snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
0529 PCM186X_PWR_CTRL_PWRDN, 0);
0530
0531 return 0;
0532 }
0533
0534 static int pcm186x_power_off(struct snd_soc_component *component)
0535 {
0536 struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
0537
0538 snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
0539 PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
0540
0541 regcache_cache_only(priv->regmap, true);
0542
0543 return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
0544 priv->supplies);
0545 }
0546
0547 static int pcm186x_set_bias_level(struct snd_soc_component *component,
0548 enum snd_soc_bias_level level)
0549 {
0550 dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
0551 snd_soc_component_get_bias_level(component), level);
0552
0553 switch (level) {
0554 case SND_SOC_BIAS_ON:
0555 break;
0556 case SND_SOC_BIAS_PREPARE:
0557 break;
0558 case SND_SOC_BIAS_STANDBY:
0559 if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
0560 pcm186x_power_on(component);
0561 break;
0562 case SND_SOC_BIAS_OFF:
0563 pcm186x_power_off(component);
0564 break;
0565 }
0566
0567 return 0;
0568 }
0569
0570 static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
0571 .set_bias_level = pcm186x_set_bias_level,
0572 .controls = pcm1863_snd_controls,
0573 .num_controls = ARRAY_SIZE(pcm1863_snd_controls),
0574 .dapm_widgets = pcm1863_dapm_widgets,
0575 .num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets),
0576 .dapm_routes = pcm1863_dapm_routes,
0577 .num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes),
0578 .idle_bias_on = 1,
0579 .use_pmdown_time = 1,
0580 .endianness = 1,
0581 };
0582
0583 static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
0584 .set_bias_level = pcm186x_set_bias_level,
0585 .controls = pcm1865_snd_controls,
0586 .num_controls = ARRAY_SIZE(pcm1865_snd_controls),
0587 .dapm_widgets = pcm1865_dapm_widgets,
0588 .num_dapm_widgets = ARRAY_SIZE(pcm1865_dapm_widgets),
0589 .dapm_routes = pcm1865_dapm_routes,
0590 .num_dapm_routes = ARRAY_SIZE(pcm1865_dapm_routes),
0591 .suspend_bias_off = 1,
0592 .idle_bias_on = 1,
0593 .use_pmdown_time = 1,
0594 .endianness = 1,
0595 };
0596
0597 static bool pcm186x_volatile(struct device *dev, unsigned int reg)
0598 {
0599 switch (reg) {
0600 case PCM186X_PAGE:
0601 case PCM186X_DEVICE_STATUS:
0602 case PCM186X_FSAMPLE_STATUS:
0603 case PCM186X_DIV_STATUS:
0604 case PCM186X_CLK_STATUS:
0605 case PCM186X_SUPPLY_STATUS:
0606 case PCM186X_MMAP_STAT_CTRL:
0607 case PCM186X_MMAP_ADDRESS:
0608 return true;
0609 }
0610
0611 return false;
0612 }
0613
0614 static const struct regmap_range_cfg pcm186x_range = {
0615 .name = "Pages",
0616 .range_max = PCM186X_MAX_REGISTER,
0617 .selector_reg = PCM186X_PAGE,
0618 .selector_mask = 0xff,
0619 .window_len = PCM186X_PAGE_LEN,
0620 };
0621
0622 const struct regmap_config pcm186x_regmap = {
0623 .reg_bits = 8,
0624 .val_bits = 8,
0625
0626 .volatile_reg = pcm186x_volatile,
0627
0628 .ranges = &pcm186x_range,
0629 .num_ranges = 1,
0630
0631 .max_register = PCM186X_MAX_REGISTER,
0632
0633 .cache_type = REGCACHE_RBTREE,
0634 };
0635 EXPORT_SYMBOL_GPL(pcm186x_regmap);
0636
0637 int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
0638 struct regmap *regmap)
0639 {
0640 struct pcm186x_priv *priv;
0641 int i, ret;
0642
0643 priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
0644 if (!priv)
0645 return -ENOMEM;
0646
0647 dev_set_drvdata(dev, priv);
0648 priv->regmap = regmap;
0649
0650 for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
0651 priv->supplies[i].supply = pcm186x_supply_names[i];
0652
0653 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
0654 priv->supplies);
0655 if (ret) {
0656 dev_err(dev, "failed to request supplies: %d\n", ret);
0657 return ret;
0658 }
0659
0660 ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
0661 priv->supplies);
0662 if (ret) {
0663 dev_err(dev, "failed enable supplies: %d\n", ret);
0664 return ret;
0665 }
0666
0667
0668 ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
0669 if (ret) {
0670 dev_err(dev, "failed to write device: %d\n", ret);
0671 return ret;
0672 }
0673
0674 ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
0675 priv->supplies);
0676 if (ret) {
0677 dev_err(dev, "failed disable supplies: %d\n", ret);
0678 return ret;
0679 }
0680
0681 switch (type) {
0682 case PCM1865:
0683 case PCM1864:
0684 ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
0685 &pcm1865_dai, 1);
0686 break;
0687 case PCM1863:
0688 case PCM1862:
0689 default:
0690 ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
0691 &pcm1863_dai, 1);
0692 }
0693 if (ret) {
0694 dev_err(dev, "failed to register CODEC: %d\n", ret);
0695 return ret;
0696 }
0697
0698 return 0;
0699 }
0700 EXPORT_SYMBOL_GPL(pcm186x_probe);
0701
0702 MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
0703 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
0704 MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
0705 MODULE_LICENSE("GPL v2");