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