1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * stac9766.c -- ALSA SoC STAC9766 codec support
5 * Copyright 2009 Jon Smirl, Digispeaker
6 * Author: Jon Smirl <jonsmirl@gmail.com>
10 * o Support for AC97 Codec, S/PDIF
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/regmap.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/ac97_codec.h>
21 #include <sound/initval.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24 #include <sound/tlv.h>
26 #define STAC9766_VENDOR_ID 0x83847666
27 #define STAC9766_VENDOR_ID_MASK 0xffffffff
29 #define AC97_STAC_DA_CONTROL 0x6A
30 #define AC97_STAC_ANALOG_SPECIAL 0x6E
31 #define AC97_STAC_STEREO_MIC 0x78
33 static const struct reg_default stac9766_reg_defaults
[] = {
65 static const struct regmap_config stac9766_regmap_config
= {
70 .cache_type
= REGCACHE_RBTREE
,
72 .volatile_reg
= regmap_ac97_default_volatile
,
74 .reg_defaults
= stac9766_reg_defaults
,
75 .num_reg_defaults
= ARRAY_SIZE(stac9766_reg_defaults
),
78 static const char *stac9766_record_mux
[] = {"Mic", "CD", "Video", "AUX",
79 "Line", "Stereo Mix", "Mono Mix", "Phone"};
80 static const char *stac9766_mono_mux
[] = {"Mix", "Mic"};
81 static const char *stac9766_mic_mux
[] = {"Mic1", "Mic2"};
82 static const char *stac9766_SPDIF_mux
[] = {"PCM", "ADC Record"};
83 static const char *stac9766_popbypass_mux
[] = {"Normal", "Bypass Mixer"};
84 static const char *stac9766_record_all_mux
[] = {"All analog",
86 static const char *stac9766_boost1
[] = {"0dB", "10dB"};
87 static const char *stac9766_boost2
[] = {"0dB", "20dB"};
88 static const char *stac9766_stereo_mic
[] = {"Off", "On"};
90 static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum
,
91 AC97_REC_SEL
, 8, 0, stac9766_record_mux
);
92 static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum
,
93 AC97_GENERAL_PURPOSE
, 9, stac9766_mono_mux
);
94 static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum
,
95 AC97_GENERAL_PURPOSE
, 8, stac9766_mic_mux
);
96 static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum
,
97 AC97_STAC_DA_CONTROL
, 1, stac9766_SPDIF_mux
);
98 static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum
,
99 AC97_GENERAL_PURPOSE
, 15, stac9766_popbypass_mux
);
100 static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum
,
101 AC97_STAC_ANALOG_SPECIAL
, 12,
102 stac9766_record_all_mux
);
103 static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum
,
104 AC97_MIC
, 6, stac9766_boost1
); /* 0/10dB */
105 static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum
,
106 AC97_STAC_ANALOG_SPECIAL
, 2, stac9766_boost2
); /* 0/20dB */
107 static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum
,
108 AC97_STAC_STEREO_MIC
, 2, stac9766_stereo_mic
);
110 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv
, -4650, 150, 0);
111 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv
, 0, 150, 0);
112 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv
, -4500, 300, 0);
113 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv
, -3450, 150, 0);
115 static const struct snd_kcontrol_new stac9766_snd_ac97_controls
[] = {
116 SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER
, 8, 0, 31, 1, master_tlv
),
117 SOC_SINGLE("Speaker Switch", AC97_MASTER
, 15, 1, 1),
118 SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE
, 8, 0, 31, 1,
120 SOC_SINGLE("Headphone Switch", AC97_HEADPHONE
, 15, 1, 1),
121 SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO
, 0, 31, 1,
123 SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO
, 15, 1, 1),
125 SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN
, 8, 0, 15, 0, record_tlv
),
126 SOC_SINGLE("Record Switch", AC97_REC_GAIN
, 15, 1, 1),
129 SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP
, 1, 15, 1, beep_tlv
),
130 SOC_SINGLE("Beep Switch", AC97_PC_BEEP
, 15, 1, 1),
131 SOC_SINGLE("Beep Frequency", AC97_PC_BEEP
, 5, 127, 1),
132 SOC_SINGLE_TLV("Phone Volume", AC97_PHONE
, 0, 31, 1, mix_tlv
),
133 SOC_SINGLE("Phone Switch", AC97_PHONE
, 15, 1, 1),
135 SOC_ENUM("Mic Boost1", stac9766_boost1_enum
),
136 SOC_ENUM("Mic Boost2", stac9766_boost2_enum
),
137 SOC_SINGLE_TLV("Mic Volume", AC97_MIC
, 0, 31, 1, mix_tlv
),
138 SOC_SINGLE("Mic Switch", AC97_MIC
, 15, 1, 1),
139 SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum
),
141 SOC_DOUBLE_TLV("Line Volume", AC97_LINE
, 8, 0, 31, 1, mix_tlv
),
142 SOC_SINGLE("Line Switch", AC97_LINE
, 15, 1, 1),
143 SOC_DOUBLE_TLV("CD Volume", AC97_CD
, 8, 0, 31, 1, mix_tlv
),
144 SOC_SINGLE("CD Switch", AC97_CD
, 15, 1, 1),
145 SOC_DOUBLE_TLV("AUX Volume", AC97_AUX
, 8, 0, 31, 1, mix_tlv
),
146 SOC_SINGLE("AUX Switch", AC97_AUX
, 15, 1, 1),
147 SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO
, 8, 0, 31, 1, mix_tlv
),
148 SOC_SINGLE("Video Switch", AC97_VIDEO
, 15, 1, 1),
150 SOC_DOUBLE_TLV("DAC Volume", AC97_PCM
, 8, 0, 31, 1, mix_tlv
),
151 SOC_SINGLE("DAC Switch", AC97_PCM
, 15, 1, 1),
152 SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE
, 7, 1, 0),
153 SOC_SINGLE("3D Volume", AC97_3D_CONTROL
, 3, 2, 1),
154 SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE
, 13, 1, 0),
156 SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum
),
157 SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum
),
158 SOC_ENUM("Record All Mux", stac9766_record_all_enum
),
159 SOC_ENUM("Record Mux", stac9766_record_enum
),
160 SOC_ENUM("Mono Mux", stac9766_mono_enum
),
161 SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum
),
164 static int ac97_analog_prepare(struct snd_pcm_substream
*substream
,
165 struct snd_soc_dai
*dai
)
167 struct snd_soc_component
*component
= dai
->component
;
168 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
171 /* enable variable rate audio, disable SPDIF output */
172 snd_soc_component_update_bits(component
, AC97_EXTENDED_STATUS
, 0x5, 0x1);
174 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
175 reg
= AC97_PCM_FRONT_DAC_RATE
;
177 reg
= AC97_PCM_LR_ADC_RATE
;
179 return snd_soc_component_write(component
, reg
, runtime
->rate
);
182 static int ac97_digital_prepare(struct snd_pcm_substream
*substream
,
183 struct snd_soc_dai
*dai
)
185 struct snd_soc_component
*component
= dai
->component
;
186 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
189 snd_soc_component_write(component
, AC97_SPDIF
, 0x2002);
191 /* Enable VRA and SPDIF out */
192 snd_soc_component_update_bits(component
, AC97_EXTENDED_STATUS
, 0x5, 0x5);
194 reg
= AC97_PCM_FRONT_DAC_RATE
;
196 return snd_soc_component_write(component
, reg
, runtime
->rate
);
199 static int stac9766_set_bias_level(struct snd_soc_component
*component
,
200 enum snd_soc_bias_level level
)
203 case SND_SOC_BIAS_ON
: /* full On */
204 case SND_SOC_BIAS_PREPARE
: /* partial On */
205 case SND_SOC_BIAS_STANDBY
: /* Off, with power */
206 snd_soc_component_write(component
, AC97_POWERDOWN
, 0x0000);
208 case SND_SOC_BIAS_OFF
: /* Off, without power */
209 /* disable everything including AC link */
210 snd_soc_component_write(component
, AC97_POWERDOWN
, 0xffff);
216 static int stac9766_component_resume(struct snd_soc_component
*component
)
218 struct snd_ac97
*ac97
= snd_soc_component_get_drvdata(component
);
220 return snd_ac97_reset(ac97
, true, STAC9766_VENDOR_ID
,
221 STAC9766_VENDOR_ID_MASK
);
224 static const struct snd_soc_dai_ops stac9766_dai_ops_analog
= {
225 .prepare
= ac97_analog_prepare
,
228 static const struct snd_soc_dai_ops stac9766_dai_ops_digital
= {
229 .prepare
= ac97_digital_prepare
,
232 static struct snd_soc_dai_driver stac9766_dai
[] = {
234 .name
= "stac9766-hifi-analog",
236 /* stream cababilities */
238 .stream_name
= "stac9766 analog",
241 .rates
= SNDRV_PCM_RATE_8000_48000
,
242 .formats
= SND_SOC_STD_AC97_FMTS
,
245 .stream_name
= "stac9766 analog",
248 .rates
= SNDRV_PCM_RATE_8000_48000
,
249 .formats
= SND_SOC_STD_AC97_FMTS
,
252 .ops
= &stac9766_dai_ops_analog
,
255 .name
= "stac9766-hifi-IEC958",
257 /* stream cababilities */
259 .stream_name
= "stac9766 IEC958",
262 .rates
= SNDRV_PCM_RATE_32000
| \
263 SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
264 .formats
= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE
,
267 .ops
= &stac9766_dai_ops_digital
,
271 static int stac9766_component_probe(struct snd_soc_component
*component
)
273 struct snd_ac97
*ac97
;
274 struct regmap
*regmap
;
277 ac97
= snd_soc_new_ac97_component(component
, STAC9766_VENDOR_ID
,
278 STAC9766_VENDOR_ID_MASK
);
280 return PTR_ERR(ac97
);
282 regmap
= regmap_init_ac97(ac97
, &stac9766_regmap_config
);
283 if (IS_ERR(regmap
)) {
284 ret
= PTR_ERR(regmap
);
288 snd_soc_component_init_regmap(component
, regmap
);
289 snd_soc_component_set_drvdata(component
, ac97
);
293 snd_soc_free_ac97_component(ac97
);
297 static void stac9766_component_remove(struct snd_soc_component
*component
)
299 struct snd_ac97
*ac97
= snd_soc_component_get_drvdata(component
);
301 snd_soc_component_exit_regmap(component
);
302 snd_soc_free_ac97_component(ac97
);
305 static const struct snd_soc_component_driver soc_component_dev_stac9766
= {
306 .controls
= stac9766_snd_ac97_controls
,
307 .num_controls
= ARRAY_SIZE(stac9766_snd_ac97_controls
),
308 .set_bias_level
= stac9766_set_bias_level
,
309 .probe
= stac9766_component_probe
,
310 .remove
= stac9766_component_remove
,
311 .resume
= stac9766_component_resume
,
312 .suspend_bias_off
= 1,
314 .use_pmdown_time
= 1,
316 .non_legacy_dai_naming
= 1,
320 static int stac9766_probe(struct platform_device
*pdev
)
322 return devm_snd_soc_register_component(&pdev
->dev
,
323 &soc_component_dev_stac9766
, stac9766_dai
, ARRAY_SIZE(stac9766_dai
));
326 static struct platform_driver stac9766_codec_driver
= {
328 .name
= "stac9766-codec",
331 .probe
= stac9766_probe
,
334 module_platform_driver(stac9766_codec_driver
);
336 MODULE_DESCRIPTION("ASoC stac9766 driver");
337 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
338 MODULE_LICENSE("GPL");