Commit 4ee4ffcc authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'opp-updates-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into pm-opp

Merge OPP (Operating Performance Points) updates for 6.8 from Viresh
Kumar:

"- Fix _set_required_opps when opp is NULL (Bryan O'Donoghue).
 - ti: Use device_get_match_data() (Rob Herring).
 - Minor cleanups around OPP level and other parts and call
   dev_pm_opp_set_opp() recursively for required OPPs (Viresh Kumar)."

* tag 'opp-updates-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  OPP: Rename 'rate_clk_single'
  OPP: Pass rounded rate to _set_opp()
  OPP: Relocate dev_pm_opp_sync_regulators()
  OPP: Move dev_pm_opp_icc_bw to internal opp.h
  OPP: Fix _set_required_opps when opp is NULL
  OPP: The level field is always of unsigned int type
  OPP: Check for invalid OPP in dev_pm_opp_find_level_ceil()
  OPP: Don't set OPP recursively for a parent genpd
  OPP: Call dev_pm_opp_set_opp() for required OPPs
  OPP: Use _set_opp_level() for single genpd case
  OPP: Level zero is valid
  opp: ti: Use device_get_match_data()
parents 610a9b8f dcfec12b
Loading
Loading
Loading
Loading
+166 −128
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq_indexed);
 * @opp:	opp for which level value has to be returned for
 *
 * Return: level read from device tree corresponding to the opp, else
 * return 0.
 * return U32_MAX.
 */
unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)
{
@@ -221,7 +221,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_level);
 * @index:	index of the required opp
 *
 * Return: performance state read from device tree corresponding to the
 * required opp, else return 0.
 * required opp, else return U32_MAX.
 */
unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
					    unsigned int index)
@@ -808,6 +808,16 @@ struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
	struct dev_pm_opp *opp;

	opp = _find_key_ceil(dev, &temp, 0, true, _read_level, NULL);
	if (IS_ERR(opp))
		return opp;

	/* False match */
	if (temp == OPP_LEVEL_UNSET) {
		dev_err(dev, "%s: OPP levels aren't available\n", __func__);
		dev_pm_opp_put(opp);
		return ERR_PTR(-ENODEV);
	}

	*level = temp;
	return opp;
}
@@ -832,9 +842,14 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_ceil);
 * use.
 */
struct dev_pm_opp *dev_pm_opp_find_level_floor(struct device *dev,
					       unsigned long *level)
					       unsigned int *level)
{
	return _find_key_floor(dev, level, 0, true, _read_level, NULL);
	unsigned long temp = *level;
	struct dev_pm_opp *opp;

	opp = _find_key_floor(dev, &temp, 0, true, _read_level, NULL);
	*level = temp;
	return opp;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_floor);

@@ -948,7 +963,7 @@ _opp_config_clk_single(struct device *dev, struct opp_table *opp_table,
		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
			ret);
	} else {
		opp_table->rate_clk_single = freq;
		opp_table->current_rate_single_clk = freq;
	}

	return ret;
@@ -1046,40 +1061,23 @@ static int _set_opp_bw(const struct opp_table *opp_table,
	return 0;
}

static int _set_performance_state(struct device *dev, struct device *pd_dev,
				  struct dev_pm_opp *opp, int i)
/* This is only called for PM domain for now */
static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
			      struct dev_pm_opp *opp, bool up)
{
	unsigned int pstate = likely(opp) ? opp->required_opps[i]->level: 0;
	int ret;
	struct device **devs = opp_table->required_devs;
	struct dev_pm_opp *required_opp;
	int index, target, delta, ret;

	if (!pd_dev)
	if (!devs)
		return 0;

	ret = dev_pm_domain_set_performance_state(pd_dev, pstate);
	if (ret) {
		dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
			dev_name(pd_dev), pstate, ret);
	}

	return ret;
}

