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;
}