275 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Sound Core PDAudioCF soundcards4 *5 * PCM part6 *7 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>8 */9 10#include <linux/delay.h>11#include <sound/core.h>12#include <sound/asoundef.h>13#include "pdaudiocf.h"14 15 16/*17 * clear the SRAM contents18 */19static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)20{21 int max_loop = 64 * 1024;22 23 while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {24 if (max_loop-- < 0)25 return -EIO;26 inw(chip->port + PDAUDIOCF_REG_MD);27 }28 return 0;29}30 31/*32 * pdacf_pcm_trigger - trigger callback for capture33 */34static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)35{36 struct snd_pdacf *chip = snd_pcm_substream_chip(subs);37 struct snd_pcm_runtime *runtime = subs->runtime;38 int inc, ret = 0, rate;39 unsigned short mask, val, tmp;40 41 if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)42 return -EBUSY;43 44 switch (cmd) {45 case SNDRV_PCM_TRIGGER_START:46 chip->pcm_hwptr = 0;47 chip->pcm_tdone = 0;48 fallthrough;49 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:50 case SNDRV_PCM_TRIGGER_RESUME:51 mask = 0;52 val = PDAUDIOCF_RECORD;53 inc = 1;54 rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);55 break;56 case SNDRV_PCM_TRIGGER_STOP:57 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:58 case SNDRV_PCM_TRIGGER_SUSPEND:59 mask = PDAUDIOCF_RECORD;60 val = 0;61 inc = -1;62 rate = 0;63 break;64 default:65 return -EINVAL;66 }67 mutex_lock(&chip->reg_lock);68 chip->pcm_running += inc;69 tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);70 if (chip->pcm_running) {71 if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {72 chip->pcm_running -= inc;73 ret = -EIO;74 goto __end;75 }76 }77 tmp &= ~mask;78 tmp |= val;79 pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);80 __end:81 mutex_unlock(&chip->reg_lock);82 snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);83 return ret;84}85 86/*87 * pdacf_pcm_prepare - prepare callback for playback and capture88 */89static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)90{91 struct snd_pdacf *chip = snd_pcm_substream_chip(subs);92 struct snd_pcm_runtime *runtime = subs->runtime;93 u16 val, nval, aval;94 95 if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)96 return -EBUSY;97 98 chip->pcm_channels = runtime->channels;99 100 chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;101#ifdef SNDRV_LITTLE_ENDIAN102 chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;103#else104 chip->pcm_swab = chip->pcm_little;105#endif106 107 if (snd_pcm_format_unsigned(runtime->format))108 chip->pcm_xor = 0x80008000;109 110 if (pdacf_pcm_clear_sram(chip) < 0)111 return -EIO;112 113 val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);114 nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);115 switch (runtime->format) {116 case SNDRV_PCM_FORMAT_S16_LE:117 case SNDRV_PCM_FORMAT_S16_BE:118 break;119 default: /* 24-bit */120 nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;121 break;122 }123 aval = 0;124 chip->pcm_sample = 4;125 switch (runtime->format) {126 case SNDRV_PCM_FORMAT_S16_LE:127 case SNDRV_PCM_FORMAT_S16_BE:128 aval = AK4117_DIF_16R;129 chip->pcm_frame = 2;130 chip->pcm_sample = 2;131 break;132 case SNDRV_PCM_FORMAT_S24_3LE:133 case SNDRV_PCM_FORMAT_S24_3BE:134 chip->pcm_sample = 3;135 fallthrough;136 default: /* 24-bit */137 aval = AK4117_DIF_24R;138 chip->pcm_frame = 3;139 chip->pcm_xor &= 0xffff0000;140 break;141 }142 143 if (val != nval) {144 snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);145 pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);146 }147 148 val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER);149 val &= ~(PDAUDIOCF_IRQLVLEN1);150 val |= PDAUDIOCF_IRQLVLEN0;151 pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);152 153 chip->pcm_size = runtime->buffer_size;154 chip->pcm_period = runtime->period_size;155 chip->pcm_area = runtime->dma_area;156 157 return 0;158}159 160 161/*162 * capture hw information163 */164 165static const struct snd_pcm_hardware pdacf_pcm_capture_hw = {166 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |167 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |168 SNDRV_PCM_INFO_MMAP_VALID |169 SNDRV_PCM_INFO_BATCH),170 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |171 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |172 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,173 .rates = SNDRV_PCM_RATE_32000 |174 SNDRV_PCM_RATE_44100 |175 SNDRV_PCM_RATE_48000 |176 SNDRV_PCM_RATE_88200 |177 SNDRV_PCM_RATE_96000 |178 SNDRV_PCM_RATE_176400 |179 SNDRV_PCM_RATE_192000,180 .rate_min = 32000,181 .rate_max = 192000,182 .channels_min = 1,183 .channels_max = 2,184 .buffer_bytes_max = (512*1024),185 .period_bytes_min = 8*1024,186 .period_bytes_max = (64*1024),187 .periods_min = 2,188 .periods_max = 128,189 .fifo_size = 0,190};191 192 193/*194 * pdacf_pcm_capture_open - open callback for capture195 */196static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)197{198 struct snd_pcm_runtime *runtime = subs->runtime;199 struct snd_pdacf *chip = snd_pcm_substream_chip(subs);200 201 if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)202 return -EBUSY;203 204 runtime->hw = pdacf_pcm_capture_hw;205 runtime->private_data = chip;206 chip->pcm_substream = subs;207 208 return 0;209}210 211/*212 * pdacf_pcm_capture_close - close callback for capture213 */214static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)215{216 struct snd_pdacf *chip = snd_pcm_substream_chip(subs);217 218 if (!chip)219 return -EINVAL;220 pdacf_reinit(chip, 0);221 chip->pcm_substream = NULL;222 return 0;223}224 225 226/*227 * pdacf_pcm_capture_pointer - pointer callback for capture228 */229static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)230{231 struct snd_pdacf *chip = snd_pcm_substream_chip(subs);232 return chip->pcm_hwptr;233}234 235/*236 * operators for PCM capture237 */238static const struct snd_pcm_ops pdacf_pcm_capture_ops = {239 .open = pdacf_pcm_capture_open,240 .close = pdacf_pcm_capture_close,241 .prepare = pdacf_pcm_prepare,242 .trigger = pdacf_pcm_trigger,243 .pointer = pdacf_pcm_capture_pointer,244};245 246 247/*248 * snd_pdacf_pcm_new - create and initialize a pcm249 */250int snd_pdacf_pcm_new(struct snd_pdacf *chip)251{252 struct snd_pcm *pcm;253 int err;254 255 err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);256 if (err < 0)257 return err;258 259 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);260 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL,261 0, 0);262 263 pcm->private_data = chip;264 pcm->info_flags = 0;265 pcm->nonatomic = true;266 strcpy(pcm->name, chip->card->shortname);267 chip->pcm = pcm;268 269 err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);270 if (err < 0)271 return err;272 273 return 0;274}275