drivers/clk/sunxi-ng/ccu-sun6i-rtc.c

Source file repositories/reference/linux-study-clean/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
Extension
.c
Size
10226 bytes
Lines
398
Domain
Driver Families
Bucket
drivers/clk
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sun6i_rtc_match_data {
	bool				have_ext_osc32k		: 1;
	bool				have_iosc_calibration	: 1;
	bool				rtc_32k_single_parent	: 1;
	const struct clk_parent_data	*osc32k_fanout_parents;
	u8				osc32k_fanout_nparents;
};

static bool have_iosc_calibration;

static int ccu_iosc_enable(struct clk_hw *hw)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);

	return ccu_gate_helper_enable(cm, DCXO_CTRL_CLK16M_RC_EN);
}

static void ccu_iosc_disable(struct clk_hw *hw)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);

	return ccu_gate_helper_disable(cm, DCXO_CTRL_CLK16M_RC_EN);
}

static int ccu_iosc_is_enabled(struct clk_hw *hw)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);

	return ccu_gate_helper_is_enabled(cm, DCXO_CTRL_CLK16M_RC_EN);
}

static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
					  unsigned long parent_rate)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);

	if (have_iosc_calibration) {
		u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);

		/*
		 * Recover the IOSC frequency by shifting the ones place of
		 * (fixed-point divider * 32768) into bit zero.
		 */
		if (reg & IOSC_CLK_CALI_EN)
			return reg >> (IOSC_CLK_CALI_DIV_ONES - LOSC_RATE_SHIFT);
	}

	return IOSC_RATE;
}

static unsigned long ccu_iosc_recalc_accuracy(struct clk_hw *hw,
					      unsigned long parent_accuracy)
{
	return IOSC_ACCURACY;
}

static const struct clk_ops ccu_iosc_ops = {
	.enable			= ccu_iosc_enable,
	.disable		= ccu_iosc_disable,
	.is_enabled		= ccu_iosc_is_enabled,
	.recalc_rate		= ccu_iosc_recalc_rate,
	.recalc_accuracy	= ccu_iosc_recalc_accuracy,
};

static struct ccu_common iosc_clk = {
	.reg		= DCXO_CTRL_REG,
	.hw.init	= CLK_HW_INIT_NO_PARENT("iosc", &ccu_iosc_ops,
						CLK_GET_RATE_NOCACHE),
};

static int ccu_iosc_32k_prepare(struct clk_hw *hw)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);
	u32 val;

	if (!have_iosc_calibration)
		return 0;

	val = readl(cm->base + IOSC_CLK_CALI_REG);
	writel(val | IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL,
	       cm->base + IOSC_CLK_CALI_REG);

	return 0;
}

static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
{
	struct ccu_common *cm = hw_to_ccu_common(hw);
	u32 val;

Annotation

Implementation Notes