summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra_core_volt_cap.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2013-07-16 22:47:55 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:42:30 -0700
commitaae3c500f426c5478663c18fe6cfa479f3eaa007 (patch)
tree5ced77b7d21395d1bbd5ccb1ebaa07d8f28e95a4 /arch/arm/mach-tegra/tegra_core_volt_cap.c
parent8bf60bf8bb65bc3785010799b6b5d8a924348371 (diff)
ARM: tegra: clock: Add sysfs interface for bus floors
Added mechanism to install sysfs objects for tegra shared bus floors. Currently no floor objects are installed. Change-Id: I4940b096fe7013f09213813b18b1cfe71fce9336 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/250416 (cherry picked from commit ec8651cf8f8822253dc6a6221a390ea79568a638) Reviewed-on: http://git-master/r/254750 (cherry picked from commit 5eba5ed2d405fb99787fed57e33f4cbc17b44ce0) Reviewed-on: http://git-master/r/264675 Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_core_volt_cap.c')
-rw-r--r--arch/arm/mach-tegra/tegra_core_volt_cap.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/tegra_core_volt_cap.c b/arch/arm/mach-tegra/tegra_core_volt_cap.c
index c842158c2b19..c7a286f9c7bf 100644
--- a/arch/arm/mach-tegra/tegra_core_volt_cap.c
+++ b/arch/arm/mach-tegra/tegra_core_volt_cap.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra_core_volt_cap.c
*
- * Copyright (C) 2013 NVIDIA Corporation.
+ * Copyright (c), NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -23,6 +23,7 @@
#include "clock.h"
#include "dvfs.h"
+#include "tegra_core_sysfs_limits.h"
/*
* sysfs and kernel interfaces to limit tegra core shared bus frequencies based
@@ -414,3 +415,99 @@ int __init tegra_init_shared_bus_cap(
return -ENOMEM;
return 0;
}
+
+static DEFINE_MUTEX(bus_floor_lock);
+const struct attribute *bus_floor_attributes[2 * MAX_BUS_NUM + 1];
+
+#define refcnt_to_bus_floor(attr) \
+ container_of(attr, struct core_bus_floor_table, refcnt_attr)
+#define level_to_bus_floor(attr) \
+ container_of(attr, struct core_bus_floor_table, level_attr)
+
+static ssize_t
+bus_floor_state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct core_bus_floor_table *bus_floor = refcnt_to_bus_floor(attr);
+ struct clk *c = bus_floor->floor_clk;
+ return sprintf(buf, "%d\n", tegra_is_clk_enabled(c) ? 1 : 0);
+}
+static ssize_t
+bus_floor_state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+ struct core_bus_floor_table *bus_floor = refcnt_to_bus_floor(attr);
+ struct clk *c = bus_floor->floor_clk;
+
+ if (sscanf(buf, "%d", &state) != 1)
+ return -EINVAL;
+
+ if (state) {
+ int ret = tegra_clk_prepare_enable(c);
+ if (ret)
+ return ret;
+ } else {
+ tegra_clk_disable_unprepare(c);
+ }
+ return count;
+}
+
+static ssize_t
+bus_floor_level_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct core_bus_floor_table *bus_floor = level_to_bus_floor(attr);
+ return sprintf(buf, "%d\n", bus_floor->level);
+}
+static ssize_t
+bus_floor_level_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int level, ret;
+ struct core_bus_floor_table *bus_floor = level_to_bus_floor(attr);
+ struct clk *c = bus_floor->floor_clk;
+
+ if (sscanf(buf, "%d", &level) != 1)
+ return -EINVAL;
+
+ mutex_lock(&bus_floor_lock);
+ ret = clk_set_rate(c, level);
+ if (!ret)
+ bus_floor->level = level;
+ mutex_unlock(&bus_floor_lock);
+ return ret ? : count;
+}
+
+int __init tegra_init_shared_bus_floor(
+ struct core_bus_floor_table *table, int table_size,
+ struct kobject *floor_kobj)
+{
+ int i, j;
+ struct clk *c = NULL;
+
+ if (!table || !table_size || (table_size > MAX_BUS_NUM))
+ return -EINVAL;
+
+ for (i = 0, j = 0; i < table_size; i++) {
+ c = tegra_get_clock_by_name(table[i].floor_name);
+ if (!c) {
+ pr_err("%s: failed to initialize %s table\n",
+ __func__, table[i].floor_name);
+ continue;
+ }
+ table[i].floor_clk = c;
+ table[i].level = clk_get_max_rate(c);
+ table[i].refcnt_attr.show = bus_floor_state_show;
+ table[i].refcnt_attr.store = bus_floor_state_store;
+ table[i].level_attr.show = bus_floor_level_show;
+ table[i].level_attr.store = bus_floor_level_store;
+ bus_floor_attributes[j++] = &table[i].refcnt_attr.attr;
+ bus_floor_attributes[j++] = &table[i].level_attr.attr;
+ }
+ bus_floor_attributes[j] = NULL;
+
+ if (!floor_kobj || sysfs_create_files(floor_kobj, bus_floor_attributes))
+ return -ENOMEM;
+ return 0;
+}