~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sunxi/sun50i-codec-analog.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 /*
  3  * This driver supports the analog controls for the internal codec
  4  * found in Allwinner's A64 SoC.
  5  *
  6  * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
  7  * Copyright (C) 2017 Marcus Cooper <codekipper@gmail.com>
  8  * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com>
  9  *
 10  * Based on sun8i-codec-analog.c
 11  *
 12  */
 13 
 14 #include <linux/io.h>
 15 #include <linux/kernel.h>
 16 #include <linux/mod_devicetable.h>
 17 #include <linux/module.h>
 18 #include <linux/platform_device.h>
 19 #include <linux/regmap.h>
 20 
 21 #include <sound/soc.h>
 22 #include <sound/soc-dapm.h>
 23 #include <sound/tlv.h>
 24 
 25 #include "sun8i-adda-pr-regmap.h"
 26 
 27 /* Codec analog control register offsets and bit fields */
 28 #define SUN50I_ADDA_HP_CTRL             0x00
 29 #define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE         7
 30 #define SUN50I_ADDA_HP_CTRL_HPPA_EN             6
 31 #define SUN50I_ADDA_HP_CTRL_HPVOL               0
 32 
 33 #define SUN50I_ADDA_OL_MIX_CTRL         0x01
 34 #define SUN50I_ADDA_OL_MIX_CTRL_MIC1            6
 35 #define SUN50I_ADDA_OL_MIX_CTRL_MIC2            5
 36 #define SUN50I_ADDA_OL_MIX_CTRL_PHONE           4
 37 #define SUN50I_ADDA_OL_MIX_CTRL_PHONEN          3
 38 #define SUN50I_ADDA_OL_MIX_CTRL_LINEINL         2
 39 #define SUN50I_ADDA_OL_MIX_CTRL_DACL            1
 40 #define SUN50I_ADDA_OL_MIX_CTRL_DACR            0
 41 
 42 #define SUN50I_ADDA_OR_MIX_CTRL         0x02
 43 #define SUN50I_ADDA_OR_MIX_CTRL_MIC1            6
 44 #define SUN50I_ADDA_OR_MIX_CTRL_MIC2            5
 45 #define SUN50I_ADDA_OR_MIX_CTRL_PHONE           4
 46 #define SUN50I_ADDA_OR_MIX_CTRL_PHONEP          3
 47 #define SUN50I_ADDA_OR_MIX_CTRL_LINEINR         2
 48 #define SUN50I_ADDA_OR_MIX_CTRL_DACR            1
 49 #define SUN50I_ADDA_OR_MIX_CTRL_DACL            0
 50 
 51 #define SUN50I_ADDA_EARPIECE_CTRL0      0x03
 52 #define SUN50I_ADDA_EARPIECE_CTRL0_EAR_RAMP_TIME        4
 53 #define SUN50I_ADDA_EARPIECE_CTRL0_ESPSR                0
 54 
 55 #define SUN50I_ADDA_EARPIECE_CTRL1      0x04
 56 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN     7
 57 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE   6
 58 #define SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL      0
 59 
 60 #define SUN50I_ADDA_LINEOUT_CTRL0       0x05
 61 #define SUN50I_ADDA_LINEOUT_CTRL0_LEN           7
 62 #define SUN50I_ADDA_LINEOUT_CTRL0_REN           6
 63 #define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL      5
 64 #define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL      4
 65 
 66 #define SUN50I_ADDA_LINEOUT_CTRL1       0x06
 67 #define SUN50I_ADDA_LINEOUT_CTRL1_VOL           0
 68 
 69 #define SUN50I_ADDA_MIC1_CTRL           0x07
 70 #define SUN50I_ADDA_MIC1_CTRL_MIC1G             4
 71 #define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN         3
 72 #define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST         0
 73 
 74 #define SUN50I_ADDA_MIC2_CTRL           0x08
 75 #define SUN50I_ADDA_MIC2_CTRL_MIC2G             4
 76 #define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN         3
 77 #define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST         0
 78 
 79 #define SUN50I_ADDA_LINEIN_CTRL         0x09
 80 #define SUN50I_ADDA_LINEIN_CTRL_LINEING         0
 81 
 82 #define SUN50I_ADDA_MIX_DAC_CTRL        0x0a
 83 #define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN        7
 84 #define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN        6
 85 #define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN         5
 86 #define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN         4
 87 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE      3
 88 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE      2
 89 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS          1
 90 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS          0
 91 
 92 #define SUN50I_ADDA_L_ADCMIX_SRC        0x0b
 93 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC1           6
 94 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC2           5
 95 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONE          4
 96 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN         3
 97 #define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL        2
 98 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL         1
 99 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR         0
