/* * 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) { }