drivers/clk/clk-composite.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/clk-composite.c
Extension
.c
Size
12817 bytes
Lines
465
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 (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
			struct clk_rate_request tmp_req;

			parent = clk_hw_get_parent(mux_hw);

			clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
			ret = clk_composite_determine_rate_for_parent(rate_hw,
								      &tmp_req,
								      parent,
								      rate_ops);
			if (ret)
				return ret;

			req->rate = tmp_req.rate;
			req->best_parent_hw = tmp_req.best_parent_hw;
			req->best_parent_rate = tmp_req.best_parent_rate;

			return 0;
		}

		for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
			struct clk_rate_request tmp_req;

			parent = clk_hw_get_parent_by_index(mux_hw, i);
			if (!parent)
				continue;

			clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
			ret = clk_composite_determine_rate_for_parent(rate_hw,
								      &tmp_req,
								      parent,
								      rate_ops);
			if (ret)
				continue;

			if (req->rate >= tmp_req.rate)
				rate_diff = req->rate - tmp_req.rate;
			else
				rate_diff = tmp_req.rate - req->rate;

			if (!rate_diff || !req->best_parent_hw
				       || best_rate_diff > rate_diff) {
				req->best_parent_hw = parent;
				req->best_parent_rate = tmp_req.best_parent_rate;
				best_rate_diff = rate_diff;
				best_rate = tmp_req.rate;
			}

			if (!rate_diff)
				return 0;
		}

		req->rate = best_rate;
		return 0;
	} else if (rate_hw && rate_ops && rate_ops->determine_rate) {
		__clk_hw_set_clk(rate_hw, hw);
		return rate_ops->determine_rate(rate_hw, req);
	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
		__clk_hw_set_clk(mux_hw, hw);
		return mux_ops->determine_rate(mux_hw, req);
	} else {
		pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
		return -EINVAL;
	}
}

static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
			       unsigned long parent_rate)
{
	struct clk_composite *composite = to_clk_composite(hw);
	const struct clk_ops *rate_ops = composite->rate_ops;
	struct clk_hw *rate_hw = composite->rate_hw;

	__clk_hw_set_clk(rate_hw, hw);

	return rate_ops->set_rate(rate_hw, rate, parent_rate);
}

static int clk_composite_set_rate_and_parent(struct clk_hw *hw,
					     unsigned long rate,
					     unsigned long parent_rate,
					     u8 index)
{
	struct clk_composite *composite = to_clk_composite(hw);
	const struct clk_ops *rate_ops = composite->rate_ops;
	const struct clk_ops *mux_ops = composite->mux_ops;
	struct clk_hw *rate_hw = composite->rate_hw;
	struct clk_hw *mux_hw = composite->mux_hw;
	unsigned long temp_rate;

Annotation

Implementation Notes