summaryrefslogtreecommitdiff
path: root/sound/hda/codecs/realtek/realtek.h
blob: ee893da0c486a63dc975e625799e372e770512da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Realtek HD-audio codec support code
//

#ifndef __HDA_REALTEK_H
#define __HDA_REALTEK_H

#include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/ctype.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
#include "../generic.h"
#include "../side-codecs/hda_component.h"

/* extra amp-initialization sequence types */
enum {
	ALC_INIT_UNDEFINED,
	ALC_INIT_NONE,
	ALC_INIT_DEFAULT,
};

enum {
	ALC_HEADSET_MODE_UNKNOWN,
	ALC_HEADSET_MODE_UNPLUGGED,
	ALC_HEADSET_MODE_HEADSET,
	ALC_HEADSET_MODE_MIC,
	ALC_HEADSET_MODE_HEADPHONE,
};

enum {
	ALC_HEADSET_TYPE_UNKNOWN,
	ALC_HEADSET_TYPE_CTIA,
	ALC_HEADSET_TYPE_OMTP,
};

enum {
	ALC_KEY_MICMUTE_INDEX,
};

struct alc_customize_define {
	unsigned int  sku_cfg;
	unsigned char port_connectivity;
	unsigned char check_sum;
	unsigned char customization;
	unsigned char external_amp;
	unsigned int  enable_pcbeep:1;
	unsigned int  platform_type:1;
	unsigned int  swap:1;
	unsigned int  override:1;
	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
};

struct alc_coef_led {
	unsigned int idx;
	unsigned int mask;
	unsigned int on;
	unsigned int off;
};

struct alc_spec {
	struct hda_gen_spec gen; /* must be at head */

	/* codec parameterization */
	struct alc_customize_define cdefine;
	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */

	/* GPIO bits */
	unsigned int gpio_mask;
	unsigned int gpio_dir;
	unsigned int gpio_data;
	bool gpio_write_delay;	/* add a delay before writing gpio_data */

	/* mute LED for HP laptops, see vref_mute_led_set() */
	int mute_led_polarity;
	int micmute_led_polarity;
	hda_nid_t mute_led_nid;
	hda_nid_t cap_mute_led_nid;

	unsigned int gpio_mute_led_mask;
	unsigned int gpio_mic_led_mask;
	struct alc_coef_led mute_led_coef;
	struct alc_coef_led mic_led_coef;
	struct mutex coef_mutex;

	hda_nid_t headset_mic_pin;
	hda_nid_t headphone_mic_pin;
	int current_headset_mode;
	int current_headset_type;

	/* hooks */
	void (*init_hook)(struct hda_codec *codec);
	void (*power_hook)(struct hda_codec *codec);
	void (*shutup)(struct hda_codec *codec);

	int init_amp;
	int codec_variant;	/* flag for other variants */
	unsigned int has_alc5505_dsp:1;
	unsigned int no_depop_delay:1;
	unsigned int done_hp_init:1;
	unsigned int no_shutup_pins:1;
	unsigned int ultra_low_power:1;
	unsigned int has_hs_key:1;
	unsigned int no_internal_mic_pin:1;
	unsigned int en_3kpull_low:1;
	int num_speaker_amps;

	/* for PLL fix */
	hda_nid_t pll_nid;
	unsigned int pll_coef_idx, pll_coef_bit;
	unsigned int coef0;
	struct input_dev *kb_dev;
	u8 alc_mute_keycode_map[1];

	/* component binding */
	struct hda_component_parent comps;
};

int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
			unsigned int coef_idx);
void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
			  unsigned int coef_idx, unsigned int coef_val);
void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
			   unsigned int coef_idx, unsigned int mask,
			   unsigned int bits_set);
#define alc_read_coef_idx(codec, coef_idx) \
	alc_read_coefex_idx(codec, 0x20, coef_idx)
#define alc_write_coef_idx(codec, coef_idx, coef_val) \
	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)

unsigned int alc_get_coef0(struct hda_codec *codec);

/* coef writes/updates batch */
struct coef_fw {
	unsigned char nid;
	unsigned char idx;
	unsigned short mask;
	unsigned short val;
};

#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)

void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw);

/*
 * GPIO helpers
 */
void alc_setup_gpio(struct hda_codec *codec, unsigned int mask);
void alc_write_gpio_data(struct hda_codec *codec);
void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
			  bool on);
void alc_write_gpio(struct hda_codec *codec);

/* common GPIO fixups */
void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask);
void alc_fixup_gpio1(struct hda_codec *codec,
		     const struct hda_fixup *fix, int action);
