blob: 33d20482e7b54881641669ad1af9f842bbf463d4 [file] [log] [blame]
/******************************************************************************
* @file clock.c
*
* @brief for TLSR chips
*
* @author public@telink-semi.com;
* @date Sep. 30, 2010
*
* @attention
*
* Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************/
#include "register.h"
#include "clock.h"
#include "irq.h"
#include "analog.h"
#include "timer.h"
#include "pm.h"
extern _attribute_data_retention_ unsigned char tl_24mrc_cal;
_attribute_data_retention_ unsigned char system_clk_type;
#if 0
/**
* @brief This function to set RC for the system clock.
* @param[in] SYS_CLK - the clock source of the system clock.
* @return none
*/
void clock_rc_set(SYS_CLK_TypeDef SYS_CLK)
{
unsigned char temp = analog_read(0x04)&0xfc;
if(SYS_CLK==SYS_CLK_24M_RC)
{
analog_write(0x04, temp|0x00);
rc_24m_cal();
}
else if(SYS_CLK==SYS_CLK_32M_RC)
{
analog_write(0x04, temp|0x01);
//rc_32m_cal();
}
else if(SYS_CLK==SYS_CLK_48M_RC)
{
analog_write(0x04, temp|0x03);
rc_48m_cal();
}
}
#endif
/**
* @brief This function to select the system clock source.
* @param[in] SYS_CLK - the clock source of the system clock.
* @return none
*/
#if (BLC_PM_DEEP_RETENTION_MODE_EN)
_attribute_ram_code_
#endif
void clock_init(SYS_CLK_TypeDef SYS_CLK)
{
reg_clk_sel = (unsigned char)SYS_CLK;
system_clk_type = (unsigned char)SYS_CLK;
#if 0 //vulture is normal
if(SYS_CLK == SYS_CLK_48M_Crystal)
{
/*default c4: dcdc 1.8V -> GD flash£º 48M clock may error £¬ need higher DCDC voltage
c6: dcdc 1.9V
*/
analog_write(0x0c, 0xc6);
}
#endif
#if (MODULE_WATCHDOG_ENABLE)
reg_tmr_ctrl = MASK_VAL(
FLD_TMR_WD_CAPT, (MODULE_WATCHDOG_ENABLE ? (WATCHDOG_INIT_TIMEOUT * CLOCK_SYS_CLOCK_1MS >> WATCHDOG_TIMEOUT_COEFF):0)
, FLD_TMR_WD_EN, (MODULE_WATCHDOG_ENABLE?1:0));
#endif
if(!(pm_is_MCU_deepRetentionWakeup())){
rc_24m_cal();
}
}
/**
* @brief This function serves to set 32k clock source.
* @param[in] variable of 32k type.
* @return none.
*/
void clock_32k_init (CLK_32K_TypeDef src)
{
unsigned char sel_32k = analog_read(0x2d)&0x7f;
unsigned char power_32k = analog_read(0x05)&0xfc;
analog_write(0x2d, sel_32k|(src<<7));
if(src)
{
analog_write(0x05, power_32k|0x1);//32k xtal
//2.set pc3 as pwm output
unsigned char sys_clk = read_reg8(0x66);
write_reg8(0x66,0x43);
unsigned char reg_596 = read_reg8(0x596);
write_reg8(0x596,reg_596&0xf7);
unsigned short reg_798 = read_reg16(0x798);
write_reg16(0x798,0x01);
unsigned short reg_79a = read_reg16(0x79a);
write_reg16(0x79a,0x02);
unsigned char reg_780 = read_reg8(0x780);
write_reg8(0x780,0x02);
write_reg8(0x782,0xf3);
//3.wait for PWM wake up Xtal
sleep_ms(5);
//4.Xtal 32k output
analog_write(0x03,0x4f); //<7:6>current select
//5.Recover PC3 as Xtal pin
write_reg8(0x66,sys_clk);
write_reg8(0x596,reg_596);
write_reg16(0x798,reg_798);
write_reg16(0x79a,reg_79a);
write_reg8(0x780,reg_780);
}
else
{
analog_write(0x05, power_32k|0x2);//32k rc
}
}
/**
* @brief This function performs to select 48M RC as the system clock source.
* @param[in] none.
* @return none.
*/
void rc_48m_cal (void)
{
analog_write(0x33, 0x80);
analog_write(0x30, 0x20);
analog_write(0xc7, 0x0e);
sleep_us(1000);
analog_write(0xc7, 0x0f);
while((analog_read(0xcf) & 0x80) == 0);
volatile unsigned int cal_cnt = analog_read(0xcf)&0x07 ;
cal_cnt = (cal_cnt<<8) + analog_read(0xce);
unsigned int f = 64;
unsigned int temp_v = 0;
unsigned int temp_d = 0;
unsigned int temp_d2 = 100;
unsigned char temp_cap = 0;
unsigned int i=0;
while(f>=1)
{
temp_v = analog_read(0x33);
if(cal_cnt>250)
{
temp_d = cal_cnt - 250;
}
else
{
temp_d = 250 - cal_cnt;
}
if(cal_cnt>250)
{
analog_write(0x33, temp_v-f);
}
else
{
analog_write(0x33, temp_v+f);
}
f = f/2;
analog_write(0xc7, 0x0e);
analog_write(0xc7, 0x0f);
while((analog_read(0xcf) & 0x80) == 0);
cal_cnt = analog_read(0xcf)&0x07 ;
cal_cnt = (cal_cnt<<8) + analog_read(0xce);
i++;
if(temp_d2>temp_d)
{
temp_d2 = temp_d;
temp_cap = temp_v;
}
}
analog_write(0x33, temp_cap);
}
/**
* @brief This function performs to select 24M as the system clock source.
* @param[in] none.
* @return none.
*/
void rc_24m_cal (void)
{
analog_write(0xc8, 0x80);
// sub_wr_ana(0x30, 1, 7, 7);
analog_write(0x30, analog_read(0x30) | BIT(7) );
analog_write(0xc7, 0x0e);
analog_write(0xc7, 0x0f);
while((analog_read(0xcf) & 0x80) == 0);
unsigned char cap = analog_read(0xcb);
analog_write(0x33, cap); //write 24m cap into manual register
// sub_wr_ana(0x30, 0, 7, 7); //manual on
analog_write(0x30, analog_read(0x30) & (~BIT(7)) );
analog_write(0xc7, 0x0e);
tl_24mrc_cal = analog_read(0x33);
}
/**
* @brief This function performs to select 32K as the system clock source.
* @param[in] none.
* @return none.
*/
void rc_32k_cal (void)
{
analog_write(0x30, 0x60);
analog_write(0xc6, 0xf6);
analog_write(0xc6, 0xf7);
while((analog_read(0xcf) & BIT(6)) == 0);
unsigned char res1 = analog_read(0xc9); //read 32k res[13:6]
analog_write(0x32, res1); //write 32k res[13:6] into manual register
unsigned char res2 = analog_read(0xca); //read 32k res[5:0]
analog_write(0x31, res2); //write 32k res[5:0] into manual register
analog_write(0xc6, 0xf6);
analog_write(0x30, 0x20);//manual on
}
/**
* @brief This function performs to select 32K as source of DMIC.
* @param[in] source clock to provide DMIC.
* @return none.
*/
void dmic_prob_32k(unsigned char src)
{
write_reg8(0x73,read_reg8(0x73)|0x02); // sel dmic src
write_reg8(0x73,(read_reg8(0x73)&0xfe)|src); // sel 32k src
write_reg8(0x586,read_reg8(0x586)&0xfd);
write_reg8(0x5a8,read_reg8(0x5a8)&0xf3);
}
/**
* @brief This function performs to select 24M/2 RC as source of DMIC.
* @param[in] source clock to provide DMIC.
* @return none.
*/
void dmic_prob_24M_rc()
{
//probe 24M/2 RC
//PD[5] select dmic clk
write_reg8(0x586,0x1f);
write_reg8(0x794,0x01);
write_reg8(0x796,0x02);
write_reg8(0x781,0x01);
write_reg8(0x59e,0x5b);
}