1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Driver for Sound Core PDAudioCF soundcards 4 * 5 * PCM part 6 * 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 contents 18 */ 19 static 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 capture 33 */ 34 static 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 capture 88 */ 89 static 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_ENDIAN 102 chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0; 103 #else 104 chip->pcm_swab = chip->pcm_little; 105 #endif 106 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 information 163 */ 164 165 static 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 capture 195 */ 196 static 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 capture 213 */ 214 static 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 capture 228 */ 229 static 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 capture 237 */ 238 static 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 pcm 249 */ 250 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.