drivers/clk/imx/clk-composite-8m.c

Source file repositories/reference/linux-study-clean/drivers/clk/imx/clk-composite-8m.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/imx/clk-composite-8m.c
Extension
.c
Size
7301 bytes
Lines
303
Domain
Driver Families
Bucket
drivers/clk
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (abs(new_error) < abs(error)) {
				*prediv = div1;
				*postdiv = div2;
				error = new_error;
				ret = 0;
			}
		}
	}
	return ret;
}

static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
					unsigned long rate,
					unsigned long parent_rate)
{
	struct clk_divider *divider = to_clk_divider(hw);
	unsigned long flags;
	int prediv_value;
	int div_value;
	int ret;
	u32 orig, val;

	ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
						&prediv_value, &div_value);
	if (ret)
		return -EINVAL;

	spin_lock_irqsave(divider->lock, flags);

	orig = readl(divider->reg);
	val = orig & ~((clk_div_mask(divider->width) << divider->shift) |
		       (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));

	val |= (u32)(prediv_value  - 1) << divider->shift;
	val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;

	if (val != orig)
		writel(val, divider->reg);

	spin_unlock_irqrestore(divider->lock, flags);

	return ret;
}

static int imx8m_divider_determine_rate(struct clk_hw *hw,
				      struct clk_rate_request *req)
{
	struct clk_divider *divider = to_clk_divider(hw);
	int prediv_value;
	int div_value;

	/* if read only, just return current value */
	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
		u32 val;

		val = readl(divider->reg);
		prediv_value = val >> divider->shift;
		prediv_value &= clk_div_mask(divider->width);
		prediv_value++;

		div_value = val >> PCG_DIV_SHIFT;
		div_value &= clk_div_mask(PCG_DIV_WIDTH);
		div_value++;

		return divider_ro_determine_rate(hw, req, divider->table,
						 PCG_PREDIV_WIDTH + PCG_DIV_WIDTH,
						 divider->flags, prediv_value * div_value);
	}

	return divider_determine_rate(hw, req, divider->table,
				      PCG_PREDIV_WIDTH + PCG_DIV_WIDTH,
				      divider->flags);
}

static const struct clk_ops imx8m_clk_composite_divider_ops = {
	.recalc_rate = imx8m_clk_composite_divider_recalc_rate,
	.set_rate = imx8m_clk_composite_divider_set_rate,
	.determine_rate = imx8m_divider_determine_rate,
};

static u8 imx8m_clk_composite_mux_get_parent(struct clk_hw *hw)
{
	return clk_mux_ops.get_parent(hw);
}

static int imx8m_clk_composite_mux_set_parent(struct clk_hw *hw, u8 index)
{
	struct clk_mux *mux = to_clk_mux(hw);
	u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
	unsigned long flags = 0;

Annotation

Implementation Notes