/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* must reproduce the above copyright notice, this list of conditions and
|
* the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
|
#include "mk_calib.h"
|
#include "mk_clock.h"
|
#include "mk_reset.h"
|
#include "mk_trace.h"
|
#include "mk_misc.h"
|
#include "mk_rtc.h"
|
|
#include "board.h"
|
|
int calib_open(void)
|
{
|
// enable CAL clock
|
clock_enable(CLOCK_CALIB);
|
reset_module(RESET_MODULE_CALIB);
|
return DRV_OK;
|
}
|
|
int calib_close(void)
|
{
|
// disable CAL clock
|
clock_disable(CLOCK_CALIB);
|
return DRV_OK;
|
}
|
|
void calib_start(uint32_t items)
|
{
|
REG_WRITE(CALIB_BASE, items | CALIB_START);
|
}
|
|
void calib_check(uint32_t done)
|
{
|
while ((REG_READ(CALIB_BASE + 0x4) & done) != done)
|
{
|
}
|
}
|
|
void calib_chip(void)
|
{
|
uint32_t val;
|
|
// load cap
|
if (board_param.flag & (1 << BOARD_LOAD_CAP))
|
{
|
calib_xtal38m4_load_cap_set(board_param.load_cap);
|
}
|
if (board_param.flag & (1 << BOARD_X32K_LOAD_CAP))
|
{
|
calib_xtal32k_load_cap_set(board_param.x32k_load_cap);
|
}
|
|
clock_enable(CLOCK_CALIB);
|
|
// fix DCDC_EN
|
val = REG_READ(0x40000204) & ~0x3U;
|
REG_WRITE(0x40000204, val | 0x2);
|
|
// LO PLL configure
|
REG_WRITE(0x4000060c, 0x0A106BAF);
|
|
#if HIGH_PERFORMANCE_MODE_EN
|
// LPF_BM
|
REG_WRITE(0x40000608, 0x03E80004);
|
// increase Trim current to promote RF performance
|
REG_WRITE_BYTE(0x40010072, 0x77);
|
#else
|
// decrease Trim current
|
// REG_WRITE_BYTE(0x40010072, 0x88); // lowest
|
|
// clear Trim code
|
REG_WRITE_BYTE(0x40010072, 0x00); // middle
|
|
val = REG_READ_BYTE(0x40010071) & 0x1F;
|
REG_WRITE_BYTE(0x40010071, (uint8_t)val);
|
#endif
|
|
#define LO_L (77 + (56 << 8) + (54 << 16) + (80 << 24))
|
#define LO_H (49 + (46 << 8) + (50 << 16) + (54 << 24))
|
#define WF (7 + (52 << 8))
|
|
// patch for buck calibration voltage
|
uint8_t x = REG_READ_BYTE(0x40010075);
|
if ((READ_WORD(0x4001007C) == LO_L) && (READ_WORD(0x40010078) == LO_H) && (READ_SHORT(0x40010076) == WF) && (x >= 1) && (x <= 19))
|
{
|
REG_WRITE_BYTE(0x40010073, 0x20);
|
}
|
|
// patch for ADC trim code
|
val = REG_READ_BYTE(0x4001006B);
|
if ((val & 0x1F) == 0)
|
{
|
REG_WRITE_BYTE(0x4001006B, (uint8_t)(val | 0x10));
|
}
|
|
// Open RCO for calibration
|
SYSCON->PMU_CTRL0 &= ~(1U << 5);
|
|
// calibrate
|
REG_WRITE(0x40006000, 0x80001cfe);
|
|
while ((REG_READ(0x40006004) & 0x80000000) == 0)
|
{
|
}
|
|
uint32_t id = mk_chip_id();
|
LOG_INFO(TRACE_MODULE_DRIVER, "Chip ID: %08x\r\n", id);
|
if (id == 0x0 || id == 0x400 || id == 0x800 || id == 0xC00)
|
{
|
LOG_INFO(TRACE_MODULE_DRIVER, "Old chip model is not supported by this SDK!!!\r\n");
|
while (1)
|
{
|
}
|
}
|
|
// Reduce next PA calibration time
|
val = REG_READ(0x400060d4) & ~0xfU;
|
REG_WRITE(0x400060d4, val);
|
|
val = REG_READ(0x400060c8) & ~((0xfU << 18) | (0x1));
|
REG_WRITE(0x400060c8, val);
|
|
// Reduce turnaround time
|
REG_WRITE(0x40000410, 400);
|
REG_WRITE(0x4000040c, 0x1f);
|
|
// val = REG_READ(0x4000020c) & ~(0x1fU << 7);
|
// REG_WRITE(0x4000020c, val | (0x18 << 7));
|
|
#if (LOW_POWER_EN) && (XTAL32K_EN == 0)
|
rco32k_clk_calibrate(RCO32K_MEAS_TIME_64_CYCLES);
|
#endif
|
}
|
|
void calib_xtal38m4_load_cap_auto_tune(int32_t ppm)
|
{
|
uint32_t tmp_val = REG_READ(0x40000048);
|
uint8_t val = (tmp_val & 0x7FU);
|
|
if (ppm > 2)
|
{
|
val += 1;
|
}
|
else if (ppm < -2)
|
{
|
val -= 1;
|
}
|
else
|
{
|
return;
|
}
|
tmp_val &= ~0x7FU;
|
tmp_val |= (val & 0x7FU);
|
REG_WRITE(0x40000048, tmp_val);
|
LOG_INFO(TRACE_NO_REPORT_HOST | TRACE_MODULE_DRIVER, "XTAL load cap tune %d : %d\r\n", ppm, (tmp_val & 0x7FU));
|
}
|
|
void calib_xtal38m4_load_cap_set(uint8_t val)
|
{
|
uint32_t tmp_val = REG_READ(0x40000048);
|
|
tmp_val &= ~0x7FU;
|
val &= 0x7FU;
|
|
REG_WRITE(0x40000048, tmp_val | val);
|
LOG_INFO(TRACE_MODULE_DRIVER, "XTAL load cap val %d\r\n", REG_READ(0x40000048) & 0x7FU);
|
}
|
|
void calib_xtal38m4_with_clock_out(uint8_t val)
|
{
|
/* Setting GPIO17 output 38.4M clock. */
|
uint32_t tmp_val = REG_READ(0x4000003C);
|
tmp_val &= ~0x70U;
|
tmp_val |= (0x1U << 4);
|
REG_WRITE(0x4000003C, tmp_val);
|
|
/* Setting internal load cap of MK8000, the valid value is from 0 ot 127. */
|
tmp_val = REG_READ(0x40000048);
|
|
tmp_val &= ~0x7FU;
|
val &= 0x7FU;
|
|
REG_WRITE(0x40000048, tmp_val | val);
|
REG_WRITE(0x40000104, 0x3FFF);
|
LOG_INFO(TRACE_MODULE_DRIVER, "XTAL load cap val %d\r\n", REG_READ(0x40000048) & 0x7FU);
|
}
|
|
void calib_xtal32k_load_cap_set(uint8_t val)
|
{
|
uint32_t tmp_val = REG_READ(0x4000004C);
|
|
tmp_val &= ~0x7FU;
|
val &= 0x7FU;
|
|
REG_WRITE(0x4000004C, tmp_val | val);
|
LOG_INFO(TRACE_MODULE_DRIVER, "32K load cap val %d\r\n", REG_READ(0x4000004C) & 0x7FU);
|
}
|
|
void calib_xtal32k_with_clock_out(uint8_t val)
|
{
|
/* Setting GPIO02 output 32K clock. */
|
uint32_t tmp_val = REG_READ(0x40000234);
|
tmp_val |= (0x1U << 10);
|
REG_WRITE(0x40000234, tmp_val);
|
|
/* Setting GPIO02 oupt 32K clock by pin mux. */
|
tmp_val = REG_READ(0x40000034);
|
tmp_val &= ~(0xFU << 8);
|
tmp_val |= (0x4U << 8);
|
REG_WRITE(0x40000034, tmp_val);
|
|
/* Setting internal load cap of MK8000, the valid value is from 0 ot 127. */
|
tmp_val = REG_READ(0x4000004C);
|
|
tmp_val &= ~0x7FU;
|
val &= 0x7FU;
|
|
REG_WRITE(0x4000004C, tmp_val | val);
|
LOG_INFO(TRACE_MODULE_DRIVER, "32K load cap val %d\r\n", REG_READ(0x4000004C) & 0x7FU);
|
}
|
|
void CALIB_IRQHandler(void)
|
{
|
}
|