| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * This driver supports the digital controls for the internal codec |
|---|
| 3 | 4 | * found in Allwinner's A33 SoCs. |
|---|
| .. | .. |
|---|
| 6 | 7 | * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> |
|---|
| 7 | 8 | * huangxin <huangxin@Reuuimllatech.com> |
|---|
| 8 | 9 | * Mylène Josserand <mylene.josserand@free-electrons.com> |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 12 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 16 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 18 | | - * GNU General Public License for more details. |
|---|
| 19 | 10 | */ |
|---|
| 20 | 11 | |
|---|
| 21 | 12 | #include <linux/module.h> |
|---|
| 22 | 13 | #include <linux/delay.h> |
|---|
| 23 | 14 | #include <linux/clk.h> |
|---|
| 24 | 15 | #include <linux/io.h> |
|---|
| 16 | +#include <linux/of_device.h> |
|---|
| 25 | 17 | #include <linux/pm_runtime.h> |
|---|
| 26 | 18 | #include <linux/regmap.h> |
|---|
| 19 | +#include <linux/log2.h> |
|---|
| 27 | 20 | |
|---|
| 28 | 21 | #include <sound/pcm_params.h> |
|---|
| 29 | 22 | #include <sound/soc.h> |
|---|
| .. | .. |
|---|
| 31 | 24 | |
|---|
| 32 | 25 | #define SUN8I_SYSCLK_CTL 0x00c |
|---|
| 33 | 26 | #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11 |
|---|
| 34 | | -#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9 |
|---|
| 35 | | -#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8 |
|---|
| 27 | +#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8) |
|---|
| 28 | +#define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7 |
|---|
| 29 | +#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4) |
|---|
| 36 | 30 | #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3 |
|---|
| 37 | 31 | #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0 |
|---|
| 32 | +#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0) |
|---|
| 33 | +#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0) |
|---|
| 38 | 34 | #define SUN8I_MOD_CLK_ENA 0x010 |
|---|
| 39 | 35 | #define SUN8I_MOD_CLK_ENA_AIF1 15 |
|---|
| 40 | 36 | #define SUN8I_MOD_CLK_ENA_ADC 3 |
|---|
| .. | .. |
|---|
| 52 | 48 | #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 |
|---|
| 53 | 49 | #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 |
|---|
| 54 | 50 | #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 |
|---|
| 55 | | -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6) |
|---|
| 56 | 51 | #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 |
|---|
| 57 | 52 | #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) |
|---|
| 58 | 53 | #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 |
|---|
| 59 | 54 | #define SUN8I_AIF1_ADCDAT_CTRL 0x044 |
|---|
| 60 | | -#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA 15 |
|---|
| 61 | | -#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA 14 |
|---|
| 55 | +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 |
|---|
| 56 | +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14 |
|---|
| 57 | +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10 |
|---|
| 58 | +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8 |
|---|
| 62 | 59 | #define SUN8I_AIF1_DACDAT_CTRL 0x048 |
|---|
| 63 | 60 | #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15 |
|---|
| 64 | 61 | #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14 |
|---|
| 62 | +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10 |
|---|
| 63 | +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8 |
|---|
| 65 | 64 | #define SUN8I_AIF1_MXR_SRC 0x04c |
|---|
| 66 | | -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L 15 |
|---|
| 67 | | -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL 14 |
|---|
| 68 | | -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL 13 |
|---|
| 69 | | -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR 12 |
|---|
| 65 | +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15 |
|---|
| 66 | +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14 |
|---|
| 67 | +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13 |
|---|
| 68 | +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12 |
|---|
| 70 | 69 | #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11 |
|---|
| 71 | 70 | #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 |
|---|
| 72 | 71 | #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 |
|---|
| 73 | 72 | #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 |
|---|
| 74 | 73 | #define SUN8I_ADC_DIG_CTRL 0x100 |
|---|
| 75 | | -#define SUN8I_ADC_DIG_CTRL_ENDA 15 |
|---|
| 74 | +#define SUN8I_ADC_DIG_CTRL_ENAD 15 |
|---|
| 76 | 75 | #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 |
|---|
| 77 | 76 | #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1 |
|---|
| 78 | 77 | #define SUN8I_DAC_DIG_CTRL 0x120 |
|---|
| 79 | | -#define SUN8I_DAC_DIG_CTRL_ENDA 15 |
|---|
| 78 | +#define SUN8I_DAC_DIG_CTRL_ENDA 15 |
|---|
| 80 | 79 | #define SUN8I_DAC_MXR_SRC 0x130 |
|---|
| 81 | | -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 |
|---|
| 82 | | -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 |
|---|
| 83 | | -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 |
|---|
| 80 | +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 |
|---|
| 81 | +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 |
|---|
| 82 | +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 |
|---|
| 84 | 83 | #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12 |
|---|
| 85 | | -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 |
|---|
| 86 | | -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 |
|---|
| 87 | | -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 |
|---|
| 84 | +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 |
|---|
| 85 | +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 |
|---|
| 86 | +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 |
|---|
| 88 | 87 | #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8 |
|---|
| 89 | 88 | |
|---|
| 89 | +#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8) |
|---|
| 90 | +#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4) |
|---|
| 90 | 91 | #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) |
|---|
| 91 | 92 | #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) |
|---|
| 92 | | -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) |
|---|
| 93 | | -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) |
|---|
| 94 | | -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) |
|---|
| 95 | 93 | #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) |
|---|
| 94 | +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) |
|---|
| 95 | +#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) |
|---|
| 96 | +#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) |
|---|
| 97 | + |
|---|
| 98 | +struct sun8i_codec_quirks { |
|---|
| 99 | + bool legacy_widgets : 1; |
|---|
| 100 | + bool lrck_inversion : 1; |
|---|
| 101 | +}; |
|---|
| 96 | 102 | |
|---|
| 97 | 103 | struct sun8i_codec { |
|---|
| 98 | | - struct device *dev; |
|---|
| 99 | | - struct regmap *regmap; |
|---|
| 100 | | - struct clk *clk_module; |
|---|
| 101 | | - struct clk *clk_bus; |
|---|
| 104 | + struct regmap *regmap; |
|---|
| 105 | + struct clk *clk_module; |
|---|
| 106 | + const struct sun8i_codec_quirks *quirks; |
|---|
| 102 | 107 | }; |
|---|
| 103 | 108 | |
|---|
| 104 | 109 | static int sun8i_codec_runtime_resume(struct device *dev) |
|---|
| .. | .. |
|---|
| 106 | 111 | struct sun8i_codec *scodec = dev_get_drvdata(dev); |
|---|
| 107 | 112 | int ret; |
|---|
| 108 | 113 | |
|---|
| 109 | | - ret = clk_prepare_enable(scodec->clk_module); |
|---|
| 110 | | - if (ret) { |
|---|
| 111 | | - dev_err(dev, "Failed to enable the module clock\n"); |
|---|
| 112 | | - return ret; |
|---|
| 113 | | - } |
|---|
| 114 | | - |
|---|
| 115 | | - ret = clk_prepare_enable(scodec->clk_bus); |
|---|
| 116 | | - if (ret) { |
|---|
| 117 | | - dev_err(dev, "Failed to enable the bus clock\n"); |
|---|
| 118 | | - goto err_disable_modclk; |
|---|
| 119 | | - } |
|---|
| 120 | | - |
|---|
| 121 | 114 | regcache_cache_only(scodec->regmap, false); |
|---|
| 122 | 115 | |
|---|
| 123 | 116 | ret = regcache_sync(scodec->regmap); |
|---|
| 124 | 117 | if (ret) { |
|---|
| 125 | 118 | dev_err(dev, "Failed to sync regmap cache\n"); |
|---|
| 126 | | - goto err_disable_clk; |
|---|
| 119 | + return ret; |
|---|
| 127 | 120 | } |
|---|
| 128 | 121 | |
|---|
| 129 | 122 | return 0; |
|---|
| 130 | | - |
|---|
| 131 | | -err_disable_clk: |
|---|
| 132 | | - clk_disable_unprepare(scodec->clk_bus); |
|---|
| 133 | | - |
|---|
| 134 | | -err_disable_modclk: |
|---|
| 135 | | - clk_disable_unprepare(scodec->clk_module); |
|---|
| 136 | | - |
|---|
| 137 | | - return ret; |
|---|
| 138 | 123 | } |
|---|
| 139 | 124 | |
|---|
| 140 | 125 | static int sun8i_codec_runtime_suspend(struct device *dev) |
|---|
| .. | .. |
|---|
| 143 | 128 | |
|---|
| 144 | 129 | regcache_cache_only(scodec->regmap, true); |
|---|
| 145 | 130 | regcache_mark_dirty(scodec->regmap); |
|---|
| 146 | | - |
|---|
| 147 | | - clk_disable_unprepare(scodec->clk_module); |
|---|
| 148 | | - clk_disable_unprepare(scodec->clk_bus); |
|---|
| 149 | 131 | |
|---|
| 150 | 132 | return 0; |
|---|
| 151 | 133 | } |
|---|
| .. | .. |
|---|
| 185 | 167 | |
|---|
| 186 | 168 | static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
|---|
| 187 | 169 | { |
|---|
| 188 | | - struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); |
|---|
| 170 | + struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); |
|---|
| 189 | 171 | u32 value; |
|---|
| 190 | 172 | |
|---|
| 191 | 173 | /* clock masters */ |
|---|
| .. | .. |
|---|
| 219 | 201 | value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); |
|---|
| 220 | 202 | |
|---|
| 221 | 203 | /* |
|---|
| 222 | | - * It appears that the DAI and the codec don't share the same |
|---|
| 223 | | - * polarity for the LRCK signal when they mean 'normal' and |
|---|
| 224 | | - * 'inverted' in the datasheet. |
|---|
| 204 | + * It appears that the DAI and the codec in the A33 SoC don't |
|---|
| 205 | + * share the same polarity for the LRCK signal when they mean |
|---|
| 206 | + * 'normal' and 'inverted' in the datasheet. |
|---|
| 225 | 207 | * |
|---|
| 226 | 208 | * Since the DAI here is our regular i2s driver that have been |
|---|
| 227 | 209 | * tested with way more codecs than just this one, it means |
|---|
| 228 | 210 | * that the codec probably gets it backward, and we have to |
|---|
| 229 | 211 | * invert the value here. |
|---|
| 230 | 212 | */ |
|---|
| 213 | + value ^= scodec->quirks->lrck_inversion; |
|---|
| 231 | 214 | regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, |
|---|
| 232 | 215 | BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), |
|---|
| 233 | | - !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); |
|---|
| 216 | + value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); |
|---|
| 234 | 217 | |
|---|
| 235 | 218 | /* DAI format */ |
|---|
| 236 | 219 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
|---|
| .. | .. |
|---|
| 301 | 284 | return best_val; |
|---|
| 302 | 285 | } |
|---|
| 303 | 286 | |
|---|
| 287 | +static int sun8i_codec_get_lrck_div(unsigned int channels, |
|---|
| 288 | + unsigned int word_size) |
|---|
| 289 | +{ |
|---|
| 290 | + unsigned int div = word_size * channels; |
|---|
| 291 | + |
|---|
| 292 | + if (div < 16 || div > 256) |
|---|
| 293 | + return -EINVAL; |
|---|
| 294 | + |
|---|
| 295 | + return ilog2(div) - 4; |
|---|
| 296 | +} |
|---|
| 297 | + |
|---|
| 304 | 298 | static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, |
|---|
| 305 | 299 | struct snd_pcm_hw_params *params, |
|---|
| 306 | 300 | struct snd_soc_dai *dai) |
|---|
| 307 | 301 | { |
|---|
| 308 | | - struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); |
|---|
| 309 | | - int sample_rate; |
|---|
| 302 | + struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); |
|---|
| 303 | + int sample_rate, lrck_div; |
|---|
| 310 | 304 | u8 bclk_div; |
|---|
| 311 | 305 | |
|---|
| 312 | 306 | /* |
|---|
| .. | .. |
|---|
| 322 | 316 | SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, |
|---|
| 323 | 317 | bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); |
|---|
| 324 | 318 | |
|---|
| 319 | + lrck_div = sun8i_codec_get_lrck_div(params_channels(params), |
|---|
| 320 | + params_physical_width(params)); |
|---|
| 321 | + if (lrck_div < 0) |
|---|
| 322 | + return lrck_div; |
|---|
| 323 | + |
|---|
| 325 | 324 | regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, |
|---|
| 326 | 325 | SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, |
|---|
| 327 | | - SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); |
|---|
| 326 | + lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); |
|---|
| 328 | 327 | |
|---|
| 329 | 328 | sample_rate = sun8i_codec_get_hw_rate(params); |
|---|
| 330 | 329 | if (sample_rate < 0) |
|---|
| .. | .. |
|---|
| 333 | 332 | regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, |
|---|
| 334 | 333 | SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, |
|---|
| 335 | 334 | sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); |
|---|
| 336 | | - regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, |
|---|
| 337 | | - SUN8I_SYS_SR_CTRL_AIF2_FS_MASK, |
|---|
| 338 | | - sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS); |
|---|
| 339 | 335 | |
|---|
| 340 | 336 | return 0; |
|---|
| 341 | 337 | } |
|---|
| 338 | + |
|---|
| 339 | +static const char *const sun8i_aif_stereo_mux_enum_values[] = { |
|---|
| 340 | + "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono" |
|---|
| 341 | +}; |
|---|
| 342 | + |
|---|
| 343 | +static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum, |
|---|
| 344 | + SUN8I_AIF1_ADCDAT_CTRL, |
|---|
| 345 | + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC, |
|---|
| 346 | + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC, |
|---|
| 347 | + sun8i_aif_stereo_mux_enum_values); |
|---|
| 348 | + |
|---|
| 349 | +static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control = |
|---|
| 350 | + SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route", |
|---|
| 351 | + sun8i_aif1_ad0_stereo_mux_enum); |
|---|
| 352 | + |
|---|
| 353 | +static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { |
|---|
| 354 | + SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", |
|---|
| 355 | + SUN8I_AIF1_MXR_SRC, |
|---|
| 356 | + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L, |
|---|
| 357 | + SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0), |
|---|
| 358 | + SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", |
|---|
| 359 | + SUN8I_AIF1_MXR_SRC, |
|---|
| 360 | + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL, |
|---|
| 361 | + SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0), |
|---|
| 362 | + SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch", |
|---|
| 363 | + SUN8I_AIF1_MXR_SRC, |
|---|
| 364 | + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL, |
|---|
| 365 | + SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0), |
|---|
| 366 | + SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch", |
|---|
| 367 | + SUN8I_AIF1_MXR_SRC, |
|---|
| 368 | + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR, |
|---|
| 369 | + SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), |
|---|
| 370 | +}; |
|---|
| 371 | + |
|---|
| 372 | +static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum, |
|---|
| 373 | + SUN8I_AIF1_DACDAT_CTRL, |
|---|
| 374 | + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC, |
|---|
| 375 | + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC, |
|---|
| 376 | + sun8i_aif_stereo_mux_enum_values); |
|---|
| 377 | + |
|---|
| 378 | +static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control = |
|---|
| 379 | + SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route", |
|---|
| 380 | + sun8i_aif1_da0_stereo_mux_enum); |
|---|
| 342 | 381 | |
|---|
| 343 | 382 | static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { |
|---|
| 344 | 383 | SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch", |
|---|
| .. | .. |
|---|
| 357 | 396 | SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), |
|---|
| 358 | 397 | }; |
|---|
| 359 | 398 | |
|---|
| 360 | | -static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = { |
|---|
| 361 | | - SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", |
|---|
| 362 | | - SUN8I_AIF1_MXR_SRC, |
|---|
| 363 | | - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L, |
|---|
| 364 | | - SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0), |
|---|
| 365 | | - SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, |
|---|
| 366 | | - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL, |
|---|
| 367 | | - SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0), |
|---|
| 368 | | - SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch", |
|---|
| 369 | | - SUN8I_AIF1_MXR_SRC, |
|---|
| 370 | | - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL, |
|---|
| 371 | | - SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0), |
|---|
| 372 | | - SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch", |
|---|
| 373 | | - SUN8I_AIF1_MXR_SRC, |
|---|
| 374 | | - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR, |
|---|
| 375 | | - SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), |
|---|
| 376 | | -}; |
|---|
| 377 | | - |
|---|
| 378 | 399 | static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { |
|---|
| 379 | | - /* Digital parts of the DACs and ADC */ |
|---|
| 380 | | - SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA, |
|---|
| 381 | | - 0, NULL, 0), |
|---|
| 382 | | - SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA, |
|---|
| 383 | | - 0, NULL, 0), |
|---|
| 400 | + /* System Clocks */ |
|---|
| 401 | + SND_SOC_DAPM_CLOCK_SUPPLY("mod"), |
|---|
| 384 | 402 | |
|---|
| 385 | | - /* Analog DAC AIF */ |
|---|
| 386 | | - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0, |
|---|
| 403 | + SND_SOC_DAPM_SUPPLY("AIF1CLK", |
|---|
| 404 | + SUN8I_SYSCLK_CTL, |
|---|
| 405 | + SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), |
|---|
| 406 | + SND_SOC_DAPM_SUPPLY("SYSCLK", |
|---|
| 407 | + SUN8I_SYSCLK_CTL, |
|---|
| 408 | + SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), |
|---|
| 409 | + |
|---|
| 410 | + /* Module Clocks */ |
|---|
| 411 | + SND_SOC_DAPM_SUPPLY("CLK AIF1", |
|---|
| 412 | + SUN8I_MOD_CLK_ENA, |
|---|
| 413 | + SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), |
|---|
| 414 | + SND_SOC_DAPM_SUPPLY("CLK ADC", |
|---|
| 415 | + SUN8I_MOD_CLK_ENA, |
|---|
| 416 | + SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), |
|---|
| 417 | + SND_SOC_DAPM_SUPPLY("CLK DAC", |
|---|
| 418 | + SUN8I_MOD_CLK_ENA, |
|---|
| 419 | + SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), |
|---|
| 420 | + |
|---|
| 421 | + /* Module Resets */ |
|---|
| 422 | + SND_SOC_DAPM_SUPPLY("RST AIF1", |
|---|
| 423 | + SUN8I_MOD_RST_CTL, |
|---|
| 424 | + SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), |
|---|
| 425 | + SND_SOC_DAPM_SUPPLY("RST ADC", |
|---|
| 426 | + SUN8I_MOD_RST_CTL, |
|---|
| 427 | + SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), |
|---|
| 428 | + SND_SOC_DAPM_SUPPLY("RST DAC", |
|---|
| 429 | + SUN8I_MOD_RST_CTL, |
|---|
| 430 | + SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), |
|---|
| 431 | + |
|---|
| 432 | + /* Module Supplies */ |
|---|
| 433 | + SND_SOC_DAPM_SUPPLY("ADC", |
|---|
| 434 | + SUN8I_ADC_DIG_CTRL, |
|---|
| 435 | + SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0), |
|---|
| 436 | + SND_SOC_DAPM_SUPPLY("DAC", |
|---|
| 437 | + SUN8I_DAC_DIG_CTRL, |
|---|
| 438 | + SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), |
|---|
| 439 | + |
|---|
| 440 | + /* AIF "ADC" Outputs */ |
|---|
| 441 | + SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0, |
|---|
| 442 | + SUN8I_AIF1_ADCDAT_CTRL, |
|---|
| 443 | + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), |
|---|
| 444 | + SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1, |
|---|
| 445 | + SUN8I_AIF1_ADCDAT_CTRL, |
|---|
| 446 | + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), |
|---|
| 447 | + |
|---|
| 448 | + /* AIF "ADC" Mono/Stereo Muxes */ |
|---|
| 449 | + SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0, |
|---|
| 450 | + &sun8i_aif1_ad0_stereo_mux_control), |
|---|
| 451 | + SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0, |
|---|
| 452 | + &sun8i_aif1_ad0_stereo_mux_control), |
|---|
| 453 | + |
|---|
| 454 | + /* AIF "ADC" Mixers */ |
|---|
| 455 | + SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 456 | + sun8i_aif1_ad0_mixer_controls), |
|---|
| 457 | + SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 458 | + sun8i_aif1_ad0_mixer_controls), |
|---|
| 459 | + |
|---|
| 460 | + /* AIF "DAC" Mono/Stereo Muxes */ |
|---|
| 461 | + SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0, |
|---|
| 462 | + &sun8i_aif1_da0_stereo_mux_control), |
|---|
| 463 | + SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0, |
|---|
| 464 | + &sun8i_aif1_da0_stereo_mux_control), |
|---|
| 465 | + |
|---|
| 466 | + /* AIF "DAC" Inputs */ |
|---|
| 467 | + SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0, |
|---|
| 387 | 468 | SUN8I_AIF1_DACDAT_CTRL, |
|---|
| 388 | 469 | SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), |
|---|
| 389 | | - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0, |
|---|
| 470 | + SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1, |
|---|
| 390 | 471 | SUN8I_AIF1_DACDAT_CTRL, |
|---|
| 391 | 472 | SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), |
|---|
| 392 | 473 | |
|---|
| 393 | | - /* Analog ADC AIF */ |
|---|
| 394 | | - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0, |
|---|
| 395 | | - SUN8I_AIF1_ADCDAT_CTRL, |
|---|
| 396 | | - SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0), |
|---|
| 397 | | - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0, |
|---|
| 398 | | - SUN8I_AIF1_ADCDAT_CTRL, |
|---|
| 399 | | - SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0), |
|---|
| 474 | + /* ADC Inputs (connected to analog codec DAPM context) */ |
|---|
| 475 | + SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 476 | + SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 400 | 477 | |
|---|
| 401 | | - /* DAC and ADC Mixers */ |
|---|
| 402 | | - SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 478 | + /* DAC Outputs (connected to analog codec DAPM context) */ |
|---|
| 479 | + SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 480 | + SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 481 | + |
|---|
| 482 | + /* DAC Mixers */ |
|---|
| 483 | + SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 403 | 484 | sun8i_dac_mixer_controls), |
|---|
| 404 | | - SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 485 | + SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 405 | 486 | sun8i_dac_mixer_controls), |
|---|
| 406 | | - SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 407 | | - sun8i_input_mixer_controls), |
|---|
| 408 | | - SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0, |
|---|
| 409 | | - sun8i_input_mixer_controls), |
|---|
| 410 | | - |
|---|
| 411 | | - /* Clocks */ |
|---|
| 412 | | - SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, |
|---|
| 413 | | - SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), |
|---|
| 414 | | - SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA, |
|---|
| 415 | | - SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), |
|---|
| 416 | | - SND_SOC_DAPM_SUPPLY("MODCLK ADC", SUN8I_MOD_CLK_ENA, |
|---|
| 417 | | - SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), |
|---|
| 418 | | - SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL, |
|---|
| 419 | | - SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), |
|---|
| 420 | | - SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL, |
|---|
| 421 | | - SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), |
|---|
| 422 | | - |
|---|
| 423 | | - SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL, |
|---|
| 424 | | - SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0), |
|---|
| 425 | | - /* Inversion as 0=AIF1, 1=AIF2 */ |
|---|
| 426 | | - SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL, |
|---|
| 427 | | - SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0), |
|---|
| 428 | | - |
|---|
| 429 | | - /* Module reset */ |
|---|
| 430 | | - SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL, |
|---|
| 431 | | - SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), |
|---|
| 432 | | - SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL, |
|---|
| 433 | | - SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), |
|---|
| 434 | | - SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL, |
|---|
| 435 | | - SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), |
|---|
| 436 | | - |
|---|
| 437 | | - SND_SOC_DAPM_MIC("Headset Mic", NULL), |
|---|
| 438 | | - SND_SOC_DAPM_MIC("Mic", NULL), |
|---|
| 439 | | - |
|---|
| 440 | 487 | }; |
|---|
| 441 | 488 | |
|---|
| 442 | 489 | static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { |
|---|
| 443 | 490 | /* Clock Routes */ |
|---|
| 444 | | - { "AIF1", NULL, "SYSCLK AIF1" }, |
|---|
| 445 | | - { "AIF1 PLL", NULL, "AIF1" }, |
|---|
| 446 | | - { "RST AIF1", NULL, "AIF1 PLL" }, |
|---|
| 447 | | - { "MODCLK AFI1", NULL, "RST AIF1" }, |
|---|
| 448 | | - { "DAC", NULL, "MODCLK AFI1" }, |
|---|
| 449 | | - { "ADC", NULL, "MODCLK AFI1" }, |
|---|
| 491 | + { "AIF1CLK", NULL, "mod" }, |
|---|
| 450 | 492 | |
|---|
| 451 | | - { "RST DAC", NULL, "SYSCLK" }, |
|---|
| 452 | | - { "MODCLK DAC", NULL, "RST DAC" }, |
|---|
| 453 | | - { "DAC", NULL, "MODCLK DAC" }, |
|---|
| 493 | + { "SYSCLK", NULL, "AIF1CLK" }, |
|---|
| 454 | 494 | |
|---|
| 455 | | - { "RST ADC", NULL, "SYSCLK" }, |
|---|
| 456 | | - { "MODCLK ADC", NULL, "RST ADC" }, |
|---|
| 457 | | - { "ADC", NULL, "MODCLK ADC" }, |
|---|
| 495 | + { "CLK AIF1", NULL, "AIF1CLK" }, |
|---|
| 496 | + { "CLK AIF1", NULL, "SYSCLK" }, |
|---|
| 497 | + { "RST AIF1", NULL, "CLK AIF1" }, |
|---|
| 498 | + { "AIF1 AD0L", NULL, "RST AIF1" }, |
|---|
| 499 | + { "AIF1 AD0R", NULL, "RST AIF1" }, |
|---|
| 500 | + { "AIF1 DA0L", NULL, "RST AIF1" }, |
|---|
| 501 | + { "AIF1 DA0R", NULL, "RST AIF1" }, |
|---|
| 458 | 502 | |
|---|
| 459 | | - /* DAC Routes */ |
|---|
| 460 | | - { "AIF1 Slot 0 Right", NULL, "DAC" }, |
|---|
| 461 | | - { "AIF1 Slot 0 Left", NULL, "DAC" }, |
|---|
| 503 | + { "CLK ADC", NULL, "SYSCLK" }, |
|---|
| 504 | + { "RST ADC", NULL, "CLK ADC" }, |
|---|
| 505 | + { "ADC", NULL, "RST ADC" }, |
|---|
| 506 | + { "ADCL", NULL, "ADC" }, |
|---|
| 507 | + { "ADCR", NULL, "ADC" }, |
|---|
| 508 | + |
|---|
| 509 | + { "CLK DAC", NULL, "SYSCLK" }, |
|---|
| 510 | + { "RST DAC", NULL, "CLK DAC" }, |
|---|
| 511 | + { "DAC", NULL, "RST DAC" }, |
|---|
| 512 | + { "DACL", NULL, "DAC" }, |
|---|
| 513 | + { "DACR", NULL, "DAC" }, |
|---|
| 514 | + |
|---|
| 515 | + /* AIF "ADC" Output Routes */ |
|---|
| 516 | + { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" }, |
|---|
| 517 | + { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" }, |
|---|
| 518 | + |
|---|
| 519 | + /* AIF "ADC" Mono/Stereo Mux Routes */ |
|---|
| 520 | + { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" }, |
|---|
| 521 | + { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" }, |
|---|
| 522 | + { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" }, |
|---|
| 523 | + { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" }, |
|---|
| 524 | + { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" }, |
|---|
| 525 | + { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" }, |
|---|
| 526 | + |
|---|
| 527 | + { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" }, |
|---|
| 528 | + { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" }, |
|---|
| 529 | + { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" }, |
|---|
| 530 | + { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" }, |
|---|
| 531 | + { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" }, |
|---|
| 532 | + { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" }, |
|---|
| 533 | + |
|---|
| 534 | + /* AIF "ADC" Mixer Routes */ |
|---|
| 535 | + { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" }, |
|---|
| 536 | + { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" }, |
|---|
| 537 | + |
|---|
| 538 | + { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" }, |
|---|
| 539 | + { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" }, |
|---|
| 540 | + |
|---|
| 541 | + /* AIF "DAC" Mono/Stereo Mux Routes */ |
|---|
| 542 | + { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" }, |
|---|
| 543 | + { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" }, |
|---|
| 544 | + { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" }, |
|---|
| 545 | + { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" }, |
|---|
| 546 | + { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" }, |
|---|
| 547 | + { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" }, |
|---|
| 548 | + |
|---|
| 549 | + { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" }, |
|---|
| 550 | + { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" }, |
|---|
| 551 | + { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" }, |
|---|
| 552 | + { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" }, |
|---|
| 553 | + { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" }, |
|---|
| 554 | + { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" }, |
|---|
| 555 | + |
|---|
| 556 | + /* DAC Output Routes */ |
|---|
| 557 | + { "DACL", NULL, "DACL Mixer" }, |
|---|
| 558 | + { "DACR", NULL, "DACR Mixer" }, |
|---|
| 462 | 559 | |
|---|
| 463 | 560 | /* DAC Mixer Routes */ |
|---|
| 464 | | - { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", |
|---|
| 465 | | - "AIF1 Slot 0 Left"}, |
|---|
| 466 | | - { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", |
|---|
| 467 | | - "AIF1 Slot 0 Right"}, |
|---|
| 561 | + { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" }, |
|---|
| 562 | + { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" }, |
|---|
| 468 | 563 | |
|---|
| 469 | | - /* ADC Routes */ |
|---|
| 470 | | - { "AIF1 Slot 0 Right ADC", NULL, "ADC" }, |
|---|
| 471 | | - { "AIF1 Slot 0 Left ADC", NULL, "ADC" }, |
|---|
| 472 | | - |
|---|
| 473 | | - /* ADC Mixer Routes */ |
|---|
| 474 | | - { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", |
|---|
| 475 | | - "AIF1 Slot 0 Left ADC" }, |
|---|
| 476 | | - { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", |
|---|
| 477 | | - "AIF1 Slot 0 Right ADC" }, |
|---|
| 564 | + { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" }, |
|---|
| 565 | + { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" }, |
|---|
| 478 | 566 | }; |
|---|
| 567 | + |
|---|
| 568 | +static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = { |
|---|
| 569 | + /* Legacy ADC Inputs (connected to analog codec DAPM context) */ |
|---|
| 570 | + SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 571 | + SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 572 | + |
|---|
| 573 | + /* Legacy DAC Outputs (connected to analog codec DAPM context) */ |
|---|
| 574 | + SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 575 | + SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0), |
|---|
| 576 | +}; |
|---|
| 577 | + |
|---|
| 578 | +static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = { |
|---|
| 579 | + /* Legacy ADC Routes */ |
|---|
| 580 | + { "ADCL", NULL, "AIF1 Slot 0 Left ADC" }, |
|---|
| 581 | + { "ADCR", NULL, "AIF1 Slot 0 Right ADC" }, |
|---|
| 582 | + |
|---|
| 583 | + /* Legacy DAC Routes */ |
|---|
| 584 | + { "AIF1 Slot 0 Left", NULL, "DACL" }, |
|---|
| 585 | + { "AIF1 Slot 0 Right", NULL, "DACR" }, |
|---|
| 586 | +}; |
|---|
| 587 | + |
|---|
| 588 | +static int sun8i_codec_component_probe(struct snd_soc_component *component) |
|---|
| 589 | +{ |
|---|
| 590 | + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
|---|
| 591 | + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); |
|---|
| 592 | + int ret; |
|---|
| 593 | + |
|---|
| 594 | + /* Add widgets for backward compatibility with old device trees. */ |
|---|
| 595 | + if (scodec->quirks->legacy_widgets) { |
|---|
| 596 | + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, |
|---|
| 597 | + ARRAY_SIZE(sun8i_codec_legacy_widgets)); |
|---|
| 598 | + if (ret) |
|---|
| 599 | + return ret; |
|---|
| 600 | + |
|---|
| 601 | + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes, |
|---|
| 602 | + ARRAY_SIZE(sun8i_codec_legacy_routes)); |
|---|
| 603 | + if (ret) |
|---|
| 604 | + return ret; |
|---|
| 605 | + } |
|---|
| 606 | + |
|---|
| 607 | + /* |
|---|
| 608 | + * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod") |
|---|
| 609 | + * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also |
|---|
| 610 | + * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO |
|---|
| 611 | + * directly to simplify the clock tree. |
|---|
| 612 | + */ |
|---|
| 613 | + regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, |
|---|
| 614 | + SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK | |
|---|
| 615 | + SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK, |
|---|
| 616 | + SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL | |
|---|
| 617 | + SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL); |
|---|
| 618 | + |
|---|
| 619 | + /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */ |
|---|
| 620 | + regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, |
|---|
| 621 | + BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC), |
|---|
| 622 | + SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK); |
|---|
| 623 | + |
|---|
| 624 | + return 0; |
|---|
| 625 | +} |
|---|
| 479 | 626 | |
|---|
| 480 | 627 | static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { |
|---|
| 481 | 628 | .hw_params = sun8i_codec_hw_params, |
|---|
| .. | .. |
|---|
| 510 | 657 | .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), |
|---|
| 511 | 658 | .dapm_routes = sun8i_codec_dapm_routes, |
|---|
| 512 | 659 | .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), |
|---|
| 660 | + .probe = sun8i_codec_component_probe, |
|---|
| 513 | 661 | .idle_bias_on = 1, |
|---|
| 514 | 662 | .use_pmdown_time = 1, |
|---|
| 515 | 663 | .endianness = 1, |
|---|
| .. | .. |
|---|
| 527 | 675 | |
|---|
| 528 | 676 | static int sun8i_codec_probe(struct platform_device *pdev) |
|---|
| 529 | 677 | { |
|---|
| 530 | | - struct resource *res_base; |
|---|
| 531 | 678 | struct sun8i_codec *scodec; |
|---|
| 532 | 679 | void __iomem *base; |
|---|
| 533 | 680 | int ret; |
|---|
| .. | .. |
|---|
| 536 | 683 | if (!scodec) |
|---|
| 537 | 684 | return -ENOMEM; |
|---|
| 538 | 685 | |
|---|
| 539 | | - scodec->dev = &pdev->dev; |
|---|
| 540 | | - |
|---|
| 541 | 686 | scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); |
|---|
| 542 | 687 | if (IS_ERR(scodec->clk_module)) { |
|---|
| 543 | 688 | dev_err(&pdev->dev, "Failed to get the module clock\n"); |
|---|
| 544 | 689 | return PTR_ERR(scodec->clk_module); |
|---|
| 545 | 690 | } |
|---|
| 546 | 691 | |
|---|
| 547 | | - scodec->clk_bus = devm_clk_get(&pdev->dev, "bus"); |
|---|
| 548 | | - if (IS_ERR(scodec->clk_bus)) { |
|---|
| 549 | | - dev_err(&pdev->dev, "Failed to get the bus clock\n"); |
|---|
| 550 | | - return PTR_ERR(scodec->clk_bus); |
|---|
| 551 | | - } |
|---|
| 552 | | - |
|---|
| 553 | | - res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 554 | | - base = devm_ioremap_resource(&pdev->dev, res_base); |
|---|
| 692 | + base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 555 | 693 | if (IS_ERR(base)) { |
|---|
| 556 | 694 | dev_err(&pdev->dev, "Failed to map the registers\n"); |
|---|
| 557 | 695 | return PTR_ERR(base); |
|---|
| 558 | 696 | } |
|---|
| 559 | 697 | |
|---|
| 560 | | - scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, |
|---|
| 561 | | - &sun8i_codec_regmap_config); |
|---|
| 698 | + scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, |
|---|
| 699 | + &sun8i_codec_regmap_config); |
|---|
| 562 | 700 | if (IS_ERR(scodec->regmap)) { |
|---|
| 563 | 701 | dev_err(&pdev->dev, "Failed to create our regmap\n"); |
|---|
| 564 | 702 | return PTR_ERR(scodec->regmap); |
|---|
| 565 | 703 | } |
|---|
| 704 | + |
|---|
| 705 | + scodec->quirks = of_device_get_match_data(&pdev->dev); |
|---|
| 566 | 706 | |
|---|
| 567 | 707 | platform_set_drvdata(pdev, scodec); |
|---|
| 568 | 708 | |
|---|
| .. | .. |
|---|
| 601 | 741 | return 0; |
|---|
| 602 | 742 | } |
|---|
| 603 | 743 | |
|---|
| 744 | +static const struct sun8i_codec_quirks sun8i_a33_quirks = { |
|---|
| 745 | + .legacy_widgets = true, |
|---|
| 746 | + .lrck_inversion = true, |
|---|
| 747 | +}; |
|---|
| 748 | + |
|---|
| 749 | +static const struct sun8i_codec_quirks sun50i_a64_quirks = { |
|---|
| 750 | +}; |
|---|
| 751 | + |
|---|
| 604 | 752 | static const struct of_device_id sun8i_codec_of_match[] = { |
|---|
| 605 | | - { .compatible = "allwinner,sun8i-a33-codec" }, |
|---|
| 753 | + { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks }, |
|---|
| 754 | + { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks }, |
|---|
| 606 | 755 | {} |
|---|
| 607 | 756 | }; |
|---|
| 608 | 757 | MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); |
|---|