drivers/clk/sophgo/clk-sg2042-clkgen.c

Source file repositories/reference/linux-study-clean/drivers/clk/sophgo/clk-sg2042-clkgen.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sophgo/clk-sg2042-clkgen.c
Extension
.c
Size
37294 bytes
Lines
1149
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 sg2042_divider_clock {
	struct clk_hw hw;

	unsigned int id;

	void __iomem *reg;
	/* protect register access */
	spinlock_t *lock;

	u32 offset_ctrl;
	u8 shift;
	u8 width;
	u8 div_flags;
	u32 initval;
};

#define to_sg2042_clk_divider(_hw)	\
	container_of(_hw, struct sg2042_divider_clock, hw)

/**
 * struct sg2042_gate_clock - Gate clock
 * @hw:			clk_hw for initialization
 * @id:			used to map clk_onecell_data
 * @offset_enable:	offset of gate enable registers
 * @bit_idx:		which bit in the register controls gating of this clock
 */
struct sg2042_gate_clock {
	struct clk_hw hw;

	unsigned int id;

	u32 offset_enable;
	u8 bit_idx;
};

/**
 * struct sg2042_mux_clock - Mux clock
 * @hw:			clk_hw for initialization
 * @id:			used to map clk_onecell_data
 * @offset_select:	offset of mux selection registers
 *			**NOTE**: MUX registers are ALL in CLOCK!
 * @shift:		shift of "Clock Select" in mux selection register
 * @width:		width of "Clock Select" in mux selection register
 * @clk_nb:		used for notification
 * @original_index:	set by notifier callback
 */
struct sg2042_mux_clock {
	struct clk_hw hw;

	unsigned int id;

	u32 offset_select;
	u8 shift;
	u8 width;

	struct notifier_block clk_nb;
	u8 original_index;
};

#define to_sg2042_mux_nb(_nb) container_of(_nb, struct sg2042_mux_clock, clk_nb)

static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw *hw,
						    unsigned long parent_rate)
{
	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
	unsigned long ret_rate;
	u32 val;

	if (!(readl(divider->reg) & BIT(SHIFT_DIV_FACTOR_SEL))) {
		val = divider->initval;
	} else {
		val = readl(divider->reg) >> divider->shift;
		val &= clk_div_mask(divider->width);
	}

	ret_rate = divider_recalc_rate(hw, parent_rate, val, NULL,
				       divider->div_flags, divider->width);

	pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n",
		 clk_hw_get_name(hw), ret_rate);
	return ret_rate;
}

static int sg2042_clk_divider_determine_rate(struct clk_hw *hw,
					     struct clk_rate_request *req)
{
	struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
	u32 bestdiv;

	/* if read only, just return current value */

Annotation

Implementation Notes