13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
43d0407baSopenharmony_ci *        for Non-CPU Devices.
53d0407baSopenharmony_ci *
63d0407baSopenharmony_ci * Copyright (C) 2011 Samsung Electronics
73d0407baSopenharmony_ci *    MyungJoo Ham <myungjoo.ham@samsung.com>
83d0407baSopenharmony_ci */
93d0407baSopenharmony_ci
103d0407baSopenharmony_ci#include <linux/kernel.h>
113d0407baSopenharmony_ci#include <linux/kmod.h>
123d0407baSopenharmony_ci#include <linux/sched.h>
133d0407baSopenharmony_ci#include <linux/debugfs.h>
143d0407baSopenharmony_ci#include <linux/errno.h>
153d0407baSopenharmony_ci#include <linux/err.h>
163d0407baSopenharmony_ci#include <linux/init.h>
173d0407baSopenharmony_ci#include <linux/export.h>
183d0407baSopenharmony_ci#include <linux/slab.h>
193d0407baSopenharmony_ci#include <linux/stat.h>
203d0407baSopenharmony_ci#include <linux/pm_opp.h>
213d0407baSopenharmony_ci#include <linux/devfreq.h>
223d0407baSopenharmony_ci#include <linux/workqueue.h>
233d0407baSopenharmony_ci#include <linux/platform_device.h>
243d0407baSopenharmony_ci#include <linux/list.h>
253d0407baSopenharmony_ci#include <linux/printk.h>
263d0407baSopenharmony_ci#include <linux/hrtimer.h>
273d0407baSopenharmony_ci#include <linux/of.h>
283d0407baSopenharmony_ci#include <linux/pm_qos.h>
293d0407baSopenharmony_ci#include "governor.h"
303d0407baSopenharmony_ci
313d0407baSopenharmony_ci#define CREATE_TRACE_POINTS
323d0407baSopenharmony_ci#include <trace/events/devfreq.h>
333d0407baSopenharmony_ci
343d0407baSopenharmony_ci#define HZ_PER_KHZ 1000
353d0407baSopenharmony_ci
363d0407baSopenharmony_cistatic struct class *devfreq_class;
373d0407baSopenharmony_cistatic struct dentry *devfreq_debugfs;
383d0407baSopenharmony_ci
393d0407baSopenharmony_ci/*
403d0407baSopenharmony_ci * devfreq core provides delayed work based load monitoring helper
413d0407baSopenharmony_ci * functions. Governors can use these or can implement their own
423d0407baSopenharmony_ci * monitoring mechanism.
433d0407baSopenharmony_ci */
443d0407baSopenharmony_cistatic struct workqueue_struct *devfreq_wq;
453d0407baSopenharmony_ci
463d0407baSopenharmony_ci/* The list of all device-devfreq governors */
473d0407baSopenharmony_cistatic LIST_HEAD(devfreq_governor_list);
483d0407baSopenharmony_ci/* The list of all device-devfreq */
493d0407baSopenharmony_cistatic LIST_HEAD(devfreq_list);
503d0407baSopenharmony_cistatic DEFINE_MUTEX(devfreq_list_lock);
513d0407baSopenharmony_ci
523d0407baSopenharmony_cistatic const char timer_name[][DEVFREQ_NAME_LEN] = {
533d0407baSopenharmony_ci    [DEVFREQ_TIMER_DEFERRABLE] = {"deferrable"},
543d0407baSopenharmony_ci    [DEVFREQ_TIMER_DELAYED] = {"delayed"},
553d0407baSopenharmony_ci};
563d0407baSopenharmony_ci
573d0407baSopenharmony_ci/**
583d0407baSopenharmony_ci * find_device_devfreq() - find devfreq struct using device pointer
593d0407baSopenharmony_ci * @dev:    device pointer used to lookup device devfreq.
603d0407baSopenharmony_ci *
613d0407baSopenharmony_ci * Search the list of device devfreqs and return the matched device's
623d0407baSopenharmony_ci * devfreq info. devfreq_list_lock should be held by the caller.
633d0407baSopenharmony_ci */
643d0407baSopenharmony_cistatic struct devfreq *find_device_devfreq(struct device *dev)
653d0407baSopenharmony_ci{
663d0407baSopenharmony_ci    struct devfreq *tmp_devfreq;
673d0407baSopenharmony_ci
683d0407baSopenharmony_ci    lockdep_assert_held(&devfreq_list_lock);
693d0407baSopenharmony_ci
703d0407baSopenharmony_ci    if (IS_ERR_OR_NULL(dev)) {
713d0407baSopenharmony_ci        pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
723d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
733d0407baSopenharmony_ci    }
743d0407baSopenharmony_ci
753d0407baSopenharmony_ci    list_for_each_entry(tmp_devfreq, &devfreq_list, node)
763d0407baSopenharmony_ci    {
773d0407baSopenharmony_ci        if (tmp_devfreq->dev.parent == dev) {
783d0407baSopenharmony_ci            return tmp_devfreq;
793d0407baSopenharmony_ci        }
803d0407baSopenharmony_ci    }
813d0407baSopenharmony_ci
823d0407baSopenharmony_ci    return ERR_PTR(-ENODEV);
833d0407baSopenharmony_ci}
843d0407baSopenharmony_ci
853d0407baSopenharmony_cistatic unsigned long find_available_min_freq(struct devfreq *devfreq)
863d0407baSopenharmony_ci{
873d0407baSopenharmony_ci    struct dev_pm_opp *opp;
883d0407baSopenharmony_ci    unsigned long min_freq = 0;
893d0407baSopenharmony_ci
903d0407baSopenharmony_ci    opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &min_freq);
913d0407baSopenharmony_ci    if (IS_ERR(opp)) {
923d0407baSopenharmony_ci        min_freq = 0;
933d0407baSopenharmony_ci    } else {
943d0407baSopenharmony_ci        dev_pm_opp_put(opp);
953d0407baSopenharmony_ci    }
963d0407baSopenharmony_ci
973d0407baSopenharmony_ci    return min_freq;
983d0407baSopenharmony_ci}
993d0407baSopenharmony_ci
1003d0407baSopenharmony_cistatic unsigned long find_available_max_freq(struct devfreq *devfreq)
1013d0407baSopenharmony_ci{
1023d0407baSopenharmony_ci    struct dev_pm_opp *opp;
1033d0407baSopenharmony_ci    unsigned long max_freq = ULONG_MAX;
1043d0407baSopenharmony_ci
1053d0407baSopenharmony_ci    opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, &max_freq);
1063d0407baSopenharmony_ci    if (IS_ERR(opp)) {
1073d0407baSopenharmony_ci        max_freq = 0;
1083d0407baSopenharmony_ci    } else {
1093d0407baSopenharmony_ci        dev_pm_opp_put(opp);
1103d0407baSopenharmony_ci    }
1113d0407baSopenharmony_ci
1123d0407baSopenharmony_ci    return max_freq;
1133d0407baSopenharmony_ci}
1143d0407baSopenharmony_ci
1153d0407baSopenharmony_ci/**
1163d0407baSopenharmony_ci * get_freq_range() - Get the current freq range
1173d0407baSopenharmony_ci * @devfreq:    the devfreq instance
1183d0407baSopenharmony_ci * @min_freq:    the min frequency
1193d0407baSopenharmony_ci * @max_freq:    the max frequency
1203d0407baSopenharmony_ci *
1213d0407baSopenharmony_ci * This takes into consideration all constraints.
1223d0407baSopenharmony_ci */
1233d0407baSopenharmony_cistatic void get_freq_range(struct devfreq *devfreq, unsigned long *min_freq, unsigned long *max_freq)
1243d0407baSopenharmony_ci{
1253d0407baSopenharmony_ci    unsigned long *freq_table = devfreq->profile->freq_table;
1263d0407baSopenharmony_ci    s32 qos_min_freq, qos_max_freq;
1273d0407baSopenharmony_ci
1283d0407baSopenharmony_ci    lockdep_assert_held(&devfreq->lock);
1293d0407baSopenharmony_ci
1303d0407baSopenharmony_ci    /*
1313d0407baSopenharmony_ci     * Initialize minimum/maximum frequency from freq table.
1323d0407baSopenharmony_ci     * The devfreq drivers can initialize this in either ascending or
1333d0407baSopenharmony_ci     * descending order and devfreq core supports both.
1343d0407baSopenharmony_ci     */
1353d0407baSopenharmony_ci    if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
1363d0407baSopenharmony_ci        *min_freq = freq_table[0];
1373d0407baSopenharmony_ci        *max_freq = freq_table[devfreq->profile->max_state - 1];
1383d0407baSopenharmony_ci    } else {
1393d0407baSopenharmony_ci        *min_freq = freq_table[devfreq->profile->max_state - 1];
1403d0407baSopenharmony_ci        *max_freq = freq_table[0];
1413d0407baSopenharmony_ci    }
1423d0407baSopenharmony_ci
1433d0407baSopenharmony_ci    /* Apply constraints from PM QoS */
1443d0407baSopenharmony_ci    qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent, DEV_PM_QOS_MIN_FREQUENCY);
1453d0407baSopenharmony_ci    qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent, DEV_PM_QOS_MAX_FREQUENCY);
1463d0407baSopenharmony_ci    *min_freq = max(*min_freq, (unsigned long)HZ_PER_KHZ * qos_min_freq);
1473d0407baSopenharmony_ci    if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE) {
1483d0407baSopenharmony_ci        *max_freq = min(*max_freq, (unsigned long)HZ_PER_KHZ * qos_max_freq);
1493d0407baSopenharmony_ci    }
1503d0407baSopenharmony_ci
1513d0407baSopenharmony_ci    /* Apply constraints from OPP interface */
1523d0407baSopenharmony_ci    *min_freq = max(*min_freq, devfreq->scaling_min_freq);
1533d0407baSopenharmony_ci    *max_freq = min(*max_freq, devfreq->scaling_max_freq);
1543d0407baSopenharmony_ci
1553d0407baSopenharmony_ci    if (*min_freq > *max_freq) {
1563d0407baSopenharmony_ci        *min_freq = *max_freq;
1573d0407baSopenharmony_ci    }
1583d0407baSopenharmony_ci}
1593d0407baSopenharmony_ci
1603d0407baSopenharmony_ci/**
1613d0407baSopenharmony_ci * devfreq_get_freq_level() - Lookup freq_table for the frequency
1623d0407baSopenharmony_ci * @devfreq:    the devfreq instance
1633d0407baSopenharmony_ci * @freq:    the target frequency
1643d0407baSopenharmony_ci */
1653d0407baSopenharmony_cistatic int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
1663d0407baSopenharmony_ci{
1673d0407baSopenharmony_ci    int lev;
1683d0407baSopenharmony_ci
1693d0407baSopenharmony_ci    for (lev = 0; lev < devfreq->profile->max_state; lev++) {
1703d0407baSopenharmony_ci        if (freq == devfreq->profile->freq_table[lev]) {
1713d0407baSopenharmony_ci            return lev;
1723d0407baSopenharmony_ci        }
1733d0407baSopenharmony_ci    }
1743d0407baSopenharmony_ci
1753d0407baSopenharmony_ci    return -EINVAL;
1763d0407baSopenharmony_ci}
1773d0407baSopenharmony_ci
1783d0407baSopenharmony_cistatic int set_freq_table(struct devfreq *devfreq)
1793d0407baSopenharmony_ci{
1803d0407baSopenharmony_ci    struct devfreq_dev_profile *profile = devfreq->profile;
1813d0407baSopenharmony_ci    struct dev_pm_opp *opp;
1823d0407baSopenharmony_ci    unsigned long freq;
1833d0407baSopenharmony_ci    int i, count;
1843d0407baSopenharmony_ci
1853d0407baSopenharmony_ci    /* Initialize the freq_table from OPP table */
1863d0407baSopenharmony_ci    count = dev_pm_opp_get_opp_count(devfreq->dev.parent);
1873d0407baSopenharmony_ci    if (count <= 0) {
1883d0407baSopenharmony_ci        return -EINVAL;
1893d0407baSopenharmony_ci    }
1903d0407baSopenharmony_ci
1913d0407baSopenharmony_ci    profile->max_state = count;
1923d0407baSopenharmony_ci    profile->freq_table =
1933d0407baSopenharmony_ci        devm_kcalloc(devfreq->dev.parent, profile->max_state, sizeof(*profile->freq_table), GFP_KERNEL);
1943d0407baSopenharmony_ci    if (!profile->freq_table) {
1953d0407baSopenharmony_ci        profile->max_state = 0;
1963d0407baSopenharmony_ci        return -ENOMEM;
1973d0407baSopenharmony_ci    }
1983d0407baSopenharmony_ci
1993d0407baSopenharmony_ci    for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
2003d0407baSopenharmony_ci        opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
2013d0407baSopenharmony_ci        if (IS_ERR(opp)) {
2023d0407baSopenharmony_ci            devm_kfree(devfreq->dev.parent, profile->freq_table);
2033d0407baSopenharmony_ci            profile->max_state = 0;
2043d0407baSopenharmony_ci            return PTR_ERR(opp);
2053d0407baSopenharmony_ci        }
2063d0407baSopenharmony_ci        dev_pm_opp_put(opp);
2073d0407baSopenharmony_ci        profile->freq_table[i] = freq;
2083d0407baSopenharmony_ci    }
2093d0407baSopenharmony_ci
2103d0407baSopenharmony_ci    return 0;
2113d0407baSopenharmony_ci}
2123d0407baSopenharmony_ci
2133d0407baSopenharmony_ci/**
2143d0407baSopenharmony_ci * devfreq_update_status() - Update statistics of devfreq behavior
2153d0407baSopenharmony_ci * @devfreq:    the devfreq instance
2163d0407baSopenharmony_ci * @freq:    the update target frequency
2173d0407baSopenharmony_ci */
2183d0407baSopenharmony_ciint devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
2193d0407baSopenharmony_ci{
2203d0407baSopenharmony_ci    int lev, prev_lev, ret = 0;
2213d0407baSopenharmony_ci    u64 cur_time;
2223d0407baSopenharmony_ci
2233d0407baSopenharmony_ci    lockdep_assert_held(&devfreq->lock);
2243d0407baSopenharmony_ci    cur_time = get_jiffies_64();
2253d0407baSopenharmony_ci
2263d0407baSopenharmony_ci    /* Immediately exit if previous_freq is not initialized yet. */
2273d0407baSopenharmony_ci    if (!devfreq->previous_freq) {
2283d0407baSopenharmony_ci        goto out;
2293d0407baSopenharmony_ci    }
2303d0407baSopenharmony_ci
2313d0407baSopenharmony_ci    prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
2323d0407baSopenharmony_ci    if (prev_lev < 0) {
2333d0407baSopenharmony_ci        ret = prev_lev;
2343d0407baSopenharmony_ci        goto out;
2353d0407baSopenharmony_ci    }
2363d0407baSopenharmony_ci
2373d0407baSopenharmony_ci    devfreq->stats.time_in_state[prev_lev] += cur_time - devfreq->stats.last_update;
2383d0407baSopenharmony_ci
2393d0407baSopenharmony_ci    lev = devfreq_get_freq_level(devfreq, freq);
2403d0407baSopenharmony_ci    if (lev < 0) {
2413d0407baSopenharmony_ci        ret = lev;
2423d0407baSopenharmony_ci        goto out;
2433d0407baSopenharmony_ci    }
2443d0407baSopenharmony_ci
2453d0407baSopenharmony_ci    if (lev != prev_lev) {
2463d0407baSopenharmony_ci        devfreq->stats.trans_table[(prev_lev * devfreq->profile->max_state) + lev]++;
2473d0407baSopenharmony_ci        devfreq->stats.total_trans++;
2483d0407baSopenharmony_ci    }
2493d0407baSopenharmony_ci
2503d0407baSopenharmony_ciout:
2513d0407baSopenharmony_ci    devfreq->stats.last_update = cur_time;
2523d0407baSopenharmony_ci    return ret;
2533d0407baSopenharmony_ci}
2543d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_update_status);
2553d0407baSopenharmony_ci
2563d0407baSopenharmony_ci/**
2573d0407baSopenharmony_ci * find_devfreq_governor() - find devfreq governor from name
2583d0407baSopenharmony_ci * @name:    name of the governor
2593d0407baSopenharmony_ci *
2603d0407baSopenharmony_ci * Search the list of devfreq governors and return the matched
2613d0407baSopenharmony_ci * governor's pointer. devfreq_list_lock should be held by the caller.
2623d0407baSopenharmony_ci */
2633d0407baSopenharmony_cistatic struct devfreq_governor *find_devfreq_governor(const char *name)
2643d0407baSopenharmony_ci{
2653d0407baSopenharmony_ci    struct devfreq_governor *tmp_governor;
2663d0407baSopenharmony_ci
2673d0407baSopenharmony_ci    lockdep_assert_held(&devfreq_list_lock);
2683d0407baSopenharmony_ci
2693d0407baSopenharmony_ci    if (IS_ERR_OR_NULL(name)) {
2703d0407baSopenharmony_ci        pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
2713d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
2723d0407baSopenharmony_ci    }
2733d0407baSopenharmony_ci
2743d0407baSopenharmony_ci    list_for_each_entry(tmp_governor, &devfreq_governor_list, node)
2753d0407baSopenharmony_ci    {
2763d0407baSopenharmony_ci        if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN)) {
2773d0407baSopenharmony_ci            return tmp_governor;
2783d0407baSopenharmony_ci        }
2793d0407baSopenharmony_ci    }
2803d0407baSopenharmony_ci
2813d0407baSopenharmony_ci    return ERR_PTR(-ENODEV);
2823d0407baSopenharmony_ci}
2833d0407baSopenharmony_ci
2843d0407baSopenharmony_ci/**
2853d0407baSopenharmony_ci * try_then_request_governor() - Try to find the governor and request the
2863d0407baSopenharmony_ci *                               module if is not found.
2873d0407baSopenharmony_ci * @name:    name of the governor
2883d0407baSopenharmony_ci *
2893d0407baSopenharmony_ci * Search the list of devfreq governors and request the module and try again
2903d0407baSopenharmony_ci * if is not found. This can happen when both drivers (the governor driver
2913d0407baSopenharmony_ci * and the driver that call devfreq_add_device) are built as modules.
2923d0407baSopenharmony_ci * devfreq_list_lock should be held by the caller. Returns the matched
2933d0407baSopenharmony_ci * governor's pointer or an error pointer.
2943d0407baSopenharmony_ci */
2953d0407baSopenharmony_cistatic struct devfreq_governor *try_then_request_governor(const char *name)
2963d0407baSopenharmony_ci{
2973d0407baSopenharmony_ci    struct devfreq_governor *governor;
2983d0407baSopenharmony_ci    int err = 0;
2993d0407baSopenharmony_ci
3003d0407baSopenharmony_ci    lockdep_assert_held(&devfreq_list_lock);
3013d0407baSopenharmony_ci
3023d0407baSopenharmony_ci    if (IS_ERR_OR_NULL(name)) {
3033d0407baSopenharmony_ci        pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
3043d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
3053d0407baSopenharmony_ci    }
3063d0407baSopenharmony_ci
3073d0407baSopenharmony_ci    governor = find_devfreq_governor(name);
3083d0407baSopenharmony_ci    if (IS_ERR(governor)) {
3093d0407baSopenharmony_ci        mutex_unlock(&devfreq_list_lock);
3103d0407baSopenharmony_ci
3113d0407baSopenharmony_ci        if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND, DEVFREQ_NAME_LEN)) {
3123d0407baSopenharmony_ci            err = request_module("governor_%s", "simpleondemand");
3133d0407baSopenharmony_ci        } else {
3143d0407baSopenharmony_ci            err = request_module("governor_%s", name);
3153d0407baSopenharmony_ci        }
3163d0407baSopenharmony_ci        /* Restore previous state before return */
3173d0407baSopenharmony_ci        mutex_lock(&devfreq_list_lock);
3183d0407baSopenharmony_ci        if (err) {
3193d0407baSopenharmony_ci            return (err < 0) ? ERR_PTR(err) : ERR_PTR(-EINVAL);
3203d0407baSopenharmony_ci        }
3213d0407baSopenharmony_ci
3223d0407baSopenharmony_ci        governor = find_devfreq_governor(name);
3233d0407baSopenharmony_ci    }
3243d0407baSopenharmony_ci
3253d0407baSopenharmony_ci    return governor;
3263d0407baSopenharmony_ci}
3273d0407baSopenharmony_ci
3283d0407baSopenharmony_cistatic int devfreq_notify_transition(struct devfreq *devfreq, struct devfreq_freqs *freqs, unsigned int state)
3293d0407baSopenharmony_ci{
3303d0407baSopenharmony_ci    if (!devfreq) {
3313d0407baSopenharmony_ci        return -EINVAL;
3323d0407baSopenharmony_ci    }
3333d0407baSopenharmony_ci
3343d0407baSopenharmony_ci    switch (state) {
3353d0407baSopenharmony_ci        case DEVFREQ_PRECHANGE:
3363d0407baSopenharmony_ci            srcu_notifier_call_chain(&devfreq->transition_notifier_list, DEVFREQ_PRECHANGE, freqs);
3373d0407baSopenharmony_ci            break;
3383d0407baSopenharmony_ci
3393d0407baSopenharmony_ci        case DEVFREQ_POSTCHANGE:
3403d0407baSopenharmony_ci            srcu_notifier_call_chain(&devfreq->transition_notifier_list, DEVFREQ_POSTCHANGE, freqs);
3413d0407baSopenharmony_ci            break;
3423d0407baSopenharmony_ci        default:
3433d0407baSopenharmony_ci            return -EINVAL;
3443d0407baSopenharmony_ci    }
3453d0407baSopenharmony_ci
3463d0407baSopenharmony_ci    return 0;
3473d0407baSopenharmony_ci}
3483d0407baSopenharmony_ci
3493d0407baSopenharmony_cistatic int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq, u32 flags)
3503d0407baSopenharmony_ci{
3513d0407baSopenharmony_ci    struct devfreq_freqs freqs;
3523d0407baSopenharmony_ci    unsigned long cur_freq;
3533d0407baSopenharmony_ci    int err = 0;
3543d0407baSopenharmony_ci
3553d0407baSopenharmony_ci    if (devfreq->profile->get_cur_freq) {
3563d0407baSopenharmony_ci        devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
3573d0407baSopenharmony_ci    } else {
3583d0407baSopenharmony_ci        cur_freq = devfreq->previous_freq;
3593d0407baSopenharmony_ci    }
3603d0407baSopenharmony_ci
3613d0407baSopenharmony_ci    freqs.old = cur_freq;
3623d0407baSopenharmony_ci    freqs.new = new_freq;
3633d0407baSopenharmony_ci    devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
3643d0407baSopenharmony_ci
3653d0407baSopenharmony_ci    err = devfreq->profile->target(devfreq->dev.parent, &new_freq, flags);
3663d0407baSopenharmony_ci    if (err) {
3673d0407baSopenharmony_ci        freqs.new = cur_freq;
3683d0407baSopenharmony_ci        devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
3693d0407baSopenharmony_ci        return err;
3703d0407baSopenharmony_ci    }
3713d0407baSopenharmony_ci
3723d0407baSopenharmony_ci    freqs.new = new_freq;
3733d0407baSopenharmony_ci    devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
3743d0407baSopenharmony_ci
3753d0407baSopenharmony_ci    if (devfreq_update_status(devfreq, new_freq)) {
3763d0407baSopenharmony_ci        dev_err(&devfreq->dev, "Couldn't update frequency transition information.\n");
3773d0407baSopenharmony_ci    }
3783d0407baSopenharmony_ci
3793d0407baSopenharmony_ci    devfreq->previous_freq = new_freq;
3803d0407baSopenharmony_ci
3813d0407baSopenharmony_ci    if (devfreq->suspend_freq) {
3823d0407baSopenharmony_ci        devfreq->resume_freq = new_freq;
3833d0407baSopenharmony_ci    }
3843d0407baSopenharmony_ci
3853d0407baSopenharmony_ci    return err;
3863d0407baSopenharmony_ci}
3873d0407baSopenharmony_ci
3883d0407baSopenharmony_ci/* Load monitoring helper functions for governors use */
3893d0407baSopenharmony_ci
3903d0407baSopenharmony_ci/**
3913d0407baSopenharmony_ci * update_devfreq() - Reevaluate the device and configure frequency.
3923d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
3933d0407baSopenharmony_ci *
3943d0407baSopenharmony_ci * Note: Lock devfreq->lock before calling update_devfreq
3953d0407baSopenharmony_ci *     This function is exported for governors.
3963d0407baSopenharmony_ci */
3973d0407baSopenharmony_ciint update_devfreq(struct devfreq *devfreq)
3983d0407baSopenharmony_ci{
3993d0407baSopenharmony_ci    unsigned long freq, min_freq, max_freq;
4003d0407baSopenharmony_ci    int err = 0;
4013d0407baSopenharmony_ci    u32 flags = 0;
4023d0407baSopenharmony_ci
4033d0407baSopenharmony_ci    lockdep_assert_held(&devfreq->lock);
4043d0407baSopenharmony_ci
4053d0407baSopenharmony_ci    if (!devfreq->governor) {
4063d0407baSopenharmony_ci        return -EINVAL;
4073d0407baSopenharmony_ci    }
4083d0407baSopenharmony_ci
4093d0407baSopenharmony_ci    /* Reevaluate the proper frequency */
4103d0407baSopenharmony_ci    err = devfreq->governor->get_target_freq(devfreq, &freq);
4113d0407baSopenharmony_ci    if (err) {
4123d0407baSopenharmony_ci        return err;
4133d0407baSopenharmony_ci    }
4143d0407baSopenharmony_ci    get_freq_range(devfreq, &min_freq, &max_freq);
4153d0407baSopenharmony_ci
4163d0407baSopenharmony_ci    if (freq < min_freq) {
4173d0407baSopenharmony_ci        freq = min_freq;
4183d0407baSopenharmony_ci        flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
4193d0407baSopenharmony_ci    }
4203d0407baSopenharmony_ci    if (freq > max_freq) {
4213d0407baSopenharmony_ci        freq = max_freq;
4223d0407baSopenharmony_ci        flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
4233d0407baSopenharmony_ci    }
4243d0407baSopenharmony_ci
4253d0407baSopenharmony_ci    return devfreq_set_target(devfreq, freq, flags);
4263d0407baSopenharmony_ci}
4273d0407baSopenharmony_ciEXPORT_SYMBOL(update_devfreq);
4283d0407baSopenharmony_ci
4293d0407baSopenharmony_ci/**
4303d0407baSopenharmony_ci * devfreq_monitor() - Periodically poll devfreq objects.
4313d0407baSopenharmony_ci * @work:    the work struct used to run devfreq_monitor periodically.
4323d0407baSopenharmony_ci *
4333d0407baSopenharmony_ci */
4343d0407baSopenharmony_cistatic void devfreq_monitor(struct work_struct *work)
4353d0407baSopenharmony_ci{
4363d0407baSopenharmony_ci    int err;
4373d0407baSopenharmony_ci    struct devfreq *devfreq = container_of(work, struct devfreq, work.work);
4383d0407baSopenharmony_ci
4393d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
4403d0407baSopenharmony_ci    err = update_devfreq(devfreq);
4413d0407baSopenharmony_ci    if (err) {
4423d0407baSopenharmony_ci        dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
4433d0407baSopenharmony_ci    }
4443d0407baSopenharmony_ci
4453d0407baSopenharmony_ci    queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms));
4463d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
4473d0407baSopenharmony_ci
4483d0407baSopenharmony_ci    trace_devfreq_monitor(devfreq);
4493d0407baSopenharmony_ci}
4503d0407baSopenharmony_ci
4513d0407baSopenharmony_ci/**
4523d0407baSopenharmony_ci * devfreq_monitor_start() - Start load monitoring of devfreq instance
4533d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
4543d0407baSopenharmony_ci *
4553d0407baSopenharmony_ci * Helper function for starting devfreq device load monitoring. By
4563d0407baSopenharmony_ci * default delayed work based monitoring is supported. Function
4573d0407baSopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_START
4583d0407baSopenharmony_ci * event when device is added to devfreq framework.
4593d0407baSopenharmony_ci */
4603d0407baSopenharmony_civoid devfreq_monitor_start(struct devfreq *devfreq)
4613d0407baSopenharmony_ci{
4623d0407baSopenharmony_ci    if (devfreq->governor->interrupt_driven) {
4633d0407baSopenharmony_ci        return;
4643d0407baSopenharmony_ci    }
4653d0407baSopenharmony_ci
4663d0407baSopenharmony_ci    switch (devfreq->profile->timer) {
4673d0407baSopenharmony_ci        case DEVFREQ_TIMER_DEFERRABLE:
4683d0407baSopenharmony_ci            INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
4693d0407baSopenharmony_ci            break;
4703d0407baSopenharmony_ci        case DEVFREQ_TIMER_DELAYED:
4713d0407baSopenharmony_ci            INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor);
4723d0407baSopenharmony_ci            break;
4733d0407baSopenharmony_ci        default:
4743d0407baSopenharmony_ci            return;
4753d0407baSopenharmony_ci    }
4763d0407baSopenharmony_ci
4773d0407baSopenharmony_ci    if (devfreq->profile->polling_ms) {
4783d0407baSopenharmony_ci        queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms));
4793d0407baSopenharmony_ci    }
4803d0407baSopenharmony_ci}
4813d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_start);
4823d0407baSopenharmony_ci
4833d0407baSopenharmony_ci/**
4843d0407baSopenharmony_ci * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
4853d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
4863d0407baSopenharmony_ci *
4873d0407baSopenharmony_ci * Helper function to stop devfreq device load monitoring. Function
4883d0407baSopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_STOP
4893d0407baSopenharmony_ci * event when device is removed from devfreq framework.
4903d0407baSopenharmony_ci */
4913d0407baSopenharmony_civoid devfreq_monitor_stop(struct devfreq *devfreq)
4923d0407baSopenharmony_ci{
4933d0407baSopenharmony_ci    if (devfreq->governor->interrupt_driven) {
4943d0407baSopenharmony_ci        return;
4953d0407baSopenharmony_ci    }
4963d0407baSopenharmony_ci
4973d0407baSopenharmony_ci    cancel_delayed_work_sync(&devfreq->work);
4983d0407baSopenharmony_ci}
4993d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_stop);
5003d0407baSopenharmony_ci
5013d0407baSopenharmony_ci/**
5023d0407baSopenharmony_ci * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
5033d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
5043d0407baSopenharmony_ci *
5053d0407baSopenharmony_ci * Helper function to suspend devfreq device load monitoring. Function
5063d0407baSopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_SUSPEND
5073d0407baSopenharmony_ci * event or when polling interval is set to zero.
5083d0407baSopenharmony_ci *
5093d0407baSopenharmony_ci * Note: Though this function is same as devfreq_monitor_stop(),
5103d0407baSopenharmony_ci * intentionally kept separate to provide hooks for collecting
5113d0407baSopenharmony_ci * transition statistics.
5123d0407baSopenharmony_ci */
5133d0407baSopenharmony_civoid devfreq_monitor_suspend(struct devfreq *devfreq)
5143d0407baSopenharmony_ci{
5153d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
5163d0407baSopenharmony_ci    if (devfreq->stop_polling) {
5173d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
5183d0407baSopenharmony_ci        return;
5193d0407baSopenharmony_ci    }
5203d0407baSopenharmony_ci
5213d0407baSopenharmony_ci    devfreq_update_status(devfreq, devfreq->previous_freq);
5223d0407baSopenharmony_ci    devfreq->stop_polling = true;
5233d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
5243d0407baSopenharmony_ci
5253d0407baSopenharmony_ci    if (devfreq->governor->interrupt_driven) {
5263d0407baSopenharmony_ci        return;
5273d0407baSopenharmony_ci    }
5283d0407baSopenharmony_ci
5293d0407baSopenharmony_ci    cancel_delayed_work_sync(&devfreq->work);
5303d0407baSopenharmony_ci}
5313d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_suspend);
5323d0407baSopenharmony_ci
5333d0407baSopenharmony_ci/**
5343d0407baSopenharmony_ci * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
5353d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
5363d0407baSopenharmony_ci *
5373d0407baSopenharmony_ci * Helper function to resume devfreq device load monitoring. Function
5383d0407baSopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_RESUME
5393d0407baSopenharmony_ci * event or when polling interval is set to non-zero.
5403d0407baSopenharmony_ci */
5413d0407baSopenharmony_civoid devfreq_monitor_resume(struct devfreq *devfreq)
5423d0407baSopenharmony_ci{
5433d0407baSopenharmony_ci    unsigned long freq;
5443d0407baSopenharmony_ci
5453d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
5463d0407baSopenharmony_ci    if (!devfreq->stop_polling) {
5473d0407baSopenharmony_ci        goto out;
5483d0407baSopenharmony_ci    }
5493d0407baSopenharmony_ci
5503d0407baSopenharmony_ci    if (devfreq->governor->interrupt_driven) {
5513d0407baSopenharmony_ci        goto out_update;
5523d0407baSopenharmony_ci    }
5533d0407baSopenharmony_ci
5543d0407baSopenharmony_ci    if (!delayed_work_pending(&devfreq->work) && devfreq->profile->polling_ms) {
5553d0407baSopenharmony_ci        queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms));
5563d0407baSopenharmony_ci    }
5573d0407baSopenharmony_ci
5583d0407baSopenharmony_ciout_update:
5593d0407baSopenharmony_ci    devfreq->stats.last_update = get_jiffies_64();
5603d0407baSopenharmony_ci    devfreq->stop_polling = false;
5613d0407baSopenharmony_ci
5623d0407baSopenharmony_ci    if (devfreq->profile->get_cur_freq && !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) {
5633d0407baSopenharmony_ci        devfreq->previous_freq = freq;
5643d0407baSopenharmony_ci    }
5653d0407baSopenharmony_ci
5663d0407baSopenharmony_ciout:
5673d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
5683d0407baSopenharmony_ci}
5693d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_monitor_resume);
5703d0407baSopenharmony_ci
5713d0407baSopenharmony_ci/**
5723d0407baSopenharmony_ci * devfreq_update_interval() - Update device devfreq monitoring interval
5733d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
5743d0407baSopenharmony_ci * @delay:      new polling interval to be set.
5753d0407baSopenharmony_ci *
5763d0407baSopenharmony_ci * Helper function to set new load monitoring polling interval. Function
5773d0407baSopenharmony_ci * to be called from governor in response to DEVFREQ_GOV_UPDATE_INTERVAL event.
5783d0407baSopenharmony_ci */
5793d0407baSopenharmony_civoid devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay)
5803d0407baSopenharmony_ci{
5813d0407baSopenharmony_ci    unsigned int cur_delay = devfreq->profile->polling_ms;
5823d0407baSopenharmony_ci    unsigned int new_delay = *delay;
5833d0407baSopenharmony_ci
5843d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
5853d0407baSopenharmony_ci    devfreq->profile->polling_ms = new_delay;
5863d0407baSopenharmony_ci
5873d0407baSopenharmony_ci    if (devfreq->stop_polling) {
5883d0407baSopenharmony_ci        goto out;
5893d0407baSopenharmony_ci    }
5903d0407baSopenharmony_ci
5913d0407baSopenharmony_ci    if (devfreq->governor->interrupt_driven) {
5923d0407baSopenharmony_ci        goto out;
5933d0407baSopenharmony_ci    }
5943d0407baSopenharmony_ci
5953d0407baSopenharmony_ci    /* if new delay is zero, stop polling */
5963d0407baSopenharmony_ci    if (!new_delay) {
5973d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
5983d0407baSopenharmony_ci        cancel_delayed_work_sync(&devfreq->work);
5993d0407baSopenharmony_ci        return;
6003d0407baSopenharmony_ci    }
6013d0407baSopenharmony_ci
6023d0407baSopenharmony_ci    /* if current delay is zero, start polling with new delay */
6033d0407baSopenharmony_ci    if (!cur_delay) {
6043d0407baSopenharmony_ci        queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms));
6053d0407baSopenharmony_ci        goto out;
6063d0407baSopenharmony_ci    }
6073d0407baSopenharmony_ci
6083d0407baSopenharmony_ci    /* if current delay is greater than new delay, restart polling */
6093d0407baSopenharmony_ci    if (cur_delay > new_delay) {
6103d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
6113d0407baSopenharmony_ci        cancel_delayed_work_sync(&devfreq->work);
6123d0407baSopenharmony_ci        mutex_lock(&devfreq->lock);
6133d0407baSopenharmony_ci        if (!devfreq->stop_polling) {
6143d0407baSopenharmony_ci            queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms));
6153d0407baSopenharmony_ci        }
6163d0407baSopenharmony_ci    }
6173d0407baSopenharmony_ciout:
6183d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
6193d0407baSopenharmony_ci}
6203d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_update_interval);
6213d0407baSopenharmony_ci
6223d0407baSopenharmony_ci/**
6233d0407baSopenharmony_ci * devfreq_notifier_call() - Notify that the device frequency requirements
6243d0407baSopenharmony_ci *                 has been changed out of devfreq framework.
6253d0407baSopenharmony_ci * @nb:        the notifier_block (supposed to be devfreq->nb)
6263d0407baSopenharmony_ci * @type:    not used
6273d0407baSopenharmony_ci * @devp:    not used
6283d0407baSopenharmony_ci *
6293d0407baSopenharmony_ci * Called by a notifier that uses devfreq->nb.
6303d0407baSopenharmony_ci */
6313d0407baSopenharmony_cistatic int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, void *devp)
6323d0407baSopenharmony_ci{
6333d0407baSopenharmony_ci    struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
6343d0407baSopenharmony_ci    int err = -EINVAL;
6353d0407baSopenharmony_ci
6363d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
6373d0407baSopenharmony_ci
6383d0407baSopenharmony_ci    devfreq->scaling_min_freq = find_available_min_freq(devfreq);
6393d0407baSopenharmony_ci    if (!devfreq->scaling_min_freq) {
6403d0407baSopenharmony_ci        goto out;
6413d0407baSopenharmony_ci    }
6423d0407baSopenharmony_ci
6433d0407baSopenharmony_ci    devfreq->scaling_max_freq = find_available_max_freq(devfreq);
6443d0407baSopenharmony_ci    if (!devfreq->scaling_max_freq) {
6453d0407baSopenharmony_ci        devfreq->scaling_max_freq = ULONG_MAX;
6463d0407baSopenharmony_ci        goto out;
6473d0407baSopenharmony_ci    }
6483d0407baSopenharmony_ci
6493d0407baSopenharmony_ci    err = update_devfreq(devfreq);
6503d0407baSopenharmony_ci
6513d0407baSopenharmony_ciout:
6523d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
6533d0407baSopenharmony_ci    if (err) {
6543d0407baSopenharmony_ci        dev_err(devfreq->dev.parent, "failed to update frequency from OPP notifier (%d)\n", err);
6553d0407baSopenharmony_ci    }
6563d0407baSopenharmony_ci
6573d0407baSopenharmony_ci    return NOTIFY_OK;
6583d0407baSopenharmony_ci}
6593d0407baSopenharmony_ci
6603d0407baSopenharmony_ci/**
6613d0407baSopenharmony_ci * qos_notifier_call() - Common handler for QoS constraints.
6623d0407baSopenharmony_ci * @devfreq:    the devfreq instance.
6633d0407baSopenharmony_ci */
6643d0407baSopenharmony_cistatic int qos_notifier_call(struct devfreq *devfreq)
6653d0407baSopenharmony_ci{
6663d0407baSopenharmony_ci    int err;
6673d0407baSopenharmony_ci
6683d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
6693d0407baSopenharmony_ci    err = update_devfreq(devfreq);
6703d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
6713d0407baSopenharmony_ci    if (err) {
6723d0407baSopenharmony_ci        dev_err(devfreq->dev.parent, "failed to update frequency from PM QoS (%d)\n", err);
6733d0407baSopenharmony_ci    }
6743d0407baSopenharmony_ci
6753d0407baSopenharmony_ci    return NOTIFY_OK;
6763d0407baSopenharmony_ci}
6773d0407baSopenharmony_ci
6783d0407baSopenharmony_ci/**
6793d0407baSopenharmony_ci * qos_min_notifier_call() - Callback for QoS min_freq changes.
6803d0407baSopenharmony_ci * @nb:        Should be devfreq->nb_min
6813d0407baSopenharmony_ci */
6823d0407baSopenharmony_cistatic int qos_min_notifier_call(struct notifier_block *nb, unsigned long val, void *ptr)
6833d0407baSopenharmony_ci{
6843d0407baSopenharmony_ci    return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
6853d0407baSopenharmony_ci}
6863d0407baSopenharmony_ci
6873d0407baSopenharmony_ci/**
6883d0407baSopenharmony_ci * qos_max_notifier_call() - Callback for QoS max_freq changes.
6893d0407baSopenharmony_ci * @nb:        Should be devfreq->nb_max
6903d0407baSopenharmony_ci */
6913d0407baSopenharmony_cistatic int qos_max_notifier_call(struct notifier_block *nb, unsigned long val, void *ptr)
6923d0407baSopenharmony_ci{
6933d0407baSopenharmony_ci    return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
6943d0407baSopenharmony_ci}
6953d0407baSopenharmony_ci
6963d0407baSopenharmony_ci/**
6973d0407baSopenharmony_ci * devfreq_dev_release() - Callback for struct device to release the device.
6983d0407baSopenharmony_ci * @dev:    the devfreq device
6993d0407baSopenharmony_ci *
7003d0407baSopenharmony_ci * Remove devfreq from the list and release its resources.
7013d0407baSopenharmony_ci */
7023d0407baSopenharmony_cistatic void devfreq_dev_release(struct device *dev)
7033d0407baSopenharmony_ci{
7043d0407baSopenharmony_ci    struct devfreq *devfreq = to_devfreq(dev);
7053d0407baSopenharmony_ci    int err;
7063d0407baSopenharmony_ci
7073d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
7083d0407baSopenharmony_ci    list_del(&devfreq->node);
7093d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
7103d0407baSopenharmony_ci
7113d0407baSopenharmony_ci    err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max, DEV_PM_QOS_MAX_FREQUENCY);
7123d0407baSopenharmony_ci    if (err && err != -ENOENT) {
7133d0407baSopenharmony_ci        dev_warn(dev->parent, "Failed to remove max_freq notifier: %d\n", err);
7143d0407baSopenharmony_ci    }
7153d0407baSopenharmony_ci    err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min, DEV_PM_QOS_MIN_FREQUENCY);
7163d0407baSopenharmony_ci    if (err && err != -ENOENT) {
7173d0407baSopenharmony_ci        dev_warn(dev->parent, "Failed to remove min_freq notifier: %d\n", err);
7183d0407baSopenharmony_ci    }
7193d0407baSopenharmony_ci
7203d0407baSopenharmony_ci    if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) {
7213d0407baSopenharmony_ci        err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
7223d0407baSopenharmony_ci        if (err < 0) {
7233d0407baSopenharmony_ci            dev_warn(dev->parent, "Failed to remove max_freq request: %d\n", err);
7243d0407baSopenharmony_ci        }
7253d0407baSopenharmony_ci    }
7263d0407baSopenharmony_ci    if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) {
7273d0407baSopenharmony_ci        err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
7283d0407baSopenharmony_ci        if (err < 0) {
7293d0407baSopenharmony_ci            dev_warn(dev->parent, "Failed to remove min_freq request: %d\n", err);
7303d0407baSopenharmony_ci        }
7313d0407baSopenharmony_ci    }
7323d0407baSopenharmony_ci
7333d0407baSopenharmony_ci    if (devfreq->profile->exit) {
7343d0407baSopenharmony_ci        devfreq->profile->exit(devfreq->dev.parent);
7353d0407baSopenharmony_ci    }
7363d0407baSopenharmony_ci
7373d0407baSopenharmony_ci    mutex_destroy(&devfreq->lock);
7383d0407baSopenharmony_ci    kfree(devfreq);
7393d0407baSopenharmony_ci}
7403d0407baSopenharmony_ci
7413d0407baSopenharmony_ci/**
7423d0407baSopenharmony_ci * devfreq_remove_device() - Remove devfreq feature from a device.
7433d0407baSopenharmony_ci * @devfreq:    the devfreq instance to be removed
7443d0407baSopenharmony_ci *
7453d0407baSopenharmony_ci * The opposite of devfreq_add_device().
7463d0407baSopenharmony_ci */
7473d0407baSopenharmony_ciint devfreq_remove_device(struct devfreq *devfreq)
7483d0407baSopenharmony_ci{
7493d0407baSopenharmony_ci    if (!devfreq) {
7503d0407baSopenharmony_ci        return -EINVAL;
7513d0407baSopenharmony_ci    }
7523d0407baSopenharmony_ci
7533d0407baSopenharmony_ci    if (devfreq->governor) {
7543d0407baSopenharmony_ci        devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
7553d0407baSopenharmony_ci    }
7563d0407baSopenharmony_ci    device_unregister(&devfreq->dev);
7573d0407baSopenharmony_ci
7583d0407baSopenharmony_ci    return 0;
7593d0407baSopenharmony_ci}
7603d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_remove_device);
7613d0407baSopenharmony_ci
7623d0407baSopenharmony_ci/**
7633d0407baSopenharmony_ci * devfreq_add_device() - Add devfreq feature to the device
7643d0407baSopenharmony_ci * @dev:    the device to add devfreq feature.
7653d0407baSopenharmony_ci * @profile:    device-specific profile to run devfreq.
7663d0407baSopenharmony_ci * @governor_name:    name of the policy to choose frequency.
7673d0407baSopenharmony_ci * @data:    private data for the governor. The devfreq framework does not
7683d0407baSopenharmony_ci *        touch this value.
7693d0407baSopenharmony_ci */
7703d0407baSopenharmony_cistruct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, const char *governor_name,
7713d0407baSopenharmony_ci                                   void *data)
7723d0407baSopenharmony_ci{
7733d0407baSopenharmony_ci    struct devfreq *devfreq;
7743d0407baSopenharmony_ci    struct devfreq_governor *governor;
7753d0407baSopenharmony_ci    int err = 0;
7763d0407baSopenharmony_ci
7773d0407baSopenharmony_ci    if (!dev || !profile || !governor_name) {
7783d0407baSopenharmony_ci        dev_err(dev, "%s: Invalid parameters.\n", __func__);
7793d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
7803d0407baSopenharmony_ci    }
7813d0407baSopenharmony_ci
7823d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
7833d0407baSopenharmony_ci    devfreq = find_device_devfreq(dev);
7843d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
7853d0407baSopenharmony_ci    if (!IS_ERR(devfreq)) {
7863d0407baSopenharmony_ci        dev_err(dev, "%s: devfreq device already exists!\n", __func__);
7873d0407baSopenharmony_ci        err = -EINVAL;
7883d0407baSopenharmony_ci        goto err_out;
7893d0407baSopenharmony_ci    }
7903d0407baSopenharmony_ci
7913d0407baSopenharmony_ci    devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
7923d0407baSopenharmony_ci    if (!devfreq) {
7933d0407baSopenharmony_ci        err = -ENOMEM;
7943d0407baSopenharmony_ci        goto err_out;
7953d0407baSopenharmony_ci    }
7963d0407baSopenharmony_ci
7973d0407baSopenharmony_ci    mutex_init(&devfreq->lock);
7983d0407baSopenharmony_ci    mutex_lock(&devfreq->lock);
7993d0407baSopenharmony_ci    devfreq->dev.parent = dev;
8003d0407baSopenharmony_ci    devfreq->dev.class = devfreq_class;
8013d0407baSopenharmony_ci    devfreq->dev.release = devfreq_dev_release;
8023d0407baSopenharmony_ci    INIT_LIST_HEAD(&devfreq->node);
8033d0407baSopenharmony_ci    devfreq->profile = profile;
8043d0407baSopenharmony_ci    strscpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
8053d0407baSopenharmony_ci    devfreq->previous_freq = profile->initial_freq;
8063d0407baSopenharmony_ci    devfreq->last_status.current_frequency = profile->initial_freq;
8073d0407baSopenharmony_ci    devfreq->data = data;
8083d0407baSopenharmony_ci    devfreq->nb.notifier_call = devfreq_notifier_call;
8093d0407baSopenharmony_ci
8103d0407baSopenharmony_ci    if (devfreq->profile->timer < 0 || devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
8113d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8123d0407baSopenharmony_ci        err = -EINVAL;
8133d0407baSopenharmony_ci        goto err_dev;
8143d0407baSopenharmony_ci    }
8153d0407baSopenharmony_ci
8163d0407baSopenharmony_ci    if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
8173d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8183d0407baSopenharmony_ci        err = set_freq_table(devfreq);
8193d0407baSopenharmony_ci        if (err < 0) {
8203d0407baSopenharmony_ci            goto err_dev;
8213d0407baSopenharmony_ci        }
8223d0407baSopenharmony_ci        mutex_lock(&devfreq->lock);
8233d0407baSopenharmony_ci    }
8243d0407baSopenharmony_ci
8253d0407baSopenharmony_ci    devfreq->scaling_min_freq = find_available_min_freq(devfreq);
8263d0407baSopenharmony_ci    if (!devfreq->scaling_min_freq) {
8273d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8283d0407baSopenharmony_ci        err = -EINVAL;
8293d0407baSopenharmony_ci        goto err_dev;
8303d0407baSopenharmony_ci    }
8313d0407baSopenharmony_ci
8323d0407baSopenharmony_ci    devfreq->scaling_max_freq = find_available_max_freq(devfreq);
8333d0407baSopenharmony_ci    if (!devfreq->scaling_max_freq) {
8343d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8353d0407baSopenharmony_ci        err = -EINVAL;
8363d0407baSopenharmony_ci        goto err_dev;
8373d0407baSopenharmony_ci    }
8383d0407baSopenharmony_ci
8393d0407baSopenharmony_ci    devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
8403d0407baSopenharmony_ci    atomic_set(&devfreq->suspend_count, 0);
8413d0407baSopenharmony_ci
8423d0407baSopenharmony_ci    dev_set_name(&devfreq->dev, "%s", dev_name(dev));
8433d0407baSopenharmony_ci    err = device_register(&devfreq->dev);
8443d0407baSopenharmony_ci    if (err) {
8453d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8463d0407baSopenharmony_ci        put_device(&devfreq->dev);
8473d0407baSopenharmony_ci        goto err_out;
8483d0407baSopenharmony_ci    }
8493d0407baSopenharmony_ci
8503d0407baSopenharmony_ci    devfreq->stats.trans_table = devm_kzalloc(
8513d0407baSopenharmony_ci        &devfreq->dev, array3_size(sizeof(unsigned int), devfreq->profile->max_state, devfreq->profile->max_state),
8523d0407baSopenharmony_ci        GFP_KERNEL);
8533d0407baSopenharmony_ci    if (!devfreq->stats.trans_table) {
8543d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8553d0407baSopenharmony_ci        err = -ENOMEM;
8563d0407baSopenharmony_ci        goto err_devfreq;
8573d0407baSopenharmony_ci    }
8583d0407baSopenharmony_ci
8593d0407baSopenharmony_ci    devfreq->stats.time_in_state =
8603d0407baSopenharmony_ci        devm_kcalloc(&devfreq->dev, devfreq->profile->max_state, sizeof(*devfreq->stats.time_in_state), GFP_KERNEL);
8613d0407baSopenharmony_ci    if (!devfreq->stats.time_in_state) {
8623d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
8633d0407baSopenharmony_ci        err = -ENOMEM;
8643d0407baSopenharmony_ci        goto err_devfreq;
8653d0407baSopenharmony_ci    }
8663d0407baSopenharmony_ci
8673d0407baSopenharmony_ci    devfreq->stats.total_trans = 0;
8683d0407baSopenharmony_ci    devfreq->stats.last_update = get_jiffies_64();
8693d0407baSopenharmony_ci
8703d0407baSopenharmony_ci    srcu_init_notifier_head(&devfreq->transition_notifier_list);
8713d0407baSopenharmony_ci
8723d0407baSopenharmony_ci    mutex_unlock(&devfreq->lock);
8733d0407baSopenharmony_ci
8743d0407baSopenharmony_ci    err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req, DEV_PM_QOS_MIN_FREQUENCY, 0);
8753d0407baSopenharmony_ci    if (err < 0) {
8763d0407baSopenharmony_ci        goto err_devfreq;
8773d0407baSopenharmony_ci    }
8783d0407baSopenharmony_ci    err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req, DEV_PM_QOS_MAX_FREQUENCY,
8793d0407baSopenharmony_ci                                 PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
8803d0407baSopenharmony_ci    if (err < 0) {
8813d0407baSopenharmony_ci        goto err_devfreq;
8823d0407baSopenharmony_ci    }
8833d0407baSopenharmony_ci
8843d0407baSopenharmony_ci    devfreq->nb_min.notifier_call = qos_min_notifier_call;
8853d0407baSopenharmony_ci    err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min, DEV_PM_QOS_MIN_FREQUENCY);
8863d0407baSopenharmony_ci    if (err) {
8873d0407baSopenharmony_ci        goto err_devfreq;
8883d0407baSopenharmony_ci    }
8893d0407baSopenharmony_ci
8903d0407baSopenharmony_ci    devfreq->nb_max.notifier_call = qos_max_notifier_call;
8913d0407baSopenharmony_ci    err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max, DEV_PM_QOS_MAX_FREQUENCY);
8923d0407baSopenharmony_ci    if (err) {
8933d0407baSopenharmony_ci        goto err_devfreq;
8943d0407baSopenharmony_ci    }
8953d0407baSopenharmony_ci
8963d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
8973d0407baSopenharmony_ci
8983d0407baSopenharmony_ci    governor = try_then_request_governor(devfreq->governor_name);
8993d0407baSopenharmony_ci    if (IS_ERR(governor)) {
9003d0407baSopenharmony_ci        dev_err(dev, "%s: Unable to find governor for the device\n", __func__);
9013d0407baSopenharmony_ci        err = PTR_ERR(governor);
9023d0407baSopenharmony_ci        goto err_init;
9033d0407baSopenharmony_ci    }
9043d0407baSopenharmony_ci
9053d0407baSopenharmony_ci    devfreq->governor = governor;
9063d0407baSopenharmony_ci    err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, NULL);
9073d0407baSopenharmony_ci    if (err) {
9083d0407baSopenharmony_ci        dev_err(dev, "%s: Unable to start governor for the device\n", __func__);
9093d0407baSopenharmony_ci        goto err_init;
9103d0407baSopenharmony_ci    }
9113d0407baSopenharmony_ci
9123d0407baSopenharmony_ci    list_add(&devfreq->node, &devfreq_list);
9133d0407baSopenharmony_ci
9143d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
9153d0407baSopenharmony_ci
9163d0407baSopenharmony_ci    return devfreq;
9173d0407baSopenharmony_ci
9183d0407baSopenharmony_cierr_init:
9193d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
9203d0407baSopenharmony_cierr_devfreq:
9213d0407baSopenharmony_ci    devfreq_remove_device(devfreq);
9223d0407baSopenharmony_ci    devfreq = NULL;
9233d0407baSopenharmony_cierr_dev:
9243d0407baSopenharmony_ci    kfree(devfreq);
9253d0407baSopenharmony_cierr_out:
9263d0407baSopenharmony_ci    return ERR_PTR(err);
9273d0407baSopenharmony_ci}
9283d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_add_device);
9293d0407baSopenharmony_ci
9303d0407baSopenharmony_cistatic int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
9313d0407baSopenharmony_ci{
9323d0407baSopenharmony_ci    struct devfreq **r = res;
9333d0407baSopenharmony_ci
9343d0407baSopenharmony_ci    if (WARN_ON(!r || !*r)) {
9353d0407baSopenharmony_ci        return 0;
9363d0407baSopenharmony_ci    }
9373d0407baSopenharmony_ci
9383d0407baSopenharmony_ci    return *r == data;
9393d0407baSopenharmony_ci}
9403d0407baSopenharmony_ci
9413d0407baSopenharmony_cistatic void devm_devfreq_dev_release(struct device *dev, void *res)
9423d0407baSopenharmony_ci{
9433d0407baSopenharmony_ci    devfreq_remove_device(*(struct devfreq **)res);
9443d0407baSopenharmony_ci}
9453d0407baSopenharmony_ci
9463d0407baSopenharmony_ci/**
9473d0407baSopenharmony_ci * devm_devfreq_add_device() - Resource-managed devfreq_add_device()
9483d0407baSopenharmony_ci * @dev:    the device to add devfreq feature.
9493d0407baSopenharmony_ci * @profile:    device-specific profile to run devfreq.
9503d0407baSopenharmony_ci * @governor_name:    name of the policy to choose frequency.
9513d0407baSopenharmony_ci * @data:    private data for the governor. The devfreq framework does not
9523d0407baSopenharmony_ci *        touch this value.
9533d0407baSopenharmony_ci *
9543d0407baSopenharmony_ci * This function manages automatically the memory of devfreq device using device
9553d0407baSopenharmony_ci * resource management and simplify the free operation for memory of devfreq
9563d0407baSopenharmony_ci * device.
9573d0407baSopenharmony_ci */
9583d0407baSopenharmony_cistruct devfreq *devm_devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile,
9593d0407baSopenharmony_ci                                        const char *governor_name, void *data)
9603d0407baSopenharmony_ci{
9613d0407baSopenharmony_ci    struct devfreq **ptr, *devfreq;
9623d0407baSopenharmony_ci
9633d0407baSopenharmony_ci    ptr = devres_alloc(devm_devfreq_dev_release, sizeof(*ptr), GFP_KERNEL);
9643d0407baSopenharmony_ci    if (!ptr) {
9653d0407baSopenharmony_ci        return ERR_PTR(-ENOMEM);
9663d0407baSopenharmony_ci    }
9673d0407baSopenharmony_ci
9683d0407baSopenharmony_ci    devfreq = devfreq_add_device(dev, profile, governor_name, data);
9693d0407baSopenharmony_ci    if (IS_ERR(devfreq)) {
9703d0407baSopenharmony_ci        devres_free(ptr);
9713d0407baSopenharmony_ci        return devfreq;
9723d0407baSopenharmony_ci    }
9733d0407baSopenharmony_ci
9743d0407baSopenharmony_ci    *ptr = devfreq;
9753d0407baSopenharmony_ci    devres_add(dev, ptr);
9763d0407baSopenharmony_ci
9773d0407baSopenharmony_ci    return devfreq;
9783d0407baSopenharmony_ci}
9793d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_add_device);
9803d0407baSopenharmony_ci
9813d0407baSopenharmony_ci#ifdef CONFIG_OF
9823d0407baSopenharmony_ci/*
9833d0407baSopenharmony_ci * devfreq_get_devfreq_by_node - Get the devfreq device from devicetree
9843d0407baSopenharmony_ci * @node - pointer to device_node
9853d0407baSopenharmony_ci *
9863d0407baSopenharmony_ci * return the instance of devfreq device
9873d0407baSopenharmony_ci */
9883d0407baSopenharmony_cistruct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
9893d0407baSopenharmony_ci{
9903d0407baSopenharmony_ci    struct devfreq *devfreq;
9913d0407baSopenharmony_ci
9923d0407baSopenharmony_ci    if (!node) {
9933d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
9943d0407baSopenharmony_ci    }
9953d0407baSopenharmony_ci
9963d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
9973d0407baSopenharmony_ci    list_for_each_entry(devfreq, &devfreq_list, node)
9983d0407baSopenharmony_ci    {
9993d0407baSopenharmony_ci        if (devfreq->dev.parent && devfreq->dev.parent->of_node == node) {
10003d0407baSopenharmony_ci            mutex_unlock(&devfreq_list_lock);
10013d0407baSopenharmony_ci            return devfreq;
10023d0407baSopenharmony_ci        }
10033d0407baSopenharmony_ci    }
10043d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
10053d0407baSopenharmony_ci
10063d0407baSopenharmony_ci    return ERR_PTR(-ENODEV);
10073d0407baSopenharmony_ci}
10083d0407baSopenharmony_ci
10093d0407baSopenharmony_ci/*
10103d0407baSopenharmony_ci * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
10113d0407baSopenharmony_ci * @dev - instance to the given device
10123d0407baSopenharmony_ci * @phandle_name - name of property holding a phandle value
10133d0407baSopenharmony_ci * @index - index into list of devfreq
10143d0407baSopenharmony_ci *
10153d0407baSopenharmony_ci * return the instance of devfreq device
10163d0407baSopenharmony_ci */
10173d0407baSopenharmony_cistruct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, const char *phandle_name, int index)
10183d0407baSopenharmony_ci{
10193d0407baSopenharmony_ci    struct device_node *node;
10203d0407baSopenharmony_ci    struct devfreq *devfreq;
10213d0407baSopenharmony_ci
10223d0407baSopenharmony_ci    if (!dev || !phandle_name) {
10233d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
10243d0407baSopenharmony_ci    }
10253d0407baSopenharmony_ci
10263d0407baSopenharmony_ci    if (!dev->of_node) {
10273d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
10283d0407baSopenharmony_ci    }
10293d0407baSopenharmony_ci
10303d0407baSopenharmony_ci    node = of_parse_phandle(dev->of_node, phandle_name, index);
10313d0407baSopenharmony_ci    if (!node) {
10323d0407baSopenharmony_ci        return ERR_PTR(-ENODEV);
10333d0407baSopenharmony_ci    }
10343d0407baSopenharmony_ci
10353d0407baSopenharmony_ci    devfreq = devfreq_get_devfreq_by_node(node);
10363d0407baSopenharmony_ci    of_node_put(node);
10373d0407baSopenharmony_ci
10383d0407baSopenharmony_ci    return devfreq;
10393d0407baSopenharmony_ci}
10403d0407baSopenharmony_ci
10413d0407baSopenharmony_ci#else
10423d0407baSopenharmony_cistruct devfreq *devfreq_get_devfreq_by_node(struct device_node *node)
10433d0407baSopenharmony_ci{
10443d0407baSopenharmony_ci    return ERR_PTR(-ENODEV);
10453d0407baSopenharmony_ci}
10463d0407baSopenharmony_ci
10473d0407baSopenharmony_cistruct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, const char *phandle_name, int index)
10483d0407baSopenharmony_ci{
10493d0407baSopenharmony_ci    return ERR_PTR(-ENODEV);
10503d0407baSopenharmony_ci}
10513d0407baSopenharmony_ci#endif /* CONFIG_OF */
10523d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_node);
10533d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_phandle);
10543d0407baSopenharmony_ci
10553d0407baSopenharmony_ci/**
10563d0407baSopenharmony_ci * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
10573d0407baSopenharmony_ci * @dev:    the device from which to remove devfreq feature.
10583d0407baSopenharmony_ci * @devfreq:    the devfreq instance to be removed
10593d0407baSopenharmony_ci */
10603d0407baSopenharmony_civoid devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
10613d0407baSopenharmony_ci{
10623d0407baSopenharmony_ci    WARN_ON(devres_release(dev, devm_devfreq_dev_release, devm_devfreq_dev_match, devfreq));
10633d0407baSopenharmony_ci}
10643d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_remove_device);
10653d0407baSopenharmony_ci
10663d0407baSopenharmony_ci/**
10673d0407baSopenharmony_ci * devfreq_suspend_device() - Suspend devfreq of a device.
10683d0407baSopenharmony_ci * @devfreq: the devfreq instance to be suspended
10693d0407baSopenharmony_ci *
10703d0407baSopenharmony_ci * This function is intended to be called by the pm callbacks
10713d0407baSopenharmony_ci * (e.g., runtime_suspend, suspend) of the device driver that
10723d0407baSopenharmony_ci * holds the devfreq.
10733d0407baSopenharmony_ci */
10743d0407baSopenharmony_ciint devfreq_suspend_device(struct devfreq *devfreq)
10753d0407baSopenharmony_ci{
10763d0407baSopenharmony_ci    int ret;
10773d0407baSopenharmony_ci
10783d0407baSopenharmony_ci    if (!devfreq) {
10793d0407baSopenharmony_ci        return -EINVAL;
10803d0407baSopenharmony_ci    }
10813d0407baSopenharmony_ci
10823d0407baSopenharmony_ci    if (atomic_inc_return(&devfreq->suspend_count) > 1) {
10833d0407baSopenharmony_ci        return 0;
10843d0407baSopenharmony_ci    }
10853d0407baSopenharmony_ci
10863d0407baSopenharmony_ci    if (devfreq->governor) {
10873d0407baSopenharmony_ci        ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_SUSPEND, NULL);
10883d0407baSopenharmony_ci        if (ret) {
10893d0407baSopenharmony_ci            return ret;
10903d0407baSopenharmony_ci        }
10913d0407baSopenharmony_ci    }
10923d0407baSopenharmony_ci
10933d0407baSopenharmony_ci    if (devfreq->suspend_freq) {
10943d0407baSopenharmony_ci        mutex_lock(&devfreq->lock);
10953d0407baSopenharmony_ci        ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
10963d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
10973d0407baSopenharmony_ci        if (ret) {
10983d0407baSopenharmony_ci            return ret;
10993d0407baSopenharmony_ci        }
11003d0407baSopenharmony_ci    }
11013d0407baSopenharmony_ci
11023d0407baSopenharmony_ci    return 0;
11033d0407baSopenharmony_ci}
11043d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_suspend_device);
11053d0407baSopenharmony_ci
11063d0407baSopenharmony_ci/**
11073d0407baSopenharmony_ci * devfreq_resume_device() - Resume devfreq of a device.
11083d0407baSopenharmony_ci * @devfreq: the devfreq instance to be resumed
11093d0407baSopenharmony_ci *
11103d0407baSopenharmony_ci * This function is intended to be called by the pm callbacks
11113d0407baSopenharmony_ci * (e.g., runtime_resume, resume) of the device driver that
11123d0407baSopenharmony_ci * holds the devfreq.
11133d0407baSopenharmony_ci */
11143d0407baSopenharmony_ciint devfreq_resume_device(struct devfreq *devfreq)
11153d0407baSopenharmony_ci{
11163d0407baSopenharmony_ci    int ret;
11173d0407baSopenharmony_ci
11183d0407baSopenharmony_ci    if (!devfreq) {
11193d0407baSopenharmony_ci        return -EINVAL;
11203d0407baSopenharmony_ci    }
11213d0407baSopenharmony_ci
11223d0407baSopenharmony_ci    if (atomic_dec_return(&devfreq->suspend_count) >= 1) {
11233d0407baSopenharmony_ci        return 0;
11243d0407baSopenharmony_ci    }
11253d0407baSopenharmony_ci
11263d0407baSopenharmony_ci    if (devfreq->resume_freq) {
11273d0407baSopenharmony_ci        mutex_lock(&devfreq->lock);
11283d0407baSopenharmony_ci        ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
11293d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
11303d0407baSopenharmony_ci        if (ret) {
11313d0407baSopenharmony_ci            return ret;
11323d0407baSopenharmony_ci        }
11333d0407baSopenharmony_ci    }
11343d0407baSopenharmony_ci
11353d0407baSopenharmony_ci    if (devfreq->governor) {
11363d0407baSopenharmony_ci        ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_RESUME, NULL);
11373d0407baSopenharmony_ci        if (ret) {
11383d0407baSopenharmony_ci            return ret;
11393d0407baSopenharmony_ci        }
11403d0407baSopenharmony_ci    }
11413d0407baSopenharmony_ci
11423d0407baSopenharmony_ci    return 0;
11433d0407baSopenharmony_ci}
11443d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_resume_device);
11453d0407baSopenharmony_ci
11463d0407baSopenharmony_ci/**
11473d0407baSopenharmony_ci * devfreq_suspend() - Suspend devfreq governors and devices
11483d0407baSopenharmony_ci *
11493d0407baSopenharmony_ci * Called during system wide Suspend/Hibernate cycles for suspending governors
11503d0407baSopenharmony_ci * and devices preserving the state for resume. On some platforms the devfreq
11513d0407baSopenharmony_ci * device must have precise state (frequency) after resume in order to provide
11523d0407baSopenharmony_ci * fully operating setup.
11533d0407baSopenharmony_ci */
11543d0407baSopenharmony_civoid devfreq_suspend(void)
11553d0407baSopenharmony_ci{
11563d0407baSopenharmony_ci    struct devfreq *devfreq;
11573d0407baSopenharmony_ci    int ret;
11583d0407baSopenharmony_ci
11593d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
11603d0407baSopenharmony_ci    list_for_each_entry(devfreq, &devfreq_list, node)
11613d0407baSopenharmony_ci    {
11623d0407baSopenharmony_ci        ret = devfreq_suspend_device(devfreq);
11633d0407baSopenharmony_ci        if (ret) {
11643d0407baSopenharmony_ci            dev_err(&devfreq->dev, "failed to suspend devfreq device\n");
11653d0407baSopenharmony_ci        }
11663d0407baSopenharmony_ci    }
11673d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
11683d0407baSopenharmony_ci}
11693d0407baSopenharmony_ci
11703d0407baSopenharmony_ci/**
11713d0407baSopenharmony_ci * devfreq_resume() - Resume devfreq governors and devices
11723d0407baSopenharmony_ci *
11733d0407baSopenharmony_ci * Called during system wide Suspend/Hibernate cycle for resuming governors and
11743d0407baSopenharmony_ci * devices that are suspended with devfreq_suspend().
11753d0407baSopenharmony_ci */
11763d0407baSopenharmony_civoid devfreq_resume(void)
11773d0407baSopenharmony_ci{
11783d0407baSopenharmony_ci    struct devfreq *devfreq;
11793d0407baSopenharmony_ci    int ret;
11803d0407baSopenharmony_ci
11813d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
11823d0407baSopenharmony_ci    list_for_each_entry(devfreq, &devfreq_list, node)
11833d0407baSopenharmony_ci    {
11843d0407baSopenharmony_ci        ret = devfreq_resume_device(devfreq);
11853d0407baSopenharmony_ci        if (ret) {
11863d0407baSopenharmony_ci            dev_warn(&devfreq->dev, "failed to resume devfreq device\n");
11873d0407baSopenharmony_ci        }
11883d0407baSopenharmony_ci    }
11893d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
11903d0407baSopenharmony_ci}
11913d0407baSopenharmony_ci
11923d0407baSopenharmony_ci/**
11933d0407baSopenharmony_ci * devfreq_add_governor() - Add devfreq governor
11943d0407baSopenharmony_ci * @governor:    the devfreq governor to be added
11953d0407baSopenharmony_ci */
11963d0407baSopenharmony_ciint devfreq_add_governor(struct devfreq_governor *governor)
11973d0407baSopenharmony_ci{
11983d0407baSopenharmony_ci    struct devfreq_governor *g;
11993d0407baSopenharmony_ci    struct devfreq *devfreq;
12003d0407baSopenharmony_ci    int err = 0;
12013d0407baSopenharmony_ci
12023d0407baSopenharmony_ci    if (!governor) {
12033d0407baSopenharmony_ci        pr_err("%s: Invalid parameters.\n", __func__);
12043d0407baSopenharmony_ci        return -EINVAL;
12053d0407baSopenharmony_ci    }
12063d0407baSopenharmony_ci
12073d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
12083d0407baSopenharmony_ci    g = find_devfreq_governor(governor->name);
12093d0407baSopenharmony_ci    if (!IS_ERR(g)) {
12103d0407baSopenharmony_ci        pr_err("%s: governor %s already registered\n", __func__, g->name);
12113d0407baSopenharmony_ci        err = -EINVAL;
12123d0407baSopenharmony_ci        goto err_out;
12133d0407baSopenharmony_ci    }
12143d0407baSopenharmony_ci
12153d0407baSopenharmony_ci    list_add(&governor->node, &devfreq_governor_list);
12163d0407baSopenharmony_ci
12173d0407baSopenharmony_ci    list_for_each_entry(devfreq, &devfreq_list, node)
12183d0407baSopenharmony_ci    {
12193d0407baSopenharmony_ci        int ret = 0;
12203d0407baSopenharmony_ci        struct device *dev = devfreq->dev.parent;
12213d0407baSopenharmony_ci
12223d0407baSopenharmony_ci        if (!strncmp(devfreq->governor_name, governor->name, DEVFREQ_NAME_LEN)) {
12233d0407baSopenharmony_ci            /* The following should never occur */
12243d0407baSopenharmony_ci            if (devfreq->governor) {
12253d0407baSopenharmony_ci                dev_warn(dev, "%s: Governor %s already present\n", __func__, devfreq->governor->name);
12263d0407baSopenharmony_ci                ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
12273d0407baSopenharmony_ci                if (ret) {
12283d0407baSopenharmony_ci                    dev_warn(dev, "%s: Governor %s stop = %d\n", __func__, devfreq->governor->name, ret);
12293d0407baSopenharmony_ci                }
12303d0407baSopenharmony_ci                /* Fall through */
12313d0407baSopenharmony_ci            }
12323d0407baSopenharmony_ci            devfreq->governor = governor;
12333d0407baSopenharmony_ci            ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, NULL);
12343d0407baSopenharmony_ci            if (ret) {
12353d0407baSopenharmony_ci                dev_warn(dev, "%s: Governor %s start=%d\n", __func__, devfreq->governor->name, ret);
12363d0407baSopenharmony_ci            }
12373d0407baSopenharmony_ci        }
12383d0407baSopenharmony_ci    }
12393d0407baSopenharmony_ci
12403d0407baSopenharmony_cierr_out:
12413d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
12423d0407baSopenharmony_ci
12433d0407baSopenharmony_ci    return err;
12443d0407baSopenharmony_ci}
12453d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_add_governor);
12463d0407baSopenharmony_ci
12473d0407baSopenharmony_ci/**
12483d0407baSopenharmony_ci * devfreq_remove_governor() - Remove devfreq feature from a device.
12493d0407baSopenharmony_ci * @governor:    the devfreq governor to be removed
12503d0407baSopenharmony_ci */
12513d0407baSopenharmony_ciint devfreq_remove_governor(struct devfreq_governor *governor)
12523d0407baSopenharmony_ci{
12533d0407baSopenharmony_ci    struct devfreq_governor *g;
12543d0407baSopenharmony_ci    struct devfreq *devfreq;
12553d0407baSopenharmony_ci    int err = 0;
12563d0407baSopenharmony_ci
12573d0407baSopenharmony_ci    if (!governor) {
12583d0407baSopenharmony_ci        pr_err("%s: Invalid parameters.\n", __func__);
12593d0407baSopenharmony_ci        return -EINVAL;
12603d0407baSopenharmony_ci    }
12613d0407baSopenharmony_ci
12623d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
12633d0407baSopenharmony_ci    g = find_devfreq_governor(governor->name);
12643d0407baSopenharmony_ci    if (IS_ERR(g)) {
12653d0407baSopenharmony_ci        pr_err("%s: governor %s not registered\n", __func__, governor->name);
12663d0407baSopenharmony_ci        err = PTR_ERR(g);
12673d0407baSopenharmony_ci        goto err_out;
12683d0407baSopenharmony_ci    }
12693d0407baSopenharmony_ci    list_for_each_entry(devfreq, &devfreq_list, node)
12703d0407baSopenharmony_ci    {
12713d0407baSopenharmony_ci        int ret;
12723d0407baSopenharmony_ci        struct device *dev = devfreq->dev.parent;
12733d0407baSopenharmony_ci
12743d0407baSopenharmony_ci        if (!strncmp(devfreq->governor_name, governor->name, DEVFREQ_NAME_LEN)) {
12753d0407baSopenharmony_ci            /* we should have a devfreq governor! */
12763d0407baSopenharmony_ci            if (!devfreq->governor) {
12773d0407baSopenharmony_ci                dev_warn(dev, "%s: Governor %s NOT present\n", __func__, governor->name);
12783d0407baSopenharmony_ci                continue;
12793d0407baSopenharmony_ci                /* Fall through */
12803d0407baSopenharmony_ci            }
12813d0407baSopenharmony_ci            ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
12823d0407baSopenharmony_ci            if (ret) {
12833d0407baSopenharmony_ci                dev_warn(dev, "%s: Governor %s stop=%d\n", __func__, devfreq->governor->name, ret);
12843d0407baSopenharmony_ci            }
12853d0407baSopenharmony_ci            devfreq->governor = NULL;
12863d0407baSopenharmony_ci        }
12873d0407baSopenharmony_ci    }
12883d0407baSopenharmony_ci
12893d0407baSopenharmony_ci    list_del(&governor->node);
12903d0407baSopenharmony_cierr_out:
12913d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
12923d0407baSopenharmony_ci
12933d0407baSopenharmony_ci    return err;
12943d0407baSopenharmony_ci}
12953d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_remove_governor);
12963d0407baSopenharmony_ci
12973d0407baSopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
12983d0407baSopenharmony_ci{
12993d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
13003d0407baSopenharmony_ci    return sprintf(buf, "%s\n", dev_name(df->dev.parent));
13013d0407baSopenharmony_ci}
13023d0407baSopenharmony_cistatic DEVICE_ATTR_RO(name);
13033d0407baSopenharmony_ci
13043d0407baSopenharmony_cistatic ssize_t governor_show(struct device *dev, struct device_attribute *attr, char *buf)
13053d0407baSopenharmony_ci{
13063d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
13073d0407baSopenharmony_ci
13083d0407baSopenharmony_ci    if (!df->governor) {
13093d0407baSopenharmony_ci        return -EINVAL;
13103d0407baSopenharmony_ci    }
13113d0407baSopenharmony_ci
13123d0407baSopenharmony_ci    return sprintf(buf, "%s\n", df->governor->name);
13133d0407baSopenharmony_ci}
13143d0407baSopenharmony_ci
13153d0407baSopenharmony_cistatic ssize_t governor_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
13163d0407baSopenharmony_ci{
13173d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
13183d0407baSopenharmony_ci    int ret;
13193d0407baSopenharmony_ci    char str_governor[DEVFREQ_NAME_LEN + 1];
13203d0407baSopenharmony_ci    const struct devfreq_governor *governor, *prev_governor;
13213d0407baSopenharmony_ci
13223d0407baSopenharmony_ci    if (!df->governor) {
13233d0407baSopenharmony_ci        return -EINVAL;
13243d0407baSopenharmony_ci    }
13253d0407baSopenharmony_ci
13263d0407baSopenharmony_ci    ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
13273d0407baSopenharmony_ci    if (ret != 1) {
13283d0407baSopenharmony_ci        return -EINVAL;
13293d0407baSopenharmony_ci    }
13303d0407baSopenharmony_ci
13313d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
13323d0407baSopenharmony_ci    governor = try_then_request_governor(str_governor);
13333d0407baSopenharmony_ci    if (IS_ERR(governor)) {
13343d0407baSopenharmony_ci        ret = PTR_ERR(governor);
13353d0407baSopenharmony_ci        goto out;
13363d0407baSopenharmony_ci    }
13373d0407baSopenharmony_ci    if (df->governor == governor) {
13383d0407baSopenharmony_ci        ret = 0;
13393d0407baSopenharmony_ci        goto out;
13403d0407baSopenharmony_ci    } else if (df->governor->immutable || governor->immutable) {
13413d0407baSopenharmony_ci        ret = -EINVAL;
13423d0407baSopenharmony_ci        goto out;
13433d0407baSopenharmony_ci    }
13443d0407baSopenharmony_ci
13453d0407baSopenharmony_ci    ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
13463d0407baSopenharmony_ci    if (ret) {
13473d0407baSopenharmony_ci        dev_warn(dev, "%s: Governor %s not stopped(%d)\n", __func__, df->governor->name, ret);
13483d0407baSopenharmony_ci        goto out;
13493d0407baSopenharmony_ci    }
13503d0407baSopenharmony_ci
13513d0407baSopenharmony_ci    prev_governor = df->governor;
13523d0407baSopenharmony_ci    df->governor = governor;
13533d0407baSopenharmony_ci    strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
13543d0407baSopenharmony_ci    ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
13553d0407baSopenharmony_ci    if (ret) {
13563d0407baSopenharmony_ci        dev_warn(dev, "%s: Governor %s not started(%d)\n", __func__, df->governor->name, ret);
13573d0407baSopenharmony_ci        df->governor = prev_governor;
13583d0407baSopenharmony_ci        strncpy(df->governor_name, prev_governor->name, DEVFREQ_NAME_LEN);
13593d0407baSopenharmony_ci        ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
13603d0407baSopenharmony_ci        if (ret) {
13613d0407baSopenharmony_ci            dev_err(dev, "%s: reverting to Governor %s failed (%d)\n", __func__, df->governor_name, ret);
13623d0407baSopenharmony_ci            df->governor = NULL;
13633d0407baSopenharmony_ci        }
13643d0407baSopenharmony_ci    }
13653d0407baSopenharmony_ciout:
13663d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
13673d0407baSopenharmony_ci
13683d0407baSopenharmony_ci    if (!ret) {
13693d0407baSopenharmony_ci        ret = count;
13703d0407baSopenharmony_ci    }
13713d0407baSopenharmony_ci    return ret;
13723d0407baSopenharmony_ci}
13733d0407baSopenharmony_cistatic DEVICE_ATTR_RW(governor);
13743d0407baSopenharmony_ci
13753d0407baSopenharmony_cistatic ssize_t available_governors_show(struct device *d, struct device_attribute *attr, char *buf)
13763d0407baSopenharmony_ci{
13773d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(d);
13783d0407baSopenharmony_ci    ssize_t count = 0;
13793d0407baSopenharmony_ci
13803d0407baSopenharmony_ci    if (!df->governor) {
13813d0407baSopenharmony_ci        return -EINVAL;
13823d0407baSopenharmony_ci    }
13833d0407baSopenharmony_ci
13843d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
13853d0407baSopenharmony_ci
13863d0407baSopenharmony_ci    /*
13873d0407baSopenharmony_ci     * The devfreq with immutable governor (e.g., passive) shows
13883d0407baSopenharmony_ci     * only own governor.
13893d0407baSopenharmony_ci     */
13903d0407baSopenharmony_ci    if (df->governor->immutable) {
13913d0407baSopenharmony_ci        count = scnprintf(&buf[count], DEVFREQ_NAME_LEN, "%s ", df->governor_name);
13923d0407baSopenharmony_ci        /*
13933d0407baSopenharmony_ci         * The devfreq device shows the registered governor except for
13943d0407baSopenharmony_ci         * immutable governors such as passive governor .
13953d0407baSopenharmony_ci         */
13963d0407baSopenharmony_ci    } else {
13973d0407baSopenharmony_ci        struct devfreq_governor *governor;
13983d0407baSopenharmony_ci
13993d0407baSopenharmony_ci        list_for_each_entry(governor, &devfreq_governor_list, node)
14003d0407baSopenharmony_ci        {
14013d0407baSopenharmony_ci            if (governor->immutable) {
14023d0407baSopenharmony_ci                continue;
14033d0407baSopenharmony_ci            }
14043d0407baSopenharmony_ci            count += scnprintf(&buf[count], (PAGE_SIZE - count - 0x2), "%s ", governor->name);
14053d0407baSopenharmony_ci        }
14063d0407baSopenharmony_ci    }
14073d0407baSopenharmony_ci
14083d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
14093d0407baSopenharmony_ci
14103d0407baSopenharmony_ci    /* Truncate the trailing space */
14113d0407baSopenharmony_ci    if (count) {
14123d0407baSopenharmony_ci        count--;
14133d0407baSopenharmony_ci    }
14143d0407baSopenharmony_ci
14153d0407baSopenharmony_ci    count += sprintf(&buf[count], "\n");
14163d0407baSopenharmony_ci
14173d0407baSopenharmony_ci    return count;
14183d0407baSopenharmony_ci}
14193d0407baSopenharmony_cistatic DEVICE_ATTR_RO(available_governors);
14203d0407baSopenharmony_ci
14213d0407baSopenharmony_cistatic ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
14223d0407baSopenharmony_ci{
14233d0407baSopenharmony_ci    unsigned long freq;
14243d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
14253d0407baSopenharmony_ci
14263d0407baSopenharmony_ci    if (!df->profile) {
14273d0407baSopenharmony_ci        return -EINVAL;
14283d0407baSopenharmony_ci    }
14293d0407baSopenharmony_ci
14303d0407baSopenharmony_ci    if (df->profile->get_cur_freq && !df->profile->get_cur_freq(df->dev.parent, &freq)) {
14313d0407baSopenharmony_ci        return sprintf(buf, "%lu\n", freq);
14323d0407baSopenharmony_ci    }
14333d0407baSopenharmony_ci
14343d0407baSopenharmony_ci    return sprintf(buf, "%lu\n", df->previous_freq);
14353d0407baSopenharmony_ci}
14363d0407baSopenharmony_cistatic DEVICE_ATTR_RO(cur_freq);
14373d0407baSopenharmony_ci
14383d0407baSopenharmony_cistatic ssize_t target_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
14393d0407baSopenharmony_ci{
14403d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
14413d0407baSopenharmony_ci
14423d0407baSopenharmony_ci    return sprintf(buf, "%lu\n", df->previous_freq);
14433d0407baSopenharmony_ci}
14443d0407baSopenharmony_cistatic DEVICE_ATTR_RO(target_freq);
14453d0407baSopenharmony_ci
14463d0407baSopenharmony_cistatic ssize_t polling_interval_show(struct device *dev, struct device_attribute *attr, char *buf)
14473d0407baSopenharmony_ci{
14483d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
14493d0407baSopenharmony_ci
14503d0407baSopenharmony_ci    if (!df->profile) {
14513d0407baSopenharmony_ci        return -EINVAL;
14523d0407baSopenharmony_ci    }
14533d0407baSopenharmony_ci
14543d0407baSopenharmony_ci    return sprintf(buf, "%d\n", df->profile->polling_ms);
14553d0407baSopenharmony_ci}
14563d0407baSopenharmony_ci
14573d0407baSopenharmony_cistatic ssize_t polling_interval_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
14583d0407baSopenharmony_ci{
14593d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
14603d0407baSopenharmony_ci    unsigned int value;
14613d0407baSopenharmony_ci    int ret;
14623d0407baSopenharmony_ci
14633d0407baSopenharmony_ci    if (!df->governor) {
14643d0407baSopenharmony_ci        return -EINVAL;
14653d0407baSopenharmony_ci    }
14663d0407baSopenharmony_ci
14673d0407baSopenharmony_ci    ret = sscanf(buf, "%u", &value);
14683d0407baSopenharmony_ci    if (ret != 1) {
14693d0407baSopenharmony_ci        return -EINVAL;
14703d0407baSopenharmony_ci    }
14713d0407baSopenharmony_ci
14723d0407baSopenharmony_ci    df->governor->event_handler(df, DEVFREQ_GOV_UPDATE_INTERVAL, &value);
14733d0407baSopenharmony_ci    ret = count;
14743d0407baSopenharmony_ci
14753d0407baSopenharmony_ci    return ret;
14763d0407baSopenharmony_ci}
14773d0407baSopenharmony_cistatic DEVICE_ATTR_RW(polling_interval);
14783d0407baSopenharmony_ci
14793d0407baSopenharmony_cistatic ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
14803d0407baSopenharmony_ci{
14813d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
14823d0407baSopenharmony_ci    unsigned long value;
14833d0407baSopenharmony_ci    int ret;
14843d0407baSopenharmony_ci
14853d0407baSopenharmony_ci    /*
14863d0407baSopenharmony_ci     * Protect against theoretical sysfs writes between
14873d0407baSopenharmony_ci     * device_add and dev_pm_qos_add_request
14883d0407baSopenharmony_ci     */
14893d0407baSopenharmony_ci    if (!dev_pm_qos_request_active(&df->user_min_freq_req)) {
14903d0407baSopenharmony_ci        return -EAGAIN;
14913d0407baSopenharmony_ci    }
14923d0407baSopenharmony_ci
14933d0407baSopenharmony_ci    ret = sscanf(buf, "%lu", &value);
14943d0407baSopenharmony_ci    if (ret != 1) {
14953d0407baSopenharmony_ci        return -EINVAL;
14963d0407baSopenharmony_ci    }
14973d0407baSopenharmony_ci
14983d0407baSopenharmony_ci    /* Round down to kHz for PM QoS */
14993d0407baSopenharmony_ci    ret = dev_pm_qos_update_request(&df->user_min_freq_req, value / HZ_PER_KHZ);
15003d0407baSopenharmony_ci    if (ret < 0) {
15013d0407baSopenharmony_ci        return ret;
15023d0407baSopenharmony_ci    }
15033d0407baSopenharmony_ci
15043d0407baSopenharmony_ci    return count;
15053d0407baSopenharmony_ci}
15063d0407baSopenharmony_ci
15073d0407baSopenharmony_cistatic ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
15083d0407baSopenharmony_ci{
15093d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
15103d0407baSopenharmony_ci    unsigned long min_freq, max_freq;
15113d0407baSopenharmony_ci
15123d0407baSopenharmony_ci    mutex_lock(&df->lock);
15133d0407baSopenharmony_ci    get_freq_range(df, &min_freq, &max_freq);
15143d0407baSopenharmony_ci    mutex_unlock(&df->lock);
15153d0407baSopenharmony_ci
15163d0407baSopenharmony_ci    return sprintf(buf, "%lu\n", min_freq);
15173d0407baSopenharmony_ci}
15183d0407baSopenharmony_cistatic DEVICE_ATTR_RW(min_freq);
15193d0407baSopenharmony_ci
15203d0407baSopenharmony_cistatic ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
15213d0407baSopenharmony_ci{
15223d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
15233d0407baSopenharmony_ci    unsigned long value;
15243d0407baSopenharmony_ci    int ret;
15253d0407baSopenharmony_ci
15263d0407baSopenharmony_ci    /*
15273d0407baSopenharmony_ci     * Protect against theoretical sysfs writes between
15283d0407baSopenharmony_ci     * device_add and dev_pm_qos_add_request
15293d0407baSopenharmony_ci     */
15303d0407baSopenharmony_ci    if (!dev_pm_qos_request_active(&df->user_max_freq_req)) {
15313d0407baSopenharmony_ci        return -EINVAL;
15323d0407baSopenharmony_ci    }
15333d0407baSopenharmony_ci
15343d0407baSopenharmony_ci    ret = sscanf(buf, "%lu", &value);
15353d0407baSopenharmony_ci    if (ret != 1) {
15363d0407baSopenharmony_ci        return -EINVAL;
15373d0407baSopenharmony_ci    }
15383d0407baSopenharmony_ci
15393d0407baSopenharmony_ci    /*
15403d0407baSopenharmony_ci     * PM QoS frequencies are in kHz so we need to convert. Convert by
15413d0407baSopenharmony_ci     * rounding upwards so that the acceptable interval never shrinks.
15423d0407baSopenharmony_ci     *
15433d0407baSopenharmony_ci     * For example if the user writes "666666666" to sysfs this value will
15443d0407baSopenharmony_ci     * be converted to 666667 kHz and back to 666667000 Hz before an OPP
15453d0407baSopenharmony_ci     * lookup, this ensures that an OPP of 666666666Hz is still accepted.
15463d0407baSopenharmony_ci     *
15473d0407baSopenharmony_ci     * A value of zero means "no limit".
15483d0407baSopenharmony_ci     */
15493d0407baSopenharmony_ci    if (value) {
15503d0407baSopenharmony_ci        value = DIV_ROUND_UP(value, HZ_PER_KHZ);
15513d0407baSopenharmony_ci    } else {
15523d0407baSopenharmony_ci        value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
15533d0407baSopenharmony_ci    }
15543d0407baSopenharmony_ci
15553d0407baSopenharmony_ci    ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
15563d0407baSopenharmony_ci    if (ret < 0) {
15573d0407baSopenharmony_ci        return ret;
15583d0407baSopenharmony_ci    }
15593d0407baSopenharmony_ci
15603d0407baSopenharmony_ci    return count;
15613d0407baSopenharmony_ci}
15623d0407baSopenharmony_ci
15633d0407baSopenharmony_cistatic ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
15643d0407baSopenharmony_ci{
15653d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
15663d0407baSopenharmony_ci    unsigned long min_freq, max_freq;
15673d0407baSopenharmony_ci
15683d0407baSopenharmony_ci    mutex_lock(&df->lock);
15693d0407baSopenharmony_ci    get_freq_range(df, &min_freq, &max_freq);
15703d0407baSopenharmony_ci    mutex_unlock(&df->lock);
15713d0407baSopenharmony_ci
15723d0407baSopenharmony_ci    return sprintf(buf, "%lu\n", max_freq);
15733d0407baSopenharmony_ci}
15743d0407baSopenharmony_cistatic DEVICE_ATTR_RW(max_freq);
15753d0407baSopenharmony_ci
15763d0407baSopenharmony_cistatic ssize_t available_frequencies_show(struct device *d, struct device_attribute *attr, char *buf)
15773d0407baSopenharmony_ci{
15783d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(d);
15793d0407baSopenharmony_ci    ssize_t count = 0;
15803d0407baSopenharmony_ci    int i;
15813d0407baSopenharmony_ci
15823d0407baSopenharmony_ci    if (!df->profile) {
15833d0407baSopenharmony_ci        return -EINVAL;
15843d0407baSopenharmony_ci    }
15853d0407baSopenharmony_ci
15863d0407baSopenharmony_ci    mutex_lock(&df->lock);
15873d0407baSopenharmony_ci
15883d0407baSopenharmony_ci    for (i = 0; i < df->profile->max_state; i++) {
15893d0407baSopenharmony_ci        count += scnprintf(&buf[count], (PAGE_SIZE - count - 0x2), "%lu ", df->profile->freq_table[i]);
15903d0407baSopenharmony_ci    }
15913d0407baSopenharmony_ci
15923d0407baSopenharmony_ci    mutex_unlock(&df->lock);
15933d0407baSopenharmony_ci    /* Truncate the trailing space */
15943d0407baSopenharmony_ci    if (count) {
15953d0407baSopenharmony_ci        count--;
15963d0407baSopenharmony_ci    }
15973d0407baSopenharmony_ci
15983d0407baSopenharmony_ci    count += sprintf(&buf[count], "\n");
15993d0407baSopenharmony_ci
16003d0407baSopenharmony_ci    return count;
16013d0407baSopenharmony_ci}
16023d0407baSopenharmony_cistatic DEVICE_ATTR_RO(available_frequencies);
16033d0407baSopenharmony_ci
16043d0407baSopenharmony_cistatic ssize_t trans_stat_show(struct device *dev, struct device_attribute *attr, char *buf)
16053d0407baSopenharmony_ci{
16063d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
16073d0407baSopenharmony_ci    ssize_t len;
16083d0407baSopenharmony_ci    int i, j;
16093d0407baSopenharmony_ci    unsigned int max_state;
16103d0407baSopenharmony_ci
16113d0407baSopenharmony_ci    if (!df->profile) {
16123d0407baSopenharmony_ci        return -EINVAL;
16133d0407baSopenharmony_ci    }
16143d0407baSopenharmony_ci    max_state = df->profile->max_state;
16153d0407baSopenharmony_ci
16163d0407baSopenharmony_ci    if (max_state == 0) {
16173d0407baSopenharmony_ci        return sprintf(buf, "Not Supported.\n");
16183d0407baSopenharmony_ci    }
16193d0407baSopenharmony_ci
16203d0407baSopenharmony_ci    mutex_lock(&df->lock);
16213d0407baSopenharmony_ci    if (!df->stop_polling && devfreq_update_status(df, df->previous_freq)) {
16223d0407baSopenharmony_ci        mutex_unlock(&df->lock);
16233d0407baSopenharmony_ci        return 0;
16243d0407baSopenharmony_ci    }
16253d0407baSopenharmony_ci    mutex_unlock(&df->lock);
16263d0407baSopenharmony_ci
16273d0407baSopenharmony_ci    len = sprintf(buf, "     From  :   To\n");
16283d0407baSopenharmony_ci    len += sprintf(buf + len, "           :");
16293d0407baSopenharmony_ci    for (i = 0; i < max_state; i++) {
16303d0407baSopenharmony_ci        len += sprintf(buf + len, "%10lu", df->profile->freq_table[i]);
16313d0407baSopenharmony_ci    }
16323d0407baSopenharmony_ci
16333d0407baSopenharmony_ci    len += sprintf(buf + len, "   time(ms)\n");
16343d0407baSopenharmony_ci
16353d0407baSopenharmony_ci    for (i = 0; i < max_state; i++) {
16363d0407baSopenharmony_ci        if (df->profile->freq_table[i] == df->previous_freq) {
16373d0407baSopenharmony_ci            len += sprintf(buf + len, "*");
16383d0407baSopenharmony_ci        } else {
16393d0407baSopenharmony_ci            len += sprintf(buf + len, " ");
16403d0407baSopenharmony_ci        }
16413d0407baSopenharmony_ci        len += sprintf(buf + len, "%10lu:", df->profile->freq_table[i]);
16423d0407baSopenharmony_ci        for (j = 0; j < max_state; j++) {
16433d0407baSopenharmony_ci            len += sprintf(buf + len, "%10u", df->stats.trans_table[(i * max_state) + j]);
16443d0407baSopenharmony_ci        }
16453d0407baSopenharmony_ci
16463d0407baSopenharmony_ci        len += sprintf(buf + len, "%10llu\n", (u64)jiffies64_to_msecs(df->stats.time_in_state[i]));
16473d0407baSopenharmony_ci    }
16483d0407baSopenharmony_ci
16493d0407baSopenharmony_ci    len += sprintf(buf + len, "Total transition : %u\n", df->stats.total_trans);
16503d0407baSopenharmony_ci    return len;
16513d0407baSopenharmony_ci}
16523d0407baSopenharmony_ci
16533d0407baSopenharmony_cistatic ssize_t trans_stat_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
16543d0407baSopenharmony_ci{
16553d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
16563d0407baSopenharmony_ci    int err, value;
16573d0407baSopenharmony_ci
16583d0407baSopenharmony_ci    if (!df->profile) {
16593d0407baSopenharmony_ci        return -EINVAL;
16603d0407baSopenharmony_ci    }
16613d0407baSopenharmony_ci
16623d0407baSopenharmony_ci    if (df->profile->max_state == 0) {
16633d0407baSopenharmony_ci        return count;
16643d0407baSopenharmony_ci    }
16653d0407baSopenharmony_ci
16663d0407baSopenharmony_ci    err = kstrtoint(buf, 0xa, &value);
16673d0407baSopenharmony_ci    if (err || value != 0) {
16683d0407baSopenharmony_ci        return -EINVAL;
16693d0407baSopenharmony_ci    }
16703d0407baSopenharmony_ci
16713d0407baSopenharmony_ci    mutex_lock(&df->lock);
16723d0407baSopenharmony_ci    memset(df->stats.time_in_state, 0, (df->profile->max_state * sizeof(*df->stats.time_in_state)));
16733d0407baSopenharmony_ci    memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int), df->profile->max_state, df->profile->max_state));
16743d0407baSopenharmony_ci    df->stats.total_trans = 0;
16753d0407baSopenharmony_ci    df->stats.last_update = get_jiffies_64();
16763d0407baSopenharmony_ci    mutex_unlock(&df->lock);
16773d0407baSopenharmony_ci
16783d0407baSopenharmony_ci    return count;
16793d0407baSopenharmony_ci}
16803d0407baSopenharmony_cistatic DEVICE_ATTR_RW(trans_stat);
16813d0407baSopenharmony_ci
16823d0407baSopenharmony_cistatic ssize_t timer_show(struct device *dev, struct device_attribute *attr, char *buf)
16833d0407baSopenharmony_ci{
16843d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
16853d0407baSopenharmony_ci
16863d0407baSopenharmony_ci    if (!df->profile) {
16873d0407baSopenharmony_ci        return -EINVAL;
16883d0407baSopenharmony_ci    }
16893d0407baSopenharmony_ci
16903d0407baSopenharmony_ci    return sprintf(buf, "%s\n", timer_name[df->profile->timer]);
16913d0407baSopenharmony_ci}
16923d0407baSopenharmony_ci
16933d0407baSopenharmony_cistatic ssize_t timer_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
16943d0407baSopenharmony_ci{
16953d0407baSopenharmony_ci    struct devfreq *df = to_devfreq(dev);
16963d0407baSopenharmony_ci    char str_timer[DEVFREQ_NAME_LEN + 1];
16973d0407baSopenharmony_ci    int timer = -1;
16983d0407baSopenharmony_ci    int ret = 0, i;
16993d0407baSopenharmony_ci
17003d0407baSopenharmony_ci    if (!df->governor || !df->profile) {
17013d0407baSopenharmony_ci        return -EINVAL;
17023d0407baSopenharmony_ci    }
17033d0407baSopenharmony_ci
17043d0407baSopenharmony_ci    ret = sscanf(buf, "%16s", str_timer);
17053d0407baSopenharmony_ci    if (ret != 1) {
17063d0407baSopenharmony_ci        return -EINVAL;
17073d0407baSopenharmony_ci    }
17083d0407baSopenharmony_ci
17093d0407baSopenharmony_ci    for (i = 0; i < DEVFREQ_TIMER_NUM; i++) {
17103d0407baSopenharmony_ci        if (!strncmp(timer_name[i], str_timer, DEVFREQ_NAME_LEN)) {
17113d0407baSopenharmony_ci            timer = i;
17123d0407baSopenharmony_ci            break;
17133d0407baSopenharmony_ci        }
17143d0407baSopenharmony_ci    }
17153d0407baSopenharmony_ci
17163d0407baSopenharmony_ci    if (timer < 0) {
17173d0407baSopenharmony_ci        ret = -EINVAL;
17183d0407baSopenharmony_ci        goto out;
17193d0407baSopenharmony_ci    }
17203d0407baSopenharmony_ci
17213d0407baSopenharmony_ci    if (df->profile->timer == timer) {
17223d0407baSopenharmony_ci        ret = 0;
17233d0407baSopenharmony_ci        goto out;
17243d0407baSopenharmony_ci    }
17253d0407baSopenharmony_ci
17263d0407baSopenharmony_ci    mutex_lock(&df->lock);
17273d0407baSopenharmony_ci    df->profile->timer = timer;
17283d0407baSopenharmony_ci    mutex_unlock(&df->lock);
17293d0407baSopenharmony_ci
17303d0407baSopenharmony_ci    ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
17313d0407baSopenharmony_ci    if (ret) {
17323d0407baSopenharmony_ci        dev_warn(dev, "%s: Governor %s not stopped(%d)\n", __func__, df->governor->name, ret);
17333d0407baSopenharmony_ci        goto out;
17343d0407baSopenharmony_ci    }
17353d0407baSopenharmony_ci
17363d0407baSopenharmony_ci    ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
17373d0407baSopenharmony_ci    if (ret) {
17383d0407baSopenharmony_ci        dev_warn(dev, "%s: Governor %s not started(%d)\n", __func__, df->governor->name, ret);
17393d0407baSopenharmony_ci    }
17403d0407baSopenharmony_ciout:
17413d0407baSopenharmony_ci    return ret ? ret : count;
17423d0407baSopenharmony_ci}
17433d0407baSopenharmony_cistatic DEVICE_ATTR_RW(timer);
17443d0407baSopenharmony_ci
17453d0407baSopenharmony_cistatic ssize_t load_show(struct device *dev, struct device_attribute *attr, char *buf)
17463d0407baSopenharmony_ci{
17473d0407baSopenharmony_ci    int err;
17483d0407baSopenharmony_ci    struct devfreq *devfreq = to_devfreq(dev);
17493d0407baSopenharmony_ci    struct devfreq_dev_status stat = devfreq->last_status;
17503d0407baSopenharmony_ci    unsigned long freq;
17513d0407baSopenharmony_ci    ssize_t len;
17523d0407baSopenharmony_ci
17533d0407baSopenharmony_ci    err = devfreq_update_stats(devfreq);
17543d0407baSopenharmony_ci    if (err) {
17553d0407baSopenharmony_ci        return err;
17563d0407baSopenharmony_ci    }
17573d0407baSopenharmony_ci
17583d0407baSopenharmony_ci    if (stat.total_time < stat.busy_time) {
17593d0407baSopenharmony_ci        err = devfreq_update_stats(devfreq);
17603d0407baSopenharmony_ci        if (err) {
17613d0407baSopenharmony_ci            return err;
17623d0407baSopenharmony_ci        }
17633d0407baSopenharmony_ci    };
17643d0407baSopenharmony_ci
17653d0407baSopenharmony_ci    if (!stat.total_time) {
17663d0407baSopenharmony_ci        return 0;
17673d0407baSopenharmony_ci    }
17683d0407baSopenharmony_ci
17693d0407baSopenharmony_ci    len = sprintf(buf, "%lu", stat.busy_time * 0x64 / stat.total_time);
17703d0407baSopenharmony_ci
17713d0407baSopenharmony_ci    if (devfreq->profile->get_cur_freq && !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) {
17723d0407baSopenharmony_ci        len += sprintf(buf + len, "@%luHz\n", freq);
17733d0407baSopenharmony_ci    } else {
17743d0407baSopenharmony_ci        len += sprintf(buf + len, "@%luHz\n", devfreq->previous_freq);
17753d0407baSopenharmony_ci    }
17763d0407baSopenharmony_ci
17773d0407baSopenharmony_ci    return len;
17783d0407baSopenharmony_ci}
17793d0407baSopenharmony_cistatic DEVICE_ATTR_RO(load);
17803d0407baSopenharmony_ci
17813d0407baSopenharmony_cistatic struct attribute *devfreq_attrs[] = {
17823d0407baSopenharmony_ci    &dev_attr_name.attr,
17833d0407baSopenharmony_ci    &dev_attr_governor.attr,
17843d0407baSopenharmony_ci    &dev_attr_available_governors.attr,
17853d0407baSopenharmony_ci    &dev_attr_cur_freq.attr,
17863d0407baSopenharmony_ci    &dev_attr_available_frequencies.attr,
17873d0407baSopenharmony_ci    &dev_attr_target_freq.attr,
17883d0407baSopenharmony_ci    &dev_attr_polling_interval.attr,
17893d0407baSopenharmony_ci    &dev_attr_min_freq.attr,
17903d0407baSopenharmony_ci    &dev_attr_max_freq.attr,
17913d0407baSopenharmony_ci    &dev_attr_trans_stat.attr,
17923d0407baSopenharmony_ci    &dev_attr_timer.attr,
17933d0407baSopenharmony_ci    &dev_attr_load.attr,
17943d0407baSopenharmony_ci    NULL,
17953d0407baSopenharmony_ci};
17963d0407baSopenharmony_ciATTRIBUTE_GROUPS(devfreq);
17973d0407baSopenharmony_ci
17983d0407baSopenharmony_ci/**
17993d0407baSopenharmony_ci * devfreq_summary_show() - Show the summary of the devfreq devices
18003d0407baSopenharmony_ci * @s:        seq_file instance to show the summary of devfreq devices
18013d0407baSopenharmony_ci * @data:    not used
18023d0407baSopenharmony_ci *
18033d0407baSopenharmony_ci * Show the summary of the devfreq devices via 'devfreq_summary' debugfs file.
18043d0407baSopenharmony_ci * It helps that user can know the detailed information of the devfreq devices.
18053d0407baSopenharmony_ci *
18063d0407baSopenharmony_ci * Return 0 always because it shows the information without any data change.
18073d0407baSopenharmony_ci */
18083d0407baSopenharmony_cistatic int devfreq_summary_show(struct seq_file *s, void *data)
18093d0407baSopenharmony_ci{
18103d0407baSopenharmony_ci    struct devfreq *devfreq;
18113d0407baSopenharmony_ci    struct devfreq *p_devfreq = NULL;
18123d0407baSopenharmony_ci    unsigned long cur_freq, min_freq, max_freq;
18133d0407baSopenharmony_ci    unsigned int polling_ms;
18143d0407baSopenharmony_ci    unsigned int timer;
18153d0407baSopenharmony_ci
18163d0407baSopenharmony_ci    seq_printf(s, "%-30s %-30s %-15s %-10s %10s %12s %12s %12s\n", "dev", "parent_dev", "governor", "timer",
18173d0407baSopenharmony_ci               "polling_ms", "cur_freq_Hz", "min_freq_Hz", "max_freq_Hz");
18183d0407baSopenharmony_ci    seq_printf(s, "%30s %30s %15s %10s %10s %12s %12s %12s\n", "------------------------------",
18193d0407baSopenharmony_ci               "------------------------------", "---------------", "----------", "----------", "------------",
18203d0407baSopenharmony_ci               "------------", "------------");
18213d0407baSopenharmony_ci
18223d0407baSopenharmony_ci    mutex_lock(&devfreq_list_lock);
18233d0407baSopenharmony_ci
18243d0407baSopenharmony_ci    list_for_each_entry_reverse(devfreq, &devfreq_list, node)
18253d0407baSopenharmony_ci    {
18263d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
18273d0407baSopenharmony_ci        if (!strncmp(devfreq->governor_name, DEVFREQ_GOV_PASSIVE, DEVFREQ_NAME_LEN)) {
18283d0407baSopenharmony_ci            struct devfreq_passive_data *data = devfreq->data;
18293d0407baSopenharmony_ci
18303d0407baSopenharmony_ci            if (data) {
18313d0407baSopenharmony_ci                p_devfreq = data->parent;
18323d0407baSopenharmony_ci            }
18333d0407baSopenharmony_ci        } else {
18343d0407baSopenharmony_ci            p_devfreq = NULL;
18353d0407baSopenharmony_ci        }
18363d0407baSopenharmony_ci#endif
18373d0407baSopenharmony_ci
18383d0407baSopenharmony_ci        mutex_lock(&devfreq->lock);
18393d0407baSopenharmony_ci        cur_freq = devfreq->previous_freq;
18403d0407baSopenharmony_ci        get_freq_range(devfreq, &min_freq, &max_freq);
18413d0407baSopenharmony_ci        polling_ms = devfreq->profile->polling_ms;
18423d0407baSopenharmony_ci        timer = devfreq->profile->timer;
18433d0407baSopenharmony_ci        mutex_unlock(&devfreq->lock);
18443d0407baSopenharmony_ci
18453d0407baSopenharmony_ci        seq_printf(s, "%-30s %-30s %-15s %-10s %10d %12ld %12ld %12ld\n", dev_name(&devfreq->dev),
18463d0407baSopenharmony_ci                   p_devfreq ? dev_name(&p_devfreq->dev) : "null", devfreq->governor_name,
18473d0407baSopenharmony_ci                   polling_ms ? timer_name[timer] : "null", polling_ms, cur_freq, min_freq, max_freq);
18483d0407baSopenharmony_ci    }
18493d0407baSopenharmony_ci
18503d0407baSopenharmony_ci    mutex_unlock(&devfreq_list_lock);
18513d0407baSopenharmony_ci
18523d0407baSopenharmony_ci    return 0;
18533d0407baSopenharmony_ci}
18543d0407baSopenharmony_ciDEFINE_SHOW_ATTRIBUTE(devfreq_summary);
18553d0407baSopenharmony_ci
18563d0407baSopenharmony_cistatic int __init devfreq_init(void)
18573d0407baSopenharmony_ci{
18583d0407baSopenharmony_ci    devfreq_class = class_create(THIS_MODULE, "devfreq");
18593d0407baSopenharmony_ci    if (IS_ERR(devfreq_class)) {
18603d0407baSopenharmony_ci        pr_err("%s: couldn't create class\n", __FILE__);
18613d0407baSopenharmony_ci        return PTR_ERR(devfreq_class);
18623d0407baSopenharmony_ci    }
18633d0407baSopenharmony_ci
18643d0407baSopenharmony_ci    devfreq_wq = create_freezable_workqueue("devfreq_wq");
18653d0407baSopenharmony_ci    if (!devfreq_wq) {
18663d0407baSopenharmony_ci        class_destroy(devfreq_class);
18673d0407baSopenharmony_ci        pr_err("%s: couldn't create workqueue\n", __FILE__);
18683d0407baSopenharmony_ci        return -ENOMEM;
18693d0407baSopenharmony_ci    }
18703d0407baSopenharmony_ci    devfreq_class->dev_groups = devfreq_groups;
18713d0407baSopenharmony_ci
18723d0407baSopenharmony_ci    devfreq_debugfs = debugfs_create_dir("devfreq", NULL);
18733d0407baSopenharmony_ci    debugfs_create_file("devfreq_summary", 0444, devfreq_debugfs, NULL, &devfreq_summary_fops);
18743d0407baSopenharmony_ci
18753d0407baSopenharmony_ci    return 0;
18763d0407baSopenharmony_ci}
18773d0407baSopenharmony_cisubsys_initcall(devfreq_init);
18783d0407baSopenharmony_ci
18793d0407baSopenharmony_ci/*
18803d0407baSopenharmony_ci * The following are helper functions for devfreq user device drivers with
18813d0407baSopenharmony_ci * OPP framework.
18823d0407baSopenharmony_ci */
18833d0407baSopenharmony_ci
18843d0407baSopenharmony_ci/**
18853d0407baSopenharmony_ci * devfreq_recommended_opp() - Helper function to get proper OPP for the
18863d0407baSopenharmony_ci *                 freq value given to target callback.
18873d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
18883d0407baSopenharmony_ci * @freq:    The frequency given to target function
18893d0407baSopenharmony_ci * @flags:    Flags handed from devfreq framework.
18903d0407baSopenharmony_ci *
18913d0407baSopenharmony_ci * The callers are required to call dev_pm_opp_put() for the returned OPP after
18923d0407baSopenharmony_ci * use.
18933d0407baSopenharmony_ci */
18943d0407baSopenharmony_cistruct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags)
18953d0407baSopenharmony_ci{
18963d0407baSopenharmony_ci    struct dev_pm_opp *opp;
18973d0407baSopenharmony_ci
18983d0407baSopenharmony_ci    if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
18993d0407baSopenharmony_ci        /* The freq is an upper bound. opp should be lower */
19003d0407baSopenharmony_ci        opp = dev_pm_opp_find_freq_floor(dev, freq);
19013d0407baSopenharmony_ci        /* If not available, use the closest opp */
19023d0407baSopenharmony_ci        if (opp == ERR_PTR(-ERANGE)) {
19033d0407baSopenharmony_ci            opp = dev_pm_opp_find_freq_ceil(dev, freq);
19043d0407baSopenharmony_ci        }
19053d0407baSopenharmony_ci    } else {
19063d0407baSopenharmony_ci        /* The freq is an lower bound. opp should be higher */
19073d0407baSopenharmony_ci        opp = dev_pm_opp_find_freq_ceil(dev, freq);
19083d0407baSopenharmony_ci        /* If not available, use the closest opp */
19093d0407baSopenharmony_ci        if (opp == ERR_PTR(-ERANGE)) {
19103d0407baSopenharmony_ci            opp = dev_pm_opp_find_freq_floor(dev, freq);
19113d0407baSopenharmony_ci        }
19123d0407baSopenharmony_ci    }
19133d0407baSopenharmony_ci
19143d0407baSopenharmony_ci    return opp;
19153d0407baSopenharmony_ci}
19163d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_recommended_opp);
19173d0407baSopenharmony_ci
19183d0407baSopenharmony_ci/**
19193d0407baSopenharmony_ci * devfreq_register_opp_notifier() - Helper function to get devfreq notified
19203d0407baSopenharmony_ci *                     for any changes in the OPP availability
19213d0407baSopenharmony_ci *                     changes
19223d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
19233d0407baSopenharmony_ci * @devfreq:    The devfreq object.
19243d0407baSopenharmony_ci */
19253d0407baSopenharmony_ciint devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
19263d0407baSopenharmony_ci{
19273d0407baSopenharmony_ci    return dev_pm_opp_register_notifier(dev, &devfreq->nb);
19283d0407baSopenharmony_ci}
19293d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_register_opp_notifier);
19303d0407baSopenharmony_ci
19313d0407baSopenharmony_ci/**
19323d0407baSopenharmony_ci * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
19333d0407baSopenharmony_ci *                       notified for any changes in the OPP
19343d0407baSopenharmony_ci *                       availability changes anymore.
19353d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
19363d0407baSopenharmony_ci * @devfreq:    The devfreq object.
19373d0407baSopenharmony_ci *
19383d0407baSopenharmony_ci * At exit() callback of devfreq_dev_profile, this must be included if
19393d0407baSopenharmony_ci * devfreq_recommended_opp is used.
19403d0407baSopenharmony_ci */
19413d0407baSopenharmony_ciint devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
19423d0407baSopenharmony_ci{
19433d0407baSopenharmony_ci    return dev_pm_opp_unregister_notifier(dev, &devfreq->nb);
19443d0407baSopenharmony_ci}
19453d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_unregister_opp_notifier);
19463d0407baSopenharmony_ci
19473d0407baSopenharmony_cistatic void devm_devfreq_opp_release(struct device *dev, void *res)
19483d0407baSopenharmony_ci{
19493d0407baSopenharmony_ci    devfreq_unregister_opp_notifier(dev, *(struct devfreq **)res);
19503d0407baSopenharmony_ci}
19513d0407baSopenharmony_ci
19523d0407baSopenharmony_ci/**
19533d0407baSopenharmony_ci * devm_devfreq_register_opp_notifier() - Resource-managed
19543d0407baSopenharmony_ci *                      devfreq_register_opp_notifier()
19553d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
19563d0407baSopenharmony_ci * @devfreq:    The devfreq object.
19573d0407baSopenharmony_ci */
19583d0407baSopenharmony_ciint devm_devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
19593d0407baSopenharmony_ci{
19603d0407baSopenharmony_ci    struct devfreq **ptr;
19613d0407baSopenharmony_ci    int ret;
19623d0407baSopenharmony_ci
19633d0407baSopenharmony_ci    ptr = devres_alloc(devm_devfreq_opp_release, sizeof(*ptr), GFP_KERNEL);
19643d0407baSopenharmony_ci    if (!ptr) {
19653d0407baSopenharmony_ci        return -ENOMEM;
19663d0407baSopenharmony_ci    }
19673d0407baSopenharmony_ci
19683d0407baSopenharmony_ci    ret = devfreq_register_opp_notifier(dev, devfreq);
19693d0407baSopenharmony_ci    if (ret) {
19703d0407baSopenharmony_ci        devres_free(ptr);
19713d0407baSopenharmony_ci        return ret;
19723d0407baSopenharmony_ci    }
19733d0407baSopenharmony_ci
19743d0407baSopenharmony_ci    *ptr = devfreq;
19753d0407baSopenharmony_ci    devres_add(dev, ptr);
19763d0407baSopenharmony_ci
19773d0407baSopenharmony_ci    return 0;
19783d0407baSopenharmony_ci}
19793d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_register_opp_notifier);
19803d0407baSopenharmony_ci
19813d0407baSopenharmony_ci/**
19823d0407baSopenharmony_ci * devm_devfreq_unregister_opp_notifier() - Resource-managed
19833d0407baSopenharmony_ci *                        devfreq_unregister_opp_notifier()
19843d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
19853d0407baSopenharmony_ci * @devfreq:    The devfreq object.
19863d0407baSopenharmony_ci */
19873d0407baSopenharmony_civoid devm_devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
19883d0407baSopenharmony_ci{
19893d0407baSopenharmony_ci    WARN_ON(devres_release(dev, devm_devfreq_opp_release, devm_devfreq_dev_match, devfreq));
19903d0407baSopenharmony_ci}
19913d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
19923d0407baSopenharmony_ci
19933d0407baSopenharmony_ci/**
19943d0407baSopenharmony_ci * devfreq_register_notifier() - Register a driver with devfreq
19953d0407baSopenharmony_ci * @devfreq:    The devfreq object.
19963d0407baSopenharmony_ci * @nb:        The notifier block to register.
19973d0407baSopenharmony_ci * @list:    DEVFREQ_TRANSITION_NOTIFIER.
19983d0407baSopenharmony_ci */
19993d0407baSopenharmony_ciint devfreq_register_notifier(struct devfreq *devfreq, struct notifier_block *nb, unsigned int list)
20003d0407baSopenharmony_ci{
20013d0407baSopenharmony_ci    int ret = 0;
20023d0407baSopenharmony_ci
20033d0407baSopenharmony_ci    if (!devfreq) {
20043d0407baSopenharmony_ci        return -EINVAL;
20053d0407baSopenharmony_ci    }
20063d0407baSopenharmony_ci
20073d0407baSopenharmony_ci    switch (list) {
20083d0407baSopenharmony_ci        case DEVFREQ_TRANSITION_NOTIFIER:
20093d0407baSopenharmony_ci            ret = srcu_notifier_chain_register(&devfreq->transition_notifier_list, nb);
20103d0407baSopenharmony_ci            break;
20113d0407baSopenharmony_ci        default:
20123d0407baSopenharmony_ci            ret = -EINVAL;
20133d0407baSopenharmony_ci    }
20143d0407baSopenharmony_ci
20153d0407baSopenharmony_ci    return ret;
20163d0407baSopenharmony_ci}
20173d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_register_notifier);
20183d0407baSopenharmony_ci
20193d0407baSopenharmony_ci/*
20203d0407baSopenharmony_ci * devfreq_unregister_notifier() - Unregister a driver with devfreq
20213d0407baSopenharmony_ci * @devfreq:    The devfreq object.
20223d0407baSopenharmony_ci * @nb:        The notifier block to be unregistered.
20233d0407baSopenharmony_ci * @list:    DEVFREQ_TRANSITION_NOTIFIER.
20243d0407baSopenharmony_ci */
20253d0407baSopenharmony_ciint devfreq_unregister_notifier(struct devfreq *devfreq, struct notifier_block *nb, unsigned int list)
20263d0407baSopenharmony_ci{
20273d0407baSopenharmony_ci    int ret = 0;
20283d0407baSopenharmony_ci
20293d0407baSopenharmony_ci    if (!devfreq) {
20303d0407baSopenharmony_ci        return -EINVAL;
20313d0407baSopenharmony_ci    }
20323d0407baSopenharmony_ci
20333d0407baSopenharmony_ci    switch (list) {
20343d0407baSopenharmony_ci        case DEVFREQ_TRANSITION_NOTIFIER:
20353d0407baSopenharmony_ci            ret = srcu_notifier_chain_unregister(&devfreq->transition_notifier_list, nb);
20363d0407baSopenharmony_ci            break;
20373d0407baSopenharmony_ci        default:
20383d0407baSopenharmony_ci            ret = -EINVAL;
20393d0407baSopenharmony_ci    }
20403d0407baSopenharmony_ci
20413d0407baSopenharmony_ci    return ret;
20423d0407baSopenharmony_ci}
20433d0407baSopenharmony_ciEXPORT_SYMBOL(devfreq_unregister_notifier);
20443d0407baSopenharmony_ci
20453d0407baSopenharmony_cistruct devfreq_notifier_devres {
20463d0407baSopenharmony_ci    struct devfreq *devfreq;
20473d0407baSopenharmony_ci    struct notifier_block *nb;
20483d0407baSopenharmony_ci    unsigned int list;
20493d0407baSopenharmony_ci};
20503d0407baSopenharmony_ci
20513d0407baSopenharmony_cistatic void devm_devfreq_notifier_release(struct device *dev, void *res)
20523d0407baSopenharmony_ci{
20533d0407baSopenharmony_ci    struct devfreq_notifier_devres *this = res;
20543d0407baSopenharmony_ci
20553d0407baSopenharmony_ci    devfreq_unregister_notifier(this->devfreq, this->nb, this->list);
20563d0407baSopenharmony_ci}
20573d0407baSopenharmony_ci
20583d0407baSopenharmony_ci/**
20593d0407baSopenharmony_ci * devm_devfreq_register_notifier()
20603d0407baSopenharmony_ci *    - Resource-managed devfreq_register_notifier()
20613d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
20623d0407baSopenharmony_ci * @devfreq:    The devfreq object.
20633d0407baSopenharmony_ci * @nb:        The notifier block to be unregistered.
20643d0407baSopenharmony_ci * @list:    DEVFREQ_TRANSITION_NOTIFIER.
20653d0407baSopenharmony_ci */
20663d0407baSopenharmony_ciint devm_devfreq_register_notifier(struct device *dev, struct devfreq *devfreq, struct notifier_block *nb,
20673d0407baSopenharmony_ci                                   unsigned int list)
20683d0407baSopenharmony_ci{
20693d0407baSopenharmony_ci    struct devfreq_notifier_devres *ptr;
20703d0407baSopenharmony_ci    int ret;
20713d0407baSopenharmony_ci
20723d0407baSopenharmony_ci    ptr = devres_alloc(devm_devfreq_notifier_release, sizeof(*ptr), GFP_KERNEL);
20733d0407baSopenharmony_ci    if (!ptr) {
20743d0407baSopenharmony_ci        return -ENOMEM;
20753d0407baSopenharmony_ci    }
20763d0407baSopenharmony_ci
20773d0407baSopenharmony_ci    ret = devfreq_register_notifier(devfreq, nb, list);
20783d0407baSopenharmony_ci    if (ret) {
20793d0407baSopenharmony_ci        devres_free(ptr);
20803d0407baSopenharmony_ci        return ret;
20813d0407baSopenharmony_ci    }
20823d0407baSopenharmony_ci
20833d0407baSopenharmony_ci    ptr->devfreq = devfreq;
20843d0407baSopenharmony_ci    ptr->nb = nb;
20853d0407baSopenharmony_ci    ptr->list = list;
20863d0407baSopenharmony_ci    devres_add(dev, ptr);
20873d0407baSopenharmony_ci
20883d0407baSopenharmony_ci    return 0;
20893d0407baSopenharmony_ci}
20903d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_register_notifier);
20913d0407baSopenharmony_ci
20923d0407baSopenharmony_ci/**
20933d0407baSopenharmony_ci * devm_devfreq_unregister_notifier()
20943d0407baSopenharmony_ci *    - Resource-managed devfreq_unregister_notifier()
20953d0407baSopenharmony_ci * @dev:    The devfreq user device. (parent of devfreq)
20963d0407baSopenharmony_ci * @devfreq:    The devfreq object.
20973d0407baSopenharmony_ci * @nb:        The notifier block to be unregistered.
20983d0407baSopenharmony_ci * @list:    DEVFREQ_TRANSITION_NOTIFIER.
20993d0407baSopenharmony_ci */
21003d0407baSopenharmony_civoid devm_devfreq_unregister_notifier(struct device *dev, struct devfreq *devfreq, struct notifier_block *nb,
21013d0407baSopenharmony_ci                                      unsigned int list)
21023d0407baSopenharmony_ci{
21033d0407baSopenharmony_ci    WARN_ON(devres_release(dev, devm_devfreq_notifier_release, devm_devfreq_dev_match, devfreq));
21043d0407baSopenharmony_ci}
21053d0407baSopenharmony_ciEXPORT_SYMBOL(devm_devfreq_unregister_notifier);
2106