diff options
author | Yuchen Huang <yuchen.huang@mediatek.corp-partner.google.com> | 2020-08-18 16:29:29 +0800 |
---|---|---|
committer | Hung-Te Lin <hungte@chromium.org> | 2020-12-28 13:39:01 +0000 |
commit | b0ab41e0279e47d3bb09d6cddc803686859e6985 (patch) | |
tree | 08b5681adc26bbf5500b5727a24729424625d840 /src/soc/mediatek/common/rtc_osc_init.c | |
parent | 87c30a064c33071d4494c03c34abf2cdea6ff850 (diff) |
soc/mediatek/mt8192: add rtc MT6359P driver
Add rtc MT6359P driver for rtc init and rtc eosc calibration. Refactor
mt8173 and mt8183 code by extracting common API. Move rtc_read and
rtc_write to each SoC folder, because mt8173 and mt8183 access rtc via
pmic wrapper, while mt8192 accesses it via pmif.
Reference datasheet:
Document No: RH-D-2018-0101.
Signed-off-by: Yuchen Huang <yuchen.huang@mediatek.corp-partner.google.com>
Change-Id: I57d6738fdec148c7458b2024a0a8225415ca2f3e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/46395
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Diffstat (limited to 'src/soc/mediatek/common/rtc_osc_init.c')
-rw-r--r-- | src/soc/mediatek/common/rtc_osc_init.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/soc/mediatek/common/rtc_osc_init.c b/src/soc/mediatek/common/rtc_osc_init.c new file mode 100644 index 0000000000..521e7a0981 --- /dev/null +++ b/src/soc/mediatek/common/rtc_osc_init.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <soc/rtc.h> +#include <soc/rtc_common.h> + +/* 32k clock calibration */ +static int rtc_eosc_cali(void) +{ + u16 diff_left, diff_right, cksel; + u16 val = 0; + u16 middle; + u16 left = RTC_XOSCCALI_START; + u16 right = RTC_XOSCCALI_END; + + rtc_read(PMIC_RG_FQMTR_CKSEL, &cksel); + cksel &= ~PMIC_FQMTR_CKSEL_MASK; + /* select EOSC_32 as fixed clock */ + rtc_write(PMIC_RG_FQMTR_CKSEL, cksel | PMIC_FQMTR_FIX_CLK_EOSC_32K); + rtc_read(PMIC_RG_FQMTR_CKSEL, &cksel); + rtc_info("PMIC_RG_FQMTR_CKSEL=%#x\n", cksel); + + while (left <= right) { + middle = (right + left) / 2; + if (middle == left) + break; + + /* select 26M as target clock */ + val = rtc_get_frequency_meter(middle, PMIC_FQMTR_CON0_FQM26M_CK, 0); + if (val >= RTC_FQMTR_LOW_BASE && val <= RTC_FQMTR_HIGH_BASE) + break; + + if (val > RTC_FQMTR_HIGH_BASE) + right = middle; + else + left = middle; + } + + if (val >= RTC_FQMTR_LOW_BASE && val <= RTC_FQMTR_HIGH_BASE) + return middle; + + val = rtc_get_frequency_meter(left, PMIC_FQMTR_CON0_FQM26M_CK, 0); + diff_left = ABS(val - RTC_FQMTR_LOW_BASE); + + val = rtc_get_frequency_meter(right, PMIC_FQMTR_CON0_FQM26M_CK, 0); + diff_right = ABS(val - RTC_FQMTR_LOW_BASE); + + rtc_info("left: %d, middle: %d, right: %d\n", left, middle, right); + if (diff_left < diff_right) + return left; + else + return right; +} + +void rtc_osc_init(void) +{ + u16 osc32con; + + /* enable 32K export */ + rtc_gpio_init(); + /* calibrate eosc32 for powerdown clock */ + rtc_read(RTC_OSC32CON, &osc32con); + rtc_info("osc32con val = %#x\n", osc32con); + osc32con &= ~RTC_XOSCCALI_MASK; + osc32con |= rtc_eosc_cali() & RTC_XOSCCALI_MASK; + rtc_xosc_write(osc32con); + rtc_info("EOSC32 cali val = %#x\n", osc32con); +} |