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.
28 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
52 * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt
60 * Capture channels do not have a SSO, so we allocate a playback channel to
61 * use as a timer for the capture periods. We use the SSO on the playback
79 u32 sso; member
140 /* The HW offset parameters (Loop End, Stop Sample, End Sample) have a
141 * documented range of 8-0xfff8 samples. Given that they are 0-based,
142 * that places our period/buffer range at 9-0xfff9 samples. That makes the
193 void __iomem *base = voice->ctrl_base; in sis_update_sso()
195 voice->sso += period; in sis_update_sso()
196 if (voice->sso >= voice->buffer_size) in sis_update_sso()
197 voice->sso -= voice->buffer_size; in sis_update_sso()
200 if (voice->sso < 8) in sis_update_sso()
201 voice->sso = 8; in sis_update_sso()
203 /* The SSO is in the upper 16 bits of the register. */ in sis_update_sso()
204 writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2); in sis_update_sso()
209 if (voice->flags & VOICE_SSO_TIMING) { in sis_update_voice()
210 sis_update_sso(voice, voice->period_size); in sis_update_voice()
211 } else if (voice->flags & VOICE_SYNC_TIMING) { in sis_update_voice()
217 if (voice->vperiod > voice->period_size) { in sis_update_voice()
218 voice->vperiod -= voice->period_size; in sis_update_voice()
219 if (voice->vperiod < voice->period_size) in sis_update_voice()
220 sis_update_sso(voice, voice->vperiod); in sis_update_voice()
222 sis_update_sso(voice, voice->period_size); in sis_update_voice()
231 sync = voice->sync_cso; in sis_update_voice()
232 sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO); in sis_update_voice()
233 if (sync > (voice->sync_buffer_size / 2)) in sis_update_voice()
234 sync -= voice->sync_buffer_size; in sis_update_voice()
253 * it really is past a period when we get our interrupt -- in sis_update_voice()
263 if (sync > -9) in sis_update_voice()
264 voice->vperiod = voice->sync_period_size + 1; in sis_update_voice()
266 voice->vperiod = voice->sync_period_size + sync + 10; in sis_update_voice()
268 if (voice->vperiod < voice->buffer_size) { in sis_update_voice()
269 sis_update_sso(voice, voice->vperiod); in sis_update_voice()
270 voice->vperiod = 0; in sis_update_voice()
272 sis_update_sso(voice, voice->period_size); in sis_update_voice()
274 sync = voice->sync_cso + voice->sync_period_size; in sis_update_voice()
275 if (sync >= voice->sync_buffer_size) in sis_update_voice()
276 sync -= voice->sync_buffer_size; in sis_update_voice()
277 voice->sync_cso = sync; in sis_update_voice()
280 snd_pcm_period_elapsed(voice->substream); in sis_update_voice()
299 unsigned long io = sis->ioport; in sis_interrupt()
318 sis_voice_irq(status, sis->voices); in sis_interrupt()
324 sis_voice_irq(status, &sis->voices[32]); in sis_interrupt()
330 voice = &sis->capture_voice; in sis_interrupt()
331 if (!voice->timing) in sis_interrupt()
332 snd_pcm_period_elapsed(voice->substream); in sis_interrupt()
371 /* Helper function: must hold sis->voice_lock on entry */ in __sis_map_silence()
372 if (!sis->silence_users) in __sis_map_silence()
373 sis->silence_dma_addr = dma_map_single(&sis->pci->dev, in __sis_map_silence()
374 sis->suspend_state[0], in __sis_map_silence()
376 sis->silence_users++; in __sis_map_silence()
381 /* Helper function: must hold sis->voice_lock on entry */ in __sis_unmap_silence()
382 sis->silence_users--; in __sis_unmap_silence()
383 if (!sis->silence_users) in __sis_unmap_silence()
384 dma_unmap_single(&sis->pci->dev, sis->silence_dma_addr, 4096, in __sis_unmap_silence()
392 spin_lock_irqsave(&sis->voice_lock, flags); in sis_free_voice()
393 if (voice->timing) { in sis_free_voice()
395 voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | in sis_free_voice()
397 voice->timing = NULL; in sis_free_voice()
399 voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); in sis_free_voice()
400 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_free_voice()
410 voice = &sis->voices[i]; in __sis_alloc_playback_voice()
411 if (voice->flags & VOICE_IN_USE) in __sis_alloc_playback_voice()
413 voice->flags |= VOICE_IN_USE; in __sis_alloc_playback_voice()
427 spin_lock_irqsave(&sis->voice_lock, flags); in sis_alloc_playback_voice()
429 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_alloc_playback_voice()
438 struct snd_pcm_runtime *runtime = substream->runtime; in sis_alloc_timing_voice()
439 struct voice *voice = runtime->private_data; in sis_alloc_timing_voice()
453 if (needed && !voice->timing) { in sis_alloc_timing_voice()
454 spin_lock_irqsave(&sis->voice_lock, flags); in sis_alloc_timing_voice()
455 voice->timing = __sis_alloc_playback_voice(sis); in sis_alloc_timing_voice()
456 if (voice->timing) in sis_alloc_timing_voice()
458 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_alloc_timing_voice()
459 if (!voice->timing) in sis_alloc_timing_voice()
460 return -ENOMEM; in sis_alloc_timing_voice()
461 voice->timing->substream = substream; in sis_alloc_timing_voice()
462 } else if (!needed && voice->timing) { in sis_alloc_timing_voice()
464 voice->timing = NULL; in sis_alloc_timing_voice()
473 struct snd_pcm_runtime *runtime = substream->runtime; in sis_playback_open()
478 return -EAGAIN; in sis_playback_open()
480 voice->substream = substream; in sis_playback_open()
481 runtime->private_data = voice; in sis_playback_open()
482 runtime->hw = sis_playback_hw_info; in sis_playback_open()
494 struct snd_pcm_runtime *runtime = substream->runtime; in sis_substream_close()
495 struct voice *voice = runtime->private_data; in sis_substream_close()
503 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_playback_prepare()
504 struct voice *voice = runtime->private_data; in sis_pcm_playback_prepare()
505 void __iomem *ctrl_base = voice->ctrl_base; in sis_pcm_playback_prepare()
506 void __iomem *wave_base = voice->wave_base; in sis_pcm_playback_prepare()
511 * substream do not change on us while we're programming the HW. in sis_pcm_playback_prepare()
514 if (snd_pcm_format_width(runtime->format) == 8) in sis_pcm_playback_prepare()
516 if (!snd_pcm_format_signed(runtime->format)) in sis_pcm_playback_prepare()
518 if (runtime->channels == 1) in sis_pcm_playback_prepare()
524 dma_addr = runtime->dma_addr; in sis_pcm_playback_prepare()
525 leo = runtime->buffer_size - 1; in sis_pcm_playback_prepare()
529 if (runtime->period_size == (runtime->buffer_size / 2)) { in sis_pcm_playback_prepare()
531 } else if (runtime->period_size != runtime->buffer_size) { in sis_pcm_playback_prepare()
532 voice->flags |= VOICE_SSO_TIMING; in sis_pcm_playback_prepare()
533 voice->sso = runtime->period_size - 1; in sis_pcm_playback_prepare()
534 voice->period_size = runtime->period_size; in sis_pcm_playback_prepare()
535 voice->buffer_size = runtime->buffer_size; in sis_pcm_playback_prepare()
539 sso_eso |= (runtime->period_size - 1) << 16; in sis_pcm_playback_prepare()
542 delta = sis_rate_to_delta(runtime->rate); in sis_pcm_playback_prepare()
570 unsigned long io = sis->ioport; in sis_pcm_trigger()
579 * substreams, and the HW will only start/stop the indicated voices in sis_pcm_trigger()
594 return -EINVAL; in sis_pcm_trigger()
603 voice = s->runtime->private_data; in sis_pcm_trigger()
604 if (voice->flags & VOICE_CAPTURE) { in sis_pcm_trigger()
605 record |= 1 << voice->num; in sis_pcm_trigger()
606 voice = voice->timing; in sis_pcm_trigger()
613 play[voice->num / 32] |= 1 << (voice->num & 0x1f); in sis_pcm_trigger()
638 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_pointer()
639 struct voice *voice = runtime->private_data; in sis_pcm_pointer()
642 cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); in sis_pcm_pointer()
650 struct snd_pcm_runtime *runtime = substream->runtime; in sis_capture_open()
651 struct voice *voice = &sis->capture_voice; in sis_capture_open()
657 spin_lock_irqsave(&sis->voice_lock, flags); in sis_capture_open()
658 if (voice->flags & VOICE_IN_USE) in sis_capture_open()
661 voice->flags |= VOICE_IN_USE; in sis_capture_open()
662 spin_unlock_irqrestore(&sis->voice_lock, flags); in sis_capture_open()
665 return -EAGAIN; in sis_capture_open()
667 voice->substream = substream; in sis_capture_open()
668 runtime->private_data = voice; in sis_capture_open()
669 runtime->hw = sis_capture_hw_info; in sis_capture_open()
670 runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC]; in sis_capture_open()
686 rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE, in sis_capture_hw_params()
701 struct snd_pcm_runtime *runtime = substream->runtime; in sis_prepare_timing_voice()
702 struct voice *timing = voice->timing; in sis_prepare_timing_voice()
703 void __iomem *play_base = timing->ctrl_base; in sis_prepare_timing_voice()
704 void __iomem *wave_base = timing->wave_base; in sis_prepare_timing_voice()
707 u32 vperiod, sso, reg; in sis_prepare_timing_voice() local
712 buffer_size = 4096 / runtime->channels; in sis_prepare_timing_voice()
713 buffer_size /= snd_pcm_format_size(runtime->format, 1); in sis_prepare_timing_voice()
722 * end -- this helps minimize the effects of any jitter. Adjust our in sis_prepare_timing_voice()
728 vperiod = runtime->period_size + 12; in sis_prepare_timing_voice()
736 tail = quarter_period - tail; in sis_prepare_timing_voice()
737 tail += loops - 1; in sis_prepare_timing_voice()
739 period_size -= tail; in sis_prepare_timing_voice()
742 sso = period_size - 1; in sis_prepare_timing_voice()
745 * don't need to use virtual periods -- disable them. in sis_prepare_timing_voice()
747 period_size = runtime->period_size; in sis_prepare_timing_voice()
748 sso = vperiod - 1; in sis_prepare_timing_voice()
755 timing->flags |= VOICE_SYNC_TIMING; in sis_prepare_timing_voice()
756 timing->sync_base = voice->ctrl_base; in sis_prepare_timing_voice()
757 timing->sync_cso = runtime->period_size; in sis_prepare_timing_voice()
758 timing->sync_period_size = runtime->period_size; in sis_prepare_timing_voice()
759 timing->sync_buffer_size = runtime->buffer_size; in sis_prepare_timing_voice()
760 timing->period_size = period_size; in sis_prepare_timing_voice()
761 timing->buffer_size = buffer_size; in sis_prepare_timing_voice()
762 timing->sso = sso; in sis_prepare_timing_voice()
763 timing->vperiod = vperiod; in sis_prepare_timing_voice()
765 /* Using unsigned samples with the all-zero silence buffer in sis_prepare_timing_voice()
767 * So ignore unsigned vs signed -- it doesn't change the timing. in sis_prepare_timing_voice()
770 if (snd_pcm_format_width(runtime->format) == 8) in sis_prepare_timing_voice()
772 if (runtime->channels == 1) in sis_prepare_timing_voice()
775 control = timing->buffer_size - 1; in sis_prepare_timing_voice()
777 sso_eso = timing->buffer_size - 1; in sis_prepare_timing_voice()
778 sso_eso |= timing->sso << 16; in sis_prepare_timing_voice()
780 delta = sis_rate_to_delta(runtime->rate); in sis_prepare_timing_voice()
785 writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE); in sis_prepare_timing_voice()
802 struct snd_pcm_runtime *runtime = substream->runtime; in sis_pcm_capture_prepare()
803 struct voice *voice = runtime->private_data; in sis_pcm_capture_prepare()
804 void __iomem *rec_base = voice->ctrl_base; in sis_pcm_capture_prepare()
809 * substream do not change on us while we're programming the HW. in sis_pcm_capture_prepare()
812 if (snd_pcm_format_width(runtime->format) == 8) in sis_pcm_capture_prepare()
814 if (!snd_pcm_format_signed(runtime->format)) in sis_pcm_capture_prepare()
816 if (runtime->channels == 1) in sis_pcm_capture_prepare()
819 dma_addr = runtime->dma_addr; in sis_pcm_capture_prepare()
820 leo = runtime->buffer_size - 1; in sis_pcm_capture_prepare()
827 if (voice->timing) { in sis_pcm_capture_prepare()
831 if (runtime->period_size != runtime->buffer_size) in sis_pcm_capture_prepare()
849 .trigger = sis_pcm_trigger,
858 .trigger = sis_pcm_trigger,
870 rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm); in sis_pcm_create()
874 pcm->private_data = sis; in sis_pcm_create()
875 strcpy(pcm->name, "SiS7019"); in sis_pcm_create()
876 sis->pcm = pcm; in sis_pcm_create()
885 &sis->pci->dev, 64*1024, 128*1024); in sis_pcm_create()
892 unsigned long io = sis->ioport; in sis_ac97_rw()
906 /* Get the AC97 semaphore -- software first, so we don't spin in sis_ac97_rw()
909 mutex_lock(&sis->ac97_mutex); in sis_ac97_rw()
912 while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) in sis_ac97_rw()
927 } while (--count); in sis_ac97_rw()
938 while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) in sis_ac97_rw()
948 mutex_unlock(&sis->ac97_mutex); in sis_ac97_rw()
951 dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n", in sis_ac97_rw()
966 sis_ac97_rw(ac97->private_data, ac97->num, in sis_ac97_write()
967 (val << 16) | (reg << 8) | cmd[ac97->num]); in sis_ac97_write()
977 return sis_ac97_rw(ac97->private_data, ac97->num, in sis_ac97_read()
978 (reg << 8) | cmd[ac97->num]); in sis_ac97_read()
994 rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus); in sis_mixer_create()
995 if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_mixer_create()
996 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]); in sis_mixer_create()
998 if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)) in sis_mixer_create()
999 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]); in sis_mixer_create()
1001 if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)) in sis_mixer_create()
1002 rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]); in sis_mixer_create()
1012 struct sis7019 *sis = card->private_data; in sis_chip_free()
1016 outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); in sis_chip_free()
1018 outl(0, sis->ioport + SIS_GCR); in sis_chip_free()
1019 outl(0, sis->ioport + SIS_GIER); in sis_chip_free()
1023 if (sis->irq >= 0) in sis_chip_free()
1024 free_irq(sis->irq, sis); in sis_chip_free()
1029 unsigned long io = sis->ioport; in sis_chip_init()
1030 void __iomem *ioaddr = sis->ioaddr; in sis_chip_init()
1042 /* Get the AC-link semaphore, and reset the codecs in sis_chip_init()
1045 while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) in sis_chip_init()
1049 return -EIO; in sis_chip_init()
1055 while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) in sis_chip_init()
1062 return -EIO; in sis_chip_init()
1069 sis->codecs_present = 0; in sis_chip_init()
1074 sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; in sis_chip_init()
1076 sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; in sis_chip_init()
1078 sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; in sis_chip_init()
1080 if (sis->codecs_present == codecs) in sis_chip_init()
1088 if (!sis->codecs_present) { in sis_chip_init()
1089 dev_err(&sis->pci->dev, "could not find any codecs\n"); in sis_chip_init()
1090 return -EIO; in sis_chip_init()
1093 if (sis->codecs_present != codecs) { in sis_chip_init()
1094 dev_warn(&sis->pci->dev, "missing codecs, found %0x, expected %0x\n", in sis_chip_init()
1095 sis->codecs_present, codecs); in sis_chip_init()
1099 * and enable PCM slots on the AC-link for L/R playback (3 & 4) and in sis_chip_init()
1109 /* All AC97 PCM slots should be sourced from sub-mixer 0. in sis_chip_init()
1120 * assign sub-mixer 0 to all playback channels, and avoid any in sis_chip_init()
1159 struct sis7019 *sis = card->private_data; in sis_suspend()
1160 void __iomem *ioaddr = sis->ioaddr; in sis_suspend()
1164 if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_suspend()
1165 snd_ac97_suspend(sis->ac97[0]); in sis_suspend()
1166 if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) in sis_suspend()
1167 snd_ac97_suspend(sis->ac97[1]); in sis_suspend()
1168 if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) in sis_suspend()
1169 snd_ac97_suspend(sis->ac97[2]); in sis_suspend()
1173 if (sis->irq >= 0) { in sis_suspend()
1174 free_irq(sis->irq, sis); in sis_suspend()
1175 sis->irq = -1; in sis_suspend()
1181 memcpy_fromio(sis->suspend_state[i], ioaddr, 4096); in sis_suspend()
1192 struct sis7019 *sis = card->private_data; in sis_resume()
1193 void __iomem *ioaddr = sis->ioaddr; in sis_resume()
1197 dev_err(&pci->dev, "unable to re-init controller\n"); in sis_resume()
1201 if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, in sis_resume()
1203 dev_err(&pci->dev, "unable to regain IRQ %d\n", pci->irq); in sis_resume()
1211 memcpy_toio(ioaddr, sis->suspend_state[i], 4096); in sis_resume()
1215 memset(sis->suspend_state[0], 0, 4096); in sis_resume()
1217 sis->irq = pci->irq; in sis_resume()
1219 if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) in sis_resume()
1220 snd_ac97_resume(sis->ac97[0]); in sis_resume()
1221 if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) in sis_resume()
1222 snd_ac97_resume(sis->ac97[1]); in sis_resume()
1223 if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) in sis_resume()
1224 snd_ac97_resume(sis->ac97[2]); in sis_resume()
1231 return -EIO; in sis_resume()
1250 sis->suspend_state[i] = devm_kmalloc(&sis->pci->dev, 4096, in sis_alloc_suspend()
1252 if (!sis->suspend_state[i]) in sis_alloc_suspend()
1253 return -ENOMEM; in sis_alloc_suspend()
1255 memset(sis->suspend_state[0], 0, 4096); in sis_alloc_suspend()
1263 struct sis7019 *sis = card->private_data; in sis_chip_create()
1272 rc = dma_set_mask(&pci->dev, DMA_BIT_MASK(30)); in sis_chip_create()
1274 dev_err(&pci->dev, "architecture does not support 30-bit PCI busmaster DMA"); in sis_chip_create()
1275 return -ENXIO; in sis_chip_create()
1278 mutex_init(&sis->ac97_mutex); in sis_chip_create()
1279 spin_lock_init(&sis->voice_lock); in sis_chip_create()
1280 sis->card = card; in sis_chip_create()
1281 sis->pci = pci; in sis_chip_create()
1282 sis->irq = -1; in sis_chip_create()
1283 sis->ioport = pci_resource_start(pci, 0); in sis_chip_create()
1287 dev_err(&pci->dev, "unable request regions\n"); in sis_chip_create()
1291 sis->ioaddr = devm_ioremap(&pci->dev, pci_resource_start(pci, 1), 0x4000); in sis_chip_create()
1292 if (!sis->ioaddr) { in sis_chip_create()
1293 dev_err(&pci->dev, "unable to remap MMIO, aborting\n"); in sis_chip_create()
1294 return -EIO; in sis_chip_create()
1299 dev_err(&pci->dev, "unable to allocate state storage\n"); in sis_chip_create()
1306 card->private_free = sis_chip_free; in sis_chip_create()
1308 rc = request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME, in sis_chip_create()
1311 dev_err(&pci->dev, "unable to allocate irq %d\n", sis->irq); in sis_chip_create()
1315 sis->irq = pci->irq; in sis_chip_create()
1316 card->sync_irq = sis->irq; in sis_chip_create()
1320 voice = &sis->voices[i]; in sis_chip_create()
1321 voice->num = i; in sis_chip_create()
1322 voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i); in sis_chip_create()
1323 voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i); in sis_chip_create()
1326 voice = &sis->capture_voice; in sis_chip_create()
1327 voice->flags = VOICE_CAPTURE; in sis_chip_create()
1328 voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN; in sis_chip_create()
1329 voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num); in sis_chip_create()
1342 return -ENOENT; in __snd_sis7019_probe()
1348 * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2. in __snd_sis7019_probe()
1355 rc = snd_devm_card_new(&pci->dev, index, id, THIS_MODULE, in __snd_sis7019_probe()
1360 strcpy(card->driver, "SiS7019"); in __snd_sis7019_probe()
1361 strcpy(card->shortname, "SiS7019"); in __snd_sis7019_probe()
1366 sis = card->private_data; in __snd_sis7019_probe()
1376 snprintf(card->longname, sizeof(card->longname), in __snd_sis7019_probe()
1378 card->shortname, snd_ac97_get_short_name(sis->ac97[0]), in __snd_sis7019_probe()
1379 sis->ioport, sis->irq); in __snd_sis7019_probe()
1392 return snd_card_free_on_error(&pci->dev, __snd_sis7019_probe(pci, pci_id)); in snd_sis7019_probe()