static int _opp_set_required_opps_generic(struct device *dev,
	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
{
	dev_err(dev, "setting required-opps isn't supported for non-genpd devices\n");
	return -ENOENT;
}

static int _opp_set_required_opps_genpd(struct device *dev,
	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
{
	struct device **genpd_virt_devs =
		opp_table->genpd_virt_devs ? opp_table->genpd_virt_devs : &dev;
	int index, target, delta, ret;
	/* required-opps not fully initialized yet */
	if (lazy_linking_pending(opp_table))
		return -EBUSY;

	/* Scaling up? Set required OPPs in normal order, else reverse */
	if (!scaling_down) {
	if (up) {
		index = 0;
		target = opp_table->required_opp_count;
		delta = 1;
@@ -1090,44 +1088,20 @@ static int _opp_set_required_opps_genpd(struct device *dev,
	}

	while (index != target) {
		ret = _set_performance_state(dev, genpd_virt_devs[index], opp, index);
		if (devs[index]) {
			required_opp = opp ? opp->required_opps[index] : NULL;

			ret = dev_pm_opp_set_opp(devs[index], required_opp);
			if (ret)
				return ret;

		index += delta;
		}

	return 0;
		index += delta;
	}

/* This is only called for PM domain for now */
static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
			      struct dev_pm_opp *opp, bool up)
{
	/* required-opps not fully initialized yet */
	if (lazy_linking_pending(opp_table))
		return -EBUSY;

	if (opp_table->set_required_opps)
		return opp_table->set_required_opps(dev, opp_table, opp, up);

	return 0;
}

/* Update set_required_opps handler */
void _update_set_required_opps(struct opp_table *opp_table)
{
	/* Already set */
	if (opp_table->set_required_opps)
		return;

	/* All required OPPs will belong to genpd or none */
	if (opp_table->required_opp_tables[0]->is_genpd)
		opp_table->set_required_opps = _opp_set_required_opps_genpd;
	else
		opp_table->set_required_opps = _opp_set_required_opps_generic;
}

static int _set_opp_level(struct device *dev, struct opp_table *opp_table,
			  struct dev_pm_opp *opp)
{
@@ -1135,7 +1109,7 @@ static int _set_opp_level(struct device *dev, struct opp_table *opp_table,
	int ret = 0;

	if (opp) {
		if (!opp->level)
		if (opp->level == OPP_LEVEL_UNSET)
			return 0;

		level = opp->level;
@@ -1378,12 +1352,12 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
		 * value of the frequency. In such a case, do not abort but
		 * configure the hardware to the desired frequency forcefully.
		 */
		forced = opp_table->rate_clk_single != target_freq;
		forced = opp_table->current_rate_single_clk != freq;
	}

	ret = _set_opp(dev, opp_table, opp, &target_freq, forced);
	ret = _set_opp(dev, opp_table, opp, &freq, forced);

	if (target_freq)
	if (freq)
		dev_pm_opp_put(opp);

put_opp_table:
@@ -1867,6 +1841,8 @@ struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table)

	INIT_LIST_HEAD(&opp->node);

	opp->level = OPP_LEVEL_UNSET;

	return opp;
}

@@ -2388,19 +2364,13 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
{
	int index;

	if (!opp_table->genpd_virt_devs)
		return;

	for (index = 0; index < opp_table->required_opp_count; index++) {
		if (!opp_table->genpd_virt_devs[index])
		if (!opp_table->required_devs[index])
			continue;

		dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false);
		opp_table->genpd_virt_devs[index] = NULL;
		dev_pm_domain_detach(opp_table->required_devs[index], false);
		opp_table->required_devs[index] = NULL;
	}

	kfree(opp_table->genpd_virt_devs);
	opp_table->genpd_virt_devs = NULL;
}

/*
@@ -2427,14 +2397,20 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
	int index = 0, ret = -EINVAL;
	const char * const *name = names;

	if (opp_table->genpd_virt_devs)
		return 0;
	if (!opp_table->required_devs) {
		dev_err(dev, "Required OPPs not available, can't attach genpd\n");
		return -EINVAL;
	}

	opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count,
					     sizeof(*opp_table->genpd_virt_devs),
					     GFP_KERNEL);
	if (!opp_table->genpd_virt_devs)
		return -ENOMEM;
	/* Genpd core takes care of propagation to parent genpd */
	if (opp_table->is_genpd) {
		dev_err(dev, "%s: Operation not supported for genpds\n", __func__);
		return -EOPNOTSUPP;
	}

	/* Checking only the first one is enough ? */
	if (opp_table->required_devs[0])
		return 0;

	while (*name) {
		if (index >= opp_table->required_opp_count) {
@@ -2450,13 +2426,25 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
			goto err;
		}

		opp_table->genpd_virt_devs[index] = virt_dev;
		/*
		 * Add the virtual genpd device as a user of the OPP table, so
		 * we can call dev_pm_opp_set_opp() on it directly.
		 *
		 * This will be automatically removed when the OPP table is
		 * removed, don't need to handle that here.
		 */
		if (!_add_opp_dev(virt_dev, opp_table->required_opp_tables[index])) {
			ret = -ENOMEM;
			goto err;
		}

		opp_table->required_devs[index] = virt_dev;
		index++;
		name++;
	}

	if (virt_devs)
		*virt_devs = opp_table->genpd_virt_devs;
		*virt_devs = opp_table->required_devs;

	return 0;

@@ -2466,10 +2454,50 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,

}

static int _opp_set_required_devs(struct opp_table *opp_table,
				  struct device *dev,
				  struct device **required_devs)
{
	int i;

	if (!opp_table->required_devs) {
		dev_err(dev, "Required OPPs not available, can't set required devs\n");
		return -EINVAL;
	}

	/* Another device that shares the OPP table has set the required devs ? */
	if (opp_table->required_devs[0])
		return 0;

	for (i = 0; i < opp_table->required_opp_count; i++) {
		/* Genpd core takes care of propagation to parent genpd */
		if (required_devs[i] && opp_table->is_genpd &&
		    opp_table->required_opp_tables[i]->is_genpd) {
			dev_err(dev, "%s: Operation not supported for genpds\n", __func__);
			return -EOPNOTSUPP;
		}

		opp_table->required_devs[i] = required_devs[i];
	}

	return 0;
}

static void _opp_put_required_devs(struct opp_table *opp_table)
{
	int i;

	for (i = 0; i < opp_table->required_opp_count; i++)
		opp_table->required_devs[i] = NULL;
}

static void _opp_clear_config(struct opp_config_data *data)
{
	if (data->flags & OPP_CONFIG_GENPD)
	if (data->flags & OPP_CONFIG_REQUIRED_DEVS)
		_opp_put_required_devs(data->opp_table);
	else if (data->flags & OPP_CONFIG_GENPD)
		_opp_detach_genpd(data->opp_table);

	if (data->flags & OPP_CONFIG_REGULATOR)
		_opp_put_regulators(data->opp_table);
	if (data->flags & OPP_CONFIG_SUPPORTED_HW)
@@ -2583,12 +2611,22 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)

	/* Attach genpds */
	if (config->genpd_names) {
		if (config->required_devs)
			goto err;

		ret = _opp_attach_genpd(opp_table, dev, config->genpd_names,
					config->virt_devs);
		if (ret)
			goto err;

		data->flags |= OPP_CONFIG_GENPD;
	} else if (config->required_devs) {
		ret = _opp_set_required_devs(opp_table, dev,
					     config->required_devs);
		if (ret)
			goto err;

		data->flags |= OPP_CONFIG_REQUIRED_DEVS;
	}

	ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),
@@ -2974,6 +3012,47 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
}
EXPORT_SYMBOL_GPL(dev_pm_opp_adjust_voltage);

