18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2014 Emilio López <emilio@elopez.com.ar> 48c2ecf20Sopenharmony_ci * Copyright 2014 Jon Smirl <jonsmirl@gmail.com> 58c2ecf20Sopenharmony_ci * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com> 68c2ecf20Sopenharmony_ci * Copyright 2015 Adam Sampson <ats@offog.org> 78c2ecf20Sopenharmony_ci * Copyright 2016 Chen-Yu Tsai <wens@csie.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on the Allwinner SDK driver, released under the GPL. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_address.h> 208c2ecf20Sopenharmony_ci#include <linux/of_device.h> 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#include <linux/clk.h> 238c2ecf20Sopenharmony_ci#include <linux/regmap.h> 248c2ecf20Sopenharmony_ci#include <linux/reset.h> 258c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <sound/core.h> 288c2ecf20Sopenharmony_ci#include <sound/pcm.h> 298c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 308c2ecf20Sopenharmony_ci#include <sound/soc.h> 318c2ecf20Sopenharmony_ci#include <sound/tlv.h> 328c2ecf20Sopenharmony_ci#include <sound/initval.h> 338c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Codec DAC digital controls and FIFO registers */ 368c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_DPC (0x00) 378c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_DPC_EN_DA (31) 388c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_DPC_DVOL (12) 398c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC (0x04) 408c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_DAC_FS (29) 418c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION (28) 428c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT (26) 438c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE (24) 448c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT (21) 458c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL (8) 468c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_MONO_EN (6) 478c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS (5) 488c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN (4) 498c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0) 508c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_FIFOS (0x08) 518c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_TXDATA (0x0c) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Codec DAC side analog signal controls */ 548c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL (0x10) 558c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_DACAENR (31) 568c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_DACAENL (30) 578c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIXEN (29) 588c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_LNG (26) 598c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_FMG (23) 608c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MICG (20) 618c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_LLNS (19) 628c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_RLNS (18) 638c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_LFMS (17) 648c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_RFMS (16) 658c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) 668c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) 678c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) 688c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIC1LS (12) 698c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIC1RS (11) 708c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIC2LS (10) 718c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIC2RS (9) 728c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_DACPAS (8) 738c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_MIXPAS (7) 748c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_PA_MUTE (6) 758c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_ACTL_PA_VOL (0) 768c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_TUNE (0x14) 778c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_DEBUG (0x18) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Codec ADC digital controls and FIFO registers */ 808c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC (0x1c) 818c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) 828c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) 838c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24) 848c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8) 858c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_MONO_EN (7) 868c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS (6) 878c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN (4) 888c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0) 898c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_FIFOS (0x20) 908c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_RXDATA (0x24) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Codec ADC side analog signal controls */ 938c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL (0x28) 948c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31) 958c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30) 968c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_PREG1EN (29) 978c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_PREG2EN (28) 988c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_VMICEN (27) 998c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_PREG1 (25) 1008c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_PREG2 (23) 1018c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_VADCG (20) 1028c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_ADCIS (17) 1038c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_LNPREG (13) 1048c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_PA_EN (4) 1058c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_ACTL_DDE (3) 1068c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_DEBUG (0x2c) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* FIFO counters */ 1098c2ecf20Sopenharmony_ci#define SUN4I_CODEC_DAC_TXCNT (0x30) 1108c2ecf20Sopenharmony_ci#define SUN4I_CODEC_ADC_RXCNT (0x34) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* Calibration register (sun7i only) */ 1138c2ecf20Sopenharmony_ci#define SUN7I_CODEC_AC_DAC_CAL (0x38) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Microphone controls (sun7i only) */ 1168c2ecf20Sopenharmony_ci#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1 (29) 1198c2ecf20Sopenharmony_ci#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2 (26) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * sun6i specific registers 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * sun6i shares the same digital control and FIFO registers as sun4i, 1258c2ecf20Sopenharmony_ci * but only the DAC digital controls are at the same offset. The others 1268c2ecf20Sopenharmony_ci * have been moved around to accommodate extra analog controls. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Codec DAC digital controls and FIFO registers */ 1308c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_FIFOC (0x10) 1318c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28) 1328c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_FIFOS (0x14) 1338c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_RXDATA (0x18) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* Output mixer and gain controls */ 1368c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL (0x20) 1378c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31) 1388c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30) 1398c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29) 1408c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28) 1418c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23) 1428c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22) 1438c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21) 1448c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20) 1458c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19) 1468c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18) 1478c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17) 1488c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16) 1498c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15) 1508c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14) 1518c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13) 1528c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12) 1538c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11) 1548c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10) 1558c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9) 1568c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8) 1578c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7) 1588c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6) 1598c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0) 1608c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL (0x24) 1618c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31) 1628c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29) 1638c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28) 1648c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15) 1658c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12) 1668c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9) 1678c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6) 1688c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3) 1698c2ecf20Sopenharmony_ci#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Microphone, line out and phone out controls */ 1728c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL (0x28) 1738c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31) 1748c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30) 1758c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28) 1768c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25) 1778c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24) 1788c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21) 1798c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20) 1808c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19) 1818c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18) 1828c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17) 1838c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16) 1848c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11) 1858c2ecf20Sopenharmony_ci#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8) 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* ADC mixer controls */ 1888c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL (0x2c) 1898c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_ADCREN (31) 1908c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30) 1918c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_ADCRG (27) 1928c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_ADCLG (24) 1938c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13) 1948c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12) 1958c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11) 1968c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10) 1978c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9) 1988c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8) 1998c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7) 2008c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6) 2018c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5) 2028c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4) 2038c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3) 2048c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2) 2058c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1) 2068c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0) 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* Analog performance tuning controls */ 2098c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADDA_TUNE (0x30) 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* Calibration controls */ 2128c2ecf20Sopenharmony_ci#define SUN6I_CODEC_CALIBRATION (0x34) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* FIFO counters */ 2158c2ecf20Sopenharmony_ci#define SUN6I_CODEC_DAC_TXCNT (0x40) 2168c2ecf20Sopenharmony_ci#define SUN6I_CODEC_ADC_RXCNT (0x44) 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* headset jack detection and button support registers */ 2198c2ecf20Sopenharmony_ci#define SUN6I_CODEC_HMIC_CTL (0x50) 2208c2ecf20Sopenharmony_ci#define SUN6I_CODEC_HMIC_DATA (0x54) 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* TODO sun6i DAP (Digital Audio Processing) bits */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* FIFO counters moved on A23 */ 2258c2ecf20Sopenharmony_ci#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) 2268c2ecf20Sopenharmony_ci#define SUN8I_A23_CODEC_ADC_RXCNT (0x20) 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* TX FIFO moved on H3 */ 2298c2ecf20Sopenharmony_ci#define SUN8I_H3_CODEC_DAC_TXDATA (0x20) 2308c2ecf20Sopenharmony_ci#define SUN8I_H3_CODEC_DAC_DBG (0x48) 2318c2ecf20Sopenharmony_ci#define SUN8I_H3_CODEC_ADC_DBG (0x4c) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* TODO H3 DAP (Digital Audio Processing) bits */ 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistruct sun4i_codec { 2368c2ecf20Sopenharmony_ci struct device *dev; 2378c2ecf20Sopenharmony_ci struct regmap *regmap; 2388c2ecf20Sopenharmony_ci struct clk *clk_apb; 2398c2ecf20Sopenharmony_ci struct clk *clk_module; 2408c2ecf20Sopenharmony_ci struct reset_control *rst; 2418c2ecf20Sopenharmony_ci struct gpio_desc *gpio_pa; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* ADC_FIFOC register is at different offset on different SoCs */ 2448c2ecf20Sopenharmony_ci struct regmap_field *reg_adc_fifoc; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture_dma_data; 2478c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void sun4i_codec_start_playback(struct sun4i_codec *scodec) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci /* Flush TX FIFO */ 2538c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 2548c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), 2558c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Enable DAC DRQ */ 2588c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 2598c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), 2608c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void sun4i_codec_stop_playback(struct sun4i_codec *scodec) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci /* Disable DAC DRQ */ 2668c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 2678c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), 2688c2ecf20Sopenharmony_ci 0); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void sun4i_codec_start_capture(struct sun4i_codec *scodec) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci /* Enable ADC DRQ */ 2748c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 2758c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 2768c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void sun4i_codec_stop_capture(struct sun4i_codec *scodec) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci /* Disable ADC DRQ */ 2828c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 2838c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, 2878c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2908c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci switch (cmd) { 2938c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2948c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2958c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2968c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2978c2ecf20Sopenharmony_ci sun4i_codec_start_playback(scodec); 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci sun4i_codec_start_capture(scodec); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3038c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 3048c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3058c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 3068c2ecf20Sopenharmony_ci sun4i_codec_stop_playback(scodec); 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci sun4i_codec_stop_capture(scodec); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, 3198c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 3228c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Flush RX FIFO */ 3268c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 3278c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), 3288c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Set RX FIFO trigger level */ 3328c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 3338c2ecf20Sopenharmony_ci 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, 3348c2ecf20Sopenharmony_ci 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* 3378c2ecf20Sopenharmony_ci * FIXME: Undocumented in the datasheet, but 3388c2ecf20Sopenharmony_ci * Allwinner's code mentions that it is 3398c2ecf20Sopenharmony_ci * related to microphone gain 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci if (of_device_is_compatible(scodec->dev->of_node, 3428c2ecf20Sopenharmony_ci "allwinner,sun4i-a10-codec") || 3438c2ecf20Sopenharmony_ci of_device_is_compatible(scodec->dev->of_node, 3448c2ecf20Sopenharmony_ci "allwinner,sun7i-a20-codec")) { 3458c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, 3468c2ecf20Sopenharmony_ci 0x3 << 25, 3478c2ecf20Sopenharmony_ci 0x1 << 25); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (of_device_is_compatible(scodec->dev->of_node, 3518c2ecf20Sopenharmony_ci "allwinner,sun7i-a20-codec")) 3528c2ecf20Sopenharmony_ci /* FIXME: Undocumented bits */ 3538c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE, 3548c2ecf20Sopenharmony_ci 0x3 << 8, 3558c2ecf20Sopenharmony_ci 0x1 << 8); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, 3618c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 3648c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 3658c2ecf20Sopenharmony_ci u32 val; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Flush the TX FIFO */ 3688c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 3698c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), 3708c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Set TX FIFO Empty Trigger Level */ 3738c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 3748c2ecf20Sopenharmony_ci 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, 3758c2ecf20Sopenharmony_ci 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (substream->runtime->rate > 32000) 3788c2ecf20Sopenharmony_ci /* Use 64 bits FIR filter */ 3798c2ecf20Sopenharmony_ci val = 0; 3808c2ecf20Sopenharmony_ci else 3818c2ecf20Sopenharmony_ci /* Use 32 bits FIR filter */ 3828c2ecf20Sopenharmony_ci val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 3858c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), 3868c2ecf20Sopenharmony_ci val); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Send zeros when we have an underrun */ 3898c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 3908c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT), 3918c2ecf20Sopenharmony_ci 0); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci}; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int sun4i_codec_prepare(struct snd_pcm_substream *substream, 3978c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4008c2ecf20Sopenharmony_ci return sun4i_codec_prepare_playback(substream, dai); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return sun4i_codec_prepare_capture(substream, dai); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci unsigned int rate = params_rate(params); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci switch (rate) { 4108c2ecf20Sopenharmony_ci case 176400: 4118c2ecf20Sopenharmony_ci case 88200: 4128c2ecf20Sopenharmony_ci case 44100: 4138c2ecf20Sopenharmony_ci case 33075: 4148c2ecf20Sopenharmony_ci case 22050: 4158c2ecf20Sopenharmony_ci case 14700: 4168c2ecf20Sopenharmony_ci case 11025: 4178c2ecf20Sopenharmony_ci case 7350: 4188c2ecf20Sopenharmony_ci return 22579200; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci case 192000: 4218c2ecf20Sopenharmony_ci case 96000: 4228c2ecf20Sopenharmony_ci case 48000: 4238c2ecf20Sopenharmony_ci case 32000: 4248c2ecf20Sopenharmony_ci case 24000: 4258c2ecf20Sopenharmony_ci case 16000: 4268c2ecf20Sopenharmony_ci case 12000: 4278c2ecf20Sopenharmony_ci case 8000: 4288c2ecf20Sopenharmony_ci return 24576000; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci default: 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci unsigned int rate = params_rate(params); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci switch (rate) { 4408c2ecf20Sopenharmony_ci case 192000: 4418c2ecf20Sopenharmony_ci case 176400: 4428c2ecf20Sopenharmony_ci return 6; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci case 96000: 4458c2ecf20Sopenharmony_ci case 88200: 4468c2ecf20Sopenharmony_ci return 7; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci case 48000: 4498c2ecf20Sopenharmony_ci case 44100: 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci case 32000: 4538c2ecf20Sopenharmony_ci case 33075: 4548c2ecf20Sopenharmony_ci return 1; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci case 24000: 4578c2ecf20Sopenharmony_ci case 22050: 4588c2ecf20Sopenharmony_ci return 2; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case 16000: 4618c2ecf20Sopenharmony_ci case 14700: 4628c2ecf20Sopenharmony_ci return 3; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci case 12000: 4658c2ecf20Sopenharmony_ci case 11025: 4668c2ecf20Sopenharmony_ci return 4; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci case 8000: 4698c2ecf20Sopenharmony_ci case 7350: 4708c2ecf20Sopenharmony_ci return 5; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci default: 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, 4788c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 4798c2ecf20Sopenharmony_ci unsigned int hwrate) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci /* Set ADC sample rate */ 4828c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 4838c2ecf20Sopenharmony_ci 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, 4848c2ecf20Sopenharmony_ci hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Set the number of channels we want to use */ 4878c2ecf20Sopenharmony_ci if (params_channels(params) == 1) 4888c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 4898c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 4908c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); 4918c2ecf20Sopenharmony_ci else 4928c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 4938c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 4948c2ecf20Sopenharmony_ci 0); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Set the number of sample bits to either 16 or 24 bits */ 4978c2ecf20Sopenharmony_ci if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { 4988c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 4998c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS), 5008c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS)); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 5038c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), 5048c2ecf20Sopenharmony_ci 0); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 5098c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS), 5108c2ecf20Sopenharmony_ci 0); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Fill most significant bits with valid data MSB */ 5138c2ecf20Sopenharmony_ci regmap_field_update_bits(scodec->reg_adc_fifoc, 5148c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), 5158c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, 5248c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 5258c2ecf20Sopenharmony_ci unsigned int hwrate) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci u32 val; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* Set DAC sample rate */ 5308c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5318c2ecf20Sopenharmony_ci 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, 5328c2ecf20Sopenharmony_ci hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Set the number of channels we want to use */ 5358c2ecf20Sopenharmony_ci if (params_channels(params) == 1) 5368c2ecf20Sopenharmony_ci val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN); 5378c2ecf20Sopenharmony_ci else 5388c2ecf20Sopenharmony_ci val = 0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5418c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), 5428c2ecf20Sopenharmony_ci val); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Set the number of sample bits to either 16 or 24 bits */ 5458c2ecf20Sopenharmony_ci if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { 5468c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5478c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS), 5488c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Set TX FIFO mode to padding the LSBs with 0 */ 5518c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5528c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE), 5538c2ecf20Sopenharmony_ci 0); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5588c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS), 5598c2ecf20Sopenharmony_ci 0); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Set TX FIFO mode to repeat the MSB */ 5628c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 5638c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE), 5648c2ecf20Sopenharmony_ci BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int sun4i_codec_hw_params(struct snd_pcm_substream *substream, 5738c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 5748c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5778c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 5788c2ecf20Sopenharmony_ci unsigned long clk_freq; 5798c2ecf20Sopenharmony_ci int ret, hwrate; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci clk_freq = sun4i_codec_get_mod_freq(params); 5828c2ecf20Sopenharmony_ci if (!clk_freq) 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ret = clk_set_rate(scodec->clk_module, clk_freq); 5868c2ecf20Sopenharmony_ci if (ret) 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci hwrate = sun4i_codec_get_hw_rate(params); 5908c2ecf20Sopenharmony_ci if (hwrate < 0) 5918c2ecf20Sopenharmony_ci return hwrate; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 5948c2ecf20Sopenharmony_ci return sun4i_codec_hw_params_playback(scodec, params, 5958c2ecf20Sopenharmony_ci hwrate); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return sun4i_codec_hw_params_capture(scodec, params, 5988c2ecf20Sopenharmony_ci hwrate); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic unsigned int sun4i_codec_src_rates[] = { 6038c2ecf20Sopenharmony_ci 8000, 11025, 12000, 16000, 22050, 24000, 32000, 6048c2ecf20Sopenharmony_ci 44100, 48000, 96000, 192000 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic struct snd_pcm_hw_constraint_list sun4i_codec_constraints = { 6098c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(sun4i_codec_src_rates), 6108c2ecf20Sopenharmony_ci .list = sun4i_codec_src_rates, 6118c2ecf20Sopenharmony_ci}; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int sun4i_codec_startup(struct snd_pcm_substream *substream, 6158c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 6188c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 6218c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * Stop issuing DRQ when we have room for less than 16 samples 6258c2ecf20Sopenharmony_ci * in our TX FIFO 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 6288c2ecf20Sopenharmony_ci 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT, 6298c2ecf20Sopenharmony_ci 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return clk_prepare_enable(scodec->clk_module); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic void sun4i_codec_shutdown(struct snd_pcm_substream *substream, 6358c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 6388c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci clk_disable_unprepare(scodec->clk_module); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sun4i_codec_dai_ops = { 6448c2ecf20Sopenharmony_ci .startup = sun4i_codec_startup, 6458c2ecf20Sopenharmony_ci .shutdown = sun4i_codec_shutdown, 6468c2ecf20Sopenharmony_ci .trigger = sun4i_codec_trigger, 6478c2ecf20Sopenharmony_ci .hw_params = sun4i_codec_hw_params, 6488c2ecf20Sopenharmony_ci .prepare = sun4i_codec_prepare, 6498c2ecf20Sopenharmony_ci}; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver sun4i_codec_dai = { 6528c2ecf20Sopenharmony_ci .name = "Codec", 6538c2ecf20Sopenharmony_ci .ops = &sun4i_codec_dai_ops, 6548c2ecf20Sopenharmony_ci .playback = { 6558c2ecf20Sopenharmony_ci .stream_name = "Codec Playback", 6568c2ecf20Sopenharmony_ci .channels_min = 1, 6578c2ecf20Sopenharmony_ci .channels_max = 2, 6588c2ecf20Sopenharmony_ci .rate_min = 8000, 6598c2ecf20Sopenharmony_ci .rate_max = 192000, 6608c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 6618c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 6628c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 6638c2ecf20Sopenharmony_ci .sig_bits = 24, 6648c2ecf20Sopenharmony_ci }, 6658c2ecf20Sopenharmony_ci .capture = { 6668c2ecf20Sopenharmony_ci .stream_name = "Codec Capture", 6678c2ecf20Sopenharmony_ci .channels_min = 1, 6688c2ecf20Sopenharmony_ci .channels_max = 2, 6698c2ecf20Sopenharmony_ci .rate_min = 8000, 6708c2ecf20Sopenharmony_ci .rate_max = 48000, 6718c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 6728c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 6738c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 6748c2ecf20Sopenharmony_ci .sig_bits = 24, 6758c2ecf20Sopenharmony_ci }, 6768c2ecf20Sopenharmony_ci}; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/*** sun4i Codec ***/ 6798c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun4i_codec_pa_mute = 6808c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL, 6818c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); 6848c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150, 6858c2ecf20Sopenharmony_ci 0); 6868c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300, 6878c2ecf20Sopenharmony_ci 0); 6888c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150, 6898c2ecf20Sopenharmony_ci 0); 6908c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, 6918c2ecf20Sopenharmony_ci 0); 6928c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale, 6938c2ecf20Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 6948c2ecf20Sopenharmony_ci 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0)); 6958c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale, 6968c2ecf20Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 6978c2ecf20Sopenharmony_ci 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0)); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun4i_codec_controls[] = { 7008c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, 7018c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, 7028c2ecf20Sopenharmony_ci sun4i_codec_pa_volume_scale), 7038c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, 7048c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, 7058c2ecf20Sopenharmony_ci sun4i_codec_linein_loopback_gain_scale), 7068c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, 7078c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, 7088c2ecf20Sopenharmony_ci sun4i_codec_linein_preamp_gain_scale), 7098c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, 7108c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, 7118c2ecf20Sopenharmony_ci sun4i_codec_fmin_loopback_gain_scale), 7128c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, 7138c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, 7148c2ecf20Sopenharmony_ci sun4i_codec_micin_loopback_gain_scale), 7158c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL, 7168c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0, 7178c2ecf20Sopenharmony_ci sun4i_codec_micin_preamp_gain_scale), 7188c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL, 7198c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0, 7208c2ecf20Sopenharmony_ci sun4i_codec_micin_preamp_gain_scale), 7218c2ecf20Sopenharmony_ci}; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun7i_codec_controls[] = { 7248c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, 7258c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, 7268c2ecf20Sopenharmony_ci sun4i_codec_pa_volume_scale), 7278c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, 7288c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, 7298c2ecf20Sopenharmony_ci sun4i_codec_linein_loopback_gain_scale), 7308c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, 7318c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, 7328c2ecf20Sopenharmony_ci sun4i_codec_linein_preamp_gain_scale), 7338c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, 7348c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, 7358c2ecf20Sopenharmony_ci sun4i_codec_fmin_loopback_gain_scale), 7368c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, 7378c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, 7388c2ecf20Sopenharmony_ci sun4i_codec_micin_loopback_gain_scale), 7398c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, 7408c2ecf20Sopenharmony_ci SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0, 7418c2ecf20Sopenharmony_ci sun7i_codec_micin_preamp_gain_scale), 7428c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, 7438c2ecf20Sopenharmony_ci SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0, 7448c2ecf20Sopenharmony_ci sun7i_codec_micin_preamp_gain_scale), 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { 7488c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch", 7498c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 7508c2ecf20Sopenharmony_ci 1, 0), 7518c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch", 7528c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 7538c2ecf20Sopenharmony_ci 1, 0), 7548c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", 7558c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL, 7568c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), 7578c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL, 7588c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_LLNS, 7598c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0), 7608c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL, 7618c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_LFMS, 7628c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0), 7638c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL, 7648c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIC1LS, 7658c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0), 7668c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL, 7678c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIC2LS, 7688c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0), 7698c2ecf20Sopenharmony_ci}; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { 7728c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, 7738c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0), 7748c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL, 7758c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0), 7768c2ecf20Sopenharmony_ci}; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { 7798c2ecf20Sopenharmony_ci /* Digital parts of the ADCs */ 7808c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC, 7818c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_FIFOC_EN_AD, 0, 7828c2ecf20Sopenharmony_ci NULL, 0), 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Digital parts of the DACs */ 7858c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC, 7868c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_DPC_EN_DA, 0, 7878c2ecf20Sopenharmony_ci NULL, 0), 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* Analog parts of the ADCs */ 7908c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, 7918c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0), 7928c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, 7938c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0), 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* Analog parts of the DACs */ 7968c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL, 7978c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_DACAENL, 0), 7988c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL, 7998c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_DACAENR, 0), 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* Mixers */ 8028c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, 8038c2ecf20Sopenharmony_ci sun4i_codec_mixer_controls, 8048c2ecf20Sopenharmony_ci ARRAY_SIZE(sun4i_codec_mixer_controls)), 8058c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, 8068c2ecf20Sopenharmony_ci sun4i_codec_mixer_controls, 8078c2ecf20Sopenharmony_ci ARRAY_SIZE(sun4i_codec_mixer_controls)), 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Global Mixer Enable */ 8108c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, 8118c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0), 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* VMIC */ 8148c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL, 8158c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0), 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Mic Pre-Amplifiers */ 8188c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, 8198c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0), 8208c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, 8218c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0), 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* Power Amplifier */ 8248c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL, 8258c2ecf20Sopenharmony_ci SUN4I_CODEC_ADC_ACTL_PA_EN, 0, 8268c2ecf20Sopenharmony_ci sun4i_codec_pa_mixer_controls, 8278c2ecf20Sopenharmony_ci ARRAY_SIZE(sun4i_codec_pa_mixer_controls)), 8288c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, 8298c2ecf20Sopenharmony_ci &sun4i_codec_pa_mute), 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("Line Right"), 8328c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("Line Left"), 8338c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("FM Right"), 8348c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("FM Left"), 8358c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("Mic1"), 8368c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("Mic2"), 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP Right"), 8398c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP Left"), 8408c2ecf20Sopenharmony_ci}; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { 8438c2ecf20Sopenharmony_ci /* Left ADC / DAC Routes */ 8448c2ecf20Sopenharmony_ci { "Left ADC", NULL, "ADC" }, 8458c2ecf20Sopenharmony_ci { "Left DAC", NULL, "DAC" }, 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Right ADC / DAC Routes */ 8488c2ecf20Sopenharmony_ci { "Right ADC", NULL, "ADC" }, 8498c2ecf20Sopenharmony_ci { "Right DAC", NULL, "DAC" }, 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* Right Mixer Routes */ 8528c2ecf20Sopenharmony_ci { "Right Mixer", NULL, "Mixer Enable" }, 8538c2ecf20Sopenharmony_ci { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, 8548c2ecf20Sopenharmony_ci { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, 8558c2ecf20Sopenharmony_ci { "Right Mixer", "Line Playback Switch", "Line Right" }, 8568c2ecf20Sopenharmony_ci { "Right Mixer", "FM Playback Switch", "FM Right" }, 8578c2ecf20Sopenharmony_ci { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, 8588c2ecf20Sopenharmony_ci { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Left Mixer Routes */ 8618c2ecf20Sopenharmony_ci { "Left Mixer", NULL, "Mixer Enable" }, 8628c2ecf20Sopenharmony_ci { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, 8638c2ecf20Sopenharmony_ci { "Left Mixer", "Line Playback Switch", "Line Left" }, 8648c2ecf20Sopenharmony_ci { "Left Mixer", "FM Playback Switch", "FM Left" }, 8658c2ecf20Sopenharmony_ci { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, 8668c2ecf20Sopenharmony_ci { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Power Amplifier Routes */ 8698c2ecf20Sopenharmony_ci { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, 8708c2ecf20Sopenharmony_ci { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" }, 8718c2ecf20Sopenharmony_ci { "Power Amplifier", "DAC Playback Switch", "Left DAC" }, 8728c2ecf20Sopenharmony_ci { "Power Amplifier", "DAC Playback Switch", "Right DAC" }, 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Headphone Output Routes */ 8758c2ecf20Sopenharmony_ci { "Power Amplifier Mute", "Switch", "Power Amplifier" }, 8768c2ecf20Sopenharmony_ci { "HP Right", NULL, "Power Amplifier Mute" }, 8778c2ecf20Sopenharmony_ci { "HP Left", NULL, "Power Amplifier Mute" }, 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* Mic1 Routes */ 8808c2ecf20Sopenharmony_ci { "Left ADC", NULL, "MIC1 Pre-Amplifier" }, 8818c2ecf20Sopenharmony_ci { "Right ADC", NULL, "MIC1 Pre-Amplifier" }, 8828c2ecf20Sopenharmony_ci { "MIC1 Pre-Amplifier", NULL, "Mic1"}, 8838c2ecf20Sopenharmony_ci { "Mic1", NULL, "VMIC" }, 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* Mic2 Routes */ 8868c2ecf20Sopenharmony_ci { "Left ADC", NULL, "MIC2 Pre-Amplifier" }, 8878c2ecf20Sopenharmony_ci { "Right ADC", NULL, "MIC2 Pre-Amplifier" }, 8888c2ecf20Sopenharmony_ci { "MIC2 Pre-Amplifier", NULL, "Mic2"}, 8898c2ecf20Sopenharmony_ci { "Mic2", NULL, "VMIC" }, 8908c2ecf20Sopenharmony_ci}; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun4i_codec_codec = { 8938c2ecf20Sopenharmony_ci .controls = sun4i_codec_controls, 8948c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sun4i_codec_controls), 8958c2ecf20Sopenharmony_ci .dapm_widgets = sun4i_codec_codec_dapm_widgets, 8968c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), 8978c2ecf20Sopenharmony_ci .dapm_routes = sun4i_codec_codec_dapm_routes, 8988c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), 8998c2ecf20Sopenharmony_ci .idle_bias_on = 1, 9008c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 9018c2ecf20Sopenharmony_ci .endianness = 1, 9028c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 9038c2ecf20Sopenharmony_ci}; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun7i_codec_codec = { 9068c2ecf20Sopenharmony_ci .controls = sun7i_codec_controls, 9078c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sun7i_codec_controls), 9088c2ecf20Sopenharmony_ci .dapm_widgets = sun4i_codec_codec_dapm_widgets, 9098c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), 9108c2ecf20Sopenharmony_ci .dapm_routes = sun4i_codec_codec_dapm_routes, 9118c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), 9128c2ecf20Sopenharmony_ci .idle_bias_on = 1, 9138c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 9148c2ecf20Sopenharmony_ci .endianness = 1, 9158c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 9168c2ecf20Sopenharmony_ci}; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/*** sun6i Codec ***/ 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/* mixer controls */ 9218c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { 9228c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("DAC Playback Switch", 9238c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9248c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL, 9258c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0), 9268c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", 9278c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9288c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR, 9298c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0), 9308c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Line In Playback Switch", 9318c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9328c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL, 9338c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0), 9348c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic1 Playback Switch", 9358c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9368c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1, 9378c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0), 9388c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic2 Playback Switch", 9398c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9408c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2, 9418c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0), 9428c2ecf20Sopenharmony_ci}; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci/* ADC mixer controls */ 9458c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = { 9468c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mixer Capture Switch", 9478c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, 9488c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL, 9498c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0), 9508c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch", 9518c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, 9528c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR, 9538c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0), 9548c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Line In Capture Switch", 9558c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, 9568c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL, 9578c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0), 9588c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic1 Capture Switch", 9598c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, 9608c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1, 9618c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0), 9628c2ecf20Sopenharmony_ci SOC_DAPM_DOUBLE("Mic2 Capture Switch", 9638c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, 9648c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2, 9658c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0), 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/* headphone controls */ 9698c2ecf20Sopenharmony_cistatic const char * const sun6i_codec_hp_src_enum_text[] = { 9708c2ecf20Sopenharmony_ci "DAC", "Mixer", 9718c2ecf20Sopenharmony_ci}; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum, 9748c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 9758c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LHPIS, 9768c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RHPIS, 9778c2ecf20Sopenharmony_ci sun6i_codec_hp_src_enum_text); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_hp_src[] = { 9808c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Headphone Source Playback Route", 9818c2ecf20Sopenharmony_ci sun6i_codec_hp_src_enum), 9828c2ecf20Sopenharmony_ci}; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/* microphone controls */ 9858c2ecf20Sopenharmony_cistatic const char * const sun6i_codec_mic2_src_enum_text[] = { 9868c2ecf20Sopenharmony_ci "Mic2", "Mic3", 9878c2ecf20Sopenharmony_ci}; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum, 9908c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL, 9918c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MIC2SLT, 9928c2ecf20Sopenharmony_ci sun6i_codec_mic2_src_enum_text); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_mic2_src[] = { 9958c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Mic2 Amplifier Source Route", 9968c2ecf20Sopenharmony_ci sun6i_codec_mic2_src_enum), 9978c2ecf20Sopenharmony_ci}; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/* line out controls */ 10008c2ecf20Sopenharmony_cistatic const char * const sun6i_codec_lineout_src_enum_text[] = { 10018c2ecf20Sopenharmony_ci "Stereo", "Mono Differential", 10028c2ecf20Sopenharmony_ci}; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum, 10058c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL, 10068c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC, 10078c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC, 10088c2ecf20Sopenharmony_ci sun6i_codec_lineout_src_enum_text); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_lineout_src[] = { 10118c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Line Out Source Playback Route", 10128c2ecf20Sopenharmony_ci sun6i_codec_lineout_src_enum), 10138c2ecf20Sopenharmony_ci}; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci/* volume / mute controls */ 10168c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); 10178c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); 10188c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale, 10198c2ecf20Sopenharmony_ci -450, 150, 0); 10208c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale, 10218c2ecf20Sopenharmony_ci 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 10228c2ecf20Sopenharmony_ci 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), 10238c2ecf20Sopenharmony_ci); 10248c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale, 10258c2ecf20Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 10268c2ecf20Sopenharmony_ci 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), 10278c2ecf20Sopenharmony_ci); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { 10308c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, 10318c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, 10328c2ecf20Sopenharmony_ci sun6i_codec_dvol_scale), 10338c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Headphone Playback Volume", 10348c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 10358c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0, 10368c2ecf20Sopenharmony_ci sun6i_codec_hp_vol_scale), 10378c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line Out Playback Volume", 10388c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL, 10398c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0, 10408c2ecf20Sopenharmony_ci sun6i_codec_lineout_vol_scale), 10418c2ecf20Sopenharmony_ci SOC_DOUBLE("Headphone Playback Switch", 10428c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 10438c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, 10448c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), 10458c2ecf20Sopenharmony_ci SOC_DOUBLE("Line Out Playback Switch", 10468c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL, 10478c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_LINEOUTLEN, 10488c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0), 10498c2ecf20Sopenharmony_ci /* Mixer pre-gains */ 10508c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Line In Playback Volume", 10518c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, 10528c2ecf20Sopenharmony_ci 0x7, 0, sun6i_codec_out_mixer_pregain_scale), 10538c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Playback Volume", 10548c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G, 10558c2ecf20Sopenharmony_ci 0x7, 0, sun6i_codec_out_mixer_pregain_scale), 10568c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Playback Volume", 10578c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G, 10588c2ecf20Sopenharmony_ci 0x7, 0, sun6i_codec_out_mixer_pregain_scale), 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* Microphone Amp boost gains */ 10618c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL, 10628c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0, 10638c2ecf20Sopenharmony_ci sun6i_codec_mic_gain_scale), 10648c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL, 10658c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0, 10668c2ecf20Sopenharmony_ci sun6i_codec_mic_gain_scale), 10678c2ecf20Sopenharmony_ci SOC_DOUBLE_TLV("ADC Capture Volume", 10688c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG, 10698c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0, 10708c2ecf20Sopenharmony_ci sun6i_codec_out_mixer_pregain_scale), 10718c2ecf20Sopenharmony_ci}; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { 10748c2ecf20Sopenharmony_ci /* Microphone inputs */ 10758c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1"), 10768c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2"), 10778c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC3"), 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* Microphone Bias */ 10808c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL, 10818c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0), 10828c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL, 10838c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0), 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Mic input path */ 10868c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route", 10878c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src), 10888c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL, 10898c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0), 10908c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL, 10918c2ecf20Sopenharmony_ci SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0), 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Line In */ 10948c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINEIN"), 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Digital parts of the ADCs */ 10978c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, 10988c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, 10998c2ecf20Sopenharmony_ci NULL, 0), 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Analog parts of the ADCs */ 11028c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, 11038c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_ADCLEN, 0), 11048c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, 11058c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_ACTL_ADCREN, 0), 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* ADC Mixers */ 11088c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0, 11098c2ecf20Sopenharmony_ci sun6i_codec_adc_mixer_controls), 11108c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0, 11118c2ecf20Sopenharmony_ci sun6i_codec_adc_mixer_controls), 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* Digital parts of the DACs */ 11148c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, 11158c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_DPC_EN_DA, 0, 11168c2ecf20Sopenharmony_ci NULL, 0), 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Analog parts of the DACs */ 11198c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", 11208c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 11218c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0), 11228c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", 11238c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL, 11248c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0), 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Mixers */ 11278c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL, 11288c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0, 11298c2ecf20Sopenharmony_ci sun6i_codec_mixer_controls), 11308c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL, 11318c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0, 11328c2ecf20Sopenharmony_ci sun6i_codec_mixer_controls), 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Headphone output path */ 11358c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Headphone Source Playback Route", 11368c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src), 11378c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL, 11388c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0), 11398c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL, 11408c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0), 11418c2ecf20Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL, 11428c2ecf20Sopenharmony_ci SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0), 11438c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP"), 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* Line Out path */ 11468c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Line Out Source Playback Route", 11478c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src), 11488c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINEOUT"), 11498c2ecf20Sopenharmony_ci}; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { 11528c2ecf20Sopenharmony_ci /* DAC Routes */ 11538c2ecf20Sopenharmony_ci { "Left DAC", NULL, "DAC Enable" }, 11548c2ecf20Sopenharmony_ci { "Right DAC", NULL, "DAC Enable" }, 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* Microphone Routes */ 11578c2ecf20Sopenharmony_ci { "Mic1 Amplifier", NULL, "MIC1"}, 11588c2ecf20Sopenharmony_ci { "Mic2 Amplifier Source Route", "Mic2", "MIC2" }, 11598c2ecf20Sopenharmony_ci { "Mic2 Amplifier Source Route", "Mic3", "MIC3" }, 11608c2ecf20Sopenharmony_ci { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"}, 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* Left Mixer Routes */ 11638c2ecf20Sopenharmony_ci { "Left Mixer", "DAC Playback Switch", "Left DAC" }, 11648c2ecf20Sopenharmony_ci { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, 11658c2ecf20Sopenharmony_ci { "Left Mixer", "Line In Playback Switch", "LINEIN" }, 11668c2ecf20Sopenharmony_ci { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 11678c2ecf20Sopenharmony_ci { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* Right Mixer Routes */ 11708c2ecf20Sopenharmony_ci { "Right Mixer", "DAC Playback Switch", "Right DAC" }, 11718c2ecf20Sopenharmony_ci { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, 11728c2ecf20Sopenharmony_ci { "Right Mixer", "Line In Playback Switch", "LINEIN" }, 11738c2ecf20Sopenharmony_ci { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, 11748c2ecf20Sopenharmony_ci { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Left ADC Mixer Routes */ 11778c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, 11788c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, 11798c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, 11808c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 11818c2ecf20Sopenharmony_ci { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci /* Right ADC Mixer Routes */ 11848c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, 11858c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, 11868c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, 11878c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, 11888c2ecf20Sopenharmony_ci { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* Headphone Routes */ 11918c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "DAC", "Left DAC" }, 11928c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "DAC", "Right DAC" }, 11938c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, 11948c2ecf20Sopenharmony_ci { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, 11958c2ecf20Sopenharmony_ci { "Headphone Amp", NULL, "Headphone Source Playback Route" }, 11968c2ecf20Sopenharmony_ci { "HP", NULL, "Headphone Amp" }, 11978c2ecf20Sopenharmony_ci { "HPCOM", NULL, "HPCOM Protection" }, 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Line Out Routes */ 12008c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, 12018c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, 12028c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, 12038c2ecf20Sopenharmony_ci { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, 12048c2ecf20Sopenharmony_ci { "LINEOUT", NULL, "Line Out Source Playback Route" }, 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* ADC Routes */ 12078c2ecf20Sopenharmony_ci { "Left ADC", NULL, "ADC Enable" }, 12088c2ecf20Sopenharmony_ci { "Right ADC", NULL, "ADC Enable" }, 12098c2ecf20Sopenharmony_ci { "Left ADC", NULL, "Left ADC Mixer" }, 12108c2ecf20Sopenharmony_ci { "Right ADC", NULL, "Right ADC Mixer" }, 12118c2ecf20Sopenharmony_ci}; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun6i_codec_codec = { 12148c2ecf20Sopenharmony_ci .controls = sun6i_codec_codec_widgets, 12158c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets), 12168c2ecf20Sopenharmony_ci .dapm_widgets = sun6i_codec_codec_dapm_widgets, 12178c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets), 12188c2ecf20Sopenharmony_ci .dapm_routes = sun6i_codec_codec_dapm_routes, 12198c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes), 12208c2ecf20Sopenharmony_ci .idle_bias_on = 1, 12218c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 12228c2ecf20Sopenharmony_ci .endianness = 1, 12238c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 12248c2ecf20Sopenharmony_ci}; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci/* sun8i A23 codec */ 12278c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = { 12288c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, 12298c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, 12308c2ecf20Sopenharmony_ci sun6i_codec_dvol_scale), 12318c2ecf20Sopenharmony_ci}; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = { 12348c2ecf20Sopenharmony_ci /* Digital parts of the ADCs */ 12358c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, 12368c2ecf20Sopenharmony_ci SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), 12378c2ecf20Sopenharmony_ci /* Digital parts of the DACs */ 12388c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, 12398c2ecf20Sopenharmony_ci SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci}; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun8i_a23_codec_codec = { 12448c2ecf20Sopenharmony_ci .controls = sun8i_a23_codec_codec_controls, 12458c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls), 12468c2ecf20Sopenharmony_ci .dapm_widgets = sun8i_a23_codec_codec_widgets, 12478c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets), 12488c2ecf20Sopenharmony_ci .idle_bias_on = 1, 12498c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 12508c2ecf20Sopenharmony_ci .endianness = 1, 12518c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 12528c2ecf20Sopenharmony_ci}; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun4i_codec_component = { 12558c2ecf20Sopenharmony_ci .name = "sun4i-codec", 12568c2ecf20Sopenharmony_ci}; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS 12598c2ecf20Sopenharmony_ci#define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 12608c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE) 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic int sun4i_codec_dai_probe(struct snd_soc_dai *dai) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai); 12658c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data, 12688c2ecf20Sopenharmony_ci &scodec->capture_dma_data); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver dummy_cpu_dai = { 12748c2ecf20Sopenharmony_ci .name = "sun4i-codec-cpu-dai", 12758c2ecf20Sopenharmony_ci .probe = sun4i_codec_dai_probe, 12768c2ecf20Sopenharmony_ci .playback = { 12778c2ecf20Sopenharmony_ci .stream_name = "Playback", 12788c2ecf20Sopenharmony_ci .channels_min = 1, 12798c2ecf20Sopenharmony_ci .channels_max = 2, 12808c2ecf20Sopenharmony_ci .rates = SUN4I_CODEC_RATES, 12818c2ecf20Sopenharmony_ci .formats = SUN4I_CODEC_FORMATS, 12828c2ecf20Sopenharmony_ci .sig_bits = 24, 12838c2ecf20Sopenharmony_ci }, 12848c2ecf20Sopenharmony_ci .capture = { 12858c2ecf20Sopenharmony_ci .stream_name = "Capture", 12868c2ecf20Sopenharmony_ci .channels_min = 1, 12878c2ecf20Sopenharmony_ci .channels_max = 2, 12888c2ecf20Sopenharmony_ci .rates = SUN4I_CODEC_RATES, 12898c2ecf20Sopenharmony_ci .formats = SUN4I_CODEC_FORMATS, 12908c2ecf20Sopenharmony_ci .sig_bits = 24, 12918c2ecf20Sopenharmony_ci }, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, 12958c2ecf20Sopenharmony_ci int *num_links) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link), 12988c2ecf20Sopenharmony_ci GFP_KERNEL); 12998c2ecf20Sopenharmony_ci struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev, 13008c2ecf20Sopenharmony_ci 3 * sizeof(*dlc), GFP_KERNEL); 13018c2ecf20Sopenharmony_ci if (!link || !dlc) 13028c2ecf20Sopenharmony_ci return NULL; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci link->cpus = &dlc[0]; 13058c2ecf20Sopenharmony_ci link->codecs = &dlc[1]; 13068c2ecf20Sopenharmony_ci link->platforms = &dlc[2]; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci link->num_cpus = 1; 13098c2ecf20Sopenharmony_ci link->num_codecs = 1; 13108c2ecf20Sopenharmony_ci link->num_platforms = 1; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci link->name = "cdc"; 13138c2ecf20Sopenharmony_ci link->stream_name = "CDC PCM"; 13148c2ecf20Sopenharmony_ci link->codecs->dai_name = "Codec"; 13158c2ecf20Sopenharmony_ci link->cpus->dai_name = dev_name(dev); 13168c2ecf20Sopenharmony_ci link->codecs->name = dev_name(dev); 13178c2ecf20Sopenharmony_ci link->platforms->name = dev_name(dev); 13188c2ecf20Sopenharmony_ci link->dai_fmt = SND_SOC_DAIFMT_I2S; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci *num_links = 1; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return link; 13238c2ecf20Sopenharmony_ci}; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w, 13268c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(scodec->gpio_pa, 13318c2ecf20Sopenharmony_ci !!SND_SOC_DAPM_EVENT_ON(event)); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) { 13348c2ecf20Sopenharmony_ci /* 13358c2ecf20Sopenharmony_ci * Need a delay to wait for DAC to push the data. 700ms seems 13368c2ecf20Sopenharmony_ci * to be the best compromise not to feel this delay while 13378c2ecf20Sopenharmony_ci * playing a sound. 13388c2ecf20Sopenharmony_ci */ 13398c2ecf20Sopenharmony_ci msleep(700); 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci return 0; 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = { 13468c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), 13478c2ecf20Sopenharmony_ci}; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = { 13508c2ecf20Sopenharmony_ci { "Speaker", NULL, "HP Right" }, 13518c2ecf20Sopenharmony_ci { "Speaker", NULL, "HP Left" }, 13528c2ecf20Sopenharmony_ci}; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_cistatic struct snd_soc_card *sun4i_codec_create_card(struct device *dev) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci struct snd_soc_card *card; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 13598c2ecf20Sopenharmony_ci if (!card) 13608c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 13638c2ecf20Sopenharmony_ci if (!card->dai_link) 13648c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci card->dev = dev; 13678c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 13688c2ecf20Sopenharmony_ci card->name = "sun4i-codec"; 13698c2ecf20Sopenharmony_ci card->dapm_widgets = sun4i_codec_card_dapm_widgets; 13708c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets); 13718c2ecf20Sopenharmony_ci card->dapm_routes = sun4i_codec_card_dapm_routes; 13728c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return card; 13758c2ecf20Sopenharmony_ci}; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = { 13788c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone", NULL), 13798c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line In", NULL), 13808c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line Out", NULL), 13818c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 13828c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Mic", NULL), 13838c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), 13848c2ecf20Sopenharmony_ci}; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic struct snd_soc_card *sun6i_codec_create_card(struct device *dev) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct snd_soc_card *card; 13898c2ecf20Sopenharmony_ci int ret; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 13928c2ecf20Sopenharmony_ci if (!card) 13938c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 13968c2ecf20Sopenharmony_ci if (!card->dai_link) 13978c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci card->dev = dev; 14008c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 14018c2ecf20Sopenharmony_ci card->name = "A31 Audio Codec"; 14028c2ecf20Sopenharmony_ci card->dapm_widgets = sun6i_codec_card_dapm_widgets; 14038c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); 14048c2ecf20Sopenharmony_ci card->fully_routed = true; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); 14078c2ecf20Sopenharmony_ci if (ret) 14088c2ecf20Sopenharmony_ci dev_warn(dev, "failed to parse audio-routing: %d\n", ret); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci return card; 14118c2ecf20Sopenharmony_ci}; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci/* Connect digital side enables to analog side widgets */ 14148c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { 14158c2ecf20Sopenharmony_ci /* ADC Routes */ 14168c2ecf20Sopenharmony_ci { "Left ADC", NULL, "ADC Enable" }, 14178c2ecf20Sopenharmony_ci { "Right ADC", NULL, "ADC Enable" }, 14188c2ecf20Sopenharmony_ci { "Codec Capture", NULL, "Left ADC" }, 14198c2ecf20Sopenharmony_ci { "Codec Capture", NULL, "Right ADC" }, 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* DAC Routes */ 14228c2ecf20Sopenharmony_ci { "Left DAC", NULL, "DAC Enable" }, 14238c2ecf20Sopenharmony_ci { "Right DAC", NULL, "DAC Enable" }, 14248c2ecf20Sopenharmony_ci { "Left DAC", NULL, "Codec Playback" }, 14258c2ecf20Sopenharmony_ci { "Right DAC", NULL, "Codec Playback" }, 14268c2ecf20Sopenharmony_ci}; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic struct snd_soc_aux_dev aux_dev = { 14298c2ecf20Sopenharmony_ci .dlc = COMP_EMPTY(), 14308c2ecf20Sopenharmony_ci}; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistatic struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci struct snd_soc_card *card; 14358c2ecf20Sopenharmony_ci int ret; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 14388c2ecf20Sopenharmony_ci if (!card) 14398c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, 14428c2ecf20Sopenharmony_ci "allwinner,codec-analog-controls", 14438c2ecf20Sopenharmony_ci 0); 14448c2ecf20Sopenharmony_ci if (!aux_dev.dlc.of_node) { 14458c2ecf20Sopenharmony_ci dev_err(dev, "Can't find analog controls for codec.\n"); 14468c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 14508c2ecf20Sopenharmony_ci if (!card->dai_link) 14518c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci card->dev = dev; 14548c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 14558c2ecf20Sopenharmony_ci card->name = "A23 Audio Codec"; 14568c2ecf20Sopenharmony_ci card->dapm_widgets = sun6i_codec_card_dapm_widgets; 14578c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); 14588c2ecf20Sopenharmony_ci card->dapm_routes = sun8i_codec_card_routes; 14598c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); 14608c2ecf20Sopenharmony_ci card->aux_dev = &aux_dev; 14618c2ecf20Sopenharmony_ci card->num_aux_devs = 1; 14628c2ecf20Sopenharmony_ci card->fully_routed = true; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); 14658c2ecf20Sopenharmony_ci if (ret) 14668c2ecf20Sopenharmony_ci dev_warn(dev, "failed to parse audio-routing: %d\n", ret); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci return card; 14698c2ecf20Sopenharmony_ci}; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct snd_soc_card *card; 14748c2ecf20Sopenharmony_ci int ret; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 14778c2ecf20Sopenharmony_ci if (!card) 14788c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, 14818c2ecf20Sopenharmony_ci "allwinner,codec-analog-controls", 14828c2ecf20Sopenharmony_ci 0); 14838c2ecf20Sopenharmony_ci if (!aux_dev.dlc.of_node) { 14848c2ecf20Sopenharmony_ci dev_err(dev, "Can't find analog controls for codec.\n"); 14858c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 14898c2ecf20Sopenharmony_ci if (!card->dai_link) 14908c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci card->dev = dev; 14938c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 14948c2ecf20Sopenharmony_ci card->name = "H3 Audio Codec"; 14958c2ecf20Sopenharmony_ci card->dapm_widgets = sun6i_codec_card_dapm_widgets; 14968c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); 14978c2ecf20Sopenharmony_ci card->dapm_routes = sun8i_codec_card_routes; 14988c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); 14998c2ecf20Sopenharmony_ci card->aux_dev = &aux_dev; 15008c2ecf20Sopenharmony_ci card->num_aux_devs = 1; 15018c2ecf20Sopenharmony_ci card->fully_routed = true; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); 15048c2ecf20Sopenharmony_ci if (ret) 15058c2ecf20Sopenharmony_ci dev_warn(dev, "failed to parse audio-routing: %d\n", ret); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return card; 15088c2ecf20Sopenharmony_ci}; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct snd_soc_card *card; 15138c2ecf20Sopenharmony_ci int ret; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 15168c2ecf20Sopenharmony_ci if (!card) 15178c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, 15208c2ecf20Sopenharmony_ci "allwinner,codec-analog-controls", 15218c2ecf20Sopenharmony_ci 0); 15228c2ecf20Sopenharmony_ci if (!aux_dev.dlc.of_node) { 15238c2ecf20Sopenharmony_ci dev_err(dev, "Can't find analog controls for codec.\n"); 15248c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 15288c2ecf20Sopenharmony_ci if (!card->dai_link) 15298c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci card->dev = dev; 15328c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 15338c2ecf20Sopenharmony_ci card->name = "V3s Audio Codec"; 15348c2ecf20Sopenharmony_ci card->dapm_widgets = sun6i_codec_card_dapm_widgets; 15358c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); 15368c2ecf20Sopenharmony_ci card->dapm_routes = sun8i_codec_card_routes; 15378c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); 15388c2ecf20Sopenharmony_ci card->aux_dev = &aux_dev; 15398c2ecf20Sopenharmony_ci card->num_aux_devs = 1; 15408c2ecf20Sopenharmony_ci card->fully_routed = true; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); 15438c2ecf20Sopenharmony_ci if (ret) 15448c2ecf20Sopenharmony_ci dev_warn(dev, "failed to parse audio-routing: %d\n", ret); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci return card; 15478c2ecf20Sopenharmony_ci}; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_cistatic const struct regmap_config sun4i_codec_regmap_config = { 15508c2ecf20Sopenharmony_ci .reg_bits = 32, 15518c2ecf20Sopenharmony_ci .reg_stride = 4, 15528c2ecf20Sopenharmony_ci .val_bits = 32, 15538c2ecf20Sopenharmony_ci .max_register = SUN4I_CODEC_ADC_RXCNT, 15548c2ecf20Sopenharmony_ci}; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic const struct regmap_config sun6i_codec_regmap_config = { 15578c2ecf20Sopenharmony_ci .reg_bits = 32, 15588c2ecf20Sopenharmony_ci .reg_stride = 4, 15598c2ecf20Sopenharmony_ci .val_bits = 32, 15608c2ecf20Sopenharmony_ci .max_register = SUN6I_CODEC_HMIC_DATA, 15618c2ecf20Sopenharmony_ci}; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic const struct regmap_config sun7i_codec_regmap_config = { 15648c2ecf20Sopenharmony_ci .reg_bits = 32, 15658c2ecf20Sopenharmony_ci .reg_stride = 4, 15668c2ecf20Sopenharmony_ci .val_bits = 32, 15678c2ecf20Sopenharmony_ci .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, 15688c2ecf20Sopenharmony_ci}; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic const struct regmap_config sun8i_a23_codec_regmap_config = { 15718c2ecf20Sopenharmony_ci .reg_bits = 32, 15728c2ecf20Sopenharmony_ci .reg_stride = 4, 15738c2ecf20Sopenharmony_ci .val_bits = 32, 15748c2ecf20Sopenharmony_ci .max_register = SUN8I_A23_CODEC_ADC_RXCNT, 15758c2ecf20Sopenharmony_ci}; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic const struct regmap_config sun8i_h3_codec_regmap_config = { 15788c2ecf20Sopenharmony_ci .reg_bits = 32, 15798c2ecf20Sopenharmony_ci .reg_stride = 4, 15808c2ecf20Sopenharmony_ci .val_bits = 32, 15818c2ecf20Sopenharmony_ci .max_register = SUN8I_H3_CODEC_ADC_DBG, 15828c2ecf20Sopenharmony_ci}; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_cistatic const struct regmap_config sun8i_v3s_codec_regmap_config = { 15858c2ecf20Sopenharmony_ci .reg_bits = 32, 15868c2ecf20Sopenharmony_ci .reg_stride = 4, 15878c2ecf20Sopenharmony_ci .val_bits = 32, 15888c2ecf20Sopenharmony_ci .max_register = SUN8I_H3_CODEC_ADC_DBG, 15898c2ecf20Sopenharmony_ci}; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistruct sun4i_codec_quirks { 15928c2ecf20Sopenharmony_ci const struct regmap_config *regmap_config; 15938c2ecf20Sopenharmony_ci const struct snd_soc_component_driver *codec; 15948c2ecf20Sopenharmony_ci struct snd_soc_card * (*create_card)(struct device *dev); 15958c2ecf20Sopenharmony_ci struct reg_field reg_adc_fifoc; /* used for regmap_field */ 15968c2ecf20Sopenharmony_ci unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ 15978c2ecf20Sopenharmony_ci unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ 15988c2ecf20Sopenharmony_ci bool has_reset; 15998c2ecf20Sopenharmony_ci}; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun4i_codec_quirks = { 16028c2ecf20Sopenharmony_ci .regmap_config = &sun4i_codec_regmap_config, 16038c2ecf20Sopenharmony_ci .codec = &sun4i_codec_codec, 16048c2ecf20Sopenharmony_ci .create_card = sun4i_codec_create_card, 16058c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), 16068c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 16078c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, 16088c2ecf20Sopenharmony_ci}; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { 16118c2ecf20Sopenharmony_ci .regmap_config = &sun6i_codec_regmap_config, 16128c2ecf20Sopenharmony_ci .codec = &sun6i_codec_codec, 16138c2ecf20Sopenharmony_ci .create_card = sun6i_codec_create_card, 16148c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 16158c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 16168c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 16178c2ecf20Sopenharmony_ci .has_reset = true, 16188c2ecf20Sopenharmony_ci}; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun7i_codec_quirks = { 16218c2ecf20Sopenharmony_ci .regmap_config = &sun7i_codec_regmap_config, 16228c2ecf20Sopenharmony_ci .codec = &sun7i_codec_codec, 16238c2ecf20Sopenharmony_ci .create_card = sun4i_codec_create_card, 16248c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), 16258c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 16268c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, 16278c2ecf20Sopenharmony_ci}; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { 16308c2ecf20Sopenharmony_ci .regmap_config = &sun8i_a23_codec_regmap_config, 16318c2ecf20Sopenharmony_ci .codec = &sun8i_a23_codec_codec, 16328c2ecf20Sopenharmony_ci .create_card = sun8i_a23_codec_create_card, 16338c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 16348c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 16358c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 16368c2ecf20Sopenharmony_ci .has_reset = true, 16378c2ecf20Sopenharmony_ci}; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { 16408c2ecf20Sopenharmony_ci .regmap_config = &sun8i_h3_codec_regmap_config, 16418c2ecf20Sopenharmony_ci /* 16428c2ecf20Sopenharmony_ci * TODO Share the codec structure with A23 for now. 16438c2ecf20Sopenharmony_ci * This should be split out when adding digital audio 16448c2ecf20Sopenharmony_ci * processing support for the H3. 16458c2ecf20Sopenharmony_ci */ 16468c2ecf20Sopenharmony_ci .codec = &sun8i_a23_codec_codec, 16478c2ecf20Sopenharmony_ci .create_card = sun8i_h3_codec_create_card, 16488c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 16498c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, 16508c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 16518c2ecf20Sopenharmony_ci .has_reset = true, 16528c2ecf20Sopenharmony_ci}; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = { 16558c2ecf20Sopenharmony_ci .regmap_config = &sun8i_v3s_codec_regmap_config, 16568c2ecf20Sopenharmony_ci /* 16578c2ecf20Sopenharmony_ci * TODO The codec structure should be split out, like 16588c2ecf20Sopenharmony_ci * H3, when adding digital audio processing support. 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ci .codec = &sun8i_a23_codec_codec, 16618c2ecf20Sopenharmony_ci .create_card = sun8i_v3s_codec_create_card, 16628c2ecf20Sopenharmony_ci .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 16638c2ecf20Sopenharmony_ci .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, 16648c2ecf20Sopenharmony_ci .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 16658c2ecf20Sopenharmony_ci .has_reset = true, 16668c2ecf20Sopenharmony_ci}; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_cistatic const struct of_device_id sun4i_codec_of_match[] = { 16698c2ecf20Sopenharmony_ci { 16708c2ecf20Sopenharmony_ci .compatible = "allwinner,sun4i-a10-codec", 16718c2ecf20Sopenharmony_ci .data = &sun4i_codec_quirks, 16728c2ecf20Sopenharmony_ci }, 16738c2ecf20Sopenharmony_ci { 16748c2ecf20Sopenharmony_ci .compatible = "allwinner,sun6i-a31-codec", 16758c2ecf20Sopenharmony_ci .data = &sun6i_a31_codec_quirks, 16768c2ecf20Sopenharmony_ci }, 16778c2ecf20Sopenharmony_ci { 16788c2ecf20Sopenharmony_ci .compatible = "allwinner,sun7i-a20-codec", 16798c2ecf20Sopenharmony_ci .data = &sun7i_codec_quirks, 16808c2ecf20Sopenharmony_ci }, 16818c2ecf20Sopenharmony_ci { 16828c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-a23-codec", 16838c2ecf20Sopenharmony_ci .data = &sun8i_a23_codec_quirks, 16848c2ecf20Sopenharmony_ci }, 16858c2ecf20Sopenharmony_ci { 16868c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-h3-codec", 16878c2ecf20Sopenharmony_ci .data = &sun8i_h3_codec_quirks, 16888c2ecf20Sopenharmony_ci }, 16898c2ecf20Sopenharmony_ci { 16908c2ecf20Sopenharmony_ci .compatible = "allwinner,sun8i-v3s-codec", 16918c2ecf20Sopenharmony_ci .data = &sun8i_v3s_codec_quirks, 16928c2ecf20Sopenharmony_ci }, 16938c2ecf20Sopenharmony_ci {} 16948c2ecf20Sopenharmony_ci}; 16958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_codec_of_match); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic int sun4i_codec_probe(struct platform_device *pdev) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct snd_soc_card *card; 17008c2ecf20Sopenharmony_ci struct sun4i_codec *scodec; 17018c2ecf20Sopenharmony_ci const struct sun4i_codec_quirks *quirks; 17028c2ecf20Sopenharmony_ci struct resource *res; 17038c2ecf20Sopenharmony_ci void __iomem *base; 17048c2ecf20Sopenharmony_ci int ret; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); 17078c2ecf20Sopenharmony_ci if (!scodec) 17088c2ecf20Sopenharmony_ci return -ENOMEM; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci scodec->dev = &pdev->dev; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 17138c2ecf20Sopenharmony_ci base = devm_ioremap_resource(&pdev->dev, res); 17148c2ecf20Sopenharmony_ci if (IS_ERR(base)) { 17158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to map the registers\n"); 17168c2ecf20Sopenharmony_ci return PTR_ERR(base); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci quirks = of_device_get_match_data(&pdev->dev); 17208c2ecf20Sopenharmony_ci if (quirks == NULL) { 17218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); 17228c2ecf20Sopenharmony_ci return -ENODEV; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, 17268c2ecf20Sopenharmony_ci quirks->regmap_config); 17278c2ecf20Sopenharmony_ci if (IS_ERR(scodec->regmap)) { 17288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create our regmap\n"); 17298c2ecf20Sopenharmony_ci return PTR_ERR(scodec->regmap); 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* Get the clocks from the DT */ 17338c2ecf20Sopenharmony_ci scodec->clk_apb = devm_clk_get(&pdev->dev, "apb"); 17348c2ecf20Sopenharmony_ci if (IS_ERR(scodec->clk_apb)) { 17358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get the APB clock\n"); 17368c2ecf20Sopenharmony_ci return PTR_ERR(scodec->clk_apb); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci scodec->clk_module = devm_clk_get(&pdev->dev, "codec"); 17408c2ecf20Sopenharmony_ci if (IS_ERR(scodec->clk_module)) { 17418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get the module clock\n"); 17428c2ecf20Sopenharmony_ci return PTR_ERR(scodec->clk_module); 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (quirks->has_reset) { 17468c2ecf20Sopenharmony_ci scodec->rst = devm_reset_control_get_exclusive(&pdev->dev, 17478c2ecf20Sopenharmony_ci NULL); 17488c2ecf20Sopenharmony_ci if (IS_ERR(scodec->rst)) { 17498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get reset control\n"); 17508c2ecf20Sopenharmony_ci return PTR_ERR(scodec->rst); 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", 17558c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 17568c2ecf20Sopenharmony_ci if (IS_ERR(scodec->gpio_pa)) { 17578c2ecf20Sopenharmony_ci ret = PTR_ERR(scodec->gpio_pa); 17588c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 17598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret); 17608c2ecf20Sopenharmony_ci return ret; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* reg_field setup */ 17648c2ecf20Sopenharmony_ci scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, 17658c2ecf20Sopenharmony_ci scodec->regmap, 17668c2ecf20Sopenharmony_ci quirks->reg_adc_fifoc); 17678c2ecf20Sopenharmony_ci if (IS_ERR(scodec->reg_adc_fifoc)) { 17688c2ecf20Sopenharmony_ci ret = PTR_ERR(scodec->reg_adc_fifoc); 17698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", 17708c2ecf20Sopenharmony_ci ret); 17718c2ecf20Sopenharmony_ci return ret; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* Enable the bus clock */ 17758c2ecf20Sopenharmony_ci if (clk_prepare_enable(scodec->clk_apb)) { 17768c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable the APB clock\n"); 17778c2ecf20Sopenharmony_ci return -EINVAL; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci /* Deassert the reset control */ 17818c2ecf20Sopenharmony_ci if (scodec->rst) { 17828c2ecf20Sopenharmony_ci ret = reset_control_deassert(scodec->rst); 17838c2ecf20Sopenharmony_ci if (ret) { 17848c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 17858c2ecf20Sopenharmony_ci "Failed to deassert the reset control\n"); 17868c2ecf20Sopenharmony_ci goto err_clk_disable; 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* DMA configuration for TX FIFO */ 17918c2ecf20Sopenharmony_ci scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; 17928c2ecf20Sopenharmony_ci scodec->playback_dma_data.maxburst = 8; 17938c2ecf20Sopenharmony_ci scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* DMA configuration for RX FIFO */ 17968c2ecf20Sopenharmony_ci scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; 17978c2ecf20Sopenharmony_ci scodec->capture_dma_data.maxburst = 8; 17988c2ecf20Sopenharmony_ci scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, 18018c2ecf20Sopenharmony_ci &sun4i_codec_dai, 1); 18028c2ecf20Sopenharmony_ci if (ret) { 18038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register our codec\n"); 18048c2ecf20Sopenharmony_ci goto err_assert_reset; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 18088c2ecf20Sopenharmony_ci &sun4i_codec_component, 18098c2ecf20Sopenharmony_ci &dummy_cpu_dai, 1); 18108c2ecf20Sopenharmony_ci if (ret) { 18118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register our DAI\n"); 18128c2ecf20Sopenharmony_ci goto err_assert_reset; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 18168c2ecf20Sopenharmony_ci if (ret) { 18178c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register against DMAEngine\n"); 18188c2ecf20Sopenharmony_ci goto err_assert_reset; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci card = quirks->create_card(&pdev->dev); 18228c2ecf20Sopenharmony_ci if (IS_ERR(card)) { 18238c2ecf20Sopenharmony_ci ret = PTR_ERR(card); 18248c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to create our card\n"); 18258c2ecf20Sopenharmony_ci goto err_assert_reset; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(card, scodec); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci ret = snd_soc_register_card(card); 18318c2ecf20Sopenharmony_ci if (ret) { 18328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register our card\n"); 18338c2ecf20Sopenharmony_ci goto err_assert_reset; 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci return 0; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_cierr_assert_reset: 18398c2ecf20Sopenharmony_ci if (scodec->rst) 18408c2ecf20Sopenharmony_ci reset_control_assert(scodec->rst); 18418c2ecf20Sopenharmony_cierr_clk_disable: 18428c2ecf20Sopenharmony_ci clk_disable_unprepare(scodec->clk_apb); 18438c2ecf20Sopenharmony_ci return ret; 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int sun4i_codec_remove(struct platform_device *pdev) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci struct snd_soc_card *card = platform_get_drvdata(pdev); 18498c2ecf20Sopenharmony_ci struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci snd_soc_unregister_card(card); 18528c2ecf20Sopenharmony_ci if (scodec->rst) 18538c2ecf20Sopenharmony_ci reset_control_assert(scodec->rst); 18548c2ecf20Sopenharmony_ci clk_disable_unprepare(scodec->clk_apb); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci return 0; 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic struct platform_driver sun4i_codec_driver = { 18608c2ecf20Sopenharmony_ci .driver = { 18618c2ecf20Sopenharmony_ci .name = "sun4i-codec", 18628c2ecf20Sopenharmony_ci .of_match_table = sun4i_codec_of_match, 18638c2ecf20Sopenharmony_ci }, 18648c2ecf20Sopenharmony_ci .probe = sun4i_codec_probe, 18658c2ecf20Sopenharmony_ci .remove = sun4i_codec_remove, 18668c2ecf20Sopenharmony_ci}; 18678c2ecf20Sopenharmony_cimodule_platform_driver(sun4i_codec_driver); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A10 codec driver"); 18708c2ecf20Sopenharmony_ciMODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>"); 18718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); 18728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 18738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); 18748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1875