Lines Matching +full:pcm +full:- +full:clock +full:- +full:mode

1 // SPDX-License-Identifier: GPL-2.0-or-later
18 #include <linux/dma-mapping.h>
22 #include <sound/pcm.h>
37 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
61 #define SV_REG(sonic, x) ((sonic)->enh_port + SV_REG_##x)
64 #define SV_ENHANCED 0x01 /* audio mode select - enhanced mode */
68 #define SV_INTA 0x20 /* INTA driving - should be always 1 */
71 #define SV_DMAA_MASK 0x01 /* mask DMA-A interrupt */
72 #define SV_DMAC_MASK 0x04 /* mask DMA-C interrupt */
73 #define SV_SPEC_MASK 0x08 /* special interrupt mask - should be always masked */
77 #define SV_DMAA_IRQ 0x01 /* DMA-A interrupt */
78 #define SV_DMAC_IRQ 0x04 /* DMA-C interrupt */
83 #define SV_MCE 0x40 /* mode change enable */
107 #define SV_IREG_LEFT_PCM 0x10 /* Left PCM Input Control */
108 #define SV_IREG_RIGHT_PCM 0x11 /* Right PCM Input Control */
118 #define SV_IREG_PCM_RATE_LOW 0x1e /* PCM Sampling Rate Low Byte */
119 #define SV_IREG_PCM_RATE_HIGH 0x1f /* PCM Sampling Rate High Byte */
122 #define SV_IREG_ADC_CLOCK 0x22 /* ADC Clock Source Selection */
128 #define SV_IREG_MPU401 0x2a /* MPU-401 UART Operation */
206 unsigned int mode;
210 struct snd_pcm *pcm;
255 count--;
256 outl(addr, sonic->dmaa_port + SV_DMA_ADDR0);
257 outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
258 outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
260 dev_dbg(sonic->card->dev, "program dmaa: addr = 0x%x, paddr = 0x%x\n",
261 addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
269 /* note: dmac is working in word mode!!! */
271 count--;
272 outl(addr, sonic->dmac_port + SV_DMA_ADDR0);
273 outl(count, sonic->dmac_port + SV_DMA_COUNT0);
274 outb(0x14, sonic->dmac_port + SV_DMA_MODE);
276 dev_dbg(sonic->card->dev, "program dmac: addr = 0x%x, paddr = 0x%x\n",
277 addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
283 return (inl(sonic->dmaa_port + SV_DMA_COUNT0) & 0xffffff) + 1;
288 /* note: dmac is working in word mode!!! */
289 return ((inl(sonic->dmac_port + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
306 guard(spinlock_irqsave)(&sonic->reg_lock);
328 guard(spinlock_irqsave)(&sonic->reg_lock);
339 dev_dbg(sonic->card->dev,
342 dev_dbg(sonic->card->dev,
345 dev_dbg(sonic->card->dev,
348 dev_dbg(sonic->card->dev,
349 " 0x02: left AUX1 = 0x%02x 0x22: ADC clock = 0x%02x\n",
351 dev_dbg(sonic->card->dev,
354 dev_dbg(sonic->card->dev,
357 dev_dbg(sonic->card->dev,
360 dev_dbg(sonic->card->dev,
363 dev_dbg(sonic->card->dev,
366 dev_dbg(sonic->card->dev,
367 " 0x08: MIC = 0x%02x 0x28: --- = 0x%02x\n",
369 dev_dbg(sonic->card->dev,
370 " 0x09: Game port = 0x%02x 0x29: --- = 0x%02x\n",
372 dev_dbg(sonic->card->dev,
375 dev_dbg(sonic->card->dev,
378 dev_dbg(sonic->card->dev,
381 dev_dbg(sonic->card->dev,
384 dev_dbg(sonic->card->dev,
387 dev_dbg(sonic->card->dev,
388 " 0x0f: right analog = 0x%02x 0x2f: --- = 0x%02x\n",
390 dev_dbg(sonic->card->dev,
391 " 0x10: left PCM = 0x%02x 0x30: analog power = 0x%02x\n",
393 dev_dbg(sonic->card->dev,
394 " 0x11: right PCM = 0x%02x 0x31: analog power = 0x%02x\n",
396 dev_dbg(sonic->card->dev,
397 " 0x12: DMA data format = 0x%02x 0x32: --- = 0x%02x\n",
399 dev_dbg(sonic->card->dev,
400 " 0x13: P/C enable = 0x%02x 0x33: --- = 0x%02x\n",
402 dev_dbg(sonic->card->dev,
403 " 0x14: U/D button = 0x%02x 0x34: --- = 0x%02x\n",
405 dev_dbg(sonic->card->dev,
406 " 0x15: revision = 0x%02x 0x35: --- = 0x%02x\n",
408 dev_dbg(sonic->card->dev,
409 " 0x16: ADC output ctrl = 0x%02x 0x36: --- = 0x%02x\n",
411 dev_dbg(sonic->card->dev,
412 " 0x17: --- = 0x%02x 0x37: --- = 0x%02x\n",
414 dev_dbg(sonic->card->dev,
415 " 0x18: DMA A upper cnt = 0x%02x 0x38: --- = 0x%02x\n",
417 dev_dbg(sonic->card->dev,
418 " 0x19: DMA A lower cnt = 0x%02x 0x39: --- = 0x%02x\n",
420 dev_dbg(sonic->card->dev,
421 " 0x1a: --- = 0x%02x 0x3a: --- = 0x%02x\n",
423 dev_dbg(sonic->card->dev,
424 " 0x1b: --- = 0x%02x 0x3b: --- = 0x%02x\n",
426 dev_dbg(sonic->card->dev,
427 " 0x1c: DMA C upper cnt = 0x%02x 0x3c: --- = 0x%02x\n",
429 dev_dbg(sonic->card->dev,
430 " 0x1d: DMA C upper cnt = 0x%02x 0x3d: --- = 0x%02x\n",
432 dev_dbg(sonic->card->dev,
433 " 0x1e: PCM rate low = 0x%02x 0x3e: --- = 0x%02x\n",
435 dev_dbg(sonic->card->dev,
436 " 0x1f: PCM rate high = 0x%02x 0x3f: --- = 0x%02x\n",
446 guard(spinlock_irqsave)(&sonic->reg_lock);
449 sonic->format = inb(SV_REG(sonic, DATA));
452 sonic->format = (sonic->format & mask) | value;
453 outb(sonic->format, SV_REG(sonic, DATA));
477 xd = xr - rate;
479 xd = rate - xr;
482 m = xm - 2;
483 n = xn - 2;
490 dev_dbg(sonic->card->dev,
492 dev_dbg(sonic->card->dev,
505 guard(spinlock_irqsave)(&sonic->reg_lock);
514 unsigned char clock;
519 if ((48000 / div) == rate) { /* use the alternate clock */
520 clock = 0x10;
522 clock = 0x00;
525 guard(spinlock_irqsave)(&sonic->reg_lock);
526 snd_sonicvibes_out1(sonic, SV_IREG_ADC_ALT_RATE, (div - 1) << 4);
527 snd_sonicvibes_out1(sonic, SV_IREG_ADC_CLOCK, clock);
535 if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min ==
536 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max) {
537 rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min;
542 params->rate_num = rate;
543 params->rate_den = 1;
548 params->rate_num = (SV_REFFREQUENCY/16) * (n+2) * r;
549 params->rate_den = (SV_ADCMULT/512) * (m+2);
562 guard(spinlock_irqsave)(&sonic->reg_lock);
569 guard(spinlock)(&sonic->reg_lock);
571 if (!(sonic->enable & what)) {
572 sonic->enable |= what;
573 snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable);
576 if (sonic->enable & what) {
577 sonic->enable &= ~what;
578 snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable);
581 return -EINVAL;
595 outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK));
596 dev_err(sonic->card->dev,
597 "IRQ failure - interrupts disabled!!\n");
600 if (sonic->pcm) {
602 snd_pcm_period_elapsed(sonic->playback_substream);
604 snd_pcm_period_elapsed(sonic->capture_substream);
606 if (sonic->rmidi) {
608 snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data);
614 scoped_guard(spinlock, &sonic->reg_lock) {
618 vol = -vol;
642 snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_mute->id);
643 snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_volume->id);
649 * PCM part
669 struct snd_pcm_runtime *runtime = substream->runtime;
674 sonic->p_dma_size = size;
675 count--;
676 if (runtime->channels > 1)
678 if (snd_pcm_format_width(runtime->format) == 16)
681 snd_sonicvibes_set_dac_rate(sonic, runtime->rate);
682 guard(spinlock_irq)(&sonic->reg_lock);
683 snd_sonicvibes_setdmaa(sonic, runtime->dma_addr, size);
692 struct snd_pcm_runtime *runtime = substream->runtime;
697 sonic->c_dma_size = size;
699 count--;
700 if (runtime->channels > 1)
702 if (snd_pcm_format_width(runtime->format) == 16)
705 snd_sonicvibes_set_adc_rate(sonic, runtime->rate);
706 guard(spinlock_irq)(&sonic->reg_lock);
707 snd_sonicvibes_setdmac(sonic, runtime->dma_addr, size);
718 if (!(sonic->enable & 1))
720 ptr = sonic->p_dma_size - snd_sonicvibes_getdmaa(sonic);
721 return bytes_to_frames(substream->runtime, ptr);
728 if (!(sonic->enable & 2))
730 ptr = sonic->c_dma_size - snd_sonicvibes_getdmac(sonic);
731 return bytes_to_frames(substream->runtime, ptr);
775 struct snd_pcm_runtime *runtime = substream->runtime;
777 sonic->mode |= SV_MODE_PLAY;
778 sonic->playback_substream = substream;
779 runtime->hw = snd_sonicvibes_playback;
780 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_sonicvibes_hw_constraint_dac_rate, NULL, SNDRV_PCM_HW_PARAM_RATE, -1);
787 struct snd_pcm_runtime *runtime = substream->runtime;
789 sonic->mode |= SV_MODE_CAPTURE;
790 sonic->capture_substream = substream;
791 runtime->hw = snd_sonicvibes_capture;
801 sonic->playback_substream = NULL;
802 sonic->mode &= ~SV_MODE_PLAY;
810 sonic->capture_substream = NULL;
811 sonic->mode &= ~SV_MODE_CAPTURE;
833 struct snd_pcm *pcm;
836 err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm);
839 if (snd_BUG_ON(!pcm))
840 return -EINVAL;
842 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sonicvibes_playback_ops);
843 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sonicvibes_capture_ops);
845 pcm->private_data = sonic;
846 pcm->info_flags = 0;
847 strscpy(pcm->name, "S3 SonicVibes");
848 sonic->pcm = pcm;
850 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
851 &sonic->pci->dev, 64*1024, 128*1024);
868 "CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix"
878 guard(spinlock_irq)(&sonic->reg_lock);
879 ucontrol->value.enumerated.item[0] = ((snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
880 ucontrol->value.enumerated.item[1] = ((snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
890 if (ucontrol->value.enumerated.item[0] >= 7 ||
891 ucontrol->value.enumerated.item[1] >= 7)
892 return -EINVAL;
893 left = (ucontrol->value.enumerated.item[0] + 1) << 5;
894 right = (ucontrol->value.enumerated.item[1] + 1) << 5;
895 guard(spinlock_irq)(&sonic->reg_lock);
914 int mask = (kcontrol->private_value >> 16) & 0xff;
916 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
917 uinfo->count = 1;
918 uinfo->value.integer.min = 0;
919 uinfo->value.integer.max = mask;
926 int reg = kcontrol->private_value & 0xff;
927 int shift = (kcontrol->private_value >> 8) & 0xff;
928 int mask = (kcontrol->private_value >> 16) & 0xff;
929 int invert = (kcontrol->private_value >> 24) & 0xff;
931 guard(spinlock_irq)(&sonic->reg_lock);
932 ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, reg)>> shift) & mask;
934 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
941 int reg = kcontrol->private_value & 0xff;
942 int shift = (kcontrol->private_value >> 8) & 0xff;
943 int mask = (kcontrol->private_value >> 16) & 0xff;
944 int invert = (kcontrol->private_value >> 24) & 0xff;
948 val = (ucontrol->value.integer.value[0] & mask);
950 val = mask - val;
952 guard(spinlock_irq)(&sonic->reg_lock);
968 int mask = (kcontrol->private_value >> 24) & 0xff;
970 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
971 uinfo->count = 2;
972 uinfo->value.integer.min = 0;
973 uinfo->value.integer.max = mask;
980 int left_reg = kcontrol->private_value & 0xff;
981 int right_reg = (kcontrol->private_value >> 8) & 0xff;
982 int shift_left = (kcontrol->private_value >> 16) & 0x07;
983 int shift_right = (kcontrol->private_value >> 19) & 0x07;
984 int mask = (kcontrol->private_value >> 24) & 0xff;
985 int invert = (kcontrol->private_value >> 22) & 1;
987 guard(spinlock_irq)(&sonic->reg_lock);
988 ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, left_reg) >> shift_left) & mask;
989 ucontrol->value.integer.value[1] = (snd_sonicvibes_in1(sonic, right_reg) >> shift_right) & mask;
991 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
992 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
1000 int left_reg = kcontrol->private_value & 0xff;
1001 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1002 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1003 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1004 int mask = (kcontrol->private_value >> 24) & 0xff;
1005 int invert = (kcontrol->private_value >> 22) & 1;
1009 val1 = ucontrol->value.integer.value[0] & mask;
1010 val2 = ucontrol->value.integer.value[1] & mask;
1012 val1 = mask - val1;
1013 val2 = mask - val2;
1017 guard(spinlock_irq)(&sonic->reg_lock);
1045 SONICVIBES_DOUBLE("PCM Playback Switch", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 7, 7, 1, 1),
1046 SONICVIBES_DOUBLE("PCM Playback Volume", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 0, 0, 63, 1),
1055 sonic->master_mute = NULL;
1056 sonic->master_volume = NULL;
1066 if (snd_BUG_ON(!sonic || !sonic->card))
1067 return -EINVAL;
1068 card = sonic->card;
1069 strscpy(card->mixername, "S3 SonicVibes");
1078 case 1: kctl->private_free = snd_sonicvibes_master_free; break;
1091 struct sonicvibes *sonic = entry->private_data;
1094 tmp = sonic->srs_space & 0x0f;
1096 str_off_on(sonic->srs_space & 0x80));
1102 tmp = sonic->srs_center & 0x0f;
1108 tmp = sonic->wave_source & 0x03;
1110 tmp == 0x00 ? "on-board ROM" :
1111 tmp == 0x01 ? "PCI bus" : "on-board ROM + PCI bus");
1112 tmp = sonic->mpu_switch;
1120 snd_card_ro_proc_new(sonic->card, "sonicvibes", sonic,
1137 sonic->gameport = gp = gameport_allocate_port();
1139 dev_err(sonic->card->dev,
1141 return -ENOMEM;
1145 gameport_set_phys(gp, "pci%s/gameport0", pci_name(sonic->pci));
1146 gameport_set_dev_parent(gp, &sonic->pci->dev);
1147 gp->io = sonic->game_port;
1151 err = snd_ctl_add(sonic->card,
1161 if (sonic->gameport) {
1162 gameport_unregister_port(sonic->gameport);
1163 sonic->gameport = NULL;
1167 static inline int snd_sonicvibes_create_gameport(struct sonicvibes *sonic) { return -ENOSYS; }
1173 struct sonicvibes *sonic = card->private_data;
1176 pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port);
1177 pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port);
1185 struct sonicvibes *sonic = card->private_data;
1194 if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
1195 dev_err(card->dev,
1197 return -ENXIO;
1200 spin_lock_init(&sonic->reg_lock);
1201 sonic->card = card;
1202 sonic->pci = pci;
1203 sonic->irq = -1;
1209 sonic->sb_port = pci_resource_start(pci, 0);
1210 sonic->enh_port = pci_resource_start(pci, 1);
1211 sonic->synth_port = pci_resource_start(pci, 2);
1212 sonic->midi_port = pci_resource_start(pci, 3);
1213 sonic->game_port = pci_resource_start(pci, 4);
1215 if (devm_request_irq(&pci->dev, pci->irq, snd_sonicvibes_interrupt,
1217 dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
1218 return -EBUSY;
1220 sonic->irq = pci->irq;
1221 card->sync_irq = sonic->irq;
1222 card->private_free = snd_sonicvibes_free;
1232 dev_info(card->dev,
1239 dev_info(card->dev,
1246 sonic->res_dmaa = devm_request_region(&pci->dev, dmaa, 0x10,
1247 "S3 SonicVibes DDMA-A");
1248 if (!sonic->res_dmaa) {
1249 dev_err(card->dev,
1250 "unable to grab DDMA-A port at 0x%x-0x%x\n",
1251 dmaa, dmaa + 0x10 - 1);
1252 return -EBUSY;
1254 sonic->res_dmac = devm_request_region(&pci->dev, dmac, 0x10,
1255 "S3 SonicVibes DDMA-C");
1256 if (!sonic->res_dmac) {
1257 dev_err(card->dev,
1258 "unable to grab DDMA-C port at 0x%x-0x%x\n",
1259 dmac, dmac + 0x10 - 1);
1260 return -EBUSY;
1263 pci_read_config_dword(pci, 0x40, &sonic->dmaa_port);
1264 pci_read_config_dword(pci, 0x48, &sonic->dmac_port);
1265 sonic->dmaa_port &= ~0x0f;
1266 sonic->dmac_port &= ~0x0f;
1267 pci_write_config_dword(pci, 0x40, sonic->dmaa_port | 9); /* enable + enhanced */
1268 pci_write_config_dword(pci, 0x48, sonic->dmac_port | 9); /* enable */
1281 snd_sonicvibes_out(sonic, SV_IREG_PC_ENABLE, sonic->enable = 0); /* disable playback & capture */
1282 outb(sonic->irqmask = ~(SV_DMAA_MASK | SV_DMAC_MASK | SV_UD_MASK), SV_REG(sonic, IRQMASK));
1284 snd_sonicvibes_out(sonic, SV_IREG_ADC_CLOCK, 0); /* use PLL as clock source */
1288 snd_sonicvibes_out(sonic, SV_IREG_SRS_SPACE, sonic->srs_space = 0x80); /* SRS space off */
1289 snd_sonicvibes_out(sonic, SV_IREG_SRS_CENTER, sonic->srs_center = 0x00);/* SRS center off */
1290 snd_sonicvibes_out(sonic, SV_IREG_MPU401, sonic->mpu_switch = 0x05); /* MPU-401 switch */
1291 snd_sonicvibes_out(sonic, SV_IREG_WAVE_SOURCE, sonic->wave_source = 0x00); /* onboard ROM */
1315 sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION);
1335 struct sonicvibes *sonic = mpu->private_data;
1336 outb(sonic->irqmask &= ~SV_MIDI_MASK, SV_REG(sonic, IRQMASK));
1342 struct sonicvibes *sonic = mpu->private_data;
1343 outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK));
1349 struct snd_mpu401 * mpu = rmidi->private_data;
1350 struct snd_card *card = sonic->card;
1354 mpu->private_data = sonic;
1355 mpu->open_input = snd_sonicvibes_midi_input_open;
1356 mpu->close_input = snd_sonicvibes_midi_input_close;
1376 return -ENODEV;
1379 return -ENOENT;
1382 err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
1386 sonic = card->private_data;
1393 strscpy(card->driver, "SonicVibes");
1394 strscpy(card->shortname, "S3 SonicVibes");
1395 sprintf(card->longname, "%s rev %i at 0x%llx, irq %i",
1396 card->shortname,
1397 sonic->revision,
1399 sonic->irq);
1408 sonic->midi_port,
1411 -1, &midi_uart);
1415 err = snd_opl3_create(card, sonic->synth_port,
1416 sonic->synth_port + 2,
1440 return snd_card_free_on_error(&pci->dev, __snd_sonic_probe(pci, pci_id));