162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    ad1816a.c - lowlevel code for Analog Devices AD1816A chip.
462306a36Sopenharmony_ci    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci*/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/ioport.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <sound/core.h>
1562306a36Sopenharmony_ci#include <sound/tlv.h>
1662306a36Sopenharmony_ci#include <sound/ad1816a.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/dma.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	int timeout;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	for (timeout = 1000; timeout-- > 0; udelay(10))
2562306a36Sopenharmony_ci		if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
2662306a36Sopenharmony_ci			return 0;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	snd_printk(KERN_WARNING "chip busy.\n");
2962306a36Sopenharmony_ci	return -EBUSY;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic inline unsigned char snd_ad1816a_in(struct snd_ad1816a *chip, unsigned char reg)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	snd_ad1816a_busy_wait(chip);
3562306a36Sopenharmony_ci	return inb(AD1816A_REG(reg));
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic inline void snd_ad1816a_out(struct snd_ad1816a *chip, unsigned char reg,
3962306a36Sopenharmony_ci			    unsigned char value)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	snd_ad1816a_busy_wait(chip);
4262306a36Sopenharmony_ci	outb(value, AD1816A_REG(reg));
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline void snd_ad1816a_out_mask(struct snd_ad1816a *chip, unsigned char reg,
4662306a36Sopenharmony_ci				 unsigned char mask, unsigned char value)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	snd_ad1816a_out(chip, reg,
4962306a36Sopenharmony_ci		(value & mask) | (snd_ad1816a_in(chip, reg) & ~mask));
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic unsigned short snd_ad1816a_read(struct snd_ad1816a *chip, unsigned char reg)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INDIR_ADDR, reg & 0x3f);
5562306a36Sopenharmony_ci	return snd_ad1816a_in(chip, AD1816A_INDIR_DATA_LOW) |
5662306a36Sopenharmony_ci		(snd_ad1816a_in(chip, AD1816A_INDIR_DATA_HIGH) << 8);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void snd_ad1816a_write(struct snd_ad1816a *chip, unsigned char reg,
6062306a36Sopenharmony_ci			      unsigned short value)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INDIR_ADDR, reg & 0x3f);
6362306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INDIR_DATA_LOW, value & 0xff);
6462306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INDIR_DATA_HIGH, (value >> 8) & 0xff);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void snd_ad1816a_write_mask(struct snd_ad1816a *chip, unsigned char reg,
6862306a36Sopenharmony_ci				   unsigned short mask, unsigned short value)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	snd_ad1816a_write(chip, reg,
7162306a36Sopenharmony_ci		(value & mask) | (snd_ad1816a_read(chip, reg) & ~mask));
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic unsigned char snd_ad1816a_get_format(struct snd_ad1816a *chip,
7662306a36Sopenharmony_ci					    snd_pcm_format_t format,
7762306a36Sopenharmony_ci					    int channels)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	unsigned char retval = AD1816A_FMT_LINEAR_8;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	switch (format) {
8262306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_MU_LAW:
8362306a36Sopenharmony_ci		retval = AD1816A_FMT_ULAW_8;
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_A_LAW:
8662306a36Sopenharmony_ci		retval = AD1816A_FMT_ALAW_8;
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
8962306a36Sopenharmony_ci		retval = AD1816A_FMT_LINEAR_16_LIT;
9062306a36Sopenharmony_ci		break;
9162306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_BE:
9262306a36Sopenharmony_ci		retval = AD1816A_FMT_LINEAR_16_BIG;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci	return (channels > 1) ? (retval | AD1816A_FMT_STEREO) : retval;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	unsigned long flags;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (chip->mode & mode) {
10462306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->lock, flags);
10562306a36Sopenharmony_ci		return -EAGAIN;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	switch ((mode &= AD1816A_MODE_OPEN)) {
10962306a36Sopenharmony_ci	case AD1816A_MODE_PLAYBACK:
11062306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
11162306a36Sopenharmony_ci			AD1816A_PLAYBACK_IRQ_PENDING, 0x00);
11262306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
11362306a36Sopenharmony_ci			AD1816A_PLAYBACK_IRQ_ENABLE, 0xffff);
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case AD1816A_MODE_CAPTURE:
11662306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
11762306a36Sopenharmony_ci			AD1816A_CAPTURE_IRQ_PENDING, 0x00);
11862306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
11962306a36Sopenharmony_ci			AD1816A_CAPTURE_IRQ_ENABLE, 0xffff);
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case AD1816A_MODE_TIMER:
12262306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
12362306a36Sopenharmony_ci			AD1816A_TIMER_IRQ_PENDING, 0x00);
12462306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
12562306a36Sopenharmony_ci			AD1816A_TIMER_IRQ_ENABLE, 0xffff);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci	chip->mode |= mode;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	unsigned long flags;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	switch ((mode &= AD1816A_MODE_OPEN)) {
14062306a36Sopenharmony_ci	case AD1816A_MODE_PLAYBACK:
14162306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
14262306a36Sopenharmony_ci			AD1816A_PLAYBACK_IRQ_PENDING, 0x00);
14362306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
14462306a36Sopenharmony_ci			AD1816A_PLAYBACK_IRQ_ENABLE, 0x0000);
14562306a36Sopenharmony_ci		break;
14662306a36Sopenharmony_ci	case AD1816A_MODE_CAPTURE:
14762306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
14862306a36Sopenharmony_ci			AD1816A_CAPTURE_IRQ_PENDING, 0x00);
14962306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
15062306a36Sopenharmony_ci			AD1816A_CAPTURE_IRQ_ENABLE, 0x0000);
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	case AD1816A_MODE_TIMER:
15362306a36Sopenharmony_ci		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
15462306a36Sopenharmony_ci			AD1816A_TIMER_IRQ_PENDING, 0x00);
15562306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
15662306a36Sopenharmony_ci			AD1816A_TIMER_IRQ_ENABLE, 0x0000);
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	chip->mode &= ~mode;
15962306a36Sopenharmony_ci	if (!(chip->mode & AD1816A_MODE_OPEN))
16062306a36Sopenharmony_ci		chip->mode = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
16762306a36Sopenharmony_ci			       int channel, int cmd, int iscapture)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	int error = 0;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	switch (cmd) {
17262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
17362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
17462306a36Sopenharmony_ci		spin_lock(&chip->lock);
17562306a36Sopenharmony_ci		cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
17662306a36Sopenharmony_ci		/* if (what & AD1816A_PLAYBACK_ENABLE) */
17762306a36Sopenharmony_ci		/* That is not valid, because playback and capture enable
17862306a36Sopenharmony_ci		 * are the same bit pattern, just to different addresses
17962306a36Sopenharmony_ci		 */
18062306a36Sopenharmony_ci		if (! iscapture)
18162306a36Sopenharmony_ci			snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
18262306a36Sopenharmony_ci				AD1816A_PLAYBACK_ENABLE, cmd);
18362306a36Sopenharmony_ci		else
18462306a36Sopenharmony_ci			snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
18562306a36Sopenharmony_ci				AD1816A_CAPTURE_ENABLE, cmd);
18662306a36Sopenharmony_ci		spin_unlock(&chip->lock);
18762306a36Sopenharmony_ci		break;
18862306a36Sopenharmony_ci	default:
18962306a36Sopenharmony_ci		snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
19062306a36Sopenharmony_ci		error = -EINVAL;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return error;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic int snd_ad1816a_playback_trigger(struct snd_pcm_substream *substream, int cmd)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
19962306a36Sopenharmony_ci	return snd_ad1816a_trigger(chip, AD1816A_PLAYBACK_ENABLE,
20062306a36Sopenharmony_ci				   SNDRV_PCM_STREAM_PLAYBACK, cmd, 0);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int snd_ad1816a_capture_trigger(struct snd_pcm_substream *substream, int cmd)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
20662306a36Sopenharmony_ci	return snd_ad1816a_trigger(chip, AD1816A_CAPTURE_ENABLE,
20762306a36Sopenharmony_ci				   SNDRV_PCM_STREAM_CAPTURE, cmd, 1);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int snd_ad1816a_playback_prepare(struct snd_pcm_substream *substream)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
21362306a36Sopenharmony_ci	unsigned long flags;
21462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
21562306a36Sopenharmony_ci	unsigned int size, rate;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	chip->p_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
22062306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
22162306a36Sopenharmony_ci		AD1816A_PLAYBACK_ENABLE | AD1816A_PLAYBACK_PIO, 0x00);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	snd_dma_program(chip->dma1, runtime->dma_addr, size,
22462306a36Sopenharmony_ci			DMA_MODE_WRITE | DMA_AUTOINIT);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	rate = runtime->rate;
22762306a36Sopenharmony_ci	if (chip->clock_freq)
22862306a36Sopenharmony_ci		rate = (rate * 33000) / chip->clock_freq;
22962306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, rate);
23062306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
23162306a36Sopenharmony_ci		AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
23262306a36Sopenharmony_ci		snd_ad1816a_get_format(chip, runtime->format,
23362306a36Sopenharmony_ci			runtime->channels));
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_PLAYBACK_BASE_COUNT,
23662306a36Sopenharmony_ci		snd_pcm_lib_period_bytes(substream) / 4 - 1);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
24562306a36Sopenharmony_ci	unsigned long flags;
24662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
24762306a36Sopenharmony_ci	unsigned int size, rate;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	chip->c_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
25262306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
25362306a36Sopenharmony_ci		AD1816A_CAPTURE_ENABLE | AD1816A_CAPTURE_PIO, 0x00);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	snd_dma_program(chip->dma2, runtime->dma_addr, size,
25662306a36Sopenharmony_ci			DMA_MODE_READ | DMA_AUTOINIT);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	rate = runtime->rate;
25962306a36Sopenharmony_ci	if (chip->clock_freq)
26062306a36Sopenharmony_ci		rate = (rate * 33000) / chip->clock_freq;
26162306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
26262306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
26362306a36Sopenharmony_ci		AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
26462306a36Sopenharmony_ci		snd_ad1816a_get_format(chip, runtime->format,
26562306a36Sopenharmony_ci			runtime->channels));
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_CAPTURE_BASE_COUNT,
26862306a36Sopenharmony_ci		snd_pcm_lib_period_bytes(substream) / 4 - 1);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
27162306a36Sopenharmony_ci	return 0;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ad1816a_playback_pointer(struct snd_pcm_substream *substream)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
27862306a36Sopenharmony_ci	size_t ptr;
27962306a36Sopenharmony_ci	if (!(chip->mode & AD1816A_MODE_PLAYBACK))
28062306a36Sopenharmony_ci		return 0;
28162306a36Sopenharmony_ci	ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
28262306a36Sopenharmony_ci	return bytes_to_frames(substream->runtime, ptr);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ad1816a_capture_pointer(struct snd_pcm_substream *substream)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
28862306a36Sopenharmony_ci	size_t ptr;
28962306a36Sopenharmony_ci	if (!(chip->mode & AD1816A_MODE_CAPTURE))
29062306a36Sopenharmony_ci		return 0;
29162306a36Sopenharmony_ci	ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
29262306a36Sopenharmony_ci	return bytes_to_frames(substream->runtime, ptr);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct snd_ad1816a *chip = dev_id;
29962306a36Sopenharmony_ci	unsigned char status;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	spin_lock(&chip->lock);
30262306a36Sopenharmony_ci	status = snd_ad1816a_in(chip, AD1816A_INTERRUPT_STATUS);
30362306a36Sopenharmony_ci	spin_unlock(&chip->lock);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if ((status & AD1816A_PLAYBACK_IRQ_PENDING) && chip->playback_substream)
30662306a36Sopenharmony_ci		snd_pcm_period_elapsed(chip->playback_substream);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if ((status & AD1816A_CAPTURE_IRQ_PENDING) && chip->capture_substream)
30962306a36Sopenharmony_ci		snd_pcm_period_elapsed(chip->capture_substream);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if ((status & AD1816A_TIMER_IRQ_PENDING) && chip->timer)
31262306a36Sopenharmony_ci		snd_timer_interrupt(chip->timer, chip->timer->sticks);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	spin_lock(&chip->lock);
31562306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
31662306a36Sopenharmony_ci	spin_unlock(&chip->lock);
31762306a36Sopenharmony_ci	return IRQ_HANDLED;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ad1816a_playback = {
32262306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
32362306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID),
32462306a36Sopenharmony_ci	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
32562306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
32662306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S16_BE),
32762306a36Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
32862306a36Sopenharmony_ci	.rate_min =		4000,
32962306a36Sopenharmony_ci	.rate_max =		55200,
33062306a36Sopenharmony_ci	.channels_min =		1,
33162306a36Sopenharmony_ci	.channels_max =		2,
33262306a36Sopenharmony_ci	.buffer_bytes_max =	(128*1024),
33362306a36Sopenharmony_ci	.period_bytes_min =	64,
33462306a36Sopenharmony_ci	.period_bytes_max =	(128*1024),
33562306a36Sopenharmony_ci	.periods_min =		1,
33662306a36Sopenharmony_ci	.periods_max =		1024,
33762306a36Sopenharmony_ci	.fifo_size =		0,
33862306a36Sopenharmony_ci};
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ad1816a_capture = {
34162306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
34262306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID),
34362306a36Sopenharmony_ci	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
34462306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
34562306a36Sopenharmony_ci				 SNDRV_PCM_FMTBIT_S16_BE),
34662306a36Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
34762306a36Sopenharmony_ci	.rate_min =		4000,
34862306a36Sopenharmony_ci	.rate_max =		55200,
34962306a36Sopenharmony_ci	.channels_min =		1,
35062306a36Sopenharmony_ci	.channels_max =		2,
35162306a36Sopenharmony_ci	.buffer_bytes_max =	(128*1024),
35262306a36Sopenharmony_ci	.period_bytes_min =	64,
35362306a36Sopenharmony_ci	.period_bytes_max =	(128*1024),
35462306a36Sopenharmony_ci	.periods_min =		1,
35562306a36Sopenharmony_ci	.periods_max =		1024,
35662306a36Sopenharmony_ci	.fifo_size =		0,
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int snd_ad1816a_timer_close(struct snd_timer *timer)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_timer_chip(timer);
36262306a36Sopenharmony_ci	snd_ad1816a_close(chip, AD1816A_MODE_TIMER);
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int snd_ad1816a_timer_open(struct snd_timer *timer)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_timer_chip(timer);
36962306a36Sopenharmony_ci	snd_ad1816a_open(chip, AD1816A_MODE_TIMER);
37062306a36Sopenharmony_ci	return 0;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	if (snd_BUG_ON(!timer))
37662306a36Sopenharmony_ci		return 0;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return 10000;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int snd_ad1816a_timer_start(struct snd_timer *timer)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	unsigned short bits;
38462306a36Sopenharmony_ci	unsigned long flags;
38562306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_timer_chip(timer);
38662306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
38762306a36Sopenharmony_ci	bits = snd_ad1816a_read(chip, AD1816A_INTERRUPT_ENABLE);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (!(bits & AD1816A_TIMER_ENABLE)) {
39062306a36Sopenharmony_ci		snd_ad1816a_write(chip, AD1816A_TIMER_BASE_COUNT,
39162306a36Sopenharmony_ci			timer->sticks & 0xffff);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
39462306a36Sopenharmony_ci			AD1816A_TIMER_ENABLE, 0xffff);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
39762306a36Sopenharmony_ci	return 0;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic int snd_ad1816a_timer_stop(struct snd_timer *timer)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	unsigned long flags;
40362306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_timer_chip(timer);
40462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
40762306a36Sopenharmony_ci		AD1816A_TIMER_ENABLE, 0x0000);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const struct snd_timer_hardware snd_ad1816a_timer_table = {
41462306a36Sopenharmony_ci	.flags =	SNDRV_TIMER_HW_AUTO,
41562306a36Sopenharmony_ci	.resolution =	10000,
41662306a36Sopenharmony_ci	.ticks =	65535,
41762306a36Sopenharmony_ci	.open =		snd_ad1816a_timer_open,
41862306a36Sopenharmony_ci	.close =	snd_ad1816a_timer_close,
41962306a36Sopenharmony_ci	.c_resolution =	snd_ad1816a_timer_resolution,
42062306a36Sopenharmony_ci	.start =	snd_ad1816a_timer_start,
42162306a36Sopenharmony_ci	.stop =		snd_ad1816a_timer_stop,
42262306a36Sopenharmony_ci};
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
42762306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
42862306a36Sopenharmony_ci	int error;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK);
43162306a36Sopenharmony_ci	if (error < 0)
43262306a36Sopenharmony_ci		return error;
43362306a36Sopenharmony_ci	runtime->hw = snd_ad1816a_playback;
43462306a36Sopenharmony_ci	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
43562306a36Sopenharmony_ci	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
43662306a36Sopenharmony_ci	chip->playback_substream = substream;
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int snd_ad1816a_capture_open(struct snd_pcm_substream *substream)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
44362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
44462306a36Sopenharmony_ci	int error;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE);
44762306a36Sopenharmony_ci	if (error < 0)
44862306a36Sopenharmony_ci		return error;
44962306a36Sopenharmony_ci	runtime->hw = snd_ad1816a_capture;
45062306a36Sopenharmony_ci	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
45162306a36Sopenharmony_ci	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
45262306a36Sopenharmony_ci	chip->capture_substream = substream;
45362306a36Sopenharmony_ci	return 0;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int snd_ad1816a_playback_close(struct snd_pcm_substream *substream)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	chip->playback_substream = NULL;
46162306a36Sopenharmony_ci	snd_ad1816a_close(chip, AD1816A_MODE_PLAYBACK);
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	chip->capture_substream = NULL;
47062306a36Sopenharmony_ci	snd_ad1816a_close(chip, AD1816A_MODE_CAPTURE);
47162306a36Sopenharmony_ci	return 0;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void snd_ad1816a_init(struct snd_ad1816a *chip)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	unsigned long flags;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
48262306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
48362306a36Sopenharmony_ci		AD1816A_PLAYBACK_ENABLE | AD1816A_PLAYBACK_PIO, 0x00);
48462306a36Sopenharmony_ci	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
48562306a36Sopenharmony_ci		AD1816A_CAPTURE_ENABLE | AD1816A_CAPTURE_PIO, 0x00);
48662306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_INTERRUPT_ENABLE, 0x0000);
48762306a36Sopenharmony_ci	snd_ad1816a_write_mask(chip, AD1816A_CHIP_CONFIG,
48862306a36Sopenharmony_ci		AD1816A_CAPTURE_NOT_EQUAL | AD1816A_WSS_ENABLE, 0xffff);
48962306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_DSP_CONFIG, 0x0000);
49062306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_POWERDOWN_CTRL, 0x0000);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci#ifdef CONFIG_PM
49662306a36Sopenharmony_civoid snd_ad1816a_suspend(struct snd_ad1816a *chip)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	int reg;
49962306a36Sopenharmony_ci	unsigned long flags;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
50262306a36Sopenharmony_ci	for (reg = 0; reg < 48; reg++)
50362306a36Sopenharmony_ci		chip->image[reg] = snd_ad1816a_read(chip, reg);
50462306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_civoid snd_ad1816a_resume(struct snd_ad1816a *chip)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	int reg;
51062306a36Sopenharmony_ci	unsigned long flags;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	snd_ad1816a_init(chip);
51362306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
51462306a36Sopenharmony_ci	for (reg = 0; reg < 48; reg++)
51562306a36Sopenharmony_ci		snd_ad1816a_write(chip, reg, chip->image[reg]);
51662306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci#endif
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int snd_ad1816a_probe(struct snd_ad1816a *chip)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	unsigned long flags;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	switch (chip->version = snd_ad1816a_read(chip, AD1816A_VERSION_ID)) {
52762306a36Sopenharmony_ci	case 0:
52862306a36Sopenharmony_ci		chip->hardware = AD1816A_HW_AD1815;
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	case 1:
53162306a36Sopenharmony_ci		chip->hardware = AD1816A_HW_AD18MAX10;
53262306a36Sopenharmony_ci		break;
53362306a36Sopenharmony_ci	case 3:
53462306a36Sopenharmony_ci		chip->hardware = AD1816A_HW_AD1816A;
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	default:
53762306a36Sopenharmony_ci		chip->hardware = AD1816A_HW_AUTO;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
54162306a36Sopenharmony_ci	return 0;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic const char *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	switch (chip->hardware) {
54762306a36Sopenharmony_ci	case AD1816A_HW_AD1816A: return "AD1816A";
54862306a36Sopenharmony_ci	case AD1816A_HW_AD1815:	return "AD1815";
54962306a36Sopenharmony_ci	case AD1816A_HW_AD18MAX10: return "AD18max10";
55062306a36Sopenharmony_ci	default:
55162306a36Sopenharmony_ci		snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
55262306a36Sopenharmony_ci			chip->version, chip->hardware);
55362306a36Sopenharmony_ci		return "AD1816A - unknown";
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ciint snd_ad1816a_create(struct snd_card *card,
55862306a36Sopenharmony_ci		       unsigned long port, int irq, int dma1, int dma2,
55962306a36Sopenharmony_ci		       struct snd_ad1816a *chip)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	int error;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	chip->irq = -1;
56462306a36Sopenharmony_ci	chip->dma1 = -1;
56562306a36Sopenharmony_ci	chip->dma2 = -1;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	chip->res_port = devm_request_region(card->dev, port, 16, "AD1816A");
56862306a36Sopenharmony_ci	if (!chip->res_port) {
56962306a36Sopenharmony_ci		snd_printk(KERN_ERR "ad1816a: can't grab port 0x%lx\n", port);
57062306a36Sopenharmony_ci		return -EBUSY;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci	if (devm_request_irq(card->dev, irq, snd_ad1816a_interrupt, 0,
57362306a36Sopenharmony_ci			     "AD1816A", (void *) chip)) {
57462306a36Sopenharmony_ci		snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq);
57562306a36Sopenharmony_ci		return -EBUSY;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	chip->irq = irq;
57862306a36Sopenharmony_ci	card->sync_irq = chip->irq;
57962306a36Sopenharmony_ci	if (snd_devm_request_dma(card->dev, dma1, "AD1816A - 1")) {
58062306a36Sopenharmony_ci		snd_printk(KERN_ERR "ad1816a: can't grab DMA1 %d\n", dma1);
58162306a36Sopenharmony_ci		return -EBUSY;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci	chip->dma1 = dma1;
58462306a36Sopenharmony_ci	if (snd_devm_request_dma(card->dev, dma2, "AD1816A - 2")) {
58562306a36Sopenharmony_ci		snd_printk(KERN_ERR "ad1816a: can't grab DMA2 %d\n", dma2);
58662306a36Sopenharmony_ci		return -EBUSY;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	chip->dma2 = dma2;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	chip->card = card;
59162306a36Sopenharmony_ci	chip->port = port;
59262306a36Sopenharmony_ci	spin_lock_init(&chip->lock);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	error = snd_ad1816a_probe(chip);
59562306a36Sopenharmony_ci	if (error)
59662306a36Sopenharmony_ci		return error;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	snd_ad1816a_init(chip);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	return 0;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ad1816a_playback_ops = {
60462306a36Sopenharmony_ci	.open =		snd_ad1816a_playback_open,
60562306a36Sopenharmony_ci	.close =	snd_ad1816a_playback_close,
60662306a36Sopenharmony_ci	.prepare =	snd_ad1816a_playback_prepare,
60762306a36Sopenharmony_ci	.trigger =	snd_ad1816a_playback_trigger,
60862306a36Sopenharmony_ci	.pointer =	snd_ad1816a_playback_pointer,
60962306a36Sopenharmony_ci};
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ad1816a_capture_ops = {
61262306a36Sopenharmony_ci	.open =		snd_ad1816a_capture_open,
61362306a36Sopenharmony_ci	.close =	snd_ad1816a_capture_close,
61462306a36Sopenharmony_ci	.prepare =	snd_ad1816a_capture_prepare,
61562306a36Sopenharmony_ci	.trigger =	snd_ad1816a_capture_trigger,
61662306a36Sopenharmony_ci	.pointer =	snd_ad1816a_capture_pointer,
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ciint snd_ad1816a_pcm(struct snd_ad1816a *chip, int device)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	int error;
62262306a36Sopenharmony_ci	struct snd_pcm *pcm;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	error = snd_pcm_new(chip->card, "AD1816A", device, 1, 1, &pcm);
62562306a36Sopenharmony_ci	if (error)
62662306a36Sopenharmony_ci		return error;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1816a_playback_ops);
62962306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1816a_capture_ops);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	pcm->private_data = chip;
63262306a36Sopenharmony_ci	pcm->info_flags = (chip->dma1 == chip->dma2 ) ? SNDRV_PCM_INFO_JOINT_DUPLEX : 0;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	strcpy(pcm->name, snd_ad1816a_chip_id(chip));
63562306a36Sopenharmony_ci	snd_ad1816a_init(chip);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, chip->card->dev,
63862306a36Sopenharmony_ci				       64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	chip->pcm = pcm;
64162306a36Sopenharmony_ci	return 0;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciint snd_ad1816a_timer(struct snd_ad1816a *chip, int device)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct snd_timer *timer;
64762306a36Sopenharmony_ci	struct snd_timer_id tid;
64862306a36Sopenharmony_ci	int error;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
65162306a36Sopenharmony_ci	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
65262306a36Sopenharmony_ci	tid.card = chip->card->number;
65362306a36Sopenharmony_ci	tid.device = device;
65462306a36Sopenharmony_ci	tid.subdevice = 0;
65562306a36Sopenharmony_ci	error = snd_timer_new(chip->card, "AD1816A", &tid, &timer);
65662306a36Sopenharmony_ci	if (error < 0)
65762306a36Sopenharmony_ci		return error;
65862306a36Sopenharmony_ci	strcpy(timer->name, snd_ad1816a_chip_id(chip));
65962306a36Sopenharmony_ci	timer->private_data = chip;
66062306a36Sopenharmony_ci	chip->timer = timer;
66162306a36Sopenharmony_ci	timer->hw = snd_ad1816a_timer_table;
66262306a36Sopenharmony_ci	return 0;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci/*
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci */
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	static const char * const texts[8] = {
67262306a36Sopenharmony_ci		"Line", "Mix", "CD", "Synth", "Video",
67362306a36Sopenharmony_ci		"Mic", "Phone",
67462306a36Sopenharmony_ci	};
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 2, 7, texts);
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
68262306a36Sopenharmony_ci	unsigned long flags;
68362306a36Sopenharmony_ci	unsigned short val;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
68662306a36Sopenharmony_ci	val = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL);
68762306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
68862306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = (val >> 12) & 7;
68962306a36Sopenharmony_ci	ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
69062306a36Sopenharmony_ci	return 0;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
69662306a36Sopenharmony_ci	unsigned long flags;
69762306a36Sopenharmony_ci	unsigned short val;
69862306a36Sopenharmony_ci	int change;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] > 6 ||
70162306a36Sopenharmony_ci	    ucontrol->value.enumerated.item[1] > 6)
70262306a36Sopenharmony_ci		return -EINVAL;
70362306a36Sopenharmony_ci	val = (ucontrol->value.enumerated.item[0] << 12) |
70462306a36Sopenharmony_ci	      (ucontrol->value.enumerated.item[1] << 4);
70562306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
70662306a36Sopenharmony_ci	change = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL) != val;
70762306a36Sopenharmony_ci	snd_ad1816a_write(chip, AD1816A_ADC_SOURCE_SEL, val);
70862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
70962306a36Sopenharmony_ci	return change;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci#define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv)	\
71362306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
71462306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
71562306a36Sopenharmony_ci  .name = xname, .info = snd_ad1816a_info_single, \
71662306a36Sopenharmony_ci  .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
71762306a36Sopenharmony_ci  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
71862306a36Sopenharmony_ci  .tlv = { .p = (xtlv) } }
71962306a36Sopenharmony_ci#define AD1816A_SINGLE(xname, reg, shift, mask, invert) \
72062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \
72162306a36Sopenharmony_ci  .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
72262306a36Sopenharmony_ci  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic int snd_ad1816a_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
72962306a36Sopenharmony_ci	uinfo->count = 1;
73062306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
73162306a36Sopenharmony_ci	uinfo->value.integer.max = mask;
73262306a36Sopenharmony_ci	return 0;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic int snd_ad1816a_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
73862306a36Sopenharmony_ci	unsigned long flags;
73962306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
74062306a36Sopenharmony_ci	int shift = (kcontrol->private_value >> 8) & 0xff;
74162306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
74262306a36Sopenharmony_ci	int invert = (kcontrol->private_value >> 24) & 0xff;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
74562306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (snd_ad1816a_read(chip, reg) >> shift) & mask;
74662306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
74762306a36Sopenharmony_ci	if (invert)
74862306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
74962306a36Sopenharmony_ci	return 0;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
75562306a36Sopenharmony_ci	unsigned long flags;
75662306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
75762306a36Sopenharmony_ci	int shift = (kcontrol->private_value >> 8) & 0xff;
75862306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
75962306a36Sopenharmony_ci	int invert = (kcontrol->private_value >> 24) & 0xff;
76062306a36Sopenharmony_ci	int change;
76162306a36Sopenharmony_ci	unsigned short old_val, val;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	val = (ucontrol->value.integer.value[0] & mask);
76462306a36Sopenharmony_ci	if (invert)
76562306a36Sopenharmony_ci		val = mask - val;
76662306a36Sopenharmony_ci	val <<= shift;
76762306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
76862306a36Sopenharmony_ci	old_val = snd_ad1816a_read(chip, reg);
76962306a36Sopenharmony_ci	val = (old_val & ~(mask << shift)) | val;
77062306a36Sopenharmony_ci	change = val != old_val;
77162306a36Sopenharmony_ci	snd_ad1816a_write(chip, reg, val);
77262306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
77362306a36Sopenharmony_ci	return change;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci#define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
77762306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
77862306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
77962306a36Sopenharmony_ci  .name = xname, .info = snd_ad1816a_info_double,		\
78062306a36Sopenharmony_ci  .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
78162306a36Sopenharmony_ci  .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
78262306a36Sopenharmony_ci  .tlv = { .p = (xtlv) } }
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci#define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
78562306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \
78662306a36Sopenharmony_ci  .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
78762306a36Sopenharmony_ci  .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) }
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic int snd_ad1816a_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
79462306a36Sopenharmony_ci	uinfo->count = 2;
79562306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
79662306a36Sopenharmony_ci	uinfo->value.integer.max = mask;
79762306a36Sopenharmony_ci	return 0;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
80362306a36Sopenharmony_ci	unsigned long flags;
80462306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
80562306a36Sopenharmony_ci	int shift_left = (kcontrol->private_value >> 8) & 0x0f;
80662306a36Sopenharmony_ci	int shift_right = (kcontrol->private_value >> 12) & 0x0f;
80762306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
80862306a36Sopenharmony_ci	int invert = (kcontrol->private_value >> 24) & 0xff;
80962306a36Sopenharmony_ci	unsigned short val;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
81262306a36Sopenharmony_ci	val = snd_ad1816a_read(chip, reg);
81362306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
81462306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
81562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
81662306a36Sopenharmony_ci	if (invert) {
81762306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
81862306a36Sopenharmony_ci		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci	return 0;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
82662306a36Sopenharmony_ci	unsigned long flags;
82762306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
82862306a36Sopenharmony_ci	int shift_left = (kcontrol->private_value >> 8) & 0x0f;
82962306a36Sopenharmony_ci	int shift_right = (kcontrol->private_value >> 12) & 0x0f;
83062306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 16) & 0xff;
83162306a36Sopenharmony_ci	int invert = (kcontrol->private_value >> 24) & 0xff;
83262306a36Sopenharmony_ci	int change;
83362306a36Sopenharmony_ci	unsigned short old_val, val1, val2;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	val1 = ucontrol->value.integer.value[0] & mask;
83662306a36Sopenharmony_ci	val2 = ucontrol->value.integer.value[1] & mask;
83762306a36Sopenharmony_ci	if (invert) {
83862306a36Sopenharmony_ci		val1 = mask - val1;
83962306a36Sopenharmony_ci		val2 = mask - val2;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	val1 <<= shift_left;
84262306a36Sopenharmony_ci	val2 <<= shift_right;
84362306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
84462306a36Sopenharmony_ci	old_val = snd_ad1816a_read(chip, reg);
84562306a36Sopenharmony_ci	val1 = (old_val & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
84662306a36Sopenharmony_ci	change = val1 != old_val;
84762306a36Sopenharmony_ci	snd_ad1816a_write(chip, reg, val1);
84862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
84962306a36Sopenharmony_ci	return change;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
85362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
85462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
85562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
85662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ad1816a_controls[] = {
85962306a36Sopenharmony_ciAD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
86062306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1,
86162306a36Sopenharmony_ci		   db_scale_5bit),
86262306a36Sopenharmony_ciAD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1),
86362306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1,
86462306a36Sopenharmony_ci		   db_scale_6bit),
86562306a36Sopenharmony_ciAD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1),
86662306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1,
86762306a36Sopenharmony_ci		   db_scale_5bit_12db_max),
86862306a36Sopenharmony_ciAD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1),
86962306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1,
87062306a36Sopenharmony_ci		   db_scale_5bit_12db_max),
87162306a36Sopenharmony_ciAD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1),
87262306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1,
87362306a36Sopenharmony_ci		   db_scale_5bit_12db_max),
87462306a36Sopenharmony_ciAD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
87562306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1,
87662306a36Sopenharmony_ci		   db_scale_6bit),
87762306a36Sopenharmony_ciAD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
87862306a36Sopenharmony_ciAD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1,
87962306a36Sopenharmony_ci		   db_scale_5bit_12db_max),
88062306a36Sopenharmony_ciAD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
88162306a36Sopenharmony_ciAD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
88262306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1,
88362306a36Sopenharmony_ci		   db_scale_5bit_12db_max),
88462306a36Sopenharmony_ciAD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1),
88562306a36Sopenharmony_ciAD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1,
88662306a36Sopenharmony_ci		   db_scale_4bit),
88762306a36Sopenharmony_ciAD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1),
88862306a36Sopenharmony_ciAD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1,
88962306a36Sopenharmony_ci		   db_scale_5bit),
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
89262306a36Sopenharmony_ci	.name = "Capture Source",
89362306a36Sopenharmony_ci	.info = snd_ad1816a_info_mux,
89462306a36Sopenharmony_ci	.get = snd_ad1816a_get_mux,
89562306a36Sopenharmony_ci	.put = snd_ad1816a_put_mux,
89662306a36Sopenharmony_ci},
89762306a36Sopenharmony_ciAD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1),
89862306a36Sopenharmony_ciAD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0,
89962306a36Sopenharmony_ci		   db_scale_rec_gain),
90062306a36Sopenharmony_ciAD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1),
90162306a36Sopenharmony_ciAD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0),
90262306a36Sopenharmony_ci};
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ciint snd_ad1816a_mixer(struct snd_ad1816a *chip)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	struct snd_card *card;
90762306a36Sopenharmony_ci	unsigned int idx;
90862306a36Sopenharmony_ci	int err;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (snd_BUG_ON(!chip || !chip->card))
91162306a36Sopenharmony_ci		return -EINVAL;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	card = chip->card;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	strcpy(card->mixername, snd_ad1816a_chip_id(chip));
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_ad1816a_controls); idx++) {
91862306a36Sopenharmony_ci		err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1816a_controls[idx], chip));
91962306a36Sopenharmony_ci		if (err < 0)
92062306a36Sopenharmony_ci			return err;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
924