📄 i2s_jz4740.c
字号:
/********************** BEGIN LICENSE BLOCK ************************************ * * JZ4740 mobile_tv Project V1.0.0 * INGENIC CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM * Copyright (c) Ingenic Semiconductor Co. Ltd 2005. All rights reserved. * * This file, and the files included with this file, is distributed and made * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * * http://www.ingenic.cn * ********************** END LICENSE BLOCK ************************************** * * Author: <dsqiu@ingenic.cn> <jgao@ingenic.cn> * * Create: 2008-06-26, by dsqiu * * Maintain: 2008-06-26, by jgao * * ******************************************************************************* */#include <includes.h>#include <jz4740.h>#include "pcm.h"#include "dm.h"#include "i2s_codec_jz4740.h"#define CONFIG_I2S_AK4642EN#define DMAC_DCCSR_DAM DMAC_DCMD_DAI#define DMAC_DCCSR_SAM DMAC_DCMD_SAI#define DMAC_DCCSR_RDIL_IGN DMAC_DCMD_RDIL_IGN#ifndef u8#define u8 unsigned char#endif#ifndef u16#define u16 unsigned short#endif#ifndef u32#define u32 unsigned int#endif#define AUDIO_READ_DMA 2#define AUDIO_WRITE_DMA 3#ifdef PHYADDR#undef PHYADDR#endif#define PHYADDR(n) ((n) & 0x1fffffff)#ifdef KSEG1ADDR#undef KSEG1ADDR#endif#define KSEG1ADDR(n) (PHYADDR(n) | 0xa0000000)#ifdef PAGE_SIZE#undef PAGE_SIZE#endif#define QUEUE_MAX 0x4#define PAGE_SIZE (0x10000 / QUEUE_MAX)extern void HP_turn_off(void);#define STANDARD_SPEED 48000#define SYNC_CLK 48000#define MAX_RETRY 100extern int HP_on_off_flag;static unsigned long i2s_clk;static int jz_audio_b; static int jz_audio_rate;static char jz_audio_format;static char jz_audio_channels;static char jz_audio_volume;static u16 jz_audio_factor;int codec_get_rate(void) {return jz_audio_rate;}char codec_get_format(void) {return jz_audio_format;}char codec_get_channels(void) {return jz_audio_channels;}static void jz_update_filler(int bits, int channels);static void jz_i2s_replay_dma_irq(unsigned int);static void jz_i2s_record_dma_irq(unsigned int);static void (*replay_filler)(unsigned long src_start, int count, int id);static int (*record_filler)(unsigned long dst_start, int count, int id);static long old_mute=0; static long new_mute=0; static long old_hw_vol=0; static long new_hw_vol=0; static int flag_CDCCR=0; static int pause_flag=0;/*start*****************add volum control -by gaojian***********************/#if 0static void get_factor(int level);static void fill_sample_table(void);static u16 get_new_sample(int sample);static int codec_volue_factor;static int codec_volue_hpmute;static int codec_volue_hpvol;static u16 sample_table[32768];static u16 get_new_sample(int sample){ printf("sample:%d",sample); if (sample >= 0) return sample_table[sample]; else return (-(sample_table[(-sample)] + 1));}static void fill_sample_table(void){ int cnt; sample_table[0] = 0; for (cnt = 1; cnt <= 32767; cnt++) //sample_table[cnt] = (u16)((cnt * codec_volue_factor) >> 8); sample_table[cnt] = (u16)(cnt * codec_volue_factor / 30);}static void get_factor(int level){ int hpmute = 0, hpvol = 0, factor = 0; switch (level) { case 1 ... 30: hpmute = 0; hpvol = 0; factor = level; break; case 0: hpmute = 1; hpvol = 0; factor = 0; break; } codec_volue_factor = factor; codec_volue_hpvol = hpvol; codec_volue_hpmute = hpmute;}#endif/*end*****************add volum control -by gaojian ***********************/#if 0static u16 Factor_table[32] = { 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240,256, 216, 230, 243, 256, 214,224, 235, 245, 256, 212, 221, 230, 238, 247,256};#endifstatic u16 Factor_table[32] = { 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225,256, 216, 230, 243, 256, 214,224, 235, 245, 256, 212, 221, 230, 238, 247,256};////////////////////////////////////////typedef struct buffer_queue_s { int count; int id[QUEUE_MAX]; int oldid;} buffer_queue_t;#if 0typedef struct left_right_sample_s{ signed short left; signed short right;} left_right_sample_t;#endif//static left_right_sample_t save_last_samples[64];static unsigned long out_dma_buf[QUEUE_MAX+1];static unsigned long out_dma_pbuf[QUEUE_MAX+1];static unsigned long out_dma_buf_data_count[QUEUE_MAX+1];static unsigned long in_dma_buf[QUEUE_MAX+1];static unsigned long in_dma_pbuf[QUEUE_MAX+1];static unsigned long in_dma_buf_data_count[QUEUE_MAX+1];static buffer_queue_t out_empty_queue;static buffer_queue_t out_full_queue;static buffer_queue_t out_busy_queue;static buffer_queue_t in_empty_queue;static buffer_queue_t in_full_queue;static buffer_queue_t in_busy_queue;static int first_record_call = 0;static OS_EVENT *tx_sem;static OS_EVENT *rx_sem;//static OS_EVENT *pause_sem;//static OS_EVENT *pre_tx_sem;static int preconvert_control = 0;static int IS_WRITE_PCM;#define CODE_RESET_BUFSIZE (256)#define CODE_RESET_THREAD_PRIO 130 #define CODE_POWER_ON 0#define CODE_POWER_OFF 1static OS_STK code_reset_buf[CODE_RESET_BUFSIZE];static volatile int code_power = 0; //power on statestatic unsigned int save_REG_ICDC_CDCCR1,save_REG_ICDC_CDCCR2;static int power_count = 1;static OS_EVENT *jz_codepower_sem = NULL;#define OP_CODEPOWER_LOCK() do{ \ unsigned char err; \ OSSemPend(jz_codepower_sem, 0, &err); \ }while(0) #define OP_CODEPOWER_UNLOCK() do{ \ unsigned char err; \ OSSemPost(jz_codepower_sem); \ }while(0)#define WAIT_POWERON() while(code_power) OSTimeDly(10) void jz_codec_poweron(int d);void jz_codec_poweroff(int d);static inline int get_buffer_id(struct buffer_queue_s *q){ int r; unsigned long flags; int i; if (q->count == 0) return -1; flags = spin_lock_irqsave(); r = q->id[0]; for (i=0;i < q->count-1;i++) q->id[i] = q->id[i+1]; q->count --; spin_unlock_irqrestore(flags); return r;}static inline void put_buffer_id(struct buffer_queue_s *q, int id){ unsigned long flags; flags = spin_lock_irqsave(); q->id[q->count] = id; q->count ++; spin_unlock_irqrestore(flags);}static inline int elements_in_queue(struct buffer_queue_s *q){ int r; unsigned long flags; flags=spin_lock_irqsave(); r = q->count; spin_unlock_irqrestore(flags); return r;}/**************************************************************************** * Architecture related routines ****************************************************************************/static void jz_i2s_record_dma_irq (unsigned int arg){ int dma = AUDIO_READ_DMA; int id1, id2; dma_stop(dma);// if(preconvert_control==1)// {// OSSemPost(pre_tx_sem);// return;// } if (__dmac_channel_address_error_detected(dma)) { printf("%s: DMAC address error.\n", __FUNCTION__); __dmac_channel_clear_address_error(dma); } if (__dmac_channel_transmit_end_detected(dma)) { __dmac_channel_clear_transmit_end(dma); id1 = get_buffer_id(&in_busy_queue); put_buffer_id(&in_full_queue, id1); //__dcache_invalidate_all(); OSSemPost(rx_sem); if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { put_buffer_id(&in_busy_queue, id2); in_dma_buf_data_count[id2] = in_dma_buf_data_count[id1]; dma_start(dma, PHYADDR(AIC_DR), in_dma_pbuf[id2], in_dma_buf_data_count[id2]); } else in_busy_queue.count = 0; }}#if 0int pause_flag,control=0,jz_pause_flag =0,restart=0;int restart_count = 1;static int restart_pcm(unsigned int smp,unsigned char *p){ signed short l_sample,r_sample; signed char *mono; unsigned int cur_dma_buffer_count = 0; int i,l_flag,r_flag,step_len; signed int left_sam,right_sam,temp,l_val,r_val; unsigned long l_sample_count,r_sample_count,sample_count,temp_convert; volatile signed short *stero; volatile signed short value; //smp = smp - jz_audio_channels * 1; switch(jz_audio_b) { case 8: mono = (signed char *)p; break; case 16: stero = (signed short *)p; break; } switch(jz_audio_channels) { case 1: l_sample = (unsigned int)mono[smp]; r_sample = (unsigned int)mono[smp + 1]; break; case 2: l_sample = (signed short)( *(stero) ); r_sample = (signed short)( *(stero + 1) ); //printf("\n{ l_sample:%d ; r_sample:%d }",l_sample,r_sample); left_sam = (signed int)l_sample; right_sam = (signed int)r_sample; sample_count = smp / 4; //////////////////////////////////////// for(i=0;i <= (sample_count/2);i++) { /*if(sample_count/2 > 20) { if((i < 10) || (i > (sample_count/2 - 10) )) printf("A[ %d : %d---%d ]\n",i,(signed int)(*(stero + i)),(signed int)(*(stero + sample_count - i))); }*/ l_val = (signed int)(*(stero + i)); *(stero + i) = *(stero + sample_count - i); *(stero + sample_count - i) = (signed short)l_val; /*if(sample_count/2 > 20) { if((i < 10) || (i > (sample_count/2 - 10) )) printf("B[ %d : %d---%d ]\n",i,(signed int)(*(stero + i)),(signed int)(*(stero + sample_count - i))); }*/ } cur_dma_buffer_count = smp; //////////////////////////////////////////// break; } return cur_dma_buffer_count;}static int insert_pcm(unsigned int smp,unsigned char *p){ signed short l_sample,r_sample; signed char *mono; unsigned int cur_dma_buffer_count = 0; int i,l_flag,r_flag,step_len; signed int left_sam,right_sam,temp,l_val,r_val; unsigned long l_sample_count,r_sample_count,sample_count,temp_convert; volatile signed short *stero; volatile signed short value; //smp = smp - jz_audio_channels * 1; if(smp == 0) return 0; switch(jz_audio_b) { case 8: mono = (signed char *)p; break; case 16: stero = (signed short *)p; break; } switch(jz_audio_channels) { case 1: l_sample = (unsigned int)mono[smp]; r_sample = (unsigned int)mono[smp + 1]; break; case 2: l_sample = (signed short)( *(stero + (smp/2) -2) ); r_sample = (signed short)( *(stero + (smp/2) -1) ); left_sam = (signed int)l_sample; right_sam = (signed int)r_sample; if(left_sam == 0 && right_sam == 0) return 0; //insert some sample here //////////////////////////////////////// memset(p,0,smp); step_len = jz_audio_rate / 10 * 4; step_len /= 2; step_len = 0x7fff / step_len + 1; l_sample_count = 0; l_val = left_sam; while(1) { if(l_val > 0) { if(l_val >= step_len) { l_val -= step_len; l_sample_count ++; } else break; } if(l_val < 0) { if(l_val <= -step_len) { l_val += step_len; l_sample_count ++; } else break; } if(l_val == 0) break; } r_sample_count = 0; r_val = right_sam; while(1) { if(r_val > 0) { if(r_val >= step_len) { r_val -= step_len; r_sample_count ++; } else break; } if(r_val < 0) { if(r_val <= -step_len) { r_val += step_len; r_sample_count ++; } else break; } if(r_val == 0) break; } //fill up if(l_sample_count > r_sample_count) sample_count = l_sample_count; else sample_count = r_sample_count; l_val = left_sam; r_val = right_sam; for(i=0;i <= sample_count;i++) { *stero = (signed short)l_val; stero ++; if(l_val > step_len) { l_val -= step_len; } else if(l_val < -step_len) { l_val += step_len; } else if(l_val >= -step_len && l_val <= step_len) { l_val = 0; } *stero = (signed short)r_val; stero ++; if(r_val > step_len) { r_val -= step_len; } else if(r_val < -step_len) { r_val += step_len; } else if(r_val >= -step_len && r_val <= step_len) { r_val = 0; } } *stero = 0; stero ++; *stero = 0; stero ++; sample_count += 1; *stero = 0; stero ++; *stero = 0; stero ++; sample_count += 1; *stero = 0; stero ++; *stero = 0; stero ++; sample_count += 1; cur_dma_buffer_count = sample_count * 4; break; } return cur_dma_buffer_count;}static void pcm_pause(){ unsigned char err; int dma = AUDIO_WRITE_DMA; int id; if(control==1) { control = 0; }else { control = 1; } if(pause_flag == 0) { pause_flag = 1; printf("pause:%d\n",pause_flag); }else { pause_flag = 0; printf("pause:%d\n",pause_flag); __intc_unmask_irq(20); id = out_busy_queue.oldid; if(out_dma_buf_data_count[id] != 0) { dma_start(dma, out_dma_pbuf[id], PHYADDR(AIC_DR), out_dma_buf_data_count[id]); } }}static void pcm_start(void){ unsigned char err; int dma = AUDIO_WRITE_DMA; int id; __intc_unmask_irq(20); id = out_busy_queue.oldid; if(out_dma_buf_data_count[id] != 0) { dma_start(dma, out_dma_pbuf[id], PHYADDR(AIC_DR), out_dma_buf_data_count[id]); } }#endif #if 1static inline void set_hw_volume(void){ //set CDCCR1 if(flag_CDCCR) { if(old_mute!=new_mute) { i2s_codec_set_mute(new_mute); old_mute=new_mute; } if(old_hw_vol!=new_hw_vol) { i2s_codec_set_volume(new_hw_vol); old_hw_vol=new_hw_vol; } flag_CDCCR=0; }}static void jz_i2s_replay_dma_irq (unsigned int arg){ int dma = AUDIO_WRITE_DMA; int id; dma_stop(dma); if (__dmac_channel_address_error_detected(dma)) { printf("%s: DMAC address error.\n", __FUNCTION__); __dmac_channel_clear_address_error(dma); } if (__dmac_channel_transmit_end_detected(dma)) { __dmac_channel_clear_transmit_end(dma); if ((id = get_buffer_id(&out_busy_queue)) < 0) printf("Strange DMA finish interrupt for AIC module\n"); //set hardware volume set_hw_volume(); put_buffer_id(&out_empty_queue, id); if ((id = get_buffer_id(&out_full_queue)) >= 0) { put_buffer_id(&out_busy_queue, id); dma_start(dma, out_dma_pbuf[id], PHYADDR(AIC_DR), out_dma_buf_data_count[id]); } else out_busy_queue.count = 0; // if (elements_in_queue(&out_empty_queue) > 0) // OSSemPost(tx_sem); }}#endif#if 0void anti_pop_1(void){ unsigned char err; int dma = AUDIO_WRITE_DMA; int id; int i,j,tx_con=0,step_cnt,step_len; int d; unsigned short left,right,tmp1,tmp2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -