drivers/opp/of.c

Source file repositories/reference/linux-study-clean/drivers/opp/of.c

File Facts

System
Linux kernel
Corpus path
drivers/opp/of.c
Extension
.c
Size
40677 bytes
Lines
1599
Domain
Driver Families
Bucket
drivers/opp
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 (opp_table->np == np) {
			/*
			 * Multiple devices can point to the same OPP table and
			 * so will have same node-pointer, np.
			 *
			 * But the OPPs will be considered as shared only if the
			 * OPP table contains a "opp-shared" property.
			 */
			if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED)
				managed_table = dev_pm_opp_get_opp_table_ref(opp_table);

			break;
		}
	}

	return managed_table;
}

/* The caller must call dev_pm_opp_put() after the OPP is used */
static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
					  struct device_node *opp_np)
{
	struct dev_pm_opp *opp;

	guard(mutex)(&opp_table->lock);

	list_for_each_entry(opp, &opp_table->opp_list, node) {
		if (opp->np == opp_np)
			return dev_pm_opp_get(opp);
	}

	return NULL;
}

static struct device_node *of_parse_required_opp(struct device_node *np,
						 int index)
{
	return of_parse_phandle(np, "required-opps", index);
}

/* The caller must call dev_pm_opp_put_opp_table() after the table is used */
static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
{
	struct opp_table *opp_table;

	struct device_node *opp_table_np __free(device_node) =
		of_get_parent(opp_np);

	if (!opp_table_np)
		return ERR_PTR(-ENODEV);

	guard(mutex)(&opp_table_lock);

	list_for_each_entry(opp_table, &opp_tables, node) {
		if (opp_table_np == opp_table->np)
			return dev_pm_opp_get_opp_table_ref(opp_table);
	}

	return ERR_PTR(-ENODEV);
}

/* Free resources previously acquired by _opp_table_alloc_required_tables() */
static void _opp_table_free_required_tables(struct opp_table *opp_table)
{
	struct opp_table **required_opp_tables = opp_table->required_opp_tables;
	int i;

	if (!required_opp_tables)
		return;

	for (i = 0; i < opp_table->required_opp_count; i++) {
		if (IS_ERR_OR_NULL(required_opp_tables[i]))
			continue;

		dev_pm_opp_put_opp_table(required_opp_tables[i]);
	}

	kfree(required_opp_tables);

	opp_table->required_opp_count = 0;
	opp_table->required_opp_tables = NULL;

	guard(mutex)(&opp_table_lock);
	list_del(&opp_table->lazy);
}

/*
 * Populate all devices and opp tables which are part of "required-opps" list.
 * Checking only the first OPP node should be enough.
 */

Annotation

Implementation Notes