xref: /minix3/minix/drivers/audio/trident/mixer.c (revision eecf6d233de53b7d1fcaf6fbe895fee40cef7299)
1*eecf6d23SJia-Ju Bai #include "mixer.h"
2*eecf6d23SJia-Ju Bai 
3*eecf6d23SJia-Ju Bai #ifdef MIXER_AK4531
4*eecf6d23SJia-Ju Bai u8_t mixer_value[] = {
5*eecf6d23SJia-Ju Bai 	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
6*eecf6d23SJia-Ju Bai 	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
7*eecf6d23SJia-Ju Bai 	0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00,
8*eecf6d23SJia-Ju Bai 	0x00, 0x01
9*eecf6d23SJia-Ju Bai };
get_set_volume(u32_t * base,struct volume_level * level,int flag)10*eecf6d23SJia-Ju Bai int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
11*eecf6d23SJia-Ju Bai 	int max_level, cmd_left, cmd_right;
12*eecf6d23SJia-Ju Bai 
13*eecf6d23SJia-Ju Bai 	max_level = 0x1f;
14*eecf6d23SJia-Ju Bai 	/* Check device */
15*eecf6d23SJia-Ju Bai 	switch (level->device) {
16*eecf6d23SJia-Ju Bai 		case Master:
17*eecf6d23SJia-Ju Bai 			cmd_left = MASTER_VOLUME_LCH;
18*eecf6d23SJia-Ju Bai 			cmd_right = MASTER_VOLUME_RCH;
19*eecf6d23SJia-Ju Bai 			break;
20*eecf6d23SJia-Ju Bai 		case Dac:
21*eecf6d23SJia-Ju Bai 			return EINVAL;
22*eecf6d23SJia-Ju Bai 		case Fm:
23*eecf6d23SJia-Ju Bai 			cmd_left = FM_VOLUME_LCH;
24*eecf6d23SJia-Ju Bai 			cmd_right = FM_VOLUME_RCH;
25*eecf6d23SJia-Ju Bai 			break;
26*eecf6d23SJia-Ju Bai 		case Cd:
27*eecf6d23SJia-Ju Bai 			cmd_left = CD_AUDIO_VOLUME_LCH;
28*eecf6d23SJia-Ju Bai 			cmd_right = CD_AUDIO_VOLUME_RCH;
29*eecf6d23SJia-Ju Bai 			break;
30*eecf6d23SJia-Ju Bai 		case Line:
31*eecf6d23SJia-Ju Bai 			cmd_left = LINE_VOLUME_LCH;
32*eecf6d23SJia-Ju Bai 			cmd_right = LINE_VOLUME_RCH;
33*eecf6d23SJia-Ju Bai 			break;
34*eecf6d23SJia-Ju Bai 		case Mic:
35*eecf6d23SJia-Ju Bai 			cmd_left = cmd_right = MIC_VOLUME;
36*eecf6d23SJia-Ju Bai 			break;
37*eecf6d23SJia-Ju Bai 		case Speaker:
38*eecf6d23SJia-Ju Bai 			cmd_left = cmd_right = MONO_OUT_VOLUME;
39*eecf6d23SJia-Ju Bai 			max_level = 0x03;
40*eecf6d23SJia-Ju Bai 			break;
41*eecf6d23SJia-Ju Bai 		case Treble:
42*eecf6d23SJia-Ju Bai 			return EINVAL;
43*eecf6d23SJia-Ju Bai 		case Bass:
44*eecf6d23SJia-Ju Bai 			return EINVAL;
45*eecf6d23SJia-Ju Bai 		default:
46*eecf6d23SJia-Ju Bai 			return EINVAL;
47*eecf6d23SJia-Ju Bai 	}
48*eecf6d23SJia-Ju Bai 	/* Set volume */
49*eecf6d23SJia-Ju Bai 	if (flag) {
50*eecf6d23SJia-Ju Bai 		if (level->right < 0)
51*eecf6d23SJia-Ju Bai 			level->right = 0;
52*eecf6d23SJia-Ju Bai 		else if (level->right > max_level)
53*eecf6d23SJia-Ju Bai 			level->right = max_level;
54*eecf6d23SJia-Ju Bai 		if (level->left < 0)
55*eecf6d23SJia-Ju Bai 			level->left = 0;
56*eecf6d23SJia-Ju Bai 		else if (level->left > max_level)
57*eecf6d23SJia-Ju Bai 			level->left = max_level;
58*eecf6d23SJia-Ju Bai 		/* ### WRITE_MIXER_REG ### */
59*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, cmd_left, 0x1f - level->left);
60*eecf6d23SJia-Ju Bai 		/* ### WRITE_MIXER_REG ### */
61*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, cmd_right, 0x1f - level->right);
62*eecf6d23SJia-Ju Bai 		mixer_value[cmd_left] = 0x1f - level->left;
63*eecf6d23SJia-Ju Bai 		mixer_value[cmd_right] = 0x1f - level->right;
64*eecf6d23SJia-Ju Bai 	}
65*eecf6d23SJia-Ju Bai 	/* Get volume (mixer register can not be read in ak4531 codec) */
66*eecf6d23SJia-Ju Bai 	else {
67*eecf6d23SJia-Ju Bai 		/* ### READ_MIXER_REG ### */
68*eecf6d23SJia-Ju Bai 		dev_mixer_read(base, cmd_left);
69*eecf6d23SJia-Ju Bai 		/* ### READ_MIXER_REG ### */
70*eecf6d23SJia-Ju Bai 		dev_mixer_read(base, cmd_right);
71*eecf6d23SJia-Ju Bai 		level->left = 0x1f - mixer_value[cmd_left];
72*eecf6d23SJia-Ju Bai 		level->right = 0x1f - mixer_value[cmd_right];
73*eecf6d23SJia-Ju Bai 	}
74*eecf6d23SJia-Ju Bai 	return OK;
75*eecf6d23SJia-Ju Bai }
76*eecf6d23SJia-Ju Bai #endif
77*eecf6d23SJia-Ju Bai 
78*eecf6d23SJia-Ju Bai #ifdef MIXER_SB16
get_set_volume(u32_t * base,struct volume_level * level,int flag)79*eecf6d23SJia-Ju Bai int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
80*eecf6d23SJia-Ju Bai 	int max_level, shift, cmd_left, cmd_right;
81*eecf6d23SJia-Ju Bai 
82*eecf6d23SJia-Ju Bai 	max_level = 0x0f;
83*eecf6d23SJia-Ju Bai 	shift = 4;
84*eecf6d23SJia-Ju Bai 	/* Check device */
85*eecf6d23SJia-Ju Bai 	switch (level->device) {
86*eecf6d23SJia-Ju Bai 		case Master:
87*eecf6d23SJia-Ju Bai 			cmd_left = SB16_MASTER_LEFT;
88*eecf6d23SJia-Ju Bai 			cmd_right = SB16_MASTER_RIGHT;
89*eecf6d23SJia-Ju Bai 			break;
90*eecf6d23SJia-Ju Bai 		case Dac:
91*eecf6d23SJia-Ju Bai 			cmd_left = SB16_DAC_LEFT;
92*eecf6d23SJia-Ju Bai 			cmd_right = SB16_DAC_RIGHT;
93*eecf6d23SJia-Ju Bai 			break;
94*eecf6d23SJia-Ju Bai 		case Fm:
95*eecf6d23SJia-Ju Bai 			cmd_left = SB16_FM_LEFT;
96*eecf6d23SJia-Ju Bai 			cmd_right = SB16_FM_RIGHT;
97*eecf6d23SJia-Ju Bai 			break;
98*eecf6d23SJia-Ju Bai 		case Cd:
99*eecf6d23SJia-Ju Bai 			cmd_left = SB16_CD_LEFT;
100*eecf6d23SJia-Ju Bai 			cmd_right = SB16_CD_RIGHT;
101*eecf6d23SJia-Ju Bai 			break;
102*eecf6d23SJia-Ju Bai 		case Line:
103*eecf6d23SJia-Ju Bai 			cmd_left = SB16_LINE_LEFT;
104*eecf6d23SJia-Ju Bai 			cmd_left = SB16_LINE_RIGHT;
105*eecf6d23SJia-Ju Bai 			break;
106*eecf6d23SJia-Ju Bai 		case Mic:
107*eecf6d23SJia-Ju Bai 			cmd_left = cmd_right = SB16_MIC_LEVEL;
108*eecf6d23SJia-Ju Bai 			break;
109*eecf6d23SJia-Ju Bai 		case Speaker:
110*eecf6d23SJia-Ju Bai 			cmd_left = cmd_right = SB16_PC_LEVEL;
111*eecf6d23SJia-Ju Bai 			shift = 6;
112*eecf6d23SJia-Ju Bai 			max_level = 0x03;
113*eecf6d23SJia-Ju Bai 			break;
114*eecf6d23SJia-Ju Bai 		case Treble:
115*eecf6d23SJia-Ju Bai 			cmd_left = SB16_TREBLE_LEFT;
116*eecf6d23SJia-Ju Bai 			cmd_right = SB16_TREBLE_RIGHT;
117*eecf6d23SJia-Ju Bai 			shift = 4;
118*eecf6d23SJia-Ju Bai 			max_level = 0x0f;
119*eecf6d23SJia-Ju Bai 			break;
120*eecf6d23SJia-Ju Bai 		case Bass:
121*eecf6d23SJia-Ju Bai 			cmd_left = SB16_BASS_LEFT;
122*eecf6d23SJia-Ju Bai 			cmd_right = SB16_BASS_RIGHT;
123*eecf6d23SJia-Ju Bai 			shift = 4;
124*eecf6d23SJia-Ju Bai 			max_level = 0x0f;
125*eecf6d23SJia-Ju Bai 			break;
126*eecf6d23SJia-Ju Bai 		default:
127*eecf6d23SJia-Ju Bai 			return EINVAL;
128*eecf6d23SJia-Ju Bai 	}
129*eecf6d23SJia-Ju Bai 	/* Set volume */
130*eecf6d23SJia-Ju Bai 	if (flag) {
131*eecf6d23SJia-Ju Bai 		if (level->right < 0)
132*eecf6d23SJia-Ju Bai 			level->right = 0;
133*eecf6d23SJia-Ju Bai 		else if (level->right > max_level)
134*eecf6d23SJia-Ju Bai 			level->right = max_level;
135*eecf6d23SJia-Ju Bai 		if (level->left < 0)
136*eecf6d23SJia-Ju Bai 			level->left = 0;
137*eecf6d23SJia-Ju Bai 		else if (level->left > max_level)
138*eecf6d23SJia-Ju Bai 			level->left = max_level;
139*eecf6d23SJia-Ju Bai 		/* ### WRITE_MIXER_REG ### */
140*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, cmd_left, level->left << shift);
141*eecf6d23SJia-Ju Bai 		/* ### WRITE_MIXER_REG ### */
142*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, cmd_right, level->right << shift);
143*eecf6d23SJia-Ju Bai 	}
144*eecf6d23SJia-Ju Bai 	/* Get volume */
145*eecf6d23SJia-Ju Bai 	else {
146*eecf6d23SJia-Ju Bai 		/* ### READ_MIXER_REG ### */
147*eecf6d23SJia-Ju Bai 		level->left = dev_mixer_read(base, cmd_left);
148*eecf6d23SJia-Ju Bai 		/* ### READ_MIXER_REG ### */
149*eecf6d23SJia-Ju Bai 		level->right = dev_mixer_read(base, cmd_right);
150*eecf6d23SJia-Ju Bai 		level->left >>= shift;
151*eecf6d23SJia-Ju Bai 		level->right >>= shift;
152*eecf6d23SJia-Ju Bai 	}
153*eecf6d23SJia-Ju Bai 	return OK;
154*eecf6d23SJia-Ju Bai }
155*eecf6d23SJia-Ju Bai #endif
156*eecf6d23SJia-Ju Bai 
157*eecf6d23SJia-Ju Bai #ifdef MIXER_AC97
get_set_volume(u32_t * base,struct volume_level * level,int flag)158*eecf6d23SJia-Ju Bai int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
159*eecf6d23SJia-Ju Bai 	int max_level, cmd, data;
160*eecf6d23SJia-Ju Bai 
161*eecf6d23SJia-Ju Bai 	max_level = 0x1f;
162*eecf6d23SJia-Ju Bai 	/* Check device */
163*eecf6d23SJia-Ju Bai 	switch (level->device) {
164*eecf6d23SJia-Ju Bai 		case Master:
165*eecf6d23SJia-Ju Bai 			cmd = AC97_MASTER_VOLUME;
166*eecf6d23SJia-Ju Bai 			break;
167*eecf6d23SJia-Ju Bai 		case Dac:
168*eecf6d23SJia-Ju Bai 			return EINVAL;
169*eecf6d23SJia-Ju Bai 		case Fm:
170*eecf6d23SJia-Ju Bai 			cmd = AC97_PCM_OUT_VOLUME;
171*eecf6d23SJia-Ju Bai 			break;
172*eecf6d23SJia-Ju Bai 		case Cd:
173*eecf6d23SJia-Ju Bai 			cmd = AC97_CD_VOLUME;
174*eecf6d23SJia-Ju Bai 			break;
175*eecf6d23SJia-Ju Bai 		case Line:
176*eecf6d23SJia-Ju Bai 			cmd = AC97_LINE_IN_VOLUME;
177*eecf6d23SJia-Ju Bai 			break;
178*eecf6d23SJia-Ju Bai 		case Mic:
179*eecf6d23SJia-Ju Bai 			cmd = AC97_MIC_VOLUME;
180*eecf6d23SJia-Ju Bai 			break;
181*eecf6d23SJia-Ju Bai 		case Speaker:
182*eecf6d23SJia-Ju Bai 			return EINVAL;
183*eecf6d23SJia-Ju Bai 		case Treble:
184*eecf6d23SJia-Ju Bai 			return EINVAL;
185*eecf6d23SJia-Ju Bai 		case Bass:
186*eecf6d23SJia-Ju Bai 			return EINVAL;
187*eecf6d23SJia-Ju Bai 		default:
188*eecf6d23SJia-Ju Bai 			return EINVAL;
189*eecf6d23SJia-Ju Bai 	}
190*eecf6d23SJia-Ju Bai 	/* Set volume */
191*eecf6d23SJia-Ju Bai 	if (flag) {
192*eecf6d23SJia-Ju Bai 		if (level->right < 0)
193*eecf6d23SJia-Ju Bai 			level->right = 0;
194*eecf6d23SJia-Ju Bai 		else if (level->right > max_level)
195*eecf6d23SJia-Ju Bai 			level->right = max_level;
196*eecf6d23SJia-Ju Bai 		if (level->left < 0)
197*eecf6d23SJia-Ju Bai 			level->left = 0;
198*eecf6d23SJia-Ju Bai 		else if (level->left > max_level)
199*eecf6d23SJia-Ju Bai 			level->left = max_level;
200*eecf6d23SJia-Ju Bai 		data = (max_level - level->left) << 8 | (max_level - level->right);
201*eecf6d23SJia-Ju Bai 		/* ### WRITE_MIXER_REG ### */
202*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, cmd, data);
203*eecf6d23SJia-Ju Bai 	}
204*eecf6d23SJia-Ju Bai 	/* Get volume */
205*eecf6d23SJia-Ju Bai 	else {
206*eecf6d23SJia-Ju Bai 		/* ### READ_MIXER_REG ### */
207*eecf6d23SJia-Ju Bai 		data = dev_mixer_read(base, cmd);
208*eecf6d23SJia-Ju Bai 		level->left = (u16_t)(data >> 8);
209*eecf6d23SJia-Ju Bai 		level->right = (u16_t)(data & 0xff);
210*eecf6d23SJia-Ju Bai 		if (level->right < 0)
211*eecf6d23SJia-Ju Bai 			level->right = 0;
212*eecf6d23SJia-Ju Bai 		else if (level->right > max_level)
213*eecf6d23SJia-Ju Bai 			level->right = max_level;
214*eecf6d23SJia-Ju Bai 		if (level->left < 0)
215*eecf6d23SJia-Ju Bai 			level->left = 0;
216*eecf6d23SJia-Ju Bai 		else if (level->left > max_level)
217*eecf6d23SJia-Ju Bai 			level->left = max_level;
218*eecf6d23SJia-Ju Bai 		level->left = max_level - level->left;
219*eecf6d23SJia-Ju Bai 		level->right = max_level - level->right;
220*eecf6d23SJia-Ju Bai 	}
221*eecf6d23SJia-Ju Bai 	return OK;
222*eecf6d23SJia-Ju Bai }
223*eecf6d23SJia-Ju Bai #endif
224*eecf6d23SJia-Ju Bai 
225*eecf6d23SJia-Ju Bai /* Set default mixer volume */
dev_set_default_volume(u32_t * base)226*eecf6d23SJia-Ju Bai void dev_set_default_volume(u32_t *base) {
227*eecf6d23SJia-Ju Bai 	int i;
228*eecf6d23SJia-Ju Bai #ifdef MIXER_AK4531
229*eecf6d23SJia-Ju Bai 	for (i = 0; i <= 0x19; i++)
230*eecf6d23SJia-Ju Bai 		dev_mixer_write(base, i, mixer_value[i]);
231*eecf6d23SJia-Ju Bai #endif
232*eecf6d23SJia-Ju Bai #ifdef MIXER_SB16
233*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_MASTER_LEFT, 0x18 << 3);
234*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_MASTER_RIGHT, 0x18 << 3);
235*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_DAC_LEFT, 0x0f << 4);
236*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_DAC_RIGHT, 0x0f << 4);
237*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_FM_LEFT, 0x08 << 4);
238*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_FM_RIGHT, 0x08 << 4);
239*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_CD_LEFT, 0x08 << 4);
240*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_CD_RIGHT, 0x08 << 4);
241*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_LINE_LEFT, 0x08 << 4);
242*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_LINE_RIGHT, 0x08 << 4);
243*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_MIC_LEVEL, 0x0f << 4);
244*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_PC_LEVEL, 0x02 << 6);
245*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_TREBLE_LEFT, 0x08 << 4);
246*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_TREBLE_RIGHT, 0x08 << 4);
247*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_BASS_LEFT, 0x08 << 4);
248*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, SB16_BASS_RIGHT, 0x08 << 4);
249*eecf6d23SJia-Ju Bai #endif
250*eecf6d23SJia-Ju Bai 
251*eecf6d23SJia-Ju Bai #ifdef MIXER_AC97
252*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_POWERDOWN, 0x0000);
253*eecf6d23SJia-Ju Bai 	for (i = 0; i < 50000; i++) {
254*eecf6d23SJia-Ju Bai 		if (dev_mixer_read(base, AC97_POWERDOWN) & 0x03)
255*eecf6d23SJia-Ju Bai 			break;
256*eecf6d23SJia-Ju Bai 		micro_delay(100);
257*eecf6d23SJia-Ju Bai 	}
258*eecf6d23SJia-Ju Bai 	if (i == 50000)
259*eecf6d23SJia-Ju Bai 		printf("SDR: AC97 is not ready\n");
260*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_MASTER_VOLUME, 0x0000);
261*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_MONO_VOLUME, 0x8000);
262*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_PHONE_VOLUME, 0x8008);
263*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_MIC_VOLUME, 0x0000);
264*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_LINE_IN_VOLUME, 0x0303);
265*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_CD_VOLUME, 0x0808);
266*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_AUX_IN_VOLUME, 0x0808);
267*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_PCM_OUT_VOLUME, 0x0808);
268*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_RECORD_GAIN_VOLUME, 0x0000);
269*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_RECORD_SELECT, 0x0000);
270*eecf6d23SJia-Ju Bai 	dev_mixer_write(base, AC97_GENERAL_PURPOSE, 0x0000);
271*eecf6d23SJia-Ju Bai #endif
272*eecf6d23SJia-Ju Bai }
273