Beispiel #1
0
/* set HTC/Mbox operational parameters, this can only be called when the target is in the
 * BMI phase */
A_STATUS ar6000_set_htc_params(HIF_DEVICE *hifDevice,
                               A_UINT32    TargetType,
                               A_UINT32    MboxIsrYieldValue,
                               A_UINT8     HtcControlBuffers)
{
    A_STATUS status;
    A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX];

    do {
            /* get the block sizes */
        status = HIFConfigureDevice(hifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
                                    blocksizes, sizeof(blocksizes));

        if (A_FAILED(status)) {
            AR_DEBUG_PRINTF(ATH_LOG_ERR,("Failed to get block size info from HIF layer...\n"));
            break;
        }
            /* note: we actually get the block size for mailbox 1, for SDIO the block
             * size on mailbox 0 is artificially set to 1 */
            /* must be a power of 2 */
        A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0);

        if (HtcControlBuffers != 0) {
                /* set override for number of control buffers to use */
            blocksizes[1] |=  ((A_UINT32)HtcControlBuffers) << 16;
        }

            /* set the host interest area for the block size */
        status = BMIWriteMemory(hifDevice,
                                HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz),
                                (A_UCHAR *)&blocksizes[1],
                                4);

        if (A_FAILED(status)) {
            AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for IO block size failed \n"));
            break;
        }

        AR_DEBUG_PRINTF(ATH_LOG_INF,("Block Size Set: %d (target address:0x%X)\n",
                blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz)));

        if (MboxIsrYieldValue != 0) {
                /* set the host interest area for the mbox ISR yield limit */
            status = BMIWriteMemory(hifDevice,
                                    HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_isr_yield_limit),
                                    (A_UCHAR *)&MboxIsrYieldValue,
                                    4);

            if (A_FAILED(status)) {
                AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for yield limit failed \n"));
                break;
            }
        }

    } while (FALSE);

    return status;
}
Beispiel #2
0
    /* can only be called during bmi init stage */
