Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
26428 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Driver for Sound Core PDAudioCF soundcards3*4* PCM part5*6* Copyright (c) 2003 by Jaroslav Kysela <[email protected]>7*/89#include <linux/delay.h>10#include <sound/core.h>11#include <sound/asoundef.h>12#include "pdaudiocf.h"131415/*16* clear the SRAM contents17*/18static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)19{20int max_loop = 64 * 1024;2122while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {23if (max_loop-- < 0)24return -EIO;25inw(chip->port + PDAUDIOCF_REG_MD);26}27return 0;28}2930/*31* pdacf_pcm_trigger - trigger callback for capture32*/33static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)34{35struct snd_pdacf *chip = snd_pcm_substream_chip(subs);36struct snd_pcm_runtime *runtime = subs->runtime;37int inc, ret = 0, rate;38unsigned short mask, val, tmp;3940if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)41return -EBUSY;4243switch (cmd) {44case SNDRV_PCM_TRIGGER_START:45chip->pcm_hwptr = 0;46chip->pcm_tdone = 0;47fallthrough;48case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:49case SNDRV_PCM_TRIGGER_RESUME:50mask = 0;51val = PDAUDIOCF_RECORD;52inc = 1;53rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);54break;55case SNDRV_PCM_TRIGGER_STOP:56case SNDRV_PCM_TRIGGER_PAUSE_PUSH:57case SNDRV_PCM_TRIGGER_SUSPEND:58mask = PDAUDIOCF_RECORD;59val = 0;60inc = -1;61rate = 0;62break;63default:64return -EINVAL;65}66mutex_lock(&chip->reg_lock);67chip->pcm_running += inc;68tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);69if (chip->pcm_running) {70if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {71chip->pcm_running -= inc;72ret = -EIO;73goto __end;74}75}76tmp &= ~mask;77tmp |= val;78pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);79__end:80mutex_unlock(&chip->reg_lock);81snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);82return ret;83}8485/*86* pdacf_pcm_prepare - prepare callback for playback and capture87*/88static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)89{90struct snd_pdacf *chip = snd_pcm_substream_chip(subs);91struct snd_pcm_runtime *runtime = subs->runtime;92u16 val, nval, aval;9394if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)95return -EBUSY;9697chip->pcm_channels = runtime->channels;9899chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;100#ifdef SNDRV_LITTLE_ENDIAN101chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;102#else103chip->pcm_swab = chip->pcm_little;104#endif105106if (snd_pcm_format_unsigned(runtime->format))107chip->pcm_xor = 0x80008000;108109if (pdacf_pcm_clear_sram(chip) < 0)110return -EIO;111112val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);113nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);114switch (runtime->format) {115case SNDRV_PCM_FORMAT_S16_LE:116case SNDRV_PCM_FORMAT_S16_BE:117break;118default: /* 24-bit */119nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;120break;121}122aval = 0;123chip->pcm_sample = 4;124switch (runtime->format) {125case SNDRV_PCM_FORMAT_S16_LE:126case SNDRV_PCM_FORMAT_S16_BE:127aval = AK4117_DIF_16R;128chip->pcm_frame = 2;129chip->pcm_sample = 2;130break;131case SNDRV_PCM_FORMAT_S24_3LE:132case SNDRV_PCM_FORMAT_S24_3BE:133chip->pcm_sample = 3;134fallthrough;135default: /* 24-bit */136aval = AK4117_DIF_24R;137chip->pcm_frame = 3;138chip->pcm_xor &= 0xffff0000;139break;140}141142if (val != nval) {143snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);144pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);145}146147val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER);148val &= ~(PDAUDIOCF_IRQLVLEN1);149val |= PDAUDIOCF_IRQLVLEN0;150pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);151152chip->pcm_size = runtime->buffer_size;153chip->pcm_period = runtime->period_size;154chip->pcm_area = runtime->dma_area;155156return 0;157}158159160/*161* capture hw information162*/163164static const struct snd_pcm_hardware pdacf_pcm_capture_hw = {165.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |166SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |167SNDRV_PCM_INFO_MMAP_VALID |168SNDRV_PCM_INFO_BATCH),169.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |170SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |171SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,172.rates = SNDRV_PCM_RATE_32000 |173SNDRV_PCM_RATE_44100 |174SNDRV_PCM_RATE_48000 |175SNDRV_PCM_RATE_88200 |176SNDRV_PCM_RATE_96000 |177SNDRV_PCM_RATE_176400 |178SNDRV_PCM_RATE_192000,179.rate_min = 32000,180.rate_max = 192000,181.channels_min = 1,182.channels_max = 2,183.buffer_bytes_max = (512*1024),184.period_bytes_min = 8*1024,185.period_bytes_max = (64*1024),186.periods_min = 2,187.periods_max = 128,188.fifo_size = 0,189};190191192/*193* pdacf_pcm_capture_open - open callback for capture194*/195static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)196{197struct snd_pcm_runtime *runtime = subs->runtime;198struct snd_pdacf *chip = snd_pcm_substream_chip(subs);199200if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)201return -EBUSY;202203runtime->hw = pdacf_pcm_capture_hw;204runtime->private_data = chip;205chip->pcm_substream = subs;206207return 0;208}209210/*211* pdacf_pcm_capture_close - close callback for capture212*/213static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)214{215struct snd_pdacf *chip = snd_pcm_substream_chip(subs);216217if (!chip)218return -EINVAL;219pdacf_reinit(chip, 0);220chip->pcm_substream = NULL;221return 0;222}223224225/*226* pdacf_pcm_capture_pointer - pointer callback for capture227*/228static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)229{230struct snd_pdacf *chip = snd_pcm_substream_chip(subs);231return chip->pcm_hwptr;232}233234/*235* operators for PCM capture236*/237static const struct snd_pcm_ops pdacf_pcm_capture_ops = {238.open = pdacf_pcm_capture_open,239.close = pdacf_pcm_capture_close,240.prepare = pdacf_pcm_prepare,241.trigger = pdacf_pcm_trigger,242.pointer = pdacf_pcm_capture_pointer,243};244245246/*247* snd_pdacf_pcm_new - create and initialize a pcm248*/249int snd_pdacf_pcm_new(struct snd_pdacf *chip)250{251struct snd_pcm *pcm;252int err;253254err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);255if (err < 0)256return err;257258snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);259snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL,2600, 0);261262pcm->private_data = chip;263pcm->info_flags = 0;264pcm->nonatomic = true;265strscpy(pcm->name, chip->card->shortname);266chip->pcm = pcm;267268err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);269if (err < 0)270return err;271272return 0;273}274275276