1 /* best viewed with tabsize 4 */ 2 3 4 #include "ak4531.h" 5 #include "pci_helper.h" 6 7 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 18 19 #define RESET_AND_POWER_DOWN 0x16 20 #define PD 0x02 21 #define RST 0x01 22 23 #define AD_INPUT_SELECT 0x18 24 #define MIC_AMP_GAIN 0x19 25 26 #define MUTE 0x80 27 28 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); 33 34 static u16_t base_address; 35 static u16_t status_register; 36 static u16_t status_bit; 37 static u16_t poll_address; 38 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 */ 44 }; 45 #if 0 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 */ 51 }; 52 #endif 53 54 55 56 static int ak4531_finished(void) { 57 int i; 58 u16_t cstat; 59 for (i = 0; i < 0x40000; i++) { 60 cstat = pci_inw(status_register); 61 if (!(cstat & status_bit)) { 62 return 1; 63 } 64 } 65 return 0; 66 } 67 68 69 static int ak4531_write (u8_t address, u8_t data) { 70 u16_t to_be_written; 71 72 73 if (address > MIC_AMP_GAIN) return -1; 74 75 to_be_written = (u16_t)((address << 8) | data); 76 77 if (!ak4531_finished()) return -1; 78 pci_outw(base_address, to_be_written); 79 return 0; 80 } 81 82 83 int ak4531_init(u16_t base, u16_t status_reg, u16_t bit, 84 u16_t poll) { 85 int i; 86 87 base_address = base; 88 status_register = status_reg; 89 status_bit = bit; 90 poll_address = poll; 91 92 for (i=0; i<100; i++) { 93 pci_inb(poll_address); 94 } 95 if(ak4531_write(RESET_AND_POWER_DOWN, PD|RST) < 0) return -1; 96 97 for (i=0; i<100; i++) { 98 pci_inb(poll_address); 99 } 100 101 ak4531_write(AD_INPUT_SELECT, 0x00); 102 103 for (i = MASTER_VOLUME_LCH ; i <= MIC_AMP_GAIN; i++) { 104 if (ak4531_write(i, mixer_values[i]) < 0) return -1; 105 } 106 return 0; 107 } 108 109 110 int ak4531_get_set_volume(struct volume_level *level, int flag) { 111 int cmd_left, cmd_right, max_level; 112 113 max_level = 0x1f; 114 115 switch(level->device) { 116 case Master: 117 cmd_left = MASTER_VOLUME_LCH; 118 cmd_right = MASTER_VOLUME_RCH; 119 break; 120 case Dac: 121 return EINVAL; 122 break; 123 case Fm: 124 cmd_left = FM_VOLUME_LCH; 125 cmd_right = FM_VOLUME_RCH; 126 break; 127 case Cd: 128 cmd_left = CD_AUDIO_VOLUME_LCH; 129 cmd_right = CD_AUDIO_VOLUME_RCH; 130 break; 131 case Line: 132 cmd_left = LINE_VOLUME_LCH; 133 cmd_right = LINE_VOLUME_RCH; 134 break; 135 case Mic: 136 cmd_left = cmd_right = MIC_VOLUME; 137 break; 138 case Speaker: 139 cmd_left = cmd_right = MONO_OUT_VOLUME; 140 max_level = 0x03; 141 break; 142 case Treble: 143 return EINVAL; 144 break; 145 case Bass: 146 return EINVAL; 147 break; 148 default: 149 return EINVAL; 150 } 151 152 if (flag) { /* set volume */ 153 return set_volume(level, cmd_left, cmd_right, max_level); 154 } 155 else { /* get volume */ 156 level->left = - ((int) (mixer_values[cmd_left] & ~MUTE)) + 0x1f; 157 level->right = - ((int) (mixer_values[cmd_right] & ~MUTE)) + 0x1f; 158 return OK; 159 } 160 } 161 162 163 static int set_volume(struct volume_level *level, int cmd_left, int cmd_right, 164 int max_level) { 165 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; 170 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]); 175 176 return OK; 177 } 178