162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*****************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
562306a36Sopenharmony_ci * Jean-Christian Hassler <jhassler@free.fr>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file is part of the Audiowerk2 ALSA driver
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *****************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define AW2_SAA7146_M
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/pci.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <sound/core.h>
1962306a36Sopenharmony_ci#include <sound/initval.h>
2062306a36Sopenharmony_ci#include <sound/pcm.h>
2162306a36Sopenharmony_ci#include <sound/pcm_params.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "saa7146.h"
2462306a36Sopenharmony_ci#include "aw2-saa7146.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "aw2-tsl.c"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define WRITEREG(value, addr) writel((value), chip->base_addr + (addr))
2962306a36Sopenharmony_ci#define READREG(addr) readl(chip->base_addr + (addr))
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic struct snd_aw2_saa7146_cb_param
3262306a36Sopenharmony_ci arr_substream_it_playback_cb[NB_STREAM_PLAYBACK];
3362306a36Sopenharmony_cistatic struct snd_aw2_saa7146_cb_param
3462306a36Sopenharmony_ci arr_substream_it_capture_cb[NB_STREAM_CAPTURE];
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int snd_aw2_saa7146_get_limit(int size);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* chip-specific destructor */
3962306a36Sopenharmony_ciint snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	/* disable all irqs */
4262306a36Sopenharmony_ci	WRITEREG(0, IER);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* reset saa7146 */
4562306a36Sopenharmony_ci	WRITEREG((MRST_N << 16), MC1);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* Unset base addr */
4862306a36Sopenharmony_ci	chip->base_addr = NULL;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	return 0;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_civoid snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
5462306a36Sopenharmony_ci			   void __iomem *pci_base_addr)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	/* set PCI burst/threshold
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	   Burst length definition
5962306a36Sopenharmony_ci	   VALUE    BURST LENGTH
6062306a36Sopenharmony_ci	   000      1 Dword
6162306a36Sopenharmony_ci	   001      2 Dwords
6262306a36Sopenharmony_ci	   010      4 Dwords
6362306a36Sopenharmony_ci	   011      8 Dwords
6462306a36Sopenharmony_ci	   100      16 Dwords
6562306a36Sopenharmony_ci	   101      32 Dwords
6662306a36Sopenharmony_ci	   110      64 Dwords
6762306a36Sopenharmony_ci	   111      128 Dwords
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	   Threshold definition
7062306a36Sopenharmony_ci	   VALUE    WRITE MODE              READ MODE
7162306a36Sopenharmony_ci	   00       1 Dword of valid data   1 empty Dword
7262306a36Sopenharmony_ci	   01       4 Dwords of valid data  4 empty Dwords
7362306a36Sopenharmony_ci	   10       8 Dwords of valid data  8 empty Dwords
7462306a36Sopenharmony_ci	   11       16 Dwords of valid data 16 empty Dwords */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	unsigned int acon2;
7762306a36Sopenharmony_ci	unsigned int acon1 = 0;
7862306a36Sopenharmony_ci	int i;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Set base addr */
8162306a36Sopenharmony_ci	chip->base_addr = pci_base_addr;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* disable all irqs */
8462306a36Sopenharmony_ci	WRITEREG(0, IER);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* reset saa7146 */
8762306a36Sopenharmony_ci	WRITEREG((MRST_N << 16), MC1);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* enable audio interface */
9062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
9162306a36Sopenharmony_ci	acon1 |= A1_SWAP;
9262306a36Sopenharmony_ci	acon1 |= A2_SWAP;
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci	/* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* At initialization WS1 and WS2 are disabled (configured as input) */
9762306a36Sopenharmony_ci	acon1 |= 0 * WS1_CTRL;
9862306a36Sopenharmony_ci	acon1 |= 0 * WS2_CTRL;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* WS4 is not used. So it must not restart A2.
10162306a36Sopenharmony_ci	   This is why it is configured as output (force to low) */
10262306a36Sopenharmony_ci	acon1 |= 3 * WS4_CTRL;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* WS3_CTRL, WS3_SYNC: output TSL2, I2S */
10562306a36Sopenharmony_ci	acon1 |= 2 * WS3_CTRL;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* A1 and A2 are active and asynchronous */
10862306a36Sopenharmony_ci	acon1 |= 3 * AUDIO_MODE;
10962306a36Sopenharmony_ci	WRITEREG(acon1, ACON1);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* The following comes from original windows driver.
11262306a36Sopenharmony_ci	   It is needed to have a correct behavior of input and output
11362306a36Sopenharmony_ci	   simultenously, but I don't know why ! */
11462306a36Sopenharmony_ci	WRITEREG(3 * (BurstA1_in) + 3 * (ThreshA1_in) +
11562306a36Sopenharmony_ci		 3 * (BurstA1_out) + 3 * (ThreshA1_out) +
11662306a36Sopenharmony_ci		 3 * (BurstA2_out) + 3 * (ThreshA2_out), PCI_BT_A);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* enable audio port pins */
11962306a36Sopenharmony_ci	WRITEREG((EAP << 16) | EAP, MC1);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* enable I2C */
12262306a36Sopenharmony_ci	WRITEREG((EI2C << 16) | EI2C, MC1);
12362306a36Sopenharmony_ci	/* enable interrupts */
12462306a36Sopenharmony_ci	WRITEREG(A1_out | A2_out | A1_in | IIC_S | IIC_E, IER);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* audio configuration */
12762306a36Sopenharmony_ci	acon2 = A2_CLKSRC | BCLK1_OEN;
12862306a36Sopenharmony_ci	WRITEREG(acon2, ACON2);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* By default use analog input */
13162306a36Sopenharmony_ci	snd_aw2_saa7146_use_digital_input(chip, 0);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* TSL setup */
13462306a36Sopenharmony_ci	for (i = 0; i < 8; ++i) {
13562306a36Sopenharmony_ci		WRITEREG(tsl1[i], TSL1 + (i * 4));
13662306a36Sopenharmony_ci		WRITEREG(tsl2[i], TSL2 + (i * 4));
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
14262306a36Sopenharmony_ci				       int stream_number,
14362306a36Sopenharmony_ci				       unsigned long dma_addr,
14462306a36Sopenharmony_ci				       unsigned long period_size,
14562306a36Sopenharmony_ci				       unsigned long buffer_size)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	unsigned long dw_page, dw_limit;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Configure DMA for substream
15062306a36Sopenharmony_ci	   Configuration informations: ALSA has allocated continuous memory
15162306a36Sopenharmony_ci	   pages. So we don't need to use MMU of saa7146.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* No MMU -> nothing to do with PageA1, we only configure the limit of
15562306a36Sopenharmony_ci	   PageAx_out register */
15662306a36Sopenharmony_ci	/* Disable MMU */
15762306a36Sopenharmony_ci	dw_page = (0L << 11);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Configure Limit for DMA access.
16062306a36Sopenharmony_ci	   The limit register defines an address limit, which generates
16162306a36Sopenharmony_ci	   an interrupt if passed by the actual PCI address pointer.
16262306a36Sopenharmony_ci	   '0001' means an interrupt will be generated if the lower
16362306a36Sopenharmony_ci	   6 bits (64 bytes) of the PCI address are zero. '0010'
16462306a36Sopenharmony_ci	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
16562306a36Sopenharmony_ci	   so on up to 1 Mbyte defined by '1111'. This interrupt range
16662306a36Sopenharmony_ci	   can be calculated as follows:
16762306a36Sopenharmony_ci	   Range = 2^(5 + Limit) bytes.
16862306a36Sopenharmony_ci	 */
16962306a36Sopenharmony_ci	dw_limit = snd_aw2_saa7146_get_limit(period_size);
17062306a36Sopenharmony_ci	dw_page |= (dw_limit << 4);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (stream_number == 0) {
17362306a36Sopenharmony_ci		WRITEREG(dw_page, PageA2_out);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		/* Base address for DMA transfert. */
17662306a36Sopenharmony_ci		/* This address has been reserved by ALSA. */
17762306a36Sopenharmony_ci		/* This is a physical address */
17862306a36Sopenharmony_ci		WRITEREG(dma_addr, BaseA2_out);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		/* Define upper limit for DMA access */
18162306a36Sopenharmony_ci		WRITEREG(dma_addr + buffer_size, ProtA2_out);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	} else if (stream_number == 1) {
18462306a36Sopenharmony_ci		WRITEREG(dw_page, PageA1_out);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		/* Base address for DMA transfert. */
18762306a36Sopenharmony_ci		/* This address has been reserved by ALSA. */
18862306a36Sopenharmony_ci		/* This is a physical address */
18962306a36Sopenharmony_ci		WRITEREG(dma_addr, BaseA1_out);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		/* Define upper limit for DMA access */
19262306a36Sopenharmony_ci		WRITEREG(dma_addr + buffer_size, ProtA1_out);
19362306a36Sopenharmony_ci	} else {
19462306a36Sopenharmony_ci		pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
19562306a36Sopenharmony_ci		       "Substream number is not 0 or 1 -> not managed\n");
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
20062306a36Sopenharmony_ci				      int stream_number, unsigned long dma_addr,
20162306a36Sopenharmony_ci				      unsigned long period_size,
20262306a36Sopenharmony_ci				      unsigned long buffer_size)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	unsigned long dw_page, dw_limit;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Configure DMA for substream
20762306a36Sopenharmony_ci	   Configuration informations: ALSA has allocated continuous memory
20862306a36Sopenharmony_ci	   pages. So we don't need to use MMU of saa7146.
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* No MMU -> nothing to do with PageA1, we only configure the limit of
21262306a36Sopenharmony_ci	   PageAx_out register */
21362306a36Sopenharmony_ci	/* Disable MMU */
21462306a36Sopenharmony_ci	dw_page = (0L << 11);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* Configure Limit for DMA access.
21762306a36Sopenharmony_ci	   The limit register defines an address limit, which generates
21862306a36Sopenharmony_ci	   an interrupt if passed by the actual PCI address pointer.
21962306a36Sopenharmony_ci	   '0001' means an interrupt will be generated if the lower
22062306a36Sopenharmony_ci	   6 bits (64 bytes) of the PCI address are zero. '0010'
22162306a36Sopenharmony_ci	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
22262306a36Sopenharmony_ci	   so on up to 1 Mbyte defined by '1111'. This interrupt range
22362306a36Sopenharmony_ci	   can be calculated as follows:
22462306a36Sopenharmony_ci	   Range = 2^(5 + Limit) bytes.
22562306a36Sopenharmony_ci	 */
22662306a36Sopenharmony_ci	dw_limit = snd_aw2_saa7146_get_limit(period_size);
22762306a36Sopenharmony_ci	dw_page |= (dw_limit << 4);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (stream_number == 0) {
23062306a36Sopenharmony_ci		WRITEREG(dw_page, PageA1_in);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		/* Base address for DMA transfert. */
23362306a36Sopenharmony_ci		/* This address has been reserved by ALSA. */
23462306a36Sopenharmony_ci		/* This is a physical address */
23562306a36Sopenharmony_ci		WRITEREG(dma_addr, BaseA1_in);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* Define upper limit for DMA access  */
23862306a36Sopenharmony_ci		WRITEREG(dma_addr + buffer_size, ProtA1_in);
23962306a36Sopenharmony_ci	} else {
24062306a36Sopenharmony_ci		pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
24162306a36Sopenharmony_ci		       "Substream number is not 0 -> not managed\n");
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_civoid snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,
24662306a36Sopenharmony_ci						 snd_aw2_saa7146_it_cb
24762306a36Sopenharmony_ci						 p_it_callback,
24862306a36Sopenharmony_ci						 void *p_callback_param)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	if (stream_number < NB_STREAM_PLAYBACK) {
25162306a36Sopenharmony_ci		arr_substream_it_playback_cb[stream_number].p_it_callback =
25262306a36Sopenharmony_ci		    (snd_aw2_saa7146_it_cb) p_it_callback;
25362306a36Sopenharmony_ci		arr_substream_it_playback_cb[stream_number].p_callback_param =
25462306a36Sopenharmony_ci		    (void *)p_callback_param;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_civoid snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,
25962306a36Sopenharmony_ci						snd_aw2_saa7146_it_cb
26062306a36Sopenharmony_ci						p_it_callback,
26162306a36Sopenharmony_ci						void *p_callback_param)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	if (stream_number < NB_STREAM_CAPTURE) {
26462306a36Sopenharmony_ci		arr_substream_it_capture_cb[stream_number].p_it_callback =
26562306a36Sopenharmony_ci		    (snd_aw2_saa7146_it_cb) p_it_callback;
26662306a36Sopenharmony_ci		arr_substream_it_capture_cb[stream_number].p_callback_param =
26762306a36Sopenharmony_ci		    (void *)p_callback_param;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 *chip,
27262306a36Sopenharmony_ci						int stream_number)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	unsigned int acon1 = 0;
27562306a36Sopenharmony_ci	/* In aw8 driver, dma transfert is always active. It is
27662306a36Sopenharmony_ci	   started and stopped in a larger "space" */
27762306a36Sopenharmony_ci	acon1 = READREG(ACON1);
27862306a36Sopenharmony_ci	if (stream_number == 0) {
27962306a36Sopenharmony_ci		WRITEREG((TR_E_A2_OUT << 16) | TR_E_A2_OUT, MC1);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
28262306a36Sopenharmony_ci		acon1 |= 2 * WS2_CTRL;
28362306a36Sopenharmony_ci		WRITEREG(acon1, ACON1);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	} else if (stream_number == 1) {
28662306a36Sopenharmony_ci		WRITEREG((TR_E_A1_OUT << 16) | TR_E_A1_OUT, MC1);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
28962306a36Sopenharmony_ci		acon1 |= 1 * WS1_CTRL;
29062306a36Sopenharmony_ci		WRITEREG(acon1, ACON1);
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 *chip,
29562306a36Sopenharmony_ci					       int stream_number)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	unsigned int acon1 = 0;
29862306a36Sopenharmony_ci	acon1 = READREG(ACON1);
29962306a36Sopenharmony_ci	if (stream_number == 0) {
30062306a36Sopenharmony_ci		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
30162306a36Sopenharmony_ci		acon1 &= ~(3 * WS2_CTRL);
30262306a36Sopenharmony_ci		WRITEREG(acon1, ACON1);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		WRITEREG((TR_E_A2_OUT << 16), MC1);
30562306a36Sopenharmony_ci	} else if (stream_number == 1) {
30662306a36Sopenharmony_ci		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
30762306a36Sopenharmony_ci		acon1 &= ~(3 * WS1_CTRL);
30862306a36Sopenharmony_ci		WRITEREG(acon1, ACON1);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		WRITEREG((TR_E_A1_OUT << 16), MC1);
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 *chip,
31562306a36Sopenharmony_ci					       int stream_number)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	/* In aw8 driver, dma transfert is always active. It is
31862306a36Sopenharmony_ci	   started and stopped in a larger "space" */
31962306a36Sopenharmony_ci	if (stream_number == 0)
32062306a36Sopenharmony_ci		WRITEREG((TR_E_A1_IN << 16) | TR_E_A1_IN, MC1);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_civoid snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 *chip,
32462306a36Sopenharmony_ci					      int stream_number)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	if (stream_number == 0)
32762306a36Sopenharmony_ci		WRITEREG((TR_E_A1_IN << 16), MC1);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciirqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	unsigned int isr;
33362306a36Sopenharmony_ci	__always_unused unsigned int iicsta;
33462306a36Sopenharmony_ci	struct snd_aw2_saa7146 *chip = dev_id;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	isr = READREG(ISR);
33762306a36Sopenharmony_ci	if (!isr)
33862306a36Sopenharmony_ci		return IRQ_NONE;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	WRITEREG(isr, ISR);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (isr & (IIC_S | IIC_E)) {
34362306a36Sopenharmony_ci		iicsta = READREG(IICSTA);
34462306a36Sopenharmony_ci		WRITEREG(0x100, IICSTA);
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (isr & A1_out) {
34862306a36Sopenharmony_ci		if (arr_substream_it_playback_cb[1].p_it_callback != NULL) {
34962306a36Sopenharmony_ci			arr_substream_it_playback_cb[1].
35062306a36Sopenharmony_ci			    p_it_callback(arr_substream_it_playback_cb[1].
35162306a36Sopenharmony_ci					  p_callback_param);
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	if (isr & A2_out) {
35562306a36Sopenharmony_ci		if (arr_substream_it_playback_cb[0].p_it_callback != NULL) {
35662306a36Sopenharmony_ci			arr_substream_it_playback_cb[0].
35762306a36Sopenharmony_ci			    p_it_callback(arr_substream_it_playback_cb[0].
35862306a36Sopenharmony_ci					  p_callback_param);
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci	if (isr & A1_in) {
36362306a36Sopenharmony_ci		if (arr_substream_it_capture_cb[0].p_it_callback != NULL) {
36462306a36Sopenharmony_ci			arr_substream_it_capture_cb[0].
36562306a36Sopenharmony_ci			    p_it_callback(arr_substream_it_capture_cb[0].
36662306a36Sopenharmony_ci					  p_callback_param);
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci	return IRQ_HANDLED;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ciunsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 *chip,
37362306a36Sopenharmony_ci						 int stream_number,
37462306a36Sopenharmony_ci						 unsigned char *start_addr,
37562306a36Sopenharmony_ci						 unsigned int buffer_size)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	long pci_adp = 0;
37862306a36Sopenharmony_ci	size_t ptr = 0;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (stream_number == 0) {
38162306a36Sopenharmony_ci		pci_adp = READREG(PCI_ADP3);
38262306a36Sopenharmony_ci		ptr = pci_adp - (long)start_addr;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		if (ptr == buffer_size)
38562306a36Sopenharmony_ci			ptr = 0;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	if (stream_number == 1) {
38862306a36Sopenharmony_ci		pci_adp = READREG(PCI_ADP1);
38962306a36Sopenharmony_ci		ptr = pci_adp - (size_t) start_addr;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		if (ptr == buffer_size)
39262306a36Sopenharmony_ci			ptr = 0;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	return ptr;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciunsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 *chip,
39862306a36Sopenharmony_ci						int stream_number,
39962306a36Sopenharmony_ci						unsigned char *start_addr,
40062306a36Sopenharmony_ci						unsigned int buffer_size)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	size_t pci_adp = 0;
40362306a36Sopenharmony_ci	size_t ptr = 0;
40462306a36Sopenharmony_ci	if (stream_number == 0) {
40562306a36Sopenharmony_ci		pci_adp = READREG(PCI_ADP2);
40662306a36Sopenharmony_ci		ptr = pci_adp - (size_t) start_addr;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		if (ptr == buffer_size)
40962306a36Sopenharmony_ci			ptr = 0;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	return ptr;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_civoid snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
41562306a36Sopenharmony_ci				       int use_digital)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	/* FIXME: switch between analog and digital input does not always work.
41862306a36Sopenharmony_ci	   It can produce a kind of white noise. It seams that received data
41962306a36Sopenharmony_ci	   are inverted sometime (endian inversion). Why ? I don't know, maybe
42062306a36Sopenharmony_ci	   a problem of synchronization... However for the time being I have
42162306a36Sopenharmony_ci	   not found the problem. Workaround: switch again (and again) between
42262306a36Sopenharmony_ci	   digital and analog input until it works. */
42362306a36Sopenharmony_ci	if (use_digital)
42462306a36Sopenharmony_ci		WRITEREG(0x40, GPIO_CTRL);
42562306a36Sopenharmony_ci	else
42662306a36Sopenharmony_ci		WRITEREG(0x50, GPIO_CTRL);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ciint snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 *chip)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	unsigned int reg_val = READREG(GPIO_CTRL);
43262306a36Sopenharmony_ci	if ((reg_val & 0xFF) == 0x40)
43362306a36Sopenharmony_ci		return 1;
43462306a36Sopenharmony_ci	else
43562306a36Sopenharmony_ci		return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic int snd_aw2_saa7146_get_limit(int size)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	int limitsize = 32;
44262306a36Sopenharmony_ci	int limit = 0;
44362306a36Sopenharmony_ci	while (limitsize < size) {
44462306a36Sopenharmony_ci		limitsize *= 2;
44562306a36Sopenharmony_ci		limit++;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci	return limit;
44862306a36Sopenharmony_ci}
449