rt-thread/bsp/allwinner/libraries/sunxi-hal/hal/source/ccmu/sunxi-ng/ccu-sun8iw20-rtc.c

140 lines
4.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* sunxi RTC ccu driver
*
* Copyright (c) 2020, DaLv <lvda@allwinnertech.com>
*/
#include "ccu.h"
#include "ccu_common.h"
#include "ccu_reset.h"
#include "ccu_div.h"
#include "ccu_gate.h"
#include "ccu_mp.h"
#include "ccu_mult.h"
#include "ccu_nk.h"
#include "ccu_nkm.h"
#include "ccu_nkmp.h"
#include "ccu_nm.h"
#include "ccu_phase.h"
#include "ccu-sun8iw20-rtc.h"
/*
* iosc clk:
*/
static SUNXI_CCU_GATE(iosc_clk, "iosc", "rc-16m", 0x160, BIT(0), 0);
static SUNXI_CCU_GATE_WITH_KEY(ext32k_gate_clk, "ext32k-gate",
"ext-32k", 0x0,
KEY_FIELD_MAGIC_NUM_RTC,
BIT(4), 0);
static CLK_FIXED_FACTOR(iosc_div32k_clk, "iosc-div32k", "iosc", 500, 1, 0);
/*
* osc32k clk(losc)
*/
static const char *const osc32k_parents[] = { "iosc-div32k", "ext32k-gate" };
static SUNXI_CCU_MUX_WITH_GATE_KEY(osc32k_clk, "osc32k", osc32k_parents,
0x0, 0, 1,
KEY_FIELD_MAGIC_NUM_RTC, 0, 0);
static SUNXI_CCU_GATE_WITH_FIXED_RATE(dcxo24M_div32k_clk, "dcxo24M-div32k",
"dcxo24M", 0x60,
32768, BIT(16));
/*
* rtc-1k clock
*/
static const char *const rtc32k_clk_parents[] = { "osc32k", "dcxo24M-div32k"};
static SUNXI_CCU_MUX_WITH_GATE_KEY(rtc32k_clk, "rtc32k", rtc32k_clk_parents,
0x0, 1, 1,
KEY_FIELD_MAGIC_NUM_RTC, 0, 0);
static CLK_FIXED_FACTOR(rtc_1k_clk, "rtc-1k", "rtc32k", 32, 1, 0);
/* rtc-32k-fanout: only for debug */
static const char *const rtc_32k_fanout_clk_parents[] = { "osc32k", "ext32k-gate",
"dcxo24M-div32k"
};
static SUNXI_CCU_MUX_WITH_GATE(rtc_32k_fanout_clk, "rtc-32k-fanout",
rtc_32k_fanout_clk_parents, 0x60, 1,
2, BIT(0), 0);
/* TODO: should add the div func */
static SUNXI_CCU_GATE(rtc_spi_clk, "rtc-spi", "r-ahb", 0x310, BIT(31), 0);
static struct ccu_common *sun8iw20_rtc_ccu_clks[] =
{
&iosc_clk.common,
&ext32k_gate_clk.common,
&osc32k_clk.common,
&dcxo24M_div32k_clk.common,
&rtc32k_clk.common,
&rtc_32k_fanout_clk.common,
&rtc_spi_clk.common,
};
static struct clk_hw_onecell_data sun8iw20_rtc_ccu_hw_clks =
{
.hws = {
[CLK_IOSC] = &iosc_clk.common.hw,
[CLK_EXT32K_GATE] = &ext32k_gate_clk.common.hw,
[CLK_IOSC_DIV32K] = &iosc_div32k_clk.hw,
[CLK_OSC32K] = &osc32k_clk.common.hw,
[CLK_DCXO24M_DIV32K] = &dcxo24M_div32k_clk.common.hw,
[CLK_RTC32K] = &rtc32k_clk.common.hw,
[CLK_RTC_1K] = &rtc_1k_clk.hw,
[CLK_RTC_32K_FANOUT] = &rtc_32k_fanout_clk.common.hw,
[CLK_RTC_SPI] = &rtc_spi_clk.common.hw,
},
.num = CLK_RTC_NUMBER,
};
static const struct sunxi_ccu_desc sun8iw20_rtc_ccu_desc =
{
.ccu_clks = sun8iw20_rtc_ccu_clks,
.num_ccu_clks = ARRAY_SIZE(sun8iw20_rtc_ccu_clks),
.hw_clks = &sun8iw20_rtc_ccu_hw_clks,
.clk_type = HAL_SUNXI_RTC_CCU,
};
static void clock_source_init(unsigned long base)
{
/* (1) enable DCXO */
/* by default, DCXO_EN = 1. We don't have to do this... */
set_reg(base + XO_CTRL_REG, 0x1, 1, 1);
/* (2) enable auto switch function */
/*
* In some cases, we boot with auto switch function disabled, and try to
* enable the auto switch function by rebooting.
* But the rtc default value does not change unless vcc-rtc is loss.
* So we should not rely on the default value of reg.
* BIT(14): LOSC auto switch 32k clk source sel enable. 1: enable
* BIT(15): LOSC auto switch function disable. 1: disable
*/
set_reg_key(base + LOSC_CTRL_REG,
KEY_FIELD_MAGIC_NUM_RTC >> 16, 16, 16,
0x1, 2, 14);
/* (3) set the parent of osc32k-sys to ext-osc32k */
set_reg_key(base + LOSC_CTRL_REG,
KEY_FIELD_MAGIC_NUM_RTC >> 16, 16, 16,
0x1, 1, 0);
/* (4) set the parent of osc32k-out to osc32k-sys */
/* by default, LOSC_OUT_SRC_SEL = 0x0. We don't have to do this... */
set_reg(base + LOSC_OUT_GATING_REG,
0x0, 2, 1);
}
int sunxi_rtc_ccu_init(void)
{
unsigned long reg = (unsigned long)SUNXI_RTC_CCU_REG;
clock_source_init(reg);
return ccu_common_init(reg, &sun8iw20_rtc_ccu_desc);
}