Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / devfreq: Add sysfs node to expose available frequencies

devfreq governors such as ondemand are controlled by a min and
max frequency, while governors like userspace governor allow us
to set a specific frequency.
However, for the same specific device, depending on the SoC, the
available frequencies can vary.

So expose the available frequencies as a snapshot over sysfs to
allow informed decisions.

This was inspired by cpufreq framework's equivalent for similar
usage sysfs node: scaling_available_frequencies.

Cc: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Kevin Hilman <khilman@ti.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>

authored by

Nishanth Menon and committed by
MyungJoo Ham
d287de85 e09651fc

+41
+9
Documentation/ABI/testing/sysfs-class-devfreq
··· 51 51 The /sys/class/devfreq/.../userspace/set_freq shows and 52 52 sets the requested frequency for the devfreq object if 53 53 userspace governor is in effect. 54 + 55 + What: /sys/class/devfreq/.../available_frequencies 56 + Date: October 2012 57 + Contact: Nishanth Menon <nm@ti.com> 58 + Description: 59 + The /sys/class/devfreq/.../available_frequencies shows 60 + the available frequencies of the corresponding devfreq object. 61 + This is a snapshot of available frequencies and not limited 62 + by the min/max frequency restrictions.
+32
drivers/devfreq/devfreq.c
··· 570 570 return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); 571 571 } 572 572 573 + static ssize_t show_available_freqs(struct device *d, 574 + struct device_attribute *attr, 575 + char *buf) 576 + { 577 + struct devfreq *df = to_devfreq(d); 578 + struct device *dev = df->dev.parent; 579 + struct opp *opp; 580 + ssize_t count = 0; 581 + unsigned long freq = 0; 582 + 583 + rcu_read_lock(); 584 + do { 585 + opp = opp_find_freq_ceil(dev, &freq); 586 + if (IS_ERR(opp)) 587 + break; 588 + 589 + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), 590 + "%lu ", freq); 591 + freq++; 592 + } while (1); 593 + rcu_read_unlock(); 594 + 595 + /* Truncate the trailing space */ 596 + if (count) 597 + count--; 598 + 599 + count += sprintf(&buf[count], "\n"); 600 + 601 + return count; 602 + } 603 + 573 604 static struct device_attribute devfreq_attrs[] = { 574 605 __ATTR(governor, S_IRUGO, show_governor, NULL), 575 606 __ATTR(cur_freq, S_IRUGO, show_freq, NULL), 607 + __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL), 576 608 __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), 577 609 __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, 578 610 store_polling_interval),