162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * C-Media CMI8788 driver - PCM code 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <sound/control.h> 1062306a36Sopenharmony_ci#include <sound/core.h> 1162306a36Sopenharmony_ci#include <sound/pcm.h> 1262306a36Sopenharmony_ci#include <sound/pcm_params.h> 1362306a36Sopenharmony_ci#include "oxygen.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* most DMA channels have a 16-bit counter for 32-bit words */ 1662306a36Sopenharmony_ci#define BUFFER_BYTES_MAX ((1 << 16) * 4) 1762306a36Sopenharmony_ci/* the multichannel DMA channel has a 24-bit counter */ 1862306a36Sopenharmony_ci#define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define FIFO_BYTES 256 2162306a36Sopenharmony_ci#define FIFO_BYTES_MULTICH 1024 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define PERIOD_BYTES_MIN 64 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) 2662306a36Sopenharmony_ci#define DEFAULT_BUFFER_BYTES_MULTICH (1024 * 1024) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct snd_pcm_hardware oxygen_stereo_hardware = { 2962306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 3062306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 3162306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 3262306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 3362306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 3462306a36Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 3562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 3662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 3762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | 3862306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | 3962306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | 4062306a36Sopenharmony_ci SNDRV_PCM_RATE_64000 | 4162306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 | 4262306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | 4362306a36Sopenharmony_ci SNDRV_PCM_RATE_176400 | 4462306a36Sopenharmony_ci SNDRV_PCM_RATE_192000, 4562306a36Sopenharmony_ci .rate_min = 32000, 4662306a36Sopenharmony_ci .rate_max = 192000, 4762306a36Sopenharmony_ci .channels_min = 2, 4862306a36Sopenharmony_ci .channels_max = 2, 4962306a36Sopenharmony_ci .buffer_bytes_max = BUFFER_BYTES_MAX, 5062306a36Sopenharmony_ci .period_bytes_min = PERIOD_BYTES_MIN, 5162306a36Sopenharmony_ci .period_bytes_max = BUFFER_BYTES_MAX, 5262306a36Sopenharmony_ci .periods_min = 1, 5362306a36Sopenharmony_ci .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, 5462306a36Sopenharmony_ci .fifo_size = FIFO_BYTES, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_cistatic const struct snd_pcm_hardware oxygen_multichannel_hardware = { 5762306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 5862306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 5962306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 6062306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 6162306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 6262306a36Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 6362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 6462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 6562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_32000 | 6662306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 | 6762306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | 6862306a36Sopenharmony_ci SNDRV_PCM_RATE_64000 | 6962306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 | 7062306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | 7162306a36Sopenharmony_ci SNDRV_PCM_RATE_176400 | 7262306a36Sopenharmony_ci SNDRV_PCM_RATE_192000, 7362306a36Sopenharmony_ci .rate_min = 32000, 7462306a36Sopenharmony_ci .rate_max = 192000, 7562306a36Sopenharmony_ci .channels_min = 2, 7662306a36Sopenharmony_ci .channels_max = 8, 7762306a36Sopenharmony_ci .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, 7862306a36Sopenharmony_ci .period_bytes_min = PERIOD_BYTES_MIN, 7962306a36Sopenharmony_ci .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, 8062306a36Sopenharmony_ci .periods_min = 1, 8162306a36Sopenharmony_ci .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, 8262306a36Sopenharmony_ci .fifo_size = FIFO_BYTES_MULTICH, 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_cistatic const struct snd_pcm_hardware oxygen_ac97_hardware = { 8562306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 8662306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 8762306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 8862306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 8962306a36Sopenharmony_ci SNDRV_PCM_INFO_SYNC_START | 9062306a36Sopenharmony_ci SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 9162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 9262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 9362306a36Sopenharmony_ci .rate_min = 48000, 9462306a36Sopenharmony_ci .rate_max = 48000, 9562306a36Sopenharmony_ci .channels_min = 2, 9662306a36Sopenharmony_ci .channels_max = 2, 9762306a36Sopenharmony_ci .buffer_bytes_max = BUFFER_BYTES_MAX, 9862306a36Sopenharmony_ci .period_bytes_min = PERIOD_BYTES_MIN, 9962306a36Sopenharmony_ci .period_bytes_max = BUFFER_BYTES_MAX, 10062306a36Sopenharmony_ci .periods_min = 1, 10162306a36Sopenharmony_ci .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, 10262306a36Sopenharmony_ci .fifo_size = FIFO_BYTES, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { 10662306a36Sopenharmony_ci [PCM_A] = &oxygen_stereo_hardware, 10762306a36Sopenharmony_ci [PCM_B] = &oxygen_stereo_hardware, 10862306a36Sopenharmony_ci [PCM_C] = &oxygen_stereo_hardware, 10962306a36Sopenharmony_ci [PCM_SPDIF] = &oxygen_stereo_hardware, 11062306a36Sopenharmony_ci [PCM_MULTICH] = &oxygen_multichannel_hardware, 11162306a36Sopenharmony_ci [PCM_AC97] = &oxygen_ac97_hardware, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline unsigned int 11562306a36Sopenharmony_cioxygen_substream_channel(struct snd_pcm_substream *substream) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return (unsigned int)(uintptr_t)substream->runtime->private_data; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int oxygen_open(struct snd_pcm_substream *substream, 12162306a36Sopenharmony_ci unsigned int channel) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 12462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci runtime->private_data = (void *)(uintptr_t)channel; 12862306a36Sopenharmony_ci if (channel == PCM_B && chip->has_ac97_1 && 12962306a36Sopenharmony_ci (chip->model.device_config & CAPTURE_2_FROM_AC97_1)) 13062306a36Sopenharmony_ci runtime->hw = oxygen_ac97_hardware; 13162306a36Sopenharmony_ci else 13262306a36Sopenharmony_ci runtime->hw = *oxygen_hardware[channel]; 13362306a36Sopenharmony_ci switch (channel) { 13462306a36Sopenharmony_ci case PCM_C: 13562306a36Sopenharmony_ci if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) { 13662306a36Sopenharmony_ci runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | 13762306a36Sopenharmony_ci SNDRV_PCM_RATE_64000); 13862306a36Sopenharmony_ci runtime->hw.rate_min = 44100; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci fallthrough; 14162306a36Sopenharmony_ci case PCM_A: 14262306a36Sopenharmony_ci case PCM_B: 14362306a36Sopenharmony_ci runtime->hw.fifo_size = 0; 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case PCM_MULTICH: 14662306a36Sopenharmony_ci runtime->hw.channels_max = chip->model.dac_channels_pcm; 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci if (chip->model.pcm_hardware_filter) 15062306a36Sopenharmony_ci chip->model.pcm_hardware_filter(channel, &runtime->hw); 15162306a36Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 15262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); 15362306a36Sopenharmony_ci if (err < 0) 15462306a36Sopenharmony_ci return err; 15562306a36Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 15662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); 15762306a36Sopenharmony_ci if (err < 0) 15862306a36Sopenharmony_ci return err; 15962306a36Sopenharmony_ci if (runtime->hw.formats & SNDRV_PCM_FMTBIT_S32_LE) { 16062306a36Sopenharmony_ci err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 16162306a36Sopenharmony_ci if (err < 0) 16262306a36Sopenharmony_ci return err; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci if (runtime->hw.channels_max > 2) { 16562306a36Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 16662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 16762306a36Sopenharmony_ci 2); 16862306a36Sopenharmony_ci if (err < 0) 16962306a36Sopenharmony_ci return err; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci snd_pcm_set_sync(substream); 17262306a36Sopenharmony_ci chip->streams[channel] = substream; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci mutex_lock(&chip->mutex); 17562306a36Sopenharmony_ci chip->pcm_active |= 1 << channel; 17662306a36Sopenharmony_ci if (channel == PCM_SPDIF) { 17762306a36Sopenharmony_ci chip->spdif_pcm_bits = chip->spdif_bits; 17862306a36Sopenharmony_ci chip->controls[CONTROL_SPDIF_PCM]->vd[0].access &= 17962306a36Sopenharmony_ci ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 18062306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | 18162306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, 18262306a36Sopenharmony_ci &chip->controls[CONTROL_SPDIF_PCM]->id); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int oxygen_rec_a_open(struct snd_pcm_substream *substream) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci return oxygen_open(substream, PCM_A); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int oxygen_rec_b_open(struct snd_pcm_substream *substream) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return oxygen_open(substream, PCM_B); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int oxygen_rec_c_open(struct snd_pcm_substream *substream) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci return oxygen_open(substream, PCM_C); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int oxygen_spdif_open(struct snd_pcm_substream *substream) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return oxygen_open(substream, PCM_SPDIF); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int oxygen_multich_open(struct snd_pcm_substream *substream) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci return oxygen_open(substream, PCM_MULTICH); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int oxygen_ac97_open(struct snd_pcm_substream *substream) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return oxygen_open(substream, PCM_AC97); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int oxygen_close(struct snd_pcm_substream *substream) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 22262306a36Sopenharmony_ci unsigned int channel = oxygen_substream_channel(substream); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci mutex_lock(&chip->mutex); 22562306a36Sopenharmony_ci chip->pcm_active &= ~(1 << channel); 22662306a36Sopenharmony_ci if (channel == PCM_SPDIF) { 22762306a36Sopenharmony_ci chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |= 22862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE; 22962306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | 23062306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, 23162306a36Sopenharmony_ci &chip->controls[CONTROL_SPDIF_PCM]->id); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci if (channel == PCM_SPDIF || channel == PCM_MULTICH) 23462306a36Sopenharmony_ci oxygen_update_spdif_source(chip); 23562306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci chip->streams[channel] = NULL; 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic unsigned int oxygen_format(struct snd_pcm_hw_params *hw_params) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) 24462306a36Sopenharmony_ci return OXYGEN_FORMAT_24; 24562306a36Sopenharmony_ci else 24662306a36Sopenharmony_ci return OXYGEN_FORMAT_16; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci switch (params_rate(hw_params)) { 25262306a36Sopenharmony_ci case 32000: 25362306a36Sopenharmony_ci return OXYGEN_RATE_32000; 25462306a36Sopenharmony_ci case 44100: 25562306a36Sopenharmony_ci return OXYGEN_RATE_44100; 25662306a36Sopenharmony_ci default: /* 48000 */ 25762306a36Sopenharmony_ci return OXYGEN_RATE_48000; 25862306a36Sopenharmony_ci case 64000: 25962306a36Sopenharmony_ci return OXYGEN_RATE_64000; 26062306a36Sopenharmony_ci case 88200: 26162306a36Sopenharmony_ci return OXYGEN_RATE_88200; 26262306a36Sopenharmony_ci case 96000: 26362306a36Sopenharmony_ci return OXYGEN_RATE_96000; 26462306a36Sopenharmony_ci case 176400: 26562306a36Sopenharmony_ci return OXYGEN_RATE_176400; 26662306a36Sopenharmony_ci case 192000: 26762306a36Sopenharmony_ci return OXYGEN_RATE_192000; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) 27462306a36Sopenharmony_ci return OXYGEN_I2S_BITS_24; 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci return OXYGEN_I2S_BITS_16; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic unsigned int oxygen_play_channels(struct snd_pcm_hw_params *hw_params) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci switch (params_channels(hw_params)) { 28262306a36Sopenharmony_ci default: /* 2 */ 28362306a36Sopenharmony_ci return OXYGEN_PLAY_CHANNELS_2; 28462306a36Sopenharmony_ci case 4: 28562306a36Sopenharmony_ci return OXYGEN_PLAY_CHANNELS_4; 28662306a36Sopenharmony_ci case 6: 28762306a36Sopenharmony_ci return OXYGEN_PLAY_CHANNELS_6; 28862306a36Sopenharmony_ci case 8: 28962306a36Sopenharmony_ci return OXYGEN_PLAY_CHANNELS_8; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic const unsigned int channel_base_registers[PCM_COUNT] = { 29462306a36Sopenharmony_ci [PCM_A] = OXYGEN_DMA_A_ADDRESS, 29562306a36Sopenharmony_ci [PCM_B] = OXYGEN_DMA_B_ADDRESS, 29662306a36Sopenharmony_ci [PCM_C] = OXYGEN_DMA_C_ADDRESS, 29762306a36Sopenharmony_ci [PCM_SPDIF] = OXYGEN_DMA_SPDIF_ADDRESS, 29862306a36Sopenharmony_ci [PCM_MULTICH] = OXYGEN_DMA_MULTICH_ADDRESS, 29962306a36Sopenharmony_ci [PCM_AC97] = OXYGEN_DMA_AC97_ADDRESS, 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int oxygen_hw_params(struct snd_pcm_substream *substream, 30362306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 30662306a36Sopenharmony_ci unsigned int channel = oxygen_substream_channel(substream); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci oxygen_write32(chip, channel_base_registers[channel], 30962306a36Sopenharmony_ci (u32)substream->runtime->dma_addr); 31062306a36Sopenharmony_ci if (channel == PCM_MULTICH) { 31162306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_DMA_MULTICH_COUNT, 31262306a36Sopenharmony_ci params_buffer_bytes(hw_params) / 4 - 1); 31362306a36Sopenharmony_ci oxygen_write32(chip, OXYGEN_DMA_MULTICH_TCOUNT, 31462306a36Sopenharmony_ci params_period_bytes(hw_params) / 4 - 1); 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci oxygen_write16(chip, channel_base_registers[channel] + 4, 31762306a36Sopenharmony_ci params_buffer_bytes(hw_params) / 4 - 1); 31862306a36Sopenharmony_ci oxygen_write16(chip, channel_base_registers[channel] + 6, 31962306a36Sopenharmony_ci params_period_bytes(hw_params) / 4 - 1); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic u16 get_mclk(struct oxygen *chip, unsigned int channel, 32562306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci unsigned int mclks, shift; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (channel == PCM_MULTICH) 33062306a36Sopenharmony_ci mclks = chip->model.dac_mclks; 33162306a36Sopenharmony_ci else 33262306a36Sopenharmony_ci mclks = chip->model.adc_mclks; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (params_rate(params) <= 48000) 33562306a36Sopenharmony_ci shift = 0; 33662306a36Sopenharmony_ci else if (params_rate(params) <= 96000) 33762306a36Sopenharmony_ci shift = 2; 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci shift = 4; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return OXYGEN_I2S_MCLK(mclks >> shift); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, 34562306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci err = oxygen_hw_params(substream, hw_params); 35162306a36Sopenharmony_ci if (err < 0) 35262306a36Sopenharmony_ci return err; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 35562306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, 35662306a36Sopenharmony_ci oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT, 35762306a36Sopenharmony_ci OXYGEN_REC_FORMAT_A_MASK); 35862306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, 35962306a36Sopenharmony_ci oxygen_rate(hw_params) | 36062306a36Sopenharmony_ci chip->model.adc_i2s_format | 36162306a36Sopenharmony_ci get_mclk(chip, PCM_A, hw_params) | 36262306a36Sopenharmony_ci oxygen_i2s_bits(hw_params), 36362306a36Sopenharmony_ci OXYGEN_I2S_RATE_MASK | 36462306a36Sopenharmony_ci OXYGEN_I2S_FORMAT_MASK | 36562306a36Sopenharmony_ci OXYGEN_I2S_MCLK_MASK | 36662306a36Sopenharmony_ci OXYGEN_I2S_BITS_MASK); 36762306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci mutex_lock(&chip->mutex); 37062306a36Sopenharmony_ci chip->model.set_adc_params(chip, hw_params); 37162306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, 37662306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 37962306a36Sopenharmony_ci int is_ac97; 38062306a36Sopenharmony_ci int err; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci err = oxygen_hw_params(substream, hw_params); 38362306a36Sopenharmony_ci if (err < 0) 38462306a36Sopenharmony_ci return err; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci is_ac97 = chip->has_ac97_1 && 38762306a36Sopenharmony_ci (chip->model.device_config & CAPTURE_2_FROM_AC97_1); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 39062306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, 39162306a36Sopenharmony_ci oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT, 39262306a36Sopenharmony_ci OXYGEN_REC_FORMAT_B_MASK); 39362306a36Sopenharmony_ci if (!is_ac97) 39462306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, 39562306a36Sopenharmony_ci oxygen_rate(hw_params) | 39662306a36Sopenharmony_ci chip->model.adc_i2s_format | 39762306a36Sopenharmony_ci get_mclk(chip, PCM_B, hw_params) | 39862306a36Sopenharmony_ci oxygen_i2s_bits(hw_params), 39962306a36Sopenharmony_ci OXYGEN_I2S_RATE_MASK | 40062306a36Sopenharmony_ci OXYGEN_I2S_FORMAT_MASK | 40162306a36Sopenharmony_ci OXYGEN_I2S_MCLK_MASK | 40262306a36Sopenharmony_ci OXYGEN_I2S_BITS_MASK); 40362306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!is_ac97) { 40662306a36Sopenharmony_ci mutex_lock(&chip->mutex); 40762306a36Sopenharmony_ci chip->model.set_adc_params(chip, hw_params); 40862306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, 41462306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 41762306a36Sopenharmony_ci bool is_spdif; 41862306a36Sopenharmony_ci int err; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci err = oxygen_hw_params(substream, hw_params); 42162306a36Sopenharmony_ci if (err < 0) 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 42762306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, 42862306a36Sopenharmony_ci oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, 42962306a36Sopenharmony_ci OXYGEN_REC_FORMAT_C_MASK); 43062306a36Sopenharmony_ci if (!is_spdif) 43162306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT, 43262306a36Sopenharmony_ci oxygen_rate(hw_params) | 43362306a36Sopenharmony_ci chip->model.adc_i2s_format | 43462306a36Sopenharmony_ci get_mclk(chip, PCM_B, hw_params) | 43562306a36Sopenharmony_ci oxygen_i2s_bits(hw_params), 43662306a36Sopenharmony_ci OXYGEN_I2S_RATE_MASK | 43762306a36Sopenharmony_ci OXYGEN_I2S_FORMAT_MASK | 43862306a36Sopenharmony_ci OXYGEN_I2S_MCLK_MASK | 43962306a36Sopenharmony_ci OXYGEN_I2S_BITS_MASK); 44062306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!is_spdif) { 44362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 44462306a36Sopenharmony_ci chip->model.set_adc_params(chip, hw_params); 44562306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, 45162306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 45462306a36Sopenharmony_ci int err; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci err = oxygen_hw_params(substream, hw_params); 45762306a36Sopenharmony_ci if (err < 0) 45862306a36Sopenharmony_ci return err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci mutex_lock(&chip->mutex); 46162306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 46262306a36Sopenharmony_ci oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, 46362306a36Sopenharmony_ci OXYGEN_SPDIF_OUT_ENABLE); 46462306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, 46562306a36Sopenharmony_ci oxygen_format(hw_params) << OXYGEN_SPDIF_FORMAT_SHIFT, 46662306a36Sopenharmony_ci OXYGEN_SPDIF_FORMAT_MASK); 46762306a36Sopenharmony_ci oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, 46862306a36Sopenharmony_ci oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT, 46962306a36Sopenharmony_ci OXYGEN_SPDIF_OUT_RATE_MASK); 47062306a36Sopenharmony_ci oxygen_update_spdif_source(chip); 47162306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 47262306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int oxygen_multich_hw_params(struct snd_pcm_substream *substream, 47762306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 48062306a36Sopenharmony_ci int err; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci err = oxygen_hw_params(substream, hw_params); 48362306a36Sopenharmony_ci if (err < 0) 48462306a36Sopenharmony_ci return err; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci mutex_lock(&chip->mutex); 48762306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 48862306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, 48962306a36Sopenharmony_ci oxygen_play_channels(hw_params), 49062306a36Sopenharmony_ci OXYGEN_PLAY_CHANNELS_MASK); 49162306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, 49262306a36Sopenharmony_ci oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT, 49362306a36Sopenharmony_ci OXYGEN_MULTICH_FORMAT_MASK); 49462306a36Sopenharmony_ci oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, 49562306a36Sopenharmony_ci oxygen_rate(hw_params) | 49662306a36Sopenharmony_ci chip->model.dac_i2s_format | 49762306a36Sopenharmony_ci get_mclk(chip, PCM_MULTICH, hw_params) | 49862306a36Sopenharmony_ci oxygen_i2s_bits(hw_params), 49962306a36Sopenharmony_ci OXYGEN_I2S_RATE_MASK | 50062306a36Sopenharmony_ci OXYGEN_I2S_FORMAT_MASK | 50162306a36Sopenharmony_ci OXYGEN_I2S_MCLK_MASK | 50262306a36Sopenharmony_ci OXYGEN_I2S_BITS_MASK); 50362306a36Sopenharmony_ci oxygen_update_spdif_source(chip); 50462306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci chip->model.set_dac_params(chip, hw_params); 50762306a36Sopenharmony_ci oxygen_update_dac_routing(chip); 50862306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int oxygen_hw_free(struct snd_pcm_substream *substream) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 51562306a36Sopenharmony_ci unsigned int channel = oxygen_substream_channel(substream); 51662306a36Sopenharmony_ci unsigned int channel_mask = 1 << channel; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 51962306a36Sopenharmony_ci chip->interrupt_mask &= ~channel_mask; 52062306a36Sopenharmony_ci oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); 52362306a36Sopenharmony_ci oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); 52462306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int oxygen_spdif_hw_free(struct snd_pcm_substream *substream) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 53462306a36Sopenharmony_ci oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, 53562306a36Sopenharmony_ci OXYGEN_SPDIF_OUT_ENABLE); 53662306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 53762306a36Sopenharmony_ci return oxygen_hw_free(substream); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int oxygen_prepare(struct snd_pcm_substream *substream) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 54362306a36Sopenharmony_ci unsigned int channel = oxygen_substream_channel(substream); 54462306a36Sopenharmony_ci unsigned int channel_mask = 1 << channel; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 54762306a36Sopenharmony_ci oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); 54862306a36Sopenharmony_ci oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (substream->runtime->no_period_wakeup) 55162306a36Sopenharmony_ci chip->interrupt_mask &= ~channel_mask; 55262306a36Sopenharmony_ci else 55362306a36Sopenharmony_ci chip->interrupt_mask |= channel_mask; 55462306a36Sopenharmony_ci oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); 55562306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 56262306a36Sopenharmony_ci struct snd_pcm_substream *s; 56362306a36Sopenharmony_ci unsigned int mask = 0; 56462306a36Sopenharmony_ci int pausing; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci switch (cmd) { 56762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 56862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 56962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 57062306a36Sopenharmony_ci pausing = 0; 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 57362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 57462306a36Sopenharmony_ci pausing = 1; 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci default: 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 58162306a36Sopenharmony_ci if (snd_pcm_substream_chip(s) == chip) { 58262306a36Sopenharmony_ci mask |= 1 << oxygen_substream_channel(s); 58362306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 58862306a36Sopenharmony_ci if (!pausing) { 58962306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) 59062306a36Sopenharmony_ci chip->pcm_running |= mask; 59162306a36Sopenharmony_ci else 59262306a36Sopenharmony_ci chip->pcm_running &= ~mask; 59362306a36Sopenharmony_ci oxygen_write8(chip, OXYGEN_DMA_STATUS, chip->pcm_running); 59462306a36Sopenharmony_ci } else { 59562306a36Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) 59662306a36Sopenharmony_ci oxygen_set_bits8(chip, OXYGEN_DMA_PAUSE, mask); 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct oxygen *chip = snd_pcm_substream_chip(substream); 60762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 60862306a36Sopenharmony_ci unsigned int channel = oxygen_substream_channel(substream); 60962306a36Sopenharmony_ci u32 curr_addr; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* no spinlock, this read should be atomic */ 61262306a36Sopenharmony_ci curr_addr = oxygen_read32(chip, channel_base_registers[channel]); 61362306a36Sopenharmony_ci return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_rec_a_ops = { 61762306a36Sopenharmony_ci .open = oxygen_rec_a_open, 61862306a36Sopenharmony_ci .close = oxygen_close, 61962306a36Sopenharmony_ci .hw_params = oxygen_rec_a_hw_params, 62062306a36Sopenharmony_ci .hw_free = oxygen_hw_free, 62162306a36Sopenharmony_ci .prepare = oxygen_prepare, 62262306a36Sopenharmony_ci .trigger = oxygen_trigger, 62362306a36Sopenharmony_ci .pointer = oxygen_pointer, 62462306a36Sopenharmony_ci}; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_rec_b_ops = { 62762306a36Sopenharmony_ci .open = oxygen_rec_b_open, 62862306a36Sopenharmony_ci .close = oxygen_close, 62962306a36Sopenharmony_ci .hw_params = oxygen_rec_b_hw_params, 63062306a36Sopenharmony_ci .hw_free = oxygen_hw_free, 63162306a36Sopenharmony_ci .prepare = oxygen_prepare, 63262306a36Sopenharmony_ci .trigger = oxygen_trigger, 63362306a36Sopenharmony_ci .pointer = oxygen_pointer, 63462306a36Sopenharmony_ci}; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_rec_c_ops = { 63762306a36Sopenharmony_ci .open = oxygen_rec_c_open, 63862306a36Sopenharmony_ci .close = oxygen_close, 63962306a36Sopenharmony_ci .hw_params = oxygen_rec_c_hw_params, 64062306a36Sopenharmony_ci .hw_free = oxygen_hw_free, 64162306a36Sopenharmony_ci .prepare = oxygen_prepare, 64262306a36Sopenharmony_ci .trigger = oxygen_trigger, 64362306a36Sopenharmony_ci .pointer = oxygen_pointer, 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_spdif_ops = { 64762306a36Sopenharmony_ci .open = oxygen_spdif_open, 64862306a36Sopenharmony_ci .close = oxygen_close, 64962306a36Sopenharmony_ci .hw_params = oxygen_spdif_hw_params, 65062306a36Sopenharmony_ci .hw_free = oxygen_spdif_hw_free, 65162306a36Sopenharmony_ci .prepare = oxygen_prepare, 65262306a36Sopenharmony_ci .trigger = oxygen_trigger, 65362306a36Sopenharmony_ci .pointer = oxygen_pointer, 65462306a36Sopenharmony_ci}; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_multich_ops = { 65762306a36Sopenharmony_ci .open = oxygen_multich_open, 65862306a36Sopenharmony_ci .close = oxygen_close, 65962306a36Sopenharmony_ci .hw_params = oxygen_multich_hw_params, 66062306a36Sopenharmony_ci .hw_free = oxygen_hw_free, 66162306a36Sopenharmony_ci .prepare = oxygen_prepare, 66262306a36Sopenharmony_ci .trigger = oxygen_trigger, 66362306a36Sopenharmony_ci .pointer = oxygen_pointer, 66462306a36Sopenharmony_ci}; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic const struct snd_pcm_ops oxygen_ac97_ops = { 66762306a36Sopenharmony_ci .open = oxygen_ac97_open, 66862306a36Sopenharmony_ci .close = oxygen_close, 66962306a36Sopenharmony_ci .hw_params = oxygen_hw_params, 67062306a36Sopenharmony_ci .hw_free = oxygen_hw_free, 67162306a36Sopenharmony_ci .prepare = oxygen_prepare, 67262306a36Sopenharmony_ci .trigger = oxygen_trigger, 67362306a36Sopenharmony_ci .pointer = oxygen_pointer, 67462306a36Sopenharmony_ci}; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ciint oxygen_pcm_init(struct oxygen *chip) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct snd_pcm *pcm; 67962306a36Sopenharmony_ci int outs, ins; 68062306a36Sopenharmony_ci int err; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci outs = !!(chip->model.device_config & PLAYBACK_0_TO_I2S); 68362306a36Sopenharmony_ci ins = !!(chip->model.device_config & (CAPTURE_0_FROM_I2S_1 | 68462306a36Sopenharmony_ci CAPTURE_0_FROM_I2S_2)); 68562306a36Sopenharmony_ci if (outs | ins) { 68662306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Multichannel", 68762306a36Sopenharmony_ci 0, outs, ins, &pcm); 68862306a36Sopenharmony_ci if (err < 0) 68962306a36Sopenharmony_ci return err; 69062306a36Sopenharmony_ci if (outs) 69162306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 69262306a36Sopenharmony_ci &oxygen_multich_ops); 69362306a36Sopenharmony_ci if (chip->model.device_config & CAPTURE_0_FROM_I2S_1) 69462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 69562306a36Sopenharmony_ci &oxygen_rec_a_ops); 69662306a36Sopenharmony_ci else if (chip->model.device_config & CAPTURE_0_FROM_I2S_2) 69762306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 69862306a36Sopenharmony_ci &oxygen_rec_b_ops); 69962306a36Sopenharmony_ci pcm->private_data = chip; 70062306a36Sopenharmony_ci strcpy(pcm->name, "Multichannel"); 70162306a36Sopenharmony_ci if (outs) 70262306a36Sopenharmony_ci snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, 70362306a36Sopenharmony_ci SNDRV_DMA_TYPE_DEV, 70462306a36Sopenharmony_ci &chip->pci->dev, 70562306a36Sopenharmony_ci DEFAULT_BUFFER_BYTES_MULTICH, 70662306a36Sopenharmony_ci BUFFER_BYTES_MAX_MULTICH); 70762306a36Sopenharmony_ci if (ins) 70862306a36Sopenharmony_ci snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 70962306a36Sopenharmony_ci SNDRV_DMA_TYPE_DEV, 71062306a36Sopenharmony_ci &chip->pci->dev, 71162306a36Sopenharmony_ci DEFAULT_BUFFER_BYTES, 71262306a36Sopenharmony_ci BUFFER_BYTES_MAX); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci outs = !!(chip->model.device_config & PLAYBACK_1_TO_SPDIF); 71662306a36Sopenharmony_ci ins = !!(chip->model.device_config & CAPTURE_1_FROM_SPDIF); 71762306a36Sopenharmony_ci if (outs | ins) { 71862306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm); 71962306a36Sopenharmony_ci if (err < 0) 72062306a36Sopenharmony_ci return err; 72162306a36Sopenharmony_ci if (outs) 72262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 72362306a36Sopenharmony_ci &oxygen_spdif_ops); 72462306a36Sopenharmony_ci if (ins) 72562306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 72662306a36Sopenharmony_ci &oxygen_rec_c_ops); 72762306a36Sopenharmony_ci pcm->private_data = chip; 72862306a36Sopenharmony_ci strcpy(pcm->name, "Digital"); 72962306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 73062306a36Sopenharmony_ci &chip->pci->dev, 73162306a36Sopenharmony_ci DEFAULT_BUFFER_BYTES, 73262306a36Sopenharmony_ci BUFFER_BYTES_MAX); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (chip->has_ac97_1) { 73662306a36Sopenharmony_ci outs = !!(chip->model.device_config & PLAYBACK_2_TO_AC97_1); 73762306a36Sopenharmony_ci ins = !!(chip->model.device_config & CAPTURE_2_FROM_AC97_1); 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci outs = 0; 74062306a36Sopenharmony_ci ins = !!(chip->model.device_config & CAPTURE_2_FROM_I2S_2); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci if (outs | ins) { 74362306a36Sopenharmony_ci err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2", 74462306a36Sopenharmony_ci 2, outs, ins, &pcm); 74562306a36Sopenharmony_ci if (err < 0) 74662306a36Sopenharmony_ci return err; 74762306a36Sopenharmony_ci if (outs) { 74862306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 74962306a36Sopenharmony_ci &oxygen_ac97_ops); 75062306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_REC_ROUTING, 75162306a36Sopenharmony_ci OXYGEN_REC_B_ROUTE_AC97_1, 75262306a36Sopenharmony_ci OXYGEN_REC_B_ROUTE_MASK); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci if (ins) 75562306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 75662306a36Sopenharmony_ci &oxygen_rec_b_ops); 75762306a36Sopenharmony_ci pcm->private_data = chip; 75862306a36Sopenharmony_ci strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); 75962306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 76062306a36Sopenharmony_ci &chip->pci->dev, 76162306a36Sopenharmony_ci DEFAULT_BUFFER_BYTES, 76262306a36Sopenharmony_ci BUFFER_BYTES_MAX); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ins = !!(chip->model.device_config & CAPTURE_3_FROM_I2S_3); 76662306a36Sopenharmony_ci if (ins) { 76762306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Analog3", 3, 0, ins, &pcm); 76862306a36Sopenharmony_ci if (err < 0) 76962306a36Sopenharmony_ci return err; 77062306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 77162306a36Sopenharmony_ci &oxygen_rec_c_ops); 77262306a36Sopenharmony_ci oxygen_write8_masked(chip, OXYGEN_REC_ROUTING, 77362306a36Sopenharmony_ci OXYGEN_REC_C_ROUTE_I2S_ADC_3, 77462306a36Sopenharmony_ci OXYGEN_REC_C_ROUTE_MASK); 77562306a36Sopenharmony_ci pcm->private_data = chip; 77662306a36Sopenharmony_ci strcpy(pcm->name, "Analog 3"); 77762306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 77862306a36Sopenharmony_ci &chip->pci->dev, 77962306a36Sopenharmony_ci DEFAULT_BUFFER_BYTES, 78062306a36Sopenharmony_ci BUFFER_BYTES_MAX); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 784