drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

Source file repositories/reference/linux-study-clean/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
Extension
.c
Size
6350 bytes
Lines
289
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 tcon_ch1_clk {
	struct clk_hw	hw;
	spinlock_t	lock;
	void __iomem	*reg;
};

#define hw_to_tclk(hw)	container_of(hw, struct tcon_ch1_clk, hw)

static void tcon_ch1_disable(struct clk_hw *hw)
{
	struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
	unsigned long flags;
	u32 reg;

	spin_lock_irqsave(&tclk->lock, flags);
	reg = readl(tclk->reg);
	reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
	writel(reg, tclk->reg);
	spin_unlock_irqrestore(&tclk->lock, flags);
}

static int tcon_ch1_enable(struct clk_hw *hw)
{
	struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
	unsigned long flags;
	u32 reg;

	spin_lock_irqsave(&tclk->lock, flags);
	reg = readl(tclk->reg);
	reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT;
	writel(reg, tclk->reg);
	spin_unlock_irqrestore(&tclk->lock, flags);

	return 0;
}

static int tcon_ch1_is_enabled(struct clk_hw *hw)
{
	struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
	u32 reg;

	reg = readl(tclk->reg);
	return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
}

static u8 tcon_ch1_get_parent(struct clk_hw *hw)
{
	struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
	u32 reg;

	reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT;
	reg &= reg >> TCON_CH1_SCLK2_MUX_MASK;

	return reg;
}

static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index)
{
	struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
	unsigned long flags;
	u32 reg;

	spin_lock_irqsave(&tclk->lock, flags);
	reg = readl(tclk->reg);
	reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT);
	reg |= index << TCON_CH1_SCLK2_MUX_SHIFT;
	writel(reg, tclk->reg);
	spin_unlock_irqrestore(&tclk->lock, flags);

	return 0;
};

static unsigned long tcon_ch1_calc_divider(unsigned long rate,
					   unsigned long parent_rate,
					   u8 *div,
					   bool *half)
{
	unsigned long best_rate = 0;
	u8 best_m = 0, m;
	bool is_double;

	for (m = 1; m < 16; m++) {
		u8 d;

		for (d = 1; d < 3; d++) {
			unsigned long tmp_rate;

			tmp_rate = parent_rate / m / d;

			if (tmp_rate > rate)

Annotation

Implementation Notes