void alc_fixup_gpio2(struct hda_codec *codec,
		     const struct hda_fixup *fix, int action);
void alc_fixup_gpio3(struct hda_codec *codec,
		     const struct hda_fixup *fix, int action);
void alc_fixup_gpio4(struct hda_codec *codec,
		     const struct hda_fixup *fix, int action);
void alc_fixup_micmute_led(struct hda_codec *codec,
			   const struct hda_fixup *fix, int action);

/*
 * Common init code, callbacks and helpers
 */
void alc_fix_pll(struct hda_codec *codec);
void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
		      unsigned int coef_idx, unsigned int coef_bit);
void alc_fill_eapd_coef(struct hda_codec *codec);
void alc_auto_setup_eapd(struct hda_codec *codec, bool on);

int alc_find_ext_mic_pin(struct hda_codec *codec);
void alc_headset_mic_no_shutup(struct hda_codec *codec);
void alc_shutup_pins(struct hda_codec *codec);
void alc_eapd_shutup(struct hda_codec *codec);
void alc_auto_init_amp(struct hda_codec *codec, int type);
hda_nid_t alc_get_hp_pin(struct alc_spec *spec);
int alc_auto_parse_customize_define(struct hda_codec *codec);
int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports);
void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports);
int alc_build_controls(struct hda_codec *codec);
void alc_update_knob_master(struct hda_codec *codec,
			    struct hda_jack_callback *jack);

static inline void alc_pre_init(struct hda_codec *codec)
{
	alc_fill_eapd_coef(codec);
}

#define is_s3_resume(codec) \
	((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
#define is_s4_resume(codec) \
	((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
#define is_s4_suspend(codec) \
	((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)

int alc_init(struct hda_codec *codec);
void alc_shutup(struct hda_codec *codec);
void alc_power_eapd(struct hda_codec *codec);
int alc_suspend(struct hda_codec *codec);
int alc_resume(struct hda_codec *codec);

int alc_parse_auto_config(struct hda_codec *codec,
			  const hda_nid_t *ignore_nids,
			  const hda_nid_t *ssid_nids);
int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid);

#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)

#ifdef CONFIG_SND_HDA_INPUT_BEEP
int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir);
int alc_has_cdefine_beep(struct hda_codec *codec);
#define set_beep_amp		alc_set_beep_amp
#define has_cdefine_beep	alc_has_cdefine_beep
#else
#define set_beep_amp(spec, nid, idx, dir)	0
#define has_cdefine_beep(codec)		0
#endif

static inline void rename_ctl(struct hda_codec *codec, const char *oldname,
			      const char *newname)
{
	struct snd_kcontrol *kctl;

	kctl = snd_hda_find_mixer_ctl(codec, oldname);
	if (kctl)
		snd_ctl_rename(codec->card, kctl, newname);
}

/* Common fixups */
void alc_fixup_sku_ignore(struct hda_codec *codec,
			  const struct hda_fixup *fix, int action);
void alc_fixup_no_depop_delay(struct hda_codec *codec,
			      const struct hda_fixup *fix, int action);
void alc_fixup_inv_dmic(struct hda_codec *codec,
			const struct hda_fixup *fix, int action);
void alc_fixup_dual_codecs(struct hda_codec *codec,
			   const struct hda_fixup *fix, int action);
void alc_fixup_bass_chmap(struct hda_codec *codec,
			  const struct hda_fixup *fix, int action);
void alc_fixup_headset_mode(struct hda_codec *codec,
			    const struct hda_fixup *fix, int action);
void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
				      const struct hda_fixup *fix, int action);
void alc_fixup_headset_mic(struct hda_codec *codec,
			   const struct hda_fixup *fix, int action);
void alc_update_headset_jack_cb(struct hda_codec *codec,
				struct hda_jack_callback *jack);
void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
			 int polarity, bool enabled);
void alc_fixup_hp_gpio_led(struct hda_codec *codec,
			   int action,
			   unsigned int mute_mask,
			   unsigned int micmute_mask);
void alc_fixup_no_jack_detect(struct hda_codec *codec,
			      const struct hda_fixup *fix, int action);
void alc_fixup_disable_aamix(struct hda_codec *codec,
			     const struct hda_fixup *fix, int action);
void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
				 const struct hda_fixup *fix, int action);

/* device-specific, but used by multiple codec drivers */
void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
				  const struct hda_fixup *fix,
				  int action);
void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
					    const struct hda_fixup *fix,
					    int action);
void alc_fixup_dell_xps13(struct hda_codec *codec,
			  const struct hda_fixup *fix, int action);

#endif /* __HDA_REALTEK_H */