A_STATUS ar6000_set_hci_bridge_flags(HIF_DEVICE *hifDevice,
                                     A_UINT32    TargetType,
                                     A_UINT32    Flags)
{
    A_STATUS status = A_OK;

    do {

        if (TargetType != TARGET_TYPE_AR6003) {
            AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Target Type:%d, does not support HCI bridging! \n",
                TargetType));
            break;
        }

            /* set hci bridge flags */
        status = BMIWriteMemory(hifDevice,
                                HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_hci_bridge_flags),
                                (A_UCHAR *)&Flags,
                                4);


    } while (FALSE);

    return status;
}
static A_STATUS prepare_MCKINLEY(HIF_DEVICE *hifDevice, A_UINT32 TargetVersion)
{
    A_STATUS status = A_OK;
    A_UINT32 value  = 0;

    /* force the setting to disable sleep for Bringup FIXME_MK */
    value |= WLAN_SYSTEM_SLEEP_DISABLE_MASK;

    status = BMIWriteMemory(hifDevice,
                            HOST_INTEREST_ITEM_ADDRESS(TARGET_TYPE_AR6002, hi_system_sleep_setting),
                            (A_UCHAR *)&value,
                            4);

    return status;
}
Beispiel #4
0
/* Modules for firmware download */
A_STATUS configure_ar6000(HIF_DEVICE *hifDevice,
                           A_UINT32    TargetType,
                           A_UINT32    TargetVersion,
                           A_BOOL      enableUART,
                           A_BOOL      timerWAR,
                           A_UINT32    clkFreq,
                           wchar_t     *fileName,
                           wchar_t     *fileRoot,
                           A_BOOL      bCompressed,
                           A_BOOL      isColdBoot,
                           wchar_t     *eepromFile)
{
    A_STATUS status   = A_OK;
    A_UINT32 value    = 0;
    A_UINT32 oldSleep = 0;

    /* do any target-specific preparation that can be done through BMI */
    do
    {
        if (enableUART)
        {
            A_UINT32 uartparam;
            uartparam = 1;
            status = BMIWriteMemory(hifDevice,
                                HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_serial_enable),
                                (A_UCHAR *)&uartparam,
                                4);
            if (status != A_OK)
            {
                break;
            }
        }

        value = HTC_PROTOCOL_VERSION;
        status = BMIWriteMemory (hifDevice,
                                 HOST_INTEREST_ITEM_ADDRESS (TargetType, hi_app_host_interest),
                                (A_UCHAR *)&value,
                                4);
        if (status != A_OK)
        {
            break;
        }

        /* Selectively enable/disable the WAR for Timer Hang Symptom in the
         * firmware by setting a bit in the AR6K Scratch register. The firmware will
         * read this during init and appropriately enable/disable the WAR.
         * This setting will be retained in the firmware till target reset.
         */
        if (timerWAR)
        {
            A_UINT32 timerparam;

            status = BMIReadMemory(hifDevice,
                                   HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag),
                                   (A_UCHAR *)&timerparam,
                                   4);
            if (status != A_OK)
            {
                break;
            }
            timerparam |= HI_OPTION_TIMER_WAR;

            status = BMIWriteMemory(hifDevice,
                                    HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag),
                                    (A_UCHAR *)&timerparam,
                                    4);
            if (status != A_OK)
            {
                break;
            }
        }

        if (TargetType == TARGET_TYPE_AR6001)
        {
#ifdef FLASH_18V
            // Change the flash access time for 1.8V flash to 150ns
            status = BMIWriteSOCRegister (hifDevice,  0xac004004,  0x920100d1);
            if (status != A_OK)
            {
                break;
            }
#endif

        }
         /* set the firmware mode to AP */

        {
            A_UINT32 param;
            A_UINT32 fwmode = HI_OPTION_FW_MODE_BSS_STA;

            if (BMIReadMemory(hifDevice,
                HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag),
                (A_UCHAR *)&param,4)!= A_OK)
            {
                return -1;
            }

            param |= (fwmode << HI_OPTION_FW_MODE_SHIFT);

            if (BMIWriteMemory(hifDevice,
                HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag),
                (A_UCHAR *)&param,4) != A_OK)
            {
                return -1;
            }
        }

        if (TargetType == TARGET_TYPE_AR6002)
        {
            // Store the value of sleep
            oldSleep = 0x0;
            status = BMIReadSOCRegister (hifDevice, 0x40C4, &oldSleep);
            if (status != A_OK)
            {
                break;
            }

            // disable sleep
            status = BMIWriteSOCRegister (hifDevice, 0x40C4, oldSleep |  0x1);
            if (status != A_OK)
            {
                break;
            }

            status = ar6002_download_image(hifDevice, TargetVersion, fileName, fileRoot, bCompressed,isColdBoot);
            if (status != A_OK)
            {
               break;
            }

            // Restore the value of sleep
            status = BMIWriteSOCRegister (hifDevice, 0x40C4, oldSleep);
            if (status != A_OK)
            {
                break;
            }

            if ((TargetVersion == AR6002_VERSION_REV2) && (AR6002_REV2_APP_START_OVERRIDE != 0)) {
                    /* override default app start address known to ROM  */
                status = BMISetAppStart(hifDevice, AR6002_REV2_APP_START_OVERRIDE);
                if (status != A_OK) {
                    break;
                }
            }

        }

        status = ar6000_configure_clock (hifDevice, TargetType, TargetVersion, clkFreq);
        if (status != A_OK)
        {
            break;
        }

        status = eeprom_ar6000_transfer (hifDevice, TargetType, fileRoot, eepromFile);
        if (status != A_OK)
        {
            break;
        }

    } while (FALSE);

    return status;
}
Beispiel #5
0
A_STATUS ar6002_download_image(HIF_DEVICE *hifDevice,
                               A_UINT32    TargetVersion,
                               wchar_t    *fileName,
                               wchar_t    *fileRoot,
                               A_BOOL      bCompressed,
                               A_BOOL      isColdBoot)
{
    A_UINT32 address    = 0;
    A_STATUS status     = A_OK;
    A_UINT32 ini_patch_address = 0;

    do
    {
        address = AR6002_ATHWLAN_REV2_ADDRESS;

        if (isColdBoot) {
#ifdef EMBEDDED_AR6K_FIRMWARE
        if (!wcscmp(fileName, TCMD_BINARY_REV2_STR))
        {

#ifdef CONFIG_HOST_TCMD_SUPPORT
            status = download_binary (hifDevice,
                                      address,
                                      fileName,
                                      fileRoot,
                                      bCompressed,
                                      GET_TCMD_CACHE_INFO());
#endif
        }
        else if (!wcscmp(fileName, ART_BINARY_REV2_STR))
        {
#ifdef WINCE_ART
            status = download_binary (hifDevice,
                                      address,
                                      fileName,
                                      fileRoot,
                                      bCompressed,
                                      GET_ART_CACHE_INFO());
#endif
        }
        else
        {
            status = download_binary (hifDevice,
                                      address,
                                      fileName,
                                      fileRoot,
                                      bCompressed,
                                      GET_FIRMWARE_CACHE_INFO());
        }
#else
            status = download_binary (hifDevice,
                                      address,
                                      fileName,
                                      fileRoot,
                                      bCompressed,
                                      GET_FIRMWARE_CACHE_INFO());
#endif


            if (status != A_OK)
            {
                break;
            }
#ifdef EMBEDDED_AR6K_FIRMWARE
#ifdef AR6K_ROMPATCH_APPLY
            status = apply_patch (hifDevice,
                                  TargetVersion,
                                  WLAN_PATCH_REV2_STR,
                                  fileRoot,
                                  GET_ROMPATCH_CACHE_INFO());
            if (status != A_OK)
            {
                break;
            }
#endif
#else

            status = apply_patch (hifDevice,
                                  TargetVersion,
                                  WLAN_PATCH_REV2_STR,
                                  fileRoot,
                                  GET_ROMPATCH_CACHE_INFO());
            if (status != A_OK)
            {
                break;
            }
#endif

            // Download INI Patch
            address = AR6002_INIPATCH_REV2_ADDRESS;
            status = download_binary(hifDevice,
                                 address,
                                 INIPATCH_REV2_STR,
                                 fileRoot,
                                 FALSE,
                                 GET_DATAPATCH_CACHE_INFO());

            if (status != A_OK)
            {
                break;
            }
        }

        address = AR6002_INIPATCH_REV2_ADDRESS;

        status = BMIWriteMemory(hifDevice,
                                AR6002_HOST_INTEREST_ITEM_ADDRESS(hi_dset_list_head),
                                (A_UCHAR *)&address,
                                4);
        if (status != A_OK)
        {
            break;
        }

    } while (FALSE);

    return status;
}
Beispiel #6
0
A_STATUS apply_patch (HIF_DEVICE *hifDevice,
                      A_UINT32 TargetVersion,
                      wchar_t *patchFile,
                      wchar_t *fileRoot,
                      AR6K_BIN_CACHE_INFO *pRomCache)
{
    A_STATUS status = A_OK;
    HANDLE fd = INVALID_HANDLE_VALUE;
    wchar_t filePath[128];
    A_UINT32 ret = 0;
    A_UINT32 id = 0;
    A_UINT32 tpid = 0;
    A_UINT32 chkSum = 0;
    A_UINT32 count = 0;
    A_UINT32 max = 0;
    A_UINT32 cmd = 0;
    A_UINT32 romAddr = 0;
    A_UINT32 ramAddr = 0;
    A_UINT32 reMapSz = 0;
    A_UCHAR  *buffer = NULL;
    A_UINT32 length = 0;
    A_UINT32 i = 0;
    BY_HANDLE_FILE_INFORMATION finfo;
    A_UINT32 fileSize = 0;

    do
    {
        if (pRomCache->Valid) {
            buffer = pRomCache->pData;
            fileSize = pRomCache->ActualLength;
        } else {
            if ( wcslen(patchFile) + wcslen(fileRoot) > 127 )
            {
                 ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Name Very Long :: ====>");
                return A_ERROR;
            }

            wcscpy(filePath,fileRoot);
            wcscat(filePath,patchFile);

            ATHR_DISPLAY_MSG (L"file %s \n",filePath);
            //Read the patch distribution file
            if ( (fd = CreateFile (filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
            {
                ATHR_DISPLAY_MSG (L"CAR6K:: No Patch File :: ====> %s", filePath);
                break;
            }

            if (!GetFileInformationByHandle(fd, &finfo))
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Size Error :: ====> %s", filePath);
                status = A_ERROR;
                break;
            }
            fileSize = finfo.nFileSizeLow;
            if ((buffer=A_MALLOC(fileSize)) == NULL)
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable allocated memory :: ====> %d",fileSize);
                status = A_ERROR;
                break;
            }
            if ( !ReadFile(fd, buffer, fileSize, &ret, NULL) || (ret != fileSize))
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable to read rpdf ID from :: ====> %s",filePath);
                status = A_ERROR;
                break;
            }
            if (pRomCache->Static)
            {
                pRomCache->Valid = TRUE;
                pRomCache->pData = buffer;
                pRomCache->ActualLength = fileSize;
                pRomCache->MaxLength = fileSize;
            }
        }
        id = *((A_UINT32 *)buffer);
        buffer += sizeof(id);

        chkSum = *((A_UINT32 *)buffer);
        buffer += sizeof(chkSum);

        count = *((A_UINT32 *)buffer);
        buffer += sizeof(count);

        if ( TargetVersion == AR6002_VERSION_REV2 )
        {
             max = AR6002_REV2_MAX_PATCHES;
        }

        if (count > max)
        {
            ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Maximum patches supported :: %d ====> %d",max,count);
            status = A_ERROR;
            break;
        }

        for (; count; count--)
        {
            cmd = 0;
            romAddr = 0;
            ramAddr = 0;
            reMapSz = 0;
            length = 0;
            tpid = 0;

            cmd = *((A_UINT32 *)buffer);
            buffer += sizeof(cmd);

            if ( cmd != RPDF_CMD_INSTALL && cmd != RPDF_CMD_INST_ACT )
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unknown command in patch specification :: ====> %d",cmd);
                status = A_ERROR;
                break;
            }

            reMapSz= *((A_UINT32 *)buffer);
            buffer += sizeof(reMapSz);

            if ( reMapSz == 0 || reMapSz & (reMapSz-1) )
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Invalid remap size :: ====> 0x%x",reMapSz);
                status = A_ERROR;
                break;
            }

            romAddr= *((A_UINT32 *)buffer);
            buffer += sizeof(romAddr);

            ramAddr= *((A_UINT32 *)buffer);
            buffer += sizeof(ramAddr);

            length= *((A_UINT32 *)buffer);
            buffer += sizeof(length);

            if (length > 0)
            {
                status = BMIWriteMemory(hifDevice, ramAddr, buffer, length);
                if (status != A_OK)
                {
                    ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable write patch to target :: ====> ");
                    break;
                }

                buffer += length;
            }

            if (cmd == RPDF_CMD_INST_ACT || cmd == RPDF_CMD_INSTALL)
            {
                status = BMIrompatchInstall(hifDevice, romAddr, ramAddr, reMapSz, 0, &tpid);
                if (status != A_OK)
                {
                    ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable write patch registers in target :: ====> ");
                    break;
                }

                InstalledPatches[NumPatches++] = tpid;
            }

            if (cmd == RPDF_CMD_INST_ACT && NumPatches)
            {
                status = BMIrompatchActivate(hifDevice, NumPatches, InstalledPatches);
                if (status != A_OK)
                {
                    ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable activate patch in target :: ====> ");
                    break;
                }
            }
        }
    } while (FALSE);

    if ((!pRomCache->Valid) && (buffer))
    {
       A_FREE(buffer);
    }

    if (fd)
    {
       CloseHandle (fd);
    }
    NumPatches = 0;

    return status;
}
Beispiel #7
0
A_STATUS download_binary (HIF_DEVICE *hifDevice,
                          A_UINT32 address,
                          wchar_t *fileName,
                          wchar_t *fileRoot,
                          A_BOOL  bCompressed,
                          AR6K_BIN_CACHE_INFO *pBinCache)
{
    A_STATUS status = A_OK;
    A_UCHAR  *buffer = NULL;
    A_UINT32 length = 0;
    A_UINT32 fileSize = 0;
    A_UINT32 next_address=0;
    A_INT32 file_left = 0;
    size_t nSize;
    wchar_t filePath[128];
    HANDLE fd = NULL;
    BY_HANDLE_FILE_INFORMATION finfo;
    A_BOOL  fillCache = FALSE;

    A_MEMZERO(&finfo, sizeof(finfo));
    if ( wcslen(fileName) + wcslen(fileRoot) > 127 )
    {
         ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Name Very Long :: ====>");
         return A_ERROR;
    }

    wcscpy(filePath,fileRoot);
    wcscat(filePath,fileName);


    ATHR_DISPLAY_MSG (L"file %s \n",filePath);
    do
    {
        if (pBinCache->Valid) {

                /* binary cache is valid */
            if (bCompressed) {
                status = BMILZStreamStart (hifDevice, address);
                if (A_FAILED(status)) {
                    break;
                }
            }

            if (bCompressed) {
                A_UINT32  lastWord = 0;
                A_UINT32  lastWordOffset = pBinCache->ActualLength & ~0x3;
                A_UINT32  unalignedBytes = pBinCache->ActualLength & 0x3;

                if (unalignedBytes) {
                        /* copy the last word into a zero padded buffer */
                    A_MEMCPY(&lastWord,
                             &pBinCache->pData[lastWordOffset],
                             unalignedBytes);
                }

                status = BMILZData(hifDevice,
                                   pBinCache->pData,
                                   lastWordOffset);

                if (A_FAILED(status)) {
                    break;
                }

                if (unalignedBytes) {
                    status = BMILZData(hifDevice,
                                       (A_UINT8 *)&lastWord,
                                       4);
                }

            } else {
                status = BMIWriteMemory(hifDevice,
                                        address,
                                        pBinCache->pData,
                                        A_ROUND_UP(pBinCache->ActualLength,4));
            }

            if (bCompressed && A_SUCCESS(status)) {
                //
                // Close compressed stream and open a new (fake) one.  This serves mainly to flush Target caches.
                //
                status = BMILZStreamStart (hifDevice, 0x00);
                if (A_FAILED(status)) {
                    break;
                }
            }

                /* all done */
            break;
        }

        //Determine the length of the file
        if ( (fd = CreateFile (filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
        {
            status = A_ERROR;
            ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Not Found :: ====> %s", filePath);
            break;
        }

        if (!GetFileInformationByHandle(fd, &finfo))
        {
            ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Size Error :: ====> %s", filePath);
            status = A_ERROR;
            break;
        }
        fileSize = finfo.nFileSizeLow;
        file_left = fileSize;

        if ((pBinCache->pData != NULL) && (!pBinCache->Static)) {
            /* binary caching is supported */
            A_ASSERT(!pBinCache->Valid);

            if (fileSize <= pBinCache->MaxLength) {
                    /* size if good, flag to cache this binary when read from the filesystem */
                fillCache = TRUE;
                pBinCache->ActualLength = 0; /* reset */
            } else {
                    /* cache is not big enough to hold data */
                A_ASSERT(FALSE);
                ATHR_DISPLAY_MSG (L"AR6K::WARNING!!!! :: File :%s (%d bytes) too big for cache (max=%d)",
                         filePath, fileSize, pBinCache->MaxLength);
            }
        }

        //
        // zero data buffer and init length
        //
        buffer = (A_UCHAR *)A_MALLOC(MAX_BUF);
        if (NULL == buffer)
        {
            status = A_ERROR;
            break;
        }

        if (bCompressed)
        {
            status = BMILZStreamStart (hifDevice, address);
            if (status != A_OK)
            {
                break;
            }
        }


        while (file_left)
        {
            length  = (file_left < (MAX_BUF)) ? file_left : MAX_BUF;
            if (bCompressed)
            {
                //
                // 0 pad last word of data to avoid messy uncompression
                //
                ((A_UINT32 *)buffer)[((length-1)/4)] = 0;
            }

            if (!ReadFile( fd, buffer, length, &nSize, NULL) || nSize != length)
            {
                ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: ReadFile Error :: ====>");
                status = A_ERROR;
                break;
            }
            next_address = address + fileSize - file_left;

            //
            // We round up the requested length because some SDIO Host controllers can't handle other lengths.
            // This generally isn't a problem for users, but it's something to be aware of.
            //
            length = A_ROUND_UP(length, 4);

            if (bCompressed)
            {
                status = BMILZData(hifDevice, buffer, length);
            }
            else
            {
                status = BMIWriteMemory(hifDevice, next_address, buffer, length);
            }

            if (status != A_OK)
            {
               break;
            }

            if (fillCache) {
                CopyChunkToBinCache(pBinCache, buffer, length);
            }

            if (file_left >= MAX_BUF)
            {
                file_left = file_left - MAX_BUF;
            }
            else
            {
                file_left = 0;
            }

        };

        if (status != A_OK)
        {
            break;
        }

        if (fillCache) {
                /* cache was filled, mark it valid */
            pBinCache->Valid = TRUE;
        }

        if (bCompressed)
        {
            //
            // Close compressed stream and open a new (fake) one.  This serves mainly to flush Target caches.
            //
            status = BMILZStreamStart (hifDevice, 0x00);
            if (status != A_OK)
            {
                break;
            }
        }

    } while (FALSE);

    if (buffer)
    {
        free (buffer);
        buffer = NULL;
    }
    if (fd)
    {
        CloseHandle (fd);
    }

    return status;
}
Beispiel #8
0
static A_STATUS
ar6000_configure_clock (HIF_DEVICE *hifDevice,
                        A_UINT32    TargetType,
                        A_UINT32    TargetVersion,
                        A_UINT32    clkFreq)
{
    A_UINT32 ext_clk_detected = 0;
    A_STATUS status = A_OK;

    do
    {
        if (TargetType == TARGET_TYPE_AR6001)
        {
            status = BMIWriteSOCRegister(hifDevice, 0xAC000020, 0x203);
            if (status != A_OK)
            {
                break;
            }

            status = BMIWriteSOCRegister (hifDevice, 0xAC000024, 0x203);
            if (status != A_OK)
            {
                break;
            }
        }

        if (TargetType == TARGET_TYPE_AR6002)
        {
            if (TargetVersion == AR6002_VERSION_REV2)
            {
                status = BMIReadMemory(hifDevice,
                         HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_ext_clk_detected),
                         (A_UCHAR *)&ext_clk_detected,
                         4);
                if (status != A_OK)
                {
                    break;
                }

#ifdef FORCE_INTERNAL_CLOCK
                status = BMIWriteSOCRegister (hifDevice, 0x40E0, 0x10000);
                if (status != A_OK)
                {
                    break;
                }
                status = BMIWriteSOCRegister (hifDevice, 0x4028, 0x0);
                if (status != A_OK)
                {
                    break;
                }
#else
                // LPO_CAL.Enable for internal clock
                if (ext_clk_detected == 0x0)
                {
                    status = BMIWriteSOCRegister (hifDevice, 0x40E0, 0x10000);
                    if (status != A_OK)
                    {
                        break;
                    }
                }
#endif
                // Run at 40/44 MHz clock
                status = BMIWriteSOCRegister (hifDevice, 0x4020, 0x0);
                if (status != A_OK)
                {
                    break;
                }
            }

            // Write refclk
            status = BMIWriteMemory(hifDevice,
                                    HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_refclk_hz),
                                    (A_UCHAR *)&clkFreq,
                                    4);
            if (status != A_OK)
            {
                break;
            }
        }
    } while (FALSE);

    return status;
}