drivers/clk/sunxi-ng/ccu_nkm.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi-ng/ccu_nkm.c
Extension
.c
Size
6782 bytes
Lines
272
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

struct _ccu_nkm {
	unsigned long	n, min_n, max_n;
	unsigned long	k, min_k, max_k;
	unsigned long	m, min_m, max_m;
};

static bool ccu_nkm_is_valid_rate(struct ccu_common *common, unsigned long parent,
				  unsigned long n, unsigned long m)
{
	struct ccu_nkm *nkm = container_of(common, struct ccu_nkm, common);

	if (nkm->max_m_n_ratio && (m > nkm->max_m_n_ratio * n))
		return false;

	if (nkm->min_parent_m_ratio && (parent < nkm->min_parent_m_ratio * m))
		return false;

	return true;
}

static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common,
						       struct clk_hw *parent_hw,
						       unsigned long *parent, unsigned long rate,
						       struct _ccu_nkm *nkm)
{
	unsigned long best_rate = 0, best_parent_rate = *parent;
	unsigned long best_n = 0, best_k = 0, best_m = 0;
	unsigned long _n, _k, _m;

	for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
		for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
			for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
				unsigned long tmp_rate, tmp_parent;

				tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k));

				if (!ccu_nkm_is_valid_rate(common, tmp_parent, _n, _m))
					continue;

				tmp_rate = tmp_parent * _n * _k / _m;

				if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) ||
				    (tmp_parent == *parent && tmp_rate == best_rate)) {
					best_rate = tmp_rate;
					best_parent_rate = tmp_parent;
					best_n = _n;
					best_k = _k;
					best_m = _m;
				}
			}
		}
	}

	nkm->n = best_n;
	nkm->k = best_k;
	nkm->m = best_m;

	*parent = best_parent_rate;

	return best_rate;
}

static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
				       struct _ccu_nkm *nkm, struct ccu_common *common)
{
	unsigned long best_rate = 0;
	unsigned long best_n = 0, best_k = 0, best_m = 0;
	unsigned long _n, _k, _m;

	for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
		for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
			for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
				if (!ccu_nkm_is_valid_rate(common, parent, _n, _m))
					continue;

				unsigned long tmp_rate;

				tmp_rate = parent * _n * _k / _m;

				if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) {
					best_rate = tmp_rate;
					best_n = _n;
					best_k = _k;
					best_m = _m;
				}
			}
		}
	}

	nkm->n = best_n;

Annotation

Implementation Notes