1 /* best viewed with tabsize 4 */
5 #include "pci_helper.h"
8 #define MASTER_VOLUME_LCH 0x00
9 #define MASTER_VOLUME_RCH 0x01
10 #define FM_VOLUME_LCH 0x04
11 #define FM_VOLUME_RCH 0x05
12 #define CD_AUDIO_VOLUME_LCH 0x06
13 #define CD_AUDIO_VOLUME_RCH 0x07
14 #define LINE_VOLUME_LCH 0x08
15 #define LINE_VOLUME_RCH 0x09
16 #define MIC_VOLUME 0x0e
17 #define MONO_OUT_VOLUME 0x0f
19 #define RESET_AND_POWER_DOWN 0x16
23 #define AD_INPUT_SELECT 0x18
24 #define MIC_AMP_GAIN 0x19
29 static int ak4531_write(u8_t address
, u8_t data
);
30 static int ak4531_finished(void);
31 static int set_volume(struct volume_level
*level
, int cmd_left
, int
32 cmd_right
, int max_level
);
34 static u16_t base_address
;
35 static u16_t status_register
;
36 static u16_t status_bit
;
37 static u16_t poll_address
;
39 u8_t mixer_values
[0x20] = {
40 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
41 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, /* 0x08 - 0x0f */
42 0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, /* 0x10 - 0x17 */
43 0x00, 0x01 /* 0x18 - 0x19 */
46 u8_t mixer_values
[0x20] = {
47 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
48 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x08 - 0x0f */
49 0x7f, 0x3d, 0x55, 0x26, 0xf7, 0xef, 0x03, 0x00, /* 0x10 - 0x17 */
50 0x00, 0x01 /* 0x18 - 0x19 */
56 static int ak4531_finished(void) {
59 for (i
= 0; i
< 0x40000; i
++) {
60 cstat
= pci_inw(status_register
);
61 if (!(cstat
& status_bit
)) {
69 static int ak4531_write (u8_t address
, u8_t data
) {
73 if (address
> MIC_AMP_GAIN
) return -1;
75 to_be_written
= (u16_t
)((address
<< 8) | data
);
77 if (!ak4531_finished()) return -1;
78 pci_outw(base_address
, to_be_written
);
83 int ak4531_init(u16_t base
, u16_t status_reg
, u16_t bit
,
88 status_register
= status_reg
;
92 for (i
=0; i
<100; i
++) {
93 pci_inb(poll_address
);
95 if(ak4531_write(RESET_AND_POWER_DOWN
, PD
|RST
) < 0) return -1;
97 for (i
=0; i
<100; i
++) {
98 pci_inb(poll_address
);
101 ak4531_write(AD_INPUT_SELECT
, 0x00);
103 for (i
= MASTER_VOLUME_LCH
; i
<= MIC_AMP_GAIN
; i
++) {
104 if (ak4531_write(i
, mixer_values
[i
]) < 0) return -1;
110 int ak4531_get_set_volume(struct volume_level
*level
, int flag
) {
111 int cmd_left
, cmd_right
, max_level
;
115 switch(level
->device
) {
117 cmd_left
= MASTER_VOLUME_LCH
;
118 cmd_right
= MASTER_VOLUME_RCH
;
124 cmd_left
= FM_VOLUME_LCH
;
125 cmd_right
= FM_VOLUME_RCH
;
128 cmd_left
= CD_AUDIO_VOLUME_LCH
;
129 cmd_right
= CD_AUDIO_VOLUME_RCH
;
132 cmd_left
= LINE_VOLUME_LCH
;
133 cmd_right
= LINE_VOLUME_RCH
;
136 cmd_left
= cmd_right
= MIC_VOLUME
;
139 cmd_left
= cmd_right
= MONO_OUT_VOLUME
;
152 if (flag
) { /* set volume */
153 return set_volume(level
, cmd_left
, cmd_right
, max_level
);
155 else { /* get volume */
156 level
->left
= - ((int) (mixer_values
[cmd_left
] & ~MUTE
)) + 0x1f;
157 level
->right
= - ((int) (mixer_values
[cmd_right
] & ~MUTE
)) + 0x1f;
163 static int set_volume(struct volume_level
*level
, int cmd_left
, int cmd_right
,
166 if(level
->right
< 0) level
->right
= 0;
167 else if(level
->right
> max_level
) level
->right
= max_level
;
168 if(level
->left
< 0) level
->left
= 0;
169 else if(level
->left
> max_level
) level
->left
= max_level
;
171 mixer_values
[cmd_left
] = (-level
->left
)+0x1f;
172 ak4531_write(cmd_left
, mixer_values
[cmd_left
]);
173 mixer_values
[cmd_right
] = (-level
->right
)+0x1f;
174 ak4531_write(cmd_right
, mixer_values
[cmd_right
]);