drivers/clk/sunxi-ng/ccu_mp.c

Source file repositories/reference/linux-study-clean/drivers/clk/sunxi-ng/ccu_mp.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi-ng/ccu_mp.c
Extension
.c
Size
8966 bytes
Lines
362
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 ((rate - tmp_rate) < (rate - best_rate)) {
				best_rate = tmp_rate;
				best_m = _m;
				best_p = _p;
			}
		}
	}

	*m = best_m;
	*p = best_p;

	return best_rate;
}

static unsigned long ccu_mp_find_best_with_parent_adj(struct clk_hw *hw,
						      unsigned long *parent,
						      unsigned long rate,
						      unsigned int max_m,
						      unsigned int max_p,
						      bool shift)
{
	unsigned long parent_rate_saved;
	unsigned long parent_rate, now;
	unsigned long best_rate = 0;
	unsigned int _m, _p, div;
	unsigned long maxdiv;

	parent_rate_saved = *parent;

	/*
	 * The maximum divider we can use without overflowing
	 * unsigned long in rate * m * p below
	 */
	maxdiv = max_m * max_p;
	maxdiv = min(ULONG_MAX / rate, maxdiv);

	for (_p = 1; _p <= max_p; _p = next_div(_p, shift)) {
		for (_m = 1; _m <= max_m; _m++) {
			div = _m * _p;

			if (div > maxdiv)
				break;

			if (rate * div == parent_rate_saved) {
				/*
				 * It's the most ideal case if the requested
				 * rate can be divided from parent clock without
				 * needing to change parent rate, so return the
				 * divider immediately.
				 */
				*parent = parent_rate_saved;
				return rate;
			}

			parent_rate = clk_hw_round_rate(hw, rate * div);
			now = parent_rate / div;

			if (now <= rate && now > best_rate) {
				best_rate = now;
				*parent = parent_rate;

				if (now == rate)
					return rate;
			}
		}
	}

	return best_rate;
}

static int ccu_mp_determine_rate_helper(struct ccu_mux_internal *mux,
					struct clk_rate_request *req,
					void *data)
{
	struct ccu_mp *cmp = data;
	unsigned int max_m, max_p;
	unsigned int m, p;
	bool shift = true;

	if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
		req->rate *= cmp->fixed_post_div;

	if (cmp->common.features & CCU_FEATURE_DUAL_DIV)
		shift = false;

	max_m = cmp->m.max ?: 1 << cmp->m.width;
	if (shift)
		max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
	else
		max_p = cmp->p.max ?: 1 << cmp->p.width;

Annotation

Implementation Notes