aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/devfreq.c
diff options
context:
space:
mode:
authorJonghwa Lee <jonghwa3.lee@samsung.com>2012-08-23 07:00:46 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2012-11-20 02:05:44 -0500
commite552bbaf5b987f57c43e6981a452b8a3c700b1ae (patch)
treed48111ab3d5c71ea4ed9e8ae3cb7bfb32b06bdec /drivers/devfreq/devfreq.c
parentd287de855f97c56ca7146ff627e652bd7cd64f3f (diff)
PM / devfreq: Add sysfs node for representing frequency transition information.
This patch adds sysfs node which can be used to get information of frequency transition. It represents transition table which contains total number of transition of each freqeuncy state and time spent. It is inspired CPUFREQ's status driver. Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com> [Added Documentation/ABI entry, updated kernel-doc, and resolved merge conflict] Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r--drivers/devfreq/devfreq.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index c44e562bdfe0..bf6de38190cf 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -66,6 +66,51 @@ static struct devfreq *find_device_devfreq(struct device *dev)
66 return ERR_PTR(-ENODEV); 66 return ERR_PTR(-ENODEV);
67} 67}
68 68
69/**
70 * devfreq_get_freq_level() - Lookup freq_table for the frequency
71 * @devfreq: the devfreq instance
72 * @freq: the target frequency
73 */
74static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
75{
76 int lev;
77
78 for (lev = 0; lev < devfreq->profile->max_state; lev++)
79 if (freq == devfreq->profile->freq_table[lev])
80 return lev;
81
82 return -EINVAL;
83}
84
85/**
86 * devfreq_update_status() - Update statistics of devfreq behavior
87 * @devfreq: the devfreq instance
88 * @freq: the update target frequency
89 */
90static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
91{
92 int lev, prev_lev;
93 unsigned long cur_time;
94
95 lev = devfreq_get_freq_level(devfreq, freq);
96 if (lev < 0)
97 return lev;
98
99 cur_time = jiffies;
100 devfreq->time_in_state[lev] +=
101 cur_time - devfreq->last_stat_updated;
102 if (freq != devfreq->previous_freq) {
103 prev_lev = devfreq_get_freq_level(devfreq,
104 devfreq->previous_freq);
105 devfreq->trans_table[(prev_lev *
106 devfreq->profile->max_state) + lev]++;
107 devfreq->total_trans++;
108 }
109 devfreq->last_stat_updated = cur_time;
110
111 return 0;
112}
113
69/* Load monitoring helper functions for governors use */ 114/* Load monitoring helper functions for governors use */
70 115
71/** 116/**
@@ -112,6 +157,11 @@ int update_devfreq(struct devfreq *devfreq)
112 if (err) 157 if (err)
113 return err; 158 return err;
114 159
160 if (devfreq->profile->freq_table)
161 if (devfreq_update_status(devfreq, freq))
162 dev_err(&devfreq->dev,
163 "Couldn't update frequency transition information.\n");
164
115 devfreq->previous_freq = freq; 165 devfreq->previous_freq = freq;
116 return err; 166 return err;
117} 167}
@@ -378,6 +428,15 @@ struct devfreq *devfreq_add_device(struct device *dev,
378 devfreq->data = data; 428 devfreq->data = data;
379 devfreq->nb.notifier_call = devfreq_notifier_call; 429 devfreq->nb.notifier_call = devfreq_notifier_call;
380 430
431 devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) *
432 devfreq->profile->max_state *
433 devfreq->profile->max_state,
434 GFP_KERNEL);
435 devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
436 devfreq->profile->max_state,
437 GFP_KERNEL);
438 devfreq->last_stat_updated = jiffies;
439
381 dev_set_name(&devfreq->dev, dev_name(dev)); 440 dev_set_name(&devfreq->dev, dev_name(dev));
382 err = device_register(&devfreq->dev); 441 err = device_register(&devfreq->dev);
383 if (err) { 442 if (err) {
@@ -601,6 +660,47 @@ static ssize_t show_available_freqs(struct device *d,
601 return count; 660 return count;
602} 661}
603 662
663static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
664 char *buf)
665{
666 struct devfreq *devfreq = to_devfreq(dev);
667 ssize_t len;
668 int i, j, err;
669 unsigned int max_state = devfreq->profile->max_state;
670
671 err = devfreq_update_status(devfreq, devfreq->previous_freq);
672 if (err)
673 return 0;
674
675 len = sprintf(buf, " From : To\n");
676 len += sprintf(buf + len, " :");
677 for (i = 0; i < max_state; i++)
678 len += sprintf(buf + len, "%8u",
679 devfreq->profile->freq_table[i]);
680
681 len += sprintf(buf + len, " time(ms)\n");
682
683 for (i = 0; i < max_state; i++) {
684 if (devfreq->profile->freq_table[i]
685 == devfreq->previous_freq) {
686 len += sprintf(buf + len, "*");
687 } else {
688 len += sprintf(buf + len, " ");
689 }
690 len += sprintf(buf + len, "%8u:",
691 devfreq->profile->freq_table[i]);
692 for (j = 0; j < max_state; j++)
693 len += sprintf(buf + len, "%8u",
694 devfreq->trans_table[(i * max_state) + j]);
695 len += sprintf(buf + len, "%10u\n",
696 jiffies_to_msecs(devfreq->time_in_state[i]));
697 }
698
699 len += sprintf(buf + len, "Total transition : %u\n",
700 devfreq->total_trans);
701 return len;
702}
703
604static struct device_attribute devfreq_attrs[] = { 704static struct device_attribute devfreq_attrs[] = {
605 __ATTR(governor, S_IRUGO, show_governor, NULL), 705 __ATTR(governor, S_IRUGO, show_governor, NULL),
606 __ATTR(cur_freq, S_IRUGO, show_freq, NULL), 706 __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
@@ -610,6 +710,7 @@ static struct device_attribute devfreq_attrs[] = {
610 store_polling_interval), 710 store_polling_interval),
611 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), 711 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
612 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), 712 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
713 __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
613 { }, 714 { },
614}; 715};
615 716