1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2014 Emilio López <emilio@elopez.com.ar>
4*4882a593Smuzhiyun * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
5*4882a593Smuzhiyun * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
6*4882a593Smuzhiyun * Copyright 2015 Adam Sampson <ats@offog.org>
7*4882a593Smuzhiyun * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Based on the Allwinner SDK driver, released under the GPL.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun #include <linux/of_address.h>
20*4882a593Smuzhiyun #include <linux/of_device.h>
21*4882a593Smuzhiyun #include <linux/of_platform.h>
22*4882a593Smuzhiyun #include <linux/clk.h>
23*4882a593Smuzhiyun #include <linux/regmap.h>
24*4882a593Smuzhiyun #include <linux/reset.h>
25*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <sound/core.h>
28*4882a593Smuzhiyun #include <sound/pcm.h>
29*4882a593Smuzhiyun #include <sound/pcm_params.h>
30*4882a593Smuzhiyun #include <sound/soc.h>
31*4882a593Smuzhiyun #include <sound/tlv.h>
32*4882a593Smuzhiyun #include <sound/initval.h>
33*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Codec DAC digital controls and FIFO registers */
36*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_DPC (0x00)
37*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_DPC_EN_DA (31)
38*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_DPC_DVOL (12)
39*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC (0x04)
40*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_DAC_FS (29)
41*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION (28)
42*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT (26)
43*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE (24)
44*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT (21)
45*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL (8)
46*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_MONO_EN (6)
47*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS (5)
48*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN (4)
49*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0)
50*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_FIFOS (0x08)
51*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_TXDATA (0x0c)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Codec DAC side analog signal controls */
54*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL (0x10)
55*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_DACAENR (31)
56*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_DACAENL (30)
57*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIXEN (29)
58*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_LNG (26)
59*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_FMG (23)
60*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MICG (20)
61*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_LLNS (19)
62*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_RLNS (18)
63*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_LFMS (17)
64*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_RFMS (16)
65*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15)
66*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14)
67*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13)
68*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIC1LS (12)
69*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIC1RS (11)
70*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIC2LS (10)
71*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIC2RS (9)
72*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_DACPAS (8)
73*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_MIXPAS (7)
74*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_PA_MUTE (6)
75*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_ACTL_PA_VOL (0)
76*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_TUNE (0x14)
77*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_DEBUG (0x18)
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* Codec ADC digital controls and FIFO registers */
80*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC (0x1c)
81*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
82*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
83*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24)
84*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8)
85*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_MONO_EN (7)
86*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS (6)
87*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN (4)
88*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0)
89*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_FIFOS (0x20)
90*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_RXDATA (0x24)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* Codec ADC side analog signal controls */
93*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL (0x28)
94*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31)
95*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30)
96*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_PREG1EN (29)
97*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_PREG2EN (28)
98*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_VMICEN (27)
99*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_PREG1 (25)
100*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_PREG2 (23)
101*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_VADCG (20)
102*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_ADCIS (17)
103*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_LNPREG (13)
104*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_PA_EN (4)
105*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_ACTL_DDE (3)
106*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_DEBUG (0x2c)
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* FIFO counters */
109*4882a593Smuzhiyun #define SUN4I_CODEC_DAC_TXCNT (0x30)
110*4882a593Smuzhiyun #define SUN4I_CODEC_ADC_RXCNT (0x34)
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Calibration register (sun7i only) */
113*4882a593Smuzhiyun #define SUN7I_CODEC_AC_DAC_CAL (0x38)
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* Microphone controls (sun7i only) */
116*4882a593Smuzhiyun #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1 (29)
119*4882a593Smuzhiyun #define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2 (26)
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * sun6i specific registers
123*4882a593Smuzhiyun *
124*4882a593Smuzhiyun * sun6i shares the same digital control and FIFO registers as sun4i,
125*4882a593Smuzhiyun * but only the DAC digital controls are at the same offset. The others
126*4882a593Smuzhiyun * have been moved around to accommodate extra analog controls.
127*4882a593Smuzhiyun */
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* Codec DAC digital controls and FIFO registers */
130*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_FIFOC (0x10)
131*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_FIFOC_EN_AD (28)
132*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_FIFOS (0x14)
133*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_RXDATA (0x18)
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* Output mixer and gain controls */
136*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL (0x20)
137*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31)
138*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30)
139*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29)
140*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28)
141*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23)
142*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22)
143*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21)
144*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20)
145*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19)
146*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18)
147*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17)
148*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16)
149*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15)
150*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14)
151*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13)
152*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12)
153*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11)
154*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10)
155*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9)
156*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8)
157*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7)
158*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6)
159*4882a593Smuzhiyun #define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0)
160*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL (0x24)
161*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31)
162*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29)
163*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28)
164*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15)
165*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12)
166*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_LINEING (9)
167*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6)
168*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3)
169*4882a593Smuzhiyun #define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0)
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Microphone, line out and phone out controls */
172*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL (0x28)
173*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_HBIASEN (31)
174*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MBIASEN (30)
175*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28)
176*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25)
177*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24)
178*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21)
179*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20)
180*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19)
181*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18)
182*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17)
183*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16)
184*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11)
185*4882a593Smuzhiyun #define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8)
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* ADC mixer controls */
188*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL (0x2c)
189*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_ADCREN (31)
190*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_ADCLEN (30)
191*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_ADCRG (27)
192*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_ADCLG (24)
193*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13)
194*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12)
195*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11)
196*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10)
197*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9)
198*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8)
199*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7)
200*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6)
201*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5)
202*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4)
203*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3)
204*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2)
205*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1)
206*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0)
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* Analog performance tuning controls */
209*4882a593Smuzhiyun #define SUN6I_CODEC_ADDA_TUNE (0x30)
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* Calibration controls */
212*4882a593Smuzhiyun #define SUN6I_CODEC_CALIBRATION (0x34)
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* FIFO counters */
215*4882a593Smuzhiyun #define SUN6I_CODEC_DAC_TXCNT (0x40)
216*4882a593Smuzhiyun #define SUN6I_CODEC_ADC_RXCNT (0x44)
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* headset jack detection and button support registers */
219*4882a593Smuzhiyun #define SUN6I_CODEC_HMIC_CTL (0x50)
220*4882a593Smuzhiyun #define SUN6I_CODEC_HMIC_DATA (0x54)
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* TODO sun6i DAP (Digital Audio Processing) bits */
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* FIFO counters moved on A23 */
225*4882a593Smuzhiyun #define SUN8I_A23_CODEC_DAC_TXCNT (0x1c)
226*4882a593Smuzhiyun #define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* TX FIFO moved on H3 */
229*4882a593Smuzhiyun #define SUN8I_H3_CODEC_DAC_TXDATA (0x20)
230*4882a593Smuzhiyun #define SUN8I_H3_CODEC_DAC_DBG (0x48)
231*4882a593Smuzhiyun #define SUN8I_H3_CODEC_ADC_DBG (0x4c)
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* TODO H3 DAP (Digital Audio Processing) bits */
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun struct sun4i_codec {
236*4882a593Smuzhiyun struct device *dev;
237*4882a593Smuzhiyun struct regmap *regmap;
238*4882a593Smuzhiyun struct clk *clk_apb;
239*4882a593Smuzhiyun struct clk *clk_module;
240*4882a593Smuzhiyun struct reset_control *rst;
241*4882a593Smuzhiyun struct gpio_desc *gpio_pa;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* ADC_FIFOC register is at different offset on different SoCs */
244*4882a593Smuzhiyun struct regmap_field *reg_adc_fifoc;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun struct snd_dmaengine_dai_dma_data capture_dma_data;
247*4882a593Smuzhiyun struct snd_dmaengine_dai_dma_data playback_dma_data;
248*4882a593Smuzhiyun };
249*4882a593Smuzhiyun
sun4i_codec_start_playback(struct sun4i_codec * scodec)250*4882a593Smuzhiyun static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun /* Flush TX FIFO */
253*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
254*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
255*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Enable DAC DRQ */
258*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
259*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
260*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
sun4i_codec_stop_playback(struct sun4i_codec * scodec)263*4882a593Smuzhiyun static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun /* Disable DAC DRQ */
266*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
267*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
268*4882a593Smuzhiyun 0);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
sun4i_codec_start_capture(struct sun4i_codec * scodec)271*4882a593Smuzhiyun static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun /* Enable ADC DRQ */
274*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
275*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
276*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
sun4i_codec_stop_capture(struct sun4i_codec * scodec)279*4882a593Smuzhiyun static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun /* Disable ADC DRQ */
282*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
283*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
sun4i_codec_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)286*4882a593Smuzhiyun static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
287*4882a593Smuzhiyun struct snd_soc_dai *dai)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
290*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun switch (cmd) {
293*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
294*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_RESUME:
295*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
296*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
297*4882a593Smuzhiyun sun4i_codec_start_playback(scodec);
298*4882a593Smuzhiyun else
299*4882a593Smuzhiyun sun4i_codec_start_capture(scodec);
300*4882a593Smuzhiyun break;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
303*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_SUSPEND:
304*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
305*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
306*4882a593Smuzhiyun sun4i_codec_stop_playback(scodec);
307*4882a593Smuzhiyun else
308*4882a593Smuzhiyun sun4i_codec_stop_capture(scodec);
309*4882a593Smuzhiyun break;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun default:
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
sun4i_codec_prepare_capture(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)318*4882a593Smuzhiyun static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
319*4882a593Smuzhiyun struct snd_soc_dai *dai)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
322*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /* Flush RX FIFO */
326*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
327*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
328*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* Set RX FIFO trigger level */
332*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
333*4882a593Smuzhiyun 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
334*4882a593Smuzhiyun 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /*
337*4882a593Smuzhiyun * FIXME: Undocumented in the datasheet, but
338*4882a593Smuzhiyun * Allwinner's code mentions that it is
339*4882a593Smuzhiyun * related to microphone gain
340*4882a593Smuzhiyun */
341*4882a593Smuzhiyun if (of_device_is_compatible(scodec->dev->of_node,
342*4882a593Smuzhiyun "allwinner,sun4i-a10-codec") ||
343*4882a593Smuzhiyun of_device_is_compatible(scodec->dev->of_node,
344*4882a593Smuzhiyun "allwinner,sun7i-a20-codec")) {
345*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
346*4882a593Smuzhiyun 0x3 << 25,
347*4882a593Smuzhiyun 0x1 << 25);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (of_device_is_compatible(scodec->dev->of_node,
351*4882a593Smuzhiyun "allwinner,sun7i-a20-codec"))
352*4882a593Smuzhiyun /* FIXME: Undocumented bits */
353*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
354*4882a593Smuzhiyun 0x3 << 8,
355*4882a593Smuzhiyun 0x1 << 8);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
sun4i_codec_prepare_playback(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)360*4882a593Smuzhiyun static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
361*4882a593Smuzhiyun struct snd_soc_dai *dai)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
364*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
365*4882a593Smuzhiyun u32 val;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /* Flush the TX FIFO */
368*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
369*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
370*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* Set TX FIFO Empty Trigger Level */
373*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
374*4882a593Smuzhiyun 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
375*4882a593Smuzhiyun 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun if (substream->runtime->rate > 32000)
378*4882a593Smuzhiyun /* Use 64 bits FIR filter */
379*4882a593Smuzhiyun val = 0;
380*4882a593Smuzhiyun else
381*4882a593Smuzhiyun /* Use 32 bits FIR filter */
382*4882a593Smuzhiyun val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
385*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
386*4882a593Smuzhiyun val);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* Send zeros when we have an underrun */
389*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
390*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
391*4882a593Smuzhiyun 0);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun return 0;
394*4882a593Smuzhiyun };
395*4882a593Smuzhiyun
sun4i_codec_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)396*4882a593Smuzhiyun static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
397*4882a593Smuzhiyun struct snd_soc_dai *dai)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
400*4882a593Smuzhiyun return sun4i_codec_prepare_playback(substream, dai);
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return sun4i_codec_prepare_capture(substream, dai);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
sun4i_codec_get_mod_freq(struct snd_pcm_hw_params * params)405*4882a593Smuzhiyun static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun unsigned int rate = params_rate(params);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun switch (rate) {
410*4882a593Smuzhiyun case 176400:
411*4882a593Smuzhiyun case 88200:
412*4882a593Smuzhiyun case 44100:
413*4882a593Smuzhiyun case 33075:
414*4882a593Smuzhiyun case 22050:
415*4882a593Smuzhiyun case 14700:
416*4882a593Smuzhiyun case 11025:
417*4882a593Smuzhiyun case 7350:
418*4882a593Smuzhiyun return 22579200;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun case 192000:
421*4882a593Smuzhiyun case 96000:
422*4882a593Smuzhiyun case 48000:
423*4882a593Smuzhiyun case 32000:
424*4882a593Smuzhiyun case 24000:
425*4882a593Smuzhiyun case 16000:
426*4882a593Smuzhiyun case 12000:
427*4882a593Smuzhiyun case 8000:
428*4882a593Smuzhiyun return 24576000;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun default:
431*4882a593Smuzhiyun return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
sun4i_codec_get_hw_rate(struct snd_pcm_hw_params * params)435*4882a593Smuzhiyun static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun unsigned int rate = params_rate(params);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun switch (rate) {
440*4882a593Smuzhiyun case 192000:
441*4882a593Smuzhiyun case 176400:
442*4882a593Smuzhiyun return 6;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun case 96000:
445*4882a593Smuzhiyun case 88200:
446*4882a593Smuzhiyun return 7;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun case 48000:
449*4882a593Smuzhiyun case 44100:
450*4882a593Smuzhiyun return 0;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun case 32000:
453*4882a593Smuzhiyun case 33075:
454*4882a593Smuzhiyun return 1;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun case 24000:
457*4882a593Smuzhiyun case 22050:
458*4882a593Smuzhiyun return 2;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun case 16000:
461*4882a593Smuzhiyun case 14700:
462*4882a593Smuzhiyun return 3;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun case 12000:
465*4882a593Smuzhiyun case 11025:
466*4882a593Smuzhiyun return 4;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun case 8000:
469*4882a593Smuzhiyun case 7350:
470*4882a593Smuzhiyun return 5;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun default:
473*4882a593Smuzhiyun return -EINVAL;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
sun4i_codec_hw_params_capture(struct sun4i_codec * scodec,struct snd_pcm_hw_params * params,unsigned int hwrate)477*4882a593Smuzhiyun static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
478*4882a593Smuzhiyun struct snd_pcm_hw_params *params,
479*4882a593Smuzhiyun unsigned int hwrate)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun /* Set ADC sample rate */
482*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
483*4882a593Smuzhiyun 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
484*4882a593Smuzhiyun hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* Set the number of channels we want to use */
487*4882a593Smuzhiyun if (params_channels(params) == 1)
488*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
489*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
490*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
491*4882a593Smuzhiyun else
492*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
493*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
494*4882a593Smuzhiyun 0);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /* Set the number of sample bits to either 16 or 24 bits */
497*4882a593Smuzhiyun if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
498*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
499*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
500*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
503*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
504*4882a593Smuzhiyun 0);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
507*4882a593Smuzhiyun } else {
508*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
509*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
510*4882a593Smuzhiyun 0);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun /* Fill most significant bits with valid data MSB */
513*4882a593Smuzhiyun regmap_field_update_bits(scodec->reg_adc_fifoc,
514*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
515*4882a593Smuzhiyun BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun return 0;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
sun4i_codec_hw_params_playback(struct sun4i_codec * scodec,struct snd_pcm_hw_params * params,unsigned int hwrate)523*4882a593Smuzhiyun static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
524*4882a593Smuzhiyun struct snd_pcm_hw_params *params,
525*4882a593Smuzhiyun unsigned int hwrate)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun u32 val;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* Set DAC sample rate */
530*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
531*4882a593Smuzhiyun 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
532*4882a593Smuzhiyun hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /* Set the number of channels we want to use */
535*4882a593Smuzhiyun if (params_channels(params) == 1)
536*4882a593Smuzhiyun val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
537*4882a593Smuzhiyun else
538*4882a593Smuzhiyun val = 0;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
541*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
542*4882a593Smuzhiyun val);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun /* Set the number of sample bits to either 16 or 24 bits */
545*4882a593Smuzhiyun if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
546*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
547*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
548*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /* Set TX FIFO mode to padding the LSBs with 0 */
551*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
552*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
553*4882a593Smuzhiyun 0);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
556*4882a593Smuzhiyun } else {
557*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
558*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
559*4882a593Smuzhiyun 0);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* Set TX FIFO mode to repeat the MSB */
562*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
563*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
564*4882a593Smuzhiyun BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
sun4i_codec_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)572*4882a593Smuzhiyun static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
573*4882a593Smuzhiyun struct snd_pcm_hw_params *params,
574*4882a593Smuzhiyun struct snd_soc_dai *dai)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
577*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
578*4882a593Smuzhiyun unsigned long clk_freq;
579*4882a593Smuzhiyun int ret, hwrate;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun clk_freq = sun4i_codec_get_mod_freq(params);
582*4882a593Smuzhiyun if (!clk_freq)
583*4882a593Smuzhiyun return -EINVAL;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun ret = clk_set_rate(scodec->clk_module, clk_freq);
586*4882a593Smuzhiyun if (ret)
587*4882a593Smuzhiyun return ret;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun hwrate = sun4i_codec_get_hw_rate(params);
590*4882a593Smuzhiyun if (hwrate < 0)
591*4882a593Smuzhiyun return hwrate;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
594*4882a593Smuzhiyun return sun4i_codec_hw_params_playback(scodec, params,
595*4882a593Smuzhiyun hwrate);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun return sun4i_codec_hw_params_capture(scodec, params,
598*4882a593Smuzhiyun hwrate);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun static unsigned int sun4i_codec_src_rates[] = {
603*4882a593Smuzhiyun 8000, 11025, 12000, 16000, 22050, 24000, 32000,
604*4882a593Smuzhiyun 44100, 48000, 96000, 192000
605*4882a593Smuzhiyun };
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
609*4882a593Smuzhiyun .count = ARRAY_SIZE(sun4i_codec_src_rates),
610*4882a593Smuzhiyun .list = sun4i_codec_src_rates,
611*4882a593Smuzhiyun };
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun
sun4i_codec_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)614*4882a593Smuzhiyun static int sun4i_codec_startup(struct snd_pcm_substream *substream,
615*4882a593Smuzhiyun struct snd_soc_dai *dai)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
618*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun snd_pcm_hw_constraint_list(substream->runtime, 0,
621*4882a593Smuzhiyun SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun /*
624*4882a593Smuzhiyun * Stop issuing DRQ when we have room for less than 16 samples
625*4882a593Smuzhiyun * in our TX FIFO
626*4882a593Smuzhiyun */
627*4882a593Smuzhiyun regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
628*4882a593Smuzhiyun 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
629*4882a593Smuzhiyun 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun return clk_prepare_enable(scodec->clk_module);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
sun4i_codec_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)634*4882a593Smuzhiyun static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
635*4882a593Smuzhiyun struct snd_soc_dai *dai)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
638*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun clk_disable_unprepare(scodec->clk_module);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
644*4882a593Smuzhiyun .startup = sun4i_codec_startup,
645*4882a593Smuzhiyun .shutdown = sun4i_codec_shutdown,
646*4882a593Smuzhiyun .trigger = sun4i_codec_trigger,
647*4882a593Smuzhiyun .hw_params = sun4i_codec_hw_params,
648*4882a593Smuzhiyun .prepare = sun4i_codec_prepare,
649*4882a593Smuzhiyun };
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun static struct snd_soc_dai_driver sun4i_codec_dai = {
652*4882a593Smuzhiyun .name = "Codec",
653*4882a593Smuzhiyun .ops = &sun4i_codec_dai_ops,
654*4882a593Smuzhiyun .playback = {
655*4882a593Smuzhiyun .stream_name = "Codec Playback",
656*4882a593Smuzhiyun .channels_min = 1,
657*4882a593Smuzhiyun .channels_max = 2,
658*4882a593Smuzhiyun .rate_min = 8000,
659*4882a593Smuzhiyun .rate_max = 192000,
660*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_CONTINUOUS,
661*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE |
662*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S32_LE,
663*4882a593Smuzhiyun .sig_bits = 24,
664*4882a593Smuzhiyun },
665*4882a593Smuzhiyun .capture = {
666*4882a593Smuzhiyun .stream_name = "Codec Capture",
667*4882a593Smuzhiyun .channels_min = 1,
668*4882a593Smuzhiyun .channels_max = 2,
669*4882a593Smuzhiyun .rate_min = 8000,
670*4882a593Smuzhiyun .rate_max = 48000,
671*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_CONTINUOUS,
672*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE |
673*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S32_LE,
674*4882a593Smuzhiyun .sig_bits = 24,
675*4882a593Smuzhiyun },
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun /*** sun4i Codec ***/
679*4882a593Smuzhiyun static const struct snd_kcontrol_new sun4i_codec_pa_mute =
680*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
681*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
684*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150,
685*4882a593Smuzhiyun 0);
686*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300,
687*4882a593Smuzhiyun 0);
688*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150,
689*4882a593Smuzhiyun 0);
690*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150,
691*4882a593Smuzhiyun 0);
692*4882a593Smuzhiyun static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale,
693*4882a593Smuzhiyun 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
694*4882a593Smuzhiyun 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0));
695*4882a593Smuzhiyun static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale,
696*4882a593Smuzhiyun 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
697*4882a593Smuzhiyun 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0));
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun static const struct snd_kcontrol_new sun4i_codec_controls[] = {
700*4882a593Smuzhiyun SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
701*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
702*4882a593Smuzhiyun sun4i_codec_pa_volume_scale),
703*4882a593Smuzhiyun SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
704*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
705*4882a593Smuzhiyun sun4i_codec_linein_loopback_gain_scale),
706*4882a593Smuzhiyun SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
707*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
708*4882a593Smuzhiyun sun4i_codec_linein_preamp_gain_scale),
709*4882a593Smuzhiyun SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
710*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
711*4882a593Smuzhiyun sun4i_codec_fmin_loopback_gain_scale),
712*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
713*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
714*4882a593Smuzhiyun sun4i_codec_micin_loopback_gain_scale),
715*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL,
716*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0,
717*4882a593Smuzhiyun sun4i_codec_micin_preamp_gain_scale),
718*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL,
719*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0,
720*4882a593Smuzhiyun sun4i_codec_micin_preamp_gain_scale),
721*4882a593Smuzhiyun };
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun static const struct snd_kcontrol_new sun7i_codec_controls[] = {
724*4882a593Smuzhiyun SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
725*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
726*4882a593Smuzhiyun sun4i_codec_pa_volume_scale),
727*4882a593Smuzhiyun SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
728*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
729*4882a593Smuzhiyun sun4i_codec_linein_loopback_gain_scale),
730*4882a593Smuzhiyun SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
731*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
732*4882a593Smuzhiyun sun4i_codec_linein_preamp_gain_scale),
733*4882a593Smuzhiyun SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
734*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
735*4882a593Smuzhiyun sun4i_codec_fmin_loopback_gain_scale),
736*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
737*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
738*4882a593Smuzhiyun sun4i_codec_micin_loopback_gain_scale),
739*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
740*4882a593Smuzhiyun SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0,
741*4882a593Smuzhiyun sun7i_codec_micin_preamp_gain_scale),
742*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
743*4882a593Smuzhiyun SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0,
744*4882a593Smuzhiyun sun7i_codec_micin_preamp_gain_scale),
745*4882a593Smuzhiyun };
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = {
748*4882a593Smuzhiyun SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch",
749*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS,
750*4882a593Smuzhiyun 1, 0),
751*4882a593Smuzhiyun SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch",
752*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS,
753*4882a593Smuzhiyun 1, 0),
754*4882a593Smuzhiyun SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch",
755*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL,
756*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
757*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL,
758*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_LLNS,
759*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0),
760*4882a593Smuzhiyun SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL,
761*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_LFMS,
762*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0),
763*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL,
764*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIC1LS,
765*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0),
766*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL,
767*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIC2LS,
768*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0),
769*4882a593Smuzhiyun };
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
772*4882a593Smuzhiyun SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
773*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
774*4882a593Smuzhiyun SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
775*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
776*4882a593Smuzhiyun };
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
779*4882a593Smuzhiyun /* Digital parts of the ADCs */
780*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
781*4882a593Smuzhiyun SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
782*4882a593Smuzhiyun NULL, 0),
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun /* Digital parts of the DACs */
785*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
786*4882a593Smuzhiyun SUN4I_CODEC_DAC_DPC_EN_DA, 0,
787*4882a593Smuzhiyun NULL, 0),
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun /* Analog parts of the ADCs */
790*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
791*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
792*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
793*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun /* Analog parts of the DACs */
796*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
797*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
798*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
799*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun /* Mixers */
802*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
803*4882a593Smuzhiyun sun4i_codec_mixer_controls,
804*4882a593Smuzhiyun ARRAY_SIZE(sun4i_codec_mixer_controls)),
805*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
806*4882a593Smuzhiyun sun4i_codec_mixer_controls,
807*4882a593Smuzhiyun ARRAY_SIZE(sun4i_codec_mixer_controls)),
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /* Global Mixer Enable */
810*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
811*4882a593Smuzhiyun SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun /* VMIC */
814*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
815*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun /* Mic Pre-Amplifiers */
818*4882a593Smuzhiyun SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
819*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
820*4882a593Smuzhiyun SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
821*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0),
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /* Power Amplifier */
824*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
825*4882a593Smuzhiyun SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
826*4882a593Smuzhiyun sun4i_codec_pa_mixer_controls,
827*4882a593Smuzhiyun ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
828*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
829*4882a593Smuzhiyun &sun4i_codec_pa_mute),
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("Line Right"),
832*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("Line Left"),
833*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("FM Right"),
834*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("FM Left"),
835*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("Mic1"),
836*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("Mic2"),
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("HP Right"),
839*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("HP Left"),
840*4882a593Smuzhiyun };
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
843*4882a593Smuzhiyun /* Left ADC / DAC Routes */
844*4882a593Smuzhiyun { "Left ADC", NULL, "ADC" },
845*4882a593Smuzhiyun { "Left DAC", NULL, "DAC" },
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun /* Right ADC / DAC Routes */
848*4882a593Smuzhiyun { "Right ADC", NULL, "ADC" },
849*4882a593Smuzhiyun { "Right DAC", NULL, "DAC" },
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun /* Right Mixer Routes */
852*4882a593Smuzhiyun { "Right Mixer", NULL, "Mixer Enable" },
853*4882a593Smuzhiyun { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" },
854*4882a593Smuzhiyun { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" },
855*4882a593Smuzhiyun { "Right Mixer", "Line Playback Switch", "Line Right" },
856*4882a593Smuzhiyun { "Right Mixer", "FM Playback Switch", "FM Right" },
857*4882a593Smuzhiyun { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
858*4882a593Smuzhiyun { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun /* Left Mixer Routes */
861*4882a593Smuzhiyun { "Left Mixer", NULL, "Mixer Enable" },
862*4882a593Smuzhiyun { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" },
863*4882a593Smuzhiyun { "Left Mixer", "Line Playback Switch", "Line Left" },
864*4882a593Smuzhiyun { "Left Mixer", "FM Playback Switch", "FM Left" },
865*4882a593Smuzhiyun { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
866*4882a593Smuzhiyun { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun /* Power Amplifier Routes */
869*4882a593Smuzhiyun { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
870*4882a593Smuzhiyun { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
871*4882a593Smuzhiyun { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
872*4882a593Smuzhiyun { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun /* Headphone Output Routes */
875*4882a593Smuzhiyun { "Power Amplifier Mute", "Switch", "Power Amplifier" },
876*4882a593Smuzhiyun { "HP Right", NULL, "Power Amplifier Mute" },
877*4882a593Smuzhiyun { "HP Left", NULL, "Power Amplifier Mute" },
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun /* Mic1 Routes */
880*4882a593Smuzhiyun { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
881*4882a593Smuzhiyun { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
882*4882a593Smuzhiyun { "MIC1 Pre-Amplifier", NULL, "Mic1"},
883*4882a593Smuzhiyun { "Mic1", NULL, "VMIC" },
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun /* Mic2 Routes */
886*4882a593Smuzhiyun { "Left ADC", NULL, "MIC2 Pre-Amplifier" },
887*4882a593Smuzhiyun { "Right ADC", NULL, "MIC2 Pre-Amplifier" },
888*4882a593Smuzhiyun { "MIC2 Pre-Amplifier", NULL, "Mic2"},
889*4882a593Smuzhiyun { "Mic2", NULL, "VMIC" },
890*4882a593Smuzhiyun };
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun static const struct snd_soc_component_driver sun4i_codec_codec = {
893*4882a593Smuzhiyun .controls = sun4i_codec_controls,
894*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(sun4i_codec_controls),
895*4882a593Smuzhiyun .dapm_widgets = sun4i_codec_codec_dapm_widgets,
896*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
897*4882a593Smuzhiyun .dapm_routes = sun4i_codec_codec_dapm_routes,
898*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
899*4882a593Smuzhiyun .idle_bias_on = 1,
900*4882a593Smuzhiyun .use_pmdown_time = 1,
901*4882a593Smuzhiyun .endianness = 1,
902*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
903*4882a593Smuzhiyun };
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun static const struct snd_soc_component_driver sun7i_codec_codec = {
906*4882a593Smuzhiyun .controls = sun7i_codec_controls,
907*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(sun7i_codec_controls),
908*4882a593Smuzhiyun .dapm_widgets = sun4i_codec_codec_dapm_widgets,
909*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
910*4882a593Smuzhiyun .dapm_routes = sun4i_codec_codec_dapm_routes,
911*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
912*4882a593Smuzhiyun .idle_bias_on = 1,
913*4882a593Smuzhiyun .use_pmdown_time = 1,
914*4882a593Smuzhiyun .endianness = 1,
915*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
916*4882a593Smuzhiyun };
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun /*** sun6i Codec ***/
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /* mixer controls */
921*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
922*4882a593Smuzhiyun SOC_DAPM_DOUBLE("DAC Playback Switch",
923*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
924*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
925*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
926*4882a593Smuzhiyun SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
927*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
928*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
929*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
930*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Line In Playback Switch",
931*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
932*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
933*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
934*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic1 Playback Switch",
935*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
936*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
937*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
938*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic2 Playback Switch",
939*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
940*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
941*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun /* ADC mixer controls */
945*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
946*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mixer Capture Switch",
947*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL,
948*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
949*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
950*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
951*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL,
952*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
953*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
954*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Line In Capture Switch",
955*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL,
956*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
957*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
958*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic1 Capture Switch",
959*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL,
960*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
961*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
962*4882a593Smuzhiyun SOC_DAPM_DOUBLE("Mic2 Capture Switch",
963*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL,
964*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
965*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
966*4882a593Smuzhiyun };
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun /* headphone controls */
969*4882a593Smuzhiyun static const char * const sun6i_codec_hp_src_enum_text[] = {
970*4882a593Smuzhiyun "DAC", "Mixer",
971*4882a593Smuzhiyun };
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
974*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
975*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
976*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
977*4882a593Smuzhiyun sun6i_codec_hp_src_enum_text);
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
980*4882a593Smuzhiyun SOC_DAPM_ENUM("Headphone Source Playback Route",
981*4882a593Smuzhiyun sun6i_codec_hp_src_enum),
982*4882a593Smuzhiyun };
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun /* microphone controls */
985*4882a593Smuzhiyun static const char * const sun6i_codec_mic2_src_enum_text[] = {
986*4882a593Smuzhiyun "Mic2", "Mic3",
987*4882a593Smuzhiyun };
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
990*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL,
991*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MIC2SLT,
992*4882a593Smuzhiyun sun6i_codec_mic2_src_enum_text);
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
995*4882a593Smuzhiyun SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
996*4882a593Smuzhiyun sun6i_codec_mic2_src_enum),
997*4882a593Smuzhiyun };
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun /* line out controls */
1000*4882a593Smuzhiyun static const char * const sun6i_codec_lineout_src_enum_text[] = {
1001*4882a593Smuzhiyun "Stereo", "Mono Differential",
1002*4882a593Smuzhiyun };
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
1005*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL,
1006*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
1007*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
1008*4882a593Smuzhiyun sun6i_codec_lineout_src_enum_text);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
1011*4882a593Smuzhiyun SOC_DAPM_ENUM("Line Out Source Playback Route",
1012*4882a593Smuzhiyun sun6i_codec_lineout_src_enum),
1013*4882a593Smuzhiyun };
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun /* volume / mute controls */
1016*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
1017*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
1018*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
1019*4882a593Smuzhiyun -450, 150, 0);
1020*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
1021*4882a593Smuzhiyun 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
1022*4882a593Smuzhiyun 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
1023*4882a593Smuzhiyun );
1024*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
1025*4882a593Smuzhiyun 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1026*4882a593Smuzhiyun 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
1027*4882a593Smuzhiyun );
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
1030*4882a593Smuzhiyun SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1031*4882a593Smuzhiyun SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1032*4882a593Smuzhiyun sun6i_codec_dvol_scale),
1033*4882a593Smuzhiyun SOC_SINGLE_TLV("Headphone Playback Volume",
1034*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
1035*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
1036*4882a593Smuzhiyun sun6i_codec_hp_vol_scale),
1037*4882a593Smuzhiyun SOC_SINGLE_TLV("Line Out Playback Volume",
1038*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL,
1039*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
1040*4882a593Smuzhiyun sun6i_codec_lineout_vol_scale),
1041*4882a593Smuzhiyun SOC_DOUBLE("Headphone Playback Switch",
1042*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
1043*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
1044*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
1045*4882a593Smuzhiyun SOC_DOUBLE("Line Out Playback Switch",
1046*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL,
1047*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
1048*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
1049*4882a593Smuzhiyun /* Mixer pre-gains */
1050*4882a593Smuzhiyun SOC_SINGLE_TLV("Line In Playback Volume",
1051*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
1052*4882a593Smuzhiyun 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1053*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic1 Playback Volume",
1054*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
1055*4882a593Smuzhiyun 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1056*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic2 Playback Volume",
1057*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
1058*4882a593Smuzhiyun 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun /* Microphone Amp boost gains */
1061*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1062*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
1063*4882a593Smuzhiyun sun6i_codec_mic_gain_scale),
1064*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1065*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
1066*4882a593Smuzhiyun sun6i_codec_mic_gain_scale),
1067*4882a593Smuzhiyun SOC_DOUBLE_TLV("ADC Capture Volume",
1068*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
1069*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
1070*4882a593Smuzhiyun sun6i_codec_out_mixer_pregain_scale),
1071*4882a593Smuzhiyun };
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
1074*4882a593Smuzhiyun /* Microphone inputs */
1075*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC1"),
1076*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC2"),
1077*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC3"),
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun /* Microphone Bias */
1080*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
1081*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
1082*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
1083*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun /* Mic input path */
1086*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
1087*4882a593Smuzhiyun SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
1088*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
1089*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
1090*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
1091*4882a593Smuzhiyun SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun /* Line In */
1094*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("LINEIN"),
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun /* Digital parts of the ADCs */
1097*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1098*4882a593Smuzhiyun SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
1099*4882a593Smuzhiyun NULL, 0),
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun /* Analog parts of the ADCs */
1102*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1103*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
1104*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1105*4882a593Smuzhiyun SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun /* ADC Mixers */
1108*4882a593Smuzhiyun SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
1109*4882a593Smuzhiyun sun6i_codec_adc_mixer_controls),
1110*4882a593Smuzhiyun SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
1111*4882a593Smuzhiyun sun6i_codec_adc_mixer_controls),
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun /* Digital parts of the DACs */
1114*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1115*4882a593Smuzhiyun SUN4I_CODEC_DAC_DPC_EN_DA, 0,
1116*4882a593Smuzhiyun NULL, 0),
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun /* Analog parts of the DACs */
1119*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
1120*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
1121*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
1122*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
1123*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL,
1124*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun /* Mixers */
1127*4882a593Smuzhiyun SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1128*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
1129*4882a593Smuzhiyun sun6i_codec_mixer_controls),
1130*4882a593Smuzhiyun SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1131*4882a593Smuzhiyun SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
1132*4882a593Smuzhiyun sun6i_codec_mixer_controls),
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun /* Headphone output path */
1135*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Headphone Source Playback Route",
1136*4882a593Smuzhiyun SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
1137*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
1138*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
1139*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
1140*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
1141*4882a593Smuzhiyun SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
1142*4882a593Smuzhiyun SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
1143*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("HP"),
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun /* Line Out path */
1146*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Line Out Source Playback Route",
1147*4882a593Smuzhiyun SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
1148*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("LINEOUT"),
1149*4882a593Smuzhiyun };
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1152*4882a593Smuzhiyun /* DAC Routes */
1153*4882a593Smuzhiyun { "Left DAC", NULL, "DAC Enable" },
1154*4882a593Smuzhiyun { "Right DAC", NULL, "DAC Enable" },
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun /* Microphone Routes */
1157*4882a593Smuzhiyun { "Mic1 Amplifier", NULL, "MIC1"},
1158*4882a593Smuzhiyun { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
1159*4882a593Smuzhiyun { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
1160*4882a593Smuzhiyun { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun /* Left Mixer Routes */
1163*4882a593Smuzhiyun { "Left Mixer", "DAC Playback Switch", "Left DAC" },
1164*4882a593Smuzhiyun { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
1165*4882a593Smuzhiyun { "Left Mixer", "Line In Playback Switch", "LINEIN" },
1166*4882a593Smuzhiyun { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1167*4882a593Smuzhiyun { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun /* Right Mixer Routes */
1170*4882a593Smuzhiyun { "Right Mixer", "DAC Playback Switch", "Right DAC" },
1171*4882a593Smuzhiyun { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
1172*4882a593Smuzhiyun { "Right Mixer", "Line In Playback Switch", "LINEIN" },
1173*4882a593Smuzhiyun { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1174*4882a593Smuzhiyun { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun /* Left ADC Mixer Routes */
1177*4882a593Smuzhiyun { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
1178*4882a593Smuzhiyun { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
1179*4882a593Smuzhiyun { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
1180*4882a593Smuzhiyun { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1181*4882a593Smuzhiyun { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun /* Right ADC Mixer Routes */
1184*4882a593Smuzhiyun { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
1185*4882a593Smuzhiyun { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
1186*4882a593Smuzhiyun { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
1187*4882a593Smuzhiyun { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1188*4882a593Smuzhiyun { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun /* Headphone Routes */
1191*4882a593Smuzhiyun { "Headphone Source Playback Route", "DAC", "Left DAC" },
1192*4882a593Smuzhiyun { "Headphone Source Playback Route", "DAC", "Right DAC" },
1193*4882a593Smuzhiyun { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
1194*4882a593Smuzhiyun { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
1195*4882a593Smuzhiyun { "Headphone Amp", NULL, "Headphone Source Playback Route" },
1196*4882a593Smuzhiyun { "HP", NULL, "Headphone Amp" },
1197*4882a593Smuzhiyun { "HPCOM", NULL, "HPCOM Protection" },
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun /* Line Out Routes */
1200*4882a593Smuzhiyun { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
1201*4882a593Smuzhiyun { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
1202*4882a593Smuzhiyun { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
1203*4882a593Smuzhiyun { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
1204*4882a593Smuzhiyun { "LINEOUT", NULL, "Line Out Source Playback Route" },
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun /* ADC Routes */
1207*4882a593Smuzhiyun { "Left ADC", NULL, "ADC Enable" },
1208*4882a593Smuzhiyun { "Right ADC", NULL, "ADC Enable" },
1209*4882a593Smuzhiyun { "Left ADC", NULL, "Left ADC Mixer" },
1210*4882a593Smuzhiyun { "Right ADC", NULL, "Right ADC Mixer" },
1211*4882a593Smuzhiyun };
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun static const struct snd_soc_component_driver sun6i_codec_codec = {
1214*4882a593Smuzhiyun .controls = sun6i_codec_codec_widgets,
1215*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
1216*4882a593Smuzhiyun .dapm_widgets = sun6i_codec_codec_dapm_widgets,
1217*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
1218*4882a593Smuzhiyun .dapm_routes = sun6i_codec_codec_dapm_routes,
1219*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
1220*4882a593Smuzhiyun .idle_bias_on = 1,
1221*4882a593Smuzhiyun .use_pmdown_time = 1,
1222*4882a593Smuzhiyun .endianness = 1,
1223*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
1224*4882a593Smuzhiyun };
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun /* sun8i A23 codec */
1227*4882a593Smuzhiyun static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
1228*4882a593Smuzhiyun SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1229*4882a593Smuzhiyun SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1230*4882a593Smuzhiyun sun6i_codec_dvol_scale),
1231*4882a593Smuzhiyun };
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1234*4882a593Smuzhiyun /* Digital parts of the ADCs */
1235*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1236*4882a593Smuzhiyun SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
1237*4882a593Smuzhiyun /* Digital parts of the DACs */
1238*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1239*4882a593Smuzhiyun SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun };
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
1244*4882a593Smuzhiyun .controls = sun8i_a23_codec_codec_controls,
1245*4882a593Smuzhiyun .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
1246*4882a593Smuzhiyun .dapm_widgets = sun8i_a23_codec_codec_widgets,
1247*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
1248*4882a593Smuzhiyun .idle_bias_on = 1,
1249*4882a593Smuzhiyun .use_pmdown_time = 1,
1250*4882a593Smuzhiyun .endianness = 1,
1251*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
1252*4882a593Smuzhiyun };
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun static const struct snd_soc_component_driver sun4i_codec_component = {
1255*4882a593Smuzhiyun .name = "sun4i-codec",
1256*4882a593Smuzhiyun };
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun #define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS
1259*4882a593Smuzhiyun #define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
1260*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S32_LE)
1261*4882a593Smuzhiyun
sun4i_codec_dai_probe(struct snd_soc_dai * dai)1262*4882a593Smuzhiyun static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
1263*4882a593Smuzhiyun {
1264*4882a593Smuzhiyun struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
1265*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
1268*4882a593Smuzhiyun &scodec->capture_dma_data);
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun return 0;
1271*4882a593Smuzhiyun }
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun static struct snd_soc_dai_driver dummy_cpu_dai = {
1274*4882a593Smuzhiyun .name = "sun4i-codec-cpu-dai",
1275*4882a593Smuzhiyun .probe = sun4i_codec_dai_probe,
1276*4882a593Smuzhiyun .playback = {
1277*4882a593Smuzhiyun .stream_name = "Playback",
1278*4882a593Smuzhiyun .channels_min = 1,
1279*4882a593Smuzhiyun .channels_max = 2,
1280*4882a593Smuzhiyun .rates = SUN4I_CODEC_RATES,
1281*4882a593Smuzhiyun .formats = SUN4I_CODEC_FORMATS,
1282*4882a593Smuzhiyun .sig_bits = 24,
1283*4882a593Smuzhiyun },
1284*4882a593Smuzhiyun .capture = {
1285*4882a593Smuzhiyun .stream_name = "Capture",
1286*4882a593Smuzhiyun .channels_min = 1,
1287*4882a593Smuzhiyun .channels_max = 2,
1288*4882a593Smuzhiyun .rates = SUN4I_CODEC_RATES,
1289*4882a593Smuzhiyun .formats = SUN4I_CODEC_FORMATS,
1290*4882a593Smuzhiyun .sig_bits = 24,
1291*4882a593Smuzhiyun },
1292*4882a593Smuzhiyun };
1293*4882a593Smuzhiyun
sun4i_codec_create_link(struct device * dev,int * num_links)1294*4882a593Smuzhiyun static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
1295*4882a593Smuzhiyun int *num_links)
1296*4882a593Smuzhiyun {
1297*4882a593Smuzhiyun struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
1298*4882a593Smuzhiyun GFP_KERNEL);
1299*4882a593Smuzhiyun struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev,
1300*4882a593Smuzhiyun 3 * sizeof(*dlc), GFP_KERNEL);
1301*4882a593Smuzhiyun if (!link || !dlc)
1302*4882a593Smuzhiyun return NULL;
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun link->cpus = &dlc[0];
1305*4882a593Smuzhiyun link->codecs = &dlc[1];
1306*4882a593Smuzhiyun link->platforms = &dlc[2];
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun link->num_cpus = 1;
1309*4882a593Smuzhiyun link->num_codecs = 1;
1310*4882a593Smuzhiyun link->num_platforms = 1;
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun link->name = "cdc";
1313*4882a593Smuzhiyun link->stream_name = "CDC PCM";
1314*4882a593Smuzhiyun link->codecs->dai_name = "Codec";
1315*4882a593Smuzhiyun link->cpus->dai_name = dev_name(dev);
1316*4882a593Smuzhiyun link->codecs->name = dev_name(dev);
1317*4882a593Smuzhiyun link->platforms->name = dev_name(dev);
1318*4882a593Smuzhiyun link->dai_fmt = SND_SOC_DAIFMT_I2S;
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun *num_links = 1;
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun return link;
1323*4882a593Smuzhiyun };
1324*4882a593Smuzhiyun
sun4i_codec_spk_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)1325*4882a593Smuzhiyun static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
1326*4882a593Smuzhiyun struct snd_kcontrol *k, int event)
1327*4882a593Smuzhiyun {
1328*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun gpiod_set_value_cansleep(scodec->gpio_pa,
1331*4882a593Smuzhiyun !!SND_SOC_DAPM_EVENT_ON(event));
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun if (SND_SOC_DAPM_EVENT_ON(event)) {
1334*4882a593Smuzhiyun /*
1335*4882a593Smuzhiyun * Need a delay to wait for DAC to push the data. 700ms seems
1336*4882a593Smuzhiyun * to be the best compromise not to feel this delay while
1337*4882a593Smuzhiyun * playing a sound.
1338*4882a593Smuzhiyun */
1339*4882a593Smuzhiyun msleep(700);
1340*4882a593Smuzhiyun }
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun return 0;
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
1346*4882a593Smuzhiyun SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1347*4882a593Smuzhiyun };
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
1350*4882a593Smuzhiyun { "Speaker", NULL, "HP Right" },
1351*4882a593Smuzhiyun { "Speaker", NULL, "HP Left" },
1352*4882a593Smuzhiyun };
1353*4882a593Smuzhiyun
sun4i_codec_create_card(struct device * dev)1354*4882a593Smuzhiyun static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
1355*4882a593Smuzhiyun {
1356*4882a593Smuzhiyun struct snd_soc_card *card;
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1359*4882a593Smuzhiyun if (!card)
1360*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1363*4882a593Smuzhiyun if (!card->dai_link)
1364*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun card->dev = dev;
1367*4882a593Smuzhiyun card->owner = THIS_MODULE;
1368*4882a593Smuzhiyun card->name = "sun4i-codec";
1369*4882a593Smuzhiyun card->dapm_widgets = sun4i_codec_card_dapm_widgets;
1370*4882a593Smuzhiyun card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
1371*4882a593Smuzhiyun card->dapm_routes = sun4i_codec_card_dapm_routes;
1372*4882a593Smuzhiyun card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun return card;
1375*4882a593Smuzhiyun };
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
1378*4882a593Smuzhiyun SND_SOC_DAPM_HP("Headphone", NULL),
1379*4882a593Smuzhiyun SND_SOC_DAPM_LINE("Line In", NULL),
1380*4882a593Smuzhiyun SND_SOC_DAPM_LINE("Line Out", NULL),
1381*4882a593Smuzhiyun SND_SOC_DAPM_MIC("Headset Mic", NULL),
1382*4882a593Smuzhiyun SND_SOC_DAPM_MIC("Mic", NULL),
1383*4882a593Smuzhiyun SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1384*4882a593Smuzhiyun };
1385*4882a593Smuzhiyun
sun6i_codec_create_card(struct device * dev)1386*4882a593Smuzhiyun static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
1387*4882a593Smuzhiyun {
1388*4882a593Smuzhiyun struct snd_soc_card *card;
1389*4882a593Smuzhiyun int ret;
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1392*4882a593Smuzhiyun if (!card)
1393*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1396*4882a593Smuzhiyun if (!card->dai_link)
1397*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun card->dev = dev;
1400*4882a593Smuzhiyun card->owner = THIS_MODULE;
1401*4882a593Smuzhiyun card->name = "A31 Audio Codec";
1402*4882a593Smuzhiyun card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1403*4882a593Smuzhiyun card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1404*4882a593Smuzhiyun card->fully_routed = true;
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1407*4882a593Smuzhiyun if (ret)
1408*4882a593Smuzhiyun dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun return card;
1411*4882a593Smuzhiyun };
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun /* Connect digital side enables to analog side widgets */
1414*4882a593Smuzhiyun static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
1415*4882a593Smuzhiyun /* ADC Routes */
1416*4882a593Smuzhiyun { "Left ADC", NULL, "ADC Enable" },
1417*4882a593Smuzhiyun { "Right ADC", NULL, "ADC Enable" },
1418*4882a593Smuzhiyun { "Codec Capture", NULL, "Left ADC" },
1419*4882a593Smuzhiyun { "Codec Capture", NULL, "Right ADC" },
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun /* DAC Routes */
1422*4882a593Smuzhiyun { "Left DAC", NULL, "DAC Enable" },
1423*4882a593Smuzhiyun { "Right DAC", NULL, "DAC Enable" },
1424*4882a593Smuzhiyun { "Left DAC", NULL, "Codec Playback" },
1425*4882a593Smuzhiyun { "Right DAC", NULL, "Codec Playback" },
1426*4882a593Smuzhiyun };
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun static struct snd_soc_aux_dev aux_dev = {
1429*4882a593Smuzhiyun .dlc = COMP_EMPTY(),
1430*4882a593Smuzhiyun };
1431*4882a593Smuzhiyun
sun8i_a23_codec_create_card(struct device * dev)1432*4882a593Smuzhiyun static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun struct snd_soc_card *card;
1435*4882a593Smuzhiyun int ret;
1436*4882a593Smuzhiyun
1437*4882a593Smuzhiyun card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1438*4882a593Smuzhiyun if (!card)
1439*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1442*4882a593Smuzhiyun "allwinner,codec-analog-controls",
1443*4882a593Smuzhiyun 0);
1444*4882a593Smuzhiyun if (!aux_dev.dlc.of_node) {
1445*4882a593Smuzhiyun dev_err(dev, "Can't find analog controls for codec.\n");
1446*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1447*4882a593Smuzhiyun }
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1450*4882a593Smuzhiyun if (!card->dai_link)
1451*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun card->dev = dev;
1454*4882a593Smuzhiyun card->owner = THIS_MODULE;
1455*4882a593Smuzhiyun card->name = "A23 Audio Codec";
1456*4882a593Smuzhiyun card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1457*4882a593Smuzhiyun card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1458*4882a593Smuzhiyun card->dapm_routes = sun8i_codec_card_routes;
1459*4882a593Smuzhiyun card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1460*4882a593Smuzhiyun card->aux_dev = &aux_dev;
1461*4882a593Smuzhiyun card->num_aux_devs = 1;
1462*4882a593Smuzhiyun card->fully_routed = true;
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1465*4882a593Smuzhiyun if (ret)
1466*4882a593Smuzhiyun dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1467*4882a593Smuzhiyun
1468*4882a593Smuzhiyun return card;
1469*4882a593Smuzhiyun };
1470*4882a593Smuzhiyun
sun8i_h3_codec_create_card(struct device * dev)1471*4882a593Smuzhiyun static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
1472*4882a593Smuzhiyun {
1473*4882a593Smuzhiyun struct snd_soc_card *card;
1474*4882a593Smuzhiyun int ret;
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1477*4882a593Smuzhiyun if (!card)
1478*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1481*4882a593Smuzhiyun "allwinner,codec-analog-controls",
1482*4882a593Smuzhiyun 0);
1483*4882a593Smuzhiyun if (!aux_dev.dlc.of_node) {
1484*4882a593Smuzhiyun dev_err(dev, "Can't find analog controls for codec.\n");
1485*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1489*4882a593Smuzhiyun if (!card->dai_link)
1490*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun card->dev = dev;
1493*4882a593Smuzhiyun card->owner = THIS_MODULE;
1494*4882a593Smuzhiyun card->name = "H3 Audio Codec";
1495*4882a593Smuzhiyun card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1496*4882a593Smuzhiyun card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1497*4882a593Smuzhiyun card->dapm_routes = sun8i_codec_card_routes;
1498*4882a593Smuzhiyun card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1499*4882a593Smuzhiyun card->aux_dev = &aux_dev;
1500*4882a593Smuzhiyun card->num_aux_devs = 1;
1501*4882a593Smuzhiyun card->fully_routed = true;
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1504*4882a593Smuzhiyun if (ret)
1505*4882a593Smuzhiyun dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun return card;
1508*4882a593Smuzhiyun };
1509*4882a593Smuzhiyun
sun8i_v3s_codec_create_card(struct device * dev)1510*4882a593Smuzhiyun static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
1511*4882a593Smuzhiyun {
1512*4882a593Smuzhiyun struct snd_soc_card *card;
1513*4882a593Smuzhiyun int ret;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1516*4882a593Smuzhiyun if (!card)
1517*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1520*4882a593Smuzhiyun "allwinner,codec-analog-controls",
1521*4882a593Smuzhiyun 0);
1522*4882a593Smuzhiyun if (!aux_dev.dlc.of_node) {
1523*4882a593Smuzhiyun dev_err(dev, "Can't find analog controls for codec.\n");
1524*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1528*4882a593Smuzhiyun if (!card->dai_link)
1529*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun card->dev = dev;
1532*4882a593Smuzhiyun card->owner = THIS_MODULE;
1533*4882a593Smuzhiyun card->name = "V3s Audio Codec";
1534*4882a593Smuzhiyun card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1535*4882a593Smuzhiyun card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1536*4882a593Smuzhiyun card->dapm_routes = sun8i_codec_card_routes;
1537*4882a593Smuzhiyun card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1538*4882a593Smuzhiyun card->aux_dev = &aux_dev;
1539*4882a593Smuzhiyun card->num_aux_devs = 1;
1540*4882a593Smuzhiyun card->fully_routed = true;
1541*4882a593Smuzhiyun
1542*4882a593Smuzhiyun ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1543*4882a593Smuzhiyun if (ret)
1544*4882a593Smuzhiyun dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun return card;
1547*4882a593Smuzhiyun };
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun static const struct regmap_config sun4i_codec_regmap_config = {
1550*4882a593Smuzhiyun .reg_bits = 32,
1551*4882a593Smuzhiyun .reg_stride = 4,
1552*4882a593Smuzhiyun .val_bits = 32,
1553*4882a593Smuzhiyun .max_register = SUN4I_CODEC_ADC_RXCNT,
1554*4882a593Smuzhiyun };
1555*4882a593Smuzhiyun
1556*4882a593Smuzhiyun static const struct regmap_config sun6i_codec_regmap_config = {
1557*4882a593Smuzhiyun .reg_bits = 32,
1558*4882a593Smuzhiyun .reg_stride = 4,
1559*4882a593Smuzhiyun .val_bits = 32,
1560*4882a593Smuzhiyun .max_register = SUN6I_CODEC_HMIC_DATA,
1561*4882a593Smuzhiyun };
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun static const struct regmap_config sun7i_codec_regmap_config = {
1564*4882a593Smuzhiyun .reg_bits = 32,
1565*4882a593Smuzhiyun .reg_stride = 4,
1566*4882a593Smuzhiyun .val_bits = 32,
1567*4882a593Smuzhiyun .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
1568*4882a593Smuzhiyun };
1569*4882a593Smuzhiyun
1570*4882a593Smuzhiyun static const struct regmap_config sun8i_a23_codec_regmap_config = {
1571*4882a593Smuzhiyun .reg_bits = 32,
1572*4882a593Smuzhiyun .reg_stride = 4,
1573*4882a593Smuzhiyun .val_bits = 32,
1574*4882a593Smuzhiyun .max_register = SUN8I_A23_CODEC_ADC_RXCNT,
1575*4882a593Smuzhiyun };
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun static const struct regmap_config sun8i_h3_codec_regmap_config = {
1578*4882a593Smuzhiyun .reg_bits = 32,
1579*4882a593Smuzhiyun .reg_stride = 4,
1580*4882a593Smuzhiyun .val_bits = 32,
1581*4882a593Smuzhiyun .max_register = SUN8I_H3_CODEC_ADC_DBG,
1582*4882a593Smuzhiyun };
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun static const struct regmap_config sun8i_v3s_codec_regmap_config = {
1585*4882a593Smuzhiyun .reg_bits = 32,
1586*4882a593Smuzhiyun .reg_stride = 4,
1587*4882a593Smuzhiyun .val_bits = 32,
1588*4882a593Smuzhiyun .max_register = SUN8I_H3_CODEC_ADC_DBG,
1589*4882a593Smuzhiyun };
1590*4882a593Smuzhiyun
1591*4882a593Smuzhiyun struct sun4i_codec_quirks {
1592*4882a593Smuzhiyun const struct regmap_config *regmap_config;
1593*4882a593Smuzhiyun const struct snd_soc_component_driver *codec;
1594*4882a593Smuzhiyun struct snd_soc_card * (*create_card)(struct device *dev);
1595*4882a593Smuzhiyun struct reg_field reg_adc_fifoc; /* used for regmap_field */
1596*4882a593Smuzhiyun unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
1597*4882a593Smuzhiyun unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
1598*4882a593Smuzhiyun bool has_reset;
1599*4882a593Smuzhiyun };
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun4i_codec_quirks = {
1602*4882a593Smuzhiyun .regmap_config = &sun4i_codec_regmap_config,
1603*4882a593Smuzhiyun .codec = &sun4i_codec_codec,
1604*4882a593Smuzhiyun .create_card = sun4i_codec_create_card,
1605*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1606*4882a593Smuzhiyun .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1607*4882a593Smuzhiyun .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1608*4882a593Smuzhiyun };
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
1611*4882a593Smuzhiyun .regmap_config = &sun6i_codec_regmap_config,
1612*4882a593Smuzhiyun .codec = &sun6i_codec_codec,
1613*4882a593Smuzhiyun .create_card = sun6i_codec_create_card,
1614*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1615*4882a593Smuzhiyun .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1616*4882a593Smuzhiyun .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1617*4882a593Smuzhiyun .has_reset = true,
1618*4882a593Smuzhiyun };
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun7i_codec_quirks = {
1621*4882a593Smuzhiyun .regmap_config = &sun7i_codec_regmap_config,
1622*4882a593Smuzhiyun .codec = &sun7i_codec_codec,
1623*4882a593Smuzhiyun .create_card = sun4i_codec_create_card,
1624*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1625*4882a593Smuzhiyun .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1626*4882a593Smuzhiyun .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1627*4882a593Smuzhiyun };
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
1630*4882a593Smuzhiyun .regmap_config = &sun8i_a23_codec_regmap_config,
1631*4882a593Smuzhiyun .codec = &sun8i_a23_codec_codec,
1632*4882a593Smuzhiyun .create_card = sun8i_a23_codec_create_card,
1633*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1634*4882a593Smuzhiyun .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1635*4882a593Smuzhiyun .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1636*4882a593Smuzhiyun .has_reset = true,
1637*4882a593Smuzhiyun };
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
1640*4882a593Smuzhiyun .regmap_config = &sun8i_h3_codec_regmap_config,
1641*4882a593Smuzhiyun /*
1642*4882a593Smuzhiyun * TODO Share the codec structure with A23 for now.
1643*4882a593Smuzhiyun * This should be split out when adding digital audio
1644*4882a593Smuzhiyun * processing support for the H3.
1645*4882a593Smuzhiyun */
1646*4882a593Smuzhiyun .codec = &sun8i_a23_codec_codec,
1647*4882a593Smuzhiyun .create_card = sun8i_h3_codec_create_card,
1648*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1649*4882a593Smuzhiyun .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1650*4882a593Smuzhiyun .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1651*4882a593Smuzhiyun .has_reset = true,
1652*4882a593Smuzhiyun };
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
1655*4882a593Smuzhiyun .regmap_config = &sun8i_v3s_codec_regmap_config,
1656*4882a593Smuzhiyun /*
1657*4882a593Smuzhiyun * TODO The codec structure should be split out, like
1658*4882a593Smuzhiyun * H3, when adding digital audio processing support.
1659*4882a593Smuzhiyun */
1660*4882a593Smuzhiyun .codec = &sun8i_a23_codec_codec,
1661*4882a593Smuzhiyun .create_card = sun8i_v3s_codec_create_card,
1662*4882a593Smuzhiyun .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1663*4882a593Smuzhiyun .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1664*4882a593Smuzhiyun .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1665*4882a593Smuzhiyun .has_reset = true,
1666*4882a593Smuzhiyun };
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun static const struct of_device_id sun4i_codec_of_match[] = {
1669*4882a593Smuzhiyun {
1670*4882a593Smuzhiyun .compatible = "allwinner,sun4i-a10-codec",
1671*4882a593Smuzhiyun .data = &sun4i_codec_quirks,
1672*4882a593Smuzhiyun },
1673*4882a593Smuzhiyun {
1674*4882a593Smuzhiyun .compatible = "allwinner,sun6i-a31-codec",
1675*4882a593Smuzhiyun .data = &sun6i_a31_codec_quirks,
1676*4882a593Smuzhiyun },
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun .compatible = "allwinner,sun7i-a20-codec",
1679*4882a593Smuzhiyun .data = &sun7i_codec_quirks,
1680*4882a593Smuzhiyun },
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun .compatible = "allwinner,sun8i-a23-codec",
1683*4882a593Smuzhiyun .data = &sun8i_a23_codec_quirks,
1684*4882a593Smuzhiyun },
1685*4882a593Smuzhiyun {
1686*4882a593Smuzhiyun .compatible = "allwinner,sun8i-h3-codec",
1687*4882a593Smuzhiyun .data = &sun8i_h3_codec_quirks,
1688*4882a593Smuzhiyun },
1689*4882a593Smuzhiyun {
1690*4882a593Smuzhiyun .compatible = "allwinner,sun8i-v3s-codec",
1691*4882a593Smuzhiyun .data = &sun8i_v3s_codec_quirks,
1692*4882a593Smuzhiyun },
1693*4882a593Smuzhiyun {}
1694*4882a593Smuzhiyun };
1695*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
1696*4882a593Smuzhiyun
sun4i_codec_probe(struct platform_device * pdev)1697*4882a593Smuzhiyun static int sun4i_codec_probe(struct platform_device *pdev)
1698*4882a593Smuzhiyun {
1699*4882a593Smuzhiyun struct snd_soc_card *card;
1700*4882a593Smuzhiyun struct sun4i_codec *scodec;
1701*4882a593Smuzhiyun const struct sun4i_codec_quirks *quirks;
1702*4882a593Smuzhiyun struct resource *res;
1703*4882a593Smuzhiyun void __iomem *base;
1704*4882a593Smuzhiyun int ret;
1705*4882a593Smuzhiyun
1706*4882a593Smuzhiyun scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
1707*4882a593Smuzhiyun if (!scodec)
1708*4882a593Smuzhiyun return -ENOMEM;
1709*4882a593Smuzhiyun
1710*4882a593Smuzhiyun scodec->dev = &pdev->dev;
1711*4882a593Smuzhiyun
1712*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1713*4882a593Smuzhiyun base = devm_ioremap_resource(&pdev->dev, res);
1714*4882a593Smuzhiyun if (IS_ERR(base)) {
1715*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to map the registers\n");
1716*4882a593Smuzhiyun return PTR_ERR(base);
1717*4882a593Smuzhiyun }
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun quirks = of_device_get_match_data(&pdev->dev);
1720*4882a593Smuzhiyun if (quirks == NULL) {
1721*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
1722*4882a593Smuzhiyun return -ENODEV;
1723*4882a593Smuzhiyun }
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
1726*4882a593Smuzhiyun quirks->regmap_config);
1727*4882a593Smuzhiyun if (IS_ERR(scodec->regmap)) {
1728*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to create our regmap\n");
1729*4882a593Smuzhiyun return PTR_ERR(scodec->regmap);
1730*4882a593Smuzhiyun }
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun /* Get the clocks from the DT */
1733*4882a593Smuzhiyun scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
1734*4882a593Smuzhiyun if (IS_ERR(scodec->clk_apb)) {
1735*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to get the APB clock\n");
1736*4882a593Smuzhiyun return PTR_ERR(scodec->clk_apb);
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
1740*4882a593Smuzhiyun if (IS_ERR(scodec->clk_module)) {
1741*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to get the module clock\n");
1742*4882a593Smuzhiyun return PTR_ERR(scodec->clk_module);
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun if (quirks->has_reset) {
1746*4882a593Smuzhiyun scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
1747*4882a593Smuzhiyun NULL);
1748*4882a593Smuzhiyun if (IS_ERR(scodec->rst)) {
1749*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to get reset control\n");
1750*4882a593Smuzhiyun return PTR_ERR(scodec->rst);
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun }
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
1755*4882a593Smuzhiyun GPIOD_OUT_LOW);
1756*4882a593Smuzhiyun if (IS_ERR(scodec->gpio_pa)) {
1757*4882a593Smuzhiyun ret = PTR_ERR(scodec->gpio_pa);
1758*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
1759*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
1760*4882a593Smuzhiyun return ret;
1761*4882a593Smuzhiyun }
1762*4882a593Smuzhiyun
1763*4882a593Smuzhiyun /* reg_field setup */
1764*4882a593Smuzhiyun scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
1765*4882a593Smuzhiyun scodec->regmap,
1766*4882a593Smuzhiyun quirks->reg_adc_fifoc);
1767*4882a593Smuzhiyun if (IS_ERR(scodec->reg_adc_fifoc)) {
1768*4882a593Smuzhiyun ret = PTR_ERR(scodec->reg_adc_fifoc);
1769*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
1770*4882a593Smuzhiyun ret);
1771*4882a593Smuzhiyun return ret;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun
1774*4882a593Smuzhiyun /* Enable the bus clock */
1775*4882a593Smuzhiyun if (clk_prepare_enable(scodec->clk_apb)) {
1776*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to enable the APB clock\n");
1777*4882a593Smuzhiyun return -EINVAL;
1778*4882a593Smuzhiyun }
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun /* Deassert the reset control */
1781*4882a593Smuzhiyun if (scodec->rst) {
1782*4882a593Smuzhiyun ret = reset_control_deassert(scodec->rst);
1783*4882a593Smuzhiyun if (ret) {
1784*4882a593Smuzhiyun dev_err(&pdev->dev,
1785*4882a593Smuzhiyun "Failed to deassert the reset control\n");
1786*4882a593Smuzhiyun goto err_clk_disable;
1787*4882a593Smuzhiyun }
1788*4882a593Smuzhiyun }
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun /* DMA configuration for TX FIFO */
1791*4882a593Smuzhiyun scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
1792*4882a593Smuzhiyun scodec->playback_dma_data.maxburst = 8;
1793*4882a593Smuzhiyun scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1794*4882a593Smuzhiyun
1795*4882a593Smuzhiyun /* DMA configuration for RX FIFO */
1796*4882a593Smuzhiyun scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
1797*4882a593Smuzhiyun scodec->capture_dma_data.maxburst = 8;
1798*4882a593Smuzhiyun scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1799*4882a593Smuzhiyun
1800*4882a593Smuzhiyun ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
1801*4882a593Smuzhiyun &sun4i_codec_dai, 1);
1802*4882a593Smuzhiyun if (ret) {
1803*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to register our codec\n");
1804*4882a593Smuzhiyun goto err_assert_reset;
1805*4882a593Smuzhiyun }
1806*4882a593Smuzhiyun
1807*4882a593Smuzhiyun ret = devm_snd_soc_register_component(&pdev->dev,
1808*4882a593Smuzhiyun &sun4i_codec_component,
1809*4882a593Smuzhiyun &dummy_cpu_dai, 1);
1810*4882a593Smuzhiyun if (ret) {
1811*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to register our DAI\n");
1812*4882a593Smuzhiyun goto err_assert_reset;
1813*4882a593Smuzhiyun }
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1816*4882a593Smuzhiyun if (ret) {
1817*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
1818*4882a593Smuzhiyun goto err_assert_reset;
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun card = quirks->create_card(&pdev->dev);
1822*4882a593Smuzhiyun if (IS_ERR(card)) {
1823*4882a593Smuzhiyun ret = PTR_ERR(card);
1824*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to create our card\n");
1825*4882a593Smuzhiyun goto err_assert_reset;
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun
1828*4882a593Smuzhiyun snd_soc_card_set_drvdata(card, scodec);
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun ret = snd_soc_register_card(card);
1831*4882a593Smuzhiyun if (ret) {
1832*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to register our card\n");
1833*4882a593Smuzhiyun goto err_assert_reset;
1834*4882a593Smuzhiyun }
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun return 0;
1837*4882a593Smuzhiyun
1838*4882a593Smuzhiyun err_assert_reset:
1839*4882a593Smuzhiyun if (scodec->rst)
1840*4882a593Smuzhiyun reset_control_assert(scodec->rst);
1841*4882a593Smuzhiyun err_clk_disable:
1842*4882a593Smuzhiyun clk_disable_unprepare(scodec->clk_apb);
1843*4882a593Smuzhiyun return ret;
1844*4882a593Smuzhiyun }
1845*4882a593Smuzhiyun
sun4i_codec_remove(struct platform_device * pdev)1846*4882a593Smuzhiyun static int sun4i_codec_remove(struct platform_device *pdev)
1847*4882a593Smuzhiyun {
1848*4882a593Smuzhiyun struct snd_soc_card *card = platform_get_drvdata(pdev);
1849*4882a593Smuzhiyun struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun snd_soc_unregister_card(card);
1852*4882a593Smuzhiyun if (scodec->rst)
1853*4882a593Smuzhiyun reset_control_assert(scodec->rst);
1854*4882a593Smuzhiyun clk_disable_unprepare(scodec->clk_apb);
1855*4882a593Smuzhiyun
1856*4882a593Smuzhiyun return 0;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun
1859*4882a593Smuzhiyun static struct platform_driver sun4i_codec_driver = {
1860*4882a593Smuzhiyun .driver = {
1861*4882a593Smuzhiyun .name = "sun4i-codec",
1862*4882a593Smuzhiyun .of_match_table = sun4i_codec_of_match,
1863*4882a593Smuzhiyun },
1864*4882a593Smuzhiyun .probe = sun4i_codec_probe,
1865*4882a593Smuzhiyun .remove = sun4i_codec_remove,
1866*4882a593Smuzhiyun };
1867*4882a593Smuzhiyun module_platform_driver(sun4i_codec_driver);
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun MODULE_DESCRIPTION("Allwinner A10 codec driver");
1870*4882a593Smuzhiyun MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
1871*4882a593Smuzhiyun MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
1872*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1873*4882a593Smuzhiyun MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
1874*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1875