The existing {min|max}_freq_store() only check the range of
entered frequency. If the unsupported frequency is entered
and the entered frequency is within the ranges, {min|max}_freq_store()
will store it to devfreq->{min|max}_freq. And then when some user
try to read the {min|max}_freq, the devfreq show the unsupported
frequency value.

In order to fix this issue, this patch checks whether the entered
frequency is supported or not by OPP interface.

Signed-off-by: Chanwoo Choi <cw00.c...@samsung.com>
---
 drivers/devfreq/devfreq.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 56f8a0473834..f10017fe400f 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -97,6 +97,25 @@ static unsigned long find_available_max_freq(struct devfreq 
*devfreq)
        return max_freq;
 }
 
+static int is_supported_freq(struct devfreq *devfreq, unsigned long freq)
+{
+       struct device *dev = devfreq->dev.parent;
+       struct dev_pm_opp *opp;
+       int ret = 0;
+
+       /* Check whether entered frequency is supported or not */
+       opp = dev_pm_opp_find_freq_exact(dev, freq, true);
+       if (PTR_ERR(opp) == -ERANGE)
+               opp = dev_pm_opp_find_freq_exact(dev, freq, false);
+
+       if (IS_ERR(opp))
+               ret = PTR_ERR(opp);
+
+       dev_pm_opp_put(opp);
+
+       return ret;
+}
+
 /**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:   the devfreq instance
@@ -1099,9 +1118,8 @@ static ssize_t min_freq_store(struct device *dev, struct 
device_attribute *attr,
                              const char *buf, size_t count)
 {
        struct devfreq *df = to_devfreq(dev);
-       unsigned long value;
+       unsigned long value, max;
        int ret;
-       unsigned long max;
 
        ret = sscanf(buf, "%lu", &value);
        if (ret != 1)
@@ -1114,6 +1132,11 @@ static ssize_t min_freq_store(struct device *dev, struct 
device_attribute *attr,
                goto unlock;
        }
 
+       /* Check whether entered frequency is supported or not */
+       ret = is_supported_freq(df, value);
+       if (ret < 0)
+               goto unlock;
+
        df->min_freq = value;
        update_devfreq(df);
        ret = count;
@@ -1126,9 +1149,8 @@ static ssize_t max_freq_store(struct device *dev, struct 
device_attribute *attr,
                              const char *buf, size_t count)
 {
        struct devfreq *df = to_devfreq(dev);
-       unsigned long value;
+       unsigned long value, min;
        int ret;
-       unsigned long min;
 
        ret = sscanf(buf, "%lu", &value);
        if (ret != 1)
@@ -1141,6 +1163,11 @@ static ssize_t max_freq_store(struct device *dev, struct 
device_attribute *attr,
                goto unlock;
        }
 
+       /* Check whether entered frequency is supported or not */
+       ret = is_supported_freq(df, value);
+       if (ret < 0)
+               goto unlock;
+
        df->max_freq = value;
        update_devfreq(df);
        ret = count;
-- 
1.9.1

Reply via email to