summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorJoshua Primero <jprimero@nvidia.com>2012-02-09 12:03:00 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-07-02 06:10:44 -0700
commitd294fdf2ffc18563bdd3a14b7574b46526763be8 (patch)
tree1c9d66b1f3c78366fc8dbeae7ae3619addc98ccb /arch/arm
parent9d8eea6716367751c6f21134bc54fd91ab91a75a (diff)
ARM: tegra: Object based balanced throttling
Implemented an object based balanced throttling in preparation for multiple balanced throttling objects. bug 1007726 Change-Id: Ib58fafaf696af0ae58e78bd9fd417d3a822d0571 Signed-off-by: Joshua Primero <jprimero@nvidia.com> Reviewed-on: http://git-master/r/105238 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c3
-rw-r--r--arch/arm/mach-tegra/include/mach/thermal.h29
-rw-r--r--arch/arm/mach-tegra/tegra3_thermal.c147
-rw-r--r--arch/arm/mach-tegra/tegra3_throttle.c229
4 files changed, 267 insertions, 141 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 5c680b849435..9bed9270b412 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -435,9 +435,6 @@ static int __init tegra_cpu_debug_init(void)
if (!cpu_tegra_debugfs_root)
return -ENOMEM;
- if (tegra_throttle_debug_init(cpu_tegra_debugfs_root))
- goto err_out;
-
if (tegra_edp_debug_init(cpu_tegra_debugfs_root))
goto err_out;
diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h
index 67586224cead..78599971cd9f 100644
--- a/arch/arm/mach-tegra/include/mach/thermal.h
+++ b/arch/arm/mach-tegra/include/mach/thermal.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/thermal.h
*
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * Copyright (C) 2010-2012 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -42,8 +42,35 @@ struct tegra_thermal_device {
int (*set_limits) (void *, long, long);
int (*set_alert)(void *, void (*)(void *), void *);
int (*set_shutdown_temp)(void *, long);
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ struct thermal_zone_device *thz;
+#endif
+};
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+struct throttle_table {
+ unsigned int cpu_freq;
+ int core_cap_level;
};
+struct balanced_throttle {
+ int id;
+ struct throttle_table *throt_tab;
+ int throt_tab_size;
+
+ int is_throttling;
+ int throttle_index;
+ struct thermal_cooling_device *cdev;
+
+ struct list_head node;
+};
+
+struct balanced_throttle *balanced_throttle_register(
+ int id,
+ struct throttle_table *table,
+ int tab_size);
+#endif
+
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
int tegra_thermal_init(struct tegra_thermal_data *data);
int tegra_thermal_set_device(struct tegra_thermal_device *device);
diff --git a/arch/arm/mach-tegra/tegra3_thermal.c b/arch/arm/mach-tegra/tegra3_thermal.c
index 6322eb35ab79..d94158aff7d2 100644
--- a/arch/arm/mach-tegra/tegra3_thermal.c
+++ b/arch/arm/mach-tegra/tegra3_thermal.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_thermal.c
*
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * Copyright (C) 2010-2012 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -40,7 +40,6 @@ struct tegra_thermal {
long temp_shutdown_tj;
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
long temp_throttle_tj;
- struct thermal_zone_device *thz;
int tc1;
int tc2;
long passive_delay;
@@ -59,6 +58,24 @@ static struct tegra_thermal thermal_state = {
.edp_thermal_zone_val = -1,
#endif
};
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+static struct throttle_table tj_bthrot_table[] = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+};
+
+static struct balanced_throttle *tj_bthrot;
+
+#define TJ_BALANCED_THROTTLE_ID (0)
+#endif
#ifdef CONFIG_TEGRA_EDP_LIMITS
static inline long edp2tj(struct tegra_thermal *thermal,
@@ -86,25 +103,54 @@ static inline long tj2dev(struct tegra_thermal_device *dev,
return tj_temp - dev->offset;
}
+static int tegra_thermal_get_tj_temp(long *tj_temp)
+{
+ long temp_dev;
+ struct tegra_thermal *thermal = &thermal_state;
+
+ if (!thermal->device)
+ return -1;
+
+ thermal->device->get_temp(thermal->device->data,
+ &temp_dev);
+ *tj_temp = dev2tj(thermal->device, temp_dev);
+
+ return 0;
+}
+
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
-static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal,
+static int tegra_thermal_zone_bind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdevice) {
- /* Support only Thermal Throttling (1 trip) for now */
- return thermal_zone_bind_cooling_device(thermal, 0, cdevice);
+
+ struct balanced_throttle *bthrot = cdevice->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
+
+ if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) &&
+ (device == thermal_state.device))
+ return thermal_zone_bind_cooling_device(thz, 0, cdevice);
+
+ return 0;
}
-static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal,
+static int tegra_thermal_zone_unbind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdevice) {
- /* Support only Thermal Throttling (1 trip) for now */
- return thermal_zone_unbind_cooling_device(thermal, 0, cdevice);
+ struct balanced_throttle *bthrot = cdevice->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
+
+ if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) &&
+ (device == thermal_state.device))
+ return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
+
+ return 0;
}
static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
unsigned long *temp)
{
- struct tegra_thermal *thermal = thz->devdata;
- thermal->device->get_temp(thermal->device->data, temp);
+ struct tegra_thermal_device *device = thz->devdata;
+
+ device->get_temp(device->data, temp);
return 0;
}
@@ -113,8 +159,6 @@ static int tegra_thermal_zone_get_trip_type(
struct thermal_zone_device *thermal,
int trip,
enum thermal_trip_type *type) {
-
- /* Support only Thermal Throttling (1 trip) for now */
if (trip != 0)
return -EINVAL;
@@ -126,13 +170,12 @@ static int tegra_thermal_zone_get_trip_type(
static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
int trip,
unsigned long *temp) {
- struct tegra_thermal *thermal = thz->devdata;
+ struct tegra_thermal_device *device = thz->devdata;
- /* Support only Thermal Throttling (1 trip) for now */
if (trip != 0)
return -EINVAL;
- *temp = tj2dev(thermal->device, thermal->temp_throttle_tj);
+ *temp = tj2dev(device, thermal_state.temp_throttle_tj);
return 0;
}
@@ -150,8 +193,7 @@ static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
void tegra_thermal_alert(void *data)
{
struct tegra_thermal *thermal = data;
- int err;
- long temp_dev, temp_tj;
+ long temp_tj;
long lo_limit_throttle_tj, hi_limit_throttle_tj;
long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
long temp_low_dev, temp_low_tj;
@@ -168,21 +210,16 @@ void tegra_thermal_alert(void *data)
mutex_lock(&thermal_state.mutex);
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
- if (thermal->thz) {
- if (!thermal->thz->passive)
- thermal_zone_device_update(thermal->thz);
+ if (thermal->device->thz) {
+ if (!thermal->device->thz->passive)
+ thermal_zone_device_update(thermal->device->thz);
}
#endif
- err = thermal->device->get_temp(thermal->device->data, &temp_dev);
- if (err) {
- pr_err("%s: get temp fail(%d)", __func__, err);
- goto done;
- }
-
/* Convert all temps to tj and then do all work/logic in terms of
tj in order to avoid confusion */
- temp_tj = dev2tj(thermal->device, temp_dev);
+ if (tegra_thermal_get_tj_temp(&temp_tj))
+ goto done;
thermal->device->get_temp_low(thermal->device, &temp_low_dev);
temp_low_tj = dev2tj(thermal->device, temp_low_dev);
@@ -248,6 +285,8 @@ done:
mutex_unlock(&thermal_state.mutex);
}
+
+
int tegra_thermal_set_device(struct tegra_thermal_device *device)
{
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
@@ -261,29 +300,35 @@ int tegra_thermal_set_device(struct tegra_thermal_device *device)
thermal_state.device = device;
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
- thz = thermal_zone_device_register(thermal_state.device->name,
+ thz = thermal_zone_device_register(device->name,
1, /* trips */
- &thermal_state,
+ device,
&tegra_thermal_zone_ops,
thermal_state.tc1, /* dT/dt */
thermal_state.tc2, /* throttle */
thermal_state.passive_delay,
0); /* polling delay */
+ if (IS_ERR_OR_NULL(thz))
+ return -ENODEV;
- if (IS_ERR(thz)) {
- thz = NULL;
+ device->thz = thz;
+
+ tj_bthrot = balanced_throttle_register(
+ TJ_BALANCED_THROTTLE_ID,
+ tj_bthrot_table,
+ ARRAY_SIZE(tj_bthrot_table));
+ if (IS_ERR_OR_NULL(tj_bthrot))
return -ENODEV;
- }
- thermal_state.thz = thz;
#endif
- thermal_state.device->set_alert(thermal_state.device->data,
- tegra_thermal_alert,
- &thermal_state);
+ device->set_alert(device->data,
+ tegra_thermal_alert,
+ &thermal_state);
- thermal_state.device->set_shutdown_temp(thermal_state.device->data,
+ device->set_shutdown_temp(device->data,
tj2dev(device, thermal_state.temp_shutdown_tj));
+
/* initialize limits */
tegra_thermal_alert(&thermal_state);
@@ -313,8 +358,8 @@ int __init tegra_thermal_init(struct tegra_thermal_data *data)
int tegra_thermal_exit(void)
{
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
- if (thermal_state.thz)
- thermal_zone_device_unregister(thermal_state.thz);
+ if (thermal_state.device->thz)
+ thermal_zone_device_unregister(thermal_state.device->thz);
#endif
return 0;
@@ -375,18 +420,10 @@ DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops,
static int tegra_thermal_temp_tj_get(void *data, u64 *val)
{
- long temp_tj, temp_dev;
-
- if (thermal_state.device) {
- thermal_state.device->get_temp(thermal_state.device->data,
- &temp_dev);
+ long temp_tj;
- /* Convert all temps to tj and then do all work/logic in
- terms of tj in order to avoid confusion */
- temp_tj = dev2tj(thermal_state.device, temp_dev);
- } else {
+ if (tegra_thermal_get_tj_temp(&temp_tj))
temp_tj = -1;
- }
*val = (u64)temp_tj;
@@ -401,13 +438,13 @@ DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
static int tegra_thermal_tc1_set(void *data, u64 val)
{
- thermal_state.thz->tc1 = val;
+ thermal_state.device->thz->tc1 = val;
return 0;
}
static int tegra_thermal_tc1_get(void *data, u64 *val)
{
- *val = (u64)thermal_state.thz->tc1;
+ *val = (u64)thermal_state.device->thz->tc1;
return 0;
}
@@ -418,13 +455,13 @@ DEFINE_SIMPLE_ATTRIBUTE(tc1_fops,
static int tegra_thermal_tc2_set(void *data, u64 val)
{
- thermal_state.thz->tc2 = val;
+ thermal_state.device->thz->tc2 = val;
return 0;
}
static int tegra_thermal_tc2_get(void *data, u64 *val)
{
- *val = (u64)thermal_state.thz->tc2;
+ *val = (u64)thermal_state.device->thz->tc2;
return 0;
}
@@ -435,13 +472,13 @@ DEFINE_SIMPLE_ATTRIBUTE(tc2_fops,
static int tegra_thermal_passive_delay_set(void *data, u64 val)
{
- thermal_state.thz->passive_delay = val;
+ thermal_state.device->thz->passive_delay = val;
return 0;
}
static int tegra_thermal_passive_delay_get(void *data, u64 *val)
{
- *val = (u64)thermal_state.thz->passive_delay;
+ *val = (u64)thermal_state.device->thz->passive_delay;
return 0;
}
diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c
index 9e8d32fb79fa..61dc5cdb6a7d 100644
--- a/arch/arm/mach-tegra/tegra3_throttle.c
+++ b/arch/arm/mach-tegra/tegra3_throttle.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_throttle.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,37 +27,28 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/thermal.h>
+#include <mach/thermal.h>
#include "clock.h"
#include "cpu-tegra.h"
#include "dvfs.h"
-/* tegra throttling require frequencies in the table to be in ascending order */
-static struct cpufreq_frequency_table *cpu_freq_table;
-static struct {
- unsigned int cpu_freq;
- int core_cap_level;
-} throttle_table[] = {
- { 0, 1000 }, /* placeholder for cpu floor rate */
- { 640000, 1000 },
- { 640000, 1000 },
- { 640000, 1000 },
- { 640000, 1000 },
- { 640000, 1000 },
- { 760000, 1000 },
- { 760000, 1050 },
- {1000000, 1050 },
- {1000000, 1100 },
-};
-
-static int is_throttling;
-static int throttle_index;
-static struct thermal_cooling_device *cdev;
+static struct mutex *cpu_throttle_lock;
+static DEFINE_MUTEX(bthrot_list_lock);
+static LIST_HEAD(bthrot_list);
static unsigned int clip_to_table(unsigned int cpu_freq)
{
int i;
+ struct cpufreq_frequency_table *cpu_freq_table;
+ struct tegra_cpufreq_table_data *table_data =
+ tegra_cpufreq_table_get();
+
+ if (IS_ERR_OR_NULL(table_data))
+ return -EINVAL;
+
+ cpu_freq_table = table_data->freq_table;
for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (cpu_freq_table[i].frequency > cpu_freq)
@@ -69,13 +60,37 @@ static unsigned int clip_to_table(unsigned int cpu_freq)
unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
{
- return is_throttling ?
- min(requested_speed, throttle_table[throttle_index].cpu_freq) :
- requested_speed;
+ struct balanced_throttle *bthrot;
+ unsigned int throttle_speed = requested_speed;
+ int index;
+
+ mutex_lock(&bthrot_list_lock);
+ list_for_each_entry(bthrot, &bthrot_list, node) {
+ if (bthrot->is_throttling) {
+ index = bthrot->throttle_index;
+ throttle_speed = min(throttle_speed,
+ bthrot->throt_tab[index].cpu_freq);
+ }
+ }
+ mutex_unlock(&bthrot_list_lock);
+
+ return throttle_speed;
}
bool tegra_is_throttling(void)
{
+ struct balanced_throttle *bthrot;
+ bool is_throttling = false;
+
+ mutex_lock(&bthrot_list_lock);
+ list_for_each_entry(bthrot, &bthrot_list, node) {
+ if (bthrot->is_throttling) {
+ is_throttling = true;
+ break;
+ }
+ }
+ mutex_unlock(&bthrot_list_lock);
+
return is_throttling;
}
@@ -83,7 +98,10 @@ static int
tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *max_state)
{
- *max_state = ARRAY_SIZE(throttle_table);
+ struct balanced_throttle *bthrot = cdev->devdata;
+
+ *max_state = bthrot->throt_tab_size;
+
return 0;
}
@@ -91,9 +109,13 @@ static int
tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
- *cur_state = is_throttling ?
- (ARRAY_SIZE(throttle_table) - throttle_index) :
+ struct balanced_throttle *bthrot = cdev->devdata;
+
+ mutex_lock(cpu_throttle_lock);
+ *cur_state = bthrot->is_throttling ?
+ (bthrot->throt_tab_size - bthrot->throttle_index) :
0;
+ mutex_unlock(cpu_throttle_lock);
return 0;
}
@@ -102,84 +124,55 @@ static int
tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long cur_state)
{
+ struct balanced_throttle *bthrot = cdev->devdata;
int core_level;
+ int index;
+ mutex_lock(cpu_throttle_lock);
if (cur_state == 0) {
/* restore speed requested by governor */
- if (is_throttling) {
+ if (bthrot->is_throttling) {
tegra_dvfs_core_cap_enable(false);
- is_throttling = false;
+ bthrot->is_throttling = false;
}
tegra_cpu_set_speed_cap(NULL);
} else {
- if (!is_throttling) {
+ if (!bthrot->is_throttling) {
tegra_dvfs_core_cap_enable(true);
- is_throttling = true;
+ bthrot->is_throttling = true;
}
- throttle_index = ARRAY_SIZE(throttle_table) - cur_state;
- core_level = throttle_table[throttle_index].core_cap_level;
+ bthrot->throttle_index = bthrot->throt_tab_size - cur_state;
+ index = bthrot->throttle_index;
+ core_level = bthrot->throt_tab[index].core_cap_level;
tegra_dvfs_core_cap_level_set(core_level);
tegra_cpu_set_speed_cap(NULL);
}
+ mutex_unlock(cpu_throttle_lock);
return 0;
}
-struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
+static struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
.get_max_state = tegra_throttle_get_max_state,
.get_cur_state = tegra_throttle_get_cur_state,
.set_cur_state = tegra_throttle_set_cur_state,
};
-int __init tegra_throttle_init(struct mutex *cpu_lock)
-{
- int i;
- struct tegra_cpufreq_table_data *table_data =
- tegra_cpufreq_table_get();
- if (IS_ERR_OR_NULL(table_data))
- return -EINVAL;
-
- cpu_freq_table = table_data->freq_table;
- throttle_table[0].cpu_freq =
- cpu_freq_table[table_data->throttle_lowest_index].frequency;
-
- for (i = 0; i < ARRAY_SIZE(throttle_table); i++) {
- unsigned int cpu_freq = throttle_table[i].cpu_freq;
- throttle_table[i].cpu_freq = clip_to_table(cpu_freq);
- }
-
- cdev = thermal_cooling_device_register("Throttle", NULL,
- &tegra_throttle_cooling_ops);
-
- if (IS_ERR(cdev)) {
- cdev = NULL;
- return -ENODEV;
- }
-
- return 0;
-}
-
-void tegra_throttle_exit(void)
-{
- if (cdev) {
- thermal_cooling_device_unregister(cdev);
- cdev = NULL;
- }
-}
-
#ifdef CONFIG_DEBUG_FS
static int table_show(struct seq_file *s, void *data)
{
+ struct balanced_throttle *bthrot = s->private;
int i;
- for (i = 0; i < ARRAY_SIZE(throttle_table); i++)
+ for (i = 0; i < bthrot->throt_tab_size; i++)
seq_printf(s, "[%d] = %7u %4d\n",
- i, throttle_table[i].cpu_freq,
- throttle_table[i].core_cap_level);
+ i, bthrot->throt_tab[i].cpu_freq,
+ bthrot->throt_tab[i].core_cap_level);
+
return 0;
}
@@ -191,6 +184,7 @@ static int table_open(struct inode *inode, struct file *file)
static ssize_t table_write(struct file *file,
const char __user *userbuf, size_t count, loff_t *ppos)
{
+ struct balanced_throttle *bthrot = file->private_data;
char buf[80];
int table_idx;
unsigned int cpu_freq;
@@ -211,12 +205,12 @@ static ssize_t table_write(struct file *file,
&table_idx, &cpu_freq, &core_cap_level) != 3)
return -1;
- if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table)))
+ if ((table_idx < 0) || (table_idx >= bthrot->throt_tab_size))
return -EINVAL;
/* round new settings before updating table */
- throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq);
- throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50;
+ bthrot->throt_tab[table_idx].cpu_freq = clip_to_table(cpu_freq);
+ bthrot->throt_tab[table_idx].core_cap_level = (core_cap_level / 50) * 50;
return count;
}
@@ -229,14 +223,85 @@ static const struct file_operations table_fops = {
.release = single_release,
};
+static struct dentry *throttle_debugfs_root;
+#endif /* CONFIG_DEBUG_FS */
-int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root)
+
+struct balanced_throttle *balanced_throttle_register(
+ int id,
+ struct throttle_table *table,
+ int tab_size)
{
- if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root,
- NULL, &table_fops))
- return -ENOMEM;
+ struct balanced_throttle *bthrot;
+ char name[32];
+ int i, index;
+ struct cpufreq_frequency_table *cpu_freq_table;
+ struct tegra_cpufreq_table_data *table_data =
+ tegra_cpufreq_table_get();
+ if (IS_ERR_OR_NULL(table_data))
+ return ERR_PTR(-EINVAL);
+
+ cpu_freq_table = table_data->freq_table;
+
+ bthrot = kzalloc(sizeof(struct balanced_throttle), GFP_KERNEL);
+
+ if (!bthrot)
+ return ERR_PTR(-ENOMEM);
+
+ bthrot->id = id;
+ bthrot->throt_tab = table;
+ bthrot->throt_tab_size = tab_size;
+
+
+ for (i = 0; i < bthrot->throt_tab_size; i++) {
+ unsigned int cpu_freq = bthrot->throt_tab[i].cpu_freq;
+ if (cpu_freq == 0) {
+ index = table_data->throttle_lowest_index;
+ cpu_freq = cpu_freq_table[index].frequency;
+ } else {
+ cpu_freq = clip_to_table(cpu_freq);
+ }
+ bthrot->throt_tab[i].cpu_freq = cpu_freq;
+ }
+
+ bthrot->cdev = thermal_cooling_device_register(
+ "balanced",
+ bthrot,
+ &tegra_throttle_cooling_ops);
+
+ if (IS_ERR(bthrot->cdev)) {
+ bthrot->cdev = NULL;
+ kfree(bthrot);
+ return ERR_PTR(-ENODEV);
+ }
+
+ mutex_lock(&bthrot_list_lock);
+ list_add(&bthrot->node, &bthrot_list);
+ mutex_unlock(&bthrot_list_lock);
+
+#ifdef CONFIG_DEBUG_FS
+ sprintf(name, "throttle_table%d", id);
+ debugfs_create_file(name,0644, throttle_debugfs_root,
+ bthrot, &table_fops);
+#endif
+
+ return bthrot;
+}
+
+int __init tegra_throttle_init(struct mutex *cpu_lock)
+{
+ cpu_throttle_lock = cpu_lock;
+#ifdef CONFIG_DEBUG_FS
+ throttle_debugfs_root = debugfs_create_dir("tegra_throttle", 0);
+#endif
return 0;
}
-#endif /* CONFIG_DEBUG_FS */
+
+void tegra_throttle_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(throttle_debugfs_root);
+#endif
+}