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;
333*3d8f0f97SPierre-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