100 
101 #define SUN50I_ADDA_R_ADCMIX_SRC        0x0c
102 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC1           6
103 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC2           5
104 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONE          4
105 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP         3
106 #define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR        2
107 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR          1
108 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL          0
109 
110 #define SUN50I_ADDA_ADC_CTRL            0x0d
111 #define SUN50I_ADDA_ADC_CTRL_ADCREN             7
112 #define SUN50I_ADDA_ADC_CTRL_ADCLEN             6
113 #define SUN50I_ADDA_ADC_CTRL_ADCG               0
114 
115 #define SUN50I_ADDA_HS_MBIAS_CTRL       0x0e
116 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN    7
117 
118 #define SUN50I_ADDA_MDET_CTRL           0x1c
119 #define SUN50I_ADDA_MDET_CTRL_SELDETADC_FS      4
120 #define SUN50I_ADDA_MDET_CTRL_SELDETADC_DB      2
121 #define SUN50I_ADDA_MDET_CTRL_SELDETADC_BF      0
122 
123 #define SUN50I_ADDA_JACK_MIC_CTRL       0x1d
124 #define SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN     7
125 #define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN    6
126 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN    5
127 #define SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN      4
128 
129 /* mixer controls */
130 static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
131         SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
132                           SUN50I_ADDA_OL_MIX_CTRL,
133                           SUN50I_ADDA_OR_MIX_CTRL,
134                           SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
135         SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
136                           SUN50I_ADDA_OL_MIX_CTRL,
137                           SUN50I_ADDA_OR_MIX_CTRL,
138                           SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
139         SOC_DAPM_DOUBLE_R("Line In Playback Switch",
140                           SUN50I_ADDA_OL_MIX_CTRL,
141                           SUN50I_ADDA_OR_MIX_CTRL,
142                           SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),
143         SOC_DAPM_DOUBLE_R("DAC Playback Switch",
144                           SUN50I_ADDA_OL_MIX_CTRL,
145                           SUN50I_ADDA_OR_MIX_CTRL,
146                           SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
147         SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
148                           SUN50I_ADDA_OL_MIX_CTRL,
149                           SUN50I_ADDA_OR_MIX_CTRL,
150                           SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
151 };
152 
153 /* ADC mixer controls */
154 static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {
155         SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
156                           SUN50I_ADDA_L_ADCMIX_SRC,
157                           SUN50I_ADDA_R_ADCMIX_SRC,
158                           SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
159         SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
160                           SUN50I_ADDA_L_ADCMIX_SRC,
161                           SUN50I_ADDA_R_ADCMIX_SRC,
162                           SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
163         SOC_DAPM_DOUBLE_R("Line In Capture Switch",
164                           SUN50I_ADDA_L_ADCMIX_SRC,
165                           SUN50I_ADDA_R_ADCMIX_SRC,
166                           SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),
167         SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
168                           SUN50I_ADDA_L_ADCMIX_SRC,
169                           SUN50I_ADDA_R_ADCMIX_SRC,
170                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
171         SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
172                           SUN50I_ADDA_L_ADCMIX_SRC,
173                           SUN50I_ADDA_R_ADCMIX_SRC,
174                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
175 };
176 
177 static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,
178                                   -450, 150, 0);
179 static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale,
180         0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
181         1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
182 );
183 
184 static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1);
185 
186 static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale,
187         0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
188         2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
189 );
190 
191 static const DECLARE_TLV_DB_RANGE(sun50i_codec_earpiece_vol_scale,
192         0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
193         2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
194 );
195 
196 /* volume / mute controls */
197 static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
198         SOC_SINGLE_TLV("Headphone Playback Volume",
199                        SUN50I_ADDA_HP_CTRL,
200                        SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,
201                        sun50i_codec_hp_vol_scale),
202 
203         /* Mixer pre-gain */
204         SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
205                        SUN50I_ADDA_MIC1_CTRL_MIC1G,
206                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
207 
208         /* Microphone Amp boost gain */
209         SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,
210                        SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,
211                        sun50i_codec_mic_gain_scale),
212 
213         /* Mixer pre-gain */
214         SOC_SINGLE_TLV("Mic2 Playback Volume",
215                        SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,
216                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
217 
218         /* Microphone Amp boost gain */
219         SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,
220                        SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,
221                        sun50i_codec_mic_gain_scale),
222 
223         /* ADC */
224         SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,
225                        SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,
226                        sun50i_codec_out_mixer_pregain_scale),
227 
228         /* Mixer pre-gain */
229         SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,
230                        SUN50I_ADDA_LINEIN_CTRL_LINEING,
231                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
232 
233         SOC_SINGLE_TLV("Line Out Playback Volume",
234                        SUN50I_ADDA_LINEOUT_CTRL1,
235                        SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
236                        sun50i_codec_lineout_vol_scale),
237 
238         SOC_SINGLE_TLV("Earpiece Playback Volume",
239                        SUN50I_ADDA_EARPIECE_CTRL1,
240                        SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,
241                        sun50i_codec_earpiece_vol_scale),
242 };
243 
244 static const char * const sun50i_codec_hp_src_enum_text[] = {
245         "DAC", "Mixer",
246 };
247 
248 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,
249                             SUN50I_ADDA_MIX_DAC_CTRL,
250                             SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,
251                             SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,
252                             sun50i_codec_hp_src_enum_text);
253 
254 static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
255         SOC_DAPM_ENUM("Headphone Source Playback Route",
256                       sun50i_codec_hp_src_enum),
257 };
258 
259 static const struct snd_kcontrol_new sun50i_codec_hp_switch =
260         SOC_DAPM_DOUBLE("Headphone Playback Switch",
261                         SUN50I_ADDA_MIX_DAC_CTRL,
262                         SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
263                         SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0);
264 
265 static const char * const sun50i_codec_lineout_src_enum_text[] = {
266         "Stereo", "Mono Differential",
267 };
268 
269 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
270                             SUN50I_ADDA_LINEOUT_CTRL0,
271                             SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
272                             SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
273                             sun50i_codec_lineout_src_enum_text);
274 
275 static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
276         SOC_DAPM_ENUM("Line Out Source Playback Route",
277                       sun50i_codec_lineout_src_enum),
278 };
279 
280 static const struct snd_kcontrol_new sun50i_codec_lineout_switch =
281         SOC_DAPM_DOUBLE("Line Out Playback Switch",
282                         SUN50I_ADDA_LINEOUT_CTRL0,
283                         SUN50I_ADDA_LINEOUT_CTRL0_LEN,
284                         SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0);
285 
286 static const char * const sun50i_codec_earpiece_src_enum_text[] = {
287         "DACR", "DACL", "Right Mixer", "Left Mixer",
288 };
289 
290 static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum,
291                             SUN50I_ADDA_EARPIECE_CTRL0,
292                             SUN50I_ADDA_EARPIECE_CTRL0_ESPSR,
293                             sun50i_codec_earpiece_src_enum_text);
294 
295 static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {
296         SOC_DAPM_ENUM("Earpiece Source Playback Route",
297                       sun50i_codec_earpiece_src_enum),
298 };
299 
300 static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {
301         SOC_DAPM_SINGLE("Earpiece Playback Switch",
302                         SUN50I_ADDA_EARPIECE_CTRL1,
303                         SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
304 };
305 
306 static int sun50i_codec_hbias_event(struct snd_soc_dapm_widget *w,
307                                     struct snd_kcontrol *kcontrol, int event)
308 {
309         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
310         u32 value = !!SND_SOC_DAPM_EVENT_ON(event);
311 
312         regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
313                            BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),
314                            value << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);
315 
316         return 0;
317 }
318 
319 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
320         /* DAC */
321         SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
322                          SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),
323         SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
324                          SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),
325         /* ADC */
326         SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,
327                          SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),
328         SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,
329                          SUN50I_ADDA_ADC_CTRL_ADCREN, 0),
330         /*
331          * Due to this component and the codec belonging to separate DAPM
332          * contexts, we need to manually link the above widgets to their
333          * stream widgets at the card level.
334          */
335 
336         SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),
337         SND_SOC_DAPM_MUX("Left Headphone Source",
338                          SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
339         SND_SOC_DAPM_MUX("Right Headphone Source",
340                          SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
341         SND_SOC_DAPM_SWITCH("Left Headphone Switch",
342                             SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
343         SND_SOC_DAPM_SWITCH("Right Headphone Switch",
344                             SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
345         SND_SOC_DAPM_OUT_DRV("Left Headphone Amp",
346                              SND_SOC_NOPM, 0, 0, NULL, 0),
347         SND_SOC_DAPM_OUT_DRV("Right Headphone Amp",
348                              SND_SOC_NOPM, 0, 0, NULL, 0),
349         SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL,
350                              SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
351         SND_SOC_DAPM_OUTPUT("HP"),
352 
353         SND_SOC_DAPM_MUX("Left Line Out Source",
354                          SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
355         SND_SOC_DAPM_MUX("Right Line Out Source",
356                          SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
357         SND_SOC_DAPM_SWITCH("Left Line Out Switch",
358                             SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
359         SND_SOC_DAPM_SWITCH("Right Line Out Switch",
360                             SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
361         SND_SOC_DAPM_OUTPUT("LINEOUT"),
362 
363         SND_SOC_DAPM_MUX("Earpiece Source Playback Route",
364                          SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),
365         SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch",
366                                   SND_SOC_NOPM, 0, 0,
367                                   sun50i_codec_earpiece_switch),
368         SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,
369                              SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),
370         SND_SOC_DAPM_OUTPUT("EARPIECE"),
371 
372         /* Microphone inputs */
373         SND_SOC_DAPM_INPUT("MIC1"),
374 
375         /* Microphone Bias */
376         SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,
377                             SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,
378                             0, NULL, 0),
379 
380         /* Mic input path */
381         SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,
382                          SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),
383 
384         /* Microphone input */
385         SND_SOC_DAPM_INPUT("MIC2"),
386 
387         /* Microphone Bias */
388         SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
389                             SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
390                             0, sun50i_codec_hbias_event,
391                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
392 
393         /* Mic input path */
394         SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
395                          SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),
396 
397         /* Line input */
398         SND_SOC_DAPM_INPUT("LINEIN"),
399 
400         /* Mixers */
401         SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
402                            SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,
403                            sun50i_a64_codec_mixer_controls,
404                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
405         SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
406                            SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
407                            sun50i_a64_codec_mixer_controls,
408                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
409         SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
410                            sun50i_codec_adc_mixer_controls,
411                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
412         SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
413                            sun50i_codec_adc_mixer_controls,
414                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
415 };
416 
417 static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
418         /* Left Mixer Routes */
419         { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
420         { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
421         { "Left Mixer", "Line In Playback Switch", "LINEIN" },
422         { "Left Mixer", "DAC Playback Switch", "Left DAC" },
423         { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
424 
425         /* Right Mixer Routes */
426         { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
427         { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
428         { "Right Mixer", "Line In Playback Switch", "LINEIN" },
429         { "Right Mixer", "DAC Playback Switch", "Right DAC" },
430         { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
431 
432         /* Left ADC Mixer Routes */
433         { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
434         { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
435         { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
436         { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
437         { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
438 
439         /* Right ADC Mixer Routes */
440         { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
441         { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
442         { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
443         { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
444         { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
445 
446         /* ADC Routes */
447         { "Left ADC", NULL, "Left ADC Mixer" },
448         { "Right ADC", NULL, "Right ADC Mixer" },
449 
450         /* Headphone Routes */
451         { "Left Headphone Source", "DAC", "Left DAC" },
452         { "Left Headphone Source", "Mixer", "Left Mixer" },
453         { "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" },
454         { "Left Headphone Amp", NULL, "Left Headphone Switch" },
455         { "Left Headphone Amp", NULL, "Headphone Amp" },
456         { "HP", NULL, "Left Headphone Amp" },
457 
458         { "Right Headphone Source", "DAC", "Right DAC" },
459         { "Right Headphone Source", "Mixer", "Right Mixer" },
460         { "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" },
461         { "Right Headphone Amp", NULL, "Right Headphone Switch" },
462         { "Right Headphone Amp", NULL, "Headphone Amp" },
463         { "HP", NULL, "Right Headphone Amp" },
464 
465         { "Headphone Amp", NULL, "cpvdd" },
466 
467         /* Microphone Routes */
468         { "Mic1 Amplifier", NULL, "MIC1"},
469 
470         /* Microphone Routes */
471         { "Mic2 Amplifier", NULL, "MIC2"},
472 
473         /* Line-out Routes */
474         { "Left Line Out Source", "Stereo", "Left Mixer" },
475         { "Left Line Out Source", "Mono Differential", "Left Mixer" },
476         { "Left Line Out Source", "Mono Differential", "Right Mixer" },
477         { "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" },
478         { "LINEOUT", NULL, "Left Line Out Switch" },
479 
480         { "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" },
481         { "Right Line Out Source", "Stereo", "Right Line Out Switch" },
482         { "Right Line Out Source", "Mono Differential", "Left Line Out Switch" },
483         { "LINEOUT", NULL, "Right Line Out Source" },
484 
485         /* Earpiece Routes */
486         { "Earpiece Source Playback Route", "DACL", "Left DAC" },
487         { "Earpiece Source Playback Route", "DACR", "Right DAC" },
488         { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },
489         { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },
490         { "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" },
491         { "Earpiece Amp", NULL, "Earpiece Switch" },
492         { "EARPIECE", NULL, "Earpiece Amp" },
493 };
494 
495 static int sun50i_a64_codec_set_bias_level(struct snd_soc_component *component,
496                                            enum snd_soc_bias_level level)
497 {
498         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
499         int hbias;
500 
501         switch (level) {
502         case SND_SOC_BIAS_OFF:
503                 regmap_clear_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
504                                    BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
505                                    BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN));
506 
507                 regmap_set_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
508                                 BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
509                 break;
510         case SND_SOC_BIAS_STANDBY:
511                 regmap_clear_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
512                                    BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
513 
514                 hbias = snd_soc_dapm_get_pin_status(dapm, "HBIAS");
515                 regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
516                                    BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
517                                    BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),
518                                    BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
519                                    hbias << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);
520                 break;
521         default:
522                 break;
523         }
524 
525         return 0;
526 }
527 
528 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
529         .controls               = sun50i_a64_codec_controls,
530         .num_controls           = ARRAY_SIZE(sun50i_a64_codec_controls),
531         .dapm_widgets           = sun50i_a64_codec_widgets,
532         .num_dapm_widgets       = ARRAY_SIZE(sun50i_a64_codec_widgets),
533         .dapm_routes            = sun50i_a64_codec_routes,
534         .num_dapm_routes        = ARRAY_SIZE(sun50i_a64_codec_routes),
535         .set_bias_level         = sun50i_a64_codec_set_bias_level,
536         .idle_bias_on           = true,
537         .suspend_bias_off       = true,
538 };
539 
540 static const struct of_device_id sun50i_codec_analog_of_match[] = {
541         {
542                 .compatible = "allwinner,sun50i-a64-codec-analog",
543         },
544         {}
545 };
546 MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);
547 
548 static int sun50i_codec_analog_probe(struct platform_device *pdev)
549 {
550         struct regmap *regmap;
551         void __iomem *base;
552         bool enable;
553 
554         base = devm_platform_ioremap_resource(pdev, 0);
555         if (IS_ERR(base)) {
556                 dev_err(&pdev->dev, "Failed to map the registers\n");
557                 return PTR_ERR(base);
558         }
559 
560         regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
561         if (IS_ERR(regmap)) {
562                 dev_err(&pdev->dev, "Failed to create regmap\n");
563                 return PTR_ERR(regmap);
564         }
565 
566         enable = device_property_read_bool(&pdev->dev,
567                                            "allwinner,internal-bias-resistor");
568         regmap_update_bits(regmap, SUN50I_ADDA_JACK_MIC_CTRL,
569                            BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN),
570                            enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN);
571 
572         /* Select sample interval of the ADC sample to 16ms */
573         regmap_update_bits(regmap, SUN50I_ADDA_MDET_CTRL,
574                            0x7 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |
575                            0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF,
576                            0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |
577                            0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF);
578 
579         return devm_snd_soc_register_component(&pdev->dev,
580                                                &sun50i_codec_analog_cmpnt_drv,
581                                                NULL, 0);
582 }
583 
584 static struct platform_driver sun50i_codec_analog_driver = {
585         .driver = {
586                 .name = "sun50i-codec-analog",
587                 .of_match_table = sun50i_codec_analog_of_match,
588         },
589         .probe = sun50i_codec_analog_probe,
590 };
591 module_platform_driver(sun50i_codec_analog_driver);
592 
593 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");
594 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
595 MODULE_LICENSE("GPL");
596 MODULE_ALIAS("platform:sun50i-codec-analog");
597 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php