Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 151761 | Differences between
and this patch

Collapse All | Expand All

(-)a/Documentation/ALSA-Configuration.txt (+3 lines)
Lines 865-870 Prior to version 0.9.0rc4 options had a Link Here
865
	  laptop	3-jack with hp-jack automute
865
	  laptop	3-jack with hp-jack automute
866
	  laptop-dig	ditto with SPDIF
866
	  laptop-dig	ditto with SPDIF
867
	  auto		auto-config reading BIOS (default)
867
	  auto		auto-config reading BIOS (default)
868
	
869
	Conexant
870
	  laptop	Laptop config with SPDIF
868
871
869
	STAC9200/9205/9220/9221/9254
872
	STAC9200/9205/9220/9221/9254
870
	  ref		Reference board
873
	  ref		Reference board
(-)a/pci/hda/Makefile (-1 / +1 lines)
Lines 1-5 snd-hda-intel-objs := hda_intel.o Link Here
1
snd-hda-intel-objs := hda_intel.o
1
snd-hda-intel-objs := hda_intel.o
2
snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
2
snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o patch_conexant.o
3
ifdef CONFIG_PROC_FS
3
ifdef CONFIG_PROC_FS
4
snd-hda-codec-objs += hda_proc.o
4
snd-hda-codec-objs += hda_proc.o
5
endif
5
endif
(-)a/pci/hda/hda_patch.h (+3 lines)
Lines 14-19 extern struct hda_codec_preset snd_hda_p Link Here
14
extern struct hda_codec_preset snd_hda_preset_si3054[];
14
extern struct hda_codec_preset snd_hda_preset_si3054[];
15
/* ATI HDMI codecs */
15
/* ATI HDMI codecs */
16
extern struct hda_codec_preset snd_hda_preset_atihdmi[];
16
extern struct hda_codec_preset snd_hda_preset_atihdmi[];
17
/* Conexant audio codec */
18
extern struct hda_codec_preset snd_hda_preset_conexant[];
17
19
18
static const struct hda_codec_preset *hda_preset_tables[] = {
20
static const struct hda_codec_preset *hda_preset_tables[] = {
19
	snd_hda_preset_realtek,
21
	snd_hda_preset_realtek,
Lines 22-26 static const struct hda_codec_preset *hd Link Here
22
	snd_hda_preset_sigmatel,
24
	snd_hda_preset_sigmatel,
23
	snd_hda_preset_si3054,
25
	snd_hda_preset_si3054,
24
	snd_hda_preset_atihdmi,
26
	snd_hda_preset_atihdmi,
27
	snd_hda_preset_conexant,
25
	NULL
28
	NULL
26
};
29
};
(-) (+420 lines)
Added Link Here
1
/*
2
 * HD audio interface patch for Conexant HDA audio codec
3
 *
4
 * Copyright (c) 2006 Pototskiy Alex <alex.pototskiy@gmail.com>
5
 *
6
 *  This driver is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This driver is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19
 */
