1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
4 | * Lee Revell <rlrevell@joe-job.com> |
5 | * James Courtier-Dutton <James@superbug.co.uk> |
6 | * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> |
7 | * Creative Labs, Inc. |
8 | * |
9 | * Routines for control of EMU10K1 chips |
10 | */ |
11 | |
12 | #include <linux/time.h> |
13 | #include <sound/core.h> |
14 | #include <sound/emu10k1.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/export.h> |
17 | #include "p17v.h" |
18 | |
19 | static inline bool check_ptr_reg(struct snd_emu10k1 *emu, unsigned int reg) |
20 | { |
21 | if (snd_BUG_ON(!emu)) |
22 | return false; |
23 | if (snd_BUG_ON(reg & (emu->audigy ? (0xffff0000 & ~A_PTR_ADDRESS_MASK) |
24 | : (0xffff0000 & ~PTR_ADDRESS_MASK)))) |
25 | return false; |
26 | if (snd_BUG_ON(reg & 0x0000ffff & ~PTR_CHANNELNUM_MASK)) |
27 | return false; |
28 | return true; |
29 | } |
30 | |
31 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) |
32 | { |
33 | unsigned long flags; |
34 | unsigned int regptr, val; |
35 | unsigned int mask; |
36 | |
37 | regptr = (reg << 16) | chn; |
38 | if (!check_ptr_reg(emu, reg: regptr)) |
39 | return 0; |
40 | |
41 | spin_lock_irqsave(&emu->emu_lock, flags); |
42 | outl(value: regptr, port: emu->port + PTR); |
43 | val = inl(port: emu->port + DATA); |
44 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
45 | |
46 | if (reg & 0xff000000) { |
47 | unsigned char size, offset; |
48 | |
49 | size = (reg >> 24) & 0x3f; |
50 | offset = (reg >> 16) & 0x1f; |
51 | mask = (1 << size) - 1; |
52 | |
53 | return (val >> offset) & mask; |
54 | } else { |
55 | return val; |
56 | } |
57 | } |
58 | |
59 | EXPORT_SYMBOL(snd_emu10k1_ptr_read); |
60 | |
61 | void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data) |
62 | { |
63 | unsigned int regptr; |
64 | unsigned long flags; |
65 | unsigned int mask; |
66 | |
67 | regptr = (reg << 16) | chn; |
68 | if (!check_ptr_reg(emu, reg: regptr)) |
69 | return; |
70 | |
71 | if (reg & 0xff000000) { |
72 | unsigned char size, offset; |
73 | |
74 | size = (reg >> 24) & 0x3f; |
75 | offset = (reg >> 16) & 0x1f; |
76 | mask = (1 << size) - 1; |
77 | if (snd_BUG_ON(data & ~mask)) |
78 | return; |
79 | mask <<= offset; |
80 | data <<= offset; |
81 | |
82 | spin_lock_irqsave(&emu->emu_lock, flags); |
83 | outl(value: regptr, port: emu->port + PTR); |
84 | data |= inl(port: emu->port + DATA) & ~mask; |
85 | } else { |
86 | spin_lock_irqsave(&emu->emu_lock, flags); |
87 | outl(value: regptr, port: emu->port + PTR); |
88 | } |
89 | outl(value: data, port: emu->port + DATA); |
90 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
91 | } |
92 | |
93 | EXPORT_SYMBOL(snd_emu10k1_ptr_write); |
94 | |
95 | void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, ...) |
96 | { |
97 | va_list va; |
98 | u32 addr_mask; |
99 | unsigned long flags; |
100 | |
101 | if (snd_BUG_ON(!emu)) |
102 | return; |
103 | if (snd_BUG_ON(chn & ~PTR_CHANNELNUM_MASK)) |
104 | return; |
105 | addr_mask = ~((emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK) >> 16); |
106 | |
107 | va_start(va, chn); |
108 | spin_lock_irqsave(&emu->emu_lock, flags); |
109 | for (;;) { |
110 | u32 data; |
111 | u32 reg = va_arg(va, u32); |
112 | if (reg == REGLIST_END) |
113 | break; |
114 | data = va_arg(va, u32); |
115 | if (snd_BUG_ON(reg & addr_mask)) // Only raw registers supported here |
116 | continue; |
117 | outl(value: (reg << 16) | chn, port: emu->port + PTR); |
118 | outl(value: data, port: emu->port + DATA); |
119 | } |
120 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
121 | va_end(va); |
122 | } |
123 | |
124 | EXPORT_SYMBOL(snd_emu10k1_ptr_write_multiple); |
125 | |
126 | unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, |
127 | unsigned int reg, |
128 | unsigned int chn) |
129 | { |
130 | unsigned long flags; |
131 | unsigned int regptr, val; |
132 | |
133 | regptr = (reg << 16) | chn; |
134 | |
135 | spin_lock_irqsave(&emu->emu_lock, flags); |
136 | outl(value: regptr, port: emu->port + PTR2); |
137 | val = inl(port: emu->port + DATA2); |
138 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
139 | return val; |
140 | } |
141 | |
142 | void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, |
143 | unsigned int reg, |
144 | unsigned int chn, |
145 | unsigned int data) |
146 | { |
147 | unsigned int regptr; |
148 | unsigned long flags; |
149 | |
150 | regptr = (reg << 16) | chn; |
151 | |
152 | spin_lock_irqsave(&emu->emu_lock, flags); |
153 | outl(value: regptr, port: emu->port + PTR2); |
154 | outl(value: data, port: emu->port + DATA2); |
155 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
156 | } |
157 | |
158 | int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, |
159 | unsigned int data) |
160 | { |
161 | unsigned int reset, set; |
162 | unsigned int reg, tmp; |
163 | int n, result; |
164 | int err = 0; |
165 | |
166 | /* This function is not re-entrant, so protect against it. */ |
167 | spin_lock(lock: &emu->spi_lock); |
168 | if (emu->card_capabilities->ca0108_chip) |
169 | reg = P17V_SPI; |
170 | else { |
171 | /* For other chip types the SPI register |
172 | * is currently unknown. */ |
173 | err = 1; |
174 | goto spi_write_exit; |
175 | } |
176 | if (data > 0xffff) { |
177 | /* Only 16bit values allowed */ |
178 | err = 1; |
179 | goto spi_write_exit; |
180 | } |
181 | |
182 | tmp = snd_emu10k1_ptr20_read(emu, reg, chn: 0); |
183 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ |
184 | set = reset | 0x10000; /* Set xxx1xxxx */ |
185 | snd_emu10k1_ptr20_write(emu, reg, chn: 0, data: reset | data); |
186 | tmp = snd_emu10k1_ptr20_read(emu, reg, chn: 0); /* write post */ |
187 | snd_emu10k1_ptr20_write(emu, reg, chn: 0, data: set | data); |
188 | result = 1; |
189 | /* Wait for status bit to return to 0 */ |
190 | for (n = 0; n < 100; n++) { |
191 | udelay(10); |
192 | tmp = snd_emu10k1_ptr20_read(emu, reg, chn: 0); |
193 | if (!(tmp & 0x10000)) { |
194 | result = 0; |
195 | break; |
196 | } |
197 | } |
198 | if (result) { |
199 | /* Timed out */ |
200 | err = 1; |
201 | goto spi_write_exit; |
202 | } |
203 | snd_emu10k1_ptr20_write(emu, reg, chn: 0, data: reset | data); |
204 | tmp = snd_emu10k1_ptr20_read(emu, reg, chn: 0); /* Write post */ |
205 | err = 0; |
206 | spi_write_exit: |
207 | spin_unlock(lock: &emu->spi_lock); |
208 | return err; |
209 | } |
210 | |
211 | /* The ADC does not support i2c read, so only write is implemented */ |
212 | int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, |
213 | u32 reg, |
214 | u32 value) |
215 | { |
216 | u32 tmp; |
217 | int timeout = 0; |
218 | int status; |
219 | int retry; |
220 | int err = 0; |
221 | |
222 | if ((reg > 0x7f) || (value > 0x1ff)) { |
223 | dev_err(emu->card->dev, "i2c_write: invalid values.\n" ); |
224 | return -EINVAL; |
225 | } |
226 | |
227 | /* This function is not re-entrant, so protect against it. */ |
228 | spin_lock(lock: &emu->i2c_lock); |
229 | |
230 | tmp = reg << 25 | value << 16; |
231 | |
232 | /* This controls the I2C connected to the WM8775 ADC Codec */ |
233 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, chn: 0, data: tmp); |
234 | tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, chn: 0); /* write post */ |
235 | |
236 | for (retry = 0; retry < 10; retry++) { |
237 | /* Send the data to i2c */ |
238 | tmp = 0; |
239 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); |
240 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, chn: 0, data: tmp); |
241 | |
242 | /* Wait till the transaction ends */ |
243 | while (1) { |
244 | mdelay(1); |
245 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, chn: 0); |
246 | timeout++; |
247 | if ((status & I2C_A_ADC_START) == 0) |
248 | break; |
249 | |
250 | if (timeout > 1000) { |
251 | dev_warn(emu->card->dev, |
252 | "emu10k1:I2C:timeout status=0x%x\n" , |
253 | status); |
254 | break; |
255 | } |
256 | } |
257 | //Read back and see if the transaction is successful |
258 | if ((status & I2C_A_ADC_ABORT) == 0) |
259 | break; |
260 | } |
261 | |
262 | if (retry == 10) { |
263 | dev_err(emu->card->dev, "Writing to ADC failed!\n" ); |
264 | dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n" , |
265 | status, reg, value); |
266 | /* dump_stack(); */ |
267 | err = -EINVAL; |
268 | } |
269 | |
270 | spin_unlock(lock: &emu->i2c_lock); |
271 | return err; |
272 | } |
273 | |
274 | static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 value) |
275 | { |
276 | if (snd_BUG_ON(reg > 0x3f)) |
277 | return; |
278 | reg += 0x40; /* 0x40 upwards are registers. */ |
279 | if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */ |
280 | return; |
281 | outw(value: reg, port: emu->port + A_GPIO); |
282 | udelay(10); |
283 | outw(value: reg | 0x80, port: emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ |
284 | udelay(10); |
285 | outw(value, port: emu->port + A_GPIO); |
286 | udelay(10); |
287 | outw(value: value | 0x80 , port: emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ |
288 | } |
289 | |
290 | void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) |
291 | { |
292 | unsigned long flags; |
293 | |
294 | spin_lock_irqsave(&emu->emu_lock, flags); |
295 | snd_emu1010_fpga_write_locked(emu, reg, value); |
296 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
297 | } |
298 | |
299 | static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value) |
300 | { |
301 | // The higest input pin is used as the designated interrupt trigger, |
302 | // so it needs to be masked out. |
303 | // But note that any other input pin change will also cause an IRQ, |
304 | // so using this function often causes an IRQ as a side effect. |
305 | u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f; |
306 | if (snd_BUG_ON(reg > 0x3f)) |
307 | return; |
308 | reg += 0x40; /* 0x40 upwards are registers. */ |
309 | outw(value: reg, port: emu->port + A_GPIO); |
310 | udelay(10); |
311 | outw(value: reg | 0x80, port: emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ |
312 | udelay(10); |
313 | *value = ((inw(port: emu->port + A_GPIO) >> 8) & mask); |
314 | } |
315 | |
316 | void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) |
317 | { |
318 | unsigned long flags; |
319 | |
320 | spin_lock_irqsave(&emu->emu_lock, flags); |
321 | snd_emu1010_fpga_read_locked(emu, reg, value); |
322 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
323 | } |
324 | |
325 | /* Each Destination has one and only one Source, |
326 | * but one Source can feed any number of Destinations simultaneously. |
327 | */ |
328 | void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) |
329 | { |
330 | unsigned long flags; |
331 | |
332 | if (snd_BUG_ON(dst & ~0x71f)) |
333 | return; |
334 | if (snd_BUG_ON(src & ~0x71f)) |
335 | return; |
336 | spin_lock_irqsave(&emu->emu_lock, flags); |
337 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, value: dst >> 8); |
338 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, value: dst & 0x1f); |
339 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, value: src >> 8); |
340 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, value: src & 0x1f); |
341 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
342 | } |
343 | |
344 | u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) |
345 | { |
346 | unsigned long flags; |
347 | u32 hi, lo; |
348 | |
349 | if (snd_BUG_ON(dst & ~0x71f)) |
350 | return 0; |
351 | spin_lock_irqsave(&emu->emu_lock, flags); |
352 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, value: dst >> 8); |
353 | snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, value: dst & 0x1f); |
354 | snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCHI, value: &hi); |
355 | snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, value: &lo); |
356 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
357 | return (hi << 8) | lo; |
358 | } |
359 | |
360 | int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src) |
361 | { |
362 | u32 reg_lo, reg_hi, value, value2; |
363 | |
364 | switch (src) { |
365 | case EMU_HANA_WCLOCK_HANA_SPDIF_IN: |
366 | snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, value: &value); |
367 | if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) |
368 | return 0; |
369 | reg_lo = EMU_HANA_WC_SPDIF_LO; |
370 | reg_hi = EMU_HANA_WC_SPDIF_HI; |
371 | break; |
372 | case EMU_HANA_WCLOCK_HANA_ADAT_IN: |
373 | reg_lo = EMU_HANA_WC_ADAT_LO; |
374 | reg_hi = EMU_HANA_WC_ADAT_HI; |
375 | break; |
376 | case EMU_HANA_WCLOCK_SYNC_BNC: |
377 | reg_lo = EMU_HANA_WC_BNC_LO; |
378 | reg_hi = EMU_HANA_WC_BNC_HI; |
379 | break; |
380 | case EMU_HANA_WCLOCK_2ND_HANA: |
381 | reg_lo = EMU_HANA2_WC_SPDIF_LO; |
382 | reg_hi = EMU_HANA2_WC_SPDIF_HI; |
383 | break; |
384 | default: |
385 | return 0; |
386 | } |
387 | snd_emu1010_fpga_read(emu, reg: reg_hi, value: &value); |
388 | snd_emu1010_fpga_read(emu, reg: reg_lo, value: &value2); |
389 | // FIXME: The /4 is valid for 0404b, but contradicts all other info. |
390 | return 0x1770000 / 4 / (((value << 5) | value2) + 1); |
391 | } |
392 | |
393 | void snd_emu1010_update_clock(struct snd_emu10k1 *emu) |
394 | { |
395 | int clock; |
396 | u32 leds; |
397 | |
398 | switch (emu->emu1010.wclock) { |
399 | case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X: |
400 | clock = 44100; |
401 | leds = EMU_HANA_DOCK_LEDS_2_44K; |
402 | break; |
403 | case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X: |
404 | clock = 48000; |
405 | leds = EMU_HANA_DOCK_LEDS_2_48K; |
406 | break; |
407 | default: |
408 | clock = snd_emu1010_get_raw_rate( |
409 | emu, src: emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK); |
410 | // The raw rate reading is rather coarse (it cannot accurately |
411 | // represent 44.1 kHz) and fluctuates slightly. Luckily, the |
412 | // clock comes from digital inputs, which use standardized rates. |
413 | // So we round to the closest standard rate and ignore discrepancies. |
414 | if (clock < 46000) { |
415 | clock = 44100; |
416 | leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K; |
417 | } else { |
418 | clock = 48000; |
419 | leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K; |
420 | } |
421 | break; |
422 | } |
423 | emu->emu1010.word_clock = clock; |
424 | |
425 | // FIXME: this should probably represent the AND of all currently |
426 | // used sources' lock status. But we don't know how to get that ... |
427 | leds |= EMU_HANA_DOCK_LEDS_2_LOCK; |
428 | |
429 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, value: leds); |
430 | } |
431 | |
432 | void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) |
433 | { |
434 | unsigned long flags; |
435 | unsigned int enable; |
436 | |
437 | spin_lock_irqsave(&emu->emu_lock, flags); |
438 | enable = inl(port: emu->port + INTE) | intrenb; |
439 | outl(value: enable, port: emu->port + INTE); |
440 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
441 | } |
442 | |
443 | void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) |
444 | { |
445 | unsigned long flags; |
446 | unsigned int enable; |
447 | |
448 | spin_lock_irqsave(&emu->emu_lock, flags); |
449 | enable = inl(port: emu->port + INTE) & ~intrenb; |
450 | outl(value: enable, port: emu->port + INTE); |
451 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
452 | } |
453 | |
454 | void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) |
455 | { |
456 | unsigned long flags; |
457 | unsigned int val; |
458 | |
459 | spin_lock_irqsave(&emu->emu_lock, flags); |
460 | if (voicenum >= 32) { |
461 | outl(CLIEH << 16, port: emu->port + PTR); |
462 | val = inl(port: emu->port + DATA); |
463 | val |= 1 << (voicenum - 32); |
464 | } else { |
465 | outl(CLIEL << 16, port: emu->port + PTR); |
466 | val = inl(port: emu->port + DATA); |
467 | val |= 1 << voicenum; |
468 | } |
469 | outl(value: val, port: emu->port + DATA); |
470 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
471 | } |
472 | |
473 | void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) |
474 | { |
475 | unsigned long flags; |
476 | unsigned int val; |
477 | |
478 | spin_lock_irqsave(&emu->emu_lock, flags); |
479 | if (voicenum >= 32) { |
480 | outl(CLIEH << 16, port: emu->port + PTR); |
481 | val = inl(port: emu->port + DATA); |
482 | val &= ~(1 << (voicenum - 32)); |
483 | } else { |
484 | outl(CLIEL << 16, port: emu->port + PTR); |
485 | val = inl(port: emu->port + DATA); |
486 | val &= ~(1 << voicenum); |
487 | } |
488 | outl(value: val, port: emu->port + DATA); |
489 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
490 | } |
491 | |
492 | void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) |
493 | { |
494 | unsigned long flags; |
495 | |
496 | spin_lock_irqsave(&emu->emu_lock, flags); |
497 | if (voicenum >= 32) { |
498 | outl(CLIPH << 16, port: emu->port + PTR); |
499 | voicenum = 1 << (voicenum - 32); |
500 | } else { |
501 | outl(CLIPL << 16, port: emu->port + PTR); |
502 | voicenum = 1 << voicenum; |
503 | } |
504 | outl(value: voicenum, port: emu->port + DATA); |
505 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
506 | } |
507 | |
508 | void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) |
509 | { |
510 | unsigned long flags; |
511 | unsigned int val; |
512 | |
513 | spin_lock_irqsave(&emu->emu_lock, flags); |
514 | if (voicenum >= 32) { |
515 | outl(HLIEH << 16, port: emu->port + PTR); |
516 | val = inl(port: emu->port + DATA); |
517 | val |= 1 << (voicenum - 32); |
518 | } else { |
519 | outl(HLIEL << 16, port: emu->port + PTR); |
520 | val = inl(port: emu->port + DATA); |
521 | val |= 1 << voicenum; |
522 | } |
523 | outl(value: val, port: emu->port + DATA); |
524 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
525 | } |
526 | |
527 | void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) |
528 | { |
529 | unsigned long flags; |
530 | unsigned int val; |
531 | |
532 | spin_lock_irqsave(&emu->emu_lock, flags); |
533 | if (voicenum >= 32) { |
534 | outl(HLIEH << 16, port: emu->port + PTR); |
535 | val = inl(port: emu->port + DATA); |
536 | val &= ~(1 << (voicenum - 32)); |
537 | } else { |
538 | outl(HLIEL << 16, port: emu->port + PTR); |
539 | val = inl(port: emu->port + DATA); |
540 | val &= ~(1 << voicenum); |
541 | } |
542 | outl(value: val, port: emu->port + DATA); |
543 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
544 | } |
545 | |
546 | void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) |
547 | { |
548 | unsigned long flags; |
549 | |
550 | spin_lock_irqsave(&emu->emu_lock, flags); |
551 | if (voicenum >= 32) { |
552 | outl(HLIPH << 16, port: emu->port + PTR); |
553 | voicenum = 1 << (voicenum - 32); |
554 | } else { |
555 | outl(HLIPL << 16, port: emu->port + PTR); |
556 | voicenum = 1 << voicenum; |
557 | } |
558 | outl(value: voicenum, port: emu->port + DATA); |
559 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
560 | } |
561 | |
562 | #if 0 |
563 | void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) |
564 | { |
565 | unsigned long flags; |
566 | unsigned int sol; |
567 | |
568 | spin_lock_irqsave(&emu->emu_lock, flags); |
569 | if (voicenum >= 32) { |
570 | outl(SOLEH << 16, emu->port + PTR); |
571 | sol = inl(emu->port + DATA); |
572 | sol |= 1 << (voicenum - 32); |
573 | } else { |
574 | outl(SOLEL << 16, emu->port + PTR); |
575 | sol = inl(emu->port + DATA); |
576 | sol |= 1 << voicenum; |
577 | } |
578 | outl(sol, emu->port + DATA); |
579 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
580 | } |
581 | |
582 | void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) |
583 | { |
584 | unsigned long flags; |
585 | unsigned int sol; |
586 | |
587 | spin_lock_irqsave(&emu->emu_lock, flags); |
588 | if (voicenum >= 32) { |
589 | outl(SOLEH << 16, emu->port + PTR); |
590 | sol = inl(emu->port + DATA); |
591 | sol &= ~(1 << (voicenum - 32)); |
592 | } else { |
593 | outl(SOLEL << 16, emu->port + PTR); |
594 | sol = inl(emu->port + DATA); |
595 | sol &= ~(1 << voicenum); |
596 | } |
597 | outl(sol, emu->port + DATA); |
598 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
599 | } |
600 | #endif |
601 | |
602 | void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) |
603 | { |
604 | unsigned long flags; |
605 | |
606 | spin_lock_irqsave(&emu->emu_lock, flags); |
607 | outl(SOLEL << 16, port: emu->port + PTR); |
608 | outl(inl(port: emu->port + DATA) | (u32)voices, port: emu->port + DATA); |
609 | outl(SOLEH << 16, port: emu->port + PTR); |
610 | outl(inl(port: emu->port + DATA) | (u32)(voices >> 32), port: emu->port + DATA); |
611 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
612 | } |
613 | |
614 | void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) |
615 | { |
616 | unsigned long flags; |
617 | |
618 | spin_lock_irqsave(&emu->emu_lock, flags); |
619 | outl(SOLEL << 16, port: emu->port + PTR); |
620 | outl(inl(port: emu->port + DATA) & (u32)~voices, port: emu->port + DATA); |
621 | outl(SOLEH << 16, port: emu->port + PTR); |
622 | outl(inl(port: emu->port + DATA) & (u32)(~voices >> 32), port: emu->port + DATA); |
623 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
624 | } |
625 | |
626 | int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices) |
627 | { |
628 | unsigned long flags; |
629 | u32 soll, solh; |
630 | int ret = -EIO; |
631 | |
632 | spin_lock_irqsave(&emu->emu_lock, flags); |
633 | |
634 | outl(SOLEL << 16, port: emu->port + PTR); |
635 | soll = inl(port: emu->port + DATA); |
636 | outl(SOLEH << 16, port: emu->port + PTR); |
637 | solh = inl(port: emu->port + DATA); |
638 | |
639 | soll &= (u32)~voices; |
640 | solh &= (u32)(~voices >> 32); |
641 | |
642 | for (int tries = 0; tries < 1000; tries++) { |
643 | const u32 quart = 1U << (REG_SIZE(WC_CURRENTCHANNEL) - 2); |
644 | // First we wait for the third quarter of the sample cycle ... |
645 | u32 wc = inl(port: emu->port + WC); |
646 | u32 cc = REG_VAL_GET(WC_CURRENTCHANNEL, wc); |
647 | if (cc >= quart * 2 && cc < quart * 3) { |
648 | // ... and release the low voices, while the high ones are serviced. |
649 | outl(SOLEL << 16, port: emu->port + PTR); |
650 | outl(value: soll, port: emu->port + DATA); |
651 | // Then we wait for the first quarter of the next sample cycle ... |
652 | for (; tries < 1000; tries++) { |
653 | cc = REG_VAL_GET(WC_CURRENTCHANNEL, inl(emu->port + WC)); |
654 | if (cc < quart) |
655 | goto good; |
656 | // We will block for 10+ us with interrupts disabled. This is |
657 | // not nice at all, but necessary for reasonable reliability. |
658 | udelay(1); |
659 | } |
660 | break; |
661 | good: |
662 | // ... and release the high voices, while the low ones are serviced. |
663 | outl(SOLEH << 16, port: emu->port + PTR); |
664 | outl(value: solh, port: emu->port + DATA); |
665 | // Finally we verify that nothing interfered in fact. |
666 | if (REG_VAL_GET(WC_SAMPLECOUNTER, inl(emu->port + WC)) == |
667 | ((REG_VAL_GET(WC_SAMPLECOUNTER, wc) + 1) & REG_MASK0(WC_SAMPLECOUNTER))) { |
668 | ret = 0; |
669 | } else { |
670 | ret = -EAGAIN; |
671 | } |
672 | break; |
673 | } |
674 | // Don't block for too long |
675 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
676 | udelay(1); |
677 | spin_lock_irqsave(&emu->emu_lock, flags); |
678 | } |
679 | |
680 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
681 | return ret; |
682 | } |
683 | |
684 | void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait) |
685 | { |
686 | volatile unsigned count; |
687 | unsigned int newtime = 0, curtime; |
688 | |
689 | curtime = inl(port: emu->port + WC) >> 6; |
690 | while (wait-- > 0) { |
691 | count = 0; |
692 | while (count++ < 16384) { |
693 | newtime = inl(port: emu->port + WC) >> 6; |
694 | if (newtime != curtime) |
695 | break; |
696 | } |
697 | if (count > 16384) |
698 | break; |
699 | curtime = newtime; |
700 | } |
701 | } |
702 | |
703 | unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
704 | { |
705 | struct snd_emu10k1 *emu = ac97->private_data; |
706 | unsigned long flags; |
707 | unsigned short val; |
708 | |
709 | spin_lock_irqsave(&emu->emu_lock, flags); |
710 | outb(value: reg, port: emu->port + AC97ADDRESS); |
711 | val = inw(port: emu->port + AC97DATA); |
712 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
713 | return val; |
714 | } |
715 | |
716 | void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data) |
717 | { |
718 | struct snd_emu10k1 *emu = ac97->private_data; |
719 | unsigned long flags; |
720 | |
721 | spin_lock_irqsave(&emu->emu_lock, flags); |
722 | outb(value: reg, port: emu->port + AC97ADDRESS); |
723 | outw(value: data, port: emu->port + AC97DATA); |
724 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
725 | } |
726 | |