/**
 * dev_pm_opp_sync_regulators() - Sync state of voltage regulators
 * @dev:	device for which we do this operation
 *
 * Sync voltage state of the OPP table regulators.
 *
 * Return: 0 on success or a negative error value.
 */
int dev_pm_opp_sync_regulators(struct device *dev)
{
	struct opp_table *opp_table;
	struct regulator *reg;
	int i, ret = 0;

	/* Device may not have OPP table */
	opp_table = _find_opp_table(dev);
	if (IS_ERR(opp_table))
		return 0;

	/* Regulator may not be required for the device */
	if (unlikely(!opp_table->regulators))
		goto put_table;

	/* Nothing to sync if voltage wasn't changed */
	if (!opp_table->enabled)
		goto put_table;

	for (i = 0; i < opp_table->regulator_count; i++) {
		reg = opp_table->regulators[i];
		ret = regulator_sync_voltage(reg);
		if (ret)
			break;
	}
put_table:
	/* Drop reference taken by _find_opp_table() */
	dev_pm_opp_put_opp_table(opp_table);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_sync_regulators);

/**
 * dev_pm_opp_enable() - Enable a specific OPP
 * @dev:	device for which we do this operation
@@ -3097,44 +3176,3 @@ void dev_pm_opp_remove_table(struct device *dev)
	dev_pm_opp_put_opp_table(opp_table);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);

/**
 * dev_pm_opp_sync_regulators() - Sync state of voltage regulators
 * @dev:	device for which we do this operation
 *
 * Sync voltage state of the OPP table regulators.
 *
 * Return: 0 on success or a negative error value.
 */
