162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Generic OPP Interface
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009-2010 Texas Instruments Incorporated.
662306a36Sopenharmony_ci *	Nishanth Menon
762306a36Sopenharmony_ci *	Romit Dasgupta
862306a36Sopenharmony_ci *	Kevin Hilman
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/device.h>
1762306a36Sopenharmony_ci#include <linux/export.h>
1862306a36Sopenharmony_ci#include <linux/pm_domain.h>
1962306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/xarray.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "opp.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * The root of the list of all opp-tables. All opp_table structures branch off
2762306a36Sopenharmony_ci * from here, with each opp_table containing the list of opps it supports in
2862306a36Sopenharmony_ci * various states of availability.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ciLIST_HEAD(opp_tables);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Lock to allow exclusive modification to the device and opp lists */
3362306a36Sopenharmony_ciDEFINE_MUTEX(opp_table_lock);
3462306a36Sopenharmony_ci/* Flag indicating that opp_tables list is being updated at the moment */
3562306a36Sopenharmony_cistatic bool opp_tables_busy;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* OPP ID allocator */
3862306a36Sopenharmony_cistatic DEFINE_XARRAY_ALLOC1(opp_configs);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic bool _find_opp_dev(const struct device *dev, struct opp_table *opp_table)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct opp_device *opp_dev;
4362306a36Sopenharmony_ci	bool found = false;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
4662306a36Sopenharmony_ci	list_for_each_entry(opp_dev, &opp_table->dev_list, node)
4762306a36Sopenharmony_ci		if (opp_dev->dev == dev) {
4862306a36Sopenharmony_ci			found = true;
4962306a36Sopenharmony_ci			break;
5062306a36Sopenharmony_ci		}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
5362306a36Sopenharmony_ci	return found;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic struct opp_table *_find_opp_table_unlocked(struct device *dev)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct opp_table *opp_table;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	list_for_each_entry(opp_table, &opp_tables, node) {
6162306a36Sopenharmony_ci		if (_find_opp_dev(dev, opp_table)) {
6262306a36Sopenharmony_ci			_get_opp_table_kref(opp_table);
6362306a36Sopenharmony_ci			return opp_table;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/**
7162306a36Sopenharmony_ci * _find_opp_table() - find opp_table struct using device pointer
7262306a36Sopenharmony_ci * @dev:	device pointer used to lookup OPP table
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Search OPP table for one containing matching device.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
7762306a36Sopenharmony_ci * -EINVAL based on type of error.
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * The callers must call dev_pm_opp_put_opp_table() after the table is used.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistruct opp_table *_find_opp_table(struct device *dev)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct opp_table *opp_table;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev)) {
8662306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
8762306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	mutex_lock(&opp_table_lock);
9162306a36Sopenharmony_ci	opp_table = _find_opp_table_unlocked(dev);
9262306a36Sopenharmony_ci	mutex_unlock(&opp_table_lock);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return opp_table;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * Returns true if multiple clocks aren't there, else returns false with WARN.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * We don't force clk_count == 1 here as there are users who don't have a clock
10162306a36Sopenharmony_ci * representation in the OPP table and manage the clock configuration themselves
10262306a36Sopenharmony_ci * in an platform specific way.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cistatic bool assert_single_clk(struct opp_table *opp_table)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return !WARN_ON(opp_table->clk_count > 1);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
11162306a36Sopenharmony_ci * @opp:	opp for which voltage has to be returned for
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci * Return: voltage in micro volt corresponding to the opp, else
11462306a36Sopenharmony_ci * return 0
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * This is useful only for devices with single power supply.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_ciunsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp)) {
12162306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
12262306a36Sopenharmony_ci		return 0;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return opp->supplies[0].u_volt;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci * dev_pm_opp_get_supplies() - Gets the supply information corresponding to an opp
13162306a36Sopenharmony_ci * @opp:	opp for which voltage has to be returned for
13262306a36Sopenharmony_ci * @supplies:	Placeholder for copying the supply information.
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * Return: negative error number on failure, 0 otherwise on success after
13562306a36Sopenharmony_ci * setting @supplies.
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * This can be used for devices with any number of power supplies. The caller
13862306a36Sopenharmony_ci * must ensure the @supplies array must contain space for each regulator.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_ciint dev_pm_opp_get_supplies(struct dev_pm_opp *opp,
14162306a36Sopenharmony_ci			    struct dev_pm_opp_supply *supplies)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp) || !supplies) {
14462306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
14562306a36Sopenharmony_ci		return -EINVAL;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	memcpy(supplies, opp->supplies,
14962306a36Sopenharmony_ci	       sizeof(*supplies) * opp->opp_table->regulator_count);
15062306a36Sopenharmony_ci	return 0;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_supplies);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * dev_pm_opp_get_power() - Gets the power corresponding to an opp
15662306a36Sopenharmony_ci * @opp:	opp for which power has to be returned for
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * Return: power in micro watt corresponding to the opp, else
15962306a36Sopenharmony_ci * return 0
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * This is useful only for devices with single power supply.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ciunsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	unsigned long opp_power = 0;
16662306a36Sopenharmony_ci	int i;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp)) {
16962306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
17062306a36Sopenharmony_ci		return 0;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	for (i = 0; i < opp->opp_table->regulator_count; i++)
17362306a36Sopenharmony_ci		opp_power += opp->supplies[i].u_watt;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return opp_power;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_power);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/**
18062306a36Sopenharmony_ci * dev_pm_opp_get_freq_indexed() - Gets the frequency corresponding to an
18162306a36Sopenharmony_ci *				   available opp with specified index
18262306a36Sopenharmony_ci * @opp: opp for which frequency has to be returned for
18362306a36Sopenharmony_ci * @index: index of the frequency within the required opp
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * Return: frequency in hertz corresponding to the opp with specified index,
18662306a36Sopenharmony_ci * else return 0
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_ciunsigned long dev_pm_opp_get_freq_indexed(struct dev_pm_opp *opp, u32 index)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp) || index >= opp->opp_table->clk_count) {
19162306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
19262306a36Sopenharmony_ci		return 0;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return opp->rates[index];
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_freq_indexed);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/**
20062306a36Sopenharmony_ci * dev_pm_opp_get_level() - Gets the level corresponding to an available opp
20162306a36Sopenharmony_ci * @opp:	opp for which level value has to be returned for
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Return: level read from device tree corresponding to the opp, else
20462306a36Sopenharmony_ci * return 0.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_ciunsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp) || !opp->available) {
20962306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
21062306a36Sopenharmony_ci		return 0;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return opp->level;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_level);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/**
21862306a36Sopenharmony_ci * dev_pm_opp_get_required_pstate() - Gets the required performance state
21962306a36Sopenharmony_ci *                                    corresponding to an available opp
22062306a36Sopenharmony_ci * @opp:	opp for which performance state has to be returned for
22162306a36Sopenharmony_ci * @index:	index of the required opp
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * Return: performance state read from device tree corresponding to the
22462306a36Sopenharmony_ci * required opp, else return 0.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_ciunsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
22762306a36Sopenharmony_ci					    unsigned int index)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp) || !opp->available ||
23062306a36Sopenharmony_ci	    index >= opp->opp_table->required_opp_count) {
23162306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
23262306a36Sopenharmony_ci		return 0;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* required-opps not fully initialized yet */
23662306a36Sopenharmony_ci	if (lazy_linking_pending(opp->opp_table))
23762306a36Sopenharmony_ci		return 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* The required OPP table must belong to a genpd */
24062306a36Sopenharmony_ci	if (unlikely(!opp->opp_table->required_opp_tables[index]->is_genpd)) {
24162306a36Sopenharmony_ci		pr_err("%s: Performance state is only valid for genpds.\n", __func__);
24262306a36Sopenharmony_ci		return 0;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return opp->required_opps[index]->level;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_required_pstate);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/**
25062306a36Sopenharmony_ci * dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not
25162306a36Sopenharmony_ci * @opp: opp for which turbo mode is being verified
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci * Turbo OPPs are not for normal use, and can be enabled (under certain
25462306a36Sopenharmony_ci * conditions) for short duration of times to finish high throughput work
25562306a36Sopenharmony_ci * quickly. Running on them for longer times may overheat the chip.
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Return: true if opp is turbo opp, else false.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cibool dev_pm_opp_is_turbo(struct dev_pm_opp *opp)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(opp) || !opp->available) {
26262306a36Sopenharmony_ci		pr_err("%s: Invalid parameters\n", __func__);
26362306a36Sopenharmony_ci		return false;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return opp->turbo;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/**
27162306a36Sopenharmony_ci * dev_pm_opp_get_max_clock_latency() - Get max clock latency in nanoseconds
27262306a36Sopenharmony_ci * @dev:	device for which we do this operation
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * Return: This function returns the max clock latency in nanoseconds.
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_ciunsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct opp_table *opp_table;
27962306a36Sopenharmony_ci	unsigned long clock_latency_ns;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
28262306a36Sopenharmony_ci	if (IS_ERR(opp_table))
28362306a36Sopenharmony_ci		return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	clock_latency_ns = opp_table->clock_latency_ns_max;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return clock_latency_ns;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
29562306a36Sopenharmony_ci * @dev: device for which we do this operation
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * Return: This function returns the max voltage latency in nanoseconds.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_ciunsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct opp_table *opp_table;
30262306a36Sopenharmony_ci	struct dev_pm_opp *opp;
30362306a36Sopenharmony_ci	struct regulator *reg;
30462306a36Sopenharmony_ci	unsigned long latency_ns = 0;
30562306a36Sopenharmony_ci	int ret, i, count;
30662306a36Sopenharmony_ci	struct {
30762306a36Sopenharmony_ci		unsigned long min;
30862306a36Sopenharmony_ci		unsigned long max;
30962306a36Sopenharmony_ci	} *uV;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
31262306a36Sopenharmony_ci	if (IS_ERR(opp_table))
31362306a36Sopenharmony_ci		return 0;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Regulator may not be required for the device */
31662306a36Sopenharmony_ci	if (!opp_table->regulators)
31762306a36Sopenharmony_ci		goto put_opp_table;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	count = opp_table->regulator_count;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
32262306a36Sopenharmony_ci	if (!uV)
32362306a36Sopenharmony_ci		goto put_opp_table;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
32862306a36Sopenharmony_ci		uV[i].min = ~0;
32962306a36Sopenharmony_ci		uV[i].max = 0;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		list_for_each_entry(opp, &opp_table->opp_list, node) {
33262306a36Sopenharmony_ci			if (!opp->available)
33362306a36Sopenharmony_ci				continue;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci			if (opp->supplies[i].u_volt_min < uV[i].min)
33662306a36Sopenharmony_ci				uV[i].min = opp->supplies[i].u_volt_min;
33762306a36Sopenharmony_ci			if (opp->supplies[i].u_volt_max > uV[i].max)
33862306a36Sopenharmony_ci				uV[i].max = opp->supplies[i].u_volt_max;
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * The caller needs to ensure that opp_table (and hence the regulator)
34662306a36Sopenharmony_ci	 * isn't freed, while we are executing this routine.
34762306a36Sopenharmony_ci	 */
34862306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
34962306a36Sopenharmony_ci		reg = opp_table->regulators[i];
35062306a36Sopenharmony_ci		ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
35162306a36Sopenharmony_ci		if (ret > 0)
35262306a36Sopenharmony_ci			latency_ns += ret * 1000;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	kfree(uV);
35662306a36Sopenharmony_ciput_opp_table:
35762306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return latency_ns;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/**
36462306a36Sopenharmony_ci * dev_pm_opp_get_max_transition_latency() - Get max transition latency in
36562306a36Sopenharmony_ci *					     nanoseconds
36662306a36Sopenharmony_ci * @dev: device for which we do this operation
36762306a36Sopenharmony_ci *
36862306a36Sopenharmony_ci * Return: This function returns the max transition latency, in nanoseconds, to
36962306a36Sopenharmony_ci * switch from one OPP to other.
37062306a36Sopenharmony_ci */
37162306a36Sopenharmony_ciunsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	return dev_pm_opp_get_max_volt_latency(dev) +
37462306a36Sopenharmony_ci		dev_pm_opp_get_max_clock_latency(dev);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/**
37962306a36Sopenharmony_ci * dev_pm_opp_get_suspend_opp_freq() - Get frequency of suspend opp in Hz
38062306a36Sopenharmony_ci * @dev:	device for which we do this operation
38162306a36Sopenharmony_ci *
38262306a36Sopenharmony_ci * Return: This function returns the frequency of the OPP marked as suspend_opp
38362306a36Sopenharmony_ci * if one is available, else returns 0;
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_ciunsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct opp_table *opp_table;
38862306a36Sopenharmony_ci	unsigned long freq = 0;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
39162306a36Sopenharmony_ci	if (IS_ERR(opp_table))
39262306a36Sopenharmony_ci		return 0;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (opp_table->suspend_opp && opp_table->suspend_opp->available)
39562306a36Sopenharmony_ci		freq = dev_pm_opp_get_freq(opp_table->suspend_opp);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return freq;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciint _get_opp_count(struct opp_table *opp_table)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct dev_pm_opp *opp;
40662306a36Sopenharmony_ci	int count = 0;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	list_for_each_entry(opp, &opp_table->opp_list, node) {
41162306a36Sopenharmony_ci		if (opp->available)
41262306a36Sopenharmony_ci			count++;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return count;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci/**
42162306a36Sopenharmony_ci * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
42262306a36Sopenharmony_ci * @dev:	device for which we do this operation
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci * Return: This function returns the number of available opps if there are any,
42562306a36Sopenharmony_ci * else returns 0 if none or the corresponding error value.
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_ciint dev_pm_opp_get_opp_count(struct device *dev)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct opp_table *opp_table;
43062306a36Sopenharmony_ci	int count;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
43362306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
43462306a36Sopenharmony_ci		count = PTR_ERR(opp_table);
43562306a36Sopenharmony_ci		dev_dbg(dev, "%s: OPP table not found (%d)\n",
43662306a36Sopenharmony_ci			__func__, count);
43762306a36Sopenharmony_ci		return count;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	count = _get_opp_count(opp_table);
44162306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return count;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/* Helpers to read keys */
44862306a36Sopenharmony_cistatic unsigned long _read_freq(struct dev_pm_opp *opp, int index)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	return opp->rates[index];
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic unsigned long _read_level(struct dev_pm_opp *opp, int index)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	return opp->level;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic unsigned long _read_bw(struct dev_pm_opp *opp, int index)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	return opp->bandwidth[index].peak;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/* Generic comparison helpers */
46462306a36Sopenharmony_cistatic bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
46562306a36Sopenharmony_ci			   unsigned long opp_key, unsigned long key)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	if (opp_key == key) {
46862306a36Sopenharmony_ci		*opp = temp_opp;
46962306a36Sopenharmony_ci		return true;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return false;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic bool _compare_ceil(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
47662306a36Sopenharmony_ci			  unsigned long opp_key, unsigned long key)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	if (opp_key >= key) {
47962306a36Sopenharmony_ci		*opp = temp_opp;
48062306a36Sopenharmony_ci		return true;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return false;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
48762306a36Sopenharmony_ci			   unsigned long opp_key, unsigned long key)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	if (opp_key > key)
49062306a36Sopenharmony_ci		return true;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	*opp = temp_opp;
49362306a36Sopenharmony_ci	return false;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/* Generic key finding helpers */
49762306a36Sopenharmony_cistatic struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
49862306a36Sopenharmony_ci		unsigned long *key, int index, bool available,
49962306a36Sopenharmony_ci		unsigned long (*read)(struct dev_pm_opp *opp, int index),
50062306a36Sopenharmony_ci		bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
50162306a36Sopenharmony_ci				unsigned long opp_key, unsigned long key),
50262306a36Sopenharmony_ci		bool (*assert)(struct opp_table *opp_table))
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Assert that the requirement is met */
50762306a36Sopenharmony_ci	if (assert && !assert(opp_table))
50862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
51362306a36Sopenharmony_ci		if (temp_opp->available == available) {
51462306a36Sopenharmony_ci			if (compare(&opp, temp_opp, read(temp_opp, index), *key))
51562306a36Sopenharmony_ci				break;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* Increment the reference count of OPP */
52062306a36Sopenharmony_ci	if (!IS_ERR(opp)) {
52162306a36Sopenharmony_ci		*key = read(opp, index);
52262306a36Sopenharmony_ci		dev_pm_opp_get(opp);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return opp;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic struct dev_pm_opp *
53162306a36Sopenharmony_ci_find_key(struct device *dev, unsigned long *key, int index, bool available,
53262306a36Sopenharmony_ci	  unsigned long (*read)(struct dev_pm_opp *opp, int index),
53362306a36Sopenharmony_ci	  bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
53462306a36Sopenharmony_ci			  unsigned long opp_key, unsigned long key),
53562306a36Sopenharmony_ci	  bool (*assert)(struct opp_table *opp_table))
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct opp_table *opp_table;
53862306a36Sopenharmony_ci	struct dev_pm_opp *opp;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
54162306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
54262306a36Sopenharmony_ci		dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
54362306a36Sopenharmony_ci			PTR_ERR(opp_table));
54462306a36Sopenharmony_ci		return ERR_CAST(opp_table);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	opp = _opp_table_find_key(opp_table, key, index, available, read,
54862306a36Sopenharmony_ci				  compare, assert);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return opp;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic struct dev_pm_opp *_find_key_exact(struct device *dev,
55662306a36Sopenharmony_ci		unsigned long key, int index, bool available,
55762306a36Sopenharmony_ci		unsigned long (*read)(struct dev_pm_opp *opp, int index),
55862306a36Sopenharmony_ci		bool (*assert)(struct opp_table *opp_table))
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	/*
56162306a36Sopenharmony_ci	 * The value of key will be updated here, but will be ignored as the
56262306a36Sopenharmony_ci	 * caller doesn't need it.
56362306a36Sopenharmony_ci	 */
56462306a36Sopenharmony_ci	return _find_key(dev, &key, index, available, read, _compare_exact,
56562306a36Sopenharmony_ci			 assert);
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
56962306a36Sopenharmony_ci		unsigned long *key, int index, bool available,
57062306a36Sopenharmony_ci		unsigned long (*read)(struct dev_pm_opp *opp, int index),
57162306a36Sopenharmony_ci		bool (*assert)(struct opp_table *opp_table))
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	return _opp_table_find_key(opp_table, key, index, available, read,
57462306a36Sopenharmony_ci				   _compare_ceil, assert);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
57862306a36Sopenharmony_ci		int index, bool available,
57962306a36Sopenharmony_ci		unsigned long (*read)(struct dev_pm_opp *opp, int index),
58062306a36Sopenharmony_ci		bool (*assert)(struct opp_table *opp_table))
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	return _find_key(dev, key, index, available, read, _compare_ceil,
58362306a36Sopenharmony_ci			 assert);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic struct dev_pm_opp *_find_key_floor(struct device *dev,
58762306a36Sopenharmony_ci		unsigned long *key, int index, bool available,
58862306a36Sopenharmony_ci		unsigned long (*read)(struct dev_pm_opp *opp, int index),
58962306a36Sopenharmony_ci		bool (*assert)(struct opp_table *opp_table))
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	return _find_key(dev, key, index, available, read, _compare_floor,
59262306a36Sopenharmony_ci			 assert);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci/**
59662306a36Sopenharmony_ci * dev_pm_opp_find_freq_exact() - search for an exact frequency
59762306a36Sopenharmony_ci * @dev:		device for which we do this operation
59862306a36Sopenharmony_ci * @freq:		frequency to search for
59962306a36Sopenharmony_ci * @available:		true/false - match for available opp
60062306a36Sopenharmony_ci *
60162306a36Sopenharmony_ci * Return: Searches for exact match in the opp table and returns pointer to the
60262306a36Sopenharmony_ci * matching opp if found, else returns ERR_PTR in case of error and should
60362306a36Sopenharmony_ci * be handled using IS_ERR. Error return values can be:
60462306a36Sopenharmony_ci * EINVAL:	for bad pointer
60562306a36Sopenharmony_ci * ERANGE:	no match found for search
60662306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
60762306a36Sopenharmony_ci *
60862306a36Sopenharmony_ci * Note: available is a modifier for the search. if available=true, then the
60962306a36Sopenharmony_ci * match is for exact matching frequency and is available in the stored OPP
61062306a36Sopenharmony_ci * table. if false, the match is for exact frequency which is not available.
61162306a36Sopenharmony_ci *
61262306a36Sopenharmony_ci * This provides a mechanism to enable an opp which is not available currently
61362306a36Sopenharmony_ci * or the opposite as well.
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
61662306a36Sopenharmony_ci * use.
61762306a36Sopenharmony_ci */
61862306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
61962306a36Sopenharmony_ci		unsigned long freq, bool available)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	return _find_key_exact(dev, freq, 0, available, _read_freq,
62262306a36Sopenharmony_ci			       assert_single_clk);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/**
62762306a36Sopenharmony_ci * dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
62862306a36Sopenharmony_ci *					 clock corresponding to the index
62962306a36Sopenharmony_ci * @dev:	Device for which we do this operation
63062306a36Sopenharmony_ci * @freq:	frequency to search for
63162306a36Sopenharmony_ci * @index:	Clock index
63262306a36Sopenharmony_ci * @available:	true/false - match for available opp
63362306a36Sopenharmony_ci *
63462306a36Sopenharmony_ci * Search for the matching exact OPP for the clock corresponding to the
63562306a36Sopenharmony_ci * specified index from a starting freq for a device.
63662306a36Sopenharmony_ci *
63762306a36Sopenharmony_ci * Return: matching *opp , else returns ERR_PTR in case of error and should be
63862306a36Sopenharmony_ci * handled using IS_ERR. Error return values can be:
63962306a36Sopenharmony_ci * EINVAL:	for bad pointer
64062306a36Sopenharmony_ci * ERANGE:	no match found for search
64162306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
64462306a36Sopenharmony_ci * use.
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_cistruct dev_pm_opp *
64762306a36Sopenharmony_cidev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
64862306a36Sopenharmony_ci				   u32 index, bool available)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	return _find_key_exact(dev, freq, index, available, _read_freq, NULL);
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact_indexed);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
65562306a36Sopenharmony_ci						   unsigned long *freq)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	return _opp_table_find_key_ceil(opp_table, freq, 0, true, _read_freq,
65862306a36Sopenharmony_ci					assert_single_clk);
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/**
66262306a36Sopenharmony_ci * dev_pm_opp_find_freq_ceil() - Search for an rounded ceil freq
66362306a36Sopenharmony_ci * @dev:	device for which we do this operation
66462306a36Sopenharmony_ci * @freq:	Start frequency
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci * Search for the matching ceil *available* OPP from a starting freq
66762306a36Sopenharmony_ci * for a device.
66862306a36Sopenharmony_ci *
66962306a36Sopenharmony_ci * Return: matching *opp and refreshes *freq accordingly, else returns
67062306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
67162306a36Sopenharmony_ci * values can be:
67262306a36Sopenharmony_ci * EINVAL:	for bad pointer
67362306a36Sopenharmony_ci * ERANGE:	no match found for search
67462306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
67562306a36Sopenharmony_ci *
67662306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
67762306a36Sopenharmony_ci * use.
67862306a36Sopenharmony_ci */
67962306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
68062306a36Sopenharmony_ci					     unsigned long *freq)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return _find_key_ceil(dev, freq, 0, true, _read_freq, assert_single_clk);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci/**
68762306a36Sopenharmony_ci * dev_pm_opp_find_freq_ceil_indexed() - Search for a rounded ceil freq for the
68862306a36Sopenharmony_ci *					 clock corresponding to the index
68962306a36Sopenharmony_ci * @dev:	Device for which we do this operation
69062306a36Sopenharmony_ci * @freq:	Start frequency
69162306a36Sopenharmony_ci * @index:	Clock index
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci * Search for the matching ceil *available* OPP for the clock corresponding to
69462306a36Sopenharmony_ci * the specified index from a starting freq for a device.
69562306a36Sopenharmony_ci *
69662306a36Sopenharmony_ci * Return: matching *opp and refreshes *freq accordingly, else returns
69762306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
69862306a36Sopenharmony_ci * values can be:
69962306a36Sopenharmony_ci * EINVAL:	for bad pointer
70062306a36Sopenharmony_ci * ERANGE:	no match found for search
70162306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
70462306a36Sopenharmony_ci * use.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_cistruct dev_pm_opp *
70762306a36Sopenharmony_cidev_pm_opp_find_freq_ceil_indexed(struct device *dev, unsigned long *freq,
70862306a36Sopenharmony_ci				  u32 index)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	return _find_key_ceil(dev, freq, index, true, _read_freq, NULL);
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci/**
71562306a36Sopenharmony_ci * dev_pm_opp_find_freq_floor() - Search for a rounded floor freq
71662306a36Sopenharmony_ci * @dev:	device for which we do this operation
71762306a36Sopenharmony_ci * @freq:	Start frequency
71862306a36Sopenharmony_ci *
71962306a36Sopenharmony_ci * Search for the matching floor *available* OPP from a starting freq
72062306a36Sopenharmony_ci * for a device.
72162306a36Sopenharmony_ci *
72262306a36Sopenharmony_ci * Return: matching *opp and refreshes *freq accordingly, else returns
72362306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
72462306a36Sopenharmony_ci * values can be:
72562306a36Sopenharmony_ci * EINVAL:	for bad pointer
72662306a36Sopenharmony_ci * ERANGE:	no match found for search
72762306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
72862306a36Sopenharmony_ci *
72962306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
73062306a36Sopenharmony_ci * use.
73162306a36Sopenharmony_ci */
73262306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
73362306a36Sopenharmony_ci					      unsigned long *freq)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	return _find_key_floor(dev, freq, 0, true, _read_freq, assert_single_clk);
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci/**
74062306a36Sopenharmony_ci * dev_pm_opp_find_freq_floor_indexed() - Search for a rounded floor freq for the
74162306a36Sopenharmony_ci *					  clock corresponding to the index
74262306a36Sopenharmony_ci * @dev:	Device for which we do this operation
74362306a36Sopenharmony_ci * @freq:	Start frequency
74462306a36Sopenharmony_ci * @index:	Clock index
74562306a36Sopenharmony_ci *
74662306a36Sopenharmony_ci * Search for the matching floor *available* OPP for the clock corresponding to
74762306a36Sopenharmony_ci * the specified index from a starting freq for a device.
74862306a36Sopenharmony_ci *
74962306a36Sopenharmony_ci * Return: matching *opp and refreshes *freq accordingly, else returns
75062306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
75162306a36Sopenharmony_ci * values can be:
75262306a36Sopenharmony_ci * EINVAL:	for bad pointer
75362306a36Sopenharmony_ci * ERANGE:	no match found for search
75462306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
75562306a36Sopenharmony_ci *
75662306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
75762306a36Sopenharmony_ci * use.
75862306a36Sopenharmony_ci */
75962306a36Sopenharmony_cistruct dev_pm_opp *
76062306a36Sopenharmony_cidev_pm_opp_find_freq_floor_indexed(struct device *dev, unsigned long *freq,
76162306a36Sopenharmony_ci				   u32 index)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	return _find_key_floor(dev, freq, index, true, _read_freq, NULL);
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor_indexed);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/**
76862306a36Sopenharmony_ci * dev_pm_opp_find_level_exact() - search for an exact level
76962306a36Sopenharmony_ci * @dev:		device for which we do this operation
77062306a36Sopenharmony_ci * @level:		level to search for
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * Return: Searches for exact match in the opp table and returns pointer to the
77362306a36Sopenharmony_ci * matching opp if found, else returns ERR_PTR in case of error and should
77462306a36Sopenharmony_ci * be handled using IS_ERR. Error return values can be:
77562306a36Sopenharmony_ci * EINVAL:	for bad pointer
77662306a36Sopenharmony_ci * ERANGE:	no match found for search
77762306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
77862306a36Sopenharmony_ci *
77962306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
78062306a36Sopenharmony_ci * use.
78162306a36Sopenharmony_ci */
78262306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
78362306a36Sopenharmony_ci					       unsigned int level)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	return _find_key_exact(dev, level, 0, true, _read_level, NULL);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci/**
79062306a36Sopenharmony_ci * dev_pm_opp_find_level_ceil() - search for an rounded up level
79162306a36Sopenharmony_ci * @dev:		device for which we do this operation
79262306a36Sopenharmony_ci * @level:		level to search for
79362306a36Sopenharmony_ci *
79462306a36Sopenharmony_ci * Return: Searches for rounded up match in the opp table and returns pointer
79562306a36Sopenharmony_ci * to the  matching opp if found, else returns ERR_PTR in case of error and
79662306a36Sopenharmony_ci * should be handled using IS_ERR. Error return values can be:
79762306a36Sopenharmony_ci * EINVAL:	for bad pointer
79862306a36Sopenharmony_ci * ERANGE:	no match found for search
79962306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
80262306a36Sopenharmony_ci * use.
80362306a36Sopenharmony_ci */
80462306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
80562306a36Sopenharmony_ci					      unsigned int *level)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	unsigned long temp = *level;
80862306a36Sopenharmony_ci	struct dev_pm_opp *opp;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	opp = _find_key_ceil(dev, &temp, 0, true, _read_level, NULL);
81162306a36Sopenharmony_ci	*level = temp;
81262306a36Sopenharmony_ci	return opp;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * dev_pm_opp_find_bw_ceil() - Search for a rounded ceil bandwidth
81862306a36Sopenharmony_ci * @dev:	device for which we do this operation
81962306a36Sopenharmony_ci * @bw:	start bandwidth
82062306a36Sopenharmony_ci * @index:	which bandwidth to compare, in case of OPPs with several values
82162306a36Sopenharmony_ci *
82262306a36Sopenharmony_ci * Search for the matching floor *available* OPP from a starting bandwidth
82362306a36Sopenharmony_ci * for a device.
82462306a36Sopenharmony_ci *
82562306a36Sopenharmony_ci * Return: matching *opp and refreshes *bw accordingly, else returns
82662306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
82762306a36Sopenharmony_ci * values can be:
82862306a36Sopenharmony_ci * EINVAL:	for bad pointer
82962306a36Sopenharmony_ci * ERANGE:	no match found for search
83062306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
83162306a36Sopenharmony_ci *
83262306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
83362306a36Sopenharmony_ci * use.
83462306a36Sopenharmony_ci */
83562306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev, unsigned int *bw,
83662306a36Sopenharmony_ci					   int index)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	unsigned long temp = *bw;
83962306a36Sopenharmony_ci	struct dev_pm_opp *opp;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	opp = _find_key_ceil(dev, &temp, index, true, _read_bw, NULL);
84262306a36Sopenharmony_ci	*bw = temp;
84362306a36Sopenharmony_ci	return opp;
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_ceil);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci/**
84862306a36Sopenharmony_ci * dev_pm_opp_find_bw_floor() - Search for a rounded floor bandwidth
84962306a36Sopenharmony_ci * @dev:	device for which we do this operation
85062306a36Sopenharmony_ci * @bw:	start bandwidth
85162306a36Sopenharmony_ci * @index:	which bandwidth to compare, in case of OPPs with several values
85262306a36Sopenharmony_ci *
85362306a36Sopenharmony_ci * Search for the matching floor *available* OPP from a starting bandwidth
85462306a36Sopenharmony_ci * for a device.
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * Return: matching *opp and refreshes *bw accordingly, else returns
85762306a36Sopenharmony_ci * ERR_PTR in case of error and should be handled using IS_ERR. Error return
85862306a36Sopenharmony_ci * values can be:
85962306a36Sopenharmony_ci * EINVAL:	for bad pointer
86062306a36Sopenharmony_ci * ERANGE:	no match found for search
86162306a36Sopenharmony_ci * ENODEV:	if device not found in list of registered devices
86262306a36Sopenharmony_ci *
86362306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
86462306a36Sopenharmony_ci * use.
86562306a36Sopenharmony_ci */
86662306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_find_bw_floor(struct device *dev,
86762306a36Sopenharmony_ci					    unsigned int *bw, int index)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	unsigned long temp = *bw;
87062306a36Sopenharmony_ci	struct dev_pm_opp *opp;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	opp = _find_key_floor(dev, &temp, index, true, _read_bw, NULL);
87362306a36Sopenharmony_ci	*bw = temp;
87462306a36Sopenharmony_ci	return opp;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_find_bw_floor);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic int _set_opp_voltage(struct device *dev, struct regulator *reg,
87962306a36Sopenharmony_ci			    struct dev_pm_opp_supply *supply)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	int ret;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* Regulator not available for device */
88462306a36Sopenharmony_ci	if (IS_ERR(reg)) {
88562306a36Sopenharmony_ci		dev_dbg(dev, "%s: regulator not available: %ld\n", __func__,
88662306a36Sopenharmony_ci			PTR_ERR(reg));
88762306a36Sopenharmony_ci		return 0;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__,
89162306a36Sopenharmony_ci		supply->u_volt_min, supply->u_volt, supply->u_volt_max);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
89462306a36Sopenharmony_ci					    supply->u_volt, supply->u_volt_max);
89562306a36Sopenharmony_ci	if (ret)
89662306a36Sopenharmony_ci		dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
89762306a36Sopenharmony_ci			__func__, supply->u_volt_min, supply->u_volt,
89862306a36Sopenharmony_ci			supply->u_volt_max, ret);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	return ret;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int
90462306a36Sopenharmony_ci_opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
90562306a36Sopenharmony_ci		       struct dev_pm_opp *opp, void *data, bool scaling_down)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	unsigned long *target = data;
90862306a36Sopenharmony_ci	unsigned long freq;
90962306a36Sopenharmony_ci	int ret;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	/* One of target and opp must be available */
91262306a36Sopenharmony_ci	if (target) {
91362306a36Sopenharmony_ci		freq = *target;
91462306a36Sopenharmony_ci	} else if (opp) {
91562306a36Sopenharmony_ci		freq = opp->rates[0];
91662306a36Sopenharmony_ci	} else {
91762306a36Sopenharmony_ci		WARN_ON(1);
91862306a36Sopenharmony_ci		return -EINVAL;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	ret = clk_set_rate(opp_table->clk, freq);
92262306a36Sopenharmony_ci	if (ret) {
92362306a36Sopenharmony_ci		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
92462306a36Sopenharmony_ci			ret);
92562306a36Sopenharmony_ci	} else {
92662306a36Sopenharmony_ci		opp_table->rate_clk_single = freq;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return ret;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/*
93362306a36Sopenharmony_ci * Simple implementation for configuring multiple clocks. Configure clocks in
93462306a36Sopenharmony_ci * the order in which they are present in the array while scaling up.
93562306a36Sopenharmony_ci */
93662306a36Sopenharmony_ciint dev_pm_opp_config_clks_simple(struct device *dev,
93762306a36Sopenharmony_ci		struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
93862306a36Sopenharmony_ci		bool scaling_down)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	int ret, i;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (scaling_down) {
94362306a36Sopenharmony_ci		for (i = opp_table->clk_count - 1; i >= 0; i--) {
94462306a36Sopenharmony_ci			ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
94562306a36Sopenharmony_ci			if (ret) {
94662306a36Sopenharmony_ci				dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
94762306a36Sopenharmony_ci					ret);
94862306a36Sopenharmony_ci				return ret;
94962306a36Sopenharmony_ci			}
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci	} else {
95262306a36Sopenharmony_ci		for (i = 0; i < opp_table->clk_count; i++) {
95362306a36Sopenharmony_ci			ret = clk_set_rate(opp_table->clks[i], opp->rates[i]);
95462306a36Sopenharmony_ci			if (ret) {
95562306a36Sopenharmony_ci				dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
95662306a36Sopenharmony_ci					ret);
95762306a36Sopenharmony_ci				return ret;
95862306a36Sopenharmony_ci			}
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return 0;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_config_clks_simple);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int _opp_config_regulator_single(struct device *dev,
96762306a36Sopenharmony_ci			struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
96862306a36Sopenharmony_ci			struct regulator **regulators, unsigned int count)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct regulator *reg = regulators[0];
97162306a36Sopenharmony_ci	int ret;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* This function only supports single regulator per device */
97462306a36Sopenharmony_ci	if (WARN_ON(count > 1)) {
97562306a36Sopenharmony_ci		dev_err(dev, "multiple regulators are not supported\n");
97662306a36Sopenharmony_ci		return -EINVAL;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	ret = _set_opp_voltage(dev, reg, new_opp->supplies);
98062306a36Sopenharmony_ci	if (ret)
98162306a36Sopenharmony_ci		return ret;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/*
98462306a36Sopenharmony_ci	 * Enable the regulator after setting its voltages, otherwise it breaks
98562306a36Sopenharmony_ci	 * some boot-enabled regulators.
98662306a36Sopenharmony_ci	 */
98762306a36Sopenharmony_ci	if (unlikely(!new_opp->opp_table->enabled)) {
98862306a36Sopenharmony_ci		ret = regulator_enable(reg);
98962306a36Sopenharmony_ci		if (ret < 0)
99062306a36Sopenharmony_ci			dev_warn(dev, "Failed to enable regulator: %d", ret);
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	return 0;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistatic int _set_opp_bw(const struct opp_table *opp_table,
99762306a36Sopenharmony_ci		       struct dev_pm_opp *opp, struct device *dev)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	u32 avg, peak;
100062306a36Sopenharmony_ci	int i, ret;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (!opp_table->paths)
100362306a36Sopenharmony_ci		return 0;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	for (i = 0; i < opp_table->path_count; i++) {
100662306a36Sopenharmony_ci		if (!opp) {
100762306a36Sopenharmony_ci			avg = 0;
100862306a36Sopenharmony_ci			peak = 0;
100962306a36Sopenharmony_ci		} else {
101062306a36Sopenharmony_ci			avg = opp->bandwidth[i].avg;
101162306a36Sopenharmony_ci			peak = opp->bandwidth[i].peak;
101262306a36Sopenharmony_ci		}
101362306a36Sopenharmony_ci		ret = icc_set_bw(opp_table->paths[i], avg, peak);
101462306a36Sopenharmony_ci		if (ret) {
101562306a36Sopenharmony_ci			dev_err(dev, "Failed to %s bandwidth[%d]: %d\n",
101662306a36Sopenharmony_ci				opp ? "set" : "remove", i, ret);
101762306a36Sopenharmony_ci			return ret;
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return 0;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int _set_performance_state(struct device *dev, struct device *pd_dev,
102562306a36Sopenharmony_ci				  struct dev_pm_opp *opp, int i)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	unsigned int pstate = likely(opp) ? opp->required_opps[i]->level: 0;
102862306a36Sopenharmony_ci	int ret;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (!pd_dev)
103162306a36Sopenharmony_ci		return 0;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
103462306a36Sopenharmony_ci	if (ret) {
103562306a36Sopenharmony_ci		dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
103662306a36Sopenharmony_ci			dev_name(pd_dev), pstate, ret);
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	return ret;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic int _opp_set_required_opps_generic(struct device *dev,
104362306a36Sopenharmony_ci	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	dev_err(dev, "setting required-opps isn't supported for non-genpd devices\n");
104662306a36Sopenharmony_ci	return -ENOENT;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic int _opp_set_required_opps_genpd(struct device *dev,
105062306a36Sopenharmony_ci	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct device **genpd_virt_devs =
105362306a36Sopenharmony_ci		opp_table->genpd_virt_devs ? opp_table->genpd_virt_devs : &dev;
105462306a36Sopenharmony_ci	int i, ret = 0;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/*
105762306a36Sopenharmony_ci	 * Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev
105862306a36Sopenharmony_ci	 * after it is freed from another thread.
105962306a36Sopenharmony_ci	 */
106062306a36Sopenharmony_ci	mutex_lock(&opp_table->genpd_virt_dev_lock);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* Scaling up? Set required OPPs in normal order, else reverse */
106362306a36Sopenharmony_ci	if (!scaling_down) {
106462306a36Sopenharmony_ci		for (i = 0; i < opp_table->required_opp_count; i++) {
106562306a36Sopenharmony_ci			ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
106662306a36Sopenharmony_ci			if (ret)
106762306a36Sopenharmony_ci				break;
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_ci	} else {
107062306a36Sopenharmony_ci		for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
107162306a36Sopenharmony_ci			ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
107262306a36Sopenharmony_ci			if (ret)
107362306a36Sopenharmony_ci				break;
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	mutex_unlock(&opp_table->genpd_virt_dev_lock);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return ret;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci/* This is only called for PM domain for now */
108362306a36Sopenharmony_cistatic int _set_required_opps(struct device *dev, struct opp_table *opp_table,
108462306a36Sopenharmony_ci			      struct dev_pm_opp *opp, bool up)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	/* required-opps not fully initialized yet */
108762306a36Sopenharmony_ci	if (lazy_linking_pending(opp_table))
108862306a36Sopenharmony_ci		return -EBUSY;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (opp_table->set_required_opps)
109162306a36Sopenharmony_ci		return opp_table->set_required_opps(dev, opp_table, opp, up);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	return 0;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci/* Update set_required_opps handler */
109762306a36Sopenharmony_civoid _update_set_required_opps(struct opp_table *opp_table)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	/* Already set */
110062306a36Sopenharmony_ci	if (opp_table->set_required_opps)
110162306a36Sopenharmony_ci		return;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	/* All required OPPs will belong to genpd or none */
110462306a36Sopenharmony_ci	if (opp_table->required_opp_tables[0]->is_genpd)
110562306a36Sopenharmony_ci		opp_table->set_required_opps = _opp_set_required_opps_genpd;
110662306a36Sopenharmony_ci	else
110762306a36Sopenharmony_ci		opp_table->set_required_opps = _opp_set_required_opps_generic;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic void _find_current_opp(struct device *dev, struct opp_table *opp_table)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct dev_pm_opp *opp = ERR_PTR(-ENODEV);
111362306a36Sopenharmony_ci	unsigned long freq;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (!IS_ERR(opp_table->clk)) {
111662306a36Sopenharmony_ci		freq = clk_get_rate(opp_table->clk);
111762306a36Sopenharmony_ci		opp = _find_freq_ceil(opp_table, &freq);
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/*
112162306a36Sopenharmony_ci	 * Unable to find the current OPP ? Pick the first from the list since
112262306a36Sopenharmony_ci	 * it is in ascending order, otherwise rest of the code will need to
112362306a36Sopenharmony_ci	 * make special checks to validate current_opp.
112462306a36Sopenharmony_ci	 */
112562306a36Sopenharmony_ci	if (IS_ERR(opp)) {
112662306a36Sopenharmony_ci		mutex_lock(&opp_table->lock);
112762306a36Sopenharmony_ci		opp = list_first_entry(&opp_table->opp_list, struct dev_pm_opp, node);
112862306a36Sopenharmony_ci		dev_pm_opp_get(opp);
112962306a36Sopenharmony_ci		mutex_unlock(&opp_table->lock);
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	opp_table->current_opp = opp;
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cistatic int _disable_opp_table(struct device *dev, struct opp_table *opp_table)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	int ret;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (!opp_table->enabled)
114062306a36Sopenharmony_ci		return 0;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	/*
114362306a36Sopenharmony_ci	 * Some drivers need to support cases where some platforms may
114462306a36Sopenharmony_ci	 * have OPP table for the device, while others don't and
114562306a36Sopenharmony_ci	 * opp_set_rate() just needs to behave like clk_set_rate().
114662306a36Sopenharmony_ci	 */
114762306a36Sopenharmony_ci	if (!_get_opp_count(opp_table))
114862306a36Sopenharmony_ci		return 0;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	ret = _set_opp_bw(opp_table, NULL, dev);
115162306a36Sopenharmony_ci	if (ret)
115262306a36Sopenharmony_ci		return ret;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (opp_table->regulators)
115562306a36Sopenharmony_ci		regulator_disable(opp_table->regulators[0]);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	ret = _set_required_opps(dev, opp_table, NULL, false);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	opp_table->enabled = false;
116062306a36Sopenharmony_ci	return ret;
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_cistatic int _set_opp(struct device *dev, struct opp_table *opp_table,
116462306a36Sopenharmony_ci		    struct dev_pm_opp *opp, void *clk_data, bool forced)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct dev_pm_opp *old_opp;
116762306a36Sopenharmony_ci	int scaling_down, ret;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	if (unlikely(!opp))
117062306a36Sopenharmony_ci		return _disable_opp_table(dev, opp_table);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	/* Find the currently set OPP if we don't know already */
117362306a36Sopenharmony_ci	if (unlikely(!opp_table->current_opp))
117462306a36Sopenharmony_ci		_find_current_opp(dev, opp_table);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	old_opp = opp_table->current_opp;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	/* Return early if nothing to do */
117962306a36Sopenharmony_ci	if (!forced && old_opp == opp && opp_table->enabled) {
118062306a36Sopenharmony_ci		dev_dbg_ratelimited(dev, "%s: OPPs are same, nothing to do\n", __func__);
118162306a36Sopenharmony_ci		return 0;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	dev_dbg(dev, "%s: switching OPP: Freq %lu -> %lu Hz, Level %u -> %u, Bw %u -> %u\n",
118562306a36Sopenharmony_ci		__func__, old_opp->rates[0], opp->rates[0], old_opp->level,
118662306a36Sopenharmony_ci		opp->level, old_opp->bandwidth ? old_opp->bandwidth[0].peak : 0,
118762306a36Sopenharmony_ci		opp->bandwidth ? opp->bandwidth[0].peak : 0);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	scaling_down = _opp_compare_key(opp_table, old_opp, opp);
119062306a36Sopenharmony_ci	if (scaling_down == -1)
119162306a36Sopenharmony_ci		scaling_down = 0;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/* Scaling up? Configure required OPPs before frequency */
119462306a36Sopenharmony_ci	if (!scaling_down) {
119562306a36Sopenharmony_ci		ret = _set_required_opps(dev, opp_table, opp, true);
119662306a36Sopenharmony_ci		if (ret) {
119762306a36Sopenharmony_ci			dev_err(dev, "Failed to set required opps: %d\n", ret);
119862306a36Sopenharmony_ci			return ret;
119962306a36Sopenharmony_ci		}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci		ret = _set_opp_bw(opp_table, opp, dev);
120262306a36Sopenharmony_ci		if (ret) {
120362306a36Sopenharmony_ci			dev_err(dev, "Failed to set bw: %d\n", ret);
120462306a36Sopenharmony_ci			return ret;
120562306a36Sopenharmony_ci		}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci		if (opp_table->config_regulators) {
120862306a36Sopenharmony_ci			ret = opp_table->config_regulators(dev, old_opp, opp,
120962306a36Sopenharmony_ci							   opp_table->regulators,
121062306a36Sopenharmony_ci							   opp_table->regulator_count);
121162306a36Sopenharmony_ci			if (ret) {
121262306a36Sopenharmony_ci				dev_err(dev, "Failed to set regulator voltages: %d\n",
121362306a36Sopenharmony_ci					ret);
121462306a36Sopenharmony_ci				return ret;
121562306a36Sopenharmony_ci			}
121662306a36Sopenharmony_ci		}
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (opp_table->config_clks) {
122062306a36Sopenharmony_ci		ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down);
122162306a36Sopenharmony_ci		if (ret)
122262306a36Sopenharmony_ci			return ret;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* Scaling down? Configure required OPPs after frequency */
122662306a36Sopenharmony_ci	if (scaling_down) {
122762306a36Sopenharmony_ci		if (opp_table->config_regulators) {
122862306a36Sopenharmony_ci			ret = opp_table->config_regulators(dev, old_opp, opp,
122962306a36Sopenharmony_ci							   opp_table->regulators,
123062306a36Sopenharmony_ci							   opp_table->regulator_count);
123162306a36Sopenharmony_ci			if (ret) {
123262306a36Sopenharmony_ci				dev_err(dev, "Failed to set regulator voltages: %d\n",
123362306a36Sopenharmony_ci					ret);
123462306a36Sopenharmony_ci				return ret;
123562306a36Sopenharmony_ci			}
123662306a36Sopenharmony_ci		}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci		ret = _set_opp_bw(opp_table, opp, dev);
123962306a36Sopenharmony_ci		if (ret) {
124062306a36Sopenharmony_ci			dev_err(dev, "Failed to set bw: %d\n", ret);
124162306a36Sopenharmony_ci			return ret;
124262306a36Sopenharmony_ci		}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci		ret = _set_required_opps(dev, opp_table, opp, false);
124562306a36Sopenharmony_ci		if (ret) {
124662306a36Sopenharmony_ci			dev_err(dev, "Failed to set required opps: %d\n", ret);
124762306a36Sopenharmony_ci			return ret;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	opp_table->enabled = true;
125262306a36Sopenharmony_ci	dev_pm_opp_put(old_opp);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	/* Make sure current_opp doesn't get freed */
125562306a36Sopenharmony_ci	dev_pm_opp_get(opp);
125662306a36Sopenharmony_ci	opp_table->current_opp = opp;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	return ret;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci/**
126262306a36Sopenharmony_ci * dev_pm_opp_set_rate() - Configure new OPP based on frequency
126362306a36Sopenharmony_ci * @dev:	 device for which we do this operation
126462306a36Sopenharmony_ci * @target_freq: frequency to achieve
126562306a36Sopenharmony_ci *
126662306a36Sopenharmony_ci * This configures the power-supplies to the levels specified by the OPP
126762306a36Sopenharmony_ci * corresponding to the target_freq, and programs the clock to a value <=
126862306a36Sopenharmony_ci * target_freq, as rounded by clk_round_rate(). Device wanting to run at fmax
126962306a36Sopenharmony_ci * provided by the opp, should have already rounded to the target OPP's
127062306a36Sopenharmony_ci * frequency.
127162306a36Sopenharmony_ci */
127262306a36Sopenharmony_ciint dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct opp_table *opp_table;
127562306a36Sopenharmony_ci	unsigned long freq = 0, temp_freq;
127662306a36Sopenharmony_ci	struct dev_pm_opp *opp = NULL;
127762306a36Sopenharmony_ci	bool forced = false;
127862306a36Sopenharmony_ci	int ret;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
128162306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
128262306a36Sopenharmony_ci		dev_err(dev, "%s: device's opp table doesn't exist\n", __func__);
128362306a36Sopenharmony_ci		return PTR_ERR(opp_table);
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (target_freq) {
128762306a36Sopenharmony_ci		/*
128862306a36Sopenharmony_ci		 * For IO devices which require an OPP on some platforms/SoCs
128962306a36Sopenharmony_ci		 * while just needing to scale the clock on some others
129062306a36Sopenharmony_ci		 * we look for empty OPP tables with just a clock handle and
129162306a36Sopenharmony_ci		 * scale only the clk. This makes dev_pm_opp_set_rate()
129262306a36Sopenharmony_ci		 * equivalent to a clk_set_rate()
129362306a36Sopenharmony_ci		 */
129462306a36Sopenharmony_ci		if (!_get_opp_count(opp_table)) {
129562306a36Sopenharmony_ci			ret = opp_table->config_clks(dev, opp_table, NULL,
129662306a36Sopenharmony_ci						     &target_freq, false);
129762306a36Sopenharmony_ci			goto put_opp_table;
129862306a36Sopenharmony_ci		}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci		freq = clk_round_rate(opp_table->clk, target_freq);
130162306a36Sopenharmony_ci		if ((long)freq <= 0)
130262306a36Sopenharmony_ci			freq = target_freq;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci		/*
130562306a36Sopenharmony_ci		 * The clock driver may support finer resolution of the
130662306a36Sopenharmony_ci		 * frequencies than the OPP table, don't update the frequency we
130762306a36Sopenharmony_ci		 * pass to clk_set_rate() here.
130862306a36Sopenharmony_ci		 */
130962306a36Sopenharmony_ci		temp_freq = freq;
131062306a36Sopenharmony_ci		opp = _find_freq_ceil(opp_table, &temp_freq);
131162306a36Sopenharmony_ci		if (IS_ERR(opp)) {
131262306a36Sopenharmony_ci			ret = PTR_ERR(opp);
131362306a36Sopenharmony_ci			dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
131462306a36Sopenharmony_ci				__func__, freq, ret);
131562306a36Sopenharmony_ci			goto put_opp_table;
131662306a36Sopenharmony_ci		}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci		/*
131962306a36Sopenharmony_ci		 * An OPP entry specifies the highest frequency at which other
132062306a36Sopenharmony_ci		 * properties of the OPP entry apply. Even if the new OPP is
132162306a36Sopenharmony_ci		 * same as the old one, we may still reach here for a different
132262306a36Sopenharmony_ci		 * value of the frequency. In such a case, do not abort but
132362306a36Sopenharmony_ci		 * configure the hardware to the desired frequency forcefully.
132462306a36Sopenharmony_ci		 */
132562306a36Sopenharmony_ci		forced = opp_table->rate_clk_single != freq;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	ret = _set_opp(dev, opp_table, opp, &freq, forced);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	if (freq)
133162306a36Sopenharmony_ci		dev_pm_opp_put(opp);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ciput_opp_table:
133462306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
133562306a36Sopenharmony_ci	return ret;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci/**
134062306a36Sopenharmony_ci * dev_pm_opp_set_opp() - Configure device for OPP
134162306a36Sopenharmony_ci * @dev: device for which we do this operation
134262306a36Sopenharmony_ci * @opp: OPP to set to
134362306a36Sopenharmony_ci *
134462306a36Sopenharmony_ci * This configures the device based on the properties of the OPP passed to this
134562306a36Sopenharmony_ci * routine.
134662306a36Sopenharmony_ci *
134762306a36Sopenharmony_ci * Return: 0 on success, a negative error number otherwise.
134862306a36Sopenharmony_ci */
134962306a36Sopenharmony_ciint dev_pm_opp_set_opp(struct device *dev, struct dev_pm_opp *opp)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	struct opp_table *opp_table;
135262306a36Sopenharmony_ci	int ret;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
135562306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
135662306a36Sopenharmony_ci		dev_err(dev, "%s: device opp doesn't exist\n", __func__);
135762306a36Sopenharmony_ci		return PTR_ERR(opp_table);
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	ret = _set_opp(dev, opp_table, opp, NULL, false);
136162306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	return ret;
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_set_opp);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci/* OPP-dev Helpers */
136862306a36Sopenharmony_cistatic void _remove_opp_dev(struct opp_device *opp_dev,
136962306a36Sopenharmony_ci			    struct opp_table *opp_table)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	opp_debug_unregister(opp_dev, opp_table);
137262306a36Sopenharmony_ci	list_del(&opp_dev->node);
137362306a36Sopenharmony_ci	kfree(opp_dev);
137462306a36Sopenharmony_ci}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_cistruct opp_device *_add_opp_dev(const struct device *dev,
137762306a36Sopenharmony_ci				struct opp_table *opp_table)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	struct opp_device *opp_dev;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	opp_dev = kzalloc(sizeof(*opp_dev), GFP_KERNEL);
138262306a36Sopenharmony_ci	if (!opp_dev)
138362306a36Sopenharmony_ci		return NULL;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	/* Initialize opp-dev */
138662306a36Sopenharmony_ci	opp_dev->dev = dev;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
138962306a36Sopenharmony_ci	list_add(&opp_dev->node, &opp_table->dev_list);
139062306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	/* Create debugfs entries for the opp_table */
139362306a36Sopenharmony_ci	opp_debug_register(opp_dev, opp_table);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	return opp_dev;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic struct opp_table *_allocate_opp_table(struct device *dev, int index)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct opp_table *opp_table;
140162306a36Sopenharmony_ci	struct opp_device *opp_dev;
140262306a36Sopenharmony_ci	int ret;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/*
140562306a36Sopenharmony_ci	 * Allocate a new OPP table. In the infrequent case where a new
140662306a36Sopenharmony_ci	 * device is needed to be added, we pay this penalty.
140762306a36Sopenharmony_ci	 */
140862306a36Sopenharmony_ci	opp_table = kzalloc(sizeof(*opp_table), GFP_KERNEL);
140962306a36Sopenharmony_ci	if (!opp_table)
141062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	mutex_init(&opp_table->lock);
141362306a36Sopenharmony_ci	mutex_init(&opp_table->genpd_virt_dev_lock);
141462306a36Sopenharmony_ci	INIT_LIST_HEAD(&opp_table->dev_list);
141562306a36Sopenharmony_ci	INIT_LIST_HEAD(&opp_table->lazy);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	opp_table->clk = ERR_PTR(-ENODEV);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	/* Mark regulator count uninitialized */
142062306a36Sopenharmony_ci	opp_table->regulator_count = -1;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	opp_dev = _add_opp_dev(dev, opp_table);
142362306a36Sopenharmony_ci	if (!opp_dev) {
142462306a36Sopenharmony_ci		ret = -ENOMEM;
142562306a36Sopenharmony_ci		goto err;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	_of_init_opp_table(opp_table, dev, index);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	/* Find interconnect path(s) for the device */
143162306a36Sopenharmony_ci	ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
143262306a36Sopenharmony_ci	if (ret) {
143362306a36Sopenharmony_ci		if (ret == -EPROBE_DEFER)
143462306a36Sopenharmony_ci			goto remove_opp_dev;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci		dev_warn(dev, "%s: Error finding interconnect paths: %d\n",
143762306a36Sopenharmony_ci			 __func__, ret);
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
144162306a36Sopenharmony_ci	INIT_LIST_HEAD(&opp_table->opp_list);
144262306a36Sopenharmony_ci	kref_init(&opp_table->kref);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	return opp_table;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ciremove_opp_dev:
144762306a36Sopenharmony_ci	_of_clear_opp_table(opp_table);
144862306a36Sopenharmony_ci	_remove_opp_dev(opp_dev, opp_table);
144962306a36Sopenharmony_ci	mutex_destroy(&opp_table->genpd_virt_dev_lock);
145062306a36Sopenharmony_ci	mutex_destroy(&opp_table->lock);
145162306a36Sopenharmony_cierr:
145262306a36Sopenharmony_ci	kfree(opp_table);
145362306a36Sopenharmony_ci	return ERR_PTR(ret);
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_civoid _get_opp_table_kref(struct opp_table *opp_table)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	kref_get(&opp_table->kref);
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic struct opp_table *_update_opp_table_clk(struct device *dev,
146262306a36Sopenharmony_ci					       struct opp_table *opp_table,
146362306a36Sopenharmony_ci					       bool getclk)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	int ret;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/*
146862306a36Sopenharmony_ci	 * Return early if we don't need to get clk or we have already done it
146962306a36Sopenharmony_ci	 * earlier.
147062306a36Sopenharmony_ci	 */
147162306a36Sopenharmony_ci	if (!getclk || IS_ERR(opp_table) || !IS_ERR(opp_table->clk) ||
147262306a36Sopenharmony_ci	    opp_table->clks)
147362306a36Sopenharmony_ci		return opp_table;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/* Find clk for the device */
147662306a36Sopenharmony_ci	opp_table->clk = clk_get(dev, NULL);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	ret = PTR_ERR_OR_ZERO(opp_table->clk);
147962306a36Sopenharmony_ci	if (!ret) {
148062306a36Sopenharmony_ci		opp_table->config_clks = _opp_config_clk_single;
148162306a36Sopenharmony_ci		opp_table->clk_count = 1;
148262306a36Sopenharmony_ci		return opp_table;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (ret == -ENOENT) {
148662306a36Sopenharmony_ci		/*
148762306a36Sopenharmony_ci		 * There are few platforms which don't want the OPP core to
148862306a36Sopenharmony_ci		 * manage device's clock settings. In such cases neither the
148962306a36Sopenharmony_ci		 * platform provides the clks explicitly to us, nor the DT
149062306a36Sopenharmony_ci		 * contains a valid clk entry. The OPP nodes in DT may still
149162306a36Sopenharmony_ci		 * contain "opp-hz" property though, which we need to parse and
149262306a36Sopenharmony_ci		 * allow the platform to find an OPP based on freq later on.
149362306a36Sopenharmony_ci		 *
149462306a36Sopenharmony_ci		 * This is a simple solution to take care of such corner cases,
149562306a36Sopenharmony_ci		 * i.e. make the clk_count 1, which lets us allocate space for
149662306a36Sopenharmony_ci		 * frequency in opp->rates and also parse the entries in DT.
149762306a36Sopenharmony_ci		 */
149862306a36Sopenharmony_ci		opp_table->clk_count = 1;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
150162306a36Sopenharmony_ci		return opp_table;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
150562306a36Sopenharmony_ci	dev_err_probe(dev, ret, "Couldn't find clock\n");
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	return ERR_PTR(ret);
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci/*
151162306a36Sopenharmony_ci * We need to make sure that the OPP table for a device doesn't get added twice,
151262306a36Sopenharmony_ci * if this routine gets called in parallel with the same device pointer.
151362306a36Sopenharmony_ci *
151462306a36Sopenharmony_ci * The simplest way to enforce that is to perform everything (find existing
151562306a36Sopenharmony_ci * table and if not found, create a new one) under the opp_table_lock, so only
151662306a36Sopenharmony_ci * one creator gets access to the same. But that expands the critical section
151762306a36Sopenharmony_ci * under the lock and may end up causing circular dependencies with frameworks
151862306a36Sopenharmony_ci * like debugfs, interconnect or clock framework as they may be direct or
151962306a36Sopenharmony_ci * indirect users of OPP core.
152062306a36Sopenharmony_ci *
152162306a36Sopenharmony_ci * And for that reason we have to go for a bit tricky implementation here, which
152262306a36Sopenharmony_ci * uses the opp_tables_busy flag to indicate if another creator is in the middle
152362306a36Sopenharmony_ci * of adding an OPP table and others should wait for it to finish.
152462306a36Sopenharmony_ci */
152562306a36Sopenharmony_cistruct opp_table *_add_opp_table_indexed(struct device *dev, int index,
152662306a36Sopenharmony_ci					 bool getclk)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	struct opp_table *opp_table;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ciagain:
153162306a36Sopenharmony_ci	mutex_lock(&opp_table_lock);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	opp_table = _find_opp_table_unlocked(dev);
153462306a36Sopenharmony_ci	if (!IS_ERR(opp_table))
153562306a36Sopenharmony_ci		goto unlock;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	/*
153862306a36Sopenharmony_ci	 * The opp_tables list or an OPP table's dev_list is getting updated by
153962306a36Sopenharmony_ci	 * another user, wait for it to finish.
154062306a36Sopenharmony_ci	 */
154162306a36Sopenharmony_ci	if (unlikely(opp_tables_busy)) {
154262306a36Sopenharmony_ci		mutex_unlock(&opp_table_lock);
154362306a36Sopenharmony_ci		cpu_relax();
154462306a36Sopenharmony_ci		goto again;
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	opp_tables_busy = true;
154862306a36Sopenharmony_ci	opp_table = _managed_opp(dev, index);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/* Drop the lock to reduce the size of critical section */
155162306a36Sopenharmony_ci	mutex_unlock(&opp_table_lock);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (opp_table) {
155462306a36Sopenharmony_ci		if (!_add_opp_dev(dev, opp_table)) {
155562306a36Sopenharmony_ci			dev_pm_opp_put_opp_table(opp_table);
155662306a36Sopenharmony_ci			opp_table = ERR_PTR(-ENOMEM);
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci		mutex_lock(&opp_table_lock);
156062306a36Sopenharmony_ci	} else {
156162306a36Sopenharmony_ci		opp_table = _allocate_opp_table(dev, index);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci		mutex_lock(&opp_table_lock);
156462306a36Sopenharmony_ci		if (!IS_ERR(opp_table))
156562306a36Sopenharmony_ci			list_add(&opp_table->node, &opp_tables);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	opp_tables_busy = false;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ciunlock:
157162306a36Sopenharmony_ci	mutex_unlock(&opp_table_lock);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	return _update_opp_table_clk(dev, opp_table, getclk);
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic struct opp_table *_add_opp_table(struct device *dev, bool getclk)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	return _add_opp_table_indexed(dev, 0, getclk);
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistruct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	return _find_opp_table(dev);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic void _opp_table_kref_release(struct kref *kref)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
159062306a36Sopenharmony_ci	struct opp_device *opp_dev, *temp;
159162306a36Sopenharmony_ci	int i;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* Drop the lock as soon as we can */
159462306a36Sopenharmony_ci	list_del(&opp_table->node);
159562306a36Sopenharmony_ci	mutex_unlock(&opp_table_lock);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (opp_table->current_opp)
159862306a36Sopenharmony_ci		dev_pm_opp_put(opp_table->current_opp);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	_of_clear_opp_table(opp_table);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	/* Release automatically acquired single clk */
160362306a36Sopenharmony_ci	if (!IS_ERR(opp_table->clk))
160462306a36Sopenharmony_ci		clk_put(opp_table->clk);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (opp_table->paths) {
160762306a36Sopenharmony_ci		for (i = 0; i < opp_table->path_count; i++)
160862306a36Sopenharmony_ci			icc_put(opp_table->paths[i]);
160962306a36Sopenharmony_ci		kfree(opp_table->paths);
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	WARN_ON(!list_empty(&opp_table->opp_list));
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node)
161562306a36Sopenharmony_ci		_remove_opp_dev(opp_dev, opp_table);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	mutex_destroy(&opp_table->genpd_virt_dev_lock);
161862306a36Sopenharmony_ci	mutex_destroy(&opp_table->lock);
161962306a36Sopenharmony_ci	kfree(opp_table);
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_civoid dev_pm_opp_put_opp_table(struct opp_table *opp_table)
162362306a36Sopenharmony_ci{
162462306a36Sopenharmony_ci	kref_put_mutex(&opp_table->kref, _opp_table_kref_release,
162562306a36Sopenharmony_ci		       &opp_table_lock);
162662306a36Sopenharmony_ci}
162762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_put_opp_table);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_civoid _opp_free(struct dev_pm_opp *opp)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	kfree(opp);
163262306a36Sopenharmony_ci}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_cistatic void _opp_kref_release(struct kref *kref)
163562306a36Sopenharmony_ci{
163662306a36Sopenharmony_ci	struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
163762306a36Sopenharmony_ci	struct opp_table *opp_table = opp->opp_table;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	list_del(&opp->node);
164062306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * Notify the changes in the availability of the operable
164462306a36Sopenharmony_ci	 * frequency/voltage list.
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
164762306a36Sopenharmony_ci	_of_clear_opp(opp_table, opp);
164862306a36Sopenharmony_ci	opp_debug_remove_one(opp);
164962306a36Sopenharmony_ci	kfree(opp);
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_civoid dev_pm_opp_get(struct dev_pm_opp *opp)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	kref_get(&opp->kref);
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_civoid dev_pm_opp_put(struct dev_pm_opp *opp)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock);
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_put);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci/**
166462306a36Sopenharmony_ci * dev_pm_opp_remove()  - Remove an OPP from OPP table
166562306a36Sopenharmony_ci * @dev:	device for which we do this operation
166662306a36Sopenharmony_ci * @freq:	OPP to remove with matching 'freq'
166762306a36Sopenharmony_ci *
166862306a36Sopenharmony_ci * This function removes an opp from the opp table.
166962306a36Sopenharmony_ci */
167062306a36Sopenharmony_civoid dev_pm_opp_remove(struct device *dev, unsigned long freq)
167162306a36Sopenharmony_ci{
167262306a36Sopenharmony_ci	struct dev_pm_opp *opp = NULL, *iter;
167362306a36Sopenharmony_ci	struct opp_table *opp_table;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
167662306a36Sopenharmony_ci	if (IS_ERR(opp_table))
167762306a36Sopenharmony_ci		return;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	if (!assert_single_clk(opp_table))
168062306a36Sopenharmony_ci		goto put_table;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	list_for_each_entry(iter, &opp_table->opp_list, node) {
168562306a36Sopenharmony_ci		if (iter->rates[0] == freq) {
168662306a36Sopenharmony_ci			opp = iter;
168762306a36Sopenharmony_ci			break;
168862306a36Sopenharmony_ci		}
168962306a36Sopenharmony_ci	}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (opp) {
169462306a36Sopenharmony_ci		dev_pm_opp_put(opp);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci		/* Drop the reference taken by dev_pm_opp_add() */
169762306a36Sopenharmony_ci		dev_pm_opp_put_opp_table(opp_table);
169862306a36Sopenharmony_ci	} else {
169962306a36Sopenharmony_ci		dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
170062306a36Sopenharmony_ci			 __func__, freq);
170162306a36Sopenharmony_ci	}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ciput_table:
170462306a36Sopenharmony_ci	/* Drop the reference taken by _find_opp_table() */
170562306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_remove);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic struct dev_pm_opp *_opp_get_next(struct opp_table *opp_table,
171062306a36Sopenharmony_ci					bool dynamic)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	struct dev_pm_opp *opp = NULL, *temp;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
171562306a36Sopenharmony_ci	list_for_each_entry(temp, &opp_table->opp_list, node) {
171662306a36Sopenharmony_ci		/*
171762306a36Sopenharmony_ci		 * Refcount must be dropped only once for each OPP by OPP core,
171862306a36Sopenharmony_ci		 * do that with help of "removed" flag.
171962306a36Sopenharmony_ci		 */
172062306a36Sopenharmony_ci		if (!temp->removed && dynamic == temp->dynamic) {
172162306a36Sopenharmony_ci			opp = temp;
172262306a36Sopenharmony_ci			break;
172362306a36Sopenharmony_ci		}
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
172762306a36Sopenharmony_ci	return opp;
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci/*
173162306a36Sopenharmony_ci * Can't call dev_pm_opp_put() from under the lock as debugfs removal needs to
173262306a36Sopenharmony_ci * happen lock less to avoid circular dependency issues. This routine must be
173362306a36Sopenharmony_ci * called without the opp_table->lock held.
173462306a36Sopenharmony_ci */
173562306a36Sopenharmony_cistatic void _opp_remove_all(struct opp_table *opp_table, bool dynamic)
173662306a36Sopenharmony_ci{
173762306a36Sopenharmony_ci	struct dev_pm_opp *opp;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	while ((opp = _opp_get_next(opp_table, dynamic))) {
174062306a36Sopenharmony_ci		opp->removed = true;
174162306a36Sopenharmony_ci		dev_pm_opp_put(opp);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci		/* Drop the references taken by dev_pm_opp_add() */
174462306a36Sopenharmony_ci		if (dynamic)
174562306a36Sopenharmony_ci			dev_pm_opp_put_opp_table(opp_table);
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cibool _opp_remove_all_static(struct opp_table *opp_table)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	if (!opp_table->parsed_static_opps) {
175462306a36Sopenharmony_ci		mutex_unlock(&opp_table->lock);
175562306a36Sopenharmony_ci		return false;
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	if (--opp_table->parsed_static_opps) {
175962306a36Sopenharmony_ci		mutex_unlock(&opp_table->lock);
176062306a36Sopenharmony_ci		return true;
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	_opp_remove_all(opp_table, false);
176662306a36Sopenharmony_ci	return true;
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci/**
177062306a36Sopenharmony_ci * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
177162306a36Sopenharmony_ci * @dev:	device for which we do this operation
177262306a36Sopenharmony_ci *
177362306a36Sopenharmony_ci * This function removes all dynamically created OPPs from the opp table.
177462306a36Sopenharmony_ci */
177562306a36Sopenharmony_civoid dev_pm_opp_remove_all_dynamic(struct device *dev)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	struct opp_table *opp_table;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
178062306a36Sopenharmony_ci	if (IS_ERR(opp_table))
178162306a36Sopenharmony_ci		return;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	_opp_remove_all(opp_table, true);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	/* Drop the reference taken by _find_opp_table() */
178662306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_cistruct dev_pm_opp *_opp_allocate(struct opp_table *opp_table)
179162306a36Sopenharmony_ci{
179262306a36Sopenharmony_ci	struct dev_pm_opp *opp;
179362306a36Sopenharmony_ci	int supply_count, supply_size, icc_size, clk_size;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* Allocate space for at least one supply */
179662306a36Sopenharmony_ci	supply_count = opp_table->regulator_count > 0 ?
179762306a36Sopenharmony_ci			opp_table->regulator_count : 1;
179862306a36Sopenharmony_ci	supply_size = sizeof(*opp->supplies) * supply_count;
179962306a36Sopenharmony_ci	clk_size = sizeof(*opp->rates) * opp_table->clk_count;
180062306a36Sopenharmony_ci	icc_size = sizeof(*opp->bandwidth) * opp_table->path_count;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	/* allocate new OPP node and supplies structures */
180362306a36Sopenharmony_ci	opp = kzalloc(sizeof(*opp) + supply_size + clk_size + icc_size, GFP_KERNEL);
180462306a36Sopenharmony_ci	if (!opp)
180562306a36Sopenharmony_ci		return NULL;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	/* Put the supplies, bw and clock at the end of the OPP structure */
180862306a36Sopenharmony_ci	opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	opp->rates = (unsigned long *)(opp->supplies + supply_count);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	if (icc_size)
181362306a36Sopenharmony_ci		opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->rates + opp_table->clk_count);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	INIT_LIST_HEAD(&opp->node);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	return opp;
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
182162306a36Sopenharmony_ci					 struct opp_table *opp_table)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct regulator *reg;
182462306a36Sopenharmony_ci	int i;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	if (!opp_table->regulators)
182762306a36Sopenharmony_ci		return true;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	for (i = 0; i < opp_table->regulator_count; i++) {
183062306a36Sopenharmony_ci		reg = opp_table->regulators[i];
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci		if (!regulator_is_supported_voltage(reg,
183362306a36Sopenharmony_ci					opp->supplies[i].u_volt_min,
183462306a36Sopenharmony_ci					opp->supplies[i].u_volt_max)) {
183562306a36Sopenharmony_ci			pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
183662306a36Sopenharmony_ci				__func__, opp->supplies[i].u_volt_min,
183762306a36Sopenharmony_ci				opp->supplies[i].u_volt_max);
183862306a36Sopenharmony_ci			return false;
183962306a36Sopenharmony_ci		}
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	return true;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic int _opp_compare_rate(struct opp_table *opp_table,
184662306a36Sopenharmony_ci			     struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	int i;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	for (i = 0; i < opp_table->clk_count; i++) {
185162306a36Sopenharmony_ci		if (opp1->rates[i] != opp2->rates[i])
185262306a36Sopenharmony_ci			return opp1->rates[i] < opp2->rates[i] ? -1 : 1;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	/* Same rates for both OPPs */
185662306a36Sopenharmony_ci	return 0;
185762306a36Sopenharmony_ci}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_cistatic int _opp_compare_bw(struct opp_table *opp_table, struct dev_pm_opp *opp1,
186062306a36Sopenharmony_ci			   struct dev_pm_opp *opp2)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	int i;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	for (i = 0; i < opp_table->path_count; i++) {
186562306a36Sopenharmony_ci		if (opp1->bandwidth[i].peak != opp2->bandwidth[i].peak)
186662306a36Sopenharmony_ci			return opp1->bandwidth[i].peak < opp2->bandwidth[i].peak ? -1 : 1;
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	/* Same bw for both OPPs */
187062306a36Sopenharmony_ci	return 0;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci/*
187462306a36Sopenharmony_ci * Returns
187562306a36Sopenharmony_ci * 0: opp1 == opp2
187662306a36Sopenharmony_ci * 1: opp1 > opp2
187762306a36Sopenharmony_ci * -1: opp1 < opp2
187862306a36Sopenharmony_ci */
187962306a36Sopenharmony_ciint _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1,
188062306a36Sopenharmony_ci		     struct dev_pm_opp *opp2)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	int ret;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	ret = _opp_compare_rate(opp_table, opp1, opp2);
188562306a36Sopenharmony_ci	if (ret)
188662306a36Sopenharmony_ci		return ret;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	ret = _opp_compare_bw(opp_table, opp1, opp2);
188962306a36Sopenharmony_ci	if (ret)
189062306a36Sopenharmony_ci		return ret;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	if (opp1->level != opp2->level)
189362306a36Sopenharmony_ci		return opp1->level < opp2->level ? -1 : 1;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	/* Duplicate OPPs */
189662306a36Sopenharmony_ci	return 0;
189762306a36Sopenharmony_ci}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_cistatic int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
190062306a36Sopenharmony_ci			     struct opp_table *opp_table,
190162306a36Sopenharmony_ci			     struct list_head **head)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	struct dev_pm_opp *opp;
190462306a36Sopenharmony_ci	int opp_cmp;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	/*
190762306a36Sopenharmony_ci	 * Insert new OPP in order of increasing frequency and discard if
190862306a36Sopenharmony_ci	 * already present.
190962306a36Sopenharmony_ci	 *
191062306a36Sopenharmony_ci	 * Need to use &opp_table->opp_list in the condition part of the 'for'
191162306a36Sopenharmony_ci	 * loop, don't replace it with head otherwise it will become an infinite
191262306a36Sopenharmony_ci	 * loop.
191362306a36Sopenharmony_ci	 */
191462306a36Sopenharmony_ci	list_for_each_entry(opp, &opp_table->opp_list, node) {
191562306a36Sopenharmony_ci		opp_cmp = _opp_compare_key(opp_table, new_opp, opp);
191662306a36Sopenharmony_ci		if (opp_cmp > 0) {
191762306a36Sopenharmony_ci			*head = &opp->node;
191862306a36Sopenharmony_ci			continue;
191962306a36Sopenharmony_ci		}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci		if (opp_cmp < 0)
192262306a36Sopenharmony_ci			return 0;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		/* Duplicate OPPs */
192562306a36Sopenharmony_ci		dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
192662306a36Sopenharmony_ci			 __func__, opp->rates[0], opp->supplies[0].u_volt,
192762306a36Sopenharmony_ci			 opp->available, new_opp->rates[0],
192862306a36Sopenharmony_ci			 new_opp->supplies[0].u_volt, new_opp->available);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci		/* Should we compare voltages for all regulators here ? */
193162306a36Sopenharmony_ci		return opp->available &&
193262306a36Sopenharmony_ci		       new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	return 0;
193662306a36Sopenharmony_ci}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_civoid _required_opps_available(struct dev_pm_opp *opp, int count)
193962306a36Sopenharmony_ci{
194062306a36Sopenharmony_ci	int i;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
194362306a36Sopenharmony_ci		if (opp->required_opps[i]->available)
194462306a36Sopenharmony_ci			continue;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		opp->available = false;
194762306a36Sopenharmony_ci		pr_warn("%s: OPP not supported by required OPP %pOF (%lu)\n",
194862306a36Sopenharmony_ci			 __func__, opp->required_opps[i]->np, opp->rates[0]);
194962306a36Sopenharmony_ci		return;
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci/*
195462306a36Sopenharmony_ci * Returns:
195562306a36Sopenharmony_ci * 0: On success. And appropriate error message for duplicate OPPs.
195662306a36Sopenharmony_ci * -EBUSY: For OPP with same freq/volt and is available. The callers of
195762306a36Sopenharmony_ci *  _opp_add() must return 0 if they receive -EBUSY from it. This is to make
195862306a36Sopenharmony_ci *  sure we don't print error messages unnecessarily if different parts of
195962306a36Sopenharmony_ci *  kernel try to initialize the OPP table.
196062306a36Sopenharmony_ci * -EEXIST: For OPP with same freq but different volt or is unavailable. This
196162306a36Sopenharmony_ci *  should be considered an error by the callers of _opp_add().
196262306a36Sopenharmony_ci */
196362306a36Sopenharmony_ciint _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
196462306a36Sopenharmony_ci	     struct opp_table *opp_table)
196562306a36Sopenharmony_ci{
196662306a36Sopenharmony_ci	struct list_head *head;
196762306a36Sopenharmony_ci	int ret;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
197062306a36Sopenharmony_ci	head = &opp_table->opp_list;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	ret = _opp_is_duplicate(dev, new_opp, opp_table, &head);
197362306a36Sopenharmony_ci	if (ret) {
197462306a36Sopenharmony_ci		mutex_unlock(&opp_table->lock);
197562306a36Sopenharmony_ci		return ret;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	list_add(&new_opp->node, head);
197962306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	new_opp->opp_table = opp_table;
198262306a36Sopenharmony_ci	kref_init(&new_opp->kref);
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	opp_debug_create_one(new_opp, opp_table);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (!_opp_supported_by_regulators(new_opp, opp_table)) {
198762306a36Sopenharmony_ci		new_opp->available = false;
198862306a36Sopenharmony_ci		dev_warn(dev, "%s: OPP not supported by regulators (%lu)\n",
198962306a36Sopenharmony_ci			 __func__, new_opp->rates[0]);
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	/* required-opps not fully initialized yet */
199362306a36Sopenharmony_ci	if (lazy_linking_pending(opp_table))
199462306a36Sopenharmony_ci		return 0;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	_required_opps_available(new_opp, opp_table->required_opp_count);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	return 0;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci/**
200262306a36Sopenharmony_ci * _opp_add_v1() - Allocate a OPP based on v1 bindings.
200362306a36Sopenharmony_ci * @opp_table:	OPP table
200462306a36Sopenharmony_ci * @dev:	device for which we do this operation
200562306a36Sopenharmony_ci * @freq:	Frequency in Hz for this OPP
200662306a36Sopenharmony_ci * @u_volt:	Voltage in uVolts for this OPP
200762306a36Sopenharmony_ci * @dynamic:	Dynamically added OPPs.
200862306a36Sopenharmony_ci *
200962306a36Sopenharmony_ci * This function adds an opp definition to the opp table and returns status.
201062306a36Sopenharmony_ci * The opp is made available by default and it can be controlled using
201162306a36Sopenharmony_ci * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
201262306a36Sopenharmony_ci *
201362306a36Sopenharmony_ci * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
201462306a36Sopenharmony_ci * and freed by dev_pm_opp_of_remove_table.
201562306a36Sopenharmony_ci *
201662306a36Sopenharmony_ci * Return:
201762306a36Sopenharmony_ci * 0		On success OR
201862306a36Sopenharmony_ci *		Duplicate OPPs (both freq and volt are same) and opp->available
201962306a36Sopenharmony_ci * -EEXIST	Freq are same and volt are different OR
202062306a36Sopenharmony_ci *		Duplicate OPPs (both freq and volt are same) and !opp->available
202162306a36Sopenharmony_ci * -ENOMEM	Memory allocation failure
202262306a36Sopenharmony_ci */
202362306a36Sopenharmony_ciint _opp_add_v1(struct opp_table *opp_table, struct device *dev,
202462306a36Sopenharmony_ci		unsigned long freq, long u_volt, bool dynamic)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	struct dev_pm_opp *new_opp;
202762306a36Sopenharmony_ci	unsigned long tol;
202862306a36Sopenharmony_ci	int ret;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (!assert_single_clk(opp_table))
203162306a36Sopenharmony_ci		return -EINVAL;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	new_opp = _opp_allocate(opp_table);
203462306a36Sopenharmony_ci	if (!new_opp)
203562306a36Sopenharmony_ci		return -ENOMEM;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	/* populate the opp table */
203862306a36Sopenharmony_ci	new_opp->rates[0] = freq;
203962306a36Sopenharmony_ci	tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
204062306a36Sopenharmony_ci	new_opp->supplies[0].u_volt = u_volt;
204162306a36Sopenharmony_ci	new_opp->supplies[0].u_volt_min = u_volt - tol;
204262306a36Sopenharmony_ci	new_opp->supplies[0].u_volt_max = u_volt + tol;
204362306a36Sopenharmony_ci	new_opp->available = true;
204462306a36Sopenharmony_ci	new_opp->dynamic = dynamic;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	ret = _opp_add(dev, new_opp, opp_table);
204762306a36Sopenharmony_ci	if (ret) {
204862306a36Sopenharmony_ci		/* Don't return error for duplicate OPPs */
204962306a36Sopenharmony_ci		if (ret == -EBUSY)
205062306a36Sopenharmony_ci			ret = 0;
205162306a36Sopenharmony_ci		goto free_opp;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	/*
205562306a36Sopenharmony_ci	 * Notify the changes in the availability of the operable
205662306a36Sopenharmony_ci	 * frequency/voltage list.
205762306a36Sopenharmony_ci	 */
205862306a36Sopenharmony_ci	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
205962306a36Sopenharmony_ci	return 0;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cifree_opp:
206262306a36Sopenharmony_ci	_opp_free(new_opp);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	return ret;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci/**
206862306a36Sopenharmony_ci * _opp_set_supported_hw() - Set supported platforms
206962306a36Sopenharmony_ci * @dev: Device for which supported-hw has to be set.
207062306a36Sopenharmony_ci * @versions: Array of hierarchy of versions to match.
207162306a36Sopenharmony_ci * @count: Number of elements in the array.
207262306a36Sopenharmony_ci *
207362306a36Sopenharmony_ci * This is required only for the V2 bindings, and it enables a platform to
207462306a36Sopenharmony_ci * specify the hierarchy of versions it supports. OPP layer will then enable
207562306a36Sopenharmony_ci * OPPs, which are available for those versions, based on its 'opp-supported-hw'
207662306a36Sopenharmony_ci * property.
207762306a36Sopenharmony_ci */
207862306a36Sopenharmony_cistatic int _opp_set_supported_hw(struct opp_table *opp_table,
207962306a36Sopenharmony_ci				 const u32 *versions, unsigned int count)
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	/* Another CPU that shares the OPP table has set the property ? */
208262306a36Sopenharmony_ci	if (opp_table->supported_hw)
208362306a36Sopenharmony_ci		return 0;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
208662306a36Sopenharmony_ci					GFP_KERNEL);
208762306a36Sopenharmony_ci	if (!opp_table->supported_hw)
208862306a36Sopenharmony_ci		return -ENOMEM;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	opp_table->supported_hw_count = count;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	return 0;
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci/**
209662306a36Sopenharmony_ci * _opp_put_supported_hw() - Releases resources blocked for supported hw
209762306a36Sopenharmony_ci * @opp_table: OPP table returned by _opp_set_supported_hw().
209862306a36Sopenharmony_ci *
209962306a36Sopenharmony_ci * This is required only for the V2 bindings, and is called for a matching
210062306a36Sopenharmony_ci * _opp_set_supported_hw(). Until this is called, the opp_table structure
210162306a36Sopenharmony_ci * will not be freed.
210262306a36Sopenharmony_ci */
210362306a36Sopenharmony_cistatic void _opp_put_supported_hw(struct opp_table *opp_table)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	if (opp_table->supported_hw) {
210662306a36Sopenharmony_ci		kfree(opp_table->supported_hw);
210762306a36Sopenharmony_ci		opp_table->supported_hw = NULL;
210862306a36Sopenharmony_ci		opp_table->supported_hw_count = 0;
210962306a36Sopenharmony_ci	}
211062306a36Sopenharmony_ci}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci/**
211362306a36Sopenharmony_ci * _opp_set_prop_name() - Set prop-extn name
211462306a36Sopenharmony_ci * @dev: Device for which the prop-name has to be set.
211562306a36Sopenharmony_ci * @name: name to postfix to properties.
211662306a36Sopenharmony_ci *
211762306a36Sopenharmony_ci * This is required only for the V2 bindings, and it enables a platform to
211862306a36Sopenharmony_ci * specify the extn to be used for certain property names. The properties to
211962306a36Sopenharmony_ci * which the extension will apply are opp-microvolt and opp-microamp. OPP core
212062306a36Sopenharmony_ci * should postfix the property name with -<name> while looking for them.
212162306a36Sopenharmony_ci */
212262306a36Sopenharmony_cistatic int _opp_set_prop_name(struct opp_table *opp_table, const char *name)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	/* Another CPU that shares the OPP table has set the property ? */
212562306a36Sopenharmony_ci	if (!opp_table->prop_name) {
212662306a36Sopenharmony_ci		opp_table->prop_name = kstrdup(name, GFP_KERNEL);
212762306a36Sopenharmony_ci		if (!opp_table->prop_name)
212862306a36Sopenharmony_ci			return -ENOMEM;
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	return 0;
213262306a36Sopenharmony_ci}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci/**
213562306a36Sopenharmony_ci * _opp_put_prop_name() - Releases resources blocked for prop-name
213662306a36Sopenharmony_ci * @opp_table: OPP table returned by _opp_set_prop_name().
213762306a36Sopenharmony_ci *
213862306a36Sopenharmony_ci * This is required only for the V2 bindings, and is called for a matching
213962306a36Sopenharmony_ci * _opp_set_prop_name(). Until this is called, the opp_table structure
214062306a36Sopenharmony_ci * will not be freed.
214162306a36Sopenharmony_ci */
214262306a36Sopenharmony_cistatic void _opp_put_prop_name(struct opp_table *opp_table)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	if (opp_table->prop_name) {
214562306a36Sopenharmony_ci		kfree(opp_table->prop_name);
214662306a36Sopenharmony_ci		opp_table->prop_name = NULL;
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci/**
215162306a36Sopenharmony_ci * _opp_set_regulators() - Set regulator names for the device
215262306a36Sopenharmony_ci * @dev: Device for which regulator name is being set.
215362306a36Sopenharmony_ci * @names: Array of pointers to the names of the regulator.
215462306a36Sopenharmony_ci * @count: Number of regulators.
215562306a36Sopenharmony_ci *
215662306a36Sopenharmony_ci * In order to support OPP switching, OPP layer needs to know the name of the
215762306a36Sopenharmony_ci * device's regulators, as the core would be required to switch voltages as
215862306a36Sopenharmony_ci * well.
215962306a36Sopenharmony_ci *
216062306a36Sopenharmony_ci * This must be called before any OPPs are initialized for the device.
216162306a36Sopenharmony_ci */
216262306a36Sopenharmony_cistatic int _opp_set_regulators(struct opp_table *opp_table, struct device *dev,
216362306a36Sopenharmony_ci			       const char * const names[])
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	const char * const *temp = names;
216662306a36Sopenharmony_ci	struct regulator *reg;
216762306a36Sopenharmony_ci	int count = 0, ret, i;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	/* Count number of regulators */
217062306a36Sopenharmony_ci	while (*temp++)
217162306a36Sopenharmony_ci		count++;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	if (!count)
217462306a36Sopenharmony_ci		return -EINVAL;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	/* Another CPU that shares the OPP table has set the regulators ? */
217762306a36Sopenharmony_ci	if (opp_table->regulators)
217862306a36Sopenharmony_ci		return 0;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	opp_table->regulators = kmalloc_array(count,
218162306a36Sopenharmony_ci					      sizeof(*opp_table->regulators),
218262306a36Sopenharmony_ci					      GFP_KERNEL);
218362306a36Sopenharmony_ci	if (!opp_table->regulators)
218462306a36Sopenharmony_ci		return -ENOMEM;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
218762306a36Sopenharmony_ci		reg = regulator_get_optional(dev, names[i]);
218862306a36Sopenharmony_ci		if (IS_ERR(reg)) {
218962306a36Sopenharmony_ci			ret = dev_err_probe(dev, PTR_ERR(reg),
219062306a36Sopenharmony_ci					    "%s: no regulator (%s) found\n",
219162306a36Sopenharmony_ci					    __func__, names[i]);
219262306a36Sopenharmony_ci			goto free_regulators;
219362306a36Sopenharmony_ci		}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci		opp_table->regulators[i] = reg;
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	opp_table->regulator_count = count;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	/* Set generic config_regulators() for single regulators here */
220162306a36Sopenharmony_ci	if (count == 1)
220262306a36Sopenharmony_ci		opp_table->config_regulators = _opp_config_regulator_single;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	return 0;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cifree_regulators:
220762306a36Sopenharmony_ci	while (i != 0)
220862306a36Sopenharmony_ci		regulator_put(opp_table->regulators[--i]);
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	kfree(opp_table->regulators);
221162306a36Sopenharmony_ci	opp_table->regulators = NULL;
221262306a36Sopenharmony_ci	opp_table->regulator_count = -1;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	return ret;
221562306a36Sopenharmony_ci}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci/**
221862306a36Sopenharmony_ci * _opp_put_regulators() - Releases resources blocked for regulator
221962306a36Sopenharmony_ci * @opp_table: OPP table returned from _opp_set_regulators().
222062306a36Sopenharmony_ci */
222162306a36Sopenharmony_cistatic void _opp_put_regulators(struct opp_table *opp_table)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	int i;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (!opp_table->regulators)
222662306a36Sopenharmony_ci		return;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	if (opp_table->enabled) {
222962306a36Sopenharmony_ci		for (i = opp_table->regulator_count - 1; i >= 0; i--)
223062306a36Sopenharmony_ci			regulator_disable(opp_table->regulators[i]);
223162306a36Sopenharmony_ci	}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	for (i = opp_table->regulator_count - 1; i >= 0; i--)
223462306a36Sopenharmony_ci		regulator_put(opp_table->regulators[i]);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	kfree(opp_table->regulators);
223762306a36Sopenharmony_ci	opp_table->regulators = NULL;
223862306a36Sopenharmony_ci	opp_table->regulator_count = -1;
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_cistatic void _put_clks(struct opp_table *opp_table, int count)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	int i;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	for (i = count - 1; i >= 0; i--)
224662306a36Sopenharmony_ci		clk_put(opp_table->clks[i]);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	kfree(opp_table->clks);
224962306a36Sopenharmony_ci	opp_table->clks = NULL;
225062306a36Sopenharmony_ci}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci/**
225362306a36Sopenharmony_ci * _opp_set_clknames() - Set clk names for the device
225462306a36Sopenharmony_ci * @dev: Device for which clk names is being set.
225562306a36Sopenharmony_ci * @names: Clk names.
225662306a36Sopenharmony_ci *
225762306a36Sopenharmony_ci * In order to support OPP switching, OPP layer needs to get pointers to the
225862306a36Sopenharmony_ci * clocks for the device. Simple cases work fine without using this routine
225962306a36Sopenharmony_ci * (i.e. by passing connection-id as NULL), but for a device with multiple
226062306a36Sopenharmony_ci * clocks available, the OPP core needs to know the exact names of the clks to
226162306a36Sopenharmony_ci * use.
226262306a36Sopenharmony_ci *
226362306a36Sopenharmony_ci * This must be called before any OPPs are initialized for the device.
226462306a36Sopenharmony_ci */
226562306a36Sopenharmony_cistatic int _opp_set_clknames(struct opp_table *opp_table, struct device *dev,
226662306a36Sopenharmony_ci			     const char * const names[],
226762306a36Sopenharmony_ci			     config_clks_t config_clks)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	const char * const *temp = names;
227062306a36Sopenharmony_ci	int count = 0, ret, i;
227162306a36Sopenharmony_ci	struct clk *clk;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	/* Count number of clks */
227462306a36Sopenharmony_ci	while (*temp++)
227562306a36Sopenharmony_ci		count++;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/*
227862306a36Sopenharmony_ci	 * This is a special case where we have a single clock, whose connection
227962306a36Sopenharmony_ci	 * id name is NULL, i.e. first two entries are NULL in the array.
228062306a36Sopenharmony_ci	 */
228162306a36Sopenharmony_ci	if (!count && !names[1])
228262306a36Sopenharmony_ci		count = 1;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/* Fail early for invalid configurations */
228562306a36Sopenharmony_ci	if (!count || (!config_clks && count > 1))
228662306a36Sopenharmony_ci		return -EINVAL;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	/* Another CPU that shares the OPP table has set the clkname ? */
228962306a36Sopenharmony_ci	if (opp_table->clks)
229062306a36Sopenharmony_ci		return 0;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	opp_table->clks = kmalloc_array(count, sizeof(*opp_table->clks),
229362306a36Sopenharmony_ci					GFP_KERNEL);
229462306a36Sopenharmony_ci	if (!opp_table->clks)
229562306a36Sopenharmony_ci		return -ENOMEM;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	/* Find clks for the device */
229862306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
229962306a36Sopenharmony_ci		clk = clk_get(dev, names[i]);
230062306a36Sopenharmony_ci		if (IS_ERR(clk)) {
230162306a36Sopenharmony_ci			ret = dev_err_probe(dev, PTR_ERR(clk),
230262306a36Sopenharmony_ci					    "%s: Couldn't find clock with name: %s\n",
230362306a36Sopenharmony_ci					    __func__, names[i]);
230462306a36Sopenharmony_ci			goto free_clks;
230562306a36Sopenharmony_ci		}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci		opp_table->clks[i] = clk;
230862306a36Sopenharmony_ci	}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	opp_table->clk_count = count;
231162306a36Sopenharmony_ci	opp_table->config_clks = config_clks;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	/* Set generic single clk set here */
231462306a36Sopenharmony_ci	if (count == 1) {
231562306a36Sopenharmony_ci		if (!opp_table->config_clks)
231662306a36Sopenharmony_ci			opp_table->config_clks = _opp_config_clk_single;
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci		/*
231962306a36Sopenharmony_ci		 * We could have just dropped the "clk" field and used "clks"
232062306a36Sopenharmony_ci		 * everywhere. Instead we kept the "clk" field around for
232162306a36Sopenharmony_ci		 * following reasons:
232262306a36Sopenharmony_ci		 *
232362306a36Sopenharmony_ci		 * - avoiding clks[0] everywhere else.
232462306a36Sopenharmony_ci		 * - not running single clk helpers for multiple clk usecase by
232562306a36Sopenharmony_ci		 *   mistake.
232662306a36Sopenharmony_ci		 *
232762306a36Sopenharmony_ci		 * Since this is single-clk case, just update the clk pointer
232862306a36Sopenharmony_ci		 * too.
232962306a36Sopenharmony_ci		 */
233062306a36Sopenharmony_ci		opp_table->clk = opp_table->clks[0];
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	return 0;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_cifree_clks:
233662306a36Sopenharmony_ci	_put_clks(opp_table, i);
233762306a36Sopenharmony_ci	return ret;
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci/**
234162306a36Sopenharmony_ci * _opp_put_clknames() - Releases resources blocked for clks.
234262306a36Sopenharmony_ci * @opp_table: OPP table returned from _opp_set_clknames().
234362306a36Sopenharmony_ci */
234462306a36Sopenharmony_cistatic void _opp_put_clknames(struct opp_table *opp_table)
234562306a36Sopenharmony_ci{
234662306a36Sopenharmony_ci	if (!opp_table->clks)
234762306a36Sopenharmony_ci		return;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	opp_table->config_clks = NULL;
235062306a36Sopenharmony_ci	opp_table->clk = ERR_PTR(-ENODEV);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	_put_clks(opp_table, opp_table->clk_count);
235362306a36Sopenharmony_ci}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci/**
235662306a36Sopenharmony_ci * _opp_set_config_regulators_helper() - Register custom set regulator helper.
235762306a36Sopenharmony_ci * @dev: Device for which the helper is getting registered.
235862306a36Sopenharmony_ci * @config_regulators: Custom set regulator helper.
235962306a36Sopenharmony_ci *
236062306a36Sopenharmony_ci * This is useful to support platforms with multiple regulators per device.
236162306a36Sopenharmony_ci *
236262306a36Sopenharmony_ci * This must be called before any OPPs are initialized for the device.
236362306a36Sopenharmony_ci */
236462306a36Sopenharmony_cistatic int _opp_set_config_regulators_helper(struct opp_table *opp_table,
236562306a36Sopenharmony_ci		struct device *dev, config_regulators_t config_regulators)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	/* Another CPU that shares the OPP table has set the helper ? */
236862306a36Sopenharmony_ci	if (!opp_table->config_regulators)
236962306a36Sopenharmony_ci		opp_table->config_regulators = config_regulators;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	return 0;
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci/**
237562306a36Sopenharmony_ci * _opp_put_config_regulators_helper() - Releases resources blocked for
237662306a36Sopenharmony_ci *					 config_regulators helper.
237762306a36Sopenharmony_ci * @opp_table: OPP table returned from _opp_set_config_regulators_helper().
237862306a36Sopenharmony_ci *
237962306a36Sopenharmony_ci * Release resources blocked for platform specific config_regulators helper.
238062306a36Sopenharmony_ci */
238162306a36Sopenharmony_cistatic void _opp_put_config_regulators_helper(struct opp_table *opp_table)
238262306a36Sopenharmony_ci{
238362306a36Sopenharmony_ci	if (opp_table->config_regulators)
238462306a36Sopenharmony_ci		opp_table->config_regulators = NULL;
238562306a36Sopenharmony_ci}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_cistatic void _detach_genpd(struct opp_table *opp_table)
238862306a36Sopenharmony_ci{
238962306a36Sopenharmony_ci	int index;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (!opp_table->genpd_virt_devs)
239262306a36Sopenharmony_ci		return;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	for (index = 0; index < opp_table->required_opp_count; index++) {
239562306a36Sopenharmony_ci		if (!opp_table->genpd_virt_devs[index])
239662306a36Sopenharmony_ci			continue;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false);
239962306a36Sopenharmony_ci		opp_table->genpd_virt_devs[index] = NULL;
240062306a36Sopenharmony_ci	}
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	kfree(opp_table->genpd_virt_devs);
240362306a36Sopenharmony_ci	opp_table->genpd_virt_devs = NULL;
240462306a36Sopenharmony_ci}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci/**
240762306a36Sopenharmony_ci * _opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
240862306a36Sopenharmony_ci * @dev: Consumer device for which the genpd is getting attached.
240962306a36Sopenharmony_ci * @names: Null terminated array of pointers containing names of genpd to attach.
241062306a36Sopenharmony_ci * @virt_devs: Pointer to return the array of virtual devices.
241162306a36Sopenharmony_ci *
241262306a36Sopenharmony_ci * Multiple generic power domains for a device are supported with the help of
241362306a36Sopenharmony_ci * virtual genpd devices, which are created for each consumer device - genpd
241462306a36Sopenharmony_ci * pair. These are the device structures which are attached to the power domain
241562306a36Sopenharmony_ci * and are required by the OPP core to set the performance state of the genpd.
241662306a36Sopenharmony_ci * The same API also works for the case where single genpd is available and so
241762306a36Sopenharmony_ci * we don't need to support that separately.
241862306a36Sopenharmony_ci *
241962306a36Sopenharmony_ci * This helper will normally be called by the consumer driver of the device
242062306a36Sopenharmony_ci * "dev", as only that has details of the genpd names.
242162306a36Sopenharmony_ci *
242262306a36Sopenharmony_ci * This helper needs to be called once with a list of all genpd to attach.
242362306a36Sopenharmony_ci * Otherwise the original device structure will be used instead by the OPP core.
242462306a36Sopenharmony_ci *
242562306a36Sopenharmony_ci * The order of entries in the names array must match the order in which
242662306a36Sopenharmony_ci * "required-opps" are added in DT.
242762306a36Sopenharmony_ci */
242862306a36Sopenharmony_cistatic int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
242962306a36Sopenharmony_ci			const char * const *names, struct device ***virt_devs)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	struct device *virt_dev;
243262306a36Sopenharmony_ci	int index = 0, ret = -EINVAL;
243362306a36Sopenharmony_ci	const char * const *name = names;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	if (opp_table->genpd_virt_devs)
243662306a36Sopenharmony_ci		return 0;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	/*
243962306a36Sopenharmony_ci	 * If the genpd's OPP table isn't already initialized, parsing of the
244062306a36Sopenharmony_ci	 * required-opps fail for dev. We should retry this after genpd's OPP
244162306a36Sopenharmony_ci	 * table is added.
244262306a36Sopenharmony_ci	 */
244362306a36Sopenharmony_ci	if (!opp_table->required_opp_count)
244462306a36Sopenharmony_ci		return -EPROBE_DEFER;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	mutex_lock(&opp_table->genpd_virt_dev_lock);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count,
244962306a36Sopenharmony_ci					     sizeof(*opp_table->genpd_virt_devs),
245062306a36Sopenharmony_ci					     GFP_KERNEL);
245162306a36Sopenharmony_ci	if (!opp_table->genpd_virt_devs)
245262306a36Sopenharmony_ci		goto unlock;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	while (*name) {
245562306a36Sopenharmony_ci		if (index >= opp_table->required_opp_count) {
245662306a36Sopenharmony_ci			dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n",
245762306a36Sopenharmony_ci				*name, opp_table->required_opp_count, index);
245862306a36Sopenharmony_ci			goto err;
245962306a36Sopenharmony_ci		}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci		virt_dev = dev_pm_domain_attach_by_name(dev, *name);
246262306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(virt_dev)) {
246362306a36Sopenharmony_ci			ret = virt_dev ? PTR_ERR(virt_dev) : -ENODEV;
246462306a36Sopenharmony_ci			dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
246562306a36Sopenharmony_ci			goto err;
246662306a36Sopenharmony_ci		}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci		opp_table->genpd_virt_devs[index] = virt_dev;
246962306a36Sopenharmony_ci		index++;
247062306a36Sopenharmony_ci		name++;
247162306a36Sopenharmony_ci	}
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	if (virt_devs)
247462306a36Sopenharmony_ci		*virt_devs = opp_table->genpd_virt_devs;
247562306a36Sopenharmony_ci	mutex_unlock(&opp_table->genpd_virt_dev_lock);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	return 0;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_cierr:
248062306a36Sopenharmony_ci	_detach_genpd(opp_table);
248162306a36Sopenharmony_ciunlock:
248262306a36Sopenharmony_ci	mutex_unlock(&opp_table->genpd_virt_dev_lock);
248362306a36Sopenharmony_ci	return ret;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci/**
248862306a36Sopenharmony_ci * _opp_detach_genpd() - Detach genpd(s) from the device.
248962306a36Sopenharmony_ci * @opp_table: OPP table returned by _opp_attach_genpd().
249062306a36Sopenharmony_ci *
249162306a36Sopenharmony_ci * This detaches the genpd(s), resets the virtual device pointers, and puts the
249262306a36Sopenharmony_ci * OPP table.
249362306a36Sopenharmony_ci */
249462306a36Sopenharmony_cistatic void _opp_detach_genpd(struct opp_table *opp_table)
249562306a36Sopenharmony_ci{
249662306a36Sopenharmony_ci	/*
249762306a36Sopenharmony_ci	 * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
249862306a36Sopenharmony_ci	 * used in parallel.
249962306a36Sopenharmony_ci	 */
250062306a36Sopenharmony_ci	mutex_lock(&opp_table->genpd_virt_dev_lock);
250162306a36Sopenharmony_ci	_detach_genpd(opp_table);
250262306a36Sopenharmony_ci	mutex_unlock(&opp_table->genpd_virt_dev_lock);
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic void _opp_clear_config(struct opp_config_data *data)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_GENPD)
250862306a36Sopenharmony_ci		_opp_detach_genpd(data->opp_table);
250962306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_REGULATOR)
251062306a36Sopenharmony_ci		_opp_put_regulators(data->opp_table);
251162306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_SUPPORTED_HW)
251262306a36Sopenharmony_ci		_opp_put_supported_hw(data->opp_table);
251362306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_REGULATOR_HELPER)
251462306a36Sopenharmony_ci		_opp_put_config_regulators_helper(data->opp_table);
251562306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_PROP_NAME)
251662306a36Sopenharmony_ci		_opp_put_prop_name(data->opp_table);
251762306a36Sopenharmony_ci	if (data->flags & OPP_CONFIG_CLK)
251862306a36Sopenharmony_ci		_opp_put_clknames(data->opp_table);
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(data->opp_table);
252162306a36Sopenharmony_ci	kfree(data);
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci/**
252562306a36Sopenharmony_ci * dev_pm_opp_set_config() - Set OPP configuration for the device.
252662306a36Sopenharmony_ci * @dev: Device for which configuration is being set.
252762306a36Sopenharmony_ci * @config: OPP configuration.
252862306a36Sopenharmony_ci *
252962306a36Sopenharmony_ci * This allows all device OPP configurations to be performed at once.
253062306a36Sopenharmony_ci *
253162306a36Sopenharmony_ci * This must be called before any OPPs are initialized for the device. This may
253262306a36Sopenharmony_ci * be called multiple times for the same OPP table, for example once for each
253362306a36Sopenharmony_ci * CPU that share the same table. This must be balanced by the same number of
253462306a36Sopenharmony_ci * calls to dev_pm_opp_clear_config() in order to free the OPP table properly.
253562306a36Sopenharmony_ci *
253662306a36Sopenharmony_ci * This returns a token to the caller, which must be passed to
253762306a36Sopenharmony_ci * dev_pm_opp_clear_config() to free the resources later. The value of the
253862306a36Sopenharmony_ci * returned token will be >= 1 for success and negative for errors. The minimum
253962306a36Sopenharmony_ci * value of 1 is chosen here to make it easy for callers to manage the resource.
254062306a36Sopenharmony_ci */
254162306a36Sopenharmony_ciint dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	struct opp_table *opp_table;
254462306a36Sopenharmony_ci	struct opp_config_data *data;
254562306a36Sopenharmony_ci	unsigned int id;
254662306a36Sopenharmony_ci	int ret;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_KERNEL);
254962306a36Sopenharmony_ci	if (!data)
255062306a36Sopenharmony_ci		return -ENOMEM;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	opp_table = _add_opp_table(dev, false);
255362306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
255462306a36Sopenharmony_ci		kfree(data);
255562306a36Sopenharmony_ci		return PTR_ERR(opp_table);
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	data->opp_table = opp_table;
255962306a36Sopenharmony_ci	data->flags = 0;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	/* This should be called before OPPs are initialized */
256262306a36Sopenharmony_ci	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
256362306a36Sopenharmony_ci		ret = -EBUSY;
256462306a36Sopenharmony_ci		goto err;
256562306a36Sopenharmony_ci	}
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	/* Configure clocks */
256862306a36Sopenharmony_ci	if (config->clk_names) {
256962306a36Sopenharmony_ci		ret = _opp_set_clknames(opp_table, dev, config->clk_names,
257062306a36Sopenharmony_ci					config->config_clks);
257162306a36Sopenharmony_ci		if (ret)
257262306a36Sopenharmony_ci			goto err;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_CLK;
257562306a36Sopenharmony_ci	} else if (config->config_clks) {
257662306a36Sopenharmony_ci		/* Don't allow config callback without clocks */
257762306a36Sopenharmony_ci		ret = -EINVAL;
257862306a36Sopenharmony_ci		goto err;
257962306a36Sopenharmony_ci	}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	/* Configure property names */
258262306a36Sopenharmony_ci	if (config->prop_name) {
258362306a36Sopenharmony_ci		ret = _opp_set_prop_name(opp_table, config->prop_name);
258462306a36Sopenharmony_ci		if (ret)
258562306a36Sopenharmony_ci			goto err;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_PROP_NAME;
258862306a36Sopenharmony_ci	}
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	/* Configure config_regulators helper */
259162306a36Sopenharmony_ci	if (config->config_regulators) {
259262306a36Sopenharmony_ci		ret = _opp_set_config_regulators_helper(opp_table, dev,
259362306a36Sopenharmony_ci						config->config_regulators);
259462306a36Sopenharmony_ci		if (ret)
259562306a36Sopenharmony_ci			goto err;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_REGULATOR_HELPER;
259862306a36Sopenharmony_ci	}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	/* Configure supported hardware */
260162306a36Sopenharmony_ci	if (config->supported_hw) {
260262306a36Sopenharmony_ci		ret = _opp_set_supported_hw(opp_table, config->supported_hw,
260362306a36Sopenharmony_ci					    config->supported_hw_count);
260462306a36Sopenharmony_ci		if (ret)
260562306a36Sopenharmony_ci			goto err;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_SUPPORTED_HW;
260862306a36Sopenharmony_ci	}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	/* Configure supplies */
261162306a36Sopenharmony_ci	if (config->regulator_names) {
261262306a36Sopenharmony_ci		ret = _opp_set_regulators(opp_table, dev,
261362306a36Sopenharmony_ci					  config->regulator_names);
261462306a36Sopenharmony_ci		if (ret)
261562306a36Sopenharmony_ci			goto err;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_REGULATOR;
261862306a36Sopenharmony_ci	}
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	/* Attach genpds */
262162306a36Sopenharmony_ci	if (config->genpd_names) {
262262306a36Sopenharmony_ci		ret = _opp_attach_genpd(opp_table, dev, config->genpd_names,
262362306a36Sopenharmony_ci					config->virt_devs);
262462306a36Sopenharmony_ci		if (ret)
262562306a36Sopenharmony_ci			goto err;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci		data->flags |= OPP_CONFIG_GENPD;
262862306a36Sopenharmony_ci	}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),
263162306a36Sopenharmony_ci		       GFP_KERNEL);
263262306a36Sopenharmony_ci	if (ret)
263362306a36Sopenharmony_ci		goto err;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	return id;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_cierr:
263862306a36Sopenharmony_ci	_opp_clear_config(data);
263962306a36Sopenharmony_ci	return ret;
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_set_config);
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci/**
264462306a36Sopenharmony_ci * dev_pm_opp_clear_config() - Releases resources blocked for OPP configuration.
264562306a36Sopenharmony_ci * @opp_table: OPP table returned from dev_pm_opp_set_config().
264662306a36Sopenharmony_ci *
264762306a36Sopenharmony_ci * This allows all device OPP configurations to be cleared at once. This must be
264862306a36Sopenharmony_ci * called once for each call made to dev_pm_opp_set_config(), in order to free
264962306a36Sopenharmony_ci * the OPPs properly.
265062306a36Sopenharmony_ci *
265162306a36Sopenharmony_ci * Currently the first call itself ends up freeing all the OPP configurations,
265262306a36Sopenharmony_ci * while the later ones only drop the OPP table reference. This works well for
265362306a36Sopenharmony_ci * now as we would never want to use an half initialized OPP table and want to
265462306a36Sopenharmony_ci * remove the configurations together.
265562306a36Sopenharmony_ci */
265662306a36Sopenharmony_civoid dev_pm_opp_clear_config(int token)
265762306a36Sopenharmony_ci{
265862306a36Sopenharmony_ci	struct opp_config_data *data;
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	/*
266162306a36Sopenharmony_ci	 * This lets the callers call this unconditionally and keep their code
266262306a36Sopenharmony_ci	 * simple.
266362306a36Sopenharmony_ci	 */
266462306a36Sopenharmony_ci	if (unlikely(token <= 0))
266562306a36Sopenharmony_ci		return;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	data = xa_erase(&opp_configs, token);
266862306a36Sopenharmony_ci	if (WARN_ON(!data))
266962306a36Sopenharmony_ci		return;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	_opp_clear_config(data);
267262306a36Sopenharmony_ci}
267362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_clear_config);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_cistatic void devm_pm_opp_config_release(void *token)
267662306a36Sopenharmony_ci{
267762306a36Sopenharmony_ci	dev_pm_opp_clear_config((unsigned long)token);
267862306a36Sopenharmony_ci}
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci/**
268162306a36Sopenharmony_ci * devm_pm_opp_set_config() - Set OPP configuration for the device.
268262306a36Sopenharmony_ci * @dev: Device for which configuration is being set.
268362306a36Sopenharmony_ci * @config: OPP configuration.
268462306a36Sopenharmony_ci *
268562306a36Sopenharmony_ci * This allows all device OPP configurations to be performed at once.
268662306a36Sopenharmony_ci * This is a resource-managed variant of dev_pm_opp_set_config().
268762306a36Sopenharmony_ci *
268862306a36Sopenharmony_ci * Return: 0 on success and errorno otherwise.
268962306a36Sopenharmony_ci */
269062306a36Sopenharmony_ciint devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
269162306a36Sopenharmony_ci{
269262306a36Sopenharmony_ci	int token = dev_pm_opp_set_config(dev, config);
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	if (token < 0)
269562306a36Sopenharmony_ci		return token;
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	return devm_add_action_or_reset(dev, devm_pm_opp_config_release,
269862306a36Sopenharmony_ci					(void *) ((unsigned long) token));
269962306a36Sopenharmony_ci}
270062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_pm_opp_set_config);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci/**
270362306a36Sopenharmony_ci * dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP.
270462306a36Sopenharmony_ci * @src_table: OPP table which has @dst_table as one of its required OPP table.
270562306a36Sopenharmony_ci * @dst_table: Required OPP table of the @src_table.
270662306a36Sopenharmony_ci * @src_opp: OPP from the @src_table.
270762306a36Sopenharmony_ci *
270862306a36Sopenharmony_ci * This function returns the OPP (present in @dst_table) pointed out by the
270962306a36Sopenharmony_ci * "required-opps" property of the @src_opp (present in @src_table).
271062306a36Sopenharmony_ci *
271162306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
271262306a36Sopenharmony_ci * use.
271362306a36Sopenharmony_ci *
271462306a36Sopenharmony_ci * Return: pointer to 'struct dev_pm_opp' on success and errorno otherwise.
271562306a36Sopenharmony_ci */
271662306a36Sopenharmony_cistruct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
271762306a36Sopenharmony_ci						 struct opp_table *dst_table,
271862306a36Sopenharmony_ci						 struct dev_pm_opp *src_opp)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	struct dev_pm_opp *opp, *dest_opp = ERR_PTR(-ENODEV);
272162306a36Sopenharmony_ci	int i;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (!src_table || !dst_table || !src_opp ||
272462306a36Sopenharmony_ci	    !src_table->required_opp_tables)
272562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	/* required-opps not fully initialized yet */
272862306a36Sopenharmony_ci	if (lazy_linking_pending(src_table))
272962306a36Sopenharmony_ci		return ERR_PTR(-EBUSY);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	for (i = 0; i < src_table->required_opp_count; i++) {
273262306a36Sopenharmony_ci		if (src_table->required_opp_tables[i] == dst_table) {
273362306a36Sopenharmony_ci			mutex_lock(&src_table->lock);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci			list_for_each_entry(opp, &src_table->opp_list, node) {
273662306a36Sopenharmony_ci				if (opp == src_opp) {
273762306a36Sopenharmony_ci					dest_opp = opp->required_opps[i];
273862306a36Sopenharmony_ci					dev_pm_opp_get(dest_opp);
273962306a36Sopenharmony_ci					break;
274062306a36Sopenharmony_ci				}
274162306a36Sopenharmony_ci			}
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci			mutex_unlock(&src_table->lock);
274462306a36Sopenharmony_ci			break;
274562306a36Sopenharmony_ci		}
274662306a36Sopenharmony_ci	}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	if (IS_ERR(dest_opp)) {
274962306a36Sopenharmony_ci		pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__,
275062306a36Sopenharmony_ci		       src_table, dst_table);
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	return dest_opp;
275462306a36Sopenharmony_ci}
275562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_xlate_required_opp);
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci/**
275862306a36Sopenharmony_ci * dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
275962306a36Sopenharmony_ci * @src_table: OPP table which has dst_table as one of its required OPP table.
276062306a36Sopenharmony_ci * @dst_table: Required OPP table of the src_table.
276162306a36Sopenharmony_ci * @pstate: Current performance state of the src_table.
276262306a36Sopenharmony_ci *
276362306a36Sopenharmony_ci * This Returns pstate of the OPP (present in @dst_table) pointed out by the
276462306a36Sopenharmony_ci * "required-opps" property of the OPP (present in @src_table) which has
276562306a36Sopenharmony_ci * performance state set to @pstate.
276662306a36Sopenharmony_ci *
276762306a36Sopenharmony_ci * Return: Zero or positive performance state on success, otherwise negative
276862306a36Sopenharmony_ci * value on errors.
276962306a36Sopenharmony_ci */
277062306a36Sopenharmony_ciint dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
277162306a36Sopenharmony_ci				       struct opp_table *dst_table,
277262306a36Sopenharmony_ci				       unsigned int pstate)
277362306a36Sopenharmony_ci{
277462306a36Sopenharmony_ci	struct dev_pm_opp *opp;
277562306a36Sopenharmony_ci	int dest_pstate = -EINVAL;
277662306a36Sopenharmony_ci	int i;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	/*
277962306a36Sopenharmony_ci	 * Normally the src_table will have the "required_opps" property set to
278062306a36Sopenharmony_ci	 * point to one of the OPPs in the dst_table, but in some cases the
278162306a36Sopenharmony_ci	 * genpd and its master have one to one mapping of performance states
278262306a36Sopenharmony_ci	 * and so none of them have the "required-opps" property set. Return the
278362306a36Sopenharmony_ci	 * pstate of the src_table as it is in such cases.
278462306a36Sopenharmony_ci	 */
278562306a36Sopenharmony_ci	if (!src_table || !src_table->required_opp_count)
278662306a36Sopenharmony_ci		return pstate;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	/* Both OPP tables must belong to genpds */
278962306a36Sopenharmony_ci	if (unlikely(!src_table->is_genpd || !dst_table->is_genpd)) {
279062306a36Sopenharmony_ci		pr_err("%s: Performance state is only valid for genpds.\n", __func__);
279162306a36Sopenharmony_ci		return -EINVAL;
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	/* required-opps not fully initialized yet */
279562306a36Sopenharmony_ci	if (lazy_linking_pending(src_table))
279662306a36Sopenharmony_ci		return -EBUSY;
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci	for (i = 0; i < src_table->required_opp_count; i++) {
279962306a36Sopenharmony_ci		if (src_table->required_opp_tables[i]->np == dst_table->np)
280062306a36Sopenharmony_ci			break;
280162306a36Sopenharmony_ci	}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (unlikely(i == src_table->required_opp_count)) {
280462306a36Sopenharmony_ci		pr_err("%s: Couldn't find matching OPP table (%p: %p)\n",
280562306a36Sopenharmony_ci		       __func__, src_table, dst_table);
280662306a36Sopenharmony_ci		return -EINVAL;
280762306a36Sopenharmony_ci	}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	mutex_lock(&src_table->lock);
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	list_for_each_entry(opp, &src_table->opp_list, node) {
281262306a36Sopenharmony_ci		if (opp->level == pstate) {
281362306a36Sopenharmony_ci			dest_pstate = opp->required_opps[i]->level;
281462306a36Sopenharmony_ci			goto unlock;
281562306a36Sopenharmony_ci		}
281662306a36Sopenharmony_ci	}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__, src_table,
281962306a36Sopenharmony_ci	       dst_table);
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ciunlock:
282262306a36Sopenharmony_ci	mutex_unlock(&src_table->lock);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	return dest_pstate;
282562306a36Sopenharmony_ci}
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci/**
282862306a36Sopenharmony_ci * dev_pm_opp_add()  - Add an OPP table from a table definitions
282962306a36Sopenharmony_ci * @dev:	device for which we do this operation
283062306a36Sopenharmony_ci * @freq:	Frequency in Hz for this OPP
283162306a36Sopenharmony_ci * @u_volt:	Voltage in uVolts for this OPP
283262306a36Sopenharmony_ci *
283362306a36Sopenharmony_ci * This function adds an opp definition to the opp table and returns status.
283462306a36Sopenharmony_ci * The opp is made available by default and it can be controlled using
283562306a36Sopenharmony_ci * dev_pm_opp_enable/disable functions.
283662306a36Sopenharmony_ci *
283762306a36Sopenharmony_ci * Return:
283862306a36Sopenharmony_ci * 0		On success OR
283962306a36Sopenharmony_ci *		Duplicate OPPs (both freq and volt are same) and opp->available
284062306a36Sopenharmony_ci * -EEXIST	Freq are same and volt are different OR
284162306a36Sopenharmony_ci *		Duplicate OPPs (both freq and volt are same) and !opp->available
284262306a36Sopenharmony_ci * -ENOMEM	Memory allocation failure
284362306a36Sopenharmony_ci */
284462306a36Sopenharmony_ciint dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	struct opp_table *opp_table;
284762306a36Sopenharmony_ci	int ret;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	opp_table = _add_opp_table(dev, true);
285062306a36Sopenharmony_ci	if (IS_ERR(opp_table))
285162306a36Sopenharmony_ci		return PTR_ERR(opp_table);
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	/* Fix regulator count for dynamic OPPs */
285462306a36Sopenharmony_ci	opp_table->regulator_count = 1;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
285762306a36Sopenharmony_ci	if (ret)
285862306a36Sopenharmony_ci		dev_pm_opp_put_opp_table(opp_table);
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	return ret;
286162306a36Sopenharmony_ci}
286262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_add);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci/**
286562306a36Sopenharmony_ci * _opp_set_availability() - helper to set the availability of an opp
286662306a36Sopenharmony_ci * @dev:		device for which we do this operation
286762306a36Sopenharmony_ci * @freq:		OPP frequency to modify availability
286862306a36Sopenharmony_ci * @availability_req:	availability status requested for this opp
286962306a36Sopenharmony_ci *
287062306a36Sopenharmony_ci * Set the availability of an OPP, opp_{enable,disable} share a common logic
287162306a36Sopenharmony_ci * which is isolated here.
287262306a36Sopenharmony_ci *
287362306a36Sopenharmony_ci * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
287462306a36Sopenharmony_ci * copy operation, returns 0 if no modification was done OR modification was
287562306a36Sopenharmony_ci * successful.
287662306a36Sopenharmony_ci */
287762306a36Sopenharmony_cistatic int _opp_set_availability(struct device *dev, unsigned long freq,
287862306a36Sopenharmony_ci				 bool availability_req)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci	struct opp_table *opp_table;
288162306a36Sopenharmony_ci	struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
288262306a36Sopenharmony_ci	int r = 0;
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	/* Find the opp_table */
288562306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
288662306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
288762306a36Sopenharmony_ci		r = PTR_ERR(opp_table);
288862306a36Sopenharmony_ci		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
288962306a36Sopenharmony_ci		return r;
289062306a36Sopenharmony_ci	}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	if (!assert_single_clk(opp_table)) {
289362306a36Sopenharmony_ci		r = -EINVAL;
289462306a36Sopenharmony_ci		goto put_table;
289562306a36Sopenharmony_ci	}
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	/* Do we have the frequency? */
290062306a36Sopenharmony_ci	list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
290162306a36Sopenharmony_ci		if (tmp_opp->rates[0] == freq) {
290262306a36Sopenharmony_ci			opp = tmp_opp;
290362306a36Sopenharmony_ci			break;
290462306a36Sopenharmony_ci		}
290562306a36Sopenharmony_ci	}
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	if (IS_ERR(opp)) {
290862306a36Sopenharmony_ci		r = PTR_ERR(opp);
290962306a36Sopenharmony_ci		goto unlock;
291062306a36Sopenharmony_ci	}
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	/* Is update really needed? */
291362306a36Sopenharmony_ci	if (opp->available == availability_req)
291462306a36Sopenharmony_ci		goto unlock;
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	opp->available = availability_req;
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	dev_pm_opp_get(opp);
291962306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	/* Notify the change of the OPP availability */
292262306a36Sopenharmony_ci	if (availability_req)
292362306a36Sopenharmony_ci		blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE,
292462306a36Sopenharmony_ci					     opp);
292562306a36Sopenharmony_ci	else
292662306a36Sopenharmony_ci		blocking_notifier_call_chain(&opp_table->head,
292762306a36Sopenharmony_ci					     OPP_EVENT_DISABLE, opp);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	dev_pm_opp_put(opp);
293062306a36Sopenharmony_ci	goto put_table;
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ciunlock:
293362306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
293462306a36Sopenharmony_ciput_table:
293562306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
293662306a36Sopenharmony_ci	return r;
293762306a36Sopenharmony_ci}
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci/**
294062306a36Sopenharmony_ci * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP
294162306a36Sopenharmony_ci * @dev:		device for which we do this operation
294262306a36Sopenharmony_ci * @freq:		OPP frequency to adjust voltage of
294362306a36Sopenharmony_ci * @u_volt:		new OPP target voltage
294462306a36Sopenharmony_ci * @u_volt_min:		new OPP min voltage
294562306a36Sopenharmony_ci * @u_volt_max:		new OPP max voltage
294662306a36Sopenharmony_ci *
294762306a36Sopenharmony_ci * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
294862306a36Sopenharmony_ci * copy operation, returns 0 if no modifcation was done OR modification was
294962306a36Sopenharmony_ci * successful.
295062306a36Sopenharmony_ci */
295162306a36Sopenharmony_ciint dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
295262306a36Sopenharmony_ci			      unsigned long u_volt, unsigned long u_volt_min,
295362306a36Sopenharmony_ci			      unsigned long u_volt_max)
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci{
295662306a36Sopenharmony_ci	struct opp_table *opp_table;
295762306a36Sopenharmony_ci	struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
295862306a36Sopenharmony_ci	int r = 0;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	/* Find the opp_table */
296162306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
296262306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
296362306a36Sopenharmony_ci		r = PTR_ERR(opp_table);
296462306a36Sopenharmony_ci		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
296562306a36Sopenharmony_ci		return r;
296662306a36Sopenharmony_ci	}
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	if (!assert_single_clk(opp_table)) {
296962306a36Sopenharmony_ci		r = -EINVAL;
297062306a36Sopenharmony_ci		goto put_table;
297162306a36Sopenharmony_ci	}
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	mutex_lock(&opp_table->lock);
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	/* Do we have the frequency? */
297662306a36Sopenharmony_ci	list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
297762306a36Sopenharmony_ci		if (tmp_opp->rates[0] == freq) {
297862306a36Sopenharmony_ci			opp = tmp_opp;
297962306a36Sopenharmony_ci			break;
298062306a36Sopenharmony_ci		}
298162306a36Sopenharmony_ci	}
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	if (IS_ERR(opp)) {
298462306a36Sopenharmony_ci		r = PTR_ERR(opp);
298562306a36Sopenharmony_ci		goto adjust_unlock;
298662306a36Sopenharmony_ci	}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	/* Is update really needed? */
298962306a36Sopenharmony_ci	if (opp->supplies->u_volt == u_volt)
299062306a36Sopenharmony_ci		goto adjust_unlock;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	opp->supplies->u_volt = u_volt;
299362306a36Sopenharmony_ci	opp->supplies->u_volt_min = u_volt_min;
299462306a36Sopenharmony_ci	opp->supplies->u_volt_max = u_volt_max;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	dev_pm_opp_get(opp);
299762306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	/* Notify the voltage change of the OPP */
300062306a36Sopenharmony_ci	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE,
300162306a36Sopenharmony_ci				     opp);
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	dev_pm_opp_put(opp);
300462306a36Sopenharmony_ci	goto put_table;
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ciadjust_unlock:
300762306a36Sopenharmony_ci	mutex_unlock(&opp_table->lock);
300862306a36Sopenharmony_ciput_table:
300962306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
301062306a36Sopenharmony_ci	return r;
301162306a36Sopenharmony_ci}
301262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_adjust_voltage);
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci/**
301562306a36Sopenharmony_ci * dev_pm_opp_enable() - Enable a specific OPP
301662306a36Sopenharmony_ci * @dev:	device for which we do this operation
301762306a36Sopenharmony_ci * @freq:	OPP frequency to enable
301862306a36Sopenharmony_ci *
301962306a36Sopenharmony_ci * Enables a provided opp. If the operation is valid, this returns 0, else the
302062306a36Sopenharmony_ci * corresponding error value. It is meant to be used for users an OPP available
302162306a36Sopenharmony_ci * after being temporarily made unavailable with dev_pm_opp_disable.
302262306a36Sopenharmony_ci *
302362306a36Sopenharmony_ci * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
302462306a36Sopenharmony_ci * copy operation, returns 0 if no modification was done OR modification was
302562306a36Sopenharmony_ci * successful.
302662306a36Sopenharmony_ci */
302762306a36Sopenharmony_ciint dev_pm_opp_enable(struct device *dev, unsigned long freq)
302862306a36Sopenharmony_ci{
302962306a36Sopenharmony_ci	return _opp_set_availability(dev, freq, true);
303062306a36Sopenharmony_ci}
303162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_enable);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci/**
303462306a36Sopenharmony_ci * dev_pm_opp_disable() - Disable a specific OPP
303562306a36Sopenharmony_ci * @dev:	device for which we do this operation
303662306a36Sopenharmony_ci * @freq:	OPP frequency to disable
303762306a36Sopenharmony_ci *
303862306a36Sopenharmony_ci * Disables a provided opp. If the operation is valid, this returns
303962306a36Sopenharmony_ci * 0, else the corresponding error value. It is meant to be a temporary
304062306a36Sopenharmony_ci * control by users to make this OPP not available until the circumstances are
304162306a36Sopenharmony_ci * right to make it available again (with a call to dev_pm_opp_enable).
304262306a36Sopenharmony_ci *
304362306a36Sopenharmony_ci * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
304462306a36Sopenharmony_ci * copy operation, returns 0 if no modification was done OR modification was
304562306a36Sopenharmony_ci * successful.
304662306a36Sopenharmony_ci */
304762306a36Sopenharmony_ciint dev_pm_opp_disable(struct device *dev, unsigned long freq)
304862306a36Sopenharmony_ci{
304962306a36Sopenharmony_ci	return _opp_set_availability(dev, freq, false);
305062306a36Sopenharmony_ci}
305162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_disable);
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci/**
305462306a36Sopenharmony_ci * dev_pm_opp_register_notifier() - Register OPP notifier for the device
305562306a36Sopenharmony_ci * @dev:	Device for which notifier needs to be registered
305662306a36Sopenharmony_ci * @nb:		Notifier block to be registered
305762306a36Sopenharmony_ci *
305862306a36Sopenharmony_ci * Return: 0 on success or a negative error value.
305962306a36Sopenharmony_ci */
306062306a36Sopenharmony_ciint dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
306162306a36Sopenharmony_ci{
306262306a36Sopenharmony_ci	struct opp_table *opp_table;
306362306a36Sopenharmony_ci	int ret;
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
306662306a36Sopenharmony_ci	if (IS_ERR(opp_table))
306762306a36Sopenharmony_ci		return PTR_ERR(opp_table);
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	ret = blocking_notifier_chain_register(&opp_table->head, nb);
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	return ret;
307462306a36Sopenharmony_ci}
307562306a36Sopenharmony_ciEXPORT_SYMBOL(dev_pm_opp_register_notifier);
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci/**
307862306a36Sopenharmony_ci * dev_pm_opp_unregister_notifier() - Unregister OPP notifier for the device
307962306a36Sopenharmony_ci * @dev:	Device for which notifier needs to be unregistered
308062306a36Sopenharmony_ci * @nb:		Notifier block to be unregistered
308162306a36Sopenharmony_ci *
308262306a36Sopenharmony_ci * Return: 0 on success or a negative error value.
308362306a36Sopenharmony_ci */
308462306a36Sopenharmony_ciint dev_pm_opp_unregister_notifier(struct device *dev,
308562306a36Sopenharmony_ci				   struct notifier_block *nb)
308662306a36Sopenharmony_ci{
308762306a36Sopenharmony_ci	struct opp_table *opp_table;
308862306a36Sopenharmony_ci	int ret;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
309162306a36Sopenharmony_ci	if (IS_ERR(opp_table))
309262306a36Sopenharmony_ci		return PTR_ERR(opp_table);
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	ret = blocking_notifier_chain_unregister(&opp_table->head, nb);
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	return ret;
309962306a36Sopenharmony_ci}
310062306a36Sopenharmony_ciEXPORT_SYMBOL(dev_pm_opp_unregister_notifier);
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci/**
310362306a36Sopenharmony_ci * dev_pm_opp_remove_table() - Free all OPPs associated with the device
310462306a36Sopenharmony_ci * @dev:	device pointer used to lookup OPP table.
310562306a36Sopenharmony_ci *
310662306a36Sopenharmony_ci * Free both OPPs created using static entries present in DT and the
310762306a36Sopenharmony_ci * dynamically added entries.
310862306a36Sopenharmony_ci */
310962306a36Sopenharmony_civoid dev_pm_opp_remove_table(struct device *dev)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	struct opp_table *opp_table;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	/* Check for existing table for 'dev' */
311462306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
311562306a36Sopenharmony_ci	if (IS_ERR(opp_table)) {
311662306a36Sopenharmony_ci		int error = PTR_ERR(opp_table);
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci		if (error != -ENODEV)
311962306a36Sopenharmony_ci			WARN(1, "%s: opp_table: %d\n",
312062306a36Sopenharmony_ci			     IS_ERR_OR_NULL(dev) ?
312162306a36Sopenharmony_ci					"Invalid device" : dev_name(dev),
312262306a36Sopenharmony_ci			     error);
312362306a36Sopenharmony_ci		return;
312462306a36Sopenharmony_ci	}
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	/*
312762306a36Sopenharmony_ci	 * Drop the extra reference only if the OPP table was successfully added
312862306a36Sopenharmony_ci	 * with dev_pm_opp_of_add_table() earlier.
312962306a36Sopenharmony_ci	 **/
313062306a36Sopenharmony_ci	if (_opp_remove_all_static(opp_table))
313162306a36Sopenharmony_ci		dev_pm_opp_put_opp_table(opp_table);
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	/* Drop reference taken by _find_opp_table() */
313462306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci/**
313962306a36Sopenharmony_ci * dev_pm_opp_sync_regulators() - Sync state of voltage regulators
314062306a36Sopenharmony_ci * @dev:	device for which we do this operation
314162306a36Sopenharmony_ci *
314262306a36Sopenharmony_ci * Sync voltage state of the OPP table regulators.
314362306a36Sopenharmony_ci *
314462306a36Sopenharmony_ci * Return: 0 on success or a negative error value.
314562306a36Sopenharmony_ci */
314662306a36Sopenharmony_ciint dev_pm_opp_sync_regulators(struct device *dev)
314762306a36Sopenharmony_ci{
314862306a36Sopenharmony_ci	struct opp_table *opp_table;
314962306a36Sopenharmony_ci	struct regulator *reg;
315062306a36Sopenharmony_ci	int i, ret = 0;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	/* Device may not have OPP table */
315362306a36Sopenharmony_ci	opp_table = _find_opp_table(dev);
315462306a36Sopenharmony_ci	if (IS_ERR(opp_table))
315562306a36Sopenharmony_ci		return 0;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	/* Regulator may not be required for the device */
315862306a36Sopenharmony_ci	if (unlikely(!opp_table->regulators))
315962306a36Sopenharmony_ci		goto put_table;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	/* Nothing to sync if voltage wasn't changed */
316262306a36Sopenharmony_ci	if (!opp_table->enabled)
316362306a36Sopenharmony_ci		goto put_table;
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	for (i = 0; i < opp_table->regulator_count; i++) {
316662306a36Sopenharmony_ci		reg = opp_table->regulators[i];
316762306a36Sopenharmony_ci		ret = regulator_sync_voltage(reg);
316862306a36Sopenharmony_ci		if (ret)
316962306a36Sopenharmony_ci			break;
317062306a36Sopenharmony_ci	}
317162306a36Sopenharmony_ciput_table:
317262306a36Sopenharmony_ci	/* Drop reference taken by _find_opp_table() */
317362306a36Sopenharmony_ci	dev_pm_opp_put_opp_table(opp_table);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	return ret;
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_pm_opp_sync_regulators);
3178