0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009
0010 #include <linux/debugfs.h>
0011 #include <linux/device.h>
0012 #include <linux/err.h>
0013 #include <linux/of.h>
0014 #include <linux/init.h>
0015 #include <linux/limits.h>
0016 #include <linux/slab.h>
0017
0018 #include "opp.h"
0019
0020 static struct dentry *rootdir;
0021
0022 static void opp_set_dev_name(const struct device *dev, char *name)
0023 {
0024 if (dev->parent)
0025 snprintf(name, NAME_MAX, "%s-%s", dev_name(dev->parent),
0026 dev_name(dev));
0027 else
0028 snprintf(name, NAME_MAX, "%s", dev_name(dev));
0029 }
0030
0031 void opp_debug_remove_one(struct dev_pm_opp *opp)
0032 {
0033 debugfs_remove_recursive(opp->dentry);
0034 }
0035
0036 static ssize_t bw_name_read(struct file *fp, char __user *userbuf,
0037 size_t count, loff_t *ppos)
0038 {
0039 struct icc_path *path = fp->private_data;
0040 char buf[64];
0041 int i;
0042
0043 i = scnprintf(buf, sizeof(buf), "%.62s\n", icc_get_name(path));
0044
0045 return simple_read_from_buffer(userbuf, count, ppos, buf, i);
0046 }
0047
0048 static const struct file_operations bw_name_fops = {
0049 .open = simple_open,
0050 .read = bw_name_read,
0051 .llseek = default_llseek,
0052 };
0053
0054 static void opp_debug_create_bw(struct dev_pm_opp *opp,
0055 struct opp_table *opp_table,
0056 struct dentry *pdentry)
0057 {
0058 struct dentry *d;
0059 char name[11];
0060 int i;
0061
0062 for (i = 0; i < opp_table->path_count; i++) {
0063 snprintf(name, sizeof(name), "icc-path-%.1d", i);
0064
0065
0066 d = debugfs_create_dir(name, pdentry);
0067
0068 debugfs_create_file("name", S_IRUGO, d, opp_table->paths[i],
0069 &bw_name_fops);
0070 debugfs_create_u32("peak_bw", S_IRUGO, d,
0071 &opp->bandwidth[i].peak);
0072 debugfs_create_u32("avg_bw", S_IRUGO, d,
0073 &opp->bandwidth[i].avg);
0074 }
0075 }
0076
0077 static void opp_debug_create_clks(struct dev_pm_opp *opp,
0078 struct opp_table *opp_table,
0079 struct dentry *pdentry)
0080 {
0081 char name[12];
0082 int i;
0083
0084 if (opp_table->clk_count == 1) {
0085 debugfs_create_ulong("rate_hz", S_IRUGO, pdentry, &opp->rates[0]);
0086 return;
0087 }
0088
0089 for (i = 0; i < opp_table->clk_count; i++) {
0090 snprintf(name, sizeof(name), "rate_hz_%d", i);
0091 debugfs_create_ulong(name, S_IRUGO, pdentry, &opp->rates[i]);
0092 }
0093 }
0094
0095 static void opp_debug_create_supplies(struct dev_pm_opp *opp,
0096 struct opp_table *opp_table,
0097 struct dentry *pdentry)
0098 {
0099 struct dentry *d;
0100 int i;
0101
0102 for (i = 0; i < opp_table->regulator_count; i++) {
0103 char name[15];
0104
0105 snprintf(name, sizeof(name), "supply-%d", i);
0106
0107
0108 d = debugfs_create_dir(name, pdentry);
0109
0110 debugfs_create_ulong("u_volt_target", S_IRUGO, d,
0111 &opp->supplies[i].u_volt);
0112
0113 debugfs_create_ulong("u_volt_min", S_IRUGO, d,
0114 &opp->supplies[i].u_volt_min);
0115
0116 debugfs_create_ulong("u_volt_max", S_IRUGO, d,
0117 &opp->supplies[i].u_volt_max);
0118
0119 debugfs_create_ulong("u_amp", S_IRUGO, d,
0120 &opp->supplies[i].u_amp);
0121
0122 debugfs_create_ulong("u_watt", S_IRUGO, d,
0123 &opp->supplies[i].u_watt);
0124 }
0125 }
0126
0127 void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
0128 {
0129 struct dentry *pdentry = opp_table->dentry;
0130 struct dentry *d;
0131 unsigned long id;
0132 char name[25];
0133
0134
0135
0136
0137
0138
0139
0140
0141 if (likely(opp_table->clk_count == 1 && opp->rates[0]))
0142 id = opp->rates[0];
0143 else
0144 id = _get_opp_count(opp_table);
0145
0146 snprintf(name, sizeof(name), "opp:%lu", id);
0147
0148
0149 d = debugfs_create_dir(name, pdentry);
0150
0151 debugfs_create_bool("available", S_IRUGO, d, &opp->available);
0152 debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic);
0153 debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
0154 debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
0155 debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
0156 debugfs_create_u32("level", S_IRUGO, d, &opp->level);
0157 debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
0158 &opp->clock_latency_ns);
0159
0160 opp->of_name = of_node_full_name(opp->np);
0161 debugfs_create_str("of_name", S_IRUGO, d, (char **)&opp->of_name);
0162
0163 opp_debug_create_clks(opp, opp_table, d);
0164 opp_debug_create_supplies(opp, opp_table, d);
0165 opp_debug_create_bw(opp, opp_table, d);
0166
0167 opp->dentry = d;
0168 }
0169
0170 static void opp_list_debug_create_dir(struct opp_device *opp_dev,
0171 struct opp_table *opp_table)
0172 {
0173 const struct device *dev = opp_dev->dev;
0174 struct dentry *d;
0175
0176 opp_set_dev_name(dev, opp_table->dentry_name);
0177
0178
0179 d = debugfs_create_dir(opp_table->dentry_name, rootdir);
0180
0181 opp_dev->dentry = d;
0182 opp_table->dentry = d;
0183 }
0184
0185 static void opp_list_debug_create_link(struct opp_device *opp_dev,
0186 struct opp_table *opp_table)
0187 {
0188 char name[NAME_MAX];
0189
0190 opp_set_dev_name(opp_dev->dev, name);
0191
0192
0193 opp_dev->dentry = debugfs_create_symlink(name, rootdir,
0194 opp_table->dentry_name);
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table)
0207 {
0208 if (opp_table->dentry)
0209 opp_list_debug_create_link(opp_dev, opp_table);
0210 else
0211 opp_list_debug_create_dir(opp_dev, opp_table);
0212 }
0213
0214 static void opp_migrate_dentry(struct opp_device *opp_dev,
0215 struct opp_table *opp_table)
0216 {
0217 struct opp_device *new_dev = NULL, *iter;
0218 const struct device *dev;
0219 struct dentry *dentry;
0220
0221
0222 list_for_each_entry(iter, &opp_table->dev_list, node)
0223 if (iter != opp_dev) {
0224 new_dev = iter;
0225 break;
0226 }
0227
0228 BUG_ON(!new_dev);
0229
0230
0231 dev = new_dev->dev;
0232 debugfs_remove_recursive(new_dev->dentry);
0233
0234 opp_set_dev_name(dev, opp_table->dentry_name);
0235
0236 dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir,
0237 opp_table->dentry_name);
0238 if (!dentry) {
0239 dev_err(dev, "%s: Failed to rename link from: %s to %s\n",
0240 __func__, dev_name(opp_dev->dev), dev_name(dev));
0241 return;
0242 }
0243
0244 new_dev->dentry = dentry;
0245 opp_table->dentry = dentry;
0246 }
0247
0248
0249
0250
0251
0252
0253
0254
0255 void opp_debug_unregister(struct opp_device *opp_dev,
0256 struct opp_table *opp_table)
0257 {
0258 if (opp_dev->dentry == opp_table->dentry) {
0259
0260 if (!list_is_singular(&opp_table->dev_list)) {
0261 opp_migrate_dentry(opp_dev, opp_table);
0262 goto out;
0263 }
0264 opp_table->dentry = NULL;
0265 }
0266
0267 debugfs_remove_recursive(opp_dev->dentry);
0268
0269 out:
0270 opp_dev->dentry = NULL;
0271 }
0272
0273 static int __init opp_debug_init(void)
0274 {
0275
0276 rootdir = debugfs_create_dir("opp", NULL);
0277
0278 return 0;
0279 }
0280 core_initcall(opp_debug_init);