diff options
author | Ben Dooks <ben@simtec.co.uk> | 2009-07-30 18:23:42 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2009-07-30 18:22:56 -0400 |
commit | e6d197a6954c8a9ff85727c31ca61fc1da78628a (patch) | |
tree | 4f83b37f17499111ae9381746b3427996eb75007 /arch/arm/plat-s3c24xx/cpu-freq-debugfs.c | |
parent | dfff4e95d749c414af3f7350835139103408a50d (diff) |
ARM: S3C: CPUFREQ: Add debugfs support for cpufreq
Add debugfs support for the cpufreq driver to allow
information about the system state to be exported to
the user.
Signed-off-by: Ben Dooks <ben@simtec.co.uk>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'arch/arm/plat-s3c24xx/cpu-freq-debugfs.c')
-rw-r--r-- | arch/arm/plat-s3c24xx/cpu-freq-debugfs.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c b/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c new file mode 100644 index 000000000000..a9276667c2fb --- /dev/null +++ b/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c | ||
2 | * | ||
3 | * Copyright (c) 2009 Simtec Electronics | ||
4 | * http://armlinux.simtec.co.uk/ | ||
5 | * Ben Dooks <ben@simtec.co.uk> | ||
6 | * | ||
7 | * S3C24XX CPU Frequency scaling - debugfs status support | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/cpufreq.h> | ||
19 | #include <linux/debugfs.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/err.h> | ||
22 | |||
23 | #include <plat/cpu-freq-core.h> | ||
24 | |||
25 | static struct dentry *dbgfs_root; | ||
26 | static struct dentry *dbgfs_file_io; | ||
27 | static struct dentry *dbgfs_file_info; | ||
28 | static struct dentry *dbgfs_file_board; | ||
29 | |||
30 | #define print_ns(x) ((x) / 10), ((x) % 10) | ||
31 | |||
32 | static void show_max(struct seq_file *seq, struct s3c_freq *f) | ||
33 | { | ||
34 | seq_printf(seq, "MAX: F=%lu, H=%lu, P=%lu, A=%lu\n", | ||
35 | f->fclk, f->hclk, f->pclk, f->armclk); | ||
36 | } | ||
37 | |||
38 | static int board_show(struct seq_file *seq, void *p) | ||
39 | { | ||
40 | struct s3c_cpufreq_config *cfg; | ||
41 | struct s3c_cpufreq_board *brd; | ||
42 | |||
43 | cfg = s3c_cpufreq_getconfig(); | ||
44 | if (!cfg) { | ||
45 | seq_printf(seq, "no configuration registered\n"); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | brd = cfg->board; | ||
50 | if (!brd) { | ||
51 | seq_printf(seq, "no board definition set?\n"); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | seq_printf(seq, "SDRAM refresh %u ns\n", brd->refresh); | ||
56 | seq_printf(seq, "auto_io=%u\n", brd->auto_io); | ||
57 | seq_printf(seq, "need_io=%u\n", brd->need_io); | ||
58 | |||
59 | show_max(seq, &brd->max); | ||
60 | |||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int fops_board_open(struct inode *inode, struct file *file) | ||
66 | { | ||
67 | return single_open(file, board_show, NULL); | ||
68 | } | ||
69 | |||
70 | static const struct file_operations fops_board = { | ||
71 | .open = fops_board_open, | ||
72 | .read = seq_read, | ||
73 | .llseek = seq_lseek, | ||
74 | .release = single_release, | ||
75 | .owner = THIS_MODULE, | ||
76 | }; | ||
77 | |||
78 | static int info_show(struct seq_file *seq, void *p) | ||
79 | { | ||
80 | struct s3c_cpufreq_config *cfg; | ||
81 | |||
82 | cfg = s3c_cpufreq_getconfig(); | ||
83 | if (!cfg) { | ||
84 | seq_printf(seq, "no configuration registered\n"); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | seq_printf(seq, " FCLK %ld Hz\n", cfg->freq.fclk); | ||
89 | seq_printf(seq, " HCLK %ld Hz (%lu.%lu ns)\n", | ||
90 | cfg->freq.hclk, print_ns(cfg->freq.hclk_tns)); | ||
91 | seq_printf(seq, " PCLK %ld Hz\n", cfg->freq.hclk); | ||
92 | seq_printf(seq, "ARMCLK %ld Hz\n", cfg->freq.armclk); | ||
93 | seq_printf(seq, "\n"); | ||
94 | |||
95 | show_max(seq, &cfg->max); | ||
96 | |||
97 | seq_printf(seq, "Divisors: P=%d, H=%d, A=%d, dvs=%s\n", | ||
98 | cfg->divs.h_divisor, cfg->divs.p_divisor, | ||
99 | cfg->divs.arm_divisor, cfg->divs.dvs ? "on" : "off"); | ||
100 | seq_printf(seq, "\n"); | ||
101 | |||
102 | seq_printf(seq, "lock_pll=%u\n", cfg->lock_pll); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int fops_info_open(struct inode *inode, struct file *file) | ||
108 | { | ||
109 | return single_open(file, info_show, NULL); | ||
110 | } | ||
111 | |||
112 | static const struct file_operations fops_info = { | ||
113 | .open = fops_info_open, | ||
114 | .read = seq_read, | ||
115 | .llseek = seq_lseek, | ||
116 | .release = single_release, | ||
117 | .owner = THIS_MODULE, | ||
118 | }; | ||
119 | |||
120 | static int io_show(struct seq_file *seq, void *p) | ||
121 | { | ||
122 | void (*show_bank)(struct seq_file *, struct s3c_cpufreq_config *, union s3c_iobank *); | ||
123 | struct s3c_cpufreq_config *cfg; | ||
124 | struct s3c_iotimings *iot; | ||
125 | union s3c_iobank *iob; | ||
126 | int bank; | ||
127 | |||
128 | cfg = s3c_cpufreq_getconfig(); | ||
129 | if (!cfg) { | ||
130 | seq_printf(seq, "no configuration registered\n"); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | show_bank = cfg->info->debug_io_show; | ||
135 | if (!show_bank) { | ||
136 | seq_printf(seq, "no code to show bank timing\n"); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | iot = s3c_cpufreq_getiotimings(); | ||
141 | if (!iot) { | ||
142 | seq_printf(seq, "no io timings registered\n"); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | seq_printf(seq, "hclk period is %lu.%lu ns\n", print_ns(cfg->freq.hclk_tns)); | ||
147 | |||
148 | for (bank = 0; bank < MAX_BANKS; bank++) { | ||
149 | iob = &iot->bank[bank]; | ||
150 | |||
151 | seq_printf(seq, "bank %d: ", bank); | ||
152 | |||
153 | if (!iob->io_2410) { | ||
154 | seq_printf(seq, "nothing set\n"); | ||
155 | continue; | ||
156 | } | ||
157 | |||
158 | show_bank(seq, cfg, iob); | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int fops_io_open(struct inode *inode, struct file *file) | ||
165 | { | ||
166 | return single_open(file, io_show, NULL); | ||
167 | } | ||
168 | |||
169 | static const struct file_operations fops_io = { | ||
170 | .open = fops_io_open, | ||
171 | .read = seq_read, | ||
172 | .llseek = seq_lseek, | ||
173 | .release = single_release, | ||
174 | .owner = THIS_MODULE, | ||
175 | }; | ||
176 | |||
177 | |||
178 | static int __init s3c_freq_debugfs_init(void) | ||
179 | { | ||
180 | dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL); | ||
181 | if (IS_ERR(dbgfs_root)) { | ||
182 | printk(KERN_ERR "%s: error creating debugfs root\n", __func__); | ||
183 | return PTR_ERR(dbgfs_root); | ||
184 | } | ||
185 | |||
186 | dbgfs_file_io = debugfs_create_file("io-timing", S_IRUGO, dbgfs_root, | ||
187 | NULL, &fops_io); | ||
188 | |||
189 | dbgfs_file_info = debugfs_create_file("info", S_IRUGO, dbgfs_root, | ||
190 | NULL, &fops_info); | ||
191 | |||
192 | dbgfs_file_board = debugfs_create_file("board", S_IRUGO, dbgfs_root, | ||
193 | NULL, &fops_board); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | late_initcall(s3c_freq_debugfs_init); | ||
199 | |||