162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
462306a36Sopenharmony_ci *	    for Non-CPU Devices.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2011 Samsung Electronics
762306a36Sopenharmony_ci *	MyungJoo Ham <myungjoo.ham@samsung.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/kmod.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/debugfs.h>
1462306a36Sopenharmony_ci#include <linux/devfreq_cooling.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/export.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/stat.h>
2162306a36Sopenharmony_ci#include <linux/pm_opp.h>
2262306a36Sopenharmony_ci#include <linux/devfreq.h>
2362306a36Sopenharmony_ci#include <linux/workqueue.h>
2462306a36Sopenharmony_ci#include <linux/platform_device.h>
2562306a36Sopenharmony_ci#include <linux/list.h>
2662306a36Sopenharmony_ci#include <linux/printk.h>
2762306a36Sopenharmony_ci#include <linux/hrtimer.h>
2862306a36Sopenharmony_ci#include <linux/of.h>
2962306a36Sopenharmony_ci#include <linux/pm_qos.h>
3062306a36Sopenharmony_ci#include <linux/units.h>
3162306a36Sopenharmony_ci#include "governor.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
3462306a36Sopenharmony_ci#include <trace/events/devfreq.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define IS_SUPPORTED_FLAG(f, name) ((f & DEVFREQ_GOV_FLAG_##name) ? true : false)
3762306a36Sopenharmony_ci#define IS_SUPPORTED_ATTR(f, name) ((f & DEVFREQ_GOV_ATTR_##name) ? true : false)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct class *devfreq_class;
4062306a36Sopenharmony_cistatic struct dentry *devfreq_debugfs;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * devfreq core provides delayed work based load monitoring helper
4462306a36Sopenharmony_ci * functions. Governors can use these or can implement their own
4562306a36Sopenharmony_ci * monitoring mechanism.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic struct workqueue_struct *devfreq_wq;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* The list of all device-devfreq governors */
5062306a36Sopenharmony_cistatic LIST_HEAD(devfreq_governor_list);
5162306a36Sopenharmony_ci/* The list of all device-devfreq */
5262306a36Sopenharmony_cistatic LIST_HEAD(devfreq_list);
5362306a36Sopenharmony_cistatic DEFINE_MUTEX(devfreq_list_lock);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const char timer_name[][DEVFREQ_NAME_LEN] = {
5662306a36Sopenharmony_ci	[DEVFREQ_TIMER_DEFERRABLE] = { "deferrable" },
5762306a36Sopenharmony_ci	[DEVFREQ_TIMER_DELAYED] = { "delayed" },
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/**
6162306a36Sopenharmony_ci * find_device_devfreq() - find devfreq struct using device pointer
6262306a36Sopenharmony_ci * @dev:	device pointer used to lookup device devfreq.
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * Search the list of device devfreqs and return the matched device's
6562306a36Sopenharmony_ci * devfreq info. devfreq_list_lock should be held by the caller.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic struct devfreq *find_device_devfreq(struct device *dev)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct devfreq *tmp_devfreq;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	lockdep_assert_held(&devfreq_list_lock);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dev)) {
7462306a36Sopenharmony_ci		pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
7562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
7962306a36Sopenharmony_ci		if (tmp_devfreq->dev.parent == dev)
8062306a36Sopenharmony_ci			return tmp_devfreq;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic unsigned long find_available_min_freq(struct devfreq *devfreq)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct dev_pm_opp *opp;
8962306a36Sopenharmony_ci	unsigned long min_freq = 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &min_freq);
9262306a36Sopenharmony_ci	if (IS_ERR(opp))
9362306a36Sopenharmony_ci		min_freq = 0;
9462306a36Sopenharmony_ci	else
9562306a36Sopenharmony_ci		dev_pm_opp_put(opp);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return min_freq;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic unsigned long find_available_max_freq(struct devfreq *devfreq)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct dev_pm_opp *opp;
10362306a36Sopenharmony_ci	unsigned long max_freq = ULONG_MAX;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, &max_freq);
10662306a36Sopenharmony_ci	if (IS_ERR(opp))
10762306a36Sopenharmony_ci		max_freq = 0;
10862306a36Sopenharmony_ci	else
10962306a36Sopenharmony_ci		dev_pm_opp_put(opp);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return max_freq;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/**
11562306a36Sopenharmony_ci * devfreq_get_freq_range() - Get the current freq range
11662306a36Sopenharmony_ci * @devfreq:	the devfreq instance
11762306a36Sopenharmony_ci * @min_freq:	the min frequency
11862306a36Sopenharmony_ci * @max_freq:	the max frequency
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * This takes into consideration all constraints.
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_civoid devfreq_get_freq_range(struct devfreq *devfreq,
12362306a36Sopenharmony_ci			    unsigned long *min_freq,
12462306a36Sopenharmony_ci			    unsigned long *max_freq)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	unsigned long *freq_table = devfreq->freq_table;
12762306a36Sopenharmony_ci	s32 qos_min_freq, qos_max_freq;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	lockdep_assert_held(&devfreq->lock);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/*
13262306a36Sopenharmony_ci	 * Initialize minimum/maximum frequency from freq table.
13362306a36Sopenharmony_ci	 * The devfreq drivers can initialize this in either ascending or
13462306a36Sopenharmony_ci	 * descending order and devfreq core supports both.
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
13762306a36Sopenharmony_ci		*min_freq = freq_table[0];
13862306a36Sopenharmony_ci		*max_freq = freq_table[devfreq->max_state - 1];
13962306a36Sopenharmony_ci	} else {
14062306a36Sopenharmony_ci		*min_freq = freq_table[devfreq->max_state - 1];
14162306a36Sopenharmony_ci		*max_freq = freq_table[0];
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Apply constraints from PM QoS */
14562306a36Sopenharmony_ci	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
14662306a36Sopenharmony_ci					     DEV_PM_QOS_MIN_FREQUENCY);
14762306a36Sopenharmony_ci	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
14862306a36Sopenharmony_ci					     DEV_PM_QOS_MAX_FREQUENCY);
14962306a36Sopenharmony_ci	*min_freq = max(*min_freq, (unsigned long)HZ_PER_KHZ * qos_min_freq);
15062306a36Sopenharmony_ci	if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE)
15162306a36Sopenharmony_ci		*max_freq = min(*max_freq,
15262306a36Sopenharmony_ci				(unsigned long)HZ_PER_KHZ * qos_max_freq);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Apply constraints from OPP interface */
15562306a36Sopenharmony_ci	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
15662306a36Sopenharmony_ci	*max_freq = min(*max_freq, devfreq->scaling_max_freq);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (*min_freq > *max_freq)
15962306a36Sopenharmony_ci		*min_freq = *max_freq;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_get_freq_range);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * devfreq_get_freq_level() - Lookup freq_table for the frequency
16562306a36Sopenharmony_ci * @devfreq:	the devfreq instance
16662306a36Sopenharmony_ci * @freq:	the target frequency
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	int lev;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	for (lev = 0; lev < devfreq->max_state; lev++)
17362306a36Sopenharmony_ci		if (freq == devfreq->freq_table[lev])
17462306a36Sopenharmony_ci			return lev;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return -EINVAL;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int set_freq_table(struct devfreq *devfreq)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct dev_pm_opp *opp;
18262306a36Sopenharmony_ci	unsigned long freq;
18362306a36Sopenharmony_ci	int i, count;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Initialize the freq_table from OPP table */
18662306a36Sopenharmony_ci	count = dev_pm_opp_get_opp_count(devfreq->dev.parent);
18762306a36Sopenharmony_ci	if (count <= 0)
18862306a36Sopenharmony_ci		return -EINVAL;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	devfreq->max_state = count;
19162306a36Sopenharmony_ci	devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
19262306a36Sopenharmony_ci					   devfreq->max_state,
19362306a36Sopenharmony_ci					   sizeof(*devfreq->freq_table),
19462306a36Sopenharmony_ci					   GFP_KERNEL);
19562306a36Sopenharmony_ci	if (!devfreq->freq_table)
19662306a36Sopenharmony_ci		return -ENOMEM;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
19962306a36Sopenharmony_ci		opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
20062306a36Sopenharmony_ci		if (IS_ERR(opp)) {
20162306a36Sopenharmony_ci			devm_kfree(devfreq->dev.parent, devfreq->freq_table);
20262306a36Sopenharmony_ci			return PTR_ERR(opp);
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci		dev_pm_opp_put(opp);
20562306a36Sopenharmony_ci		devfreq->freq_table[i] = freq;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return 0;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/**
21262306a36Sopenharmony_ci * devfreq_update_status() - Update statistics of devfreq behavior
21362306a36Sopenharmony_ci * @devfreq:	the devfreq instance
21462306a36Sopenharmony_ci * @freq:	the update target frequency
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_ciint devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	int lev, prev_lev, ret = 0;
21962306a36Sopenharmony_ci	u64 cur_time;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	lockdep_assert_held(&devfreq->lock);
22262306a36Sopenharmony_ci	cur_time = get_jiffies_64();
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Immediately exit if previous_freq is not initialized yet. */
22562306a36Sopenharmony_ci	if (!devfreq->previous_freq)
22662306a36Sopenharmony_ci		goto out;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
22962306a36Sopenharmony_ci	if (prev_lev < 0) {
23062306a36Sopenharmony_ci		ret = prev_lev;
23162306a36Sopenharmony_ci		goto out;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	devfreq->stats.time_in_state[prev_lev] +=
23562306a36Sopenharmony_ci			cur_time - devfreq->stats.last_update;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	lev = devfreq_get_freq_level(devfreq, freq);
23862306a36Sopenharmony_ci	if (lev < 0) {
23962306a36Sopenharmony_ci		ret = lev;
24062306a36Sopenharmony_ci		goto out;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (lev != prev_lev) {
24462306a36Sopenharmony_ci		devfreq->stats.trans_table[
24562306a36Sopenharmony_ci			(prev_lev * devfreq->max_state) + lev]++;
24662306a36Sopenharmony_ci		devfreq->stats.total_trans++;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciout:
25062306a36Sopenharmony_ci	devfreq->stats.last_update = cur_time;
25162306a36Sopenharmony_ci	return ret;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_update_status);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/**
25662306a36Sopenharmony_ci * find_devfreq_governor() - find devfreq governor from name
25762306a36Sopenharmony_ci * @name:	name of the governor
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * Search the list of devfreq governors and return the matched
26062306a36Sopenharmony_ci * governor's pointer. devfreq_list_lock should be held by the caller.
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_cistatic struct devfreq_governor *find_devfreq_governor(const char *name)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct devfreq_governor *tmp_governor;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	lockdep_assert_held(&devfreq_list_lock);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(name)) {
26962306a36Sopenharmony_ci		pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
27062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	list_for_each_entry(tmp_governor, &devfreq_governor_list, node) {
27462306a36Sopenharmony_ci		if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN))
27562306a36Sopenharmony_ci			return tmp_governor;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/**
28262306a36Sopenharmony_ci * try_then_request_governor() - Try to find the governor and request the
28362306a36Sopenharmony_ci *                               module if is not found.
28462306a36Sopenharmony_ci * @name:	name of the governor
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * Search the list of devfreq governors and request the module and try again
28762306a36Sopenharmony_ci * if is not found. This can happen when both drivers (the governor driver
28862306a36Sopenharmony_ci * and the driver that call devfreq_add_device) are built as modules.
28962306a36Sopenharmony_ci * devfreq_list_lock should be held by the caller. Returns the matched
29062306a36Sopenharmony_ci * governor's pointer or an error pointer.
29162306a36Sopenharmony_ci */
29262306a36Sopenharmony_cistatic struct devfreq_governor *try_then_request_governor(const char *name)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct devfreq_governor *governor;
29562306a36Sopenharmony_ci	int err = 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	lockdep_assert_held(&devfreq_list_lock);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(name)) {
30062306a36Sopenharmony_ci		pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
30162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	governor = find_devfreq_governor(name);
30562306a36Sopenharmony_ci	if (IS_ERR(governor)) {
30662306a36Sopenharmony_ci		mutex_unlock(&devfreq_list_lock);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND,
30962306a36Sopenharmony_ci			     DEVFREQ_NAME_LEN))
31062306a36Sopenharmony_ci			err = request_module("governor_%s", "simpleondemand");
31162306a36Sopenharmony_ci		else
31262306a36Sopenharmony_ci			err = request_module("governor_%s", name);
31362306a36Sopenharmony_ci		/* Restore previous state before return */
31462306a36Sopenharmony_ci		mutex_lock(&devfreq_list_lock);
31562306a36Sopenharmony_ci		if (err)
31662306a36Sopenharmony_ci			return (err < 0) ? ERR_PTR(err) : ERR_PTR(-EINVAL);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		governor = find_devfreq_governor(name);
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return governor;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int devfreq_notify_transition(struct devfreq *devfreq,
32562306a36Sopenharmony_ci		struct devfreq_freqs *freqs, unsigned int state)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	if (!devfreq)
32862306a36Sopenharmony_ci		return -EINVAL;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	switch (state) {
33162306a36Sopenharmony_ci	case DEVFREQ_PRECHANGE:
33262306a36Sopenharmony_ci		srcu_notifier_call_chain(&devfreq->transition_notifier_list,
33362306a36Sopenharmony_ci				DEVFREQ_PRECHANGE, freqs);
33462306a36Sopenharmony_ci		break;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	case DEVFREQ_POSTCHANGE:
33762306a36Sopenharmony_ci		srcu_notifier_call_chain(&devfreq->transition_notifier_list,
33862306a36Sopenharmony_ci				DEVFREQ_POSTCHANGE, freqs);
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci	default:
34162306a36Sopenharmony_ci		return -EINVAL;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return 0;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
34862306a36Sopenharmony_ci			      u32 flags)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct devfreq_freqs freqs;
35162306a36Sopenharmony_ci	unsigned long cur_freq;
35262306a36Sopenharmony_ci	int err = 0;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (devfreq->profile->get_cur_freq)
35562306a36Sopenharmony_ci		devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
35662306a36Sopenharmony_ci	else
35762306a36Sopenharmony_ci		cur_freq = devfreq->previous_freq;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	freqs.old = cur_freq;
36062306a36Sopenharmony_ci	freqs.new = new_freq;
36162306a36Sopenharmony_ci	devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	err = devfreq->profile->target(devfreq->dev.parent, &new_freq, flags);
36462306a36Sopenharmony_ci	if (err) {
36562306a36Sopenharmony_ci		freqs.new = cur_freq;
36662306a36Sopenharmony_ci		devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
36762306a36Sopenharmony_ci		return err;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/*
37162306a36Sopenharmony_ci	 * Print devfreq_frequency trace information between DEVFREQ_PRECHANGE
37262306a36Sopenharmony_ci	 * and DEVFREQ_POSTCHANGE because for showing the correct frequency
37362306a36Sopenharmony_ci	 * change order of between devfreq device and passive devfreq device.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	if (trace_devfreq_frequency_enabled() && new_freq != cur_freq)
37662306a36Sopenharmony_ci		trace_devfreq_frequency(devfreq, new_freq, cur_freq);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	freqs.new = new_freq;
37962306a36Sopenharmony_ci	devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (devfreq_update_status(devfreq, new_freq))
38262306a36Sopenharmony_ci		dev_warn(&devfreq->dev,
38362306a36Sopenharmony_ci			 "Couldn't update frequency transition information.\n");
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	devfreq->previous_freq = new_freq;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (devfreq->suspend_freq)
38862306a36Sopenharmony_ci		devfreq->resume_freq = new_freq;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return err;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/**
39462306a36Sopenharmony_ci * devfreq_update_target() - Reevaluate the device and configure frequency
39562306a36Sopenharmony_ci *			   on the final stage.
39662306a36Sopenharmony_ci * @devfreq:	the devfreq instance.
39762306a36Sopenharmony_ci * @freq:	the new frequency of parent device. This argument
39862306a36Sopenharmony_ci *		is only used for devfreq device using passive governor.
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * Note: Lock devfreq->lock before calling devfreq_update_target. This function
40162306a36Sopenharmony_ci *	 should be only used by both update_devfreq() and devfreq governors.
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_ciint devfreq_update_target(struct devfreq *devfreq, unsigned long freq)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	unsigned long min_freq, max_freq;
40662306a36Sopenharmony_ci	int err = 0;
40762306a36Sopenharmony_ci	u32 flags = 0;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	lockdep_assert_held(&devfreq->lock);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (!devfreq->governor)
41262306a36Sopenharmony_ci		return -EINVAL;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Reevaluate the proper frequency */
41562306a36Sopenharmony_ci	err = devfreq->governor->get_target_freq(devfreq, &freq);
41662306a36Sopenharmony_ci	if (err)
41762306a36Sopenharmony_ci		return err;
41862306a36Sopenharmony_ci	devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (freq < min_freq) {
42162306a36Sopenharmony_ci		freq = min_freq;
42262306a36Sopenharmony_ci		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci	if (freq > max_freq) {
42562306a36Sopenharmony_ci		freq = max_freq;
42662306a36Sopenharmony_ci		flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return devfreq_set_target(devfreq, freq, flags);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_update_target);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/* Load monitoring helper functions for governors use */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/**
43662306a36Sopenharmony_ci * update_devfreq() - Reevaluate the device and configure frequency.
43762306a36Sopenharmony_ci * @devfreq:	the devfreq instance.
43862306a36Sopenharmony_ci *
43962306a36Sopenharmony_ci * Note: Lock devfreq->lock before calling update_devfreq
44062306a36Sopenharmony_ci *	 This function is exported for governors.
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_ciint update_devfreq(struct devfreq *devfreq)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	return devfreq_update_target(devfreq, 0L);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ciEXPORT_SYMBOL(update_devfreq);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/**
44962306a36Sopenharmony_ci * devfreq_monitor() - Periodically poll devfreq objects.
45062306a36Sopenharmony_ci * @work:	the work struct used to run devfreq_monitor periodically.
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_cistatic void devfreq_monitor(struct work_struct *work)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	int err;
45662306a36Sopenharmony_ci	struct devfreq *devfreq = container_of(work,
45762306a36Sopenharmony_ci					struct devfreq, work.work);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
46062306a36Sopenharmony_ci	err = update_devfreq(devfreq);
46162306a36Sopenharmony_ci	if (err)
46262306a36Sopenharmony_ci		dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (devfreq->stop_polling)
46562306a36Sopenharmony_ci		goto out;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	queue_delayed_work(devfreq_wq, &devfreq->work,
46862306a36Sopenharmony_ci				msecs_to_jiffies(devfreq->profile->polling_ms));
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ciout:
47162306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
47262306a36Sopenharmony_ci	trace_devfreq_monitor(devfreq);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/**
47662306a36Sopenharmony_ci * devfreq_monitor_start() - Start load monitoring of devfreq instance
47762306a36Sopenharmony_ci * @devfreq:	the devfreq instance.
47862306a36Sopenharmony_ci *
47962306a36Sopenharmony_ci * Helper function for starting devfreq device load monitoring. By default,
48062306a36Sopenharmony_ci * deferrable timer is used for load monitoring. But the users can change this
48162306a36Sopenharmony_ci * behavior using the "timer" type in devfreq_dev_profile. This function will be
48262306a36Sopenharmony_ci * called by devfreq governor in response to the DEVFREQ_GOV_START event
48362306a36Sopenharmony_ci * generated while adding a device to the devfreq framework.
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_civoid devfreq_monitor_start(struct devfreq *devfreq)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
48862306a36Sopenharmony_ci		return;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
49162306a36Sopenharmony_ci	if (delayed_work_pending(&devfreq->work))
49262306a36Sopenharmony_ci		goto out;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	switch (devfreq->profile->timer) {
49562306a36Sopenharmony_ci	case DEVFREQ_TIMER_DEFERRABLE:
49662306a36Sopenharmony_ci		INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci	case DEVFREQ_TIMER_DELAYED:
49962306a36Sopenharmony_ci		INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor);
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	default:
50262306a36Sopenharmony_ci		goto out;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (devfreq->profile->polling_ms)
50662306a36Sopenharmony_ci		queue_delayed_work(devfreq_wq, &devfreq->work,
50762306a36Sopenharmony_ci			msecs_to_jiffies(devfreq->profile->polling_ms));
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ciout:
51062306a36Sopenharmony_ci	devfreq->stop_polling = false;
51162306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_start);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/**
51662306a36Sopenharmony_ci * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
51762306a36Sopenharmony_ci * @devfreq:	the devfreq instance.
51862306a36Sopenharmony_ci *
51962306a36Sopenharmony_ci * Helper function to stop devfreq device load monitoring. Function
52062306a36Sopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_STOP
52162306a36Sopenharmony_ci * event when device is removed from devfreq framework.
52262306a36Sopenharmony_ci */
52362306a36Sopenharmony_civoid devfreq_monitor_stop(struct devfreq *devfreq)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
52662306a36Sopenharmony_ci		return;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
52962306a36Sopenharmony_ci	if (devfreq->stop_polling) {
53062306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
53162306a36Sopenharmony_ci		return;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	devfreq->stop_polling = true;
53562306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
53662306a36Sopenharmony_ci	cancel_delayed_work_sync(&devfreq->work);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_stop);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/**
54162306a36Sopenharmony_ci * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
54262306a36Sopenharmony_ci * @devfreq:	the devfreq instance.
54362306a36Sopenharmony_ci *
54462306a36Sopenharmony_ci * Helper function to suspend devfreq device load monitoring. Function
54562306a36Sopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_SUSPEND
54662306a36Sopenharmony_ci * event or when polling interval is set to zero.
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * Note: Though this function is same as devfreq_monitor_stop(),
54962306a36Sopenharmony_ci * intentionally kept separate to provide hooks for collecting
55062306a36Sopenharmony_ci * transition statistics.
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_civoid devfreq_monitor_suspend(struct devfreq *devfreq)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
55562306a36Sopenharmony_ci	if (devfreq->stop_polling) {
55662306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
55762306a36Sopenharmony_ci		return;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	devfreq_update_status(devfreq, devfreq->previous_freq);
56162306a36Sopenharmony_ci	devfreq->stop_polling = true;
56262306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
56562306a36Sopenharmony_ci		return;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	cancel_delayed_work_sync(&devfreq->work);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_suspend);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/**
57262306a36Sopenharmony_ci * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
57362306a36Sopenharmony_ci * @devfreq:    the devfreq instance.
57462306a36Sopenharmony_ci *
57562306a36Sopenharmony_ci * Helper function to resume devfreq device load monitoring. Function
57662306a36Sopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_RESUME
57762306a36Sopenharmony_ci * event or when polling interval is set to non-zero.
57862306a36Sopenharmony_ci */
57962306a36Sopenharmony_civoid devfreq_monitor_resume(struct devfreq *devfreq)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	unsigned long freq;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
58662306a36Sopenharmony_ci		goto out_update;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (!devfreq->stop_polling)
58962306a36Sopenharmony_ci		goto out;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (!delayed_work_pending(&devfreq->work) &&
59262306a36Sopenharmony_ci			devfreq->profile->polling_ms)
59362306a36Sopenharmony_ci		queue_delayed_work(devfreq_wq, &devfreq->work,
59462306a36Sopenharmony_ci			msecs_to_jiffies(devfreq->profile->polling_ms));
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciout_update:
59762306a36Sopenharmony_ci	devfreq->stats.last_update = get_jiffies_64();
59862306a36Sopenharmony_ci	devfreq->stop_polling = false;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (devfreq->profile->get_cur_freq &&
60162306a36Sopenharmony_ci		!devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
60262306a36Sopenharmony_ci		devfreq->previous_freq = freq;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ciout:
60562306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_resume);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/**
61062306a36Sopenharmony_ci * devfreq_update_interval() - Update device devfreq monitoring interval
61162306a36Sopenharmony_ci * @devfreq:    the devfreq instance.
61262306a36Sopenharmony_ci * @delay:      new polling interval to be set.
61362306a36Sopenharmony_ci *
61462306a36Sopenharmony_ci * Helper function to set new load monitoring polling interval. Function
61562306a36Sopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_UPDATE_INTERVAL event.
61662306a36Sopenharmony_ci */
61762306a36Sopenharmony_civoid devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	unsigned int cur_delay = devfreq->profile->polling_ms;
62062306a36Sopenharmony_ci	unsigned int new_delay = *delay;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
62362306a36Sopenharmony_ci	devfreq->profile->polling_ms = new_delay;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
62662306a36Sopenharmony_ci		goto out;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (devfreq->stop_polling)
62962306a36Sopenharmony_ci		goto out;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	/* if new delay is zero, stop polling */
63262306a36Sopenharmony_ci	if (!new_delay) {
63362306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
63462306a36Sopenharmony_ci		cancel_delayed_work_sync(&devfreq->work);
63562306a36Sopenharmony_ci		return;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* if current delay is zero, start polling with new delay */
63962306a36Sopenharmony_ci	if (!cur_delay) {
64062306a36Sopenharmony_ci		queue_delayed_work(devfreq_wq, &devfreq->work,
64162306a36Sopenharmony_ci			msecs_to_jiffies(devfreq->profile->polling_ms));
64262306a36Sopenharmony_ci		goto out;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* if current delay is greater than new delay, restart polling */
64662306a36Sopenharmony_ci	if (cur_delay > new_delay) {
64762306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
64862306a36Sopenharmony_ci		cancel_delayed_work_sync(&devfreq->work);
64962306a36Sopenharmony_ci		mutex_lock(&devfreq->lock);
65062306a36Sopenharmony_ci		if (!devfreq->stop_polling)
65162306a36Sopenharmony_ci			queue_delayed_work(devfreq_wq, &devfreq->work,
65262306a36Sopenharmony_ci				msecs_to_jiffies(devfreq->profile->polling_ms));
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ciout:
65562306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_update_interval);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/**
66062306a36Sopenharmony_ci * devfreq_notifier_call() - Notify that the device frequency requirements
66162306a36Sopenharmony_ci *			     has been changed out of devfreq framework.
66262306a36Sopenharmony_ci * @nb:		the notifier_block (supposed to be devfreq->nb)
66362306a36Sopenharmony_ci * @type:	not used
66462306a36Sopenharmony_ci * @devp:	not used
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci * Called by a notifier that uses devfreq->nb.
66762306a36Sopenharmony_ci */
66862306a36Sopenharmony_cistatic int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
66962306a36Sopenharmony_ci				 void *devp)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
67262306a36Sopenharmony_ci	int err = -EINVAL;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
67762306a36Sopenharmony_ci	if (!devfreq->scaling_min_freq)
67862306a36Sopenharmony_ci		goto out;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
68162306a36Sopenharmony_ci	if (!devfreq->scaling_max_freq) {
68262306a36Sopenharmony_ci		devfreq->scaling_max_freq = ULONG_MAX;
68362306a36Sopenharmony_ci		goto out;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	err = update_devfreq(devfreq);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciout:
68962306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
69062306a36Sopenharmony_ci	if (err)
69162306a36Sopenharmony_ci		dev_err(devfreq->dev.parent,
69262306a36Sopenharmony_ci			"failed to update frequency from OPP notifier (%d)\n",
69362306a36Sopenharmony_ci			err);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return NOTIFY_OK;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/**
69962306a36Sopenharmony_ci * qos_notifier_call() - Common handler for QoS constraints.
70062306a36Sopenharmony_ci * @devfreq:    the devfreq instance.
70162306a36Sopenharmony_ci */
70262306a36Sopenharmony_cistatic int qos_notifier_call(struct devfreq *devfreq)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	int err;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
70762306a36Sopenharmony_ci	err = update_devfreq(devfreq);
70862306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
70962306a36Sopenharmony_ci	if (err)
71062306a36Sopenharmony_ci		dev_err(devfreq->dev.parent,
71162306a36Sopenharmony_ci			"failed to update frequency from PM QoS (%d)\n",
71262306a36Sopenharmony_ci			err);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return NOTIFY_OK;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci/**
71862306a36Sopenharmony_ci * qos_min_notifier_call() - Callback for QoS min_freq changes.
71962306a36Sopenharmony_ci * @nb:		Should be devfreq->nb_min
72062306a36Sopenharmony_ci * @val:	not used
72162306a36Sopenharmony_ci * @ptr:	not used
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_cistatic int qos_min_notifier_call(struct notifier_block *nb,
72462306a36Sopenharmony_ci					 unsigned long val, void *ptr)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/**
73062306a36Sopenharmony_ci * qos_max_notifier_call() - Callback for QoS max_freq changes.
73162306a36Sopenharmony_ci * @nb:		Should be devfreq->nb_max
73262306a36Sopenharmony_ci * @val:	not used
73362306a36Sopenharmony_ci * @ptr:	not used
73462306a36Sopenharmony_ci */
73562306a36Sopenharmony_cistatic int qos_max_notifier_call(struct notifier_block *nb,
73662306a36Sopenharmony_ci					 unsigned long val, void *ptr)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci/**
74262306a36Sopenharmony_ci * devfreq_dev_release() - Callback for struct device to release the device.
74362306a36Sopenharmony_ci * @dev:	the devfreq device
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * Remove devfreq from the list and release its resources.
74662306a36Sopenharmony_ci */
74762306a36Sopenharmony_cistatic void devfreq_dev_release(struct device *dev)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct devfreq *devfreq = to_devfreq(dev);
75062306a36Sopenharmony_ci	int err;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
75362306a36Sopenharmony_ci	list_del(&devfreq->node);
75462306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
75762306a36Sopenharmony_ci					 DEV_PM_QOS_MAX_FREQUENCY);
75862306a36Sopenharmony_ci	if (err && err != -ENOENT)
75962306a36Sopenharmony_ci		dev_warn(dev->parent,
76062306a36Sopenharmony_ci			"Failed to remove max_freq notifier: %d\n", err);
76162306a36Sopenharmony_ci	err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
76262306a36Sopenharmony_ci					 DEV_PM_QOS_MIN_FREQUENCY);
76362306a36Sopenharmony_ci	if (err && err != -ENOENT)
76462306a36Sopenharmony_ci		dev_warn(dev->parent,
76562306a36Sopenharmony_ci			"Failed to remove min_freq notifier: %d\n", err);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) {
76862306a36Sopenharmony_ci		err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
76962306a36Sopenharmony_ci		if (err < 0)
77062306a36Sopenharmony_ci			dev_warn(dev->parent,
77162306a36Sopenharmony_ci				"Failed to remove max_freq request: %d\n", err);
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) {
77462306a36Sopenharmony_ci		err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
77562306a36Sopenharmony_ci		if (err < 0)
77662306a36Sopenharmony_ci			dev_warn(dev->parent,
77762306a36Sopenharmony_ci				"Failed to remove min_freq request: %d\n", err);
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (devfreq->profile->exit)
78162306a36Sopenharmony_ci		devfreq->profile->exit(devfreq->dev.parent);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	if (devfreq->opp_table)
78462306a36Sopenharmony_ci		dev_pm_opp_put_opp_table(devfreq->opp_table);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	mutex_destroy(&devfreq->lock);
78762306a36Sopenharmony_ci	srcu_cleanup_notifier_head(&devfreq->transition_notifier_list);
78862306a36Sopenharmony_ci	kfree(devfreq);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void create_sysfs_files(struct devfreq *devfreq,
79262306a36Sopenharmony_ci				const struct devfreq_governor *gov);
79362306a36Sopenharmony_cistatic void remove_sysfs_files(struct devfreq *devfreq,
79462306a36Sopenharmony_ci				const struct devfreq_governor *gov);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci/**
79762306a36Sopenharmony_ci * devfreq_add_device() - Add devfreq feature to the device
79862306a36Sopenharmony_ci * @dev:	the device to add devfreq feature.
79962306a36Sopenharmony_ci * @profile:	device-specific profile to run devfreq.
80062306a36Sopenharmony_ci * @governor_name:	name of the policy to choose frequency.
80162306a36Sopenharmony_ci * @data:	devfreq driver pass to governors, governor should not change it.
80262306a36Sopenharmony_ci */
80362306a36Sopenharmony_cistruct devfreq *devfreq_add_device(struct device *dev,
80462306a36Sopenharmony_ci				   struct devfreq_dev_profile *profile,
80562306a36Sopenharmony_ci				   const char *governor_name,
80662306a36Sopenharmony_ci				   void *data)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct devfreq *devfreq;
80962306a36Sopenharmony_ci	struct devfreq_governor *governor;
81062306a36Sopenharmony_ci	unsigned long min_freq, max_freq;
81162306a36Sopenharmony_ci	int err = 0;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (!dev || !profile || !governor_name) {
81462306a36Sopenharmony_ci		dev_err(dev, "%s: Invalid parameters.\n", __func__);
81562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
81962306a36Sopenharmony_ci	devfreq = find_device_devfreq(dev);
82062306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
82162306a36Sopenharmony_ci	if (!IS_ERR(devfreq)) {
82262306a36Sopenharmony_ci		dev_err(dev, "%s: devfreq device already exists!\n",
82362306a36Sopenharmony_ci			__func__);
82462306a36Sopenharmony_ci		err = -EINVAL;
82562306a36Sopenharmony_ci		goto err_out;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
82962306a36Sopenharmony_ci	if (!devfreq) {
83062306a36Sopenharmony_ci		err = -ENOMEM;
83162306a36Sopenharmony_ci		goto err_out;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	mutex_init(&devfreq->lock);
83562306a36Sopenharmony_ci	mutex_lock(&devfreq->lock);
83662306a36Sopenharmony_ci	devfreq->dev.parent = dev;
83762306a36Sopenharmony_ci	devfreq->dev.class = devfreq_class;
83862306a36Sopenharmony_ci	devfreq->dev.release = devfreq_dev_release;
83962306a36Sopenharmony_ci	INIT_LIST_HEAD(&devfreq->node);
84062306a36Sopenharmony_ci	devfreq->profile = profile;
84162306a36Sopenharmony_ci	devfreq->previous_freq = profile->initial_freq;
84262306a36Sopenharmony_ci	devfreq->last_status.current_frequency = profile->initial_freq;
84362306a36Sopenharmony_ci	devfreq->data = data;
84462306a36Sopenharmony_ci	devfreq->nb.notifier_call = devfreq_notifier_call;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (devfreq->profile->timer < 0
84762306a36Sopenharmony_ci		|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
84862306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
84962306a36Sopenharmony_ci		err = -EINVAL;
85062306a36Sopenharmony_ci		goto err_dev;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (!devfreq->profile->max_state || !devfreq->profile->freq_table) {
85462306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
85562306a36Sopenharmony_ci		err = set_freq_table(devfreq);
85662306a36Sopenharmony_ci		if (err < 0)
85762306a36Sopenharmony_ci			goto err_dev;
85862306a36Sopenharmony_ci		mutex_lock(&devfreq->lock);
85962306a36Sopenharmony_ci	} else {
86062306a36Sopenharmony_ci		devfreq->freq_table = devfreq->profile->freq_table;
86162306a36Sopenharmony_ci		devfreq->max_state = devfreq->profile->max_state;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
86562306a36Sopenharmony_ci	if (!devfreq->scaling_min_freq) {
86662306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
86762306a36Sopenharmony_ci		err = -EINVAL;
86862306a36Sopenharmony_ci		goto err_dev;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
87262306a36Sopenharmony_ci	if (!devfreq->scaling_max_freq) {
87362306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
87462306a36Sopenharmony_ci		err = -EINVAL;
87562306a36Sopenharmony_ci		goto err_dev;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
88162306a36Sopenharmony_ci	devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
88262306a36Sopenharmony_ci	if (IS_ERR(devfreq->opp_table))
88362306a36Sopenharmony_ci		devfreq->opp_table = NULL;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	atomic_set(&devfreq->suspend_count, 0);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	dev_set_name(&devfreq->dev, "%s", dev_name(dev));
88862306a36Sopenharmony_ci	err = device_register(&devfreq->dev);
88962306a36Sopenharmony_ci	if (err) {
89062306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
89162306a36Sopenharmony_ci		put_device(&devfreq->dev);
89262306a36Sopenharmony_ci		goto err_out;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
89662306a36Sopenharmony_ci			array3_size(sizeof(unsigned int),
89762306a36Sopenharmony_ci				    devfreq->max_state,
89862306a36Sopenharmony_ci				    devfreq->max_state),
89962306a36Sopenharmony_ci			GFP_KERNEL);
90062306a36Sopenharmony_ci	if (!devfreq->stats.trans_table) {
90162306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
90262306a36Sopenharmony_ci		err = -ENOMEM;
90362306a36Sopenharmony_ci		goto err_devfreq;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
90762306a36Sopenharmony_ci			devfreq->max_state,
90862306a36Sopenharmony_ci			sizeof(*devfreq->stats.time_in_state),
90962306a36Sopenharmony_ci			GFP_KERNEL);
91062306a36Sopenharmony_ci	if (!devfreq->stats.time_in_state) {
91162306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
91262306a36Sopenharmony_ci		err = -ENOMEM;
91362306a36Sopenharmony_ci		goto err_devfreq;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	devfreq->stats.total_trans = 0;
91762306a36Sopenharmony_ci	devfreq->stats.last_update = get_jiffies_64();
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	srcu_init_notifier_head(&devfreq->transition_notifier_list);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	mutex_unlock(&devfreq->lock);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
92462306a36Sopenharmony_ci				     DEV_PM_QOS_MIN_FREQUENCY, 0);
92562306a36Sopenharmony_ci	if (err < 0)
92662306a36Sopenharmony_ci		goto err_devfreq;
92762306a36Sopenharmony_ci	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
92862306a36Sopenharmony_ci				     DEV_PM_QOS_MAX_FREQUENCY,
92962306a36Sopenharmony_ci				     PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
93062306a36Sopenharmony_ci	if (err < 0)
93162306a36Sopenharmony_ci		goto err_devfreq;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	devfreq->nb_min.notifier_call = qos_min_notifier_call;
93462306a36Sopenharmony_ci	err = dev_pm_qos_add_notifier(dev, &devfreq->nb_min,
93562306a36Sopenharmony_ci				      DEV_PM_QOS_MIN_FREQUENCY);
93662306a36Sopenharmony_ci	if (err)
93762306a36Sopenharmony_ci		goto err_devfreq;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	devfreq->nb_max.notifier_call = qos_max_notifier_call;
94062306a36Sopenharmony_ci	err = dev_pm_qos_add_notifier(dev, &devfreq->nb_max,
94162306a36Sopenharmony_ci				      DEV_PM_QOS_MAX_FREQUENCY);
94262306a36Sopenharmony_ci	if (err)
94362306a36Sopenharmony_ci		goto err_devfreq;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	governor = try_then_request_governor(governor_name);
94862306a36Sopenharmony_ci	if (IS_ERR(governor)) {
94962306a36Sopenharmony_ci		dev_err(dev, "%s: Unable to find governor for the device\n",
95062306a36Sopenharmony_ci			__func__);
95162306a36Sopenharmony_ci		err = PTR_ERR(governor);
95262306a36Sopenharmony_ci		goto err_init;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	devfreq->governor = governor;
95662306a36Sopenharmony_ci	err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
95762306a36Sopenharmony_ci						NULL);
95862306a36Sopenharmony_ci	if (err) {
95962306a36Sopenharmony_ci		dev_err_probe(dev, err,
96062306a36Sopenharmony_ci			"%s: Unable to start governor for the device\n",
96162306a36Sopenharmony_ci			 __func__);
96262306a36Sopenharmony_ci		goto err_init;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci	create_sysfs_files(devfreq, devfreq->governor);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	list_add(&devfreq->node, &devfreq_list);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (devfreq->profile->is_cooling_device) {
97162306a36Sopenharmony_ci		devfreq->cdev = devfreq_cooling_em_register(devfreq, NULL);
97262306a36Sopenharmony_ci		if (IS_ERR(devfreq->cdev))
97362306a36Sopenharmony_ci			devfreq->cdev = NULL;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	return devfreq;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cierr_init:
97962306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
98062306a36Sopenharmony_cierr_devfreq:
98162306a36Sopenharmony_ci	devfreq_remove_device(devfreq);
98262306a36Sopenharmony_ci	devfreq = NULL;
98362306a36Sopenharmony_cierr_dev:
98462306a36Sopenharmony_ci	kfree(devfreq);
98562306a36Sopenharmony_cierr_out:
98662306a36Sopenharmony_ci	return ERR_PTR(err);
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_add_device);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci/**
99162306a36Sopenharmony_ci * devfreq_remove_device() - Remove devfreq feature from a device.
99262306a36Sopenharmony_ci * @devfreq:	the devfreq instance to be removed
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * The opposite of devfreq_add_device().
99562306a36Sopenharmony_ci */
99662306a36Sopenharmony_ciint devfreq_remove_device(struct devfreq *devfreq)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	if (!devfreq)
99962306a36Sopenharmony_ci		return -EINVAL;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	devfreq_cooling_unregister(devfreq->cdev);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (devfreq->governor) {
100462306a36Sopenharmony_ci		devfreq->governor->event_handler(devfreq,
100562306a36Sopenharmony_ci						 DEVFREQ_GOV_STOP, NULL);
100662306a36Sopenharmony_ci		remove_sysfs_files(devfreq, devfreq->governor);
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	device_unregister(&devfreq->dev);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	return 0;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_remove_device);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct devfreq **r = res;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (WARN_ON(!r || !*r))
102062306a36Sopenharmony_ci		return 0;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	return *r == data;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic void devm_devfreq_dev_release(struct device *dev, void *res)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	devfreq_remove_device(*(struct devfreq **)res);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci/**
103162306a36Sopenharmony_ci * devm_devfreq_add_device() - Resource-managed devfreq_add_device()
103262306a36Sopenharmony_ci * @dev:	the device to add devfreq feature.
103362306a36Sopenharmony_ci * @profile:	device-specific profile to run devfreq.
103462306a36Sopenharmony_ci * @governor_name:	name of the policy to choose frequency.
103562306a36Sopenharmony_ci * @data:	 devfreq driver pass to governors, governor should not change it.
103662306a36Sopenharmony_ci *
103762306a36Sopenharmony_ci * This function manages automatically the memory of devfreq device using device
103862306a36Sopenharmony_ci * resource management and simplify the free operation for memory of devfreq
103962306a36Sopenharmony_ci * device.
104062306a36Sopenharmony_ci */
104162306a36Sopenharmony_cistruct devfreq *devm_devfreq_add_device(struct device *dev,
104262306a36Sopenharmony_ci					struct devfreq_dev_profile *profile,
104362306a36Sopenharmony_ci					const char *governor_name,
104462306a36Sopenharmony_ci					void *data)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct devfreq **ptr, *devfreq;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	ptr = devres_alloc(devm_devfreq_dev_release, sizeof(*ptr), GFP_KERNEL);
104962306a36Sopenharmony_ci	if (!ptr)
105062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	devfreq = devfreq_add_device(dev, profile, governor_name, data);
105362306a36Sopenharmony_ci	if (IS_ERR(devfreq)) {
105462306a36Sopenharmony_ci		devres_free(ptr);
105562306a36Sopenharmony_ci		return devfreq;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	*ptr = devfreq;
105962306a36Sopenharmony_ci	devres_add(dev, ptr);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return devfreq;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_add_device);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci#ifdef CONFIG_OF
106662306a36Sopenharmony_ci/*
106762306a36Sopenharmony_ci * devfreq_get_devfreq_by_node - Get the devfreq device from devicetree
106862306a36Sopenharmony_ci * @node - pointer to device_node
106962306a36Sopenharmony_ci *
107062306a36Sopenharmony_ci * return the instance of devfreq device
107162306a36Sopenharmony_ci */
107262306a36Sopenharmony_cistruct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct devfreq *devfreq;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (!node)
107762306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
108062306a36Sopenharmony_ci	list_for_each_entry(devfreq, &devfreq_list, node) {
108162306a36Sopenharmony_ci		if (devfreq->dev.parent
108262306a36Sopenharmony_ci			&& device_match_of_node(devfreq->dev.parent, node)) {
108362306a36Sopenharmony_ci			mutex_unlock(&devfreq_list_lock);
108462306a36Sopenharmony_ci			return devfreq;
108562306a36Sopenharmony_ci		}
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci/*
109362306a36Sopenharmony_ci * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
109462306a36Sopenharmony_ci * @dev - instance to the given device
109562306a36Sopenharmony_ci * @phandle_name - name of property holding a phandle value
109662306a36Sopenharmony_ci * @index - index into list of devfreq
109762306a36Sopenharmony_ci *
109862306a36Sopenharmony_ci * return the instance of devfreq device
109962306a36Sopenharmony_ci */
110062306a36Sopenharmony_cistruct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
110162306a36Sopenharmony_ci					const char *phandle_name, int index)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	struct device_node *node;
110462306a36Sopenharmony_ci	struct devfreq *devfreq;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (!dev || !phandle_name)
110762306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	if (!dev->of_node)
111062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	node = of_parse_phandle(dev->of_node, phandle_name, index);
111362306a36Sopenharmony_ci	if (!node)
111462306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	devfreq = devfreq_get_devfreq_by_node(node);
111762306a36Sopenharmony_ci	of_node_put(node);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	return devfreq;
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci#else
112362306a36Sopenharmony_cistruct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistruct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
112962306a36Sopenharmony_ci					const char *phandle_name, int index)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci#endif /* CONFIG_OF */
113462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_node);
113562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_phandle);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci/**
113862306a36Sopenharmony_ci * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
113962306a36Sopenharmony_ci * @dev:	the device from which to remove devfreq feature.
114062306a36Sopenharmony_ci * @devfreq:	the devfreq instance to be removed
114162306a36Sopenharmony_ci */
114262306a36Sopenharmony_civoid devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	WARN_ON(devres_release(dev, devm_devfreq_dev_release,
114562306a36Sopenharmony_ci			       devm_devfreq_dev_match, devfreq));
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_remove_device);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/**
115062306a36Sopenharmony_ci * devfreq_suspend_device() - Suspend devfreq of a device.
115162306a36Sopenharmony_ci * @devfreq: the devfreq instance to be suspended
115262306a36Sopenharmony_ci *
115362306a36Sopenharmony_ci * This function is intended to be called by the pm callbacks
115462306a36Sopenharmony_ci * (e.g., runtime_suspend, suspend) of the device driver that
115562306a36Sopenharmony_ci * holds the devfreq.
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_ciint devfreq_suspend_device(struct devfreq *devfreq)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	int ret;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (!devfreq)
116262306a36Sopenharmony_ci		return -EINVAL;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (atomic_inc_return(&devfreq->suspend_count) > 1)
116562306a36Sopenharmony_ci		return 0;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (devfreq->governor) {
116862306a36Sopenharmony_ci		ret = devfreq->governor->event_handler(devfreq,
116962306a36Sopenharmony_ci					DEVFREQ_GOV_SUSPEND, NULL);
117062306a36Sopenharmony_ci		if (ret)
117162306a36Sopenharmony_ci			return ret;
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (devfreq->suspend_freq) {
117562306a36Sopenharmony_ci		mutex_lock(&devfreq->lock);
117662306a36Sopenharmony_ci		ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
117762306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
117862306a36Sopenharmony_ci		if (ret)
117962306a36Sopenharmony_ci			return ret;
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	return 0;
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_suspend_device);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci/**
118762306a36Sopenharmony_ci * devfreq_resume_device() - Resume devfreq of a device.
118862306a36Sopenharmony_ci * @devfreq: the devfreq instance to be resumed
118962306a36Sopenharmony_ci *
119062306a36Sopenharmony_ci * This function is intended to be called by the pm callbacks
119162306a36Sopenharmony_ci * (e.g., runtime_resume, resume) of the device driver that
119262306a36Sopenharmony_ci * holds the devfreq.
119362306a36Sopenharmony_ci */
119462306a36Sopenharmony_ciint devfreq_resume_device(struct devfreq *devfreq)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	int ret;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	if (!devfreq)
119962306a36Sopenharmony_ci		return -EINVAL;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (atomic_dec_return(&devfreq->suspend_count) >= 1)
120262306a36Sopenharmony_ci		return 0;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (devfreq->resume_freq) {
120562306a36Sopenharmony_ci		mutex_lock(&devfreq->lock);
120662306a36Sopenharmony_ci		ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
120762306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
120862306a36Sopenharmony_ci		if (ret)
120962306a36Sopenharmony_ci			return ret;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (devfreq->governor) {
121362306a36Sopenharmony_ci		ret = devfreq->governor->event_handler(devfreq,
121462306a36Sopenharmony_ci					DEVFREQ_GOV_RESUME, NULL);
121562306a36Sopenharmony_ci		if (ret)
121662306a36Sopenharmony_ci			return ret;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_resume_device);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci/**
122462306a36Sopenharmony_ci * devfreq_suspend() - Suspend devfreq governors and devices
122562306a36Sopenharmony_ci *
122662306a36Sopenharmony_ci * Called during system wide Suspend/Hibernate cycles for suspending governors
122762306a36Sopenharmony_ci * and devices preserving the state for resume. On some platforms the devfreq
122862306a36Sopenharmony_ci * device must have precise state (frequency) after resume in order to provide
122962306a36Sopenharmony_ci * fully operating setup.
123062306a36Sopenharmony_ci */
123162306a36Sopenharmony_civoid devfreq_suspend(void)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct devfreq *devfreq;
123462306a36Sopenharmony_ci	int ret;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
123762306a36Sopenharmony_ci	list_for_each_entry(devfreq, &devfreq_list, node) {
123862306a36Sopenharmony_ci		ret = devfreq_suspend_device(devfreq);
123962306a36Sopenharmony_ci		if (ret)
124062306a36Sopenharmony_ci			dev_err(&devfreq->dev,
124162306a36Sopenharmony_ci				"failed to suspend devfreq device\n");
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci/**
124762306a36Sopenharmony_ci * devfreq_resume() - Resume devfreq governors and devices
124862306a36Sopenharmony_ci *
124962306a36Sopenharmony_ci * Called during system wide Suspend/Hibernate cycle for resuming governors and
125062306a36Sopenharmony_ci * devices that are suspended with devfreq_suspend().
125162306a36Sopenharmony_ci */
125262306a36Sopenharmony_civoid devfreq_resume(void)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct devfreq *devfreq;
125562306a36Sopenharmony_ci	int ret;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
125862306a36Sopenharmony_ci	list_for_each_entry(devfreq, &devfreq_list, node) {
125962306a36Sopenharmony_ci		ret = devfreq_resume_device(devfreq);
126062306a36Sopenharmony_ci		if (ret)
126162306a36Sopenharmony_ci			dev_warn(&devfreq->dev,
126262306a36Sopenharmony_ci				 "failed to resume devfreq device\n");
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/**
126862306a36Sopenharmony_ci * devfreq_add_governor() - Add devfreq governor
126962306a36Sopenharmony_ci * @governor:	the devfreq governor to be added
127062306a36Sopenharmony_ci */
127162306a36Sopenharmony_ciint devfreq_add_governor(struct devfreq_governor *governor)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct devfreq_governor *g;
127462306a36Sopenharmony_ci	struct devfreq *devfreq;
127562306a36Sopenharmony_ci	int err = 0;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	if (!governor) {
127862306a36Sopenharmony_ci		pr_err("%s: Invalid parameters.\n", __func__);
127962306a36Sopenharmony_ci		return -EINVAL;
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
128362306a36Sopenharmony_ci	g = find_devfreq_governor(governor->name);
128462306a36Sopenharmony_ci	if (!IS_ERR(g)) {
128562306a36Sopenharmony_ci		pr_err("%s: governor %s already registered\n", __func__,
128662306a36Sopenharmony_ci		       g->name);
128762306a36Sopenharmony_ci		err = -EINVAL;
128862306a36Sopenharmony_ci		goto err_out;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	list_add(&governor->node, &devfreq_governor_list);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	list_for_each_entry(devfreq, &devfreq_list, node) {
129462306a36Sopenharmony_ci		int ret = 0;
129562306a36Sopenharmony_ci		struct device *dev = devfreq->dev.parent;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		if (!strncmp(devfreq->governor->name, governor->name,
129862306a36Sopenharmony_ci			     DEVFREQ_NAME_LEN)) {
129962306a36Sopenharmony_ci			/* The following should never occur */
130062306a36Sopenharmony_ci			if (devfreq->governor) {
130162306a36Sopenharmony_ci				dev_warn(dev,
130262306a36Sopenharmony_ci					 "%s: Governor %s already present\n",
130362306a36Sopenharmony_ci					 __func__, devfreq->governor->name);
130462306a36Sopenharmony_ci				ret = devfreq->governor->event_handler(devfreq,
130562306a36Sopenharmony_ci							DEVFREQ_GOV_STOP, NULL);
130662306a36Sopenharmony_ci				if (ret) {
130762306a36Sopenharmony_ci					dev_warn(dev,
130862306a36Sopenharmony_ci						 "%s: Governor %s stop = %d\n",
130962306a36Sopenharmony_ci						 __func__,
131062306a36Sopenharmony_ci						 devfreq->governor->name, ret);
131162306a36Sopenharmony_ci				}
131262306a36Sopenharmony_ci				/* Fall through */
131362306a36Sopenharmony_ci			}
131462306a36Sopenharmony_ci			devfreq->governor = governor;
131562306a36Sopenharmony_ci			ret = devfreq->governor->event_handler(devfreq,
131662306a36Sopenharmony_ci						DEVFREQ_GOV_START, NULL);
131762306a36Sopenharmony_ci			if (ret) {
131862306a36Sopenharmony_ci				dev_warn(dev, "%s: Governor %s start=%d\n",
131962306a36Sopenharmony_ci					 __func__, devfreq->governor->name,
132062306a36Sopenharmony_ci					 ret);
132162306a36Sopenharmony_ci			}
132262306a36Sopenharmony_ci		}
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cierr_out:
132662306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	return err;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_add_governor);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic void devm_devfreq_remove_governor(void *governor)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	WARN_ON(devfreq_remove_governor(governor));
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci/**
133862306a36Sopenharmony_ci * devm_devfreq_add_governor() - Add devfreq governor
133962306a36Sopenharmony_ci * @dev:	device which adds devfreq governor
134062306a36Sopenharmony_ci * @governor:	the devfreq governor to be added
134162306a36Sopenharmony_ci *
134262306a36Sopenharmony_ci * This is a resource-managed variant of devfreq_add_governor().
134362306a36Sopenharmony_ci */
134462306a36Sopenharmony_ciint devm_devfreq_add_governor(struct device *dev,
134562306a36Sopenharmony_ci			      struct devfreq_governor *governor)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	int err;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	err = devfreq_add_governor(governor);
135062306a36Sopenharmony_ci	if (err)
135162306a36Sopenharmony_ci		return err;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	return devm_add_action_or_reset(dev, devm_devfreq_remove_governor,
135462306a36Sopenharmony_ci					governor);
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_add_governor);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci/**
135962306a36Sopenharmony_ci * devfreq_remove_governor() - Remove devfreq feature from a device.
136062306a36Sopenharmony_ci * @governor:	the devfreq governor to be removed
136162306a36Sopenharmony_ci */
136262306a36Sopenharmony_ciint devfreq_remove_governor(struct devfreq_governor *governor)
136362306a36Sopenharmony_ci{
136462306a36Sopenharmony_ci	struct devfreq_governor *g;
136562306a36Sopenharmony_ci	struct devfreq *devfreq;
136662306a36Sopenharmony_ci	int err = 0;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (!governor) {
136962306a36Sopenharmony_ci		pr_err("%s: Invalid parameters.\n", __func__);
137062306a36Sopenharmony_ci		return -EINVAL;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
137462306a36Sopenharmony_ci	g = find_devfreq_governor(governor->name);
137562306a36Sopenharmony_ci	if (IS_ERR(g)) {
137662306a36Sopenharmony_ci		pr_err("%s: governor %s not registered\n", __func__,
137762306a36Sopenharmony_ci		       governor->name);
137862306a36Sopenharmony_ci		err = PTR_ERR(g);
137962306a36Sopenharmony_ci		goto err_out;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci	list_for_each_entry(devfreq, &devfreq_list, node) {
138262306a36Sopenharmony_ci		int ret;
138362306a36Sopenharmony_ci		struct device *dev = devfreq->dev.parent;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci		if (!strncmp(devfreq->governor->name, governor->name,
138662306a36Sopenharmony_ci			     DEVFREQ_NAME_LEN)) {
138762306a36Sopenharmony_ci			/* we should have a devfreq governor! */
138862306a36Sopenharmony_ci			if (!devfreq->governor) {
138962306a36Sopenharmony_ci				dev_warn(dev, "%s: Governor %s NOT present\n",
139062306a36Sopenharmony_ci					 __func__, governor->name);
139162306a36Sopenharmony_ci				continue;
139262306a36Sopenharmony_ci				/* Fall through */
139362306a36Sopenharmony_ci			}
139462306a36Sopenharmony_ci			ret = devfreq->governor->event_handler(devfreq,
139562306a36Sopenharmony_ci						DEVFREQ_GOV_STOP, NULL);
139662306a36Sopenharmony_ci			if (ret) {
139762306a36Sopenharmony_ci				dev_warn(dev, "%s: Governor %s stop=%d\n",
139862306a36Sopenharmony_ci					 __func__, devfreq->governor->name,
139962306a36Sopenharmony_ci					 ret);
140062306a36Sopenharmony_ci			}
140162306a36Sopenharmony_ci			devfreq->governor = NULL;
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	list_del(&governor->node);
140662306a36Sopenharmony_cierr_out:
140762306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	return err;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_remove_governor);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev,
141462306a36Sopenharmony_ci			struct device_attribute *attr, char *buf)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
141762306a36Sopenharmony_ci	return sprintf(buf, "%s\n", dev_name(df->dev.parent));
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic ssize_t governor_show(struct device *dev,
142262306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (!df->governor)
142762306a36Sopenharmony_ci		return -EINVAL;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	return sprintf(buf, "%s\n", df->governor->name);
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_cistatic ssize_t governor_store(struct device *dev, struct device_attribute *attr,
143362306a36Sopenharmony_ci			      const char *buf, size_t count)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
143662306a36Sopenharmony_ci	int ret;
143762306a36Sopenharmony_ci	char str_governor[DEVFREQ_NAME_LEN + 1];
143862306a36Sopenharmony_ci	const struct devfreq_governor *governor, *prev_governor;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (!df->governor)
144162306a36Sopenharmony_ci		return -EINVAL;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
144462306a36Sopenharmony_ci	if (ret != 1)
144562306a36Sopenharmony_ci		return -EINVAL;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
144862306a36Sopenharmony_ci	governor = try_then_request_governor(str_governor);
144962306a36Sopenharmony_ci	if (IS_ERR(governor)) {
145062306a36Sopenharmony_ci		ret = PTR_ERR(governor);
145162306a36Sopenharmony_ci		goto out;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci	if (df->governor == governor) {
145462306a36Sopenharmony_ci		ret = 0;
145562306a36Sopenharmony_ci		goto out;
145662306a36Sopenharmony_ci	} else if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE)
145762306a36Sopenharmony_ci		|| IS_SUPPORTED_FLAG(governor->flags, IMMUTABLE)) {
145862306a36Sopenharmony_ci		ret = -EINVAL;
145962306a36Sopenharmony_ci		goto out;
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	/*
146362306a36Sopenharmony_ci	 * Stop the current governor and remove the specific sysfs files
146462306a36Sopenharmony_ci	 * which depend on current governor.
146562306a36Sopenharmony_ci	 */
146662306a36Sopenharmony_ci	ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
146762306a36Sopenharmony_ci	if (ret) {
146862306a36Sopenharmony_ci		dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
146962306a36Sopenharmony_ci			 __func__, df->governor->name, ret);
147062306a36Sopenharmony_ci		goto out;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci	remove_sysfs_files(df, df->governor);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/*
147562306a36Sopenharmony_ci	 * Start the new governor and create the specific sysfs files
147662306a36Sopenharmony_ci	 * which depend on the new governor.
147762306a36Sopenharmony_ci	 */
147862306a36Sopenharmony_ci	prev_governor = df->governor;
147962306a36Sopenharmony_ci	df->governor = governor;
148062306a36Sopenharmony_ci	ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
148162306a36Sopenharmony_ci	if (ret) {
148262306a36Sopenharmony_ci		dev_warn(dev, "%s: Governor %s not started(%d)\n",
148362306a36Sopenharmony_ci			 __func__, df->governor->name, ret);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci		/* Restore previous governor */
148662306a36Sopenharmony_ci		df->governor = prev_governor;
148762306a36Sopenharmony_ci		ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
148862306a36Sopenharmony_ci		if (ret) {
148962306a36Sopenharmony_ci			dev_err(dev,
149062306a36Sopenharmony_ci				"%s: reverting to Governor %s failed (%d)\n",
149162306a36Sopenharmony_ci				__func__, prev_governor->name, ret);
149262306a36Sopenharmony_ci			df->governor = NULL;
149362306a36Sopenharmony_ci			goto out;
149462306a36Sopenharmony_ci		}
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	/*
149862306a36Sopenharmony_ci	 * Create the sysfs files for the new governor. But if failed to start
149962306a36Sopenharmony_ci	 * the new governor, restore the sysfs files of previous governor.
150062306a36Sopenharmony_ci	 */
150162306a36Sopenharmony_ci	create_sysfs_files(df, df->governor);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ciout:
150462306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	if (!ret)
150762306a36Sopenharmony_ci		ret = count;
150862306a36Sopenharmony_ci	return ret;
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(governor);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_cistatic ssize_t available_governors_show(struct device *d,
151362306a36Sopenharmony_ci					struct device_attribute *attr,
151462306a36Sopenharmony_ci					char *buf)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(d);
151762306a36Sopenharmony_ci	ssize_t count = 0;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	if (!df->governor)
152062306a36Sopenharmony_ci		return -EINVAL;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	/*
152562306a36Sopenharmony_ci	 * The devfreq with immutable governor (e.g., passive) shows
152662306a36Sopenharmony_ci	 * only own governor.
152762306a36Sopenharmony_ci	 */
152862306a36Sopenharmony_ci	if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE)) {
152962306a36Sopenharmony_ci		count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
153062306a36Sopenharmony_ci				  "%s ", df->governor->name);
153162306a36Sopenharmony_ci	/*
153262306a36Sopenharmony_ci	 * The devfreq device shows the registered governor except for
153362306a36Sopenharmony_ci	 * immutable governors such as passive governor .
153462306a36Sopenharmony_ci	 */
153562306a36Sopenharmony_ci	} else {
153662306a36Sopenharmony_ci		struct devfreq_governor *governor;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		list_for_each_entry(governor, &devfreq_governor_list, node) {
153962306a36Sopenharmony_ci			if (IS_SUPPORTED_FLAG(governor->flags, IMMUTABLE))
154062306a36Sopenharmony_ci				continue;
154162306a36Sopenharmony_ci			count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
154262306a36Sopenharmony_ci					   "%s ", governor->name);
154362306a36Sopenharmony_ci		}
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* Truncate the trailing space */
154962306a36Sopenharmony_ci	if (count)
155062306a36Sopenharmony_ci		count--;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	count += sprintf(&buf[count], "\n");
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	return count;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(available_governors);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
155962306a36Sopenharmony_ci			     char *buf)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	unsigned long freq;
156262306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (!df->profile)
156562306a36Sopenharmony_ci		return -EINVAL;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (df->profile->get_cur_freq &&
156862306a36Sopenharmony_ci		!df->profile->get_cur_freq(df->dev.parent, &freq))
156962306a36Sopenharmony_ci		return sprintf(buf, "%lu\n", freq);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", df->previous_freq);
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cur_freq);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic ssize_t target_freq_show(struct device *dev,
157662306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", df->previous_freq);
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(target_freq);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
158562306a36Sopenharmony_ci			      const char *buf, size_t count)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
158862306a36Sopenharmony_ci	unsigned long value;
158962306a36Sopenharmony_ci	int ret;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/*
159262306a36Sopenharmony_ci	 * Protect against theoretical sysfs writes between
159362306a36Sopenharmony_ci	 * device_add and dev_pm_qos_add_request
159462306a36Sopenharmony_ci	 */
159562306a36Sopenharmony_ci	if (!dev_pm_qos_request_active(&df->user_min_freq_req))
159662306a36Sopenharmony_ci		return -EAGAIN;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	ret = sscanf(buf, "%lu", &value);
159962306a36Sopenharmony_ci	if (ret != 1)
160062306a36Sopenharmony_ci		return -EINVAL;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	/* Round down to kHz for PM QoS */
160362306a36Sopenharmony_ci	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
160462306a36Sopenharmony_ci					value / HZ_PER_KHZ);
160562306a36Sopenharmony_ci	if (ret < 0)
160662306a36Sopenharmony_ci		return ret;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	return count;
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
161262306a36Sopenharmony_ci			     char *buf)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
161562306a36Sopenharmony_ci	unsigned long min_freq, max_freq;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	mutex_lock(&df->lock);
161862306a36Sopenharmony_ci	devfreq_get_freq_range(df, &min_freq, &max_freq);
161962306a36Sopenharmony_ci	mutex_unlock(&df->lock);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", min_freq);
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(min_freq);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_cistatic ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
162662306a36Sopenharmony_ci			      const char *buf, size_t count)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
162962306a36Sopenharmony_ci	unsigned long value;
163062306a36Sopenharmony_ci	int ret;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/*
163362306a36Sopenharmony_ci	 * Protect against theoretical sysfs writes between
163462306a36Sopenharmony_ci	 * device_add and dev_pm_qos_add_request
163562306a36Sopenharmony_ci	 */
163662306a36Sopenharmony_ci	if (!dev_pm_qos_request_active(&df->user_max_freq_req))
163762306a36Sopenharmony_ci		return -EINVAL;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	ret = sscanf(buf, "%lu", &value);
164062306a36Sopenharmony_ci	if (ret != 1)
164162306a36Sopenharmony_ci		return -EINVAL;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/*
164462306a36Sopenharmony_ci	 * PM QoS frequencies are in kHz so we need to convert. Convert by
164562306a36Sopenharmony_ci	 * rounding upwards so that the acceptable interval never shrinks.
164662306a36Sopenharmony_ci	 *
164762306a36Sopenharmony_ci	 * For example if the user writes "666666666" to sysfs this value will
164862306a36Sopenharmony_ci	 * be converted to 666667 kHz and back to 666667000 Hz before an OPP
164962306a36Sopenharmony_ci	 * lookup, this ensures that an OPP of 666666666Hz is still accepted.
165062306a36Sopenharmony_ci	 *
165162306a36Sopenharmony_ci	 * A value of zero means "no limit".
165262306a36Sopenharmony_ci	 */
165362306a36Sopenharmony_ci	if (value)
165462306a36Sopenharmony_ci		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
165562306a36Sopenharmony_ci	else
165662306a36Sopenharmony_ci		value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
165962306a36Sopenharmony_ci	if (ret < 0)
166062306a36Sopenharmony_ci		return ret;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	return count;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
166662306a36Sopenharmony_ci			     char *buf)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
166962306a36Sopenharmony_ci	unsigned long min_freq, max_freq;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	mutex_lock(&df->lock);
167262306a36Sopenharmony_ci	devfreq_get_freq_range(df, &min_freq, &max_freq);
167362306a36Sopenharmony_ci	mutex_unlock(&df->lock);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", max_freq);
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(max_freq);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic ssize_t available_frequencies_show(struct device *d,
168062306a36Sopenharmony_ci					  struct device_attribute *attr,
168162306a36Sopenharmony_ci					  char *buf)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(d);
168462306a36Sopenharmony_ci	ssize_t count = 0;
168562306a36Sopenharmony_ci	int i;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	if (!df->profile)
168862306a36Sopenharmony_ci		return -EINVAL;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	mutex_lock(&df->lock);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	for (i = 0; i < df->max_state; i++)
169362306a36Sopenharmony_ci		count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
169462306a36Sopenharmony_ci				"%lu ", df->freq_table[i]);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	mutex_unlock(&df->lock);
169762306a36Sopenharmony_ci	/* Truncate the trailing space */
169862306a36Sopenharmony_ci	if (count)
169962306a36Sopenharmony_ci		count--;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	count += sprintf(&buf[count], "\n");
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	return count;
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(available_frequencies);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic ssize_t trans_stat_show(struct device *dev,
170862306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
171162306a36Sopenharmony_ci	ssize_t len = 0;
171262306a36Sopenharmony_ci	int i, j;
171362306a36Sopenharmony_ci	unsigned int max_state;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (!df->profile)
171662306a36Sopenharmony_ci		return -EINVAL;
171762306a36Sopenharmony_ci	max_state = df->max_state;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (max_state == 0)
172062306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "Not Supported.\n");
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	mutex_lock(&df->lock);
172362306a36Sopenharmony_ci	if (!df->stop_polling &&
172462306a36Sopenharmony_ci			devfreq_update_status(df, df->previous_freq)) {
172562306a36Sopenharmony_ci		mutex_unlock(&df->lock);
172662306a36Sopenharmony_ci		return 0;
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci	mutex_unlock(&df->lock);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE - len, "     From  :   To\n");
173162306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE - len, "           :");
173262306a36Sopenharmony_ci	for (i = 0; i < max_state; i++) {
173362306a36Sopenharmony_ci		if (len >= PAGE_SIZE - 1)
173462306a36Sopenharmony_ci			break;
173562306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu",
173662306a36Sopenharmony_ci				 df->freq_table[i]);
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci	if (len >= PAGE_SIZE - 1)
173962306a36Sopenharmony_ci		return PAGE_SIZE - 1;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE - len, "   time(ms)\n");
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	for (i = 0; i < max_state; i++) {
174462306a36Sopenharmony_ci		if (len >= PAGE_SIZE - 1)
174562306a36Sopenharmony_ci			break;
174662306a36Sopenharmony_ci		if (df->freq_table[i] == df->previous_freq)
174762306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE - len, "*");
174862306a36Sopenharmony_ci		else
174962306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE - len, " ");
175062306a36Sopenharmony_ci		if (len >= PAGE_SIZE - 1)
175162306a36Sopenharmony_ci			break;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu:",
175462306a36Sopenharmony_ci				 df->freq_table[i]);
175562306a36Sopenharmony_ci		for (j = 0; j < max_state; j++) {
175662306a36Sopenharmony_ci			if (len >= PAGE_SIZE - 1)
175762306a36Sopenharmony_ci				break;
175862306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE - len, "%10u",
175962306a36Sopenharmony_ci					 df->stats.trans_table[(i * max_state) + j]);
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci		if (len >= PAGE_SIZE - 1)
176262306a36Sopenharmony_ci			break;
176362306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE - len, "%10llu\n", (u64)
176462306a36Sopenharmony_ci				 jiffies64_to_msecs(df->stats.time_in_state[i]));
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (len < PAGE_SIZE - 1)
176862306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n",
176962306a36Sopenharmony_ci				 df->stats.total_trans);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (len >= PAGE_SIZE - 1) {
177262306a36Sopenharmony_ci		pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
177362306a36Sopenharmony_ci		return -EFBIG;
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	return len;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic ssize_t trans_stat_store(struct device *dev,
178062306a36Sopenharmony_ci				struct device_attribute *attr,
178162306a36Sopenharmony_ci				const char *buf, size_t count)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
178462306a36Sopenharmony_ci	int err, value;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (!df->profile)
178762306a36Sopenharmony_ci		return -EINVAL;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	if (df->max_state == 0)
179062306a36Sopenharmony_ci		return count;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	err = kstrtoint(buf, 10, &value);
179362306a36Sopenharmony_ci	if (err || value != 0)
179462306a36Sopenharmony_ci		return -EINVAL;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	mutex_lock(&df->lock);
179762306a36Sopenharmony_ci	memset(df->stats.time_in_state, 0, (df->max_state *
179862306a36Sopenharmony_ci					sizeof(*df->stats.time_in_state)));
179962306a36Sopenharmony_ci	memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
180062306a36Sopenharmony_ci					df->max_state,
180162306a36Sopenharmony_ci					df->max_state));
180262306a36Sopenharmony_ci	df->stats.total_trans = 0;
180362306a36Sopenharmony_ci	df->stats.last_update = get_jiffies_64();
180462306a36Sopenharmony_ci	mutex_unlock(&df->lock);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	return count;
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(trans_stat);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic struct attribute *devfreq_attrs[] = {
181162306a36Sopenharmony_ci	&dev_attr_name.attr,
181262306a36Sopenharmony_ci	&dev_attr_governor.attr,
181362306a36Sopenharmony_ci	&dev_attr_available_governors.attr,
181462306a36Sopenharmony_ci	&dev_attr_cur_freq.attr,
181562306a36Sopenharmony_ci	&dev_attr_available_frequencies.attr,
181662306a36Sopenharmony_ci	&dev_attr_target_freq.attr,
181762306a36Sopenharmony_ci	&dev_attr_min_freq.attr,
181862306a36Sopenharmony_ci	&dev_attr_max_freq.attr,
181962306a36Sopenharmony_ci	&dev_attr_trans_stat.attr,
182062306a36Sopenharmony_ci	NULL,
182162306a36Sopenharmony_ci};
182262306a36Sopenharmony_ciATTRIBUTE_GROUPS(devfreq);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cistatic ssize_t polling_interval_show(struct device *dev,
182562306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (!df->profile)
183062306a36Sopenharmony_ci		return -EINVAL;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	return sprintf(buf, "%d\n", df->profile->polling_ms);
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic ssize_t polling_interval_store(struct device *dev,
183662306a36Sopenharmony_ci				      struct device_attribute *attr,
183762306a36Sopenharmony_ci				      const char *buf, size_t count)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
184062306a36Sopenharmony_ci	unsigned int value;
184162306a36Sopenharmony_ci	int ret;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	if (!df->governor)
184462306a36Sopenharmony_ci		return -EINVAL;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	ret = sscanf(buf, "%u", &value);
184762306a36Sopenharmony_ci	if (ret != 1)
184862306a36Sopenharmony_ci		return -EINVAL;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	df->governor->event_handler(df, DEVFREQ_GOV_UPDATE_INTERVAL, &value);
185162306a36Sopenharmony_ci	ret = count;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return ret;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(polling_interval);
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_cistatic ssize_t timer_show(struct device *dev,
185862306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
185962306a36Sopenharmony_ci{
186062306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (!df->profile)
186362306a36Sopenharmony_ci		return -EINVAL;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	return sprintf(buf, "%s\n", timer_name[df->profile->timer]);
186662306a36Sopenharmony_ci}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_cistatic ssize_t timer_store(struct device *dev, struct device_attribute *attr,
186962306a36Sopenharmony_ci			      const char *buf, size_t count)
187062306a36Sopenharmony_ci{
187162306a36Sopenharmony_ci	struct devfreq *df = to_devfreq(dev);
187262306a36Sopenharmony_ci	char str_timer[DEVFREQ_NAME_LEN + 1];
187362306a36Sopenharmony_ci	int timer = -1;
187462306a36Sopenharmony_ci	int ret = 0, i;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (!df->governor || !df->profile)
187762306a36Sopenharmony_ci		return -EINVAL;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	ret = sscanf(buf, "%16s", str_timer);
188062306a36Sopenharmony_ci	if (ret != 1)
188162306a36Sopenharmony_ci		return -EINVAL;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	for (i = 0; i < DEVFREQ_TIMER_NUM; i++) {
188462306a36Sopenharmony_ci		if (!strncmp(timer_name[i], str_timer, DEVFREQ_NAME_LEN)) {
188562306a36Sopenharmony_ci			timer = i;
188662306a36Sopenharmony_ci			break;
188762306a36Sopenharmony_ci		}
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (timer < 0) {
189162306a36Sopenharmony_ci		ret = -EINVAL;
189262306a36Sopenharmony_ci		goto out;
189362306a36Sopenharmony_ci	}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	if (df->profile->timer == timer) {
189662306a36Sopenharmony_ci		ret = 0;
189762306a36Sopenharmony_ci		goto out;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	mutex_lock(&df->lock);
190162306a36Sopenharmony_ci	df->profile->timer = timer;
190262306a36Sopenharmony_ci	mutex_unlock(&df->lock);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
190562306a36Sopenharmony_ci	if (ret) {
190662306a36Sopenharmony_ci		dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
190762306a36Sopenharmony_ci			 __func__, df->governor->name, ret);
190862306a36Sopenharmony_ci		goto out;
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
191262306a36Sopenharmony_ci	if (ret)
191362306a36Sopenharmony_ci		dev_warn(dev, "%s: Governor %s not started(%d)\n",
191462306a36Sopenharmony_ci			 __func__, df->governor->name, ret);
191562306a36Sopenharmony_ciout:
191662306a36Sopenharmony_ci	return ret ? ret : count;
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(timer);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci#define CREATE_SYSFS_FILE(df, name)					\
192162306a36Sopenharmony_ci{									\
192262306a36Sopenharmony_ci	int ret;							\
192362306a36Sopenharmony_ci	ret = sysfs_create_file(&df->dev.kobj, &dev_attr_##name.attr);	\
192462306a36Sopenharmony_ci	if (ret < 0) {							\
192562306a36Sopenharmony_ci		dev_warn(&df->dev,					\
192662306a36Sopenharmony_ci			"Unable to create attr(%s)\n", "##name");	\
192762306a36Sopenharmony_ci	}								\
192862306a36Sopenharmony_ci}									\
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci/* Create the specific sysfs files which depend on each governor. */
193162306a36Sopenharmony_cistatic void create_sysfs_files(struct devfreq *devfreq,
193262306a36Sopenharmony_ci				const struct devfreq_governor *gov)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	if (IS_SUPPORTED_ATTR(gov->attrs, POLLING_INTERVAL))
193562306a36Sopenharmony_ci		CREATE_SYSFS_FILE(devfreq, polling_interval);
193662306a36Sopenharmony_ci	if (IS_SUPPORTED_ATTR(gov->attrs, TIMER))
193762306a36Sopenharmony_ci		CREATE_SYSFS_FILE(devfreq, timer);
193862306a36Sopenharmony_ci}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci/* Remove the specific sysfs files which depend on each governor. */
194162306a36Sopenharmony_cistatic void remove_sysfs_files(struct devfreq *devfreq,
194262306a36Sopenharmony_ci				const struct devfreq_governor *gov)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	if (IS_SUPPORTED_ATTR(gov->attrs, POLLING_INTERVAL))
194562306a36Sopenharmony_ci		sysfs_remove_file(&devfreq->dev.kobj,
194662306a36Sopenharmony_ci				&dev_attr_polling_interval.attr);
194762306a36Sopenharmony_ci	if (IS_SUPPORTED_ATTR(gov->attrs, TIMER))
194862306a36Sopenharmony_ci		sysfs_remove_file(&devfreq->dev.kobj, &dev_attr_timer.attr);
194962306a36Sopenharmony_ci}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci/**
195262306a36Sopenharmony_ci * devfreq_summary_show() - Show the summary of the devfreq devices
195362306a36Sopenharmony_ci * @s:		seq_file instance to show the summary of devfreq devices
195462306a36Sopenharmony_ci * @data:	not used
195562306a36Sopenharmony_ci *
195662306a36Sopenharmony_ci * Show the summary of the devfreq devices via 'devfreq_summary' debugfs file.
195762306a36Sopenharmony_ci * It helps that user can know the detailed information of the devfreq devices.
195862306a36Sopenharmony_ci *
195962306a36Sopenharmony_ci * Return 0 always because it shows the information without any data change.
196062306a36Sopenharmony_ci */
196162306a36Sopenharmony_cistatic int devfreq_summary_show(struct seq_file *s, void *data)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct devfreq *devfreq;
196462306a36Sopenharmony_ci	struct devfreq *p_devfreq = NULL;
196562306a36Sopenharmony_ci	unsigned long cur_freq, min_freq, max_freq;
196662306a36Sopenharmony_ci	unsigned int polling_ms;
196762306a36Sopenharmony_ci	unsigned int timer;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	seq_printf(s, "%-30s %-30s %-15s %-10s %10s %12s %12s %12s\n",
197062306a36Sopenharmony_ci			"dev",
197162306a36Sopenharmony_ci			"parent_dev",
197262306a36Sopenharmony_ci			"governor",
197362306a36Sopenharmony_ci			"timer",
197462306a36Sopenharmony_ci			"polling_ms",
197562306a36Sopenharmony_ci			"cur_freq_Hz",
197662306a36Sopenharmony_ci			"min_freq_Hz",
197762306a36Sopenharmony_ci			"max_freq_Hz");
197862306a36Sopenharmony_ci	seq_printf(s, "%30s %30s %15s %10s %10s %12s %12s %12s\n",
197962306a36Sopenharmony_ci			"------------------------------",
198062306a36Sopenharmony_ci			"------------------------------",
198162306a36Sopenharmony_ci			"---------------",
198262306a36Sopenharmony_ci			"----------",
198362306a36Sopenharmony_ci			"----------",
198462306a36Sopenharmony_ci			"------------",
198562306a36Sopenharmony_ci			"------------",
198662306a36Sopenharmony_ci			"------------");
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	mutex_lock(&devfreq_list_lock);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	list_for_each_entry_reverse(devfreq, &devfreq_list, node) {
199162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
199262306a36Sopenharmony_ci		if (!strncmp(devfreq->governor->name, DEVFREQ_GOV_PASSIVE,
199362306a36Sopenharmony_ci							DEVFREQ_NAME_LEN)) {
199462306a36Sopenharmony_ci			struct devfreq_passive_data *data = devfreq->data;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci			if (data)
199762306a36Sopenharmony_ci				p_devfreq = data->parent;
199862306a36Sopenharmony_ci		} else {
199962306a36Sopenharmony_ci			p_devfreq = NULL;
200062306a36Sopenharmony_ci		}
200162306a36Sopenharmony_ci#endif
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci		mutex_lock(&devfreq->lock);
200462306a36Sopenharmony_ci		cur_freq = devfreq->previous_freq;
200562306a36Sopenharmony_ci		devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
200662306a36Sopenharmony_ci		timer = devfreq->profile->timer;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci		if (IS_SUPPORTED_ATTR(devfreq->governor->attrs, POLLING_INTERVAL))
200962306a36Sopenharmony_ci			polling_ms = devfreq->profile->polling_ms;
201062306a36Sopenharmony_ci		else
201162306a36Sopenharmony_ci			polling_ms = 0;
201262306a36Sopenharmony_ci		mutex_unlock(&devfreq->lock);
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		seq_printf(s,
201562306a36Sopenharmony_ci			"%-30s %-30s %-15s %-10s %10d %12ld %12ld %12ld\n",
201662306a36Sopenharmony_ci			dev_name(&devfreq->dev),
201762306a36Sopenharmony_ci			p_devfreq ? dev_name(&p_devfreq->dev) : "null",
201862306a36Sopenharmony_ci			devfreq->governor->name,
201962306a36Sopenharmony_ci			polling_ms ? timer_name[timer] : "null",
202062306a36Sopenharmony_ci			polling_ms,
202162306a36Sopenharmony_ci			cur_freq,
202262306a36Sopenharmony_ci			min_freq,
202362306a36Sopenharmony_ci			max_freq);
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	mutex_unlock(&devfreq_list_lock);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	return 0;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(devfreq_summary);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_cistatic int __init devfreq_init(void)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	devfreq_class = class_create("devfreq");
203562306a36Sopenharmony_ci	if (IS_ERR(devfreq_class)) {
203662306a36Sopenharmony_ci		pr_err("%s: couldn't create class\n", __FILE__);
203762306a36Sopenharmony_ci		return PTR_ERR(devfreq_class);
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	devfreq_wq = create_freezable_workqueue("devfreq_wq");
204162306a36Sopenharmony_ci	if (!devfreq_wq) {
204262306a36Sopenharmony_ci		class_destroy(devfreq_class);
204362306a36Sopenharmony_ci		pr_err("%s: couldn't create workqueue\n", __FILE__);
204462306a36Sopenharmony_ci		return -ENOMEM;
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci	devfreq_class->dev_groups = devfreq_groups;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	devfreq_debugfs = debugfs_create_dir("devfreq", NULL);
204962306a36Sopenharmony_ci	debugfs_create_file("devfreq_summary", 0444,
205062306a36Sopenharmony_ci				devfreq_debugfs, NULL,
205162306a36Sopenharmony_ci				&devfreq_summary_fops);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	return 0;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_cisubsys_initcall(devfreq_init);
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci/*
205862306a36Sopenharmony_ci * The following are helper functions for devfreq user device drivers with
205962306a36Sopenharmony_ci * OPP framework.
206062306a36Sopenharmony_ci */
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci/**
206362306a36Sopenharmony_ci * devfreq_recommended_opp() - Helper function to get proper OPP for the
206462306a36Sopenharmony_ci *			     freq value given to target callback.
206562306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
206662306a36Sopenharmony_ci * @freq:	The frequency given to target function
206762306a36Sopenharmony_ci * @flags:	Flags handed from devfreq framework.
206862306a36Sopenharmony_ci *
206962306a36Sopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
207062306a36Sopenharmony_ci * use.
207162306a36Sopenharmony_ci */
207262306a36Sopenharmony_cistruct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
207362306a36Sopenharmony_ci					   unsigned long *freq,
207462306a36Sopenharmony_ci					   u32 flags)
207562306a36Sopenharmony_ci{
207662306a36Sopenharmony_ci	struct dev_pm_opp *opp;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
207962306a36Sopenharmony_ci		/* The freq is an upper bound. opp should be lower */
208062306a36Sopenharmony_ci		opp = dev_pm_opp_find_freq_floor(dev, freq);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci		/* If not available, use the closest opp */
208362306a36Sopenharmony_ci		if (opp == ERR_PTR(-ERANGE))
208462306a36Sopenharmony_ci			opp = dev_pm_opp_find_freq_ceil(dev, freq);
208562306a36Sopenharmony_ci	} else {
208662306a36Sopenharmony_ci		/* The freq is an lower bound. opp should be higher */
208762306a36Sopenharmony_ci		opp = dev_pm_opp_find_freq_ceil(dev, freq);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci		/* If not available, use the closest opp */
209062306a36Sopenharmony_ci		if (opp == ERR_PTR(-ERANGE))
209162306a36Sopenharmony_ci			opp = dev_pm_opp_find_freq_floor(dev, freq);
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	return opp;
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_recommended_opp);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci/**
209962306a36Sopenharmony_ci * devfreq_register_opp_notifier() - Helper function to get devfreq notified
210062306a36Sopenharmony_ci *				     for any changes in the OPP availability
210162306a36Sopenharmony_ci *				     changes
210262306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
210362306a36Sopenharmony_ci * @devfreq:	The devfreq object.
210462306a36Sopenharmony_ci */
210562306a36Sopenharmony_ciint devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	return dev_pm_opp_register_notifier(dev, &devfreq->nb);
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_register_opp_notifier);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci/**
211262306a36Sopenharmony_ci * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
211362306a36Sopenharmony_ci *				       notified for any changes in the OPP
211462306a36Sopenharmony_ci *				       availability changes anymore.
211562306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
211662306a36Sopenharmony_ci * @devfreq:	The devfreq object.
211762306a36Sopenharmony_ci *
211862306a36Sopenharmony_ci * At exit() callback of devfreq_dev_profile, this must be included if
211962306a36Sopenharmony_ci * devfreq_recommended_opp is used.
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_ciint devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	return dev_pm_opp_unregister_notifier(dev, &devfreq->nb);
212462306a36Sopenharmony_ci}
212562306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_unregister_opp_notifier);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cistatic void devm_devfreq_opp_release(struct device *dev, void *res)
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	devfreq_unregister_opp_notifier(dev, *(struct devfreq **)res);
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci/**
213362306a36Sopenharmony_ci * devm_devfreq_register_opp_notifier() - Resource-managed
213462306a36Sopenharmony_ci *					  devfreq_register_opp_notifier()
213562306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
213662306a36Sopenharmony_ci * @devfreq:	The devfreq object.
213762306a36Sopenharmony_ci */
213862306a36Sopenharmony_ciint devm_devfreq_register_opp_notifier(struct device *dev,
213962306a36Sopenharmony_ci				       struct devfreq *devfreq)
214062306a36Sopenharmony_ci{
214162306a36Sopenharmony_ci	struct devfreq **ptr;
214262306a36Sopenharmony_ci	int ret;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	ptr = devres_alloc(devm_devfreq_opp_release, sizeof(*ptr), GFP_KERNEL);
214562306a36Sopenharmony_ci	if (!ptr)
214662306a36Sopenharmony_ci		return -ENOMEM;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	ret = devfreq_register_opp_notifier(dev, devfreq);
214962306a36Sopenharmony_ci	if (ret) {
215062306a36Sopenharmony_ci		devres_free(ptr);
215162306a36Sopenharmony_ci		return ret;
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	*ptr = devfreq;
215562306a36Sopenharmony_ci	devres_add(dev, ptr);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	return 0;
215862306a36Sopenharmony_ci}
215962306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_register_opp_notifier);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci/**
216262306a36Sopenharmony_ci * devm_devfreq_unregister_opp_notifier() - Resource-managed
216362306a36Sopenharmony_ci *					    devfreq_unregister_opp_notifier()
216462306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
216562306a36Sopenharmony_ci * @devfreq:	The devfreq object.
216662306a36Sopenharmony_ci */
216762306a36Sopenharmony_civoid devm_devfreq_unregister_opp_notifier(struct device *dev,
216862306a36Sopenharmony_ci					 struct devfreq *devfreq)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	WARN_ON(devres_release(dev, devm_devfreq_opp_release,
217162306a36Sopenharmony_ci			       devm_devfreq_dev_match, devfreq));
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci/**
217662306a36Sopenharmony_ci * devfreq_register_notifier() - Register a driver with devfreq
217762306a36Sopenharmony_ci * @devfreq:	The devfreq object.
217862306a36Sopenharmony_ci * @nb:		The notifier block to register.
217962306a36Sopenharmony_ci * @list:	DEVFREQ_TRANSITION_NOTIFIER.
218062306a36Sopenharmony_ci */
218162306a36Sopenharmony_ciint devfreq_register_notifier(struct devfreq *devfreq,
218262306a36Sopenharmony_ci			      struct notifier_block *nb,
218362306a36Sopenharmony_ci			      unsigned int list)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	int ret = 0;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	if (!devfreq)
218862306a36Sopenharmony_ci		return -EINVAL;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	switch (list) {
219162306a36Sopenharmony_ci	case DEVFREQ_TRANSITION_NOTIFIER:
219262306a36Sopenharmony_ci		ret = srcu_notifier_chain_register(
219362306a36Sopenharmony_ci				&devfreq->transition_notifier_list, nb);
219462306a36Sopenharmony_ci		break;
219562306a36Sopenharmony_ci	default:
219662306a36Sopenharmony_ci		ret = -EINVAL;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return ret;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_register_notifier);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci/*
220462306a36Sopenharmony_ci * devfreq_unregister_notifier() - Unregister a driver with devfreq
220562306a36Sopenharmony_ci * @devfreq:	The devfreq object.
220662306a36Sopenharmony_ci * @nb:		The notifier block to be unregistered.
220762306a36Sopenharmony_ci * @list:	DEVFREQ_TRANSITION_NOTIFIER.
220862306a36Sopenharmony_ci */
220962306a36Sopenharmony_ciint devfreq_unregister_notifier(struct devfreq *devfreq,
221062306a36Sopenharmony_ci				struct notifier_block *nb,
221162306a36Sopenharmony_ci				unsigned int list)
221262306a36Sopenharmony_ci{
221362306a36Sopenharmony_ci	int ret = 0;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	if (!devfreq)
221662306a36Sopenharmony_ci		return -EINVAL;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	switch (list) {
221962306a36Sopenharmony_ci	case DEVFREQ_TRANSITION_NOTIFIER:
222062306a36Sopenharmony_ci		ret = srcu_notifier_chain_unregister(
222162306a36Sopenharmony_ci				&devfreq->transition_notifier_list, nb);
222262306a36Sopenharmony_ci		break;
222362306a36Sopenharmony_ci	default:
222462306a36Sopenharmony_ci		ret = -EINVAL;
222562306a36Sopenharmony_ci	}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	return ret;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ciEXPORT_SYMBOL(devfreq_unregister_notifier);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_cistruct devfreq_notifier_devres {
223262306a36Sopenharmony_ci	struct devfreq *devfreq;
223362306a36Sopenharmony_ci	struct notifier_block *nb;
223462306a36Sopenharmony_ci	unsigned int list;
223562306a36Sopenharmony_ci};
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_cistatic void devm_devfreq_notifier_release(struct device *dev, void *res)
223862306a36Sopenharmony_ci{
223962306a36Sopenharmony_ci	struct devfreq_notifier_devres *this = res;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	devfreq_unregister_notifier(this->devfreq, this->nb, this->list);
224262306a36Sopenharmony_ci}
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci/**
224562306a36Sopenharmony_ci * devm_devfreq_register_notifier()
224662306a36Sopenharmony_ci *	- Resource-managed devfreq_register_notifier()
224762306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
224862306a36Sopenharmony_ci * @devfreq:	The devfreq object.
224962306a36Sopenharmony_ci * @nb:		The notifier block to be unregistered.
225062306a36Sopenharmony_ci * @list:	DEVFREQ_TRANSITION_NOTIFIER.
225162306a36Sopenharmony_ci */
225262306a36Sopenharmony_ciint devm_devfreq_register_notifier(struct device *dev,
225362306a36Sopenharmony_ci				struct devfreq *devfreq,
225462306a36Sopenharmony_ci				struct notifier_block *nb,
225562306a36Sopenharmony_ci				unsigned int list)
225662306a36Sopenharmony_ci{
225762306a36Sopenharmony_ci	struct devfreq_notifier_devres *ptr;
225862306a36Sopenharmony_ci	int ret;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	ptr = devres_alloc(devm_devfreq_notifier_release, sizeof(*ptr),
226162306a36Sopenharmony_ci				GFP_KERNEL);
226262306a36Sopenharmony_ci	if (!ptr)
226362306a36Sopenharmony_ci		return -ENOMEM;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	ret = devfreq_register_notifier(devfreq, nb, list);
226662306a36Sopenharmony_ci	if (ret) {
226762306a36Sopenharmony_ci		devres_free(ptr);
226862306a36Sopenharmony_ci		return ret;
226962306a36Sopenharmony_ci	}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	ptr->devfreq = devfreq;
227262306a36Sopenharmony_ci	ptr->nb = nb;
227362306a36Sopenharmony_ci	ptr->list = list;
227462306a36Sopenharmony_ci	devres_add(dev, ptr);
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	return 0;
227762306a36Sopenharmony_ci}
227862306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_register_notifier);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci/**
228162306a36Sopenharmony_ci * devm_devfreq_unregister_notifier()
228262306a36Sopenharmony_ci *	- Resource-managed devfreq_unregister_notifier()
228362306a36Sopenharmony_ci * @dev:	The devfreq user device. (parent of devfreq)
228462306a36Sopenharmony_ci * @devfreq:	The devfreq object.
228562306a36Sopenharmony_ci * @nb:		The notifier block to be unregistered.
228662306a36Sopenharmony_ci * @list:	DEVFREQ_TRANSITION_NOTIFIER.
228762306a36Sopenharmony_ci */
228862306a36Sopenharmony_civoid devm_devfreq_unregister_notifier(struct device *dev,
228962306a36Sopenharmony_ci				      struct devfreq *devfreq,
229062306a36Sopenharmony_ci				      struct notifier_block *nb,
229162306a36Sopenharmony_ci				      unsigned int list)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	WARN_ON(devres_release(dev, devm_devfreq_notifier_release,
229462306a36Sopenharmony_ci			       devm_devfreq_dev_match, devfreq));
229562306a36Sopenharmony_ci}
229662306a36Sopenharmony_ciEXPORT_SYMBOL(devm_devfreq_unregister_notifier);
2297