0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/delay.h>
0017 #include <linux/slab.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_device.h>
0021 #include <linux/of_platform.h>
0022 #include <linux/clk.h>
0023 #include <linux/regmap.h>
0024 #include <linux/reset.h>
0025 #include <linux/gpio/consumer.h>
0026
0027 #include <sound/core.h>
0028 #include <sound/pcm.h>
0029 #include <sound/pcm_params.h>
0030 #include <sound/soc.h>
0031 #include <sound/tlv.h>
0032 #include <sound/initval.h>
0033 #include <sound/dmaengine_pcm.h>
0034
0035
0036 #define SUN4I_CODEC_DAC_DPC (0x00)
0037 #define SUN4I_CODEC_DAC_DPC_EN_DA (31)
0038 #define SUN4I_CODEC_DAC_DPC_DVOL (12)
0039 #define SUN4I_CODEC_DAC_FIFOC (0x04)
0040 #define SUN4I_CODEC_DAC_FIFOC_DAC_FS (29)
0041 #define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION (28)
0042 #define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT (26)
0043 #define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE (24)
0044 #define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT (21)
0045 #define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL (8)
0046 #define SUN4I_CODEC_DAC_FIFOC_MONO_EN (6)
0047 #define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS (5)
0048 #define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN (4)
0049 #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0)
0050 #define SUN4I_CODEC_DAC_FIFOS (0x08)
0051 #define SUN4I_CODEC_DAC_TXDATA (0x0c)
0052
0053
0054 #define SUN4I_CODEC_DAC_ACTL (0x10)
0055 #define SUN4I_CODEC_DAC_ACTL_DACAENR (31)
0056 #define SUN4I_CODEC_DAC_ACTL_DACAENL (30)
0057 #define SUN4I_CODEC_DAC_ACTL_MIXEN (29)
0058 #define SUN4I_CODEC_DAC_ACTL_LNG (26)
0059 #define SUN4I_CODEC_DAC_ACTL_FMG (23)
0060 #define SUN4I_CODEC_DAC_ACTL_MICG (20)
0061 #define SUN4I_CODEC_DAC_ACTL_LLNS (19)
0062 #define SUN4I_CODEC_DAC_ACTL_RLNS (18)
0063 #define SUN4I_CODEC_DAC_ACTL_LFMS (17)
0064 #define SUN4I_CODEC_DAC_ACTL_RFMS (16)
0065 #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15)
0066 #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14)
0067 #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13)
0068 #define SUN4I_CODEC_DAC_ACTL_MIC1LS (12)
0069 #define SUN4I_CODEC_DAC_ACTL_MIC1RS (11)
0070 #define SUN4I_CODEC_DAC_ACTL_MIC2LS (10)
0071 #define SUN4I_CODEC_DAC_ACTL_MIC2RS (9)
0072 #define SUN4I_CODEC_DAC_ACTL_DACPAS (8)
0073 #define SUN4I_CODEC_DAC_ACTL_MIXPAS (7)
0074 #define SUN4I_CODEC_DAC_ACTL_PA_MUTE (6)
0075 #define SUN4I_CODEC_DAC_ACTL_PA_VOL (0)
0076 #define SUN4I_CODEC_DAC_TUNE (0x14)
0077 #define SUN4I_CODEC_DAC_DEBUG (0x18)
0078
0079
0080 #define SUN4I_CODEC_ADC_FIFOC (0x1c)
0081 #define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
0082 #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
0083 #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24)
0084 #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8)
0085 #define SUN4I_CODEC_ADC_FIFOC_MONO_EN (7)
0086 #define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS (6)
0087 #define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN (4)
0088 #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0)
0089 #define SUN4I_CODEC_ADC_FIFOS (0x20)
0090 #define SUN4I_CODEC_ADC_RXDATA (0x24)
0091
0092
0093 #define SUN4I_CODEC_ADC_ACTL (0x28)
0094 #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31)
0095 #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30)
0096 #define SUN4I_CODEC_ADC_ACTL_PREG1EN (29)
0097 #define SUN4I_CODEC_ADC_ACTL_PREG2EN (28)
0098 #define SUN4I_CODEC_ADC_ACTL_VMICEN (27)
0099 #define SUN4I_CODEC_ADC_ACTL_PREG1 (25)
0100 #define SUN4I_CODEC_ADC_ACTL_PREG2 (23)
0101 #define SUN4I_CODEC_ADC_ACTL_VADCG (20)
0102 #define SUN4I_CODEC_ADC_ACTL_ADCIS (17)
0103 #define SUN4I_CODEC_ADC_ACTL_LNPREG (13)
0104 #define SUN4I_CODEC_ADC_ACTL_PA_EN (4)
0105 #define SUN4I_CODEC_ADC_ACTL_DDE (3)
0106 #define SUN4I_CODEC_ADC_DEBUG (0x2c)
0107
0108
0109 #define SUN4I_CODEC_DAC_TXCNT (0x30)
0110 #define SUN4I_CODEC_ADC_RXCNT (0x34)
0111
0112
0113 #define SUN7I_CODEC_AC_DAC_CAL (0x38)
0114
0115
0116 #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)
0117
0118 #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1 (29)
0119 #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2 (26)
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130 #define SUN6I_CODEC_ADC_FIFOC (0x10)
0131 #define SUN6I_CODEC_ADC_FIFOC_EN_AD (28)
0132 #define SUN6I_CODEC_ADC_FIFOS (0x14)
0133 #define SUN6I_CODEC_ADC_RXDATA (0x18)
0134
0135
0136 #define SUN6I_CODEC_OM_DACA_CTRL (0x20)
0137 #define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31)
0138 #define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30)
0139 #define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29)
0140 #define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28)
0141 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23)
0142 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22)
0143 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21)
0144 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20)
0145 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19)
0146 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18)
0147 #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17)
0148 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16)
0149 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15)
0150 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14)
0151 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13)
0152 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12)
0153 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11)
0154 #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10)
0155 #define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9)
0156 #define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8)
0157 #define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7)
0158 #define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6)
0159 #define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0)
0160 #define SUN6I_CODEC_OM_PA_CTRL (0x24)
0161 #define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31)
0162 #define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29)
0163 #define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28)
0164 #define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15)
0165 #define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12)
0166 #define SUN6I_CODEC_OM_PA_CTRL_LINEING (9)
0167 #define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6)
0168 #define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3)
0169 #define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0)
0170
0171
0172 #define SUN6I_CODEC_MIC_CTRL (0x28)
0173 #define SUN6I_CODEC_MIC_CTRL_HBIASEN (31)
0174 #define SUN6I_CODEC_MIC_CTRL_MBIASEN (30)
0175 #define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28)
0176 #define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25)
0177 #define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24)
0178 #define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21)
0179 #define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20)
0180 #define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19)
0181 #define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18)
0182 #define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17)
0183 #define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16)
0184 #define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11)
0185 #define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8)
0186
0187
0188 #define SUN6I_CODEC_ADC_ACTL (0x2c)
0189 #define SUN6I_CODEC_ADC_ACTL_ADCREN (31)
0190 #define SUN6I_CODEC_ADC_ACTL_ADCLEN (30)
0191 #define SUN6I_CODEC_ADC_ACTL_ADCRG (27)
0192 #define SUN6I_CODEC_ADC_ACTL_ADCLG (24)
0193 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13)
0194 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12)
0195 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11)
0196 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10)
0197 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9)
0198 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8)
0199 #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7)
0200 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6)
0201 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5)
0202 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4)
0203 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3)
0204 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2)
0205 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1)
0206 #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0)
0207
0208
0209 #define SUN6I_CODEC_ADDA_TUNE (0x30)
0210
0211
0212 #define SUN6I_CODEC_CALIBRATION (0x34)
0213
0214
0215 #define SUN6I_CODEC_DAC_TXCNT (0x40)
0216 #define SUN6I_CODEC_ADC_RXCNT (0x44)
0217
0218
0219 #define SUN6I_CODEC_HMIC_CTL (0x50)
0220 #define SUN6I_CODEC_HMIC_DATA (0x54)
0221
0222
0223
0224
0225 #define SUN8I_A23_CODEC_DAC_TXCNT (0x1c)
0226 #define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
0227
0228
0229 #define SUN8I_H3_CODEC_DAC_TXDATA (0x20)
0230 #define SUN8I_H3_CODEC_DAC_DBG (0x48)
0231 #define SUN8I_H3_CODEC_ADC_DBG (0x4c)
0232
0233
0234
0235 struct sun4i_codec {
0236 struct device *dev;
0237 struct regmap *regmap;
0238 struct clk *clk_apb;
0239 struct clk *clk_module;
0240 struct reset_control *rst;
0241 struct gpio_desc *gpio_pa;
0242
0243
0244 struct regmap_field *reg_adc_fifoc;
0245
0246 struct snd_dmaengine_dai_dma_data capture_dma_data;
0247 struct snd_dmaengine_dai_dma_data playback_dma_data;
0248 };
0249
0250 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
0251 {
0252
0253 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0254 BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
0255
0256
0257 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0258 BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
0259 }
0260
0261 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
0262 {
0263
0264 regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0265 BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
0266 }
0267
0268 static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
0269 {
0270
0271 regmap_field_set_bits(scodec->reg_adc_fifoc,
0272 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
0273 }
0274
0275 static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
0276 {
0277
0278 regmap_field_clear_bits(scodec->reg_adc_fifoc,
0279 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
0280 }
0281
0282 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
0283 struct snd_soc_dai *dai)
0284 {
0285 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0286 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0287
0288 switch (cmd) {
0289 case SNDRV_PCM_TRIGGER_START:
0290 case SNDRV_PCM_TRIGGER_RESUME:
0291 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0292 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0293 sun4i_codec_start_playback(scodec);
0294 else
0295 sun4i_codec_start_capture(scodec);
0296 break;
0297
0298 case SNDRV_PCM_TRIGGER_STOP:
0299 case SNDRV_PCM_TRIGGER_SUSPEND:
0300 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0301 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0302 sun4i_codec_stop_playback(scodec);
0303 else
0304 sun4i_codec_stop_capture(scodec);
0305 break;
0306
0307 default:
0308 return -EINVAL;
0309 }
0310
0311 return 0;
0312 }
0313
0314 static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
0315 struct snd_soc_dai *dai)
0316 {
0317 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0318 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0319
0320
0321
0322 regmap_field_set_bits(scodec->reg_adc_fifoc,
0323 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
0324
0325
0326
0327 regmap_field_update_bits(scodec->reg_adc_fifoc,
0328 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
0329 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
0330
0331
0332
0333
0334
0335
0336 if (of_device_is_compatible(scodec->dev->of_node,
0337 "allwinner,sun4i-a10-codec") ||
0338 of_device_is_compatible(scodec->dev->of_node,
0339 "allwinner,sun7i-a20-codec")) {
0340 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
0341 0x3 << 25,
0342 0x1 << 25);
0343 }
0344
0345 if (of_device_is_compatible(scodec->dev->of_node,
0346 "allwinner,sun7i-a20-codec"))
0347
0348 regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
0349 0x3 << 8,
0350 0x1 << 8);
0351
0352 return 0;
0353 }
0354
0355 static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
0356 struct snd_soc_dai *dai)
0357 {
0358 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0359 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0360 u32 val;
0361
0362
0363 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0364 BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
0365
0366
0367 regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0368 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
0369 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
0370
0371 if (substream->runtime->rate > 32000)
0372
0373 val = 0;
0374 else
0375
0376 val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
0377
0378 regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0379 BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
0380 val);
0381
0382
0383 regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0384 BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT));
0385
0386 return 0;
0387 };
0388
0389 static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
0390 struct snd_soc_dai *dai)
0391 {
0392 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0393 return sun4i_codec_prepare_playback(substream, dai);
0394
0395 return sun4i_codec_prepare_capture(substream, dai);
0396 }
0397
0398 static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
0399 {
0400 unsigned int rate = params_rate(params);
0401
0402 switch (rate) {
0403 case 176400:
0404 case 88200:
0405 case 44100:
0406 case 33075:
0407 case 22050:
0408 case 14700:
0409 case 11025:
0410 case 7350:
0411 return 22579200;
0412
0413 case 192000:
0414 case 96000:
0415 case 48000:
0416 case 32000:
0417 case 24000:
0418 case 16000:
0419 case 12000:
0420 case 8000:
0421 return 24576000;
0422
0423 default:
0424 return 0;
0425 }
0426 }
0427
0428 static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
0429 {
0430 unsigned int rate = params_rate(params);
0431
0432 switch (rate) {
0433 case 192000:
0434 case 176400:
0435 return 6;
0436
0437 case 96000:
0438 case 88200:
0439 return 7;
0440
0441 case 48000:
0442 case 44100:
0443 return 0;
0444
0445 case 32000:
0446 case 33075:
0447 return 1;
0448
0449 case 24000:
0450 case 22050:
0451 return 2;
0452
0453 case 16000:
0454 case 14700:
0455 return 3;
0456
0457 case 12000:
0458 case 11025:
0459 return 4;
0460
0461 case 8000:
0462 case 7350:
0463 return 5;
0464
0465 default:
0466 return -EINVAL;
0467 }
0468 }
0469
0470 static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
0471 struct snd_pcm_hw_params *params,
0472 unsigned int hwrate)
0473 {
0474
0475 regmap_field_update_bits(scodec->reg_adc_fifoc,
0476 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
0477 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
0478
0479
0480 if (params_channels(params) == 1)
0481 regmap_field_set_bits(scodec->reg_adc_fifoc,
0482 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
0483 else
0484 regmap_field_clear_bits(scodec->reg_adc_fifoc,
0485 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
0486
0487
0488 if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
0489 regmap_field_set_bits(scodec->reg_adc_fifoc,
0490 BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
0491
0492 regmap_field_clear_bits(scodec->reg_adc_fifoc,
0493 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
0494
0495 scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0496 } else {
0497 regmap_field_clear_bits(scodec->reg_adc_fifoc,
0498 BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
0499
0500
0501 regmap_field_set_bits(scodec->reg_adc_fifoc,
0502 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
0503
0504 scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0505 }
0506
0507 return 0;
0508 }
0509
0510 static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
0511 struct snd_pcm_hw_params *params,
0512 unsigned int hwrate)
0513 {
0514 u32 val;
0515
0516
0517 regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0518 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
0519 hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
0520
0521
0522 if (params_channels(params) == 1)
0523 val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
0524 else
0525 val = 0;
0526
0527 regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0528 BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
0529 val);
0530
0531
0532 if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
0533 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0534 BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
0535
0536
0537 regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0538 BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
0539
0540 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0541 } else {
0542 regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0543 BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
0544
0545
0546 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0547 BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
0548
0549 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0550 }
0551
0552 return 0;
0553 }
0554
0555 static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
0556 struct snd_pcm_hw_params *params,
0557 struct snd_soc_dai *dai)
0558 {
0559 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0560 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0561 unsigned long clk_freq;
0562 int ret, hwrate;
0563
0564 clk_freq = sun4i_codec_get_mod_freq(params);
0565 if (!clk_freq)
0566 return -EINVAL;
0567
0568 ret = clk_set_rate(scodec->clk_module, clk_freq);
0569 if (ret)
0570 return ret;
0571
0572 hwrate = sun4i_codec_get_hw_rate(params);
0573 if (hwrate < 0)
0574 return hwrate;
0575
0576 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0577 return sun4i_codec_hw_params_playback(scodec, params,
0578 hwrate);
0579
0580 return sun4i_codec_hw_params_capture(scodec, params,
0581 hwrate);
0582 }
0583
0584
0585 static unsigned int sun4i_codec_src_rates[] = {
0586 8000, 11025, 12000, 16000, 22050, 24000, 32000,
0587 44100, 48000, 96000, 192000
0588 };
0589
0590
0591 static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
0592 .count = ARRAY_SIZE(sun4i_codec_src_rates),
0593 .list = sun4i_codec_src_rates,
0594 };
0595
0596
0597 static int sun4i_codec_startup(struct snd_pcm_substream *substream,
0598 struct snd_soc_dai *dai)
0599 {
0600 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0601 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0602
0603 snd_pcm_hw_constraint_list(substream->runtime, 0,
0604 SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
0605
0606
0607
0608
0609
0610 regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
0611 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
0612
0613 return clk_prepare_enable(scodec->clk_module);
0614 }
0615
0616 static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
0617 struct snd_soc_dai *dai)
0618 {
0619 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0620 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
0621
0622 clk_disable_unprepare(scodec->clk_module);
0623 }
0624
0625 static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
0626 .startup = sun4i_codec_startup,
0627 .shutdown = sun4i_codec_shutdown,
0628 .trigger = sun4i_codec_trigger,
0629 .hw_params = sun4i_codec_hw_params,
0630 .prepare = sun4i_codec_prepare,
0631 };
0632
0633 static struct snd_soc_dai_driver sun4i_codec_dai = {
0634 .name = "Codec",
0635 .ops = &sun4i_codec_dai_ops,
0636 .playback = {
0637 .stream_name = "Codec Playback",
0638 .channels_min = 1,
0639 .channels_max = 2,
0640 .rate_min = 8000,
0641 .rate_max = 192000,
0642 .rates = SNDRV_PCM_RATE_CONTINUOUS,
0643 .formats = SNDRV_PCM_FMTBIT_S16_LE |
0644 SNDRV_PCM_FMTBIT_S32_LE,
0645 .sig_bits = 24,
0646 },
0647 .capture = {
0648 .stream_name = "Codec Capture",
0649 .channels_min = 1,
0650 .channels_max = 2,
0651 .rate_min = 8000,
0652 .rate_max = 48000,
0653 .rates = SNDRV_PCM_RATE_CONTINUOUS,
0654 .formats = SNDRV_PCM_FMTBIT_S16_LE |
0655 SNDRV_PCM_FMTBIT_S32_LE,
0656 .sig_bits = 24,
0657 },
0658 };
0659
0660
0661 static const struct snd_kcontrol_new sun4i_codec_pa_mute =
0662 SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
0663 SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
0664
0665 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
0666 static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150,
0667 0);
0668 static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300,
0669 0);
0670 static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150,
0671 0);
0672 static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150,
0673 0);
0674 static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale,
0675 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
0676 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0));
0677 static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale,
0678 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
0679 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0));
0680
0681 static const struct snd_kcontrol_new sun4i_codec_controls[] = {
0682 SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
0683 SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
0684 sun4i_codec_pa_volume_scale),
0685 SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
0686 SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
0687 sun4i_codec_linein_loopback_gain_scale),
0688 SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
0689 SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
0690 sun4i_codec_linein_preamp_gain_scale),
0691 SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
0692 SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
0693 sun4i_codec_fmin_loopback_gain_scale),
0694 SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
0695 SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
0696 sun4i_codec_micin_loopback_gain_scale),
0697 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL,
0698 SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0,
0699 sun4i_codec_micin_preamp_gain_scale),
0700 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL,
0701 SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0,
0702 sun4i_codec_micin_preamp_gain_scale),
0703 };
0704
0705 static const struct snd_kcontrol_new sun7i_codec_controls[] = {
0706 SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
0707 SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
0708 sun4i_codec_pa_volume_scale),
0709 SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
0710 SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
0711 sun4i_codec_linein_loopback_gain_scale),
0712 SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
0713 SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
0714 sun4i_codec_linein_preamp_gain_scale),
0715 SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
0716 SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
0717 sun4i_codec_fmin_loopback_gain_scale),
0718 SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
0719 SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
0720 sun4i_codec_micin_loopback_gain_scale),
0721 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
0722 SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0,
0723 sun7i_codec_micin_preamp_gain_scale),
0724 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
0725 SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0,
0726 sun7i_codec_micin_preamp_gain_scale),
0727 };
0728
0729 static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = {
0730 SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch",
0731 SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS,
0732 1, 0),
0733 SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch",
0734 SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS,
0735 1, 0),
0736 SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch",
0737 SUN4I_CODEC_DAC_ACTL,
0738 SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
0739 SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL,
0740 SUN4I_CODEC_DAC_ACTL_LLNS,
0741 SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0),
0742 SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL,
0743 SUN4I_CODEC_DAC_ACTL_LFMS,
0744 SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0),
0745 SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL,
0746 SUN4I_CODEC_DAC_ACTL_MIC1LS,
0747 SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0),
0748 SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL,
0749 SUN4I_CODEC_DAC_ACTL_MIC2LS,
0750 SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0),
0751 };
0752
0753 static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
0754 SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
0755 SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
0756 SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
0757 SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
0758 };
0759
0760 static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
0761
0762 SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
0763 SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
0764 NULL, 0),
0765
0766
0767 SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
0768 SUN4I_CODEC_DAC_DPC_EN_DA, 0,
0769 NULL, 0),
0770
0771
0772 SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
0773 SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
0774 SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
0775 SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
0776
0777
0778 SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
0779 SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
0780 SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
0781 SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
0782
0783
0784 SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
0785 sun4i_codec_mixer_controls,
0786 ARRAY_SIZE(sun4i_codec_mixer_controls)),
0787 SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
0788 sun4i_codec_mixer_controls,
0789 ARRAY_SIZE(sun4i_codec_mixer_controls)),
0790
0791
0792 SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
0793 SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
0794
0795
0796 SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
0797 SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
0798
0799
0800 SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
0801 SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
0802 SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
0803 SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0),
0804
0805
0806 SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
0807 SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
0808 sun4i_codec_pa_mixer_controls,
0809 ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
0810 SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
0811 &sun4i_codec_pa_mute),
0812
0813 SND_SOC_DAPM_INPUT("Line Right"),
0814 SND_SOC_DAPM_INPUT("Line Left"),
0815 SND_SOC_DAPM_INPUT("FM Right"),
0816 SND_SOC_DAPM_INPUT("FM Left"),
0817 SND_SOC_DAPM_INPUT("Mic1"),
0818 SND_SOC_DAPM_INPUT("Mic2"),
0819
0820 SND_SOC_DAPM_OUTPUT("HP Right"),
0821 SND_SOC_DAPM_OUTPUT("HP Left"),
0822 };
0823
0824 static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
0825
0826 { "Left ADC", NULL, "ADC" },
0827 { "Left DAC", NULL, "DAC" },
0828
0829
0830 { "Right ADC", NULL, "ADC" },
0831 { "Right DAC", NULL, "DAC" },
0832
0833
0834 { "Right Mixer", NULL, "Mixer Enable" },
0835 { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" },
0836 { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" },
0837 { "Right Mixer", "Line Playback Switch", "Line Right" },
0838 { "Right Mixer", "FM Playback Switch", "FM Right" },
0839 { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
0840 { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
0841
0842
0843 { "Left Mixer", NULL, "Mixer Enable" },
0844 { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" },
0845 { "Left Mixer", "Line Playback Switch", "Line Left" },
0846 { "Left Mixer", "FM Playback Switch", "FM Left" },
0847 { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
0848 { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
0849
0850
0851 { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
0852 { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
0853 { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
0854 { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
0855
0856
0857 { "Power Amplifier Mute", "Switch", "Power Amplifier" },
0858 { "HP Right", NULL, "Power Amplifier Mute" },
0859 { "HP Left", NULL, "Power Amplifier Mute" },
0860
0861
0862 { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
0863 { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
0864 { "MIC1 Pre-Amplifier", NULL, "Mic1"},
0865 { "Mic1", NULL, "VMIC" },
0866
0867
0868 { "Left ADC", NULL, "MIC2 Pre-Amplifier" },
0869 { "Right ADC", NULL, "MIC2 Pre-Amplifier" },
0870 { "MIC2 Pre-Amplifier", NULL, "Mic2"},
0871 { "Mic2", NULL, "VMIC" },
0872 };
0873
0874 static const struct snd_soc_component_driver sun4i_codec_codec = {
0875 .controls = sun4i_codec_controls,
0876 .num_controls = ARRAY_SIZE(sun4i_codec_controls),
0877 .dapm_widgets = sun4i_codec_codec_dapm_widgets,
0878 .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
0879 .dapm_routes = sun4i_codec_codec_dapm_routes,
0880 .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
0881 .idle_bias_on = 1,
0882 .use_pmdown_time = 1,
0883 .endianness = 1,
0884 };
0885
0886 static const struct snd_soc_component_driver sun7i_codec_codec = {
0887 .controls = sun7i_codec_controls,
0888 .num_controls = ARRAY_SIZE(sun7i_codec_controls),
0889 .dapm_widgets = sun4i_codec_codec_dapm_widgets,
0890 .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
0891 .dapm_routes = sun4i_codec_codec_dapm_routes,
0892 .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
0893 .idle_bias_on = 1,
0894 .use_pmdown_time = 1,
0895 .endianness = 1,
0896 };
0897
0898
0899
0900
0901 static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
0902 SOC_DAPM_DOUBLE("DAC Playback Switch",
0903 SUN6I_CODEC_OM_DACA_CTRL,
0904 SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
0905 SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
0906 SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
0907 SUN6I_CODEC_OM_DACA_CTRL,
0908 SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
0909 SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
0910 SOC_DAPM_DOUBLE("Line In Playback Switch",
0911 SUN6I_CODEC_OM_DACA_CTRL,
0912 SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
0913 SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
0914 SOC_DAPM_DOUBLE("Mic1 Playback Switch",
0915 SUN6I_CODEC_OM_DACA_CTRL,
0916 SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
0917 SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
0918 SOC_DAPM_DOUBLE("Mic2 Playback Switch",
0919 SUN6I_CODEC_OM_DACA_CTRL,
0920 SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
0921 SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
0922 };
0923
0924
0925 static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
0926 SOC_DAPM_DOUBLE("Mixer Capture Switch",
0927 SUN6I_CODEC_ADC_ACTL,
0928 SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
0929 SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
0930 SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
0931 SUN6I_CODEC_ADC_ACTL,
0932 SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
0933 SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
0934 SOC_DAPM_DOUBLE("Line In Capture Switch",
0935 SUN6I_CODEC_ADC_ACTL,
0936 SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
0937 SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
0938 SOC_DAPM_DOUBLE("Mic1 Capture Switch",
0939 SUN6I_CODEC_ADC_ACTL,
0940 SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
0941 SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
0942 SOC_DAPM_DOUBLE("Mic2 Capture Switch",
0943 SUN6I_CODEC_ADC_ACTL,
0944 SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
0945 SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
0946 };
0947
0948
0949 static const char * const sun6i_codec_hp_src_enum_text[] = {
0950 "DAC", "Mixer",
0951 };
0952
0953 static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
0954 SUN6I_CODEC_OM_DACA_CTRL,
0955 SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
0956 SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
0957 sun6i_codec_hp_src_enum_text);
0958
0959 static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
0960 SOC_DAPM_ENUM("Headphone Source Playback Route",
0961 sun6i_codec_hp_src_enum),
0962 };
0963
0964
0965 static const char * const sun6i_codec_mic2_src_enum_text[] = {
0966 "Mic2", "Mic3",
0967 };
0968
0969 static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
0970 SUN6I_CODEC_MIC_CTRL,
0971 SUN6I_CODEC_MIC_CTRL_MIC2SLT,
0972 sun6i_codec_mic2_src_enum_text);
0973
0974 static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
0975 SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
0976 sun6i_codec_mic2_src_enum),
0977 };
0978
0979
0980 static const char * const sun6i_codec_lineout_src_enum_text[] = {
0981 "Stereo", "Mono Differential",
0982 };
0983
0984 static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
0985 SUN6I_CODEC_MIC_CTRL,
0986 SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
0987 SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
0988 sun6i_codec_lineout_src_enum_text);
0989
0990 static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
0991 SOC_DAPM_ENUM("Line Out Source Playback Route",
0992 sun6i_codec_lineout_src_enum),
0993 };
0994
0995
0996 static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
0997 static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
0998 static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
0999 -450, 150, 0);
1000 static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
1001 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
1002 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
1003 );
1004 static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
1005 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1006 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
1007 );
1008
1009 static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
1010 SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1011 SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1012 sun6i_codec_dvol_scale),
1013 SOC_SINGLE_TLV("Headphone Playback Volume",
1014 SUN6I_CODEC_OM_DACA_CTRL,
1015 SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
1016 sun6i_codec_hp_vol_scale),
1017 SOC_SINGLE_TLV("Line Out Playback Volume",
1018 SUN6I_CODEC_MIC_CTRL,
1019 SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
1020 sun6i_codec_lineout_vol_scale),
1021 SOC_DOUBLE("Headphone Playback Switch",
1022 SUN6I_CODEC_OM_DACA_CTRL,
1023 SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
1024 SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
1025 SOC_DOUBLE("Line Out Playback Switch",
1026 SUN6I_CODEC_MIC_CTRL,
1027 SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
1028 SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
1029
1030 SOC_SINGLE_TLV("Line In Playback Volume",
1031 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
1032 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1033 SOC_SINGLE_TLV("Mic1 Playback Volume",
1034 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
1035 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1036 SOC_SINGLE_TLV("Mic2 Playback Volume",
1037 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
1038 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1039
1040
1041 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1042 SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
1043 sun6i_codec_mic_gain_scale),
1044 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1045 SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
1046 sun6i_codec_mic_gain_scale),
1047 SOC_DOUBLE_TLV("ADC Capture Volume",
1048 SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
1049 SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
1050 sun6i_codec_out_mixer_pregain_scale),
1051 };
1052
1053 static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
1054
1055 SND_SOC_DAPM_INPUT("MIC1"),
1056 SND_SOC_DAPM_INPUT("MIC2"),
1057 SND_SOC_DAPM_INPUT("MIC3"),
1058
1059
1060 SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
1061 SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
1062 SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
1063 SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
1064
1065
1066 SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
1067 SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
1068 SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
1069 SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
1070 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
1071 SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
1072
1073
1074 SND_SOC_DAPM_INPUT("LINEIN"),
1075
1076
1077 SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1078 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
1079 NULL, 0),
1080
1081
1082 SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1083 SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
1084 SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1085 SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
1086
1087
1088 SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
1089 sun6i_codec_adc_mixer_controls),
1090 SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
1091 sun6i_codec_adc_mixer_controls),
1092
1093
1094 SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1095 SUN4I_CODEC_DAC_DPC_EN_DA, 0,
1096 NULL, 0),
1097
1098
1099 SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
1100 SUN6I_CODEC_OM_DACA_CTRL,
1101 SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
1102 SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
1103 SUN6I_CODEC_OM_DACA_CTRL,
1104 SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
1105
1106
1107 SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1108 SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
1109 sun6i_codec_mixer_controls),
1110 SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1111 SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
1112 sun6i_codec_mixer_controls),
1113
1114
1115 SND_SOC_DAPM_MUX("Headphone Source Playback Route",
1116 SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
1117 SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
1118 SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
1119 SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
1120 SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
1121 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
1122 SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
1123 SND_SOC_DAPM_OUTPUT("HP"),
1124
1125
1126 SND_SOC_DAPM_MUX("Line Out Source Playback Route",
1127 SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
1128 SND_SOC_DAPM_OUTPUT("LINEOUT"),
1129 };
1130
1131 static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1132
1133 { "Left DAC", NULL, "DAC Enable" },
1134 { "Right DAC", NULL, "DAC Enable" },
1135
1136
1137 { "Mic1 Amplifier", NULL, "MIC1"},
1138 { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
1139 { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
1140 { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
1141
1142
1143 { "Left Mixer", "DAC Playback Switch", "Left DAC" },
1144 { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
1145 { "Left Mixer", "Line In Playback Switch", "LINEIN" },
1146 { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1147 { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1148
1149
1150 { "Right Mixer", "DAC Playback Switch", "Right DAC" },
1151 { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
1152 { "Right Mixer", "Line In Playback Switch", "LINEIN" },
1153 { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1154 { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1155
1156
1157 { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
1158 { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
1159 { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
1160 { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1161 { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1162
1163
1164 { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
1165 { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
1166 { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
1167 { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1168 { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1169
1170
1171 { "Headphone Source Playback Route", "DAC", "Left DAC" },
1172 { "Headphone Source Playback Route", "DAC", "Right DAC" },
1173 { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
1174 { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
1175 { "Headphone Amp", NULL, "Headphone Source Playback Route" },
1176 { "HP", NULL, "Headphone Amp" },
1177 { "HPCOM", NULL, "HPCOM Protection" },
1178
1179
1180 { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
1181 { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
1182 { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
1183 { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
1184 { "LINEOUT", NULL, "Line Out Source Playback Route" },
1185
1186
1187 { "Left ADC", NULL, "ADC Enable" },
1188 { "Right ADC", NULL, "ADC Enable" },
1189 { "Left ADC", NULL, "Left ADC Mixer" },
1190 { "Right ADC", NULL, "Right ADC Mixer" },
1191 };
1192
1193 static const struct snd_soc_component_driver sun6i_codec_codec = {
1194 .controls = sun6i_codec_codec_widgets,
1195 .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
1196 .dapm_widgets = sun6i_codec_codec_dapm_widgets,
1197 .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
1198 .dapm_routes = sun6i_codec_codec_dapm_routes,
1199 .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
1200 .idle_bias_on = 1,
1201 .use_pmdown_time = 1,
1202 .endianness = 1,
1203 };
1204
1205
1206 static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
1207 SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1208 SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1209 sun6i_codec_dvol_scale),
1210 };
1211
1212 static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1213
1214 SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1215 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
1216
1217 SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1218 SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
1219
1220 };
1221
1222 static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
1223 .controls = sun8i_a23_codec_codec_controls,
1224 .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
1225 .dapm_widgets = sun8i_a23_codec_codec_widgets,
1226 .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
1227 .idle_bias_on = 1,
1228 .use_pmdown_time = 1,
1229 .endianness = 1,
1230 };
1231
1232 static const struct snd_soc_component_driver sun4i_codec_component = {
1233 .name = "sun4i-codec",
1234 .legacy_dai_naming = 1,
1235 };
1236
1237 #define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS
1238 #define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
1239 SNDRV_PCM_FMTBIT_S32_LE)
1240
1241 static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
1242 {
1243 struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
1244 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1245
1246 snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
1247 &scodec->capture_dma_data);
1248
1249 return 0;
1250 }
1251
1252 static struct snd_soc_dai_driver dummy_cpu_dai = {
1253 .name = "sun4i-codec-cpu-dai",
1254 .probe = sun4i_codec_dai_probe,
1255 .playback = {
1256 .stream_name = "Playback",
1257 .channels_min = 1,
1258 .channels_max = 2,
1259 .rates = SUN4I_CODEC_RATES,
1260 .formats = SUN4I_CODEC_FORMATS,
1261 .sig_bits = 24,
1262 },
1263 .capture = {
1264 .stream_name = "Capture",
1265 .channels_min = 1,
1266 .channels_max = 2,
1267 .rates = SUN4I_CODEC_RATES,
1268 .formats = SUN4I_CODEC_FORMATS,
1269 .sig_bits = 24,
1270 },
1271 };
1272
1273 static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
1274 int *num_links)
1275 {
1276 struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
1277 GFP_KERNEL);
1278 struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev,
1279 3 * sizeof(*dlc), GFP_KERNEL);
1280 if (!link || !dlc)
1281 return NULL;
1282
1283 link->cpus = &dlc[0];
1284 link->codecs = &dlc[1];
1285 link->platforms = &dlc[2];
1286
1287 link->num_cpus = 1;
1288 link->num_codecs = 1;
1289 link->num_platforms = 1;
1290
1291 link->name = "cdc";
1292 link->stream_name = "CDC PCM";
1293 link->codecs->dai_name = "Codec";
1294 link->cpus->dai_name = dev_name(dev);
1295 link->codecs->name = dev_name(dev);
1296 link->platforms->name = dev_name(dev);
1297 link->dai_fmt = SND_SOC_DAIFMT_I2S;
1298
1299 *num_links = 1;
1300
1301 return link;
1302 };
1303
1304 static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
1305 struct snd_kcontrol *k, int event)
1306 {
1307 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
1308
1309 gpiod_set_value_cansleep(scodec->gpio_pa,
1310 !!SND_SOC_DAPM_EVENT_ON(event));
1311
1312 if (SND_SOC_DAPM_EVENT_ON(event)) {
1313
1314
1315
1316
1317
1318 msleep(700);
1319 }
1320
1321 return 0;
1322 }
1323
1324 static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
1325 SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1326 };
1327
1328 static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
1329 { "Speaker", NULL, "HP Right" },
1330 { "Speaker", NULL, "HP Left" },
1331 };
1332
1333 static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
1334 {
1335 struct snd_soc_card *card;
1336
1337 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1338 if (!card)
1339 return ERR_PTR(-ENOMEM);
1340
1341 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1342 if (!card->dai_link)
1343 return ERR_PTR(-ENOMEM);
1344
1345 card->dev = dev;
1346 card->owner = THIS_MODULE;
1347 card->name = "sun4i-codec";
1348 card->dapm_widgets = sun4i_codec_card_dapm_widgets;
1349 card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
1350 card->dapm_routes = sun4i_codec_card_dapm_routes;
1351 card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
1352
1353 return card;
1354 };
1355
1356 static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
1357 SND_SOC_DAPM_HP("Headphone", NULL),
1358 SND_SOC_DAPM_LINE("Line In", NULL),
1359 SND_SOC_DAPM_LINE("Line Out", NULL),
1360 SND_SOC_DAPM_MIC("Headset Mic", NULL),
1361 SND_SOC_DAPM_MIC("Mic", NULL),
1362 SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1363 };
1364
1365 static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
1366 {
1367 struct snd_soc_card *card;
1368 int ret;
1369
1370 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1371 if (!card)
1372 return ERR_PTR(-ENOMEM);
1373
1374 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1375 if (!card->dai_link)
1376 return ERR_PTR(-ENOMEM);
1377
1378 card->dev = dev;
1379 card->owner = THIS_MODULE;
1380 card->name = "A31 Audio Codec";
1381 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1382 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1383 card->fully_routed = true;
1384
1385 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1386 if (ret)
1387 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1388
1389 return card;
1390 };
1391
1392
1393 static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
1394
1395 { "Left ADC", NULL, "ADC Enable" },
1396 { "Right ADC", NULL, "ADC Enable" },
1397 { "Codec Capture", NULL, "Left ADC" },
1398 { "Codec Capture", NULL, "Right ADC" },
1399
1400
1401 { "Left DAC", NULL, "DAC Enable" },
1402 { "Right DAC", NULL, "DAC Enable" },
1403 { "Left DAC", NULL, "Codec Playback" },
1404 { "Right DAC", NULL, "Codec Playback" },
1405 };
1406
1407 static struct snd_soc_aux_dev aux_dev = {
1408 .dlc = COMP_EMPTY(),
1409 };
1410
1411 static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
1412 {
1413 struct snd_soc_card *card;
1414 int ret;
1415
1416 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1417 if (!card)
1418 return ERR_PTR(-ENOMEM);
1419
1420 aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1421 "allwinner,codec-analog-controls",
1422 0);
1423 if (!aux_dev.dlc.of_node) {
1424 dev_err(dev, "Can't find analog controls for codec.\n");
1425 return ERR_PTR(-EINVAL);
1426 }
1427
1428 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1429 if (!card->dai_link)
1430 return ERR_PTR(-ENOMEM);
1431
1432 card->dev = dev;
1433 card->owner = THIS_MODULE;
1434 card->name = "A23 Audio Codec";
1435 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1436 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1437 card->dapm_routes = sun8i_codec_card_routes;
1438 card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1439 card->aux_dev = &aux_dev;
1440 card->num_aux_devs = 1;
1441 card->fully_routed = true;
1442
1443 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1444 if (ret)
1445 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1446
1447 return card;
1448 };
1449
1450 static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
1451 {
1452 struct snd_soc_card *card;
1453 int ret;
1454
1455 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1456 if (!card)
1457 return ERR_PTR(-ENOMEM);
1458
1459 aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1460 "allwinner,codec-analog-controls",
1461 0);
1462 if (!aux_dev.dlc.of_node) {
1463 dev_err(dev, "Can't find analog controls for codec.\n");
1464 return ERR_PTR(-EINVAL);
1465 }
1466
1467 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1468 if (!card->dai_link)
1469 return ERR_PTR(-ENOMEM);
1470
1471 card->dev = dev;
1472 card->owner = THIS_MODULE;
1473 card->name = "H3 Audio Codec";
1474 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1475 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1476 card->dapm_routes = sun8i_codec_card_routes;
1477 card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1478 card->aux_dev = &aux_dev;
1479 card->num_aux_devs = 1;
1480 card->fully_routed = true;
1481
1482 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1483 if (ret)
1484 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1485
1486 return card;
1487 };
1488
1489 static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
1490 {
1491 struct snd_soc_card *card;
1492 int ret;
1493
1494 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1495 if (!card)
1496 return ERR_PTR(-ENOMEM);
1497
1498 aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1499 "allwinner,codec-analog-controls",
1500 0);
1501 if (!aux_dev.dlc.of_node) {
1502 dev_err(dev, "Can't find analog controls for codec.\n");
1503 return ERR_PTR(-EINVAL);
1504 }
1505
1506 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1507 if (!card->dai_link)
1508 return ERR_PTR(-ENOMEM);
1509
1510 card->dev = dev;
1511 card->owner = THIS_MODULE;
1512 card->name = "V3s Audio Codec";
1513 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1514 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1515 card->dapm_routes = sun8i_codec_card_routes;
1516 card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1517 card->aux_dev = &aux_dev;
1518 card->num_aux_devs = 1;
1519 card->fully_routed = true;
1520
1521 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1522 if (ret)
1523 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1524
1525 return card;
1526 };
1527
1528 static const struct regmap_config sun4i_codec_regmap_config = {
1529 .reg_bits = 32,
1530 .reg_stride = 4,
1531 .val_bits = 32,
1532 .max_register = SUN4I_CODEC_ADC_RXCNT,
1533 };
1534
1535 static const struct regmap_config sun6i_codec_regmap_config = {
1536 .reg_bits = 32,
1537 .reg_stride = 4,
1538 .val_bits = 32,
1539 .max_register = SUN6I_CODEC_HMIC_DATA,
1540 };
1541
1542 static const struct regmap_config sun7i_codec_regmap_config = {
1543 .reg_bits = 32,
1544 .reg_stride = 4,
1545 .val_bits = 32,
1546 .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
1547 };
1548
1549 static const struct regmap_config sun8i_a23_codec_regmap_config = {
1550 .reg_bits = 32,
1551 .reg_stride = 4,
1552 .val_bits = 32,
1553 .max_register = SUN8I_A23_CODEC_ADC_RXCNT,
1554 };
1555
1556 static const struct regmap_config sun8i_h3_codec_regmap_config = {
1557 .reg_bits = 32,
1558 .reg_stride = 4,
1559 .val_bits = 32,
1560 .max_register = SUN8I_H3_CODEC_ADC_DBG,
1561 };
1562
1563 static const struct regmap_config sun8i_v3s_codec_regmap_config = {
1564 .reg_bits = 32,
1565 .reg_stride = 4,
1566 .val_bits = 32,
1567 .max_register = SUN8I_H3_CODEC_ADC_DBG,
1568 };
1569
1570 struct sun4i_codec_quirks {
1571 const struct regmap_config *regmap_config;
1572 const struct snd_soc_component_driver *codec;
1573 struct snd_soc_card * (*create_card)(struct device *dev);
1574 struct reg_field reg_adc_fifoc;
1575 unsigned int reg_dac_txdata;
1576 unsigned int reg_adc_rxdata;
1577 bool has_reset;
1578 };
1579
1580 static const struct sun4i_codec_quirks sun4i_codec_quirks = {
1581 .regmap_config = &sun4i_codec_regmap_config,
1582 .codec = &sun4i_codec_codec,
1583 .create_card = sun4i_codec_create_card,
1584 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1585 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1586 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1587 };
1588
1589 static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
1590 .regmap_config = &sun6i_codec_regmap_config,
1591 .codec = &sun6i_codec_codec,
1592 .create_card = sun6i_codec_create_card,
1593 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1594 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1595 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1596 .has_reset = true,
1597 };
1598
1599 static const struct sun4i_codec_quirks sun7i_codec_quirks = {
1600 .regmap_config = &sun7i_codec_regmap_config,
1601 .codec = &sun7i_codec_codec,
1602 .create_card = sun4i_codec_create_card,
1603 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1604 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1605 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1606 };
1607
1608 static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
1609 .regmap_config = &sun8i_a23_codec_regmap_config,
1610 .codec = &sun8i_a23_codec_codec,
1611 .create_card = sun8i_a23_codec_create_card,
1612 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1613 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1614 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1615 .has_reset = true,
1616 };
1617
1618 static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
1619 .regmap_config = &sun8i_h3_codec_regmap_config,
1620
1621
1622
1623
1624
1625 .codec = &sun8i_a23_codec_codec,
1626 .create_card = sun8i_h3_codec_create_card,
1627 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1628 .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1629 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1630 .has_reset = true,
1631 };
1632
1633 static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
1634 .regmap_config = &sun8i_v3s_codec_regmap_config,
1635
1636
1637
1638
1639 .codec = &sun8i_a23_codec_codec,
1640 .create_card = sun8i_v3s_codec_create_card,
1641 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1642 .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1643 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1644 .has_reset = true,
1645 };
1646
1647 static const struct of_device_id sun4i_codec_of_match[] = {
1648 {
1649 .compatible = "allwinner,sun4i-a10-codec",
1650 .data = &sun4i_codec_quirks,
1651 },
1652 {
1653 .compatible = "allwinner,sun6i-a31-codec",
1654 .data = &sun6i_a31_codec_quirks,
1655 },
1656 {
1657 .compatible = "allwinner,sun7i-a20-codec",
1658 .data = &sun7i_codec_quirks,
1659 },
1660 {
1661 .compatible = "allwinner,sun8i-a23-codec",
1662 .data = &sun8i_a23_codec_quirks,
1663 },
1664 {
1665 .compatible = "allwinner,sun8i-h3-codec",
1666 .data = &sun8i_h3_codec_quirks,
1667 },
1668 {
1669 .compatible = "allwinner,sun8i-v3s-codec",
1670 .data = &sun8i_v3s_codec_quirks,
1671 },
1672 {}
1673 };
1674 MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
1675
1676 static int sun4i_codec_probe(struct platform_device *pdev)
1677 {
1678 struct snd_soc_card *card;
1679 struct sun4i_codec *scodec;
1680 const struct sun4i_codec_quirks *quirks;
1681 struct resource *res;
1682 void __iomem *base;
1683 int ret;
1684
1685 scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
1686 if (!scodec)
1687 return -ENOMEM;
1688
1689 scodec->dev = &pdev->dev;
1690
1691 base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1692 if (IS_ERR(base))
1693 return PTR_ERR(base);
1694
1695 quirks = of_device_get_match_data(&pdev->dev);
1696 if (quirks == NULL) {
1697 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
1698 return -ENODEV;
1699 }
1700
1701 scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
1702 quirks->regmap_config);
1703 if (IS_ERR(scodec->regmap)) {
1704 dev_err(&pdev->dev, "Failed to create our regmap\n");
1705 return PTR_ERR(scodec->regmap);
1706 }
1707
1708
1709 scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
1710 if (IS_ERR(scodec->clk_apb)) {
1711 dev_err(&pdev->dev, "Failed to get the APB clock\n");
1712 return PTR_ERR(scodec->clk_apb);
1713 }
1714
1715 scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
1716 if (IS_ERR(scodec->clk_module)) {
1717 dev_err(&pdev->dev, "Failed to get the module clock\n");
1718 return PTR_ERR(scodec->clk_module);
1719 }
1720
1721 if (quirks->has_reset) {
1722 scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
1723 NULL);
1724 if (IS_ERR(scodec->rst)) {
1725 dev_err(&pdev->dev, "Failed to get reset control\n");
1726 return PTR_ERR(scodec->rst);
1727 }
1728 }
1729
1730 scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
1731 GPIOD_OUT_LOW);
1732 if (IS_ERR(scodec->gpio_pa)) {
1733 ret = PTR_ERR(scodec->gpio_pa);
1734 dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
1735 return ret;
1736 }
1737
1738
1739 scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
1740 scodec->regmap,
1741 quirks->reg_adc_fifoc);
1742 if (IS_ERR(scodec->reg_adc_fifoc)) {
1743 ret = PTR_ERR(scodec->reg_adc_fifoc);
1744 dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
1745 ret);
1746 return ret;
1747 }
1748
1749
1750 if (clk_prepare_enable(scodec->clk_apb)) {
1751 dev_err(&pdev->dev, "Failed to enable the APB clock\n");
1752 return -EINVAL;
1753 }
1754
1755
1756 if (scodec->rst) {
1757 ret = reset_control_deassert(scodec->rst);
1758 if (ret) {
1759 dev_err(&pdev->dev,
1760 "Failed to deassert the reset control\n");
1761 goto err_clk_disable;
1762 }
1763 }
1764
1765
1766 scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
1767 scodec->playback_dma_data.maxburst = 8;
1768 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1769
1770
1771 scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
1772 scodec->capture_dma_data.maxburst = 8;
1773 scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1774
1775 ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
1776 &sun4i_codec_dai, 1);
1777 if (ret) {
1778 dev_err(&pdev->dev, "Failed to register our codec\n");
1779 goto err_assert_reset;
1780 }
1781
1782 ret = devm_snd_soc_register_component(&pdev->dev,
1783 &sun4i_codec_component,
1784 &dummy_cpu_dai, 1);
1785 if (ret) {
1786 dev_err(&pdev->dev, "Failed to register our DAI\n");
1787 goto err_assert_reset;
1788 }
1789
1790 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1791 if (ret) {
1792 dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
1793 goto err_assert_reset;
1794 }
1795
1796 card = quirks->create_card(&pdev->dev);
1797 if (IS_ERR(card)) {
1798 ret = PTR_ERR(card);
1799 dev_err(&pdev->dev, "Failed to create our card\n");
1800 goto err_assert_reset;
1801 }
1802
1803 snd_soc_card_set_drvdata(card, scodec);
1804
1805 ret = snd_soc_register_card(card);
1806 if (ret) {
1807 dev_err(&pdev->dev, "Failed to register our card\n");
1808 goto err_assert_reset;
1809 }
1810
1811 return 0;
1812
1813 err_assert_reset:
1814 if (scodec->rst)
1815 reset_control_assert(scodec->rst);
1816 err_clk_disable:
1817 clk_disable_unprepare(scodec->clk_apb);
1818 return ret;
1819 }
1820
1821 static int sun4i_codec_remove(struct platform_device *pdev)
1822 {
1823 struct snd_soc_card *card = platform_get_drvdata(pdev);
1824 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1825
1826 snd_soc_unregister_card(card);
1827 if (scodec->rst)
1828 reset_control_assert(scodec->rst);
1829 clk_disable_unprepare(scodec->clk_apb);
1830
1831 return 0;
1832 }
1833
1834 static struct platform_driver sun4i_codec_driver = {
1835 .driver = {
1836 .name = "sun4i-codec",
1837 .of_match_table = sun4i_codec_of_match,
1838 },
1839 .probe = sun4i_codec_probe,
1840 .remove = sun4i_codec_remove,
1841 };
1842 module_platform_driver(sun4i_codec_driver);
1843
1844 MODULE_DESCRIPTION("Allwinner A10 codec driver");
1845 MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
1846 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
1847 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1848 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
1849 MODULE_LICENSE("GPL");