pinebuds/platform/drivers/codec/codec_tlv32aic32.c

221 lines
5.9 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "codec_tlv32aic32.h"
#include "hal_i2c.h"
#include "hal_i2s.h"
#include "hal_trace.h"
#include "hal_uart.h"
#include "plat_types.h"
#include "string.h"
#define TLV32AIC32_INST HAL_I2S_ID_0
static struct HAL_I2C_CONFIG_T _codec_i2c_cfg;
static uint8_t sample_rate_div[] = {
10, /* index is 0 */
15, 20, 25, 30, 35, 40, 45, 50, 55, 60,
};
/* i2c write */
static int codec_write(uint8_t reg_addr, uint8_t value) {
uint8_t buf[2];
buf[0] = reg_addr;
buf[1] = value;
return hal_i2c_task_send(HAL_I2C_ID_0, TLV32AIC32_I2C_ADDRESS, buf, 1 + 1, 0,
0);
}
/* i2c read */
#if 0
static uint8_t codec_read(uint8_t reg_addr)
{
uint8_t buf[2];
buf[0] = reg_addr;
buf[1] = 0;
hal_i2c_task_recv(HAL_I2C_ID_0, TLV32AIC32_I2C_ADDRESS, &buf[0], 1, &buf[1], 1, 0, 0);
return buf[1];
}
#endif
uint32_t tlv32aic32_open(void) {
_codec_i2c_cfg.mode = HAL_I2C_API_MODE_TASK;
_codec_i2c_cfg.use_dma = 0;
_codec_i2c_cfg.use_sync = 1;
_codec_i2c_cfg.speed = 20000;
_codec_i2c_cfg.as_master = 1;
hal_i2c_open(HAL_I2C_ID_0, &_codec_i2c_cfg);
return 0;
}
uint32_t tlv32aic32_stream_open(enum AUD_STREAM_T stream) {
hal_i2s_open(TLV32AIC32_INST, stream, HAL_I2S_MODE_MASTER);
return 0;
}
uint32_t tlv32aic32_stream_setup(enum AUD_STREAM_T stream,
struct tlv32aic32_config_t *cfg) {
uint32_t param = 0, i = 0;
/* select page : 0*/
codec_write(AIC3X_PAGE_SELECT, PAGE0_SELECT);
/* soft reset : 1 */
codec_write(AIC3X_RESET, SOFT_RESET);
/* CLKDIV_IN uses mCLK : 102 , PLLDIV_IN use mCLK */
codec_write(AIC3X_CLKGEN_CTRL_REG, 0x02);
/* CODEC_CLK_IN uses CLKDIV : 101, CODEC_CLK_IN use CLKDIV_IN */
codec_write(101, 0x00);
/* PLL R value : 11, R is 1 */
codec_write(AIC3X_OVRF_STATUS_AND_PLLR_REG, 0x1);
/* PLL J value : 4, J is 8 */
codec_write(AIC3X_PLL_PROGB_REG, 0x8);
/* PLL D value : 5,6, D is 1920 */
codec_write(AIC3X_PLL_PROGC_REG, 0x780 >> 6);
codec_write(AIC3X_PLL_PROGD_REG, (0x780 & 0x3f) << 2);
/* PLL disable and select Q value : 3, enable pll, Q is 2 */
codec_write(AIC3X_PLL_PROGA_REG, 0x81);
/* left and right DAC open : 7, open codec dac path and fref */
if ((cfg->sample_rate % 8000) == 0) {
/* 48000 */
codec_write(AIC3X_CODEC_DATAPATH_REG, 0x0a);
param = 480000 / cfg->sample_rate;
} else {
/* 44100 */
codec_write(AIC3X_CODEC_DATAPATH_REG, 0x8a);
param = 441000 / cfg->sample_rate;
}
for (i = 0; i < sizeof(sample_rate_div); ++i) {
if (param == sample_rate_div[i])
break;
}
if (i == sizeof(sample_rate_div)) {
i = 0;
}
/* sample_rate divider : 2, default is /1 */
codec_write(AIC3X_SAMPLE_RATE_SEL_REG, i << 4 | i << 4);
/* ctrl mode : 8, bitclock input, word clock input */
codec_write(AIC3X_ASD_INTF_CTRLA, 0x20);
/* Audio Serial Data Interface Control : 9, 16bit i2s mode */
if (cfg->bits == AUD_BITS_16)
param = 0;
else if (cfg->bits == AUD_BITS_20)
param = 1;
else if (cfg->bits == AUD_BITS_24)
param = 2;
else if (cfg->bits == AUD_BITS_32)
param = 3;
else
param = 0;
codec_write(AIC3X_ASD_INTF_CTRLB, 0x00 | param << 4);
/* out ac-coupled : 14, headset control */
codec_write(AIC3X_HEADSET_DETECT_CTRL_B, 0x08);
/* left and right DAC power on : 37 */
// codec_write(DAC_PWR, 0xC0);
codec_write(DAC_PWR, 0xD0);
/* out common-mode voltage : 40 */
codec_write(HPOUT_SC, 0x00);
/* out path select : 41 */
codec_write(DAC_LINE_MUX, 0xA1);
/* left DAC not muted : 43 */
codec_write(LDAC_VOL, 0x0f);
/* right DAC not muted : 44 */
codec_write(RDAC_VOL, 0x0f);
/* HPLOUT is not muted : 51 */
codec_write(HPLOUT_CTRL, 0x9F);
/* HPROUT is not muted : 65 */
codec_write(HPROUT_CTRL, 0x9F);
/* out short circuit protection : 38 */
// codec_write(HPRCOM_CFG, 0x3A);
codec_write(HPRCOM_CFG, 0x22);
/* input */
/* mic bias : 25 */
codec_write(MICBIAS_CTRL, 0x40);
/* left adc power : 19 */
codec_write(LINE1L_2_LADC_CTRL, 0x04);
/* right adc power : 22 */
codec_write(LINE1R_2_RADC_CTRL, 0x04);
/* left adc pga mute : 15 */
codec_write(LADC_VOL, 0x0);
/* right adc pga mute : 16 */
codec_write(RADC_VOL, 0x0);
/* adc flag : 36 */
// TRACE(1,"tlv adc flag 0x%x", codec_read(ADC_FLAG));
/* left adc pga mute : 15 */
// TRACE(1,"tlv left adc pga 0x%x", codec_read(LADC_VOL));
/* right adc pga mute : 16 */
// TRACE(1,"tlv right adc pga 0x%x", codec_read(RADC_VOL));
/* input end */
struct HAL_I2S_CONFIG_T i2s_cfg;
memset(&i2s_cfg, 0, sizeof(i2s_cfg));
i2s_cfg.use_dma = cfg->use_dma;
i2s_cfg.chan_sep_buf = cfg->chan_sep_buf;
i2s_cfg.sync_start = cfg->sync_start;
i2s_cfg.cycles = cfg->slot_cycles;
i2s_cfg.bits = cfg->bits;
i2s_cfg.channel_num = cfg->channel_num;
i2s_cfg.channel_map = cfg->channel_map;
i2s_cfg.sample_rate = cfg->sample_rate;
hal_i2s_setup_stream(TLV32AIC32_INST, stream, &i2s_cfg);
return 0;
}
uint32_t tlv32aic32_stream_start(enum AUD_STREAM_T stream) {
hal_i2s_start_stream(TLV32AIC32_INST, stream);
return 0;
}
uint32_t tlv32aic32_stream_stop(enum AUD_STREAM_T stream) {
hal_i2s_stop_stream(TLV32AIC32_INST, stream);
return 0;
}
uint32_t tlv32aic32_stream_close(enum AUD_STREAM_T stream) {
hal_i2s_close(TLV32AIC32_INST, stream);
return 0;
}
uint32_t tlv32aic32_close(void) { return 0; }