rt-thread-official/bsp/x1000/drivers/audio/drv_codec_icodec.h

407 lines
11 KiB
C
Raw Normal View History

2017-11-11 13:51:56 +08:00
/*
* drv_codec_icodec.h
*
* Created on: 2017<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>10<EFBFBD><EFBFBD>
* Author: Urey
*/
#ifndef _DRV_CODEC_ICODEC_H_
#define _DRV_CODEC_ICODEC_H_
#include <stdint.h>
#include "x1000.h"
#include "drv_clock.h"
struct jz_icodec
{
struct jz_i2s *i2s;
struct rt_audio_configure replay_config;
#ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER
struct rt_mempool mp;
#endif /* AUDIO_DEVICE_USE_PRIVATE_BUFFER */
uint32_t mapped_base;
/* replay */
int user_replay_volume;
int dac_user_mute; /*dac user mute state*/
int aohp_in_pwsq; /*aohp in power up/down seq*/
int hpl_wished_gain; /*keep original hpl/r gain register value*/
int hpr_wished_gain;
int linl_wished_gain; /*keep original hpl/r gain register value*/
int linr_wished_gain;
};
#define ICODEC_PCM_FORMAT AUDIO_FMT_PCM_S16_LE
#define ICODEC_SAMPLING_RATE 44100
/* icodec internal register space */
enum {
SCODA_REG_SR = 0x0,
SCODA_REG_SR2,
SCODA_REG_SIGR,
SCODA_REG_SIGR2,
SCODA_REG_SIGR3,
SCODA_REG_SIGR5,
SCODA_REG_SIGR7,
SCODA_REG_MR,
SCODA_REG_AICR_DAC,
SCODA_REG_AICR_ADC,
SCODA_REG_CR_DMIC,
SCODA_REG_CR_MIC1,
SCODA_REG_CR_MIC2,
SCODA_REG_CR_DAC,
SCODA_REG_CR_DAC2,
SCODA_REG_CR_ADC,
SCODA_REG_CR_MIX,
SCODA_REG_DR_MIX,
SCODA_REG_CR_VIC,
SCODA_REG_CR_CK,
SCODA_REG_FCR_DAC,
SCODA_REG_SFCCR_DAC,
SCODA_REG_SFFCR_DAC,
SCODA_REG_FCR_ADC,
SCODA_REG_CR_TIMER_MSB,
SCODA_REG_CR_TIMER_LSB,
SCODA_REG_ICR,
SCODA_REG_IMR,
SCODA_REG_IFR,
SCODA_REG_IMR2,
SCODA_REG_IFR2,
SCODA_REG_GCR_DACL,
SCODA_REG_GCR_DACR,
SCODA_REG_GCR_DACL2,
SCODA_REG_GCR_DACR2,
SCODA_REG_GCR_MIC1,
SCODA_REG_GCR_MIC2,
SCODA_REG_GCR_ADCL,
SCODA_REG_GCR_ADCR,
SCODA_REG_GCR_MIXDACL,
SCODA_REG_GCR_MIXDACR,
SCODA_REG_GCR_MIXADCL,
SCODA_REG_GCR_MIXADCR,
SCODA_REG_CR_DAC_AGC,
SCODA_REG_DR_DAC_AGC,
SCODA_REG_CR_DAC2_AGC,
SCODA_REG_DR_DAC2_AGC,
SCODA_REG_CR_ADC_AGC,
SCODA_REG_DR_ADC_AGC,
SCODA_REG_SR_ADC_AGCDGL,
SCODA_REG_SR_ADC_AGCDGR,
SCODA_REG_SR_ADC_AGCAGL,
SCODA_REG_SR_ADC_AGCAGR,
SCODA_REG_CR_TR,
SCODA_REG_DR_TR,
SCODA_REG_SR_TR1,
SCODA_REG_SR_TR2,
SCODA_REG_SR_TR_SRCDAC,
/* icodec internal register extend space */
SCODA_MIX_0,
SCODA_MIX_1,
SCODA_MIX_2,
SCODA_MIX_3,
SCODA_MIX_4,
SCODA_DAC_AGC0,
SCODA_DAC_AGC1,
SCODA_DAC_AGC2,
SCODA_DAC_AGC3,
SCODA_DAC2_AGC0,
SCODA_DAC2_AGC1,
SCODA_DAC2_AGC2,
SCODA_DAC2_AGC3,
SCODA_ADC_AGC0,
SCODA_ADC_AGC1,
SCODA_ADC_AGC2,
SCODA_ADC_AGC3,
SCODA_ADC_AGC4,
SCODA_MAX_REG_NUM,
};
/*aicr dac*/
#define SCODA_AICR_DAC_ADWL_SHIFT (6)
#define SCODA_AICR_DAC_ADWL_MASK (0x3 << SCODA_AICR_DAC_ADWL_SHIFT)
#define SCODA_AICR_DAC_SLAVE_SHIFT (5)
#define SCODA_AICR_DAC_SLAVE_MASK (0x1 << SCODA_AICR_DAC_SLAVE_SHIFT)
#define SCODA_AICR_DAC_SLAVE (1 << 5)
#define SCODA_AICR_DAC_SB_SHIFT (4)
#define SCODA_AICR_DAC_SB_MASK (0x1 << SCODA_AICR_DAC_SB_SHIFT)
#define SCODA_AICR_DAC_AUDIOIF_SHIFT (0)
#define SCODA_AICR_DAC_AUDIO_MASK (0x3 << SCODA_AICR_DAC_AUDIOIF_SHIFT)
#define SCODA_AICR_DAC_AUDIOIF_I2S (0x3)
/* aicr adc */
#define SCODA_AICR_ADC_ADWL_SHIFT (6)
#define SCODA_AICR_ADC_ADWL_MASK (0x3 << SCODA_AICR_ADC_ADWL_SHIFT)
#define SCODA_AICR_ADC_SB_SHIFT (4)
#define SCODA_AICR_ADC_SB_MASK (0x1 << SCODA_AICR_ADC_SB_SHIFT)
#define SCODA_AICR_ADC_AUDIOIF_SHIFT (0)
#define SCODA_AICR_ADC_AUDIO_MASK (0x3 << SCODA_AICR_ADC_AUDIOIF_SHIFT)
#define SCODA_AICR_ADC_AUDIOIF_I2S (0x3)
/* cr vic */
#define SCODA_CR_VIC_SB_SHIFT (0)
#define SCODA_CR_VIC_SB_MASK (1 << SCODA_CR_VIC_SB_SHIFT)
#define SCODA_CR_VIC_SB_SLEEP_SHIFT (1)
#define SCODA_CR_VIC_SB_SLEEP_MASK (1 << SCODA_CR_VIC_SB_SLEEP_SHIFT)
/* fcr adc/dac */
#define SCODA_FCR_FREQ_SHIFT (0)
#define SCODA_FCR_FREQ_MASK (0xf << SCODA_FCR_FREQ_SHIFT)
/* cr dac */
#define SCODA_CR_DAC_SMUTE_SHIFT (7)
#define SCODA_CR_DAC_SMUTE_MASK (0x1 << SCODA_CR_DAC_SMUTE_SHIFT)
#define SCODA_CR_DAC_SB_SHIFT (4)
#define SCODA_CR_DAC_SB_MASK (0x1 << SCODA_CR_DAC_SB_SHIFT)
#define SCODA_CR_DAC_ZERO_SHIFT (0)
#define SCODA_CR_DAC_ZERO_MASK (0x1 << SCODA_CR_DAC_ZERO_SHIFT)
/* cr dac */
#define SCODA_CR_ADC_SMUTE_SHIFT (7)
#define SCODA_CR_ADC_SMUTE_MASK (0x1 << SCODA_CR_ADC_SMUTE_SHIFT)
#define SCODA_CR_ADC_MIC_SEL_SHIFT (6)
#define SCODA_CR_ADC_MIC_SEL_MASK (0x1 << SCODA_CR_ADC_MIC_SEL_SHIFT)
#define SCODA_CR_ADC_SB_SHIFT (4)
#define SCODA_CR_ADC_SB_MASK (0x1 << SCODA_CR_ADC_SB_SHIFT)
#define SCODA_CR_ADC_ZERO_SHIFT (0)
#define SCODA_CR_ADC_ZERO_MASK (0x1 << SCODA_CR_ADC_ZERO_SHIFT)
/* ifr */
#define SCODA_IFR_DAC_MUTE_SHIFT (0)
#define SCODA_IFR_DAC_MUTE_MASK (0x1 << SCODA_IFR_DAC_MUTE_SHIFT)
#define SCODA_IFR_ADC_MUTE_SHIFT (2)
#define SCODA_IFR_ADC_MUTE_MASK (0x1 << SCODA_IFR_ADC_MUTE_SHIFT)
#define SCODA_IFR_ADAS_LOCK_SHIFT (7)
#define SCODA_IFR_ADAS_LOCK_MASK (0x1 << SCODA_IFR_ADAS_LOCK_SHIFT)
/* cr ck */
#define SCODA_CR_CK_MCLK_DIV_SHIFT (6)
#define SCODA_CR_CK_MCLK_DIV_MASK (0x1 << SCODA_CR_CK_MCLK_DIV_SHIFT)
#define SCODA_CR_CK_SDCLK_SHIFT (4)
#define SCODA_CR_CK_SDCLK_MASK (0x1 << SCODA_CR_CK_SDCLK_SHIFT)
#define SCODA_CR_CRYSTAL_SHIFT (0)
#define SCODA_CR_CRYSTAL_MASK (0xf << SCODA_CR_CRYSTAL_SHIFT)
/* icr */
#define SCODA_ICR_INT_FORM_SHIFT (6)
#define SCODA_ICR_INT_FORM_MASK (0x3 << SCODA_ICR_INT_FORM_SHIFT)
#define SCODA_ICR_INT_FORM_HIGH (0)
#define SCODA_ICR_INT_FORM_LOW (1)
/* imr */
#define SCODA_IMR_COMMON_MASK (0xff)
#define SCODA_IMR2_COMMON_MASK (0xff)
/*For Codec*/
#define RGADW (0x4)
#define RGDATA (0x8)
static inline void icodec_mapped_reg_set(uint32_t xreg, int xmask, int xval)
{
int val = readl(xreg);
val &= ~(xmask);
val |= xval;
writel(val, xreg);
}
static inline int icodec_mapped_test_bits(uint32_t xreg, int xmask, int xval)
{
int val = readl(xreg);
val &= xmask;
return (val == xval);
}
/*
* RGADW
*/
#define SCODA_RGDIN_BIT (0)
#define SCODA_RGDIN_MASK (0xff << SCODA_RGDIN_BIT)
#define SCODA_RGADDR_BIT (8)
#define SCODA_RGADDR_MASK (0x7f << SCODA_RGADDR_BIT)
#define SCODA_RGWR_BIT (16)
#define SCODA_RGWR_MASK (0x1 << SCODA_RGWR_BIT)
#define icodec_test_rw_inval(icodec) \
icodec_mapped_test_bits((icodec->mapped_base + RGADW), SCODA_RGWR_MASK, (1 << SCODA_RGWR_BIT))
/*
* RGDATA
*/
#define SCODA_RGDOUT_BIT (0)
#define SCODA_RGDOUT_MASK (0xff << SCODA_RGDOUT_BIT)
#define SCODA_IRQ_BIT (8)
#define SCODA_IRQ_MASK (0x1 << SCODA_IRQ_BIT)
#define icodec_test_irq(icodec) \
icodec_mapped_test_bits((icodec->mapped_base + RGDATA), SCODA_IRQ_MASK, (1 << SCODA_IRQ_BIT))
static inline uint8_t icodec_hw_read_normal(struct jz_icodec *icodec, int reg)
{
uint32_t mapped_base = icodec->mapped_base;
int reval;
int timeout = 0xfffff;
uint32_t flags;
while (icodec_test_rw_inval(icodec))
{
timeout--;
if (!timeout)
{
// rt_kprintf("icodec test_rw_inval timeout\n");
break;
}
}
icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK,(0 << SCODA_RGWR_BIT));
icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGADDR_MASK,(reg << SCODA_RGADDR_BIT));
reval = readl((mapped_base + RGDATA));
reval = readl((mapped_base + RGDATA));
reval = readl((mapped_base + RGDATA));
reval = readl((mapped_base + RGDATA));
reval = readl((mapped_base + RGDATA));
reval = ((reval & SCODA_RGDOUT_MASK) >> SCODA_RGDOUT_BIT);
// rt_kprintf("reg %x = %x\n", reg, reval);
return (uint8_t) reval;
}
static inline int icodec_hw_write_normal(struct jz_icodec *icodec, int reg, int data)
{
uint32_t mapped_base = icodec->mapped_base;
int ret = 0;
int timeout = 0xfffff;
uint32_t flags;
while (icodec_test_rw_inval(icodec))
{
timeout--;
if (!timeout)
{
// rt_kprintf("icodec test_rw_inval timeout\n");
break;
}
}
icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGDIN_MASK | SCODA_RGADDR_MASK,
(data << SCODA_RGDIN_BIT) | (reg << SCODA_RGADDR_BIT));
icodec_mapped_reg_set((mapped_base + RGADW), SCODA_RGWR_MASK ,
1 << SCODA_RGWR_BIT);
if (reg != SCODA_REG_IFR && reg != SCODA_REG_IFR2)
{
ret = icodec_hw_read_normal(icodec, reg);
if (data != ret)
{
// rt_kprintf("icdc write reg %x err exp %x now is %x\n", reg, data, ret);
ret = -1;
}
}
return ret;
}
static int icodec_hw_write_extend(struct jz_icodec *icodec, uint8_t sreg, uint8_t sdata)
{
int creg, cdata, dreg;
switch (sreg) {
case SCODA_MIX_0 ... SCODA_MIX_4:
creg = SCODA_REG_CR_MIX;
dreg = SCODA_REG_DR_MIX;
sreg -= (SCODA_REG_SR_TR_SRCDAC + 1);
break;
case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3:
creg = SCODA_REG_CR_DAC_AGC;
dreg = SCODA_REG_DR_DAC_AGC;
sreg -= (SCODA_MIX_4 +1);
break;
case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3:
creg = SCODA_REG_CR_DAC2;
dreg = SCODA_REG_DR_DAC2_AGC;
sreg -= (SCODA_DAC_AGC3 + 1);
break;
case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4:
creg = SCODA_REG_CR_ADC_AGC;
dreg = SCODA_REG_DR_ADC_AGC;
sreg -= (SCODA_ADC_AGC4 + 1);
break;
default:
return 0;
}
// rt_kprintf("write extend : sreg: %d [0 - 4], creg: %x sdata: %d\n", sreg, creg, sdata);
cdata = (icodec_hw_read_normal(icodec,creg)&(~0x3f))|((sreg&0x3f)|0x40);
icodec_hw_write_normal(icodec, creg, cdata);
icodec_hw_write_normal(icodec, dreg, sdata);
if(sdata!=icodec_hw_read_normal(icodec,dreg))
return -1;
return 0;
}
static uint8_t icodec_hw_read_extend(struct jz_icodec *icodec, uint8_t sreg)
{
int creg, cdata, dreg, ddata;
switch (sreg)
{
case SCODA_MIX_0 ... SCODA_MIX_4:
creg = SCODA_REG_CR_MIX;
dreg = SCODA_REG_DR_MIX;
sreg -= (SCODA_REG_SR_TR_SRCDAC + 1);
break;
case SCODA_DAC_AGC0 ... SCODA_DAC_AGC3:
creg = SCODA_REG_CR_DAC_AGC;
dreg = SCODA_REG_DR_DAC_AGC;
sreg -= (SCODA_MIX_4 +1);
break;
case SCODA_DAC2_AGC0 ... SCODA_DAC2_AGC3:
creg = SCODA_REG_CR_DAC2;
dreg = SCODA_REG_DR_DAC2_AGC;
sreg -= (SCODA_DAC_AGC3 + 1);
break;
case SCODA_ADC_AGC0 ... SCODA_ADC_AGC4:
creg = SCODA_REG_CR_ADC_AGC;
dreg = SCODA_REG_DR_ADC_AGC;
sreg -= (SCODA_ADC_AGC4 + 1);
break;
default:
return 0;
}
cdata = (icodec_hw_read_normal(icodec, creg) & (~0x7f)) | (sreg & 0x3f);
icodec_hw_write_normal(icodec, creg, cdata);
ddata = icodec_hw_read_normal(icodec, dreg);
return (uint8_t) ddata;
}
static inline uint8_t icodec_hw_read(struct jz_icodec *icodec, int reg)
{
if (reg > SCODA_REG_SR_TR_SRCDAC)
return icodec_hw_read_extend(icodec, reg);
else
return icodec_hw_read_normal(icodec, reg);
}
static inline int icodec_hw_write(struct jz_icodec *icodec, int reg, int data)
{
if (reg > SCODA_REG_SR_TR_SRCDAC)
return icodec_hw_write_extend(icodec, reg, data);
else
return icodec_hw_write_normal(icodec, reg, data);
}
#endif /* _DRV_CODEC_ICODEC_H_ */