20
21
#include <sound/driver.h>
22
#include <linux/init.h>
23
#include <linux/delay.h>
24
#include <linux/slab.h>
25
#include <linux/pci.h>
26
#include <sound/core.h>
27
#include "hda_codec.h"
28
#include "hda_local.h"
29
30
#define MAIN_MUX	0x1A
31
#define DAC		0x10
32
#define ADC		0x12
33
#define SPDIF_OUT	0x11
34
35
struct conexant_spec {
36
37
	struct snd_kcontrol_new *mixers[5];
38
	int num_mixers;
39
40
	const struct hda_verb *init_verbs[5];	/* initialization verbs
41
						 * don't forget NULL termination!
42
						 */
43
	unsigned int num_init_verbs;
44
45
	/* playback */
46
	struct hda_multi_out multiout;	/* playback set-up
47
					 * max_channels, dacs must be set
48
					 * dig_out_nid and hp_nid are optional
49
					 */
50
	/* capture */
51
	unsigned int num_adc_nids;
52
	hda_nid_t *adc_nids;
53
	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
54
55
	/* capture source */
56
	const struct hda_input_mux *input_mux;
57
	hda_nid_t *capsrc_nids;
58
	unsigned int cur_mux[3];
59
60
	/* channel model */
61
	const struct hda_channel_mode *channel_mode;
62
	int num_channel_mode;
63
64
	/* PCM information */
65
	struct hda_pcm pcm_rec[2];	/* used in alc_build_pcms() */
66
67
	struct mutex amp_mutex;	/* PCM volume/mute control mutex */
68
	unsigned int spdif_route;
69
70
	/* dynamic controls, init_verbs and input_mux */
71
	struct auto_pin_cfg autocfg;
72
	unsigned int num_kctl_alloc, num_kctl_used;
73
	struct snd_kcontrol_new *kctl_alloc;
74
	struct hda_input_mux private_imux;
75
	hda_nid_t private_dac_nids[4];
76
77
};
78
79
static hda_nid_t conexant_dac_nids[1] = { DAC };
80
static hda_nid_t conexant_adc_nids[1] = { ADC };
81
static hda_nid_t conexant_capsrc_nids[1] = { 0x19 };
82
83
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
84
				    struct hda_codec *codec,
85
				    struct snd_pcm_substream *substream)
86
{
87
	struct conexant_spec *spec = codec->spec;
88
	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
89
}
90
91
static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
92
				       struct hda_codec *codec,
93
				       unsigned int stream_tag,
94
				       unsigned int format,
95
				       struct snd_pcm_substream *substream)
96
{
97
	struct conexant_spec *spec = codec->spec;
98
	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
99
						format, substream);
100
}
101
102
static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
103
				       struct hda_codec *codec,
104
				       struct snd_pcm_substream *substream)
105
{
106
	struct conexant_spec *spec = codec->spec;
107
	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
108
}
109
110
/*
111
 * Digital out
112
 */
113
static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
114
					struct hda_codec *codec,
115
					struct snd_pcm_substream *substream)
116
{
117
	struct conexant_spec *spec = codec->spec;
118
	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
119
}
120
121
static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
122
					 struct hda_codec *codec,
123
					 struct snd_pcm_substream *substream)
124
{
125
	struct conexant_spec *spec = codec->spec;
126
	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
127
}
128
129
/*
130
 * Analog capture
131
 */
132
static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
133
				      struct hda_codec *codec,
134
				      unsigned int stream_tag,
135
				      unsigned int format,
136
				      struct snd_pcm_substream *substream)
137
{
138
	struct conexant_spec *spec = codec->spec;
139
	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
140
				   stream_tag, 0, format);
141
	return 0;
142
}
143
144
static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
145
				      struct hda_codec *codec,
146
				      struct snd_pcm_substream *substream)
147
{
148
	struct conexant_spec *spec = codec->spec;
149
	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
150
				   0, 0, 0);
151
	return 0;
