static int __init sysfscluster_init(void) { int e; TRACE_CLUSTER(("+sysfscluster_init\n")); spin_lock_init(&cluster_lock); cluster_kobj = kobject_create_and_add("cluster", kernel_kobj); CREATE_FILE(active); CREATE_FILE(immediate); CREATE_FILE(force); CREATE_FILE(wake_ms); #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE CREATE_FILE(powermode); #endif #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE CREATE_FILE(powergate); #endif #if DEBUG_CLUSTER_SWITCH CREATE_FILE(debug); #endif spin_lock(&cluster_lock); if (is_lp_cluster()) flags |= TEGRA_POWER_CLUSTER_LP; else flags |= TEGRA_POWER_CLUSTER_G; spin_unlock(&cluster_lock); fail: TRACE_CLUSTER(("-sysfscluster_init\n")); return e; }
static ssize_t sysfscluster_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { ClusterAttr type; ssize_t len; TRACE_CLUSTER(("+sysfscluster_show\n")); type = GetClusterAttr(attr->attr.name); switch (type) { case ClusterAttr_Active: len = sprintf(buf, "%s\n", is_lp_cluster() ? "LP" : "G"); break; case ClusterAttr_Immediate: len = sprintf(buf, "%d\n", ((flags & TEGRA_POWER_CLUSTER_IMMEDIATE) != 0)); break; case ClusterAttr_Force: len = sprintf(buf, "%d\n", ((flags & TEGRA_POWER_CLUSTER_FORCE) != 0)); break; case ClusterAttr_WakeMs: len = sprintf(buf, "%d\n", wake_ms); break; #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE case ClusterAttr_PowerMode: len = sprintf(buf, "%d\n", power_mode); break; #endif #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE case ClusterAttr_PowerGate: len = sprintf(buf, "%s\n", decode_power_gate(power_gate)); break; #endif #if DEBUG_CLUSTER_SWITCH case ClusterAttr_Debug: len = sprintf(buf, "%d\n", tegra_cluster_debug); break; #endif default: len = sprintf(buf, "invalid\n"); break; } TRACE_CLUSTER(("-sysfscluster_show\n")); return len; }
static void __exit sysfscluster_exit(void) { TRACE_CLUSTER(("+sysfscluster_exit\n")); #if DEBUG_CLUSTER_SWITCH REMOVE_FILE(debug); #endif #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE REMOVE_FILE(powermode); #endif REMOVE_FILE(wake_ms); REMOVE_FILE(force); REMOVE_FILE(immediate); REMOVE_FILE(active); kobject_del(cluster_kobj); TRACE_CLUSTER(("-sysfscluster_exit\n")); }
static ClusterAttr GetClusterAttr(const char *name) { if (!strcmp(name, "active")) return ClusterAttr_Active; if (!strcmp(name, "immediate")) return ClusterAttr_Immediate; if (!strcmp(name, "force")) return ClusterAttr_Force; if (!strcmp(name, "wake_ms")) return ClusterAttr_WakeMs; #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE if (!strcmp(name, "power_mode")) return ClusterAttr_PowerMode; #endif #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE if (!strcmp(name, "power_gate")) return ClusterAttr_PowerGate; #endif #if DEBUG_CLUSTER_SWITCH if (!strcmp(name, "debug")) return ClusterAttr_Debug; #endif TRACE_CLUSTER(("GetClusterAttr(%s): invalid\n", name)); return ClusterAttr_Invalid; }
static cpu_cluster_attr cpu_cluster_get_attr(const char *name) { if (!strcmp(name, "active")) return CLUSTER_ATTR_ACTIVE; if (!strcmp(name, "immediate")) return CLUSTER_ATTR_IMME; if (!strcmp(name, "force")) return CLUSTER_ATTR_FORCE; if (!strcmp(name, "wake_ms")) return CLUSTER_ATTR_WAKEMS; #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE if (!strcmp(name, "power_mode")) return CLUSTER_ATTR_POWERMODE; #endif #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE if (!strcmp(name, "power_gate")) return CLUSTER_ATTR_POWERGATE; #endif #if DEBUG_CLUSTER_SWITCH if (!strcmp(name, "debug")) return CLUSTER_ATTR_DEBUG; #endif TRACE_CLUSTER(("cpu_cluster_get_attr(%s): invalid\n", name)); return CLUSTER_ATTR_INVALID; }
static ssize_t sysfscluster_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { ClusterAttr type; ssize_t ret = count--; unsigned request; int e; int tmp; int cnt; struct clk *cpu_clk = tegra_get_clock_by_name("cpu"); struct clk *cpu_g_clk = tegra_get_clock_by_name("cpu_g"); struct clk *cpu_lp_clk = tegra_get_clock_by_name("cpu_lp"); struct clk *new_parent = NULL; if (!cpu_clk || !cpu_g_clk || !cpu_lp_clk) { ret = -ENOSYS; goto fail; } TRACE_CLUSTER(("+sysfscluster_store: %p, %d\n", buf, count)); /* The count includes data bytes follow by a line feed character. */ if (!buf || (count < 1)) { ret = -EINVAL; goto fail; } type = GetClusterAttr(attr->attr.name); spin_lock(&cluster_lock); switch (type) { case ClusterAttr_Active: if (!strncasecmp(buf, "g", count)) { flags &= ~TEGRA_POWER_CLUSTER_MASK; flags |= TEGRA_POWER_CLUSTER_G; } else if (!strncasecmp(buf, "lp", count)) { flags &= ~TEGRA_POWER_CLUSTER_MASK; flags |= TEGRA_POWER_CLUSTER_LP; } else if (!strncasecmp(buf, "toggle", count)) { flags &= ~TEGRA_POWER_CLUSTER_MASK; if (is_lp_cluster()) flags |= TEGRA_POWER_CLUSTER_G; else flags |= TEGRA_POWER_CLUSTER_LP; } else { PRINT_CLUSTER(("cluster/active: '%*.*s' invalid, " " must be g, lp, or toggle\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/active -> %s\n", (flags & TEGRA_POWER_CLUSTER_G) ? "G" : "LP")); request = flags; #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE request |= power_gate; #endif #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE if (power_mode == 1) { request |= TEGRA_POWER_SDRAM_SELFREFRESH; } #endif tegra_cluster_switch_set_parameters(wake_ms * 1000, request); new_parent = (flags & TEGRA_POWER_CLUSTER_LP) ? cpu_lp_clk : cpu_g_clk; break; case ClusterAttr_Immediate: if ((count == 1) && (*buf == '0')) flags &= ~TEGRA_POWER_CLUSTER_IMMEDIATE; else if ((count == 1) && *buf == '1') flags |= TEGRA_POWER_CLUSTER_IMMEDIATE; else { PRINT_CLUSTER(("cluster/immediate: '%*.*s' invalid, " "must be 0 or 1\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/immediate -> %c\n", (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? '1' : '0')); break; case ClusterAttr_Force: if ((count == 1) && (*buf == '0')) flags &= ~TEGRA_POWER_CLUSTER_FORCE; else if ((count == 1) && (*buf == '1')) flags |= TEGRA_POWER_CLUSTER_FORCE; else { PRINT_CLUSTER(("cluster/force: '%*.*s' invalid, " "must be 0 or 1\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/force -> %c\n", (flags & TEGRA_POWER_CLUSTER_FORCE) ? '1' : '0')); break; case ClusterAttr_WakeMs: tmp = 0; cnt = sscanf(buf, "%d\n", &tmp); if ((cnt != 1) || (tmp < 0)) { PRINT_CLUSTER(("cluster/wake_ms: '%*.*s' is invalid\n", count, count, buf)); ret = -EINVAL; break; } wake_ms = tmp; PRINT_CLUSTER(("cluster/wake_ms -> %d\n", wake_ms)); break; #if defined(CONFIG_PM_SLEEP) && SYSFS_CLUSTER_POWER_MODE case ClusterAttr_PowerMode: if ((count == 1) && (*buf == '2')) power_mode = 2; else if ((count == 1) && *buf == '1') power_mode = 1; else { PRINT_CLUSTER(("cluster/power_mode: '%*.*s' invalid, " "must be 2 or 1\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/power_mode -> %d\n", power_mode)); break; #endif #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE case ClusterAttr_PowerGate: if (!strncasecmp(buf, "crail", count)) power_gate = TEGRA_POWER_CLUSTER_PART_CRAIL; else if (!strncasecmp(buf, "noncpu", count)) power_gate = TEGRA_POWER_CLUSTER_PART_NONCPU; else if (!strncasecmp(buf, "none", count)) power_gate = 0; else { PRINT_CLUSTER(("cluster/power_gate: '%*.*s' invalid, " "must be 'none', 'crail', or 'noncpu'\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/power_gate -> %s\n", decode_power_gate(power_gate))); break; #endif #if DEBUG_CLUSTER_SWITCH case ClusterAttr_Debug: if ((count == 1) && (*buf == '0')) tegra_cluster_debug = 0; else if ((count == 1) && (*buf == '1')) tegra_cluster_debug = 1; else { PRINT_CLUSTER(("cluster/debug: '%*.*s' invalid, " "must be 0 or 1\n", count, count, buf)); ret = -EINVAL; break; } PRINT_CLUSTER(("cluster/debug -> %d\n",tegra_cluster_debug)); break; #endif default: ret = -ENOENT; break; } spin_unlock(&cluster_lock); if (new_parent) { e = tegra_cluster_switch(cpu_clk, new_parent); if (e) { PRINT_CLUSTER(("cluster/active: request failed (%d)\n", e)); ret = e; } } fail: TRACE_CLUSTER(("-sysfscluster_store: %d\n", count)); return ret; }