Lines Matching +full:sso +full:- +full:hw +full:- +full:trigger
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2004-2007, David Dillow
7 * Inspired by the Trident 4D-WaveDX/NX driver.
29 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
53 * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt
61 * Capture channels do not have a SSO, so we allocate a playback channel to
62 * use as a timer for the capture periods. We use the SSO on the playback
80 u32 sso; member
141 /* The HW offset parameters (Loop End, Stop Sample, End Sample) have a
142 * documented range of 8-0xfff8 samples. Given that they are 0-based,
143 * that places our period/buffer range at 9-0xfff9 samples. That makes the
194 void __iomem *base = voice->ctrl_base; in sis_update_sso()
196 voice->sso += period; in sis_update_sso()
197 if (voice->sso >= voice->buffer_size) in sis_update_sso()
198 voice->sso -= voice->buffer_size; in sis_update_sso()
201 if (voice->sso < 8) in sis_update_sso()
202 voice->sso = 8; in sis_update_sso()
204 /* The SSO is in the upper 16 bits of the register. */ in sis_update_sso()
205 writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2); in sis_update_sso()
210 if (voice->flags & VOICE_SSO_TIMING) { in sis_update_voice()
211 sis_update_sso(voice, voice->period_size); in sis_update_voice()
212 } else if (voice->flags & VOICE_SYNC_TIMING) { in sis_update_voice()
218 if (voice->vperiod > voice->period_size) { in sis_update_voice()
219 voice->vperiod -= voice->period_size; in sis_update_voice()
220 if (voice->vperiod < voice->period_size) in sis_update_voice()
221 sis_update_sso(voice, voice->vperiod); in sis_update_voice()
223 sis_update_sso(voice, voice->period_size); in sis_update_voice()
232 sync = voice->sync_cso; in sis_update_voice()
233 sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO); in sis_update_voice()
234 if (sync > (voice->sync_buffer_size / 2)) in sis_update_voice()
235 sync -= voice->sync_buffer_size; in sis_update_voice()
254 * it really is past a period when we get our interrupt -- in sis_update_voice()
264 if (sync > -9) in sis_update_voice()
265 voice->vperiod = voice->sync_period_size + 1; in sis_update_voice()
267 voice->vperiod = voice->sync_period_size + sync + 10; in sis_update_voice()
269 if (voice->vperiod < voice->buffer_size) { in sis_update_voice()
270 sis_update_sso(voice, voice->vperiod); in sis_update_voice()
271 voice->vperiod = 0; in sis_update_voice()
273 sis_update_sso(voice, voice->period_size); in sis_update_voice()
275 sync = voice->sync_cso + voice->sync_period_size; in sis_update_voice()
276 if (sync >= voice->sync_buffer_size) in sis_update_voice()
277 sync -= voice->sync_buffer_size; in sis_update_voice()
278 voice->sync_cso = sync; in sis_update_voice()
281 snd_pcm_period_elapsed(voice->substream); in sis_update_voice()
300 unsigned long io = sis->ioport; in sis_interrupt()
319 sis_voice_irq(status, sis->voices); in sis_interrupt()
325 sis_voice_irq(status, &sis->voices[32]); in sis_interrupt()
331 voice = &sis->capture_voice; in sis_interrupt()
332 if (!voice->timing) in sis_interrupt()
333 snd_pcm_period_elapsed(voice->substream); in sis_interrupt()
372 /* Helper function: must hold sis->voice_lock on entry */ in __sis_map_silence()
373 if (!sis->silence_users) in __sis_map_silence()
374 sis->silence_dma_addr = dma_map_single(&sis->pci->dev, in __sis_map_silence()
375 sis->suspend_state[0], in __sis_map_silence()
377 sis->silence_users++; in __sis_map_silence()
382 /* Helper function: must hold sis->voice_lock on entry */ in __sis_unmap_silence()
383 sis->silence_users--; in __sis_unmap_silence()
384 if (!sis->silence_users) in __sis_unmap_silence()
385 dma_unmap_single(&sis->pci->dev, sis->silence_dma_addr, 4096, in __sis_unmap_silence()
393 spin_lock_irqsave(&sis->voice_lock, flags); in sis_free_voice()
394 if (voice->timing) { in sis_free_voice()
396 voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | in sis_free_voice()
398 voice->timing = NULL; in sis_free_voice()
400 voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); in sis_free_voice()
401 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_free_voice()
411 voice = &sis->voices[i]; in __sis_alloc_playback_voice()
412 if (voice->flags & VOICE_IN_USE) in __sis_alloc_playback_voice()
414 voice->flags |= VOICE_IN_USE; in __sis_alloc_playback_voice()
428 spin_lock_irqsave(&sis->voice_lock, flags); in sis_alloc_playback_voice()
430 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_alloc_playback_voice()
439 struct snd_pcm_runtime *runtime = substream->runtime; in sis_alloc_timing_voice()
440 struct voice *voice = runtime->private_data; in sis_alloc_timing_voice()
454 if (needed && !voice->timing) { in sis_alloc_timing_voice()
455 spin_lock_irqsave(&sis->voice_lock, flags); in sis_alloc_timing_voice()
456 voice->timing = __sis_alloc_playback_voice(sis); in sis_alloc_timing_voice()
457 if (voice->timing) in sis_alloc_timing_voice()
459 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_alloc_timing_voice()
460 if (!voice->timing) in sis_alloc_timing_voice()
461 return -ENOMEM; in sis_alloc_timing_voice()
462 voice->timing->substream = substream; in sis_alloc_timing_voice()
463 } else if (!needed && voice->timing) { in sis_alloc_timing_voice()
465 voice->timing = NULL; in sis_alloc_timing_voice()
474 struct snd_pcm_runtime *runtime = substream->runtime; in sis_playback_open()
479 return -EAGAIN; in sis_playback_open()
481 voice->substream = substream; in sis_playback_open()
482 runtime->private_data = voice; in sis_playback_open()
483 runtime->hw = sis_playback_hw_info; in sis_playback_open()
495 struct snd_pcm_runtime *runtime = substream->runtime; in sis_substream_close()
496 struct voice *voice = runtime->private_data; in sis_substream_close()
504 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_playback_prepare()
505 struct voice *voice = runtime->private_data; in sis_pcm_playback_prepare()
506 void __iomem *ctrl_base = voice->ctrl_base; in sis_pcm_playback_prepare()
507 void __iomem *wave_base = voice->wave_base; in sis_pcm_playback_prepare()
512 * substream do not change on us while we're programming the HW. in sis_pcm_playback_prepare()
515 if (snd_pcm_format_width(runtime->format) == 8) in sis_pcm_playback_prepare()
517 if (!snd_pcm_format_signed(runtime->format)) in sis_pcm_playback_prepare()
519 if (runtime->channels == 1) in sis_pcm_playback_prepare()
525 dma_addr = runtime->dma_addr; in sis_pcm_playback_prepare()
526 leo = runtime->buffer_size - 1; in sis_pcm_playback_prepare()
530 if (runtime->period_size == (runtime->buffer_size / 2)) { in sis_pcm_playback_prepare()
532 } else if (runtime->period_size != runtime->buffer_size) { in sis_pcm_playback_prepare()
533 voice->flags |= VOICE_SSO_TIMING; in sis_pcm_playback_prepare()
534 voice->sso = runtime->period_size - 1; in sis_pcm_playback_prepare()
535 voice->period_size = runtime->period_size; in sis_pcm_playback_prepare()
536 voice->buffer_size = runtime->buffer_size; in sis_pcm_playback_prepare()
540 sso_eso |= (runtime->period_size - 1) << 16; in sis_pcm_playback_prepare()
543 delta = sis_rate_to_delta(runtime->rate); in sis_pcm_playback_prepare()
571 unsigned long io = sis->ioport; in sis_pcm_trigger()
580 * substreams, and the HW will only start/stop the indicated voices in sis_pcm_trigger()
595 return -EINVAL; in sis_pcm_trigger()
604 voice = s->runtime->private_data; in sis_pcm_trigger()
605 if (voice->flags & VOICE_CAPTURE) { in sis_pcm_trigger()
606 record |= 1 << voice->num; in sis_pcm_trigger()
607 voice = voice->timing; in sis_pcm_trigger()
614 play[voice->num / 32] |= 1 << (voice->num & 0x1f); in sis_pcm_trigger()
639 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_pointer()
640 struct voice *voice = runtime->private_data; in sis_pcm_pointer()
643 cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); in sis_pcm_pointer()
651 struct snd_pcm_runtime *runtime = substream->runtime; in sis_capture_open()
652 struct voice *voice = &sis->capture_voice; in sis_capture_open()
658 spin_lock_irqsave(&sis->voice_lock, flags); in sis_capture_open()
659 if (voice->flags & VOICE_IN_USE) in sis_capture_open()
662 voice->flags |= VOICE_IN_USE; in sis_capture_open()
663 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_capture_open()
666 return -EAGAIN; in sis_capture_open()
668 voice->substream = substream; in sis_capture_open()
669 runtime->private_data = voice; in sis_capture_open()
670 runtime->hw = sis_capture_hw_info; in sis_capture_open()
671 runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC]; in sis_capture_open()
687 rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE, in sis_capture_hw_params()
702 struct snd_pcm_runtime *runtime = substream->runtime; in sis_prepare_timing_voice()
703 struct voice *timing = voice->timing; in sis_prepare_timing_voice()
704 void __iomem *play_base = timing->ctrl_base; in sis_prepare_timing_voice()
705 void __iomem *wave_base = timing->wave_base; in sis_prepare_timing_voice()
708 u32 vperiod, sso, reg; in sis_prepare_timing_voice() local
713 buffer_size = 4096 / runtime->channels; in sis_prepare_timing_voice()
714 buffer_size /= snd_pcm_format_size(runtime->format, 1); in sis_prepare_timing_voice()
723 * end -- this helps minimize the effects of any jitter. Adjust our in sis_prepare_timing_voice()
729 vperiod = runtime->period_size + 12; in sis_prepare_timing_voice()
737 tail = quarter_period - tail; in sis_prepare_timing_voice()
738 tail += loops - 1; in sis_prepare_timing_voice()
740 period_size -= tail; in sis_prepare_timing_voice()
743 sso = period_size - 1; in sis_prepare_timing_voice()
746 * don't need to use virtual periods -- disable them. in sis_prepare_timing_voice()
748 period_size = runtime->period_size; in sis_prepare_timing_voice()
749 sso = vperiod - 1; in sis_prepare_timing_voice()
756 timing->flags |= VOICE_SYNC_TIMING; in sis_prepare_timing_voice()
757 timing->sync_base = voice->ctrl_base; in sis_prepare_timing_voice()
758 timing->sync_cso = runtime->period_size; in sis_prepare_timing_voice()
759 timing->sync_period_size = runtime->period_size; in sis_prepare_timing_voice()
760 timing->sync_buffer_size = runtime->buffer_size; in sis_prepare_timing_voice()
761 timing->period_size = period_size; in sis_prepare_timing_voice()
762 timing->buffer_size = buffer_size; in sis_prepare_timing_voice()
763 timing->sso = sso; in sis_prepare_timing_voice()
764 timing->vperiod = vperiod; in sis_prepare_timing_voice()
766 /* Using unsigned samples with the all-zero silence buffer in sis_prepare_timing_voice()
768 * So ignore unsigned vs signed -- it doesn't change the timing. in sis_prepare_timing_voice()
771 if (snd_pcm_format_width(runtime->format) == 8) in sis_prepare_timing_voice()
773 if (runtime->channels == 1) in sis_prepare_timing_voice()
776 control = timing->buffer_size - 1; in sis_prepare_timing_voice()
778 sso_eso = timing->buffer_size - 1; in sis_prepare_timing_voice()
779 sso_eso |= timing->sso << 16; in sis_prepare_timing_voice()
781 delta = sis_rate_to_delta(runtime->rate); in sis_prepare_timing_voice()
786 writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE); in sis_prepare_timing_voice()
803 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_capture_prepare()
804 struct voice *voice = runtime->private_data; in sis_pcm_capture_prepare()
805 void __iomem *rec_base = voice->ctrl_base; in sis_pcm_capture_prepare()
810 * substream do not change on us while we're programming the HW. in sis_pcm_capture_prepare()
813 if (snd_pcm_format_width(runtime->format) == 8) in sis_pcm_capture_prepare()
815 if (!snd_pcm_format_signed(runtime->format)) in sis_pcm_capture_prepare()
817 if (runtime->channels == 1) in sis_pcm_capture_prepare()
820 dma_addr = runtime->dma_addr; in sis_pcm_capture_prepare()
821 leo = runtime->buffer_size - 1; in sis_pcm_capture_prepare()
828 if (voice->timing) { in sis_pcm_capture_prepare()
832 if (runtime->period_size != runtime->buffer_size) in sis_pcm_capture_prepare()
850 .trigger = sis_pcm_trigger,
859 .trigger = sis_pcm_trigger,
871 rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm); in sis_pcm_create()
875 pcm->private_data = sis; in sis_pcm_create()
876 strcpy(pcm->name, "SiS7019"); in sis_pcm_create()
877 sis->pcm = pcm; in sis_pcm_create()
886 &sis->pci->dev, 64*1024, 128*1024); in sis_pcm_create()
893 unsigned long io = sis->ioport; in sis_ac97_rw()
907 /* Get the AC97 semaphore -- software first, so we don't spin in sis_ac97_rw()
910 mutex_lock(&sis->ac97_mutex); in sis_ac97_rw()
913 while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) in sis_ac97_rw()
928 } while (--count); in sis_ac97_rw()
939 while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) in sis_ac97_rw()
949 mutex_unlock(&sis->ac97_mutex); in sis_ac97_rw()
952 dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n", in sis_ac97_rw()
967 sis_ac97_rw(ac97->private_data, ac97->num, in sis_ac97_write()
968 (val << 16) | (reg << 8) | cmd[ac97->num]); in sis_ac97_write()
978 return sis_ac97_rw(ac97->private_data, ac97->num, in sis_ac97_read()
979 (reg << 8) | cmd[ac97->num]); in sis_ac97_read()
995 rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus); in sis_mixer_create()
996 if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_mixer_create()
997 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]); in sis_mixer_create()
999 if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)) in sis_mixer_create()
1000 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]); in sis_mixer_create()
1002 if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)) in sis_mixer_create()
1003 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]); in sis_mixer_create()
1016 kfree(sis->suspend_state[i]); in sis_free_suspend()
1023 outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); in sis_chip_free()
1025 outl(0, sis->ioport + SIS_GCR); in sis_chip_free()
1026 outl(0, sis->ioport + SIS_GIER); in sis_chip_free()
1030 if (sis->irq >= 0) in sis_chip_free()
1031 free_irq(sis->irq, sis); in sis_chip_free()
1033 iounmap(sis->ioaddr); in sis_chip_free()
1034 pci_release_regions(sis->pci); in sis_chip_free()
1035 pci_disable_device(sis->pci); in sis_chip_free()
1042 struct sis7019 *sis = dev->device_data; in sis_dev_free()
1048 unsigned long io = sis->ioport; in sis_chip_init()
1049 void __iomem *ioaddr = sis->ioaddr; in sis_chip_init()
1061 /* Get the AC-link semaphore, and reset the codecs in sis_chip_init()
1064 while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) in sis_chip_init()
1068 return -EIO; in sis_chip_init()
1074 while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) in sis_chip_init()
1081 return -EIO; in sis_chip_init()
1088 sis->codecs_present = 0; in sis_chip_init()
1093 sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; in sis_chip_init()
1095 sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; in sis_chip_init()
1097 sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; in sis_chip_init()
1099 if (sis->codecs_present == codecs) in sis_chip_init()
1107 if (!sis->codecs_present) { in sis_chip_init()
1108 dev_err(&sis->pci->dev, "could not find any codecs\n"); in sis_chip_init()
1109 return -EIO; in sis_chip_init()
1112 if (sis->codecs_present != codecs) { in sis_chip_init()
1113 dev_warn(&sis->pci->dev, "missing codecs, found %0x, expected %0x\n", in sis_chip_init()
1114 sis->codecs_present, codecs); in sis_chip_init()
1118 * and enable PCM slots on the AC-link for L/R playback (3 & 4) and in sis_chip_init()
1128 /* All AC97 PCM slots should be sourced from sub-mixer 0. in sis_chip_init()
1139 * assign sub-mixer 0 to all playback channels, and avoid any in sis_chip_init()
1178 struct sis7019 *sis = card->private_data; in sis_suspend()
1179 void __iomem *ioaddr = sis->ioaddr; in sis_suspend()
1183 if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_suspend()
1184 snd_ac97_suspend(sis->ac97[0]); in sis_suspend()
1185 if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) in sis_suspend()
1186 snd_ac97_suspend(sis->ac97[1]); in sis_suspend()
1187 if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) in sis_suspend()
1188 snd_ac97_suspend(sis->ac97[2]); in sis_suspend()
1192 if (sis->irq >= 0) { in sis_suspend()
1193 free_irq(sis->irq, sis); in sis_suspend()
1194 sis->irq = -1; in sis_suspend()
1200 memcpy_fromio(sis->suspend_state[i], ioaddr, 4096); in sis_suspend()
1211 struct sis7019 *sis = card->private_data; in sis_resume()
1212 void __iomem *ioaddr = sis->ioaddr; in sis_resume()
1216 dev_err(&pci->dev, "unable to re-init controller\n"); in sis_resume()
1220 if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, in sis_resume()
1222 dev_err(&pci->dev, "unable to regain IRQ %d\n", pci->irq); in sis_resume()
1230 memcpy_toio(ioaddr, sis->suspend_state[i], 4096); in sis_resume()
1234 memset(sis->suspend_state[0], 0, 4096); in sis_resume()
1236 sis->irq = pci->irq; in sis_resume()
1238 if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_resume()
1239 snd_ac97_resume(sis->ac97[0]); in sis_resume()
1240 if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) in sis_resume()
1241 snd_ac97_resume(sis->ac97[1]); in sis_resume()
1242 if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) in sis_resume()
1243 snd_ac97_resume(sis->ac97[2]); in sis_resume()
1250 return -EIO; in sis_resume()
1269 sis->suspend_state[i] = kmalloc(4096, GFP_KERNEL); in sis_alloc_suspend()
1270 if (!sis->suspend_state[i]) in sis_alloc_suspend()
1271 return -ENOMEM; in sis_alloc_suspend()
1273 memset(sis->suspend_state[0], 0, 4096); in sis_alloc_suspend()
1281 struct sis7019 *sis = card->private_data; in sis_chip_create()
1293 rc = dma_set_mask(&pci->dev, DMA_BIT_MASK(30)); in sis_chip_create()
1295 dev_err(&pci->dev, "architecture does not support 30-bit PCI busmaster DMA"); in sis_chip_create()
1300 mutex_init(&sis->ac97_mutex); in sis_chip_create()
1301 spin_lock_init(&sis->voice_lock); in sis_chip_create()
1302 sis->card = card; in sis_chip_create()
1303 sis->pci = pci; in sis_chip_create()
1304 sis->irq = -1; in sis_chip_create()
1305 sis->ioport = pci_resource_start(pci, 0); in sis_chip_create()
1309 dev_err(&pci->dev, "unable request regions\n"); in sis_chip_create()
1313 rc = -EIO; in sis_chip_create()
1314 sis->ioaddr = ioremap(pci_resource_start(pci, 1), 0x4000); in sis_chip_create()
1315 if (!sis->ioaddr) { in sis_chip_create()
1316 dev_err(&pci->dev, "unable to remap MMIO, aborting\n"); in sis_chip_create()
1322 dev_err(&pci->dev, "unable to allocate state storage\n"); in sis_chip_create()
1330 rc = request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME, in sis_chip_create()
1333 dev_err(&pci->dev, "unable to allocate irq %d\n", sis->irq); in sis_chip_create()
1337 sis->irq = pci->irq; in sis_chip_create()
1338 card->sync_irq = sis->irq; in sis_chip_create()
1342 voice = &sis->voices[i]; in sis_chip_create()
1343 voice->num = i; in sis_chip_create()
1344 voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i); in sis_chip_create()
1345 voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i); in sis_chip_create()
1348 voice = &sis->capture_voice; in sis_chip_create()
1349 voice->flags = VOICE_CAPTURE; in sis_chip_create()
1350 voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN; in sis_chip_create()
1351 voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num); in sis_chip_create()
1376 rc = -ENOENT; in snd_sis7019_probe()
1384 * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2. in snd_sis7019_probe()
1391 rc = snd_card_new(&pci->dev, index, id, THIS_MODULE, in snd_sis7019_probe()
1396 strcpy(card->driver, "SiS7019"); in snd_sis7019_probe()
1397 strcpy(card->shortname, "SiS7019"); in snd_sis7019_probe()
1402 sis = card->private_data; in snd_sis7019_probe()
1412 snprintf(card->longname, sizeof(card->longname), in snd_sis7019_probe()
1414 card->shortname, snd_ac97_get_short_name(sis->ac97[0]), in snd_sis7019_probe()
1415 sis->ioport, sis->irq); in snd_sis7019_probe()