diff options
Diffstat (limited to 'sound/isa/cs423x/cs4231_lib.c')
-rw-r--r-- | sound/isa/cs423x/cs4231_lib.c | 115 |
1 files changed, 53 insertions, 62 deletions
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 914d77b61b0c..a5eb9659b519 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
3 | * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips | 3 | * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips |
4 | * | 4 | * |
5 | * Bugs: | 5 | * Bugs: |
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/dma.h> | 39 | #include <asm/dma.h> |
40 | #include <asm/irq.h> | 40 | #include <asm/irq.h> |
41 | 41 | ||
42 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 42 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
43 | MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); | 43 | MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); |
44 | MODULE_LICENSE("GPL"); | 44 | MODULE_LICENSE("GPL"); |
45 | 45 | ||
@@ -74,7 +74,7 @@ static unsigned int rates[14] = { | |||
74 | }; | 74 | }; |
75 | 75 | ||
76 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | 76 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { |
77 | .count = 14, | 77 | .count = ARRAY_SIZE(rates), |
78 | .list = rates, | 78 | .list = rates, |
79 | .mask = 0, | 79 | .mask = 0, |
80 | }; | 80 | }; |
@@ -134,29 +134,31 @@ static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset) | |||
134 | return inb(chip->port + offset); | 134 | return inb(chip->port + offset); |
135 | } | 135 | } |
136 | 136 | ||
137 | static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, | 137 | static void snd_cs4231_wait(struct snd_cs4231 *chip) |
138 | unsigned char mask, unsigned char value) | ||
139 | { | 138 | { |
140 | int timeout; | 139 | int timeout; |
141 | unsigned char tmp; | ||
142 | 140 | ||
143 | for (timeout = 250; | 141 | for (timeout = 250; |
144 | timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); | 142 | timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); |
145 | timeout--) | 143 | timeout--) |
146 | udelay(100); | 144 | udelay(100); |
145 | } | ||
146 | |||
147 | static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, | ||
148 | unsigned char mask, unsigned char value) | ||
149 | { | ||
150 | unsigned char tmp = (chip->image[reg] & mask) | value; | ||
151 | |||
152 | snd_cs4231_wait(chip); | ||
147 | #ifdef CONFIG_SND_DEBUG | 153 | #ifdef CONFIG_SND_DEBUG |
148 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 154 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) |
149 | snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); | 155 | snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); |
150 | #endif | 156 | #endif |
151 | if (chip->calibrate_mute) { | 157 | chip->image[reg] = tmp; |
152 | chip->image[reg] &= mask; | 158 | if (!chip->calibrate_mute) { |
153 | chip->image[reg] |= value; | ||
154 | } else { | ||
155 | cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); | 159 | cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); |
156 | mb(); | 160 | wmb(); |
157 | tmp = (chip->image[reg] & mask) | value; | ||
158 | cs4231_outb(chip, CS4231P(REG), tmp); | 161 | cs4231_outb(chip, CS4231P(REG), tmp); |
159 | chip->image[reg] = tmp; | ||
160 | mb(); | 162 | mb(); |
161 | } | 163 | } |
162 | } | 164 | } |
@@ -176,12 +178,7 @@ static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned | |||
176 | 178 | ||
177 | void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) | 179 | void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) |
178 | { | 180 | { |
179 | int timeout; | 181 | snd_cs4231_wait(chip); |
180 | |||
181 | for (timeout = 250; | ||
182 | timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); | ||
183 | timeout--) | ||
184 | udelay(100); | ||
185 | #ifdef CONFIG_SND_DEBUG | 182 | #ifdef CONFIG_SND_DEBUG |
186 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 183 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) |
187 | snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); | 184 | snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); |
@@ -190,19 +187,13 @@ void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char va | |||
190 | cs4231_outb(chip, CS4231P(REG), value); | 187 | cs4231_outb(chip, CS4231P(REG), value); |
191 | chip->image[reg] = value; | 188 | chip->image[reg] = value; |
192 | mb(); | 189 | mb(); |
193 | #if 0 | 190 | snd_printdd("codec out - reg 0x%x = 0x%x\n", |
194 | printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); | 191 | chip->mce_bit | reg, value); |
195 | #endif | ||
196 | } | 192 | } |
197 | 193 | ||
198 | unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) | 194 | unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) |
199 | { | 195 | { |
200 | int timeout; | 196 | snd_cs4231_wait(chip); |
201 | |||
202 | for (timeout = 250; | ||
203 | timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); | ||
204 | timeout--) | ||
205 | udelay(100); | ||
206 | #ifdef CONFIG_SND_DEBUG | 197 | #ifdef CONFIG_SND_DEBUG |
207 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 198 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) |
208 | snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); | 199 | snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); |
@@ -304,8 +295,7 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) | |||
304 | unsigned long flags; | 295 | unsigned long flags; |
305 | int timeout; | 296 | int timeout; |
306 | 297 | ||
307 | for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) | 298 | snd_cs4231_wait(chip); |
308 | udelay(100); | ||
309 | #ifdef CONFIG_SND_DEBUG | 299 | #ifdef CONFIG_SND_DEBUG |
310 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 300 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) |
311 | snd_printk("mce_up - auto calibration time out (0)\n"); | 301 | snd_printk("mce_up - auto calibration time out (0)\n"); |
@@ -323,12 +313,11 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) | |||
323 | void snd_cs4231_mce_down(struct snd_cs4231 *chip) | 313 | void snd_cs4231_mce_down(struct snd_cs4231 *chip) |
324 | { | 314 | { |
325 | unsigned long flags; | 315 | unsigned long flags; |
316 | unsigned long end_time; | ||
326 | int timeout; | 317 | int timeout; |
327 | 318 | ||
328 | snd_cs4231_busy_wait(chip); | 319 | snd_cs4231_busy_wait(chip); |
329 | #if 0 | 320 | |
330 | printk("(1) timeout = %i\n", timeout); | ||
331 | #endif | ||
332 | #ifdef CONFIG_SND_DEBUG | 321 | #ifdef CONFIG_SND_DEBUG |
333 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 322 | if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) |
334 | snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); | 323 | snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); |
@@ -346,42 +335,42 @@ void snd_cs4231_mce_down(struct snd_cs4231 *chip) | |||
346 | } | 335 | } |
347 | snd_cs4231_busy_wait(chip); | 336 | snd_cs4231_busy_wait(chip); |
348 | 337 | ||
349 | /* calibration process */ | 338 | /* |
339 | * Wait for (possible -- during init auto-calibration may not be set) | ||
340 | * calibration process to start. Needs upto 5 sample periods on AD1848 | ||
341 | * which at the slowest possible rate of 5.5125 kHz means 907 us. | ||
342 | */ | ||
343 | msleep(1); | ||
350 | 344 | ||
351 | for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) | 345 | snd_printdd("(1) jiffies = %lu\n", jiffies); |
352 | udelay(10); | 346 | |
353 | if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { | 347 | /* check condition up to 250 ms */ |
354 | snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); | 348 | end_time = jiffies + msecs_to_jiffies(250); |
355 | return; | 349 | while (snd_cs4231_in(chip, CS4231_TEST_INIT) & |
356 | } | 350 | CS4231_CALIB_IN_PROGRESS) { |
357 | #if 0 | 351 | |
358 | printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); | 352 | if (time_after(jiffies, end_time)) { |
359 | #endif | 353 | snd_printk(KERN_ERR "mce_down - " |
360 | /* in 10 ms increments, check condition, up to 250 ms */ | 354 | "auto calibration time out (2)\n"); |
361 | timeout = 25; | ||
362 | while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { | ||
363 | if (--timeout < 0) { | ||
364 | snd_printk("mce_down - auto calibration time out (2)\n"); | ||
365 | return; | 355 | return; |
366 | } | 356 | } |
367 | msleep(10); | 357 | msleep(1); |
368 | } | 358 | } |
369 | #if 0 | 359 | |
370 | printk("(3) jiffies = %li\n", jiffies); | 360 | snd_printdd("(2) jiffies = %lu\n", jiffies); |
371 | #endif | 361 | |
372 | /* in 10 ms increments, check condition, up to 100 ms */ | 362 | /* check condition up to 100 ms */ |
373 | timeout = 10; | 363 | end_time = jiffies + msecs_to_jiffies(100); |
374 | while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { | 364 | while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { |
375 | if (--timeout < 0) { | 365 | if (time_after(jiffies, end_time)) { |
376 | snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); | 366 | snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); |
377 | return; | 367 | return; |
378 | } | 368 | } |
379 | msleep(10); | 369 | msleep(1); |
380 | } | 370 | } |
381 | #if 0 | 371 | |
382 | printk("(4) jiffies = %li\n", jiffies); | 372 | snd_printdd("(3) jiffies = %lu\n", jiffies); |
383 | snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); | 373 | snd_printd("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); |
384 | #endif | ||
385 | } | 374 | } |
386 | 375 | ||
387 | static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) | 376 | static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) |
@@ -459,11 +448,11 @@ static unsigned char snd_cs4231_get_rate(unsigned int rate) | |||
459 | { | 448 | { |
460 | int i; | 449 | int i; |
461 | 450 | ||
462 | for (i = 0; i < 14; i++) | 451 | for (i = 0; i < ARRAY_SIZE(rates); i++) |
463 | if (rate == rates[i]) | 452 | if (rate == rates[i]) |
464 | return freq_bits[i]; | 453 | return freq_bits[i]; |
465 | // snd_BUG(); | 454 | // snd_BUG(); |
466 | return freq_bits[13]; | 455 | return freq_bits[ARRAY_SIZE(rates) - 1]; |
467 | } | 456 | } |
468 | 457 | ||
469 | static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, | 458 | static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, |
@@ -555,6 +544,8 @@ static void snd_cs4231_playback_format(struct snd_cs4231 *chip, | |||
555 | snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr); | 544 | snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr); |
556 | } | 545 | } |
557 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 546 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
547 | if (chip->hardware == CS4231_HW_OPL3SA2) | ||
548 | udelay(100); /* this seems to help */ | ||
558 | snd_cs4231_mce_down(chip); | 549 | snd_cs4231_mce_down(chip); |
559 | } | 550 | } |
560 | snd_cs4231_calibrate_mute(chip, 0); | 551 | snd_cs4231_calibrate_mute(chip, 0); |