int dev_pm_opp_sync_regulators(struct device *dev)
{
	struct opp_table *opp_table;
	struct regulator *reg;
	int i, ret = 0;

	/* Device may not have OPP table */
	opp_table = _find_opp_table(dev);
	if (IS_ERR(opp_table))
		return 0;

	/* Regulator may not be required for the device */
	if (unlikely(!opp_table->regulators))
		goto put_table;

	/* Nothing to sync if voltage wasn't changed */
	if (!opp_table->enabled)
		goto put_table;

	for (i = 0; i < opp_table->regulator_count; i++) {
		reg = opp_table->regulators[i];
		ret = regulator_sync_voltage(reg);
		if (ret)
			break;
	}
put_table:
	/* Drop reference taken by _find_opp_table() */
	dev_pm_opp_put_opp_table(opp_table);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_sync_regulators);
+47 −10
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
	struct opp_table **required_opp_tables;
	struct device_node *required_np, *np;
	bool lazy = false;
	int count, i;
	int count, i, size;

	/* Traversing the first OPP node is all we need */
	np = of_get_next_available_child(opp_np, NULL);
@@ -179,12 +179,13 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
	if (count <= 0)
		goto put_np;

	required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
				      GFP_KERNEL);
	size = sizeof(*required_opp_tables) + sizeof(*opp_table->required_devs);
	required_opp_tables = kcalloc(count, size, GFP_KERNEL);
	if (!required_opp_tables)
		goto put_np;

	opp_table->required_opp_tables = required_opp_tables;
	opp_table->required_devs = (void *)(required_opp_tables + count);
	opp_table->required_opp_count = count;

	for (i = 0; i < count; i++) {
@@ -208,8 +209,6 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
		mutex_lock(&opp_table_lock);
		list_add(&opp_table->lazy, &lazy_opp_tables);
		mutex_unlock(&opp_table_lock);
	} else {
		_update_set_required_opps(opp_table);
	}

	goto put_np;
@@ -296,7 +295,7 @@ void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
	of_node_put(opp->np);
}

static int _link_required_opps(struct dev_pm_opp *opp,
static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *opp_table,
			       struct opp_table *required_table, int index)
{
	struct device_node *np;
@@ -314,6 +313,39 @@ static int _link_required_opps(struct dev_pm_opp *opp,
		return -ENODEV;
	}

	/*
	 * There are two genpd (as required-opp) cases that we need to handle,
	 * devices with a single genpd and ones with multiple genpds.
	 *
	 * The single genpd case requires special handling as we need to use the
	 * same `dev` structure (instead of a virtual one provided by genpd
	 * core) for setting the performance state.
	 *
	 * It doesn't make sense for a device's DT entry to have both
	 * "opp-level" and single "required-opps" entry pointing to a genpd's
	 * OPP, as that would make the OPP core call
	 * dev_pm_domain_set_performance_state() for two different values for
	 * the same device structure. Lets treat single genpd configuration as a
	 * case where the OPP's level is directly available without required-opp
	 * link in the DT.
	 *
	 * Just update the `level` with the right value, which
	 * dev_pm_opp_set_opp() will take care of in the normal path itself.
	 *
	 * There is another case though, where a genpd's OPP table has
	 * required-opps set to a parent genpd. The OPP core expects the user to
	 * set the respective required `struct device` pointer via
	 * dev_pm_opp_set_config().
	 */
	if (required_table->is_genpd && opp_table->required_opp_count == 1 &&
	    !opp_table->required_devs[0]) {
		/* Genpd core takes care of propagation to parent genpd */
		if (!opp_table->is_genpd) {
			if (!WARN_ON(opp->level != OPP_LEVEL_UNSET))
				opp->level = opp->required_opps[0]->level;
		}
	}

