18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This driver supports the analog controls for the internal codec 48c2ecf20Sopenharmony_ci * found in Allwinner's A31s, A23, A33 and H3 SoCs. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2016 Chen-Yu Tsai <wens@csie.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_device.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <sound/soc.h> 188c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 198c2ecf20Sopenharmony_ci#include <sound/tlv.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "sun8i-adda-pr-regmap.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Codec analog control register offsets and bit fields */ 248c2ecf20Sopenharmony_ci#define SUN8I_ADDA_HP_VOLC 0x00 258c2ecf20Sopenharmony_ci#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 268c2ecf20Sopenharmony_ci#define SUN8I_ADDA_HP_VOLC_HP_VOL 0 278c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC 0x01 288c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_MIC1 6 298c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_MIC2 5 308c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_PHONE 4 318c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_PHONEN 3 328c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_LINEINL 2 338c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_DACL 1 348c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LOMIXSC_DACR 0 358c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC 0x02 368c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_MIC1 6 378c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_MIC2 5 388c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_PHONE 4 398c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_PHONEP 3 408c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_LINEINR 2 418c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_DACR 1 428c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ROMIXSC_DACL 0 438c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC 0x03 448c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7 458c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6 468c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5 478c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4 488c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3 498c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2 508c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1 518c2ecf20Sopenharmony_ci#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0 528c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEIN_GCTRL 0x04 538c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4 548c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0 558c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LINEIN_GCTRL 0x05 568c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4 578c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0 588c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MICIN_GCTRL 0x06 598c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4 608c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0 618c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL 0x07 628c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7 638c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */ 648c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5 658c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4 668c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2 678c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1 688c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0 698c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL 0x08 708c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5 718c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4 728c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3 738c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2 748c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1 758c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0 768c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09 778c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3 788c2ecf20Sopenharmony_ci#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0 798c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL 0x0a 808c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7 818c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4 828c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3 838c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2 848c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1 858c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0 868c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b 878c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7 888c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6 898c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5 908c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3 918c2ecf20Sopenharmony_ci#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0 928c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC 0x0c 938c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_MIC1 6 948c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_MIC2 5 958c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_PHONE 4 968c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_PHONEN 3 978c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_LINEINL 2 988c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1 998c2ecf20Sopenharmony_ci#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0 1008c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC 0x0d 1018c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_MIC1 6 1028c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_MIC2 5 1038c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_PHONE 4 1048c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_PHONEP 3 1058c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_LINEINR 2 1068c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_OMIXR 1 1078c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RADCMIXSC_OMIXL 0 1088c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RES 0x0e 1098c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RES_MMICBIAS_SEL 4 1108c2ecf20Sopenharmony_ci#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0 1118c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ADC_AP_EN 0x0f 1128c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7 1138c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6 1148c2ecf20Sopenharmony_ci#define SUN8I_ADDA_ADC_AP_EN_ADCG 0 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* mixer controls */ 1178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { 1188c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("DAC Playback Switch", 1198c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1208c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1218c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_DACL, 1, 0), 1228c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", 1238c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1248c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1258c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_DACR, 1, 0), 1268c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Line In Playback Switch", 1278c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1288c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1298c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0), 1308c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", 1318c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1328c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1338c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), 1348c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", 1358c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1368c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1378c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* mixer controls */ 1418c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_v3s_codec_mixer_controls[] = { 1428c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("DAC Playback Switch", 1438c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1448c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1458c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_DACL, 1, 0), 1468c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", 1478c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1488c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1498c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_DACR, 1, 0), 1508c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", 1518c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC, 1528c2ecf20Sopenharmony_ci SUN8I_ADDA_ROMIXSC, 1538c2ecf20Sopenharmony_ci SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* ADC mixer controls */ 1578c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { 1588c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mixer Capture Switch", 1598c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1608c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1618c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), 1628c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", 1638c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1648c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1658c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), 1668c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Line In Capture Switch", 1678c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1688c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1698c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0), 1708c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", 1718c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1728c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1738c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), 1748c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", 1758c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1768c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1778c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* ADC mixer controls */ 1818c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_v3s_codec_adc_mixer_controls[] = { 1828c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mixer Capture Switch", 1838c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1848c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1858c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), 1868c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", 1878c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1888c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1898c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), 1908c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", 1918c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC, 1928c2ecf20Sopenharmony_ci SUN8I_ADDA_RADCMIXSC, 1938c2ecf20Sopenharmony_ci SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* volume / mute controls */ 1978c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, 1988c2ecf20Sopenharmony_ci -450, 150, 0); 1998c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale, 2008c2ecf20Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 2018c2ecf20Sopenharmony_ci 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), 2028c2ecf20Sopenharmony_ci); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_common_controls[] = { 2058c2ecf20Sopenharmony_ci /* Mixer pre-gain */ 2068c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, 2078c2ecf20Sopenharmony_ci SUN8I_ADDA_MICIN_GCTRL_MIC1G, 2088c2ecf20Sopenharmony_ci 0x7, 0, sun8i_codec_out_mixer_pregain_scale), 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Microphone Amp boost gain */ 2118c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 2128c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0, 2138c2ecf20Sopenharmony_ci sun8i_codec_mic_gain_scale), 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* ADC */ 2168c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN, 2178c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0, 2188c2ecf20Sopenharmony_ci sun8i_codec_out_mixer_pregain_scale), 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { 2228c2ecf20Sopenharmony_ci /* ADC */ 2238c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, 2248c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), 2258c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, 2268c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* DAC */ 2298c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, 2308c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), 2318c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, 2328c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), 2338c2ecf20Sopenharmony_ci /* 2348c2ecf20Sopenharmony_ci * Due to this component and the codec belonging to separate DAPM 2358c2ecf20Sopenharmony_ci * contexts, we need to manually link the above widgets to their 2368c2ecf20Sopenharmony_ci * stream widgets at the card level. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Microphone input */ 2408c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1"), 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Mic input path */ 2438c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 2448c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_mixer_widgets[] = { 2488c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, 2498c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, 2508c2ecf20Sopenharmony_ci sun8i_codec_mixer_controls, 2518c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mixer_controls)), 2528c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, 2538c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, 2548c2ecf20Sopenharmony_ci sun8i_codec_mixer_controls, 2558c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mixer_controls)), 2568c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, 2578c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, 2588c2ecf20Sopenharmony_ci sun8i_codec_adc_mixer_controls, 2598c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), 2608c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, 2618c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, 2628c2ecf20Sopenharmony_ci sun8i_codec_adc_mixer_controls, 2638c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = { 2678c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, 2688c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, 2698c2ecf20Sopenharmony_ci sun8i_v3s_codec_mixer_controls, 2708c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)), 2718c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, 2728c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, 2738c2ecf20Sopenharmony_ci sun8i_v3s_codec_mixer_controls, 2748c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)), 2758c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, 2768c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, 2778c2ecf20Sopenharmony_ci sun8i_v3s_codec_adc_mixer_controls, 2788c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), 2798c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, 2808c2ecf20Sopenharmony_ci SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, 2818c2ecf20Sopenharmony_ci sun8i_v3s_codec_adc_mixer_controls, 2828c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), 2838c2ecf20Sopenharmony_ci}; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { 2868c2ecf20Sopenharmony_ci /* Microphone Routes */ 2878c2ecf20Sopenharmony_ci { "Mic1 Amplifier", NULL, "MIC1"}, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = { 2918c2ecf20Sopenharmony_ci /* Left Mixer Routes */ 2928c2ecf20Sopenharmony_ci { "Left Mixer", "DAC Playback Switch", "Left DAC" }, 2938c2ecf20Sopenharmony_ci { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, 2948c2ecf20Sopenharmony_ci { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Right Mixer Routes */ 2978c2ecf20Sopenharmony_ci { "Right Mixer", "DAC Playback Switch", "Right DAC" }, 2988c2ecf20Sopenharmony_ci { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, 2998c2ecf20Sopenharmony_ci { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Left ADC Mixer Routes */ 3028c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, 3038c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, 3048c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Right ADC Mixer Routes */ 3078c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, 3088c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, 3098c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* ADC Routes */ 3128c2ecf20Sopenharmony_ci { "Left ADC", NULL, "Left ADC Mixer" }, 3138c2ecf20Sopenharmony_ci { "Right ADC", NULL, "Right ADC Mixer" }, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* headphone specific controls, widgets, and routes */ 3178c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1); 3188c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = { 3198c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Headphone Playback Volume", 3208c2ecf20Sopenharmony_ci SUN8I_ADDA_HP_VOLC, 3218c2ecf20Sopenharmony_ci SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, 3228c2ecf20Sopenharmony_ci sun8i_codec_hp_vol_scale), 3238c2ecf20Sopenharmony_ci SOC_DOUBLE("Headphone Playback Switch", 3248c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC, 3258c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, 3268c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic const char * const sun8i_codec_hp_src_enum_text[] = { 3308c2ecf20Sopenharmony_ci "DAC", "Mixer", 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum, 3348c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC, 3358c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_LHPIS, 3368c2ecf20Sopenharmony_ci SUN8I_ADDA_DAC_PA_SRC_RHPIS, 3378c2ecf20Sopenharmony_ci sun8i_codec_hp_src_enum_text); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_hp_src[] = { 3408c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Headphone Source Playback Route", 3418c2ecf20Sopenharmony_ci sun8i_codec_hp_src_enum), 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w, 3458c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) { 3508c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL, 3518c2ecf20Sopenharmony_ci BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN), 3528c2ecf20Sopenharmony_ci BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN)); 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Need a delay to have the amplifier up. 700ms seems the best 3558c2ecf20Sopenharmony_ci * compromise between the time to let the amplifier up and the 3568c2ecf20Sopenharmony_ci * time not to feel this delay while playing a sound. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci msleep(700); 3598c2ecf20Sopenharmony_ci } else if (SND_SOC_DAPM_EVENT_OFF(event)) { 3608c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL, 3618c2ecf20Sopenharmony_ci BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN), 3628c2ecf20Sopenharmony_ci 0x0); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { 3698c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Headphone Source Playback Route", 3708c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), 3718c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, 3728c2ecf20Sopenharmony_ci SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0, 3738c2ecf20Sopenharmony_ci sun8i_headphone_amp_event, 3748c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), 3758c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, 3768c2ecf20Sopenharmony_ci SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), 3778c2ecf20Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL, 3788c2ecf20Sopenharmony_ci SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0), 3798c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP"), 3808c2ecf20Sopenharmony_ci}; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { 3838c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "DAC", "Left DAC" }, 3848c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "DAC", "Right DAC" }, 3858c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, 3868c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, 3878c2ecf20Sopenharmony_ci { "Headphone Amp", NULL, "Headphone Source Playback Route" }, 3888c2ecf20Sopenharmony_ci { "HPCOM", NULL, "HPCOM Protection" }, 3898c2ecf20Sopenharmony_ci { "HP", NULL, "Headphone Amp" }, 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 3958c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 3968c2ecf20Sopenharmony_ci int ret; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = snd_soc_add_component_controls(cmpnt, 3998c2ecf20Sopenharmony_ci sun8i_codec_headphone_controls, 4008c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_headphone_controls)); 4018c2ecf20Sopenharmony_ci if (ret) { 4028c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Headphone controls: %d\n", ret); 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets, 4078c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_headphone_widgets)); 4088c2ecf20Sopenharmony_ci if (ret) { 4098c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes, 4148c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_headphone_routes)); 4158c2ecf20Sopenharmony_ci if (ret) { 4168c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* mbias specific widget */ 4248c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_mbias_widgets[] = { 4258c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 4268c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, 4278c2ecf20Sopenharmony_ci 0, NULL, 0), 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 4338c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 4348c2ecf20Sopenharmony_ci int ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mbias_widgets, 4378c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mbias_widgets)); 4388c2ecf20Sopenharmony_ci if (ret) 4398c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add MBIAS DAPM widgets: %d\n", ret); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* hmic specific widget */ 4458c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { 4468c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 4478c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, 4488c2ecf20Sopenharmony_ci 0, NULL, 0), 4498c2ecf20Sopenharmony_ci}; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 4548c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 4558c2ecf20Sopenharmony_ci int ret; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets, 4588c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_hmic_widgets)); 4598c2ecf20Sopenharmony_ci if (ret) 4608c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return ret; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/* line in specific controls, widgets and rines */ 4668c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_linein_controls[] = { 4678c2ecf20Sopenharmony_ci /* Mixer pre-gain */ 4688c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, 4698c2ecf20Sopenharmony_ci SUN8I_ADDA_LINEIN_GCTRL_LINEING, 4708c2ecf20Sopenharmony_ci 0x7, 0, sun8i_codec_out_mixer_pregain_scale), 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_linein_widgets[] = { 4748c2ecf20Sopenharmony_ci /* Line input */ 4758c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINEIN"), 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_linein_routes[] = { 4798c2ecf20Sopenharmony_ci { "Left Mixer", "Line In Playback Switch", "LINEIN" }, 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci { "Right Mixer", "Line In Playback Switch", "LINEIN" }, 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, 4868c2ecf20Sopenharmony_ci}; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int sun8i_codec_add_linein(struct snd_soc_component *cmpnt) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 4918c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 4928c2ecf20Sopenharmony_ci int ret; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci ret = snd_soc_add_component_controls(cmpnt, 4958c2ecf20Sopenharmony_ci sun8i_codec_linein_controls, 4968c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_linein_controls)); 4978c2ecf20Sopenharmony_ci if (ret) { 4988c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line In controls: %d\n", ret); 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_linein_widgets, 5038c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_linein_widgets)); 5048c2ecf20Sopenharmony_ci if (ret) { 5058c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line In DAPM widgets: %d\n", ret); 5068c2ecf20Sopenharmony_ci return ret; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_linein_routes, 5108c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_linein_routes)); 5118c2ecf20Sopenharmony_ci if (ret) { 5128c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line In DAPM routes: %d\n", ret); 5138c2ecf20Sopenharmony_ci return ret; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* line out specific controls, widgets and routes */ 5218c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, 5228c2ecf20Sopenharmony_ci 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 5238c2ecf20Sopenharmony_ci 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), 5248c2ecf20Sopenharmony_ci); 5258c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { 5268c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Out Playback Volume", 5278c2ecf20Sopenharmony_ci SUN8I_ADDA_PHONE_GAIN_CTRL, 5288c2ecf20Sopenharmony_ci SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0, 5298c2ecf20Sopenharmony_ci sun8i_codec_lineout_vol_scale), 5308c2ecf20Sopenharmony_ci SOC_DOUBLE("Line Out Playback Switch", 5318c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL, 5328c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN, 5338c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), 5348c2ecf20Sopenharmony_ci}; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic const char * const sun8i_codec_lineout_src_enum_text[] = { 5378c2ecf20Sopenharmony_ci "Stereo", "Mono Differential", 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, 5418c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL, 5428c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC, 5438c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, 5448c2ecf20Sopenharmony_ci sun8i_codec_lineout_src_enum_text); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { 5478c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Line Out Source Playback Route", 5488c2ecf20Sopenharmony_ci sun8i_codec_lineout_src_enum), 5498c2ecf20Sopenharmony_ci}; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { 5528c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Line Out Source Playback Route", 5538c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), 5548c2ecf20Sopenharmony_ci /* It is unclear if this is a buffer or gate, model it as a supply */ 5558c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL, 5568c2ecf20Sopenharmony_ci SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0), 5578c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINEOUT"), 5588c2ecf20Sopenharmony_ci}; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { 5618c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, 5628c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, 5638c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, 5648c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, 5658c2ecf20Sopenharmony_ci { "LINEOUT", NULL, "Line Out Source Playback Route" }, 5668c2ecf20Sopenharmony_ci { "LINEOUT", NULL, "Line Out Enable", }, 5678c2ecf20Sopenharmony_ci}; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 5728c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 5738c2ecf20Sopenharmony_ci int ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci ret = snd_soc_add_component_controls(cmpnt, 5768c2ecf20Sopenharmony_ci sun8i_codec_lineout_controls, 5778c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_lineout_controls)); 5788c2ecf20Sopenharmony_ci if (ret) { 5798c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line Out controls: %d\n", ret); 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets, 5848c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_lineout_widgets)); 5858c2ecf20Sopenharmony_ci if (ret) { 5868c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes, 5918c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_lineout_routes)); 5928c2ecf20Sopenharmony_ci if (ret) { 5938c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); 5948c2ecf20Sopenharmony_ci return ret; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci/* mic2 specific controls, widgets and routes */ 6018c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_codec_mic2_controls[] = { 6028c2ecf20Sopenharmony_ci /* Mixer pre-gain */ 6038c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Playback Volume", 6048c2ecf20Sopenharmony_ci SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, 6058c2ecf20Sopenharmony_ci 0x7, 0, sun8i_codec_out_mixer_pregain_scale), 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Microphone Amp boost gain */ 6088c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, 6098c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, 6108c2ecf20Sopenharmony_ci sun8i_codec_mic_gain_scale), 6118c2ecf20Sopenharmony_ci}; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_codec_mic2_widgets[] = { 6148c2ecf20Sopenharmony_ci /* Microphone input */ 6158c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2"), 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Mic input path */ 6188c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, 6198c2ecf20Sopenharmony_ci SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), 6208c2ecf20Sopenharmony_ci}; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_mic2_routes[] = { 6238c2ecf20Sopenharmony_ci { "Mic2 Amplifier", NULL, "MIC2"}, 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 6378c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 6388c2ecf20Sopenharmony_ci int ret; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = snd_soc_add_component_controls(cmpnt, 6418c2ecf20Sopenharmony_ci sun8i_codec_mic2_controls, 6428c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mic2_controls)); 6438c2ecf20Sopenharmony_ci if (ret) { 6448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add MIC2 controls: %d\n", ret); 6458c2ecf20Sopenharmony_ci return ret; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mic2_widgets, 6498c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mic2_widgets)); 6508c2ecf20Sopenharmony_ci if (ret) { 6518c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add MIC2 DAPM widgets: %d\n", ret); 6528c2ecf20Sopenharmony_ci return ret; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mic2_routes, 6568c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mic2_routes)); 6578c2ecf20Sopenharmony_ci if (ret) { 6588c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add MIC2 DAPM routes: %d\n", ret); 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistruct sun8i_codec_analog_quirks { 6668c2ecf20Sopenharmony_ci bool has_headphone; 6678c2ecf20Sopenharmony_ci bool has_hmic; 6688c2ecf20Sopenharmony_ci bool has_linein; 6698c2ecf20Sopenharmony_ci bool has_lineout; 6708c2ecf20Sopenharmony_ci bool has_mbias; 6718c2ecf20Sopenharmony_ci bool has_mic2; 6728c2ecf20Sopenharmony_ci}; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { 6758c2ecf20Sopenharmony_ci .has_headphone = true, 6768c2ecf20Sopenharmony_ci .has_hmic = true, 6778c2ecf20Sopenharmony_ci .has_linein = true, 6788c2ecf20Sopenharmony_ci .has_mbias = true, 6798c2ecf20Sopenharmony_ci .has_mic2 = true, 6808c2ecf20Sopenharmony_ci}; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { 6838c2ecf20Sopenharmony_ci .has_linein = true, 6848c2ecf20Sopenharmony_ci .has_lineout = true, 6858c2ecf20Sopenharmony_ci .has_mbias = true, 6868c2ecf20Sopenharmony_ci .has_mic2 = true, 6878c2ecf20Sopenharmony_ci}; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, 6908c2ecf20Sopenharmony_ci const struct sun8i_codec_analog_quirks *quirks) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); 6938c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 6948c2ecf20Sopenharmony_ci int ret; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!quirks->has_mic2 && !quirks->has_linein) { 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * Apply the special widget set which has uses a control 6998c2ecf20Sopenharmony_ci * without MIC2 and Line In, for SoCs without these. 7008c2ecf20Sopenharmony_ci * TODO: not all special cases are supported now, this case 7018c2ecf20Sopenharmony_ci * is present because it's the case of V3s. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, 7048c2ecf20Sopenharmony_ci sun8i_v3s_codec_mixer_widgets, 7058c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_v3s_codec_mixer_widgets)); 7068c2ecf20Sopenharmony_ci if (ret) { 7078c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add V3s Mixer DAPM widgets: %d\n", ret); 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci } else { 7118c2ecf20Sopenharmony_ci /* Apply the generic mixer widget set. */ 7128c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, 7138c2ecf20Sopenharmony_ci sun8i_codec_mixer_widgets, 7148c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mixer_widgets)); 7158c2ecf20Sopenharmony_ci if (ret) { 7168c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Mixer DAPM widgets: %d\n", ret); 7178c2ecf20Sopenharmony_ci return ret; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mixer_routes, 7228c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_codec_mixer_routes)); 7238c2ecf20Sopenharmony_ci if (ret) { 7248c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add Mixer DAPM routes: %d\n", ret); 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { 7328c2ecf20Sopenharmony_ci .has_headphone = true, 7338c2ecf20Sopenharmony_ci .has_hmic = true, 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct device *dev = cmpnt->dev; 7398c2ecf20Sopenharmony_ci const struct sun8i_codec_analog_quirks *quirks; 7408c2ecf20Sopenharmony_ci int ret; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* 7438c2ecf20Sopenharmony_ci * This would never return NULL unless someone directly registers a 7448c2ecf20Sopenharmony_ci * platform device matching this driver's name, without specifying a 7458c2ecf20Sopenharmony_ci * device tree node. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci quirks = of_device_get_match_data(dev); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Add controls, widgets, and routes for individual features */ 7508c2ecf20Sopenharmony_ci ret = sun8i_codec_analog_add_mixer(cmpnt, quirks); 7518c2ecf20Sopenharmony_ci if (ret) 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (quirks->has_headphone) { 7558c2ecf20Sopenharmony_ci ret = sun8i_codec_add_headphone(cmpnt); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci return ret; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (quirks->has_hmic) { 7618c2ecf20Sopenharmony_ci ret = sun8i_codec_add_hmic(cmpnt); 7628c2ecf20Sopenharmony_ci if (ret) 7638c2ecf20Sopenharmony_ci return ret; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (quirks->has_linein) { 7678c2ecf20Sopenharmony_ci ret = sun8i_codec_add_linein(cmpnt); 7688c2ecf20Sopenharmony_ci if (ret) 7698c2ecf20Sopenharmony_ci return ret; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (quirks->has_lineout) { 7738c2ecf20Sopenharmony_ci ret = sun8i_codec_add_lineout(cmpnt); 7748c2ecf20Sopenharmony_ci if (ret) 7758c2ecf20Sopenharmony_ci return ret; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (quirks->has_mbias) { 7798c2ecf20Sopenharmony_ci ret = sun8i_codec_add_mbias(cmpnt); 7808c2ecf20Sopenharmony_ci if (ret) 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (quirks->has_mic2) { 7858c2ecf20Sopenharmony_ci ret = sun8i_codec_add_mic2(cmpnt); 7868c2ecf20Sopenharmony_ci if (ret) 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { 7948c2ecf20Sopenharmony_ci .controls = sun8i_codec_common_controls, 7958c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sun8i_codec_common_controls), 7968c2ecf20Sopenharmony_ci .dapm_widgets = sun8i_codec_common_widgets, 7978c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets), 7988c2ecf20Sopenharmony_ci .dapm_routes = sun8i_codec_common_routes, 7998c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes), 8008c2ecf20Sopenharmony_ci .probe = sun8i_codec_analog_cmpnt_probe, 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic const struct of_device_id sun8i_codec_analog_of_match[] = { 8048c2ecf20Sopenharmony_ci { 8058c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-a23-codec-analog", 8068c2ecf20Sopenharmony_ci .data = &sun8i_a23_quirks, 8078c2ecf20Sopenharmony_ci }, 8088c2ecf20Sopenharmony_ci { 8098c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-h3-codec-analog", 8108c2ecf20Sopenharmony_ci .data = &sun8i_h3_quirks, 8118c2ecf20Sopenharmony_ci }, 8128c2ecf20Sopenharmony_ci { 8138c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-v3s-codec-analog", 8148c2ecf20Sopenharmony_ci .data = &sun8i_v3s_quirks, 8158c2ecf20Sopenharmony_ci }, 8168c2ecf20Sopenharmony_ci {} 8178c2ecf20Sopenharmony_ci}; 8188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int sun8i_codec_analog_probe(struct platform_device *pdev) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct regmap *regmap; 8238c2ecf20Sopenharmony_ci void __iomem *base; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 8268c2ecf20Sopenharmony_ci if (IS_ERR(base)) { 8278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to map the registers\n"); 8288c2ecf20Sopenharmony_ci return PTR_ERR(base); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); 8328c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 8338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create regmap\n"); 8348c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(&pdev->dev, 8388c2ecf20Sopenharmony_ci &sun8i_codec_analog_cmpnt_drv, 8398c2ecf20Sopenharmony_ci NULL, 0); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic struct platform_driver sun8i_codec_analog_driver = { 8438c2ecf20Sopenharmony_ci .driver = { 8448c2ecf20Sopenharmony_ci .name = "sun8i-codec-analog", 8458c2ecf20Sopenharmony_ci .of_match_table = sun8i_codec_analog_of_match, 8468c2ecf20Sopenharmony_ci }, 8478c2ecf20Sopenharmony_ci .probe = sun8i_codec_analog_probe, 8488c2ecf20Sopenharmony_ci}; 8498c2ecf20Sopenharmony_cimodule_platform_driver(sun8i_codec_analog_driver); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner internal codec analog controls driver"); 8528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); 8538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8548c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sun8i-codec-analog"); 855