sdk-ameba-v4.0c_180328/component/common/drivers/i2s/alc5680.c

447 lines
12 KiB
C
Raw Permalink Normal View History

2019-04-02 08:34:25 +00:00
#include "PinNames.h"
#include "basic_types.h"
#include <osdep_api.h>
#include "i2c_api.h"
#include "i2c_ex_api.h"
#include "pinmap.h"
#include "wait_api.h"
#include "alc5680.h"
#define I2C_ALC5680_ADDR (0X5A/2)
#if defined(CONFIG_PLATFORM_8195A)
#define I2C_MTR_SDA PB_3
#define I2C_MTR_SCL PB_2
#elif defined(CONFIG_PLATFORM_8711B)
#define I2C_MTR_SDA PA_30
#define I2C_MTR_SCL PA_29
#endif
#define I2C_BUS_CLK 100000 //100K HZ
//i2c_t alc5680_i2c;
#if defined (__ICCARM__)
i2c_t alc5680_i2c;
#else
volatile i2c_t alc5680_i2c;
#define printf DBG_8195A
#endif
#define HELLO_BLUE_GENIE 0X03
#define ALEXA 0X04
#define SESAMEE 0X05
#define BAIDU 0X76
#define OLD_VERSION 0
#define NEW_VERSION 1
#define ALC_FW_START_ADDR 0X70000000
#if OLD_VERSION
#define header_offset 32 //[addr1][len1][addr2]][len2][addr3]][len3][size][checksum]
typedef struct _alc5680_fw{
unsigned int alc_addr[3];
unsigned int alc_len[3];
unsigned int size;
unsigned int checksum;
unsigned int alc_addr_offset;
unsigned int alc_len_offset;
unsigned int alc_len_index;
}alc5680_fw;
#endif
#if NEW_VERSION
#define header_offset 12 //[size][checksum][version]
typedef struct _alc5680_fw{
unsigned int version;
unsigned int size;
unsigned int checksum;
unsigned int alc_addr_offset;
unsigned int alc_len_offset;
}alc5680_fw;
#endif
static alc5680_fw alc5680_info;
static void alc5680_delay(void)
{
int i;
i=10000;
while (i) {
i--;
asm volatile ("nop\n\t");
}
}
u8 alc5680_reg_write_16(u16 reg, u16 val)
{
int length = 0;
char buf[4];
buf[0] = (char)(reg >> 8);
buf[1] = (char)(reg&0xff);
buf[2] = (char)(val>>8);
buf[3] = (char)(val&0xff);
length = i2c_write(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 4, 1);
//alc5680_delay();
return (length==4)?0:1;
}
u8 alc5680_reg_write_32(u32 reg, u32 val)
{
int tmp;
char *buf = (char*)&tmp;
u16 val1;
u8 ret = 0;
ret = alc5680_reg_write_16(0x0001,reg&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0002,reg>>16);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0003,val&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0004,val>>16);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0000,0x0003);
if(ret != 0)
printf("error\r\n");
return 0;
}//0x1800C02C
u8 alc5680_reg_write_16b(u32 reg, u16 val)
{
int tmp;
char *buf = (char*)&tmp;
u16 val1;
u8 ret = 0;
ret = alc5680_reg_write_16(0x0001,reg&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0002,reg>>16);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0003,val&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0000,0x0001);
if(ret != 0)
printf("error\r\n");
return 0;
}
u8 alc5680_reg_read_32(u32 reg, u32* val)
{
unsigned int tmp;
char *buf = (char*)&tmp;
u16 val1;
u8 ret = 0;
ret = alc5680_reg_write_16(0x0001,reg&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0002,reg>>16);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0000,0x0002);
if(ret != 0)
printf("error\r\n");
buf[0] = 0x0003>>8;
buf[1] = 0x0003&0xff;
if(i2c_write(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) != 2){
DBG_8195A("alc5680_reg_read(): write register addr fail\n");
ret = 1;
}
//alc5680_delay();
buf[0] = 0xaa;
buf[1] = 0xaa;
if(i2c_read(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) < 2){
printf("alc5680_reg_read(): read register value fail\n");
ret = 1;
}else
*val = ((buf[1]&0xFF)<<24)|((buf[0]&0xFF)<<16);
buf[0] = 0x0004>>8;
buf[1] = 0x0004&0xff;
if(i2c_write(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) != 2){
DBG_8195A("alc5680_reg_read(): write register addr fail\n");
ret = 1;
}
if(i2c_read(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) < 2){
printf("alc5680_reg_read(): read register value fail\n");
ret = 1;
}else
*val |= ((buf[1]&0xFF)<<8)|(buf[0]&0xFF);
//alc5680_delay();
return ret;
}
u8 alc5680_reg_read_16(u32 reg, u16* val)
{
int tmp;
char *buf = (char*)&tmp;
u16 val1;
u8 ret = 0;
ret = alc5680_reg_write_16(0x0001,reg&0xffff);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0002,reg>>16);
if(ret != 0)
printf("error\r\n");
ret = alc5680_reg_write_16(0x0000,0x0002);
if(ret != 0)
printf("error\r\n");
buf[0] = 0x0003>>8;
buf[1] = 0x0003&0xff;
if(i2c_write(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) != 2){
DBG_8195A("alc5680_reg_read(): write register addr fail\n");
ret = 1;
}
//alc5680_delay();
buf[0] = 0xaa;
buf[1] = 0xaa;
if(i2c_read(&alc5680_i2c, I2C_ALC5680_ADDR, &buf[0], 2, 1) < 2){
printf("alc5680_reg_read(): read register value fail\n");
ret = 1;
}else
*val = ((buf[0]&0xFF)<<8)|(buf[1]&0xFF);
//alc5680_delay();
return ret;
}
void alc5680_i2c_init(void)
{
i2c_init(&alc5680_i2c, I2C_MTR_SDA, I2C_MTR_SCL);
i2c_frequency(&alc5680_i2c, I2C_BUS_CLK);
memset(&alc5680_info,0,sizeof(alc5680_fw));
}
void alc5680_erase()
{
unsigned short value = 0;
alc5680_reg_write_32(0x18009508,0x00000001);//erase command
while(1){
vTaskDelay(1000);
alc5680_reg_read_16(0x18009508,&value);
if((value&0x01)==0x00){
printf("Erase finish %d\r\n",value);
break;
}else{
printf("Erase ..... %x\r\n",value);
}
vTaskDelay(1000);
}
}
void alc5680_write_data_to_flash(const unsigned char *data_value,unsigned int len,unsigned int addr)
{
int i = 0;
unsigned int value = 0;
const unsigned char *ptr = data_value;
for(int i =0; i < len/4;i++){
value = (ptr[0])|(ptr[1]<<8)|(ptr[2]<<16)|(ptr[3]<<24);
alc5680_reg_write_32(addr+i*4,value);
ptr+=4;
}
}
int alc5680_get_version()
{
unsigned int value = 0;
alc5680_reg_read_32(0x7000A004,&value);
value = value>>24;
if(value == HELLO_BLUE_GENIE )
printf("VERSION:HELLO_BLUE_GENIE\r\n");
else if(value == ALEXA)
printf("VERSION:ALEXA\r\n");
else if(value == SESAMEE)
printf("VERSION:Zhima kaimen\r\n");
else if(value == BAIDU)
printf("VERSION:Xiao du xiao du\r\n");
else
printf("NON-DEFINE VERSION ADDR=0X7000A004 %x\r\n",value);
return value;
}
void set_alc5680_volume(unsigned char left,unsigned char right)
{
alc5680_reg_write_16b(0x1800C02C, left<<8|right);
}
void get_alc5680_volume(unsigned short *value)
{
alc5680_reg_read_16(0x1800C02C, value);
}
void alc5680_status()
{
unsigned int value = 0;
alc5680_reg_read_16(0x1800c1fe,&value);
printf("codec id = %x\r\n",value);
alc5680_reg_read_16(0x1800C0CA,&value);
printf("status state = %x\r\n",value);
alc5680_get_version();
}
/////////////////////////////////////////////////////
#if OLD_VERSION
void alc5680_get_info(unsigned char *buffer)
{
alc5680_info.size = buffer[0]<<24|buffer[1]<<16|buffer[2]<<8|buffer[3];
alc5680_info.checksum = buffer[4]<<24|buffer[5]<<16|buffer[6]<<8|buffer[7];
alc5680_info.version = buffer[8]<<24|buffer[9]<<16|buffer[10]<<8|buffer[11];
printf("codec size = %x checksum = %x version = %x\r\n",alc5680_info.size,alc5680_info.version);
}
void alc5680_handler_function(unsigned char *buffer,int len,unsigned int index)
{
unsigned char *buf_index = buffer;
unsigned int buf_len = len;
if(index == 1){
alc5680_get_info(buf_index);
buf_index += header_offset;
buf_len = buf_len - header_offset;
alc5680_info.alc_len_offset = 0;
alc5680_info.alc_len_index = 0;
alc5680_info.alc_addr_offset = ALC_FW_START_ADDR;
}
alc5680_write_data_to_flash(buf_index,buf_len,alc5680_info.alc_addr_offset);
alc5680_info.alc_addr_offset += buf_len;
alc5680_info.alc_len_offset += buf_len;
if(len != 512){
printf(" alc_addr_offset = %x alc_len_offset = %x \r\n",alc5680_info.alc_addr_offset,alc5680_info.alc_len_offset);
}
}
void alc5680_check_sum()
{
unsigned int alc_checksum = 0;
unsigned int i = 0, j = 0;
unsigned int value = 0;
unsigned int count = 0;
unsigned int percent = alc5680_info.size/100;
unsigned int percent_count = 0;
if(percent%4)
percent=percent+(4-(percent%4));
printf("checksum start\r\n");
for(i=ALC_FW_START_ADDR;i<ALC_FW_START_ADDR+alc5680_info.size;i+=4){
alc5680_reg_read_32(i,&value);
alc_checksum+=((value&0xff)+((value&0xff00)>>8)+((value&0xff0000)>>16)+((value&0xff000000)>>24));
count+=4;
if(count%percent == 0){
printf("%d%%\r", percent_count );
percent_count++;
}
}
if(alc_checksum != alc5680_info.checksum)
printf("Checksum error\r\n");
else
printf("Checksum successful\r\n");
printf("bin_checksum %x alc_checksum = %x count = %d\r\n",alc5680_info.checksum,alc_checksum,count);
}
#endif
#if NEW_VERSION
void alc5680_get_info(unsigned char *buffer)
{
alc5680_info.size = buffer[0]<<24|buffer[1]<<16|buffer[2]<<8|buffer[3];
alc5680_info.checksum = buffer[4]<<24|buffer[5]<<16|buffer[6]<<8|buffer[7];
alc5680_info.version = buffer[8]<<24|buffer[9]<<16|buffer[10]<<8|buffer[11];
printf("codec size = %x checksum = %x version = %x\r\n",alc5680_info.size,alc5680_info.checksum,alc5680_info.version);
}
void alc5680_handler_function(unsigned char *buffer,int len,unsigned int index)
{
unsigned char *buf_index = buffer;
unsigned int buf_len = len;
if(index == 1){
alc5680_get_info(buf_index);
buf_index += header_offset;
buf_len = buf_len - header_offset;
alc5680_info.alc_len_offset = 0;
alc5680_info.alc_addr_offset = ALC_FW_START_ADDR;
}
alc5680_write_data_to_flash(buf_index,buf_len,alc5680_info.alc_addr_offset);
alc5680_info.alc_addr_offset += buf_len;
alc5680_info.alc_len_offset += buf_len;
if(len != 512){
printf(" alc_addr_offset = %x alc_len_offset = %x \r\n",alc5680_info.alc_addr_offset,alc5680_info.alc_len_offset);
}
}
void alc5680_check_sum()
{
unsigned int alc_checksum = 0;
unsigned int i = 0, j = 0;
unsigned int value = 0;
unsigned int count = 0;
unsigned int percent = alc5680_info.size/100;
unsigned int percent_count = 0;
if(percent%4)
percent=percent+(4-(percent%4));
printf("checksum start\r\n");
for(i=ALC_FW_START_ADDR;i<ALC_FW_START_ADDR+alc5680_info.size;i+=4){
alc5680_reg_read_32(i,&value);
alc_checksum+=((value&0xff)+((value&0xff00)>>8)+((value&0xff0000)>>16)+((value&0xff000000)>>24));
count+=4;
if(count%percent == 0){
printf("%d%%\r", percent_count );
percent_count++;
}
}
if(alc_checksum != alc5680_info.checksum)
printf("Checksum error\r\n");
else
printf("Checksum successful\r\n");
printf("bin_checksum %x alc_checksum = %x count = %d\r\n",alc5680_info.checksum,alc_checksum,count);
}
#endif