	return 0;
}

@@ -338,7 +370,7 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
		if (IS_ERR_OR_NULL(required_table))
			continue;

		ret = _link_required_opps(opp, required_table, i);
		ret = _link_required_opps(opp, opp_table, required_table, i);
		if (ret)
			goto free_required_opps;
	}
@@ -359,7 +391,7 @@ static int lazy_link_required_opps(struct opp_table *opp_table,
	int ret;

	list_for_each_entry(opp, &opp_table->opp_list, node) {
		ret = _link_required_opps(opp, new_table, index);
		ret = _link_required_opps(opp, opp_table, new_table, index);
		if (ret)
			return ret;
	}
@@ -422,7 +454,6 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)

		/* All required opp-tables found, remove from lazy list */
		if (!lazy) {
			_update_set_required_opps(opp_table);
			list_del_init(&opp_table->lazy);

			list_for_each_entry(opp, &opp_table->opp_list, node)
@@ -1393,8 +1424,14 @@ int of_get_required_opp_performance_state(struct device_node *np, int index)

	opp = _find_opp_of_np(opp_table, required_np);
	if (opp) {
		if (opp->level == OPP_LEVEL_UNSET) {
			pr_err("%s: OPP levels aren't available for %pOF\n",
			       __func__, np);
		} else {
			pstate = opp->level;
		}
		dev_pm_opp_put(opp);

	}

	dev_pm_opp_put_opp_table(opp_table);
+17 −7
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ extern struct list_head opp_tables;
#define OPP_CONFIG_PROP_NAME		BIT(3)
#define OPP_CONFIG_SUPPORTED_HW		BIT(4)
#define OPP_CONFIG_GENPD		BIT(5)
#define OPP_CONFIG_REQUIRED_DEVS	BIT(6)

/**
 * struct opp_config_data - data for set config operations
@@ -49,6 +50,18 @@ struct opp_config_data {
	unsigned int flags;
};

/**
 * struct dev_pm_opp_icc_bw - Interconnect bandwidth values
 * @avg:	Average bandwidth corresponding to this OPP (in icc units)
 * @peak:	Peak bandwidth corresponding to this OPP (in icc units)
 *
 * This structure stores the bandwidth values for a single interconnect path.
 */
struct dev_pm_opp_icc_bw {
	u32 avg;
	u32 peak;
};

/*
 * Internal data structure organization with the OPP layer library is as
 * follows:
@@ -157,12 +170,12 @@ enum opp_table_access {
 * @clock_latency_ns_max: Max clock latency in nanoseconds.
 * @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
 * @shared_opp: OPP is shared between multiple devices.
 * @rate_clk_single: Currently configured frequency for single clk.
 * @current_rate_single_clk: Currently configured frequency for single clk.
 * @current_opp: Currently configured OPP for the table.
 * @suspend_opp: Pointer to OPP to be used during device suspend.
 * @genpd_virt_devs: List of virtual devices for multiple genpd support.
 * @required_opp_tables: List of device OPP tables that are required by OPPs in
 *		this table.
 * @required_devs: List of devices for required OPP tables.
 * @required_opp_count: Number of required devices.
 * @supported_hw: Array of version number to support.
 * @supported_hw_count: Number of elements in supported_hw array.
@@ -180,7 +193,6 @@ enum opp_table_access {
 * @path_count: Number of interconnect paths
 * @enabled: Set to true if the device's resources are enabled/configured.
 * @is_genpd: Marks if the OPP table belongs to a genpd.
 * @set_required_opps: Helper responsible to set required OPPs.
 * @dentry:	debugfs dentry pointer of the real device directory (not links).
 * @dentry_name: Name of the real dentry.
 *
@@ -207,12 +219,12 @@ struct opp_table {

	unsigned int parsed_static_opps;
	enum opp_table_access shared_opp;
	unsigned long rate_clk_single;
	unsigned long current_rate_single_clk;
	struct dev_pm_opp *current_opp;
	struct dev_pm_opp *suspend_opp;

	struct device **genpd_virt_devs;
	struct opp_table **required_opp_tables;
	struct device **required_devs;
	unsigned int required_opp_count;

	unsigned int *supported_hw;
@@ -229,8 +241,6 @@ struct opp_table {
	unsigned int path_count;
	bool enabled;
	bool is_genpd;
	int (*set_required_opps)(struct device *dev,
		struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down);

#ifdef CONFIG_DEBUG_FS
	struct dentry *dentry;
+3 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>

@@ -373,23 +374,15 @@ static int ti_opp_supply_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device *cpu_dev = get_cpu_device(0);
	const struct of_device_id *match;
	const struct ti_opp_supply_of_data *of_data;
	int ret = 0;

	match = of_match_device(ti_opp_supply_of_match, dev);
	if (!match) {
		/* We do not expect this to happen */
		dev_err(dev, "%s: Unable to match device\n", __func__);
		return -ENODEV;
	}
	if (!match->data) {
	of_data = device_get_match_data(dev);
	if (!of_data) {
		/* Again, unlikely.. but mistakes do happen */
		dev_err(dev, "%s: Bad data in match\n", __func__);
		return -EINVAL;
	}
	of_data = match->data;

	dev_set_drvdata(dev, (void *)of_data);

	/* If we need optimized voltage */
+11 −17
Original line number Diff line number Diff line
@@ -45,18 +45,6 @@ struct dev_pm_opp_supply {
	unsigned long u_watt;
};

/**
 * struct dev_pm_opp_icc_bw - Interconnect bandwidth values
 * @avg:	Average bandwidth corresponding to this OPP (in icc units)
 * @peak:	Peak bandwidth corresponding to this OPP (in icc units)
 *
 * This structure stores the bandwidth values for a single interconnect path.
 */
struct dev_pm_opp_icc_bw {
	u32 avg;
	u32 peak;
};

typedef int (*config_regulators_t)(struct device *dev,
			struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
			struct regulator **regulators, unsigned int count);
@@ -74,8 +62,10 @@ typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
 * @supported_hw_count: Number of elements in the array.
 * @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
 * @genpd_names: Null terminated array of pointers containing names of genpd to
 *		 attach.
 * @virt_devs: Pointer to return the array of virtual devices.
 *		attach. Mutually exclusive with required_devs.
 * @virt_devs: Pointer to return the array of genpd virtual devices. Mutually
 *		exclusive with required_devs.
 * @required_devs: Required OPP devices. Mutually exclusive with genpd_names/virt_devs.
 *
 * This structure contains platform specific OPP configurations for the device.
 */
@@ -90,11 +80,15 @@ struct dev_pm_opp_config {
	const char * const *regulator_names;
	const char * const *genpd_names;
	struct device ***virt_devs;
	struct device **required_devs;
};

#define OPP_LEVEL_UNSET			U32_MAX

/**
 * struct dev_pm_opp_data - The data to use to initialize an OPP.
 * @level: The performance level for the OPP.
 * @level: The performance level for the OPP. Set level to OPP_LEVEL_UNSET if
 * level field isn't used.
 * @freq: The clock rate in Hz for the OPP.
 * @u_volt: The voltage in uV for the OPP.
 */
@@ -157,7 +151,7 @@ struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
					      unsigned int *level);

struct dev_pm_opp *dev_pm_opp_find_level_floor(struct device *dev,
					       unsigned long *level);
					       unsigned int *level);

struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev,
					   unsigned int *bw, int index);
@@ -324,7 +318,7 @@ static inline struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
}

static inline struct dev_pm_opp *dev_pm_opp_find_level_floor(struct device *dev,
							     unsigned long *level)
							     unsigned int *level)
{
	return ERR_PTR(-EOPNOTSUPP);
}