xref: /openbmc/linux/sound/pci/aw2/aw2-saa7146.c (revision 3d8f0f97)
1023b915eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
298f2a97fSCedric Bregardis /*****************************************************************************
398f2a97fSCedric Bregardis  *
498f2a97fSCedric Bregardis  * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
598f2a97fSCedric Bregardis  * Jean-Christian Hassler <jhassler@free.fr>
698f2a97fSCedric Bregardis  *
798f2a97fSCedric Bregardis  * This file is part of the Audiowerk2 ALSA driver
898f2a97fSCedric Bregardis  *
998f2a97fSCedric Bregardis  *****************************************************************************/
1098f2a97fSCedric Bregardis 
1198f2a97fSCedric Bregardis #define AW2_SAA7146_M
1298f2a97fSCedric Bregardis 
1398f2a97fSCedric Bregardis #include <linux/init.h>
1498f2a97fSCedric Bregardis #include <linux/pci.h>
1598f2a97fSCedric Bregardis #include <linux/interrupt.h>
1698f2a97fSCedric Bregardis #include <linux/delay.h>
176cbbfe1cSTakashi Iwai #include <linux/io.h>
1898f2a97fSCedric Bregardis #include <sound/core.h>
1998f2a97fSCedric Bregardis #include <sound/initval.h>
2098f2a97fSCedric Bregardis #include <sound/pcm.h>
2198f2a97fSCedric Bregardis #include <sound/pcm_params.h>
2298f2a97fSCedric Bregardis 
2398f2a97fSCedric Bregardis #include "saa7146.h"
2498f2a97fSCedric Bregardis #include "aw2-saa7146.h"
2598f2a97fSCedric Bregardis 
2691662577STakashi Iwai #include "aw2-tsl.c"
2791662577STakashi Iwai 
2898f2a97fSCedric Bregardis #define WRITEREG(value, addr) writel((value), chip->base_addr + (addr))
2998f2a97fSCedric Bregardis #define READREG(addr) readl(chip->base_addr + (addr))
3098f2a97fSCedric Bregardis 
3198f2a97fSCedric Bregardis static struct snd_aw2_saa7146_cb_param
3298f2a97fSCedric Bregardis  arr_substream_it_playback_cb[NB_STREAM_PLAYBACK];
3398f2a97fSCedric Bregardis static struct snd_aw2_saa7146_cb_param
3498f2a97fSCedric Bregardis  arr_substream_it_capture_cb[NB_STREAM_CAPTURE];
3598f2a97fSCedric Bregardis 
3698f2a97fSCedric Bregardis static int snd_aw2_saa7146_get_limit(int size);
3798f2a97fSCedric Bregardis 
3898f2a97fSCedric Bregardis /* chip-specific destructor */
snd_aw2_saa7146_free(struct snd_aw2_saa7146 * chip)3998f2a97fSCedric Bregardis int snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip)
4098f2a97fSCedric Bregardis {
4198f2a97fSCedric Bregardis 	/* disable all irqs */
4298f2a97fSCedric Bregardis 	WRITEREG(0, IER);
4398f2a97fSCedric Bregardis 
4498f2a97fSCedric Bregardis 	/* reset saa7146 */
4598f2a97fSCedric Bregardis 	WRITEREG((MRST_N << 16), MC1);
4698f2a97fSCedric Bregardis 
4798f2a97fSCedric Bregardis 	/* Unset base addr */
4898f2a97fSCedric Bregardis 	chip->base_addr = NULL;
4998f2a97fSCedric Bregardis 
5098f2a97fSCedric Bregardis 	return 0;
5198f2a97fSCedric Bregardis }
5298f2a97fSCedric Bregardis 
snd_aw2_saa7146_setup(struct snd_aw2_saa7146 * chip,void __iomem * pci_base_addr)5398f2a97fSCedric Bregardis void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
5498f2a97fSCedric Bregardis 			   void __iomem *pci_base_addr)
5598f2a97fSCedric Bregardis {
5698f2a97fSCedric Bregardis 	/* set PCI burst/threshold
5798f2a97fSCedric Bregardis 
5898f2a97fSCedric Bregardis 	   Burst length definition
5998f2a97fSCedric Bregardis 	   VALUE    BURST LENGTH
6098f2a97fSCedric Bregardis 	   000      1 Dword
6198f2a97fSCedric Bregardis 	   001      2 Dwords
6298f2a97fSCedric Bregardis 	   010      4 Dwords
6398f2a97fSCedric Bregardis 	   011      8 Dwords
6498f2a97fSCedric Bregardis 	   100      16 Dwords
6598f2a97fSCedric Bregardis 	   101      32 Dwords
6698f2a97fSCedric Bregardis 	   110      64 Dwords
6798f2a97fSCedric Bregardis 	   111      128 Dwords
6898f2a97fSCedric Bregardis 
6998f2a97fSCedric Bregardis 	   Threshold definition
7098f2a97fSCedric Bregardis 	   VALUE    WRITE MODE              READ MODE
7198f2a97fSCedric Bregardis 	   00       1 Dword of valid data   1 empty Dword
7298f2a97fSCedric Bregardis 	   01       4 Dwords of valid data  4 empty Dwords
7398f2a97fSCedric Bregardis 	   10       8 Dwords of valid data  8 empty Dwords
7498f2a97fSCedric Bregardis 	   11       16 Dwords of valid data 16 empty Dwords */
7598f2a97fSCedric Bregardis 
7698f2a97fSCedric Bregardis 	unsigned int acon2;
7798f2a97fSCedric Bregardis 	unsigned int acon1 = 0;
7898f2a97fSCedric Bregardis 	int i;
7998f2a97fSCedric Bregardis 
8098f2a97fSCedric Bregardis 	/* Set base addr */
8198f2a97fSCedric Bregardis 	chip->base_addr = pci_base_addr;
8298f2a97fSCedric Bregardis 
8398f2a97fSCedric Bregardis 	/* disable all irqs */
8498f2a97fSCedric Bregardis 	WRITEREG(0, IER);
8598f2a97fSCedric Bregardis 
8698f2a97fSCedric Bregardis 	/* reset saa7146 */
8798f2a97fSCedric Bregardis 	WRITEREG((MRST_N << 16), MC1);
8898f2a97fSCedric Bregardis 
8998f2a97fSCedric Bregardis 	/* enable audio interface */
9098f2a97fSCedric Bregardis #ifdef __BIG_ENDIAN
9198f2a97fSCedric Bregardis 	acon1 |= A1_SWAP;
9298f2a97fSCedric Bregardis 	acon1 |= A2_SWAP;
9398f2a97fSCedric Bregardis #endif
9498f2a97fSCedric Bregardis 	/* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
9598f2a97fSCedric Bregardis 
964b512d26SThadeu Lima de Souza Cascardo 	/* At initialization WS1 and WS2 are disabled (configured as input) */
9798f2a97fSCedric Bregardis 	acon1 |= 0 * WS1_CTRL;
9898f2a97fSCedric Bregardis 	acon1 |= 0 * WS2_CTRL;
9998f2a97fSCedric Bregardis 
10098f2a97fSCedric Bregardis 	/* WS4 is not used. So it must not restart A2.
10198f2a97fSCedric Bregardis 	   This is why it is configured as output (force to low) */
10298f2a97fSCedric Bregardis 	acon1 |= 3 * WS4_CTRL;
10398f2a97fSCedric Bregardis 
10498f2a97fSCedric Bregardis 	/* WS3_CTRL, WS3_SYNC: output TSL2, I2S */
10598f2a97fSCedric Bregardis 	acon1 |= 2 * WS3_CTRL;
10698f2a97fSCedric Bregardis 
10798f2a97fSCedric Bregardis 	/* A1 and A2 are active and asynchronous */
10898f2a97fSCedric Bregardis 	acon1 |= 3 * AUDIO_MODE;
10998f2a97fSCedric Bregardis 	WRITEREG(acon1, ACON1);
11098f2a97fSCedric Bregardis 
11198f2a97fSCedric Bregardis 	/* The following comes from original windows driver.
11298f2a97fSCedric Bregardis 	   It is needed to have a correct behavior of input and output
11398f2a97fSCedric Bregardis 	   simultenously, but I don't know why ! */
11498f2a97fSCedric Bregardis 	WRITEREG(3 * (BurstA1_in) + 3 * (ThreshA1_in) +
11598f2a97fSCedric Bregardis 		 3 * (BurstA1_out) + 3 * (ThreshA1_out) +
11698f2a97fSCedric Bregardis 		 3 * (BurstA2_out) + 3 * (ThreshA2_out), PCI_BT_A);
11798f2a97fSCedric Bregardis 
11898f2a97fSCedric Bregardis 	/* enable audio port pins */
11998f2a97fSCedric Bregardis 	WRITEREG((EAP << 16) | EAP, MC1);
12098f2a97fSCedric Bregardis 
12198f2a97fSCedric Bregardis 	/* enable I2C */
12298f2a97fSCedric Bregardis 	WRITEREG((EI2C << 16) | EI2C, MC1);
12398f2a97fSCedric Bregardis 	/* enable interrupts */
12498f2a97fSCedric Bregardis 	WRITEREG(A1_out | A2_out | A1_in | IIC_S | IIC_E, IER);
12598f2a97fSCedric Bregardis 
12698f2a97fSCedric Bregardis 	/* audio configuration */
12798f2a97fSCedric Bregardis 	acon2 = A2_CLKSRC | BCLK1_OEN;
12898f2a97fSCedric Bregardis 	WRITEREG(acon2, ACON2);
12998f2a97fSCedric Bregardis 
13098f2a97fSCedric Bregardis 	/* By default use analog input */
13198f2a97fSCedric Bregardis 	snd_aw2_saa7146_use_digital_input(chip, 0);
13298f2a97fSCedric Bregardis 
13398f2a97fSCedric Bregardis 	/* TSL setup */
13498f2a97fSCedric Bregardis 	for (i = 0; i < 8; ++i) {
13598f2a97fSCedric Bregardis 		WRITEREG(tsl1[i], TSL1 + (i * 4));
13698f2a97fSCedric Bregardis 		WRITEREG(tsl2[i], TSL2 + (i * 4));
13798f2a97fSCedric Bregardis 	}
13898f2a97fSCedric Bregardis 
13998f2a97fSCedric Bregardis }
14098f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 * chip,int stream_number,unsigned long dma_addr,unsigned long period_size,unsigned long buffer_size)14198f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
14298f2a97fSCedric Bregardis 				       int stream_number,
14398f2a97fSCedric Bregardis 				       unsigned long dma_addr,
14498f2a97fSCedric Bregardis 				       unsigned long period_size,
14598f2a97fSCedric Bregardis 				       unsigned long buffer_size)
14698f2a97fSCedric Bregardis {
14798f2a97fSCedric Bregardis 	unsigned long dw_page, dw_limit;
14898f2a97fSCedric Bregardis 
14998f2a97fSCedric Bregardis 	/* Configure DMA for substream
15098f2a97fSCedric Bregardis 	   Configuration informations: ALSA has allocated continuous memory
15198f2a97fSCedric Bregardis 	   pages. So we don't need to use MMU of saa7146.
15298f2a97fSCedric Bregardis 	 */
15398f2a97fSCedric Bregardis 
15498f2a97fSCedric Bregardis 	/* No MMU -> nothing to do with PageA1, we only configure the limit of
15598f2a97fSCedric Bregardis 	   PageAx_out register */
15698f2a97fSCedric Bregardis 	/* Disable MMU */
15798f2a97fSCedric Bregardis 	dw_page = (0L << 11);
15898f2a97fSCedric Bregardis 
15998f2a97fSCedric Bregardis 	/* Configure Limit for DMA access.
16098f2a97fSCedric Bregardis 	   The limit register defines an address limit, which generates
16198f2a97fSCedric Bregardis 	   an interrupt if passed by the actual PCI address pointer.
16298f2a97fSCedric Bregardis 	   '0001' means an interrupt will be generated if the lower
16398f2a97fSCedric Bregardis 	   6 bits (64 bytes) of the PCI address are zero. '0010'
16498f2a97fSCedric Bregardis 	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
16598f2a97fSCedric Bregardis 	   so on up to 1 Mbyte defined by '1111'. This interrupt range
16698f2a97fSCedric Bregardis 	   can be calculated as follows:
16798f2a97fSCedric Bregardis 	   Range = 2^(5 + Limit) bytes.
16898f2a97fSCedric Bregardis 	 */
16998f2a97fSCedric Bregardis 	dw_limit = snd_aw2_saa7146_get_limit(period_size);
17098f2a97fSCedric Bregardis 	dw_page |= (dw_limit << 4);
17198f2a97fSCedric Bregardis 
17298f2a97fSCedric Bregardis 	if (stream_number == 0) {
17398f2a97fSCedric Bregardis 		WRITEREG(dw_page, PageA2_out);
17498f2a97fSCedric Bregardis 
17598f2a97fSCedric Bregardis 		/* Base address for DMA transfert. */
17698f2a97fSCedric Bregardis 		/* This address has been reserved by ALSA. */
17798f2a97fSCedric Bregardis 		/* This is a physical address */
17898f2a97fSCedric Bregardis 		WRITEREG(dma_addr, BaseA2_out);
17998f2a97fSCedric Bregardis 
18098f2a97fSCedric Bregardis 		/* Define upper limit for DMA access */
18198f2a97fSCedric Bregardis 		WRITEREG(dma_addr + buffer_size, ProtA2_out);
18298f2a97fSCedric Bregardis 
18398f2a97fSCedric Bregardis 	} else if (stream_number == 1) {
18498f2a97fSCedric Bregardis 		WRITEREG(dw_page, PageA1_out);
18598f2a97fSCedric Bregardis 
18698f2a97fSCedric Bregardis 		/* Base address for DMA transfert. */
18798f2a97fSCedric Bregardis 		/* This address has been reserved by ALSA. */
18898f2a97fSCedric Bregardis 		/* This is a physical address */
18998f2a97fSCedric Bregardis 		WRITEREG(dma_addr, BaseA1_out);
19098f2a97fSCedric Bregardis 
19198f2a97fSCedric Bregardis 		/* Define upper limit for DMA access */
19298f2a97fSCedric Bregardis 		WRITEREG(dma_addr + buffer_size, ProtA1_out);
19398f2a97fSCedric Bregardis 	} else {
194179bb7f1STakashi Iwai 		pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
19598f2a97fSCedric Bregardis 		       "Substream number is not 0 or 1 -> not managed\n");
19698f2a97fSCedric Bregardis 	}
19798f2a97fSCedric Bregardis }
19898f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 * chip,int stream_number,unsigned long dma_addr,unsigned long period_size,unsigned long buffer_size)19998f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
20098f2a97fSCedric Bregardis 				      int stream_number, unsigned long dma_addr,
20198f2a97fSCedric Bregardis 				      unsigned long period_size,
20298f2a97fSCedric Bregardis 				      unsigned long buffer_size)
20398f2a97fSCedric Bregardis {
20498f2a97fSCedric Bregardis 	unsigned long dw_page, dw_limit;
20598f2a97fSCedric Bregardis 
20698f2a97fSCedric Bregardis 	/* Configure DMA for substream
20798f2a97fSCedric Bregardis 	   Configuration informations: ALSA has allocated continuous memory
20898f2a97fSCedric Bregardis 	   pages. So we don't need to use MMU of saa7146.
20998f2a97fSCedric Bregardis 	 */
21098f2a97fSCedric Bregardis 
21198f2a97fSCedric Bregardis 	/* No MMU -> nothing to do with PageA1, we only configure the limit of
21298f2a97fSCedric Bregardis 	   PageAx_out register */
21398f2a97fSCedric Bregardis 	/* Disable MMU */
21498f2a97fSCedric Bregardis 	dw_page = (0L << 11);
21598f2a97fSCedric Bregardis 
21698f2a97fSCedric Bregardis 	/* Configure Limit for DMA access.
21798f2a97fSCedric Bregardis 	   The limit register defines an address limit, which generates
21898f2a97fSCedric Bregardis 	   an interrupt if passed by the actual PCI address pointer.
21998f2a97fSCedric Bregardis 	   '0001' means an interrupt will be generated if the lower
22098f2a97fSCedric Bregardis 	   6 bits (64 bytes) of the PCI address are zero. '0010'
22198f2a97fSCedric Bregardis 	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
22298f2a97fSCedric Bregardis 	   so on up to 1 Mbyte defined by '1111'. This interrupt range
22398f2a97fSCedric Bregardis 	   can be calculated as follows:
22498f2a97fSCedric Bregardis 	   Range = 2^(5 + Limit) bytes.
22598f2a97fSCedric Bregardis 	 */
22698f2a97fSCedric Bregardis 	dw_limit = snd_aw2_saa7146_get_limit(period_size);
22798f2a97fSCedric Bregardis 	dw_page |= (dw_limit << 4);
22898f2a97fSCedric Bregardis 
22998f2a97fSCedric Bregardis 	if (stream_number == 0) {
23098f2a97fSCedric Bregardis 		WRITEREG(dw_page, PageA1_in);
23198f2a97fSCedric Bregardis 
23298f2a97fSCedric Bregardis 		/* Base address for DMA transfert. */
23398f2a97fSCedric Bregardis 		/* This address has been reserved by ALSA. */
23498f2a97fSCedric Bregardis 		/* This is a physical address */
23598f2a97fSCedric Bregardis 		WRITEREG(dma_addr, BaseA1_in);
23698f2a97fSCedric Bregardis 
23798f2a97fSCedric Bregardis 		/* Define upper limit for DMA access  */
23898f2a97fSCedric Bregardis 		WRITEREG(dma_addr + buffer_size, ProtA1_in);
23998f2a97fSCedric Bregardis 	} else {
240179bb7f1STakashi Iwai 		pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
24198f2a97fSCedric Bregardis 		       "Substream number is not 0 -> not managed\n");
24298f2a97fSCedric Bregardis 	}
24398f2a97fSCedric Bregardis }
24498f2a97fSCedric Bregardis 
snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,snd_aw2_saa7146_it_cb p_it_callback,void * p_callback_param)24598f2a97fSCedric Bregardis void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,
24698f2a97fSCedric Bregardis 						 snd_aw2_saa7146_it_cb
24798f2a97fSCedric Bregardis 						 p_it_callback,
24898f2a97fSCedric Bregardis 						 void *p_callback_param)
24998f2a97fSCedric Bregardis {
25098f2a97fSCedric Bregardis 	if (stream_number < NB_STREAM_PLAYBACK) {
25198f2a97fSCedric Bregardis 		arr_substream_it_playback_cb[stream_number].p_it_callback =
25298f2a97fSCedric Bregardis 		    (snd_aw2_saa7146_it_cb) p_it_callback;
25398f2a97fSCedric Bregardis 		arr_substream_it_playback_cb[stream_number].p_callback_param =
25498f2a97fSCedric Bregardis 		    (void *)p_callback_param;
25598f2a97fSCedric Bregardis 	}
25698f2a97fSCedric Bregardis }
25798f2a97fSCedric Bregardis 
snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,snd_aw2_saa7146_it_cb p_it_callback,void * p_callback_param)25898f2a97fSCedric Bregardis void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,
25998f2a97fSCedric Bregardis 						snd_aw2_saa7146_it_cb
26098f2a97fSCedric Bregardis 						p_it_callback,
26198f2a97fSCedric Bregardis 						void *p_callback_param)
26298f2a97fSCedric Bregardis {
26398f2a97fSCedric Bregardis 	if (stream_number < NB_STREAM_CAPTURE) {
26498f2a97fSCedric Bregardis 		arr_substream_it_capture_cb[stream_number].p_it_callback =
26598f2a97fSCedric Bregardis 		    (snd_aw2_saa7146_it_cb) p_it_callback;
26698f2a97fSCedric Bregardis 		arr_substream_it_capture_cb[stream_number].p_callback_param =
26798f2a97fSCedric Bregardis 		    (void *)p_callback_param;
26898f2a97fSCedric Bregardis 	}
26998f2a97fSCedric Bregardis }
27098f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 * chip,int stream_number)27198f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 *chip,
27298f2a97fSCedric Bregardis 						int stream_number)
27398f2a97fSCedric Bregardis {
27498f2a97fSCedric Bregardis 	unsigned int acon1 = 0;
27598f2a97fSCedric Bregardis 	/* In aw8 driver, dma transfert is always active. It is
27698f2a97fSCedric Bregardis 	   started and stopped in a larger "space" */
27798f2a97fSCedric Bregardis 	acon1 = READREG(ACON1);
27898f2a97fSCedric Bregardis 	if (stream_number == 0) {
27998f2a97fSCedric Bregardis 		WRITEREG((TR_E_A2_OUT << 16) | TR_E_A2_OUT, MC1);
28098f2a97fSCedric Bregardis 
28198f2a97fSCedric Bregardis 		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
28298f2a97fSCedric Bregardis 		acon1 |= 2 * WS2_CTRL;
28398f2a97fSCedric Bregardis 		WRITEREG(acon1, ACON1);
28498f2a97fSCedric Bregardis 
28598f2a97fSCedric Bregardis 	} else if (stream_number == 1) {
28698f2a97fSCedric Bregardis 		WRITEREG((TR_E_A1_OUT << 16) | TR_E_A1_OUT, MC1);
28798f2a97fSCedric Bregardis 
28898f2a97fSCedric Bregardis 		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
28998f2a97fSCedric Bregardis 		acon1 |= 1 * WS1_CTRL;
29098f2a97fSCedric Bregardis 		WRITEREG(acon1, ACON1);
29198f2a97fSCedric Bregardis 	}
29298f2a97fSCedric Bregardis }
29398f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 * chip,int stream_number)29498f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 *chip,
29598f2a97fSCedric Bregardis 					       int stream_number)
29698f2a97fSCedric Bregardis {
29798f2a97fSCedric Bregardis 	unsigned int acon1 = 0;
29898f2a97fSCedric Bregardis 	acon1 = READREG(ACON1);
29998f2a97fSCedric Bregardis 	if (stream_number == 0) {
30098f2a97fSCedric Bregardis 		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
30198f2a97fSCedric Bregardis 		acon1 &= ~(3 * WS2_CTRL);
30298f2a97fSCedric Bregardis 		WRITEREG(acon1, ACON1);
30398f2a97fSCedric Bregardis 
30498f2a97fSCedric Bregardis 		WRITEREG((TR_E_A2_OUT << 16), MC1);
30598f2a97fSCedric Bregardis 	} else if (stream_number == 1) {
30698f2a97fSCedric Bregardis 		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
30798f2a97fSCedric Bregardis 		acon1 &= ~(3 * WS1_CTRL);
30898f2a97fSCedric Bregardis 		WRITEREG(acon1, ACON1);
30998f2a97fSCedric Bregardis 
31098f2a97fSCedric Bregardis 		WRITEREG((TR_E_A1_OUT << 16), MC1);
31198f2a97fSCedric Bregardis 	}
31298f2a97fSCedric Bregardis }
31398f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 * chip,int stream_number)31498f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 *chip,
31598f2a97fSCedric Bregardis 					       int stream_number)
31698f2a97fSCedric Bregardis {
31798f2a97fSCedric Bregardis 	/* In aw8 driver, dma transfert is always active. It is
31898f2a97fSCedric Bregardis 	   started and stopped in a larger "space" */
31998f2a97fSCedric Bregardis 	if (stream_number == 0)
32098f2a97fSCedric Bregardis 		WRITEREG((TR_E_A1_IN << 16) | TR_E_A1_IN, MC1);
32198f2a97fSCedric Bregardis }
32298f2a97fSCedric Bregardis 
snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 * chip,int stream_number)32398f2a97fSCedric Bregardis void snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 *chip,
32498f2a97fSCedric Bregardis 					      int stream_number)
32598f2a97fSCedric Bregardis {
32698f2a97fSCedric Bregardis 	if (stream_number == 0)
32798f2a97fSCedric Bregardis 		WRITEREG((TR_E_A1_IN << 16), MC1);
32898f2a97fSCedric Bregardis }
32998f2a97fSCedric Bregardis 
snd_aw2_saa7146_interrupt(int irq,void * dev_id)33098f2a97fSCedric Bregardis irqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id)
33198f2a97fSCedric Bregardis {
33298f2a97fSCedric Bregardis 	unsigned int isr;
3333d8f0f97SPierre-Louis Bossart 	__always_unused unsigned int iicsta;
33498f2a97fSCedric Bregardis 	struct snd_aw2_saa7146 *chip = dev_id;
33598f2a97fSCedric Bregardis 
33698f2a97fSCedric Bregardis 	isr = READREG(ISR);
33798f2a97fSCedric Bregardis 	if (!isr)
33898f2a97fSCedric Bregardis 		return IRQ_NONE;
33998f2a97fSCedric Bregardis 
34098f2a97fSCedric Bregardis 	WRITEREG(isr, ISR);
34198f2a97fSCedric Bregardis 
34298f2a97fSCedric Bregardis 	if (isr & (IIC_S | IIC_E)) {
34398f2a97fSCedric Bregardis 		iicsta = READREG(IICSTA);
34498f2a97fSCedric Bregardis 		WRITEREG(0x100, IICSTA);
34598f2a97fSCedric Bregardis 	}
34698f2a97fSCedric Bregardis 
34798f2a97fSCedric Bregardis 	if (isr & A1_out) {
34898f2a97fSCedric Bregardis 		if (arr_substream_it_playback_cb[1].p_it_callback != NULL) {
34998f2a97fSCedric Bregardis 			arr_substream_it_playback_cb[1].
35098f2a97fSCedric Bregardis 			    p_it_callback(arr_substream_it_playback_cb[1].
35198f2a97fSCedric Bregardis 					  p_callback_param);
35298f2a97fSCedric Bregardis 		}
35398f2a97fSCedric Bregardis 	}
35498f2a97fSCedric Bregardis 	if (isr & A2_out) {
35598f2a97fSCedric Bregardis 		if (arr_substream_it_playback_cb[0].p_it_callback != NULL) {
35698f2a97fSCedric Bregardis 			arr_substream_it_playback_cb[0].
35798f2a97fSCedric Bregardis 			    p_it_callback(arr_substream_it_playback_cb[0].
35898f2a97fSCedric Bregardis 					  p_callback_param);
35998f2a97fSCedric Bregardis 		}
36098f2a97fSCedric Bregardis 
36198f2a97fSCedric Bregardis 	}
36298f2a97fSCedric Bregardis 	if (isr & A1_in) {
36398f2a97fSCedric Bregardis 		if (arr_substream_it_capture_cb[0].p_it_callback != NULL) {
36498f2a97fSCedric Bregardis 			arr_substream_it_capture_cb[0].
36598f2a97fSCedric Bregardis 			    p_it_callback(arr_substream_it_capture_cb[0].
36698f2a97fSCedric Bregardis 					  p_callback_param);
36798f2a97fSCedric Bregardis 		}
36898f2a97fSCedric Bregardis 	}
36998f2a97fSCedric Bregardis 	return IRQ_HANDLED;
37098f2a97fSCedric Bregardis }
37198f2a97fSCedric Bregardis 
snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 * chip,int stream_number,unsigned char * start_addr,unsigned int buffer_size)37298f2a97fSCedric Bregardis unsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 *chip,
37398f2a97fSCedric Bregardis 						 int stream_number,
37498f2a97fSCedric Bregardis 						 unsigned char *start_addr,
37598f2a97fSCedric Bregardis 						 unsigned int buffer_size)
37698f2a97fSCedric Bregardis {
37798f2a97fSCedric Bregardis 	long pci_adp = 0;
37898f2a97fSCedric Bregardis 	size_t ptr = 0;
37998f2a97fSCedric Bregardis 
38098f2a97fSCedric Bregardis 	if (stream_number == 0) {
38198f2a97fSCedric Bregardis 		pci_adp = READREG(PCI_ADP3);
38298f2a97fSCedric Bregardis 		ptr = pci_adp - (long)start_addr;
38398f2a97fSCedric Bregardis 
38498f2a97fSCedric Bregardis 		if (ptr == buffer_size)
38598f2a97fSCedric Bregardis 			ptr = 0;
38698f2a97fSCedric Bregardis 	}
38798f2a97fSCedric Bregardis 	if (stream_number == 1) {
38898f2a97fSCedric Bregardis 		pci_adp = READREG(PCI_ADP1);
38998f2a97fSCedric Bregardis 		ptr = pci_adp - (size_t) start_addr;
39098f2a97fSCedric Bregardis 
39198f2a97fSCedric Bregardis 		if (ptr == buffer_size)
39298f2a97fSCedric Bregardis 			ptr = 0;
39398f2a97fSCedric Bregardis 	}
39498f2a97fSCedric Bregardis 	return ptr;
39598f2a97fSCedric Bregardis }
39698f2a97fSCedric Bregardis 
snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 * chip,int stream_number,unsigned char * start_addr,unsigned int buffer_size)39798f2a97fSCedric Bregardis unsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 *chip,
39898f2a97fSCedric Bregardis 						int stream_number,
39998f2a97fSCedric Bregardis 						unsigned char *start_addr,
40098f2a97fSCedric Bregardis 						unsigned int buffer_size)
40198f2a97fSCedric Bregardis {
40298f2a97fSCedric Bregardis 	size_t pci_adp = 0;
40398f2a97fSCedric Bregardis 	size_t ptr = 0;
40498f2a97fSCedric Bregardis 	if (stream_number == 0) {
40598f2a97fSCedric Bregardis 		pci_adp = READREG(PCI_ADP2);
40698f2a97fSCedric Bregardis 		ptr = pci_adp - (size_t) start_addr;
40798f2a97fSCedric Bregardis 
40898f2a97fSCedric Bregardis 		if (ptr == buffer_size)
40998f2a97fSCedric Bregardis 			ptr = 0;
41098f2a97fSCedric Bregardis 	}
41198f2a97fSCedric Bregardis 	return ptr;
41298f2a97fSCedric Bregardis }
41398f2a97fSCedric Bregardis 
snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 * chip,int use_digital)41498f2a97fSCedric Bregardis void snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
41598f2a97fSCedric Bregardis 				       int use_digital)
41698f2a97fSCedric Bregardis {
41798f2a97fSCedric Bregardis 	/* FIXME: switch between analog and digital input does not always work.
41898f2a97fSCedric Bregardis 	   It can produce a kind of white noise. It seams that received data
41998f2a97fSCedric Bregardis 	   are inverted sometime (endian inversion). Why ? I don't know, maybe
42098f2a97fSCedric Bregardis 	   a problem of synchronization... However for the time being I have
42198f2a97fSCedric Bregardis 	   not found the problem. Workaround: switch again (and again) between
42298f2a97fSCedric Bregardis 	   digital and analog input until it works. */
42398f2a97fSCedric Bregardis 	if (use_digital)
42498f2a97fSCedric Bregardis 		WRITEREG(0x40, GPIO_CTRL);
42598f2a97fSCedric Bregardis 	else
42698f2a97fSCedric Bregardis 		WRITEREG(0x50, GPIO_CTRL);
42798f2a97fSCedric Bregardis }
42898f2a97fSCedric Bregardis 
snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 * chip)42998f2a97fSCedric Bregardis int snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 *chip)
43098f2a97fSCedric Bregardis {
43198f2a97fSCedric Bregardis 	unsigned int reg_val = READREG(GPIO_CTRL);
43298f2a97fSCedric Bregardis 	if ((reg_val & 0xFF) == 0x40)
43398f2a97fSCedric Bregardis 		return 1;
43498f2a97fSCedric Bregardis 	else
43598f2a97fSCedric Bregardis 		return 0;
43698f2a97fSCedric Bregardis }
43798f2a97fSCedric Bregardis 
43898f2a97fSCedric Bregardis 
snd_aw2_saa7146_get_limit(int size)43998f2a97fSCedric Bregardis static int snd_aw2_saa7146_get_limit(int size)
44098f2a97fSCedric Bregardis {
44198f2a97fSCedric Bregardis 	int limitsize = 32;
44298f2a97fSCedric Bregardis 	int limit = 0;
44398f2a97fSCedric Bregardis 	while (limitsize < size) {
44498f2a97fSCedric Bregardis 		limitsize *= 2;
44598f2a97fSCedric Bregardis 		limit++;
44698f2a97fSCedric Bregardis 	}
44798f2a97fSCedric Bregardis 	return limit;
44898f2a97fSCedric Bregardis }
449