summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_dvfs.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-07-18 13:49:28 -0700
committerLokesh Pathak <lpathak@nvidia.com>2012-07-25 07:47:57 -0700
commit5b754f99eee15772f43240830c4e76ad8cf220bb (patch)
tree9a47a41e19e26c52bca8dbb5264058ef7f52ad3f /arch/arm/mach-tegra/tegra3_dvfs.c
parent006b6827f963a1fbfc309fd546c14bf4af49fedc (diff)
ARM: tegra: clock: Add Tegra3 cbus profiling sysfs nodes
Added: /sys/kernel/tegra_cap/cbus_cap_level /sys/kernel/tegra_cap/cbus_cap_state Change-Id: I06a32ea4001f1f644da4f230870f39523f9b6df3 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/116874 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_dvfs.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index 9b06d3eda86b..38f6ed0b317c 100644
--- a/arch/arm/mach-tegra/tegra3_dvfs.c
+++ b/arch/arm/mach-tegra/tegra3_dvfs.c
@@ -780,6 +780,8 @@ static struct core_cap tegra3_core_cap;
static struct core_cap kdvfs_core_cap;
static struct core_cap user_core_cap;
+static struct core_cap user_cbus_cap;
+
static struct kobject *cap_kobj;
/* Arranged in order required for enabling/lowering the cap */
@@ -898,14 +900,91 @@ core_cap_level_store(struct kobject *kobj, struct kobj_attribute *attr,
return count;
}
+static void cbus_cap_update(void)
+{
+ static struct clk *cbus_cap;
+
+ if (!cbus_cap) {
+ cbus_cap = tegra_get_clock_by_name("cap.profile.cbus");
+ if (!cbus_cap) {
+ WARN_ONCE(1, "tegra3_dvfs: cbus profiling is not supported");
+ return;
+ }
+ }
+
+ if (user_cbus_cap.refcnt)
+ clk_set_rate(cbus_cap, user_cbus_cap.level);
+ else
+ clk_set_rate(cbus_cap, clk_get_max_rate(cbus_cap));
+}
+
+static ssize_t
+cbus_cap_state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", user_cbus_cap.refcnt ? 1 : 0);
+}
+static ssize_t
+cbus_cap_state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+
+ if (sscanf(buf, "%d", &state) != 1)
+ return -1;
+
+ mutex_lock(&core_cap_lock);
+
+ if (state) {
+ user_cbus_cap.refcnt++;
+ if (user_cbus_cap.refcnt == 1)
+ cbus_cap_update();
+ } else if (user_cbus_cap.refcnt) {
+ user_cbus_cap.refcnt--;
+ if (user_cbus_cap.refcnt == 0)
+ cbus_cap_update();
+ }
+
+ mutex_unlock(&core_cap_lock);
+ return count;
+}
+
+static ssize_t
+cbus_cap_level_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", user_cbus_cap.level);
+}
+static ssize_t
+cbus_cap_level_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int level;
+
+ if (sscanf(buf, "%d", &level) != 1)
+ return -1;
+
+ mutex_lock(&core_cap_lock);
+ user_cbus_cap.level = level;
+ cbus_cap_update();
+ mutex_unlock(&core_cap_lock);
+ return count;
+}
+
static struct kobj_attribute cap_state_attribute =
__ATTR(core_cap_state, 0644, core_cap_state_show, core_cap_state_store);
static struct kobj_attribute cap_level_attribute =
__ATTR(core_cap_level, 0644, core_cap_level_show, core_cap_level_store);
+static struct kobj_attribute cbus_state_attribute =
+ __ATTR(cbus_cap_state, 0644, cbus_cap_state_show, cbus_cap_state_store);
+static struct kobj_attribute cbus_level_attribute =
+ __ATTR(cbus_cap_level, 0644, cbus_cap_level_show, cbus_cap_level_store);
const struct attribute *cap_attributes[] = {
&cap_state_attribute.attr,
&cap_level_attribute.attr,
+ &cbus_state_attribute.attr,
+ &cbus_level_attribute.attr,
NULL,
};