152
}
153
154
155
156
static struct hda_pcm_stream conexant_pcm_analog_playback = {
157
	.substreams = 1,
158
	.channels_min = 2,
159
	.channels_max = 2,
160
	.nid = 0, /* fill later */
161
	.ops = {
162
		.open = conexant_playback_pcm_open,
163
		.prepare = conexant_playback_pcm_prepare,
164
		.cleanup = conexant_playback_pcm_cleanup
165
	},
166
167
};
168
169
static struct hda_pcm_stream conexant_pcm_analog_capture = {
170
	.substreams = 1,
171
	.channels_min = 2,
172
	.channels_max = 2,
173
	.nid = 0, /* fill later */
174
	.ops = {
175
		.prepare = conexant_capture_pcm_prepare,
176
		.cleanup = conexant_capture_pcm_cleanup
177
	},
178
179
};
180
181
182
static struct hda_pcm_stream conexant_pcm_digital_playback = {
183
	.substreams = 1,
184
	.channels_min = 2,
185
	.channels_max = 2,
186
	.nid = 0, /* fill later */
187
	.ops = {
188
		.open = conexant_dig_playback_pcm_open,
189
		.close = conexant_dig_playback_pcm_close
190
	},
191
};
192
193
static struct hda_pcm_stream conexant_pcm_digital_capture = {
194
	.substreams = 1,
195
	.channels_min = 2,
196
	.channels_max = 2,
197
	/* NID is set in alc_build_pcms */
198
};
199
200
static int conexant_build_pcms(struct hda_codec *codec) {
201
	struct conexant_spec *spec = codec->spec;
202
	struct hda_pcm *info = spec->pcm_rec;
203
204
	codec->num_pcms = 1;
205
	codec->pcm_info = info;
206
207
	info->name = "CONEXANT Analog";
208
	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
209
	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
210
	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
211
	info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
212
	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
213
	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
214
215
	if (spec->multiout.dig_out_nid) {
216
		info++;
217
		codec->num_pcms++;
218
		info->name = "Conexant Digital";
219
		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_digital_playback;
220
		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
221
		if (spec->dig_in_nid) {
222
			info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_digital_capture;
223
			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
224
		}
225
	}
226
227
	return 0;
228
}
229
/*   */
230
static struct hda_input_mux conexant_capture_source = {
231
	.num_items = 4,
232
	.items = {
233
		{ "ExtMic", 0x1 },
234
		{ "IntMic", 0x2 },
235
		{ "Line", 0x3 },
236
		{ "CD", 0x4 }
237
	}
238
};
239
240
static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
241
{
242
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
243
	struct conexant_spec *spec = codec->spec;
244
245
	return snd_hda_input_mux_info(spec->input_mux, uinfo);
246
}
247
248
static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
249
{
250
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
251
	struct conexant_spec *spec = codec->spec;
252
	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
253
254
	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
255
	return 0;
256
}
257
258
static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
259
{
260
	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
261
	struct conexant_spec *spec = codec->spec;
262
	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
263
264
	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
265
				     spec->capsrc_nids[adc_idx],
266
				     &spec->cur_mux[adc_idx]);
