1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 236c68493SMylène Josserand /* 336c68493SMylène Josserand * This driver supports the digital controls for the internal codec 436c68493SMylène Josserand * found in Allwinner's A33 SoCs. 536c68493SMylène Josserand * 636c68493SMylène Josserand * (C) Copyright 2010-2016 736c68493SMylène Josserand * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> 836c68493SMylène Josserand * huangxin <huangxin@Reuuimllatech.com> 936c68493SMylène Josserand * Mylène Josserand <mylene.josserand@free-electrons.com> 1036c68493SMylène Josserand */ 1136c68493SMylène Josserand 1236c68493SMylène Josserand #include <linux/module.h> 1336c68493SMylène Josserand #include <linux/delay.h> 1436c68493SMylène Josserand #include <linux/clk.h> 1536c68493SMylène Josserand #include <linux/io.h> 1690cac932SSamuel Holland #include <linux/of_device.h> 1736c68493SMylène Josserand #include <linux/pm_runtime.h> 1836c68493SMylène Josserand #include <linux/regmap.h> 1913c3bf17SVasily Khoruzhick #include <linux/log2.h> 2036c68493SMylène Josserand 2136c68493SMylène Josserand #include <sound/pcm_params.h> 2236c68493SMylène Josserand #include <sound/soc.h> 2336c68493SMylène Josserand #include <sound/soc-dapm.h> 2436c68493SMylène Josserand 2536c68493SMylène Josserand #define SUN8I_SYSCLK_CTL 0x00c 2636c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11 27d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8) 28d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7 29d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4) 3036c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3 3136c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0 32d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0) 33d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0) 3436c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA 0x010 3536c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_AIF1 15 36eda85d1fSMylene JOSSERAND #define SUN8I_MOD_CLK_ENA_ADC 3 3736c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_DAC 2 3836c68493SMylène Josserand #define SUN8I_MOD_RST_CTL 0x014 3936c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_AIF1 15 40eda85d1fSMylene JOSSERAND #define SUN8I_MOD_RST_CTL_ADC 3 4136c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_DAC 2 4236c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL 0x018 4336c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS 12 4436c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS 8 4536c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL 0x040 4636c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15 4736c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14 4836c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 4936c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 5036c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 5136c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 5236c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) 5336c68493SMylène Josserand #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 54eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_ADCDAT_CTRL 0x044 55fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 56fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14 5718ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10 5818ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8 5936c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL 0x048 6036c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15 6136c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14 6218ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10 6318ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8 64eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC 0x04c 650ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15 660ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14 670ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13 680ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12 69eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11 70eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 71eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 72eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 73eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL 0x100 7430aff91eSSamuel Holland #define SUN8I_ADC_DIG_CTRL_ENAD 15 75eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 76eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1 7736c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL 0x120 7836c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL_ENDA 15 7936c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC 0x130 8036c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 8136c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 8236c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 8336c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12 8436c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 8536c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 8636c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 8736c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8 8836c68493SMylène Josserand 89d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8) 90d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4) 9136c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) 9236c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) 93316b7758SMaxime Ripard #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) 94f30ef55cSSamuel Holland #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) 95f30ef55cSSamuel Holland #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) 96f30ef55cSSamuel Holland #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) 9736c68493SMylène Josserand 9890cac932SSamuel Holland struct sun8i_codec_quirks { 9990cac932SSamuel Holland bool legacy_widgets : 1; 1007518805fSSamuel Holland bool lrck_inversion : 1; 10190cac932SSamuel Holland }; 10290cac932SSamuel Holland 10336c68493SMylène Josserand struct sun8i_codec { 10436c68493SMylène Josserand struct regmap *regmap; 10536c68493SMylène Josserand struct clk *clk_module; 10690cac932SSamuel Holland const struct sun8i_codec_quirks *quirks; 10736c68493SMylène Josserand }; 10836c68493SMylène Josserand 10936c68493SMylène Josserand static int sun8i_codec_runtime_resume(struct device *dev) 11036c68493SMylène Josserand { 11136c68493SMylène Josserand struct sun8i_codec *scodec = dev_get_drvdata(dev); 11236c68493SMylène Josserand int ret; 11336c68493SMylène Josserand 11436c68493SMylène Josserand regcache_cache_only(scodec->regmap, false); 11536c68493SMylène Josserand 11636c68493SMylène Josserand ret = regcache_sync(scodec->regmap); 11736c68493SMylène Josserand if (ret) { 11836c68493SMylène Josserand dev_err(dev, "Failed to sync regmap cache\n"); 1196b3bb3c8SSamuel Holland return ret; 12036c68493SMylène Josserand } 12136c68493SMylène Josserand 12236c68493SMylène Josserand return 0; 12336c68493SMylène Josserand } 12436c68493SMylène Josserand 12536c68493SMylène Josserand static int sun8i_codec_runtime_suspend(struct device *dev) 12636c68493SMylène Josserand { 12736c68493SMylène Josserand struct sun8i_codec *scodec = dev_get_drvdata(dev); 12836c68493SMylène Josserand 12936c68493SMylène Josserand regcache_cache_only(scodec->regmap, true); 13036c68493SMylène Josserand regcache_mark_dirty(scodec->regmap); 13136c68493SMylène Josserand 13236c68493SMylène Josserand return 0; 13336c68493SMylène Josserand } 13436c68493SMylène Josserand 13536c68493SMylène Josserand static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) 13636c68493SMylène Josserand { 13736c68493SMylène Josserand unsigned int rate = params_rate(params); 13836c68493SMylène Josserand 13936c68493SMylène Josserand switch (rate) { 14036c68493SMylène Josserand case 8000: 14136c68493SMylène Josserand case 7350: 14236c68493SMylène Josserand return 0x0; 14336c68493SMylène Josserand case 11025: 14436c68493SMylène Josserand return 0x1; 14536c68493SMylène Josserand case 12000: 14636c68493SMylène Josserand return 0x2; 14736c68493SMylène Josserand case 16000: 14836c68493SMylène Josserand return 0x3; 14936c68493SMylène Josserand case 22050: 15036c68493SMylène Josserand return 0x4; 15136c68493SMylène Josserand case 24000: 15236c68493SMylène Josserand return 0x5; 15336c68493SMylène Josserand case 32000: 15436c68493SMylène Josserand return 0x6; 15536c68493SMylène Josserand case 44100: 15636c68493SMylène Josserand return 0x7; 15736c68493SMylène Josserand case 48000: 15836c68493SMylène Josserand return 0x8; 15936c68493SMylène Josserand case 96000: 16036c68493SMylène Josserand return 0x9; 16136c68493SMylène Josserand case 192000: 16236c68493SMylène Josserand return 0xa; 16336c68493SMylène Josserand default: 16436c68493SMylène Josserand return -EINVAL; 16536c68493SMylène Josserand } 16636c68493SMylène Josserand } 16736c68493SMylène Josserand 16836c68493SMylène Josserand static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 16936c68493SMylène Josserand { 170a886990cSSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); 17136c68493SMylène Josserand u32 value; 17236c68493SMylène Josserand 17336c68493SMylène Josserand /* clock masters */ 17436c68493SMylène Josserand switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 175560bfe77SMaxime Ripard case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */ 176560bfe77SMaxime Ripard value = 0x1; 17736c68493SMylène Josserand break; 178560bfe77SMaxime Ripard case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */ 179560bfe77SMaxime Ripard value = 0x0; 18036c68493SMylène Josserand break; 18136c68493SMylène Josserand default: 18236c68493SMylène Josserand return -EINVAL; 18336c68493SMylène Josserand } 18436c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 18536c68493SMylène Josserand BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), 18636c68493SMylène Josserand value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); 18736c68493SMylène Josserand 18836c68493SMylène Josserand /* clock inversion */ 18936c68493SMylène Josserand switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 19036c68493SMylène Josserand case SND_SOC_DAIFMT_NB_NF: /* Normal */ 19136c68493SMylène Josserand value = 0x0; 19236c68493SMylène Josserand break; 19336c68493SMylène Josserand case SND_SOC_DAIFMT_IB_IF: /* Inversion */ 19436c68493SMylène Josserand value = 0x1; 19536c68493SMylène Josserand break; 19636c68493SMylène Josserand default: 19736c68493SMylène Josserand return -EINVAL; 19836c68493SMylène Josserand } 19936c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 20036c68493SMylène Josserand BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV), 20136c68493SMylène Josserand value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); 202e7b8a6d3SMaxime Ripard 203e7b8a6d3SMaxime Ripard /* 2047518805fSSamuel Holland * It appears that the DAI and the codec in the A33 SoC don't 2057518805fSSamuel Holland * share the same polarity for the LRCK signal when they mean 2067518805fSSamuel Holland * 'normal' and 'inverted' in the datasheet. 207e7b8a6d3SMaxime Ripard * 208e7b8a6d3SMaxime Ripard * Since the DAI here is our regular i2s driver that have been 209e7b8a6d3SMaxime Ripard * tested with way more codecs than just this one, it means 210e7b8a6d3SMaxime Ripard * that the codec probably gets it backward, and we have to 211e7b8a6d3SMaxime Ripard * invert the value here. 212e7b8a6d3SMaxime Ripard */ 2137518805fSSamuel Holland value ^= scodec->quirks->lrck_inversion; 21436c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 21536c68493SMylène Josserand BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), 2167518805fSSamuel Holland value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); 21736c68493SMylène Josserand 21836c68493SMylène Josserand /* DAI format */ 21936c68493SMylène Josserand switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 22036c68493SMylène Josserand case SND_SOC_DAIFMT_I2S: 22136c68493SMylène Josserand value = 0x0; 22236c68493SMylène Josserand break; 22336c68493SMylène Josserand case SND_SOC_DAIFMT_LEFT_J: 22436c68493SMylène Josserand value = 0x1; 22536c68493SMylène Josserand break; 22636c68493SMylène Josserand case SND_SOC_DAIFMT_RIGHT_J: 22736c68493SMylène Josserand value = 0x2; 22836c68493SMylène Josserand break; 22936c68493SMylène Josserand case SND_SOC_DAIFMT_DSP_A: 23036c68493SMylène Josserand case SND_SOC_DAIFMT_DSP_B: 23136c68493SMylène Josserand value = 0x3; 23236c68493SMylène Josserand break; 23336c68493SMylène Josserand default: 23436c68493SMylène Josserand return -EINVAL; 23536c68493SMylène Josserand } 23636c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 23796781fd9SSamuel Holland SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, 23836c68493SMylène Josserand value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); 23936c68493SMylène Josserand 24036c68493SMylène Josserand return 0; 24136c68493SMylène Josserand } 24236c68493SMylène Josserand 243316b7758SMaxime Ripard struct sun8i_codec_clk_div { 244316b7758SMaxime Ripard u8 div; 245316b7758SMaxime Ripard u8 val; 246316b7758SMaxime Ripard }; 247316b7758SMaxime Ripard 248316b7758SMaxime Ripard static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { 249316b7758SMaxime Ripard { .div = 1, .val = 0 }, 250316b7758SMaxime Ripard { .div = 2, .val = 1 }, 251316b7758SMaxime Ripard { .div = 4, .val = 2 }, 252316b7758SMaxime Ripard { .div = 6, .val = 3 }, 253316b7758SMaxime Ripard { .div = 8, .val = 4 }, 254316b7758SMaxime Ripard { .div = 12, .val = 5 }, 255316b7758SMaxime Ripard { .div = 16, .val = 6 }, 256316b7758SMaxime Ripard { .div = 24, .val = 7 }, 257316b7758SMaxime Ripard { .div = 32, .val = 8 }, 258316b7758SMaxime Ripard { .div = 48, .val = 9 }, 259316b7758SMaxime Ripard { .div = 64, .val = 10 }, 260316b7758SMaxime Ripard { .div = 96, .val = 11 }, 261316b7758SMaxime Ripard { .div = 128, .val = 12 }, 262316b7758SMaxime Ripard { .div = 192, .val = 13 }, 263316b7758SMaxime Ripard }; 264316b7758SMaxime Ripard 265316b7758SMaxime Ripard static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, 266316b7758SMaxime Ripard unsigned int rate, 267316b7758SMaxime Ripard unsigned int word_size) 268316b7758SMaxime Ripard { 269316b7758SMaxime Ripard unsigned long clk_rate = clk_get_rate(scodec->clk_module); 270316b7758SMaxime Ripard unsigned int div = clk_rate / rate / word_size / 2; 271316b7758SMaxime Ripard unsigned int best_val = 0, best_diff = ~0; 272316b7758SMaxime Ripard int i; 273316b7758SMaxime Ripard 274316b7758SMaxime Ripard for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) { 275316b7758SMaxime Ripard const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i]; 276316b7758SMaxime Ripard unsigned int diff = abs(bdiv->div - div); 277316b7758SMaxime Ripard 278316b7758SMaxime Ripard if (diff < best_diff) { 279316b7758SMaxime Ripard best_diff = diff; 280316b7758SMaxime Ripard best_val = bdiv->val; 281316b7758SMaxime Ripard } 282316b7758SMaxime Ripard } 283316b7758SMaxime Ripard 284316b7758SMaxime Ripard return best_val; 285316b7758SMaxime Ripard } 286316b7758SMaxime Ripard 28713c3bf17SVasily Khoruzhick static int sun8i_codec_get_lrck_div(unsigned int channels, 28813c3bf17SVasily Khoruzhick unsigned int word_size) 28913c3bf17SVasily Khoruzhick { 29013c3bf17SVasily Khoruzhick unsigned int div = word_size * channels; 29113c3bf17SVasily Khoruzhick 29213c3bf17SVasily Khoruzhick if (div < 16 || div > 256) 29313c3bf17SVasily Khoruzhick return -EINVAL; 29413c3bf17SVasily Khoruzhick 29513c3bf17SVasily Khoruzhick return ilog2(div) - 4; 29613c3bf17SVasily Khoruzhick } 29713c3bf17SVasily Khoruzhick 29836c68493SMylène Josserand static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, 29936c68493SMylène Josserand struct snd_pcm_hw_params *params, 30036c68493SMylène Josserand struct snd_soc_dai *dai) 30136c68493SMylène Josserand { 302a886990cSSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); 30313c3bf17SVasily Khoruzhick int sample_rate, lrck_div; 304316b7758SMaxime Ripard u8 bclk_div; 30536c68493SMylène Josserand 30636c68493SMylène Josserand /* 30736c68493SMylène Josserand * The CPU DAI handles only a sample of 16 bits. Configure the 30836c68493SMylène Josserand * codec to handle this type of sample resolution. 30936c68493SMylène Josserand */ 31036c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 31136c68493SMylène Josserand SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, 31236c68493SMylène Josserand SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); 31336c68493SMylène Josserand 314316b7758SMaxime Ripard bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); 315316b7758SMaxime Ripard regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 316316b7758SMaxime Ripard SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, 317316b7758SMaxime Ripard bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); 318316b7758SMaxime Ripard 31913c3bf17SVasily Khoruzhick lrck_div = sun8i_codec_get_lrck_div(params_channels(params), 32013c3bf17SVasily Khoruzhick params_physical_width(params)); 32113c3bf17SVasily Khoruzhick if (lrck_div < 0) 32213c3bf17SVasily Khoruzhick return lrck_div; 32313c3bf17SVasily Khoruzhick 32436c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, 32536c68493SMylène Josserand SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, 32613c3bf17SVasily Khoruzhick lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); 32736c68493SMylène Josserand 32836c68493SMylène Josserand sample_rate = sun8i_codec_get_hw_rate(params); 32936c68493SMylène Josserand if (sample_rate < 0) 33036c68493SMylène Josserand return sample_rate; 33136c68493SMylène Josserand 33236c68493SMylène Josserand regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, 33336c68493SMylène Josserand SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, 33436c68493SMylène Josserand sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); 33536c68493SMylène Josserand 33636c68493SMylène Josserand return 0; 33736c68493SMylène Josserand } 33836c68493SMylène Josserand 33918ebd62cSSamuel Holland static const char *const sun8i_aif_stereo_mux_enum_values[] = { 34018ebd62cSSamuel Holland "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono" 34118ebd62cSSamuel Holland }; 34218ebd62cSSamuel Holland 34318ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum, 34418ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL, 34518ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC, 34618ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC, 34718ebd62cSSamuel Holland sun8i_aif_stereo_mux_enum_values); 34818ebd62cSSamuel Holland 34918ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control = 35018ebd62cSSamuel Holland SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route", 35118ebd62cSSamuel Holland sun8i_aif1_ad0_stereo_mux_enum); 35218ebd62cSSamuel Holland 353d58b7247SSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { 354d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", 355d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC, 356d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L, 357d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0), 358d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", 359d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC, 360d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL, 361d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0), 362d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch", 363d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC, 364d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL, 365d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0), 366d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch", 367d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC, 368d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR, 369d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), 370d58b7247SSamuel Holland }; 371d58b7247SSamuel Holland 37218ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum, 37318ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL, 37418ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC, 37518ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC, 37618ebd62cSSamuel Holland sun8i_aif_stereo_mux_enum_values); 37718ebd62cSSamuel Holland 37818ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control = 37918ebd62cSSamuel Holland SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route", 38018ebd62cSSamuel Holland sun8i_aif1_da0_stereo_mux_enum); 38118ebd62cSSamuel Holland 382ca14da6eSMylène Josserand static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { 383ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch", 384ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC, 385ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 38636c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0), 387ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch", 388ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC, 389ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 39036c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0), 391ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, 392ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 39336c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0), 394ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, 395ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 39636c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), 39736c68493SMylène Josserand }; 39836c68493SMylène Josserand 39936c68493SMylène Josserand static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { 400d8f00682SSamuel Holland /* System Clocks */ 4016b3bb3c8SSamuel Holland SND_SOC_DAPM_CLOCK_SUPPLY("mod"), 4026b3bb3c8SSamuel Holland 403d8f00682SSamuel Holland SND_SOC_DAPM_SUPPLY("AIF1CLK", 404d8f00682SSamuel Holland SUN8I_SYSCLK_CTL, 405d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), 406d8f00682SSamuel Holland SND_SOC_DAPM_SUPPLY("SYSCLK", 407d8f00682SSamuel Holland SUN8I_SYSCLK_CTL, 408d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), 409d8f00682SSamuel Holland 410ed3caa3bSSamuel Holland /* Module Clocks */ 411ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK AIF1", 412ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA, 413ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), 414ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK ADC", 415ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA, 416ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), 417ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK DAC", 418ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA, 419ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), 420ed3caa3bSSamuel Holland 421ed3caa3bSSamuel Holland /* Module Resets */ 422ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST AIF1", 423ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL, 424ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), 425ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST ADC", 426ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL, 427ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), 428ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST DAC", 429ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL, 430ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), 431ed3caa3bSSamuel Holland 432d58b7247SSamuel Holland /* Module Supplies */ 433d58b7247SSamuel Holland SND_SOC_DAPM_SUPPLY("ADC", 434d58b7247SSamuel Holland SUN8I_ADC_DIG_CTRL, 435d58b7247SSamuel Holland SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0), 436d58b7247SSamuel Holland SND_SOC_DAPM_SUPPLY("DAC", 437d58b7247SSamuel Holland SUN8I_DAC_DIG_CTRL, 438d58b7247SSamuel Holland SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), 43936c68493SMylène Josserand 44090cac932SSamuel Holland /* AIF "ADC" Outputs */ 441fc5668f6SSamuel Holland SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0, 442eda85d1fSMylene JOSSERAND SUN8I_AIF1_ADCDAT_CTRL, 443fa5c0ca1SSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), 4444ab60cefSSamuel Holland SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1, 445eda85d1fSMylene JOSSERAND SUN8I_AIF1_ADCDAT_CTRL, 446fa5c0ca1SSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), 447eda85d1fSMylene JOSSERAND 44818ebd62cSSamuel Holland /* AIF "ADC" Mono/Stereo Muxes */ 44918ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0, 45018ebd62cSSamuel Holland &sun8i_aif1_ad0_stereo_mux_control), 45118ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0, 45218ebd62cSSamuel Holland &sun8i_aif1_ad0_stereo_mux_control), 45318ebd62cSSamuel Holland 454d58b7247SSamuel Holland /* AIF "ADC" Mixers */ 4557b51f3c7SSamuel Holland SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0, 456d58b7247SSamuel Holland sun8i_aif1_ad0_mixer_controls), 4577b51f3c7SSamuel Holland SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0, 458d58b7247SSamuel Holland sun8i_aif1_ad0_mixer_controls), 459d58b7247SSamuel Holland 46018ebd62cSSamuel Holland /* AIF "DAC" Mono/Stereo Muxes */ 46118ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0, 46218ebd62cSSamuel Holland &sun8i_aif1_da0_stereo_mux_control), 46318ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0, 46418ebd62cSSamuel Holland &sun8i_aif1_da0_stereo_mux_control), 46518ebd62cSSamuel Holland 466d58b7247SSamuel Holland /* AIF "DAC" Inputs */ 467d58b7247SSamuel Holland SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0, 468d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL, 469d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), 4704ab60cefSSamuel Holland SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1, 471d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL, 472d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), 473d58b7247SSamuel Holland 47490cac932SSamuel Holland /* ADC Inputs (connected to analog codec DAPM context) */ 47590cac932SSamuel Holland SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), 47690cac932SSamuel Holland SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), 47790cac932SSamuel Holland 47890cac932SSamuel Holland /* DAC Outputs (connected to analog codec DAPM context) */ 47990cac932SSamuel Holland SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), 48090cac932SSamuel Holland SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), 48190cac932SSamuel Holland 482d58b7247SSamuel Holland /* DAC Mixers */ 4837b51f3c7SSamuel Holland SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0, 484fa22ca4fSMylène Josserand sun8i_dac_mixer_controls), 4857b51f3c7SSamuel Holland SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0, 486fa22ca4fSMylène Josserand sun8i_dac_mixer_controls), 48736c68493SMylène Josserand }; 48836c68493SMylène Josserand 48936c68493SMylène Josserand static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { 49036c68493SMylène Josserand /* Clock Routes */ 491d8f00682SSamuel Holland { "AIF1CLK", NULL, "mod" }, 4926b3bb3c8SSamuel Holland 493d8f00682SSamuel Holland { "SYSCLK", NULL, "AIF1CLK" }, 49490cac932SSamuel Holland 495ed3caa3bSSamuel Holland { "CLK AIF1", NULL, "AIF1CLK" }, 496ed3caa3bSSamuel Holland { "CLK AIF1", NULL, "SYSCLK" }, 497ed3caa3bSSamuel Holland { "RST AIF1", NULL, "CLK AIF1" }, 498ed3caa3bSSamuel Holland { "AIF1 AD0L", NULL, "RST AIF1" }, 499ed3caa3bSSamuel Holland { "AIF1 AD0R", NULL, "RST AIF1" }, 500ed3caa3bSSamuel Holland { "AIF1 DA0L", NULL, "RST AIF1" }, 501ed3caa3bSSamuel Holland { "AIF1 DA0R", NULL, "RST AIF1" }, 50236c68493SMylène Josserand 503ed3caa3bSSamuel Holland { "CLK ADC", NULL, "SYSCLK" }, 504ed3caa3bSSamuel Holland { "RST ADC", NULL, "CLK ADC" }, 505ed3caa3bSSamuel Holland { "ADC", NULL, "RST ADC" }, 50690cac932SSamuel Holland { "ADCL", NULL, "ADC" }, 50790cac932SSamuel Holland { "ADCR", NULL, "ADC" }, 508eda85d1fSMylene JOSSERAND 509ed3caa3bSSamuel Holland { "CLK DAC", NULL, "SYSCLK" }, 510ed3caa3bSSamuel Holland { "RST DAC", NULL, "CLK DAC" }, 511ed3caa3bSSamuel Holland { "DAC", NULL, "RST DAC" }, 512ed3caa3bSSamuel Holland { "DACL", NULL, "DAC" }, 513ed3caa3bSSamuel Holland { "DACR", NULL, "DAC" }, 514ed3caa3bSSamuel Holland 515d58b7247SSamuel Holland /* AIF "ADC" Output Routes */ 51618ebd62cSSamuel Holland { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" }, 51718ebd62cSSamuel Holland { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" }, 51818ebd62cSSamuel Holland 51918ebd62cSSamuel Holland /* AIF "ADC" Mono/Stereo Mux Routes */ 52018ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" }, 52118ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" }, 52218ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" }, 52318ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" }, 52418ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" }, 52518ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" }, 52618ebd62cSSamuel Holland 52718ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" }, 52818ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" }, 52918ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" }, 53018ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" }, 53118ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" }, 53218ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" }, 533d58b7247SSamuel Holland 534d58b7247SSamuel Holland /* AIF "ADC" Mixer Routes */ 53518ebd62cSSamuel Holland { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" }, 5367b51f3c7SSamuel Holland { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" }, 537d58b7247SSamuel Holland 53818ebd62cSSamuel Holland { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" }, 5397b51f3c7SSamuel Holland { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" }, 540d58b7247SSamuel Holland 54118ebd62cSSamuel Holland /* AIF "DAC" Mono/Stereo Mux Routes */ 54218ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" }, 54318ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" }, 54418ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" }, 54518ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" }, 54618ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" }, 54718ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" }, 54818ebd62cSSamuel Holland 54918ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" }, 55018ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" }, 55118ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" }, 55218ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" }, 55318ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" }, 55418ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" }, 55518ebd62cSSamuel Holland 556d58b7247SSamuel Holland /* DAC Output Routes */ 5577b51f3c7SSamuel Holland { "DACL", NULL, "DACL Mixer" }, 5587b51f3c7SSamuel Holland { "DACR", NULL, "DACR Mixer" }, 55936c68493SMylène Josserand 56036c68493SMylène Josserand /* DAC Mixer Routes */ 56118ebd62cSSamuel Holland { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" }, 5627b51f3c7SSamuel Holland { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" }, 563e47d2dcdSSamuel Holland 56418ebd62cSSamuel Holland { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" }, 5657b51f3c7SSamuel Holland { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" }, 56636c68493SMylène Josserand }; 56736c68493SMylène Josserand 56890cac932SSamuel Holland static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = { 56990cac932SSamuel Holland /* Legacy ADC Inputs (connected to analog codec DAPM context) */ 57090cac932SSamuel Holland SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0), 57190cac932SSamuel Holland SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0), 57290cac932SSamuel Holland 57390cac932SSamuel Holland /* Legacy DAC Outputs (connected to analog codec DAPM context) */ 57490cac932SSamuel Holland SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0), 57590cac932SSamuel Holland SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0), 57690cac932SSamuel Holland }; 57790cac932SSamuel Holland 57890cac932SSamuel Holland static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = { 57990cac932SSamuel Holland /* Legacy ADC Routes */ 58090cac932SSamuel Holland { "ADCL", NULL, "AIF1 Slot 0 Left ADC" }, 58190cac932SSamuel Holland { "ADCR", NULL, "AIF1 Slot 0 Right ADC" }, 58290cac932SSamuel Holland 58390cac932SSamuel Holland /* Legacy DAC Routes */ 58490cac932SSamuel Holland { "AIF1 Slot 0 Left", NULL, "DACL" }, 58590cac932SSamuel Holland { "AIF1 Slot 0 Right", NULL, "DACR" }, 58690cac932SSamuel Holland }; 58790cac932SSamuel Holland 58890cac932SSamuel Holland static int sun8i_codec_component_probe(struct snd_soc_component *component) 58990cac932SSamuel Holland { 59090cac932SSamuel Holland struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 59190cac932SSamuel Holland struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); 59290cac932SSamuel Holland int ret; 59390cac932SSamuel Holland 59490cac932SSamuel Holland /* Add widgets for backward compatibility with old device trees. */ 59590cac932SSamuel Holland if (scodec->quirks->legacy_widgets) { 59690cac932SSamuel Holland ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, 59790cac932SSamuel Holland ARRAY_SIZE(sun8i_codec_legacy_widgets)); 59890cac932SSamuel Holland if (ret) 59990cac932SSamuel Holland return ret; 60090cac932SSamuel Holland 60190cac932SSamuel Holland ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes, 60290cac932SSamuel Holland ARRAY_SIZE(sun8i_codec_legacy_routes)); 60390cac932SSamuel Holland if (ret) 60490cac932SSamuel Holland return ret; 60590cac932SSamuel Holland } 60690cac932SSamuel Holland 607d8f00682SSamuel Holland /* 608d8f00682SSamuel Holland * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod") 609d8f00682SSamuel Holland * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also 610d8f00682SSamuel Holland * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO 611d8f00682SSamuel Holland * directly to simplify the clock tree. 612d8f00682SSamuel Holland */ 613d8f00682SSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, 614d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK | 615d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK, 616d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL | 617d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL); 618d8f00682SSamuel Holland 619d8f00682SSamuel Holland /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */ 620d8f00682SSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, 621d8f00682SSamuel Holland BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC), 622d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK); 623d8f00682SSamuel Holland 62490cac932SSamuel Holland return 0; 62590cac932SSamuel Holland } 62690cac932SSamuel Holland 627fe49cd98SGustavo A. R. Silva static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { 62836c68493SMylène Josserand .hw_params = sun8i_codec_hw_params, 62936c68493SMylène Josserand .set_fmt = sun8i_set_fmt, 63036c68493SMylène Josserand }; 63136c68493SMylène Josserand 63236c68493SMylène Josserand static struct snd_soc_dai_driver sun8i_codec_dai = { 63336c68493SMylène Josserand .name = "sun8i", 63436c68493SMylène Josserand /* playback capabilities */ 63536c68493SMylène Josserand .playback = { 63636c68493SMylène Josserand .stream_name = "Playback", 63736c68493SMylène Josserand .channels_min = 1, 63836c68493SMylène Josserand .channels_max = 2, 63936c68493SMylène Josserand .rates = SNDRV_PCM_RATE_8000_192000, 64036c68493SMylène Josserand .formats = SNDRV_PCM_FMTBIT_S16_LE, 64136c68493SMylène Josserand }, 642eda85d1fSMylene JOSSERAND /* capture capabilities */ 643eda85d1fSMylene JOSSERAND .capture = { 644eda85d1fSMylene JOSSERAND .stream_name = "Capture", 645eda85d1fSMylene JOSSERAND .channels_min = 1, 646eda85d1fSMylene JOSSERAND .channels_max = 2, 647eda85d1fSMylene JOSSERAND .rates = SNDRV_PCM_RATE_8000_192000, 648eda85d1fSMylene JOSSERAND .formats = SNDRV_PCM_FMTBIT_S16_LE, 649eda85d1fSMylene JOSSERAND .sig_bits = 24, 650eda85d1fSMylene JOSSERAND }, 65136c68493SMylène Josserand /* pcm operations */ 65236c68493SMylène Josserand .ops = &sun8i_codec_dai_ops, 65336c68493SMylène Josserand }; 65436c68493SMylène Josserand 6557ec9b872SKuninori Morimoto static const struct snd_soc_component_driver sun8i_soc_component = { 65636c68493SMylène Josserand .dapm_widgets = sun8i_codec_dapm_widgets, 65736c68493SMylène Josserand .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), 65836c68493SMylène Josserand .dapm_routes = sun8i_codec_dapm_routes, 65936c68493SMylène Josserand .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), 660a2f6d303SSamuel Holland .probe = sun8i_codec_component_probe, 6617ec9b872SKuninori Morimoto .idle_bias_on = 1, 6627ec9b872SKuninori Morimoto .use_pmdown_time = 1, 6637ec9b872SKuninori Morimoto .endianness = 1, 6647ec9b872SKuninori Morimoto .non_legacy_dai_naming = 1, 66536c68493SMylène Josserand }; 66636c68493SMylène Josserand 66736c68493SMylène Josserand static const struct regmap_config sun8i_codec_regmap_config = { 66836c68493SMylène Josserand .reg_bits = 32, 66936c68493SMylène Josserand .reg_stride = 4, 67036c68493SMylène Josserand .val_bits = 32, 67136c68493SMylène Josserand .max_register = SUN8I_DAC_MXR_SRC, 67236c68493SMylène Josserand 67336c68493SMylène Josserand .cache_type = REGCACHE_FLAT, 67436c68493SMylène Josserand }; 67536c68493SMylène Josserand 67636c68493SMylène Josserand static int sun8i_codec_probe(struct platform_device *pdev) 67736c68493SMylène Josserand { 67836c68493SMylène Josserand struct sun8i_codec *scodec; 67936c68493SMylène Josserand void __iomem *base; 68036c68493SMylène Josserand int ret; 68136c68493SMylène Josserand 68236c68493SMylène Josserand scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); 68336c68493SMylène Josserand if (!scodec) 68436c68493SMylène Josserand return -ENOMEM; 68536c68493SMylène Josserand 68636c68493SMylène Josserand scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); 68736c68493SMylène Josserand if (IS_ERR(scodec->clk_module)) { 68836c68493SMylène Josserand dev_err(&pdev->dev, "Failed to get the module clock\n"); 68936c68493SMylène Josserand return PTR_ERR(scodec->clk_module); 69036c68493SMylène Josserand } 69136c68493SMylène Josserand 692790b3657SYueHaibing base = devm_platform_ioremap_resource(pdev, 0); 69336c68493SMylène Josserand if (IS_ERR(base)) { 69436c68493SMylène Josserand dev_err(&pdev->dev, "Failed to map the registers\n"); 69536c68493SMylène Josserand return PTR_ERR(base); 69636c68493SMylène Josserand } 69736c68493SMylène Josserand 698efb736fbSSamuel Holland scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, 69936c68493SMylène Josserand &sun8i_codec_regmap_config); 70036c68493SMylène Josserand if (IS_ERR(scodec->regmap)) { 70136c68493SMylène Josserand dev_err(&pdev->dev, "Failed to create our regmap\n"); 70236c68493SMylène Josserand return PTR_ERR(scodec->regmap); 70336c68493SMylène Josserand } 70436c68493SMylène Josserand 70590cac932SSamuel Holland scodec->quirks = of_device_get_match_data(&pdev->dev); 70690cac932SSamuel Holland 70736c68493SMylène Josserand platform_set_drvdata(pdev, scodec); 70836c68493SMylène Josserand 70936c68493SMylène Josserand pm_runtime_enable(&pdev->dev); 71036c68493SMylène Josserand if (!pm_runtime_enabled(&pdev->dev)) { 71136c68493SMylène Josserand ret = sun8i_codec_runtime_resume(&pdev->dev); 71236c68493SMylène Josserand if (ret) 71336c68493SMylène Josserand goto err_pm_disable; 71436c68493SMylène Josserand } 71536c68493SMylène Josserand 7167ec9b872SKuninori Morimoto ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component, 71736c68493SMylène Josserand &sun8i_codec_dai, 1); 71836c68493SMylène Josserand if (ret) { 71936c68493SMylène Josserand dev_err(&pdev->dev, "Failed to register codec\n"); 72036c68493SMylène Josserand goto err_suspend; 72136c68493SMylène Josserand } 72236c68493SMylène Josserand 72336c68493SMylène Josserand return ret; 72436c68493SMylène Josserand 72536c68493SMylène Josserand err_suspend: 72636c68493SMylène Josserand if (!pm_runtime_status_suspended(&pdev->dev)) 72736c68493SMylène Josserand sun8i_codec_runtime_suspend(&pdev->dev); 72836c68493SMylène Josserand 72936c68493SMylène Josserand err_pm_disable: 73036c68493SMylène Josserand pm_runtime_disable(&pdev->dev); 73136c68493SMylène Josserand 73236c68493SMylène Josserand return ret; 73336c68493SMylène Josserand } 73436c68493SMylène Josserand 73536c68493SMylène Josserand static int sun8i_codec_remove(struct platform_device *pdev) 73636c68493SMylène Josserand { 73736c68493SMylène Josserand pm_runtime_disable(&pdev->dev); 73836c68493SMylène Josserand if (!pm_runtime_status_suspended(&pdev->dev)) 73936c68493SMylène Josserand sun8i_codec_runtime_suspend(&pdev->dev); 74036c68493SMylène Josserand 74136c68493SMylène Josserand return 0; 74236c68493SMylène Josserand } 74336c68493SMylène Josserand 74490cac932SSamuel Holland static const struct sun8i_codec_quirks sun8i_a33_quirks = { 74590cac932SSamuel Holland .legacy_widgets = true, 7467518805fSSamuel Holland .lrck_inversion = true, 74790cac932SSamuel Holland }; 74890cac932SSamuel Holland 74990cac932SSamuel Holland static const struct sun8i_codec_quirks sun50i_a64_quirks = { 75090cac932SSamuel Holland }; 75190cac932SSamuel Holland 75236c68493SMylène Josserand static const struct of_device_id sun8i_codec_of_match[] = { 75390cac932SSamuel Holland { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks }, 75490cac932SSamuel Holland { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks }, 75536c68493SMylène Josserand {} 75636c68493SMylène Josserand }; 75736c68493SMylène Josserand MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); 75836c68493SMylène Josserand 75936c68493SMylène Josserand static const struct dev_pm_ops sun8i_codec_pm_ops = { 76036c68493SMylène Josserand SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend, 76136c68493SMylène Josserand sun8i_codec_runtime_resume, NULL) 76236c68493SMylène Josserand }; 76336c68493SMylène Josserand 76436c68493SMylène Josserand static struct platform_driver sun8i_codec_driver = { 76536c68493SMylène Josserand .driver = { 76636c68493SMylène Josserand .name = "sun8i-codec", 76736c68493SMylène Josserand .of_match_table = sun8i_codec_of_match, 76836c68493SMylène Josserand .pm = &sun8i_codec_pm_ops, 76936c68493SMylène Josserand }, 77036c68493SMylène Josserand .probe = sun8i_codec_probe, 77136c68493SMylène Josserand .remove = sun8i_codec_remove, 77236c68493SMylène Josserand }; 77336c68493SMylène Josserand module_platform_driver(sun8i_codec_driver); 77436c68493SMylène Josserand 77536c68493SMylène Josserand MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver"); 77636c68493SMylène Josserand MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>"); 77736c68493SMylène Josserand MODULE_LICENSE("GPL"); 77836c68493SMylène Josserand MODULE_ALIAS("platform:sun8i-codec"); 779