/* ** ============================================================================= ** Copyright (c) 2016 Texas Instruments Inc. ** ** This program is free software; you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free Software ** Foundation; version 2. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License along with ** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin ** Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** File: ** tas2563.c ** ** Description: ** functions for configurating TAS2563 Android device ** ** ============================================================================= */ #include "tas2563.h" #include "system.h" #include #include #include #include #include #include #include #include #include #define TILOAD_NODE "/dev/tiload_node" static int gTILoad = 0; static int gBinFile = 0; #define MAX_BIN_SIZE 2048 static char gpBin[MAX_BIN_SIZE]; static unsigned int gnBinIndex = 0; static unsigned int gnBinBlockIndex = 0; static char gpDevABlock[MAX_BIN_SIZE/2]; static unsigned int gnDevABlockIndex = 0; static unsigned char gnDevA; static unsigned char gnDev; static void tas2563_check_node(void); void tas2563_mixer_command(char *pCommand, int nData) { char *pMixer[] = {AUDIO_MIXER, pCommand, "0", NULL}; char *pEnv[] = {NULL}; char pData[16]; printf("TAS2563 mixer command %s = %d.\n\r", pCommand, nData); sprintf(pData, "%d", nData); pMixer[2] = pData; if (0 == (fork())) { if (execve(AUDIO_MIXER, pMixer, pEnv) == -1) { printf("factorytest: Can't find mixer. Please install %s. \n\r", AUDIO_MIXER); exit(-1); } } sys_delay(500); } void tas2563_load_calibration(int nCalibration) { tas2563_check_node(); ioctl(gTILoad, TILOAD_IOCTL_SET_CALIBRATION, &nCalibration); sys_delay(500); } static void tas2563_check_node(void) { if (gTILoad) return; gTILoad = open(TILOAD_NODE, O_RDWR); if (gTILoad < 0) { printf("factorytest: Can't find tiload. Please create %s. \n\r", TILOAD_NODE); exit(-1); } printf("factorytest: %s handle = %d\n\r", TILOAD_NODE, gTILoad); } uint8_t tas2563_get_PGID(void) { unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, 0x00}; unsigned char pPage[] = {0x00, 0x00}; unsigned char pData[] = {0x03, 0x00, 0x00, 0x00, 0x00}; tas2563_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); read(gTILoad, pData, 1); return pData[0]; } uint32_t tas2563_coeff_read(uint32_t reg) { uint8_t nbook = TAS2563_BOOK_ID(reg); uint8_t npage = TAS2563_PAGE_ID(reg); uint8_t nreg = TAS2563_PAGE_REG(reg); unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, nbook}; unsigned char pPage[] = {0x00, npage}; unsigned char pData[] = {nreg, 0x00, 0x00, 0x00, 0x00}; tas2563_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); read(gTILoad, pData, 4); printf("nbook=%u, npage=%u, nreg=%u, pData[1]=0x%x, pData[2]=0x%x, pData[3]=0x%x, pData[4]=0x%x\n\r", nbook, npage, nreg, pData[1], pData[2], pData[3], pData[4]); return ((pData[0] << 24) | (pData[1] << 16) | (pData[2] << 8) | (pData[3])); } #define TAS2563_mCDSP_SWAP_REG TAS2563_REG(0x8c, 0x19, 0x7c) #define TAS2563_uCDSP_SWAP_REG TAS2563_REG(0x00, 0x35, 0x2c) void tas2563_coeff_write(uint32_t reg, uint32_t data) { unsigned int nByte; uint8_t nbook, npage, nreg; nbook = TAS2563_BOOK_ID(reg); npage = TAS2563_PAGE_ID(reg); nreg = TAS2563_PAGE_REG(reg); // if the bin file is open, write the coefficients to the bin file if (gBinFile) { /* if the bin file is open, write the coefficients to the bin file */ unsigned int index = gnDevABlockIndex*4; gpDevABlock[index] = 0; gpDevABlock[index + 1] = 4; gpDevABlock[index + 2] = 0x85; gpDevABlock[index + 4] = nbook; gpDevABlock[index + 5] = npage; gpDevABlock[index + 6] = nreg; for (nByte = 0; nByte < 4; nByte++) gpDevABlock[index + 7 + nByte] = (data >> ((3 - nByte) * 8)) & 0xFF; gnDevABlockIndex += 3; } else { unsigned char pPageZero[] = {0x00, 0x00}; unsigned char pBook[] = {0x7F, nbook}; unsigned char pPage[] = {0x00, npage}; unsigned char pData[] = {nreg, (data & 0xFF000000) >> 24, (data & 0x00FF0000) >> 16, (data & 0x0000FF00) >> 8, data & 0x000000FF}; tas2563_check_node(); write(gTILoad, pPageZero, 2); write(gTILoad, pBook, 2); write(gTILoad, pPage, 2); write(gTILoad, pData, 5); } } void tas2563_save_cal(struct TFTCConfiguration *pFTCC, double dev_a_re, uint32_t dev_a_rms_pow, uint32_t dev_a_t_limit, double t_cal, uint32_t nResult, char * pFileName) { printf("TAS2563 calibration values:\n\r"); printf(" DevA Re = %1.2f Ohm\n\r", dev_a_re); printf(" DevA rms_pow = 0x%08X\n\r", dev_a_rms_pow); printf(" DevA t_limit = 0x%08X\n\r", dev_a_t_limit); if((nResult & RE1_CHK_MSK) == RESULT_PASS) printf(" SPK A calibration success! \n\r"); else { if(nResult & RE1_FAIL_HI) printf(" SPK A Calibration fail : Re is too high (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReHi); else printf(" SPK A Calibration fail : Re is too low (limit: %1.2f).\n\r", pFTCC->nTSpkCharDevA.nReLo); } FILE *pFile = fopen(pFileName, "w+"); fprintf(pFile, "DevA Re = %1.2f\n\r", dev_a_re); fprintf(pFile, "DevA rms_pow = 0x%08X\n\r", dev_a_rms_pow); fprintf(pFile, "DevA t_limit = 0x%08X\n\r", dev_a_t_limit); fprintf(pFile, "Ambient temperature = %2.2f\n\r\n\r", t_cal); fprintf(pFile, "Result = 0x%x\n\r\n\r", nResult); fclose(pFile); } #define DDC_DESCRIPTION "Calibration Data File for TAS2563 Mono" #define CALIBRATION_DESCRIPTION "Calibration snapshot for TAS2563 Mono" #define DATA_DESCRIPTION "data blocks for TAS2563 Mono FTC" void tas2563_open_bin(char * pFileName) { time_t timestamp; umask(002); gBinFile = open(pFileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); gnBinIndex = 0; memset(gpBin, 0, MAX_BIN_SIZE); memset(gpDevABlock, 0, MAX_BIN_SIZE/2); gnDevABlockIndex = 0; //magic number gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '5'; gpBin[gnBinIndex++] = '2'; gnBinIndex += 4; /* bypass size int */ gnBinIndex += 4; /* bypass checksum int */ gnBinIndex += 4; /* bypass PPC3 version int */ gnBinIndex += 4; /* bypass DSP version int */ gpBin[gnBinIndex++] = 0; gpBin[gnBinIndex++] = 0; gpBin[gnBinIndex++] = 1; gpBin[gnBinIndex++] = 0; /* driver version 0x00000100 */ time(×tamp); gpBin[gnBinIndex++] = (unsigned char)((timestamp&0xff000000)>>24); gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x00ff0000)>>16);; gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x0000ff00)>>8);; gpBin[gnBinIndex++] = (unsigned char)((timestamp&0x000000ff));; strcpy(&gpBin[gnBinIndex], "Calibration Data File"); /* DDC name */ gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], DDC_DESCRIPTION); gnBinIndex += strlen(DDC_DESCRIPTION) + 1; gnBinIndex += 4; /* device family index */ gpBin[gnBinIndex++] = 0; /* device index */ gpBin[gnBinIndex++] = 0; /* device index */ gpBin[gnBinIndex++] = 0; /* device index */ gpBin[gnBinIndex++] = 5; /* device index, TAS2563 Mono */ gnBinIndex += 2 + /* num programs index */ 0 + /* array programs index */ 2 + /* num configurations index */ 0; /* array configurations index */ gpBin[gnBinIndex++] = 0x00; gpBin[gnBinIndex++] = 0x01; /* one calibration data block */ strcpy(&gpBin[gnBinIndex], "Calibration snapshot"); gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], CALIBRATION_DESCRIPTION); gnBinIndex += strlen(CALIBRATION_DESCRIPTION) + 1; gpBin[gnBinIndex++] = 0x00; /* compatible program = smart amp (index 0) */ gpBin[gnBinIndex++] = 0x00; /* compatible configuration */ strcpy(&gpBin[gnBinIndex], "Calibration Data"); gnBinIndex += 64; strcpy(&gpBin[gnBinIndex], DATA_DESCRIPTION); gnBinIndex += strlen(DATA_DESCRIPTION) + 1; gpBin[gnBinIndex++] = 0x00; gpBin[gnBinIndex++] = 1; /* one blocks */ gpDevABlock[0] = 0; gpDevABlock[1] = 0; gpDevABlock[2] = 0; gpDevABlock[3] = 0x03; /* COEFF_DEVICE_A 鈥?0x03 */ gnDevABlockIndex = 2; } void tas2563_close_bin(void) { unsigned int nCommands; unsigned char pCommit[] = { 0x00, 0x04, 0x85, 0x00, TAS2563_BOOK_ID(TAS2563_mCDSP_SWAP_REG), TAS2563_PAGE_ID(TAS2563_mCDSP_SWAP_REG), TAS2563_PAGE_REG(TAS2563_mCDSP_SWAP_REG), 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x85, 0x00, TAS2563_BOOK_ID(TAS2563_uCDSP_SWAP_REG), TAS2563_PAGE_ID(TAS2563_uCDSP_SWAP_REG), TAS2563_PAGE_REG(TAS2563_uCDSP_SWAP_REG), 0x00, 0x00, 0x00, 0x01, 0x00 }; /* write the commit sequence */ memcpy(&gpDevABlock[gnDevABlockIndex*4], pCommit, 24); gnDevABlockIndex += 6; /* write number of commands for calibration block */ gpDevABlock[4] = ((gnDevABlockIndex-2) & 0xFF000000) >> 24; gpDevABlock[5] = ((gnDevABlockIndex-2) & 0x00FF0000) >> 16; gpDevABlock[6] = ((gnDevABlockIndex-2) & 0x0000FF00) >> 8; gpDevABlock[7] = ((gnDevABlockIndex-2) & 0x000000FF); memcpy(&gpBin[gnBinIndex], gpDevABlock, gnDevABlockIndex*4); gnBinIndex += (gnDevABlockIndex*4); /* write bin file size */ gpBin[4] = (gnBinIndex & 0xFF000000) >> 24; gpBin[5] = (gnBinIndex & 0x00FF0000) >> 16; gpBin[6] = (gnBinIndex & 0x0000FF00) >> 8; gpBin[7] = (gnBinIndex & 0x000000FF); write(gBinFile, gpBin, gnBinIndex); close(gBinFile); gBinFile = 0; } // ----------------------------------------------------------------------------- // check_spk_bounds // ----------------------------------------------------------------------------- // Description: // Checks if speaker paramters are within bounds. // ----------------------------------------------------------------------------- uint32_t check_spk_bounds(struct TFTCConfiguration *pFTCC, double re1) { uint32_t result = RESULT_PASS; if(re1>pFTCC->nTSpkCharDevA.nReHi) result |= RE1_FAIL_HI; if(re1nTSpkCharDevA.nReLo) result |= RE1_FAIL_LO; return result; } void tas2563_ftc_release(void) { if (gTILoad > 0) { close(gTILoad); gTILoad = 0; } }