📄 i2s_jz4740.c
字号:
/* * i2s.c * * JzSOC On-Chip I2S audio driver. * * Author: Seeger Chin * e-mail: seeger.chin@gmail.com * * Copyright (C) 2006 Ingenic Semiconductor Corp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <includes.h>#include <jz4740.h>#include "pcm.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 PAGE_SIZE 0x1000extern void printf(const char *fmt, ...);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 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);#define QUEUE_MAX 4typedef struct buffer_queue_s { int count; int id[QUEUE_MAX]; int lock;} buffer_queue_t;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;extern int IS_WRITE_PCM;static inline int get_buffer_id(struct buffer_queue_s *q){ int r; unsigned long flags; int i; flags = spin_lock_irqsave(); if (q->count == 0) return -1; 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 (__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; }}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"); 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); }}/* * Initialize the onchip I2S controller */static void jz_i2s_initHw(void){ unsigned int aic_cr_val; //__i2s_reset(); i2s_clk = __cpm_get_i2sclk(); __i2s_disable(); __i2s_as_slave(); __i2s_set_oss_sample_size(16); __i2s_set_iss_sample_size(16); //__i2s_enable(); __i2s_disable_record(); __i2s_disable_replay(); __i2s_disable_loopback(); __i2s_set_transmit_trigger(8); __i2s_set_receive_trigger(1);}static int jz_audio_set_speed(int rate){/* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ if (rate > 48000) rate = 48000; if (rate < 8000) rate = 8000; jz_audio_rate = rate; i2s_codec_set_samplerate(rate); return rate;}static int record_fill_1x8_u(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned long data; unsigned long *s = (unsigned long*)(in_dma_buf[id]); unsigned char *dp = (unsigned char*)dst_start; while (count > 0) { count -= 4; /* count in dword */ cnt += 2; data = *s++; *(dp ++) = data & 0xff; *(dp ++) = (data >> 16) & 0xff; } return cnt;}static int record_fill_2x8_u(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned long d1, d2; volatile unsigned long *s = (unsigned long*)(in_dma_buf[id]); volatile unsigned char *dp = (unsigned char*)dst_start; while (count > 0) { count -= 2; cnt += 2; d1 = *(s++); *(dp ++) = ((d1 << 16) >> 24) + 0x80; d2 = *(s++); *(dp ++) = ((d2 << 16) >> 24) + 0x80; } return cnt;}static int record_fill_1x16_s(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned long *s = (unsigned long * )(in_dma_buf[id]); unsigned short *dp = (unsigned short *)dst_start; while (count > 0) { count -= 4; /* count in dword */ cnt += 2; /* count in byte */ *(dp ++) = (*(s++) & 0xffff); } return cnt;}static int record_fill_2x16_s(unsigned long dst_start, int count, int id){ int cnt = 0; unsigned long d1, d2; unsigned long *s = (unsigned long*)(in_dma_buf[id]); unsigned short *dp = (unsigned short *)dst_start; while (count > 0) { count -= 2; /* count in dword */ cnt += 4; /* count in byte */ d1 = *(s++); *(dp ++) = (d1 + 0x80) >> 8; d2 = *(s++); *(dp ++) = (d2 + 0x80)>> 8; } return cnt;}static inline int record_fill_all(unsigned long dst_start, int count, int id){ memcpy((void *)dst_start,(void *)in_dma_buf[id],count); return count;}static void replay_fill_1x8_u(unsigned long src_start, int count, int id){ int cnt = 0; unsigned char data; unsigned long ddata; volatile unsigned char *s = (unsigned char *)src_start; volatile unsigned long *dp = (unsigned long*)(out_dma_buf[id]); while (count > 0) { count--; cnt += 1; data = *(s++) - 0x80;//see ak4642en page 29 ddata = (unsigned long) data << 8; *(dp ++) = ddata; *(dp ++) = ddata; } cnt = cnt * 2 * jz_audio_b; out_dma_buf_data_count[id] = cnt;}static void replay_fill_2x8_u(unsigned long src_start, int count, int id){ int cnt = 0; unsigned char d1; unsigned long dd1; volatile unsigned char *s = (unsigned char *)src_start; volatile unsigned long *dp = (unsigned long*)(out_dma_buf[id]); while (count > 0) { count -= 1; cnt += 1 ; d1 = *(s++) - 0x80; dd1 = (unsigned long) d1 << 8; *(dp ++) = dd1; } cnt *= jz_audio_b; out_dma_buf_data_count[id] = cnt;}static void replay_fill_1x16_s(unsigned long src_start, int count, int id){ int cnt = 0; unsigned short d1; unsigned long l1; volatile unsigned short *s = (unsigned short *)src_start; volatile unsigned long *dp = (unsigned long*)(out_dma_buf[id]); while (count > 0) { count -= 2; cnt += 2 ; d1 = *(s++); l1 = (unsigned long)d1; *(dp ++) = l1; *(dp ++) = l1; } cnt = cnt * 2 * jz_audio_b; out_dma_buf_data_count[id] = cnt;}static void replay_fill_2x16_s(unsigned long src_start, int count, int id){ int cnt = 0; unsigned short d1; unsigned long l1; unsigned short *s = (unsigned short *)src_start; unsigned long *dp = (unsigned long*)(out_dma_buf[id]); //printf("replay_fill_2x16_s dp:%x s:%x\r\n",dp,s); while (count > 0) { count -= 2; cnt += 4; d1 = *s++; l1 = (unsigned long)d1; *dp ++ = l1; } out_dma_buf_data_count[id] = cnt;}static inline void replay_fill_all(unsigned long src_start, int count, int id){ memcpy((void *)out_dma_buf[id],(void *)src_start,count); out_dma_buf_data_count[id] = count;}static unsigned int jz_audio_set_format(unsigned int fmt){ switch (fmt) { case AFMT_U8: jz_audio_format = fmt; jz_update_filler(fmt, jz_audio_channels); break; case AFMT_S16_LE: jz_audio_format = fmt; jz_update_filler(fmt, jz_audio_channels); break; } return jz_audio_format;}static short jz_audio_set_channels(short channels){ switch (channels) { case 1: //i2s_codec_set_channel(1); //jz_audio_channels = channels; //jz_update_filler(jz_audio_format, jz_audio_channels); //break; case 2: jz_audio_channels = channels;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -