ARM: tegra: Object based balanced throttling
Joshua Primero [Thu, 9 Feb 2012 20:03:00 +0000 (12:03 -0800)]
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>

arch/arm/mach-tegra/cpu-tegra.c
arch/arm/mach-tegra/include/mach/thermal.h
arch/arm/mach-tegra/tegra3_thermal.c
arch/arm/mach-tegra/tegra3_throttle.c

index 5c680b8..9bed927 100644 (file)
@@ -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;
 
index 6758622..7859997 100644 (file)
@@ -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);
index 6322eb3..d94158a 100644 (file)
@@ -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;
 }
 
index 9e8d32f..61dc5cd 100644 (file)
@@ -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
 #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
+}