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