267
}
268
269
270
static struct snd_kcontrol_new conexant_mixers[] = {
271
	{
272
	  .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
273
	  .name = "Capture Source",
274
	  .info = conexant_mux_enum_info,
275
	  .get = conexant_mux_enum_get,
276
	  .put = conexant_mux_enum_put
277
	},
278
	HDA_CODEC_VOLUME("Mic Bypass Capture Volume",0x19,0x02,HDA_INPUT),
279
	HDA_CODEC_MUTE("Mic Bypass Capture Switch",0x19,0x02,HDA_INPUT),
280
	HDA_CODEC_VOLUME("Capture Volume",0x12,0x03,HDA_INPUT),
281
	HDA_CODEC_MUTE("Capture Switch",0x12,0x03,HDA_INPUT),
282
	HDA_CODEC_VOLUME("PCM Volume",0x10,0x00,HDA_OUTPUT),
283
	HDA_CODEC_MUTE("PCM Switch",0x10,0x00,HDA_OUTPUT),
284
	HDA_CODEC_VOLUME("Headphone Playback Volume",0x13,0x00,HDA_OUTPUT),
285
	HDA_CODEC_MUTE("Headphone Playback Switch",0x13,0x00,HDA_OUTPUT),
286
	{}
287
};
288
289
static int conexant_build_controls(struct hda_codec *codec) {
290
	struct conexant_spec *spec = codec->spec;
291
	unsigned int i;
292
	int err;
293
294
	for (i = 0; i < spec->num_mixers; i++) {
295
		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
296
		if (err < 0)
297
			return err;
298
	}
299
	if (spec->multiout.dig_out_nid) {
300
		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
301
		if (err < 0)
302
			return err;
303
	} 
304
	if (spec->dig_in_nid) {
305
		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
306
		if (err < 0)
307
			return err;
308
	}
309
	return 0;
310
}
311
312
static struct hda_verb conexant_init_verbs[] = {
313
	/* Line in, Mic, Built-in Mic */
314
	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
315
	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
316
	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
317
	/* HP, Amp  */
318
	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
319
	{0x1A, AC_VERB_SET_CONNECT_SEL,0x01},
320
	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
321
	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
322
	/* Record selector: Front mic */
323
	{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
324
	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
325
	/* SPDIF route: PCM */
326
	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
327
	{ } /* end */
328
};
329
330
static int conexant_init(struct hda_codec *codec) {
331
	struct conexant_spec *spec = codec->spec;
332
	int i;
333
334
	for (i = 0; i < spec->num_init_verbs; i++)
335
		snd_hda_sequence_write(codec, spec->init_verbs[i]);
336
	return 0;
337
}
338
339
static void conexant_free(struct hda_codec *codec) {
340
        struct conexant_spec *spec = codec->spec;
341
        unsigned int i;
342
343
        if (spec->kctl_alloc) {
344
                for (i = 0; i < spec->num_kctl_used; i++)
345
                        kfree(spec->kctl_alloc[i].name);
346
                kfree(spec->kctl_alloc);
347
        }
348
349
	kfree(codec->spec);
350
}
351
352
#ifdef CONFIG_PM
353
static int conexant_resume(struct hda_codec *codec)
354
{
355
	struct conexant_spec *spec = codec->spec;
356
	int i;
357
358
	codec->patch_ops.init(codec);
359
	for (i = 0; i < spec->num_mixers; i++)
360
		snd_hda_resume_ctls(codec, spec->mixers[i]);
361
	if (spec->multiout.dig_out_nid)
362
		snd_hda_resume_spdif_out(codec);
363
	if (spec->dig_in_nid)
364
		snd_hda_resume_spdif_in(codec);
365
	return 0;
366
}
367
#endif
368
369
static struct hda_codec_ops conexant_patch_ops = {
370
	.build_controls = conexant_build_controls,
371
	.build_pcms = conexant_build_pcms,
372
	.init = conexant_init,
373
	.free = conexant_free,
374
#ifdef CONFIG_PM
375
	.resume = conexant_resume,
376
#endif
377
};
378
379
enum { CONEXANT_LAPTOP };
380
381
static struct hda_board_config conexant_cfg_tbl[] = {
382
	{ .modelname = "laptop", .config = CONEXANT_LAPTOP },
383
	{}
384
};
385
386
static int patch_conexant(struct hda_codec *codec) {
387
	struct conexant_spec *spec;
388
	int board_config;
389
390
	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
391
	if ( !spec )
392
		return -ENOMEM;
393
	mutex_init(&spec->amp_mutex);
394
	codec->spec = spec;
395
396
	spec->multiout.max_channels = 2;
397
	spec->multiout.num_dacs = ARRAY_SIZE(conexant_dac_nids);
398
	spec->multiout.dac_nids = conexant_dac_nids;
399
	spec->multiout.dig_out_nid = SPDIF_OUT;
400
	spec->num_adc_nids = 1;
401
	spec->adc_nids = conexant_adc_nids;
402
	spec->capsrc_nids = conexant_capsrc_nids;
403
	spec->input_mux = &conexant_capture_source;
404
	spec->num_mixers = 1;
405
	spec->mixers[0] = conexant_mixers;
406
	spec->num_init_verbs = 1;
407
	spec->init_verbs[0] = conexant_init_verbs;
408
	spec->spdif_route = 0;
409
410
	codec->patch_ops = conexant_patch_ops;
411
	/* Place holder for different board configurations */
412
	board_config = snd_hda_check_board_config(codec, conexant_cfg_tbl);
413
	
414
	return 0;
415
}
416
417
struct hda_codec_preset snd_hda_preset_conexant[] = {
418
	{ .id = 0x14f15047, .name = "CONEXANT", .patch = patch_conexant },
419
	{} /* terminator */
420
};

Return to bug 151761