blob: 965cb366b5919d591befb4dc04daf6c480cae974 [file] [log] [blame]
/*******************************************************************************
Copyright 2010 Broadcom Corporation. All rights reserved.
Unless you and Broadcom execute a separate written software license agreement
governing use of this software, this software is licensed to you under the
terms of the GNU General Public License version 2, available at
http://www.gnu.org/copyleft/gpl.html (the "GPL").
Notwithstanding the above, under no circumstances may you combine this software
in any way with any other Broadcom software provided under a license other than
the GPL, without Broadcom's express prior written consent.
*******************************************************************************/
/**
*
* @file bcm_auddrv_test.c
*
* @brief This file contains SysFS interface for audio driver test cases
*
****************************************************************************/
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <linux/sysfs.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <mach/hardware.h>
#include "mobcom_types.h"
#include "resultcode.h"
#include "audio_consts.h"
#include "chal_types.h"
#include "csl_caph.h"
#include "msconsts.h"
#include "shared.h"
#include "csl_aud_queue.h"
#include "csl_vpu.h"
#include "csl_arm2sp.h"
#include <mach/io_map.h>
#include "linux/gpio.h"
#include "linux/interrupt.h"
#include "mach/chip_pinmux.h"
#include "mach/pinmux.h"
#include "audio_trace.h"
#define IHF_ST_SUPPORTED
#define HEADSET_ST_SUPPORTED
#define DIGIMIC_SUPPORTED
#if defined(IHF_ST_SUPPORTED) | defined(HEADSET_ST_SUPPORTED)
/* BRCM audio */
#include "chal_caph_audioh.h"
/* BRCM PMU */
#include "linux/mfd/bcmpmu.h"
#include "linux/broadcom/bcmpmu_audio.h"
/* RDB access */
#include <mach/rdb/brcm_rdb_sysmap.h>
#include <mach/rdb/brcm_rdb_audioh.h>
#include <mach/rdb/brcm_rdb_khub_clk_mgr_reg.h> /* For DigiMic test */
#include <mach/rdb/brcm_rdb_sclkcal.h> /* For Sleep clock test */
#include <mach/rdb/brcm_rdb_bmdm_clk_mgr_reg.h> /* For Sleep clock test */
#include <chal/chal_util.h>
/* HW Settling time */
#define AUDIO_SETTLING_TIME 15
#define DMIC_SETTLING_TIME 30
#define BB_TEST_DISABLE 0x00
#define BB_TEST_10_KOHM 0x01
#define BB_TEST_500_OHM 0x02
#define BB_TEST_500_OHM_10_KOHM 0x03
/* Helper Macroes */
#define IHF_NUMBER_OF_SUBTESTS1 2
#define IHF_NUMBER_OF_SUBTESTS2 2
#define HA_NUMBER_OF_SUBTESTS 4
#define CHECKBIT_AND_ASSIGN_ERROR(xAssertLevel, xChecks, \
xReadValue, xResultArray, xErrorCode) \
{ \
int i; \
u8 TestValue; \
TestValue = xReadValue; \
for (i = 0 ; i < (xChecks) ; i++) { \
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::" \
"CHECKBIT_AND_ASSIGN_ERROR(%u):" \
" AL:%u, TV=0x%X, BTV=0x%X",\
i, xAssertLevel, TestValue,\
((TestValue) & (1 << i))); \
if (xResultArray[i] == ST_PASS) {\
if ((xAssertLevel == 1)) { \
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::" \
"CHECKBIT_AND_ASSIGN_ERROR:" \
" High Check (%u)", i); \
if (((TestValue) & (1 << i)) != 0) { \
xResultArray[i] = xErrorCode; \
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::" \
"CHECKBIT_AND_ASSIGN_ERROR:" \
" High Assign err = %u", \
xErrorCode); \
} \
} \
else { \
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::" \
"CHECKBIT_AND_ASSIGN_ERROR:" \
" Low Check (%u)", i); \
if (((TestValue) & (1 << i)) == 0) { \
xResultArray[i] = xErrorCode; \
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::" \
"CHECKBIT_AND_ASSIGN_ERROR:" \
" Low Assign err = %u", \
xErrorCode); \
} \
} \
} \
} \
}
#endif
enum Selftest_Results_t {
ST_PASS, /* Test succeded */
ST_FAIL, /* Test Failed */
ST_BUSY,
ST_NOT_TESTED,
/* Audio */
ST_SHORTED_GROUND,
ST_SHORTED_POWER,
ST_BAD_CONNECTION,
ST_BAD_CONNECTION_OR_GROUND,
ST_BAD_CONNECTION_OR_POWER,
ST_SHORTED_GROUND_ACI,
ST_SHORTED_GROUND_BIAS,
ST_SHORTED_POWER_ACI,
ST_SHORTED_POWER_BIAS,
ST_RESULT_CNT
};
static const char * const Selftest_ResultString[] = {
"PASS", /* Test succeded */
"FAIL", /* Test Failed */
"EBUSY",
"NOT_TESTED",
/* Audio */
"SHORTED_GROUND",
"SHORTED_POWER",
"BAD_CONNECTION",
"BAD_CONNECTION_OR_GROUND",
"BAD_CONNECTION_OR_POWER",
"SHORTED_GROUND_ACI",
"SHORTED_GROUND_BIAS",
"SHORTED_POWER_ACI",
"SHORTED_POWER_BIAS"
};
/* Digmic selftest defines */
enum Selftest_Digimic_Setup_e {
ST_DIGIMIC_ALL,
ST_DIGIMIC_MIC1,
ST_DIGIMIC_MIC2,
ST_DIGIMIC_MIC3,
ST_DIGIMIC_MIC4
};
enum ResultFormat_e {
ST_RESULT_FORMAT_NORMAL = 0,
ST_RESULT_FORMAT_DETAILED
};
struct SelftestDataStandard_t {
enum ResultFormat_e rf;
};
struct SelftestDataDmic_t {
enum ResultFormat_e rf;
int mic;
};
/* Selftest User Space Commands */
struct SelftestData_t {
struct SelftestDataDmic_t dmic;
struct SelftestDataStandard_t hs;
struct SelftestDataStandard_t ihf;
};
static struct SelftestData_t SelftestData = {
.dmic = {
.rf = ST_RESULT_FORMAT_DETAILED,
},
.hs = {
.rf = ST_RESULT_FORMAT_DETAILED,
},
.ihf = {
.rf = ST_RESULT_FORMAT_DETAILED,
}
};
struct SelftestUserCmdData_t {
/* Input */
uint testId; /* SelftestCmds_e */
enum ResultFormat_e ResultFormat;
uint parm1;
uint parm2;
uint parm3;
/* Output */
uint subtestCount;
uint subtestStatus[10]; /* Max 10 subtests supported */
uint testStatus;
};
#ifdef DIGIMIC_SUPPORTED
/* Variable for DigiMic test */
static bool DigiMicInterruptReceived;
#endif
/**********************************************************/
/** Stuff that should be defined in header files - Begin **/
/**********************************************************/
#define ST_PN_DMIC1DQ PN_GPIO34
#define ST_PN_DMIC1CLK PN_GPIO33
#define DIGMIC_VCC_REGULATOR "hv7ldo_uc"
/**********************************************************/
/** Stuff that should be defined in header files - End **/
/**********************************************************/
/************************/
/* Test Implementations */
/************************/
struct dac_ctrl_t {
u32 AUDIOTX_TEST_EN;
u32 AUDIOTX_BB_STI;
u32 AUDIOTX_EP_DRV_STO;
};
static void st_audio_audiotx_set_dac_ctrl(CHAL_HANDLE audiohandle,
struct dac_ctrl_t writedata)
{
u32 ctrl = 0;
ctrl = chal_audio_audiotx_get_dac_ctrl(audiohandle);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::"
"st_audio_audiotx_set_dac_ctrl():"
" Pre-AUDIOH_DAC_CTRL: 0x%08X",
ctrl);
ctrl &= (~AUDIOH_DAC_CTRL_AUDIOTX_TEST_EN_MASK);
ctrl &= (~AUDIOH_DAC_CTRL_AUDIOTX_BB_STI_MASK);
ctrl |=
((writedata.
AUDIOTX_TEST_EN)) & 3 << AUDIOH_DAC_CTRL_AUDIOTX_TEST_EN_SHIFT;
ctrl |=
((writedata.
AUDIOTX_BB_STI) & 3) << AUDIOH_DAC_CTRL_AUDIOTX_BB_STI_SHIFT;
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::st_audio_audiotx_set_dac_ctrl(): "
"AUDIOH_DAC_CTRL: 0x%08X",
ctrl);
chal_audio_audiotx_set_dac_ctrl(audiohandle, ctrl);
{
u32 val;
val = BRCM_READ_REG(KONA_AUDIOH_VA, AUDIOH_DAC_CTRL);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs():"
" AUDIOH_DAC_CTRL: 0x%08X",
val);
}
}
static void st_audio_audiotx_get_dac_ctrl(CHAL_HANDLE audiohandle,
struct dac_ctrl_t *readdata)
{
u32 ctrl;
ctrl = chal_audio_audiotx_get_dac_ctrl(audiohandle);
readdata->AUDIOTX_TEST_EN = ctrl & 3;
readdata->AUDIOTX_BB_STI = (ctrl >> 2) & 3;
readdata->AUDIOTX_EP_DRV_STO = (ctrl >> 4) & 3;
}
enum selftest_store_e {
SELFTEST_IHF,
SELFTEST_HS,
SELFTEST_DMIC,
SELFTEST_COUNT
};
/****************************************************************************
*
* NAME: AUDIOH_hw_clkInit
*
*
* Description: Initializes the clock manager settings for APB13
*
*
* Parameters: None
*
* Returns: None
*
* Notes: This function is should be part of CLKMGR block.
* Will be replaced with CLKMGR_hw_XXX function once available
*
****************************************************************************/
static void AUDIOH_hw_clkInit(void)
{
u32 regVal;
/* Enable write access */
regVal = (0x00A5A5 << KHUB_CLK_MGR_REG_WR_ACCESS_PASSWORD_SHIFT);
regVal |= KHUB_CLK_MGR_REG_WR_ACCESS_CLKMGR_ACC_MASK;
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_WR_ACCESS,
regVal);
/* Set the frequency policy */
regVal = (0x06 << KHUB_CLK_MGR_REG_POLICY_FREQ_POLICY0_FREQ_SHIFT);
regVal |= (0x06 << KHUB_CLK_MGR_REG_POLICY_FREQ_POLICY1_FREQ_SHIFT);
regVal |= (0x06 << KHUB_CLK_MGR_REG_POLICY_FREQ_POLICY2_FREQ_SHIFT);
regVal |= (0x06 << KHUB_CLK_MGR_REG_POLICY_FREQ_POLICY3_FREQ_SHIFT);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY_FREQ,
regVal);
/* Set the frequency policy */
regVal = 0x7FFFFFFF;
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY0_MASK1,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY1_MASK1,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY2_MASK1,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY3_MASK1,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY0_MASK2,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY1_MASK2,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY2_MASK2,
regVal);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY3_MASK2,
regVal);
/* start the frequency policy */
regVal =
(KHUB_CLK_MGR_REG_POLICY_CTL_GO_MASK |
KHUB_CLK_MGR_REG_POLICY_CTL_GO_AC_MASK);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_POLICY_CTL,
regVal);
}
static void AUDIOH_hw_setClk(void)
{
u32 regVal;
/* Enable all the AUDIOH clocks, 26M, 156M, 2p4M, 6p5M */
regVal = KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_APB_CLK_EN_MASK;
regVal |=
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_APB_HW_SW_GATING_SEL_MASK;
regVal |= KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_156M_CLK_EN_MASK;
regVal |=
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_156M_HW_SW_GATING_SEL_MASK;
regVal |= KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_26M_CLK_EN_MASK;
regVal |=
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_26M_HW_SW_GATING_SEL_MASK;
regVal |= KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_2P4M_CLK_EN_MASK;
regVal |=
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_2P4M_HW_SW_GATING_SEL_MASK;
regVal |= KHUB_CLK_MGR_REG_AUDIOH_CLKGATE_AUDIOH_APB_HYST_VAL_MASK;
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA, KHUB_CLK_MGR_REG_AUDIOH_CLKGATE,
regVal);
}
static struct dac_ctrl_t Stored_dac_ctrl_Value;
static u8 Stored_DacPower;
static struct pin_config DmicStoredValue[4];
static int regl_hv7ldo_orig_state;
static u8 StoredDMIC0Enable;
static u8 StoredDMIC1Enable;
static u32 StoredClkGate;
static u32 StoredPolicyFreq;
static u32 StoredPolicyMask[8];
static bool TestActive[SELFTEST_COUNT] = { false, false, false };
void st_audio_store_registers(enum selftest_store_e test)
{
CHAL_HANDLE audiohandle;
struct regulator *regl_hv7ldo = NULL;
audiohandle = chal_audio_init(KONA_AUDIOH_VA, KONA_SDT_BASE_VA);
if (TestActive[SELFTEST_DMIC] ||
TestActive[SELFTEST_IHF] || TestActive[SELFTEST_HS]) {
/* Store clock settings */
StoredClkGate =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE);
StoredPolicyFreq =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY_FREQ);
StoredPolicyMask[0] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY0_MASK1);
StoredPolicyMask[1] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY1_MASK1);
StoredPolicyMask[2] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY2_MASK1);
StoredPolicyMask[3] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY3_MASK1);
StoredPolicyMask[4] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY0_MASK2);
StoredPolicyMask[5] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY1_MASK2);
StoredPolicyMask[6] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY2_MASK2);
StoredPolicyMask[7] =
BRCM_READ_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY3_MASK2);
}
TestActive[test] = true;
switch (test) {
case SELFTEST_DMIC:
/* Store GPIO setting registers */
DmicStoredValue[0].name = PN_DMIC0CLK;
pinmux_get_pin_config(&DmicStoredValue[0]);
DmicStoredValue[1].name = PN_DMIC0DQ;
pinmux_get_pin_config(&DmicStoredValue[1]);
DmicStoredValue[2].name = ST_PN_DMIC1CLK;
pinmux_get_pin_config(&DmicStoredValue[2]);
DmicStoredValue[3].name = ST_PN_DMIC1DQ;
pinmux_get_pin_config(&DmicStoredValue[3]);
/* Store PMU register Values */
regl_hv7ldo = regulator_get(NULL, DIGMIC_VCC_REGULATOR);
if (IS_ERR(regl_hv7ldo)) {
printk(KERN_ERR "Cannot get <hv7ldo> regulator");
} else {
regl_hv7ldo_orig_state =
regulator_is_enabled(regl_hv7ldo);
regulator_put(regl_hv7ldo);
}
AUDIOH_hw_clkInit();
AUDIOH_hw_setClk();
StoredDMIC0Enable =
chal_audio_vinpath_digi_mic_enable_read(audiohandle);
StoredDMIC1Enable =
chal_audio_nvinpath_digi_mic_enable_read(audiohandle);
break;
case SELFTEST_IHF:
bcmpmu_audio_ihf_selftest_backup(1);
AUDIOH_hw_clkInit();
AUDIOH_hw_setClk();
/* Store BB register Values */
/* Register shared with HS */
st_audio_audiotx_get_dac_ctrl(audiohandle,
&Stored_dac_ctrl_Value);
Stored_DacPower = chal_audio_ihfpath_get_dac_pwr(audiohandle);
break;
case SELFTEST_HS:
bcmpmu_audio_hs_selftest_backup(1);
AUDIOH_hw_clkInit();
AUDIOH_hw_setClk();
/* Store BB register Values */
/* Register shared with IHF */
st_audio_audiotx_get_dac_ctrl(audiohandle,
&Stored_dac_ctrl_Value);
break;
default:
break;
}
}
void st_audio_restore_registers(enum selftest_store_e test)
{
CHAL_HANDLE audiohandle;
struct regulator *regl_hv7ldo = NULL;
audiohandle = chal_audio_init(KONA_AUDIOH_VA, KONA_SDT_BASE_VA);
switch (test) {
case SELFTEST_DMIC:
/* Restore GPIO setting registers */
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST:: 1:pinmux_set_pin_config(%u)",
DmicStoredValue[0].name);
pinmux_set_pin_config(&DmicStoredValue[0]);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST:: 2:pinmux_set_pin_config(%u)",
DmicStoredValue[1].name);
pinmux_set_pin_config(&DmicStoredValue[1]);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST:: 3:pinmux_set_pin_config(%u)",
DmicStoredValue[2].name);
pinmux_set_pin_config(&DmicStoredValue[2]);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST:: 4:pinmux_set_pin_config(%u)",
DmicStoredValue[3].name);
pinmux_set_pin_config(&DmicStoredValue[3]);
StoredDMIC0Enable =
chal_audio_vinpath_digi_mic_enable_read(audiohandle);
StoredDMIC1Enable =
chal_audio_nvinpath_digi_mic_enable_read(audiohandle);
regl_hv7ldo = regulator_get(NULL, DIGMIC_VCC_REGULATOR);
if (IS_ERR(regl_hv7ldo)) {
printk(KERN_ERR "Cannot get <hv7ldo> regulator");
} else {
if (regl_hv7ldo_orig_state == 0)
regulator_disable(regl_hv7ldo);
regulator_put(regl_hv7ldo);
}
break;
case SELFTEST_IHF:
bcmpmu_audio_ihf_selftest_backup(0);
/* Restore BB register values */
st_audio_audiotx_set_dac_ctrl(audiohandle,
Stored_dac_ctrl_Value);
chal_audio_ihfpath_set_dac_pwr(audiohandle, Stored_DacPower);
break;
case SELFTEST_HS:
bcmpmu_audio_hs_selftest_backup(0);
/* Restore BB register values */
st_audio_audiotx_set_dac_ctrl(audiohandle,
Stored_dac_ctrl_Value);
break;
default:
break;
}
if (!TestActive[SELFTEST_DMIC] &&
!TestActive[SELFTEST_IHF] && !TestActive[SELFTEST_HS]) {
/* Retore clock settings */
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_AUDIOH_CLKGATE, StoredClkGate);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY_FREQ, StoredPolicyFreq);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY0_MASK1,
StoredPolicyMask[0]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY1_MASK1,
StoredPolicyMask[1]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY2_MASK1,
StoredPolicyMask[2]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY3_MASK1,
StoredPolicyMask[3]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY0_MASK2,
StoredPolicyMask[4]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY1_MASK2,
StoredPolicyMask[5]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY2_MASK2,
StoredPolicyMask[6]);
BRCM_WRITE_REG(KONA_HUB_CLK_BASE_VA,
KHUB_CLK_MGR_REG_POLICY3_MASK2,
StoredPolicyMask[7]);
}
TestActive[test] = false;
}
/******************/
/* IHF TEST */
/******************/
#ifdef IHF_ST_SUPPORTED
static void std_selftest_ihf(struct SelftestUserCmdData_t *cmddata)
{
u8 ResultArray1[IHF_NUMBER_OF_SUBTESTS1] = { ST_PASS,
ST_PASS
};
u8 ResultArray2[IHF_NUMBER_OF_SUBTESTS2] = { ST_PASS,
ST_PASS
};
u8 ReadValue; /* Value read from PMU */
struct dac_ctrl_t Dac_Ctrl;
CHAL_HANDLE audiohandle;
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() called.");
audiohandle = chal_audio_init(KONA_AUDIOH_VA, KONA_SDT_BASE_VA);
st_audio_store_registers(SELFTEST_IHF);
st_audio_audiotx_get_dac_ctrl(audiohandle, &Dac_Ctrl);
/* Subtest 1 + 2 - IHF DAC */
/* PMU Input test */
/* 1. Enable test mode (driving buffer enabled) */
/* (i_hs_enst[1:0] = '11') on PMU */
bcmpmu_audio_ihf_testmode(PMU_TEST_READ_AND_ENABLE);
/*2. Disable Output (i_hs_enst = '0') on BB */
/* AUDIOTX_TEST_EN[1:0] = '00' */
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_ihf() Disable Output");
Dac_Ctrl.AUDIOTX_TEST_EN = BB_TEST_DISABLE;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*2a. Disable BB output drivers (High-Z) */
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf()"
"Disable BB output drivers (High-Z)");
chal_audio_ihfpath_set_dac_pwr(audiohandle, 0);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 1.1");
/*3. Set Output (i_hs_ist = '1') on PMU */
bcmpmu_audio_ihf_selftest_stimulus_input(0x02);
/*4. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Bit High = > Check passed */
/* b. Bit Low = > Shorted to Ground */
CHECKBIT_AND_ASSIGN_ERROR(0, IHF_NUMBER_OF_SUBTESTS1,
ReadValue,
ResultArray1, ST_SHORTED_GROUND);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_ihf()"
"Test1 readvalue = 0x%X",
ReadValue);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 1.2");
/*5. Set Output (i_hs_ist = '0') on PMU */
bcmpmu_audio_ihf_selftest_stimulus_input(0x00);
/*6. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Bit Low = > Check passed */
/* b. Bit High = > Shorted to Power */
CHECKBIT_AND_ASSIGN_ERROR(1, IHF_NUMBER_OF_SUBTESTS1, ReadValue,
ResultArray1, ST_SHORTED_POWER);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf()"
"Test2 readvalue = 0x%X",
ReadValue);
/* BB output test: */
/*1. Enable Output (Test_en[0:1] = '11') on BB */
Dac_Ctrl.AUDIOTX_TEST_EN = BB_TEST_500_OHM;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*2. Enable test mode (Short or Open test) */
/* (i_IHFselftest_en[1:0] = '10') */
bcmpmu_audio_ihf_testmode(PMU_TEST_READ_AND_DISABLE);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 1.3");
/*3. Set Output (i_BB_sti = '11') */
Dac_Ctrl.AUDIOTX_BB_STI = 0x03;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*3a. Set (i_IHFsti = '0x') */
bcmpmu_audio_ihf_selftest_stimulus_input(0x00);
/*4. Check result (o_IHFsti). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Bit High = > Check passed */
/* b. Bit Low = > Shorted to Ground */
CHECKBIT_AND_ASSIGN_ERROR(0, IHF_NUMBER_OF_SUBTESTS1,
ReadValue, ResultArray1,
ST_BAD_CONNECTION_OR_GROUND);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 1.4");
/*5. Set Output (i_BB_sti = '00') */
Dac_Ctrl.AUDIOTX_BB_STI = 0x00;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*5a. Set (i_IHFsti = '0x') */
bcmpmu_audio_ihf_selftest_stimulus_input(0x00);
/*6. Check result (o_IHFsti). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Bit Low = > Check passed */
/* b. Bit High = > Shorted to Supply */
CHECKBIT_AND_ASSIGN_ERROR(1, IHF_NUMBER_OF_SUBTESTS1, ReadValue,
ResultArray1,
ST_BAD_CONNECTION_OR_POWER);
/* Subtest 3 + 4 - IHF Output */
/*PMU Output Pins Test: */
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 2.1");
/*1. Enable by setting i_IHFselftest_en[0] to 1. */
bcmpmu_audio_ihf_testmode(PMU_TEST_ENABLE_NO_READ);
/*2. i_IHFsto[1:0] = '0x' */
bcmpmu_audio_ihf_selftest_stimulus_output(0x00);
/* Check */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Check if o_IHFsto[1:0] == '00' */
/* = > No pull-up resistor from the output pins to Supply */
/* b. Check if o_IHFsto[1:0] < >'00' */
/* = > Either or both output pins are short to Supply */
CHECKBIT_AND_ASSIGN_ERROR(1, IHF_NUMBER_OF_SUBTESTS2,
ReadValue, ResultArray2,
ST_BAD_CONNECTION_OR_POWER);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_ihf() Test 2.2");
/*3. i_IHFsto[1:0] = '1x' */
bcmpmu_audio_ihf_selftest_stimulus_output(0x02);
/* Check */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_ihf_selftest_result(&ReadValue);
/* a. Check o_IHFsto[1:0] = '00' */
/* = > No pull-down resistor from the output pins to ground */
/* b. Check o_IHFsto[1:0] < >'00' */
/* = > Either or both output pins are short to ground */
CHECKBIT_AND_ASSIGN_ERROR(1, IHF_NUMBER_OF_SUBTESTS2,
ReadValue, ResultArray2,
ST_BAD_CONNECTION_OR_GROUND);
st_audio_restore_registers(SELFTEST_IHF);
/* Fill out failures status code structure */
/* Subtest 1 + 2 - IHF DAC */
{
int i;
for (i = 0; i < IHF_NUMBER_OF_SUBTESTS1; i++) {
cmddata->subtestStatus[i] =
ResultArray1[IHF_NUMBER_OF_SUBTESTS1 - 1 - i];
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_ihf()"
"ResultArray1[%u] = %u",
IHF_NUMBER_OF_SUBTESTS1 - 1 - i,
ResultArray1[IHF_NUMBER_OF_SUBTESTS1 - 1 - i]);
}
}
/* Subtest 3 + 4 - IHF Output */
{
int i;
for (i = 0; i < IHF_NUMBER_OF_SUBTESTS2; i++) {
cmddata->subtestStatus[i + IHF_NUMBER_OF_SUBTESTS1] =
ResultArray2[IHF_NUMBER_OF_SUBTESTS2 - 1 - i];
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_ihf() "
"ResultArray2[%u] = %u",
IHF_NUMBER_OF_SUBTESTS2 - 1 - i,
ResultArray2[IHF_NUMBER_OF_SUBTESTS2 - 1 - i]);
}
}
/* Find return code */
if (ResultArray1[0] || ResultArray1[1] ||
ResultArray2[0] || ResultArray2[1]) {
cmddata->subtestCount =
IHF_NUMBER_OF_SUBTESTS1 + IHF_NUMBER_OF_SUBTESTS2;
cmddata->testStatus = ST_FAIL;
} else {
cmddata->subtestCount = 0;
cmddata->testStatus = ST_PASS;
}
}
#endif /* IHF_ST_SUPPORTED */
/******************/
/* HEADSET TEST */
/******************/
#ifdef HEADSET_ST_SUPPORTED
static void std_selftest_hs(struct SelftestUserCmdData_t *cmddata)
{
u8 ResultArray[HA_NUMBER_OF_SUBTESTS] = { ST_PASS,
ST_PASS,
ST_PASS,
ST_PASS
};
u8 ReadValue; /* Value read from PMU */
struct dac_ctrl_t Dac_Ctrl;
CHAL_HANDLE audiohandle;
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_headset() called.");
audiohandle = chal_audio_init(KONA_AUDIOH_VA, KONA_SDT_BASE_VA);
st_audio_store_registers(SELFTEST_HS);
st_audio_audiotx_get_dac_ctrl(audiohandle, &Dac_Ctrl);
/**************************/
/* Subtest 1 + 2 + 3 + 4 */
/**************************/
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs() "
"RA[0] = %u,RA[1] = %u,RA[2] = %u,RA[3] = %u",
ResultArray[0], ResultArray[1], ResultArray[2], ResultArray[3]);
/* Setup */
bcmpmu_hs_set_input_mode(0, PMU_HS_DIFFERENTIAL_DC_COUPLED);
bcmpmu_hs_set_gain(PMU_AUDIO_HS_BOTH, 0);
bcmpmu_audio_init();
bcmpmu_hs_power(true);
/* PMU Input test */
/**********/
/* TEST 1 */
/**********/
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_hs() INPUT TEST");
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::TEST 1");
/* 1. Enable test mode (driving buffer enabled)
(i_hs_enst[1:0] = '11') on PMU */
bcmpmu_audio_hs_testmode(PMU_TEST_READ_AND_ENABLE);
/*2. Disable Output (i_hs_enst = '0') on BB */
/* AUDIOTX_TEST_EN[1:0] = '00' */
Dac_Ctrl.AUDIOTX_TEST_EN = BB_TEST_10_KOHM;
Dac_Ctrl.AUDIOTX_BB_STI = 0x00;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*3. Set Output (i_hs_ist = '1') on PMU */
bcmpmu_audio_hs_selftest_stimulus(0x01);
/*4. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_hs_selftest_result(&ReadValue);
/* a. Bit High = > Check passed */
/* b. Bit Low = > Shorted to Ground */
CHECKBIT_AND_ASSIGN_ERROR(0, HA_NUMBER_OF_SUBTESTS,
ReadValue, ResultArray,
ST_SHORTED_GROUND);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs()"
"Test1 readvalue = 0x%X",
ReadValue);
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs() "
"RA[0] = %u,RA[1] = %u,RA[2] = %u,RA[3] = %u",
ResultArray[0], ResultArray[1], ResultArray[2], ResultArray[3]);
/**********/
/* TEST 2 */
/**********/
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::TEST 2");
BRCM_WRITE_REG_FIELD(KONA_AUDIOH_VA, AUDIOH_DAC_CTRL, AUDIOTX_BB_STI,
0x03);
/*5. Set Output (i_hs_ist = '0') on PMU */
bcmpmu_audio_hs_selftest_stimulus(0x00);
/*6. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_hs_selftest_result(&ReadValue);
/* a. Bit Low = > Check passed */
/* b. Bit High = > Shorted to Power */
CHECKBIT_AND_ASSIGN_ERROR(1, HA_NUMBER_OF_SUBTESTS,
ReadValue,
ResultArray, ST_SHORTED_POWER);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_hs()"
"Test2 readvalue = 0x%X",
ReadValue);
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs() "
"RA[0] = %u,RA[1] = %u,RA[2] = %u,RA[3] = %u",
ResultArray[0], ResultArray[1], ResultArray[2], ResultArray[3]);
/* BB Output Test */
/**********/
/* TEST 3 */
/**********/
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_hs() OUTPUT TEST");
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::TEST 3");
/*1. Enable test mode (driving buffer disabled)
(i_hs_enst[1:0] = '10') on PMU */
bcmpmu_audio_hs_testmode(PMU_TEST_READ_AND_DISABLE);
/*2. Enable Output (i_hs_enst = '1') on BB */
/* AUDIOTX_TEST_EN[1:0] = '11' */
Dac_Ctrl.AUDIOTX_TEST_EN = BB_TEST_500_OHM;
/*3. Set Output (i_hs_ist = '1') on BB */
/* AUDIOTX_BB_STI[1:0] = '11' */
Dac_Ctrl.AUDIOTX_BB_STI = 0x03;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*4. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_hs_selftest_result(&ReadValue);
/* a. Bit High = > Check passed */
/* b. Bit Low = > Shorted to Ground or Not connected */
CHECKBIT_AND_ASSIGN_ERROR(0, HA_NUMBER_OF_SUBTESTS,
ReadValue, ResultArray,
ST_BAD_CONNECTION_OR_GROUND);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_hs()"
"Test3 readvalue = 0x%X",
ReadValue);
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs() "
"RA[0] = %u,RA[1] = %u,RA[2] = %u,RA[3] = %u",
ResultArray[0], ResultArray[1], ResultArray[2], ResultArray[3]);
/**********/
/* TEST 4 */
/**********/
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::TEST 4");
/*5. Set Output (i_hs_ist = '0') on BB */
/* AUDIOTX_BB_STI[1:0] = '00' */
Dac_Ctrl.AUDIOTX_BB_STI = 0x00;
st_audio_audiotx_set_dac_ctrl(audiohandle, Dac_Ctrl);
/*6. Check result (o_hst_ist[3:0]). */
mdelay(AUDIO_SETTLING_TIME);
bcmpmu_audio_hs_selftest_result(&ReadValue);
/* a. Bit Low = > Check passed */
/* b. Bit High = > Shorted to Power or Not connected */
CHECKBIT_AND_ASSIGN_ERROR(1, HA_NUMBER_OF_SUBTESTS,
ReadValue,
ResultArray,
ST_BAD_CONNECTION_OR_POWER);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_hs()"
"Test4 readvalue = 0x%X",
ReadValue);
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_hs() "
"RA[0] = %u,RA[1] = %u,RA[2] = %u,RA[3] = %u",
ResultArray[0], ResultArray[1], ResultArray[2], ResultArray[3]);
st_audio_restore_registers(SELFTEST_HS);
/* Fill out failures status code structure */
{
int i;
for (i = 0; i < HA_NUMBER_OF_SUBTESTS; i++) {
cmddata->subtestStatus[i] =
ResultArray[HA_NUMBER_OF_SUBTESTS - 1 - i];
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_headset() "
"ResultArray[%u] = %u",
HA_NUMBER_OF_SUBTESTS - 1 - i,
ResultArray[HA_NUMBER_OF_SUBTESTS - 1 - i]);
}
}
/* Find return code */
if (ResultArray[0] || ResultArray[1] ||
ResultArray[2] || ResultArray[3]) {
cmddata->subtestCount = HA_NUMBER_OF_SUBTESTS;
cmddata->testStatus = ST_FAIL;
} else {
cmddata->subtestCount = 0;
cmddata->testStatus = ST_PASS;
}
}
#endif
/******************/
/* DIGIMIC TEST */
/******************/
#ifdef DIGIMIC_SUPPORTED
/* Clock control functions */
static void ST_AUDIOH_hw_DMIC_Enable(CHAL_HANDLE audiohandle, int dmic)
{
/* Enable DMIC paths */
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::AUDIOH_hw_DMIC_Enable() "
"Enable interface DMIC%u(RDB)",
dmic);
switch (dmic) {
case 0:
chal_audio_vinpath_digi_mic_enable(audiohandle,
CHAL_AUDIO_CHANNEL_LEFT);
break;
case 1:
chal_audio_vinpath_digi_mic_enable(audiohandle,
CHAL_AUDIO_CHANNEL_RIGHT);
break;
case 2:
chal_audio_nvinpath_digi_mic_enable(audiohandle,
CHAL_AUDIO_CHANNEL_LEFT);
break;
case 3:
chal_audio_nvinpath_digi_mic_enable(audiohandle,
CHAL_AUDIO_CHANNEL_RIGHT);
break;
}
/* Setup Clock */
}
static void ST_AUDIOH_hw_DMIC_Disable(CHAL_HANDLE audiohandle)
{
u32 regVal;
/* Disable all DMIC paths */
regVal = BRCM_READ_REG(KONA_AUDIOH_VA, AUDIOH_ADC_CTL);
regVal &=
~(AUDIOH_ADC_CTL_DMIC1_EN_MASK | AUDIOH_ADC_CTL_DMIC2_EN_MASK |
AUDIOH_ADC_CTL_DMIC3_EN_MASK | AUDIOH_ADC_CTL_DMIC4_EN_MASK);
BRCM_WRITE_REG(KONA_AUDIOH_VA, AUDIOH_ADC_CTL, regVal);
}
static irqreturn_t GPIO_DigiMicSelftestEventFunction(int irq, void *dev_id)
{
/* Receive GPIO event */
DigiMicInterruptReceived = true;
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::GPIO_DigiMicSelftestEventFunction(%u) "
, irq);
disable_irq_nosync(irq);
return IRQ_HANDLED;
}
#define DIGIMIC_SUBTESTS_PER_MIC 1
#define MAX_DIGIMIC_IF_COUNT 2
#define MAX_DIGIMIC_COUNT 4
#define DIGIMIC_NUMBER_OF_SUBTESTS 4
#define DIGIMIC_COMM_TEST 0 /* First digimic test */
static void std_selftest_dmic(struct SelftestUserCmdData_t *cmddata)
{
int Mic, MicIf;
int ret;
int i;
struct regulator *regl_hv7ldo = NULL;
bool TestMic[MAX_DIGIMIC_COUNT] = { false, false, false, false };
enum PIN_NAME PMUX_CLK_CONNECTION[MAX_DIGIMIC_IF_COUNT] = {
PN_DMIC0CLK, ST_PN_DMIC1CLK
};
enum PIN_NAME PMUX_DQ_CONNECTION[MAX_DIGIMIC_IF_COUNT] = {
PN_DMIC0DQ, ST_PN_DMIC1DQ
};
enum PIN_FUNC PMUX_DMIC_CLK_MODE_CLK[MAX_DIGIMIC_IF_COUNT] = {
PF_DMIC0CLK, PF_DMIC1CLK
};
enum PIN_FUNC PMUX_DMIC_DQ_MODE_GPIO[MAX_DIGIMIC_IF_COUNT];
unsigned DQ_CONNECTION[MAX_DIGIMIC_IF_COUNT];
int MIC_IF[MAX_DIGIMIC_COUNT] = { 0, 0, 1, 1 };
struct pin_config PIN_DMIC_Setup;
struct pin_config PIN_GPIO_Setup;
CHAL_HANDLE audiohandle;
unsigned find_gpio;
enum PIN_FUNC find_PF_gpio;
u8 Status[DIGIMIC_NUMBER_OF_SUBTESTS] = { ST_PASS,
ST_PASS
};
st_audio_store_registers(SELFTEST_DMIC);
for (i = 0; i < MAX_DIGIMIC_IF_COUNT; i++) {
pinmux_find_gpio(PMUX_DQ_CONNECTION[i], &find_gpio,
&find_PF_gpio);
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_digimic() "
"PMUX_DQ_CONNECTION[%u]=%u, gpio=%u, gpio_func=%u ",
i, PMUX_DQ_CONNECTION[i], find_gpio, find_PF_gpio);
DQ_CONNECTION[i] = find_gpio;
PMUX_DMIC_DQ_MODE_GPIO[i] = find_PF_gpio;
}
switch (cmddata->parm1) {
default:
case ST_DIGIMIC_ALL:
TestMic[0] = true;
TestMic[1] = true;
TestMic[2] = true;
TestMic[3] = true;
break;
case ST_DIGIMIC_MIC1:
TestMic[0] = true;
break;
case ST_DIGIMIC_MIC2:
TestMic[1] = true;
break;
case ST_DIGIMIC_MIC3:
TestMic[2] = true;
break;
case ST_DIGIMIC_MIC4:
TestMic[3] = true;
break;
}
audiohandle = chal_audio_init(KONA_AUDIOH_VA, KONA_SDT_BASE_VA);
/* Actual test */
for (Mic = 0; Mic < MAX_DIGIMIC_COUNT; Mic++) {
if (!TestMic[Mic]) {
Status[Mic * DIGIMIC_SUBTESTS_PER_MIC] =
ST_NOT_TESTED;
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic()"
"Mic#%u Not Tested",
Mic);
continue;
}
MicIf = MIC_IF[Mic];
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic()"
"Mic#%u", Mic);
/* Subtest 3(6) - Connection test */
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_digimic()"
"Connection Test (%u) DQ = %u ",
Mic, DQ_CONNECTION[MicIf]);
/*0. Power on microphone HVLDO7 (on PMU HVLDO7PMODCTRL) */
/* powerOnDigitalMic(true); */
regl_hv7ldo = regulator_get(NULL, DIGMIC_VCC_REGULATOR);
if (IS_ERR(regl_hv7ldo)) {
aError("%s: regulator_get failed(0x%X)\n",
__func__, (unsigned int)regl_hv7ldo);
aError("Cannot get <hv7ldo> regulator");
} else {
regulator_enable(regl_hv7ldo);
regulator_put(regl_hv7ldo);
}
/*1. Setup DMIC0CLK as Mic clock output */
PIN_GPIO_Setup.name = PMUX_DQ_CONNECTION[MicIf];
PIN_GPIO_Setup.func = PMUX_DMIC_DQ_MODE_GPIO[MicIf];
PIN_GPIO_Setup.reg.val = 0;
PIN_GPIO_Setup.reg.b.drv_sth = DRIVE_STRENGTH_8MA;
pinmux_set_pin_config(&PIN_GPIO_Setup);
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST:: DQ Setup 0x%X",
PIN_GPIO_Setup.reg.val);
PIN_DMIC_Setup.name = PMUX_CLK_CONNECTION[MicIf];
PIN_DMIC_Setup.func = PMUX_DMIC_CLK_MODE_CLK[MicIf];
PIN_DMIC_Setup.reg.val = 0;
PIN_DMIC_Setup.reg.b.drv_sth = DRIVE_STRENGTH_8MA;
pinmux_set_pin_config(&PIN_DMIC_Setup);
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST:: CLK Setup 0x%X",
PIN_DMIC_Setup.reg.val);
/* Enable Audio Clocks */
ST_AUDIOH_hw_DMIC_Enable(audiohandle, Mic);
mdelay(DMIC_SETTLING_TIME);
/*2. Setup DMICXDQ input */
/*3. Setup DMICXDQ to interrupt on rising edge */
ret = gpio_request(DQ_CONNECTION[MicIf], "DMICDQ");
if (ret < 0) {
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::gpio %u request failed",
DQ_CONNECTION[MicIf]);
cmddata->testStatus = ST_FAIL;
return;
}
DigiMicInterruptReceived = false;
aTrace
(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::std_selftest_digimic() "
"Set interrupt Mode(Input/Rising)");
gpio_direction_input(DQ_CONNECTION[MicIf]);
ret = request_irq(gpio_to_irq(DQ_CONNECTION[MicIf]),
GPIO_DigiMicSelftestEventFunction,
IRQF_TRIGGER_RISING, "Digmimic Data", 0);
if (ret < 0) {
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::gpio irq %u request failed",
DQ_CONNECTION[MicIf]);
cmddata->testStatus = ST_FAIL;
gpio_free(DQ_CONNECTION[MicIf]);
return;
}
/*4. Wait for interrupt for 10ms */
for (i = 0; i < 10; i++) {
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Interrrupt wait loop %u, Value = %u",
i, gpio_get_value(DQ_CONNECTION[MicIf]));
mdelay(2);
if (DigiMicInterruptReceived == true)
break;
}
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Disable Interrupt");
disable_irq(gpio_to_irq(DQ_CONNECTION[MicIf]));
free_irq(gpio_to_irq(DQ_CONNECTION[MicIf]), 0);
gpio_free(DQ_CONNECTION[MicIf]);
if (DigiMicInterruptReceived == true) {
/* b. Interrupt received = > Continue to 5. */
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Interrupt Received");
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST] = ST_PASS;
} else {
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST] = ST_BAD_CONNECTION;
/* a. Timeout = > No connection - Test failed */
}
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"3.1 Status[%u] = %u ",
(Mic * DIGIMIC_SUBTESTS_PER_MIC) + DIGIMIC_COMM_TEST,
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST]);
if (Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) + DIGIMIC_COMM_TEST]
== ST_PASS) {
/*5. Setup DMICXDQ to interrupt on falling edge */
DigiMicInterruptReceived = false;
ret = gpio_request(DQ_CONNECTION[MicIf], "DMICDQ");
if (ret < 0) {
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::gpio %u request failed",
DQ_CONNECTION[MicIf]);
cmddata->testStatus = ST_FAIL;
return;
}
gpio_direction_input(DQ_CONNECTION[MicIf]);
DigiMicInterruptReceived = false;
aTrace
(LOG_AUDIO_DRIVER ,
"GLUE_SELFTEST::std_selftest_digimic() "
"Set interrupt Mode(Input/Falling)");
ret =
request_irq(gpio_to_irq(DQ_CONNECTION[MicIf]),
GPIO_DigiMicSelftestEventFunction,
IRQF_TRIGGER_FALLING, "Digmimic Data",
0);
if (ret < 0) {
aTrace(LOG_AUDIO_DRIVER, "GLUE_SELFTEST::"
"gpio irq %u request failed",
DQ_CONNECTION[MicIf]);
cmddata->testStatus = ST_FAIL;
gpio_free(DQ_CONNECTION[MicIf]);
return;
}
/*6. Wait for interrupt for 10ms */
for (i = 0; i < 10; i++) {
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Interrrupt wait loop %u, Value = %u",
i, gpio_get_value(DQ_CONNECTION[MicIf]));
mdelay(2);
if (DigiMicInterruptReceived == true)
break;
}
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Disable Interrupt");
disable_irq(gpio_to_irq(DQ_CONNECTION[MicIf]));
free_irq(gpio_to_irq(DQ_CONNECTION[MicIf]), 0);
gpio_free(DQ_CONNECTION[MicIf]);
if (DigiMicInterruptReceived == true) {
/* b. Interrupt received
= > ST_PASS */
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() "
"Interrupt Received");
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST] = ST_PASS;
} else {
/* a. Timeout
= > No connection - Test failed */
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST] =
ST_BAD_CONNECTION;
}
aTrace(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic()"
"3.2 Status[%u] = %u",
(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST,
Status[(Mic * DIGIMIC_SUBTESTS_PER_MIC) +
DIGIMIC_COMM_TEST]);
}
ST_AUDIOH_hw_DMIC_Disable(audiohandle);
} /* Mic */
/* Restore register values */
st_audio_restore_registers(SELFTEST_DMIC);
/* Fill out failures status code structure */
for (i = 0; i < DIGIMIC_NUMBER_OF_SUBTESTS; i++) {
cmddata->subtestStatus[i] = Status[i];
aTrace
(LOG_AUDIO_DRIVER,
"GLUE_SELFTEST::std_selftest_digimic() Status[%u] = %u",
i, Status[i]);
}
/* Find return code */
if (((Status[0] != 0) && (Status[0] != ST_NOT_TESTED)) ||
((Status[1] != 0) && (Status[1] != ST_NOT_TESTED)) ||
((Status[2] != 0) && (Status[2] != ST_NOT_TESTED)) ||
((Status[3] != 0) && (Status[3] != ST_NOT_TESTED))) {
cmddata->subtestCount = DIGIMIC_NUMBER_OF_SUBTESTS;
cmddata->testStatus = ST_FAIL;
} else {
cmddata->subtestCount = 0;
cmddata->testStatus = ST_PASS;
}
}
#endif
/********************************************************************/
/* Command Handling helpers */
/********************************************************************/
static ssize_t FormatTestResult(struct SelftestUserCmdData_t cmddata, char *buf)
{
int i;
char *cbuf;
cbuf = buf;
/* Normal result */
sprintf(cbuf, "%s\n", Selftest_ResultString[cmddata.testStatus]);
/* Detailed result */
if ((cmddata.ResultFormat == ST_RESULT_FORMAT_DETAILED) &&
(cmddata.testStatus == ST_FAIL) &&
(cmddata.subtestCount != 0)) {
cbuf += strlen(cbuf);
sprintf(cbuf, "%i\n", cmddata.subtestCount);
cbuf += strlen(cbuf);
for (i = 0; i < cmddata.subtestCount; i++) {
sprintf(cbuf, "%s\n",
Selftest_ResultString[cmddata.
subtestStatus[i]]);
cbuf += strlen(cbuf);
}
}
return strlen(buf);
}
/*******************/
/* Sysfs Interface */
/*******************/
#ifdef DIGIMIC_SUPPORTED
static ssize_t show_selftest_dmic(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct SelftestUserCmdData_t cmddata;
cmddata.ResultFormat = SelftestData.dmic.rf;
cmddata.parm1 = SelftestData.dmic.mic;
if (!TestActive[SELFTEST_DMIC])
std_selftest_dmic(&cmddata);
else
cmddata.testStatus = ST_BUSY;
return FormatTestResult(cmddata, buf);
}
static ssize_t store_selftest_dmic(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int format, mic;
int parms;
parms = sscanf(buf, "%d %d", &format, &mic);
if ((parms == 0) || (parms > 2))
return -EINVAL;
if (parms >= 1)
SelftestData.dmic.rf = format;
if (parms >= 2)
SelftestData.dmic.mic = mic;
return strnlen(buf, count);
}
#endif
#ifdef IHF_ST_SUPPORTED
static ssize_t show_selftest_ihf(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct SelftestUserCmdData_t cmddata;
cmddata.ResultFormat = SelftestData.ihf.rf;
if (!TestActive[SELFTEST_IHF])
if (TestActive[SELFTEST_HS])
cmddata.testStatus = ST_BUSY;
else
std_selftest_ihf(&cmddata);
else
cmddata.testStatus = ST_BUSY;
return FormatTestResult(cmddata, buf);
}
static ssize_t store_selftest_ihf(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int format;
if ((sscanf(buf, "%d", &format)) != 1)
return -EINVAL;
SelftestData.ihf.rf = format;
return strnlen(buf, count);
}
#endif
#ifdef HEADSET_ST_SUPPORTED
static ssize_t show_selftest_hs(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct SelftestUserCmdData_t cmddata;
cmddata.ResultFormat = SelftestData.hs.rf;
if (!TestActive[SELFTEST_HS])
if (TestActive[SELFTEST_IHF])
cmddata.testStatus = ST_BUSY;
else
std_selftest_hs(&cmddata);
else
cmddata.testStatus = ST_BUSY;
return FormatTestResult(cmddata, buf);
}
static ssize_t store_selftest_hs(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int format;
if ((sscanf(buf, "%d", &format)) != 1)
return -EINVAL;
SelftestData.hs.rf = format;
return strnlen(buf, count);
}
#endif
#ifdef DIGIMIC_SUPPORTED
static DEVICE_ATTR(selftest_dmic, S_IRUGO | S_IWUSR, show_selftest_dmic,
store_selftest_dmic);
#endif
#ifdef IHF_ST_SUPPORTED
static DEVICE_ATTR(selftest_ihf, S_IRUGO | S_IWUSR, show_selftest_ihf,
store_selftest_ihf);
#endif
#ifdef HEADSET_ST_SUPPORTED
static DEVICE_ATTR(selftest_hs, S_IRUGO | S_IWUSR, show_selftest_hs,
store_selftest_hs);
#endif
int BrcmCreateAuddrv_selftestSysFs(struct snd_card *card)
{
int ret = 0;
/*create sysfs file for Aud Driver selftest control */
#ifdef DIGIMIC_SUPPORTED
ret = snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&dev_attr_selftest_dmic);
#endif
#ifdef IHF_ST_SUPPORTED
ret = snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&dev_attr_selftest_ihf);
#endif
#ifdef HEADSET_ST_SUPPORTED
ret = snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&dev_attr_selftest_hs);
#endif
return ret;
}
/************************************/
/* Selftest Boot Excution interface */
/************************************/
int BrcmAudioSelftest(void)
{
struct SelftestUserCmdData_t cmddata;
std_selftest_ihf(&cmddata);
if (cmddata.testStatus == ST_PASS) {
std_selftest_hs(&cmddata);
if (cmddata.testStatus == ST_PASS)
return 0;
}
return -EIO;
}