aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/isa/wss/wss_lib.c133
1 files changed, 69 insertions, 64 deletions
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 866e8686dbe7..011da7a2315d 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -1147,79 +1147,84 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst
1147 1147
1148static int snd_ad1848_probe(struct snd_wss *chip) 1148static int snd_ad1848_probe(struct snd_wss *chip)
1149{ 1149{
1150 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
1150 unsigned long flags; 1151 unsigned long flags;
1151 int i, id, rev, ad1847; 1152 unsigned char r;
1153 unsigned short hardware = 0;
1154 int err = 0;
1155 int i;
1152 1156
1153 id = 0; 1157 while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
1154 ad1847 = 0; 1158 if (time_after(jiffies, timeout))
1155 for (i = 0; i < 1000; i++) { 1159 return -ENODEV;
1156 mb(); 1160 cond_resched();
1157 if (inb(chip->port + CS4231P(REGSEL)) & CS4231_INIT)
1158 msleep(1);
1159 else {
1160 spin_lock_irqsave(&chip->reg_lock, flags);
1161 snd_wss_out(chip, CS4231_MISC_INFO, 0x00);
1162 snd_wss_out(chip, CS4231_LEFT_INPUT, 0xaa);
1163 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x45);
1164 rev = snd_wss_in(chip, CS4231_RIGHT_INPUT);
1165 if (rev == 0x65) {
1166 spin_unlock_irqrestore(&chip->reg_lock, flags);
1167 id = 1;
1168 ad1847 = 1;
1169 break;
1170 }
1171 if (rev == 0x45) {
1172 rev = snd_wss_in(chip, CS4231_LEFT_INPUT);
1173 if (rev == 0xaa || rev == 0x8a) {
1174 spin_unlock_irqrestore(&chip->reg_lock, flags);
1175 id = 1;
1176 break;
1177 }
1178 }
1179 spin_unlock_irqrestore(&chip->reg_lock, flags);
1180 }
1181 } 1161 }
1182 if (id != 1)
1183 return -ENODEV; /* no valid device found */
1184 id = 0;
1185 if (chip->hardware == WSS_HW_DETECT)
1186 id = ad1847 ? WSS_HW_AD1847 : WSS_HW_AD1848;
1187
1188 spin_lock_irqsave(&chip->reg_lock, flags); 1162 spin_lock_irqsave(&chip->reg_lock, flags);
1189 inb(chip->port + CS4231P(STATUS)); /* clear any pendings IRQ */ 1163
1190 outb(0, chip->port + CS4231P(STATUS)); 1164 /* set CS423x MODE 1 */
1191 mb(); 1165 snd_wss_out(chip, CS4231_MISC_INFO, 0);
1192 if (id == WSS_HW_AD1848) { 1166
1193 /* check if there are more than 16 registers */ 1167 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */
1194 rev = snd_wss_in(chip, CS4231_MISC_INFO); 1168 r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
1195 snd_wss_out(chip, CS4231_MISC_INFO, 0x40); 1169 if (r != 0x45) {
1196 for (i = 0; i < 16; ++i) { 1170 /* RMGE always high on AD1847 */
1197 if (snd_wss_in(chip, i) != snd_wss_in(chip, i + 16)) { 1171 if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
1198 id = WSS_HW_CMI8330; 1172 err = -ENODEV;
1199 break; 1173 goto out;
1200 } 1174 }
1175 hardware = WSS_HW_AD1847;
1176 } else {
1177 snd_wss_out(chip, CS4231_LEFT_INPUT, 0xaa);
1178 r = snd_wss_in(chip, CS4231_LEFT_INPUT);
1179 /* L/RMGE always low on AT2320 */
1180 if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
1181 err = -ENODEV;
1182 goto out;
1201 } 1183 }
1202 snd_wss_out(chip, CS4231_MISC_INFO, 0x00);
1203 if (id != WSS_HW_CMI8330 && (rev & 0x80))
1204 id = WSS_HW_CS4248;
1205 if (id == WSS_HW_CMI8330 && (rev & 0x0f) != 0x0a)
1206 id = 0;
1207 } 1184 }
1208 if (id == WSS_HW_CMI8330) { 1185
1209 /* verify it is not CS4231 by changing the version register */ 1186 /* clear pending IRQ */
1210 /* on CMI8330 it is volume control register and can be set 0 */ 1187 wss_inb(chip, CS4231P(STATUS));
1211 snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); 1188 wss_outb(chip, CS4231P(STATUS), 0);
1212 snd_wss_dout(chip, CS4231_VERSION, 0x00); 1189 mb();
1213 rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; 1190
1214 if (rev) 1191 if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
1215 id = 0; 1192 goto out;
1216 snd_wss_out(chip, CS4231_MISC_INFO, 0); 1193
1194 if (hardware) {
1195 chip->hardware = hardware;
1196 goto out;
1217 } 1197 }
1218 if (id)
1219 chip->hardware = id;
1220 1198
1199 r = snd_wss_in(chip, CS4231_MISC_INFO);
1200
1201 /* set CS423x MODE 2 */
1202 snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
1203 for (i = 0; i < 16; i++) {
1204 if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) {
1205 /* we have more than 16 registers: check ID */
1206 if ((r & 0xf) != 0xa)
1207 goto out_mode;
1208 /*
1209 * on CMI8330, CS4231_VERSION is volume control and
1210 * can be set to 0
1211 */
1212 snd_wss_dout(chip, CS4231_VERSION, 0);
1213 r = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
1214 if (!r)
1215 chip->hardware = WSS_HW_CMI8330;
1216 goto out_mode;
1217 }
1218 }
1219 if (r & 0x80)
1220 chip->hardware = WSS_HW_CS4248;
1221 else
1222 chip->hardware = WSS_HW_AD1848;
1223out_mode:
1224 snd_wss_out(chip, CS4231_MISC_INFO, 0);
1225out:
1221 spin_unlock_irqrestore(&chip->reg_lock, flags); 1226 spin_unlock_irqrestore(&chip->reg_lock, flags);
1222 return 0; /* all things are ok.. */ 1227 return err;
1223} 1228}
1224 1229
1225static int snd_wss_probe(struct snd_wss *chip) 1230static int snd_wss_probe(struct snd_wss *chip)