static void snd_ca0106_pcm_prepare_playback(struct emu10k1_card *card,struct mpxplay_audioout_info_s *aui) { const uint32_t channel=0; uint32_t *table_base =card->virtualpagetable; uint32_t period_size_bytes=card->period_size; uint32_t i,reg40_set,reg71_set; switch(aui->freq_card){ case 44100: reg40_set = 0x10000 << (channel<<1); reg71_set = 0x01010000; break; case 96000: reg40_set = 0x20000 << (channel<<1); reg71_set = 0x02020000; break; case 192000: reg40_set = 0x30000 << (channel<<1); reg71_set = 0x03030000; break; default: // 48000 reg40_set = 0; reg71_set = 0; break; } i = snd_ca0106_ptr_read(card, 0x40, 0); // control host to fifo i = (i & (~(0x30000<<(channel<<1)))) | reg40_set; snd_ca0106_ptr_write(card, 0x40, 0, i); i = snd_ca0106_ptr_read(card, 0x71, 0); // control DAC rate (SPDIF) i = (i & (~0x03030000)) | reg71_set; snd_ca0106_ptr_write(card, 0x71, 0, i); i=inl(card->iobase+HCFG); // control bit width if(aui->bits_card==32) i|=HCFG_PLAYBACK_S32_LE; else i&=~HCFG_PLAYBACK_S32_LE; outl(card->iobase+HCFG,i); // build pagetable for(i=0; i<CA0106_DMABUF_PERIODS; i++){ table_base[i*2]=(uint32_t)((char *)card->pcmout_buffer+(i*period_size_bytes)); table_base[i*2+1]=period_size_bytes<<16; } snd_ca0106_ptr_write(card, PLAYBACK_LIST_ADDR, channel, (uint32_t)(table_base)); snd_ca0106_ptr_write(card, PLAYBACK_LIST_SIZE, channel, (CA0106_DMABUF_PERIODS - 1) << 19); snd_ca0106_ptr_write(card, PLAYBACK_LIST_PTR, channel, 0); snd_ca0106_ptr_write(card, PLAYBACK_DMA_ADDR, channel, (uint32_t)card->pcmout_buffer); snd_ca0106_ptr_write(card, PLAYBACK_PERIOD_SIZE, channel, 0); //snd_ca0106_ptr_write(card, PLAYBACK_PERIOD_SIZE, channel, period_size_bytes<<16); snd_ca0106_ptr_write(card, PLAYBACK_POINTER, channel, 0); snd_ca0106_ptr_write(card, 0x07, channel, 0x0); snd_ca0106_ptr_write(card, 0x08, channel, 0); snd_ca0106_ptr_write(card, PLAYBACK_MUTE, 0x0, 0x0); // unmute output mpxplay_debugf(SBL_DEBUG_OUTPUT,"prepare playback end"); }
int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value) { u32 tmp; int timeout=0; int status; int retry; if ((reg > 0x7f) || (value > 0x1ff)) { snd_printk(KERN_ERR "i2c_write: invalid values.\n"); return -EINVAL; } tmp = reg << 25 | value << 16; /* Not sure what this I2C channel controls. */ /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ /* This controls the I2C connected to the WM8775 ADC Codec */ snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); for(retry=0;retry<10;retry++) { /* Send the data to i2c */ tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); /* Wait till the transaction ends */ while(1) { status = snd_ca0106_ptr_read(emu, I2C_A, 0); //snd_printk("I2C:status=0x%x\n", status); timeout++; if((status & I2C_A_ADC_START)==0) break; if(timeout>1000) break; } //Read back and see if the transaction is successful if((status & I2C_A_ADC_ABORT)==0) break; } if(retry==10) { snd_printk(KERN_ERR "Writing to ADC failed!\n"); return -EINVAL; } return 0; }
static void ca0106_set_capture_source(struct snd_ca0106 *emu) { unsigned int val = emu->capture_source; unsigned int source, mask; source = (val << 28) | (val << 24) | (val << 20) | (val << 16); mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); }
static unsigned int snd_live24_pcm_pointer_playback(struct emu10k1_card *card,struct mpxplay_audioout_info_s *aui) { unsigned int ptr,ptr1,ptr3,ptr4; const uint32_t channel=0; ptr3 = snd_ca0106_ptr_read(card, PLAYBACK_LIST_PTR, channel); ptr1 = snd_ca0106_ptr_read(card, PLAYBACK_POINTER, channel); ptr4 = snd_ca0106_ptr_read(card, PLAYBACK_LIST_PTR, channel); if(ptr3!=ptr4) ptr1=snd_ca0106_ptr_read(card, PLAYBACK_POINTER, channel); ptr4/=(2*sizeof(uint32_t)); ptr=(ptr4*card->period_size)+ptr1; mpxplay_debugf(SBL_DEBUG_OUTPUT,"list_ptr:%3d period_ptr:%4d bufpos:%d",ptr4,ptr1,ptr); ptr/=aui->chan_card; ptr/=aui->bits_card>>3; return ptr; }
static void ca0106_spdif_enable(struct snd_ca0106 *emu) { unsigned int val; if (emu->spdif_enable) { /* Digital */ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); val = inl(emu->port + GPIO) & ~0x101; outl(val, emu->port + GPIO); } else { /* Analog */ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); val = inl(emu->port + GPIO) | 0x101; outl(val, emu->port + GPIO); } }
static unsigned int snd_live24_mixer_read(struct emu10k1_card *card,unsigned int reg) { unsigned int channel_id=reg>>8; reg&=0xff; return snd_ca0106_ptr_read(card,reg,channel_id); }
static void snd_live24_pcm_stop_playback(struct emu10k1_card *card) { const uint32_t channel=0; snd_ca0106_ptr_write(card, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(card, BASIC_INTERRUPT, 0) & (~(0x1<<channel))); mpxplay_debugf(SBL_DEBUG_OUTPUT,"stop playback"); }
/* prepare playback callback */ static int snd_ca0106_pcm_prepare_playback(snd_pcm_substream_t *substream) { ca0106_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ca0106_pcm_t *epcm = runtime->private_data; int channel = epcm->channel_id; u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); u32 hcfg_mask = HCFG_PLAYBACK_S32_LE; u32 hcfg_set = 0x00000000; u32 hcfg; u32 reg40_mask = 0x30000 << (channel<<1); u32 reg40_set = 0; u32 reg40; /* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */ u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */ u32 reg71_set = 0; u32 reg71; int i; //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); /* Rate can be set per channel. */ /* reg40 control host to fifo */ /* reg71 controls DAC rate. */ switch (runtime->rate) { case 44100: reg40_set = 0x10000 << (channel<<1); reg71_set = 0x01010000; break; case 48000: reg40_set = 0; reg71_set = 0; break; case 96000: reg40_set = 0x20000 << (channel<<1); reg71_set = 0x02020000; break; case 192000: reg40_set = 0x30000 << (channel<<1); reg71_set = 0x03030000; break; default: reg40_set = 0; reg71_set = 0; break; } /* Format is a global setting */ /* FIXME: Only let the first channel accessed set this. */ switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: hcfg_set = 0; break; case SNDRV_PCM_FORMAT_S32_LE: hcfg_set = HCFG_PLAYBACK_S32_LE; break; default: hcfg_set = 0; break; } hcfg = inl(emu->port + HCFG) ; hcfg = (hcfg & ~hcfg_mask) | hcfg_set; outl(hcfg, emu->port + HCFG); reg40 = snd_ca0106_ptr_read(emu, 0x40, 0); reg40 = (reg40 & ~reg40_mask) | reg40_set; snd_ca0106_ptr_write(emu, 0x40, 0, reg40); reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); reg71 = (reg71 & ~reg71_mask) | reg71_set; snd_ca0106_ptr_write(emu, 0x71, 0, reg71); /* FIXME: Check emu->buffer.size before actually writing to it. */ for(i=0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } snd_ca0106_ptr_write(emu, PLAYBACK_LIST_ADDR, channel, emu->buffer.addr+(8*16*channel)); snd_ca0106_ptr_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes /* FIXME test what 0 bytes does. */ snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0); snd_ca0106_ptr_write(emu, 0x07, channel, 0x0); snd_ca0106_ptr_write(emu, 0x08, channel, 0); snd_ca0106_ptr_write(emu, PLAYBACK_MUTE, 0x0, 0x0); /* Unmute output */ #if 0 snd_ca0106_ptr_write(emu, SPCS0, 0, SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT ); }