aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/thermal_framework/governor/Makefile1
-rw-r--r--drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c199
-rw-r--r--drivers/staging/thermal_framework/omap4_duty_cycle.c45
-rw-r--r--include/linux/omap4_duty_cycle_governor.h47
4 files changed, 290 insertions, 2 deletions
diff --git a/drivers/staging/thermal_framework/governor/Makefile b/drivers/staging/thermal_framework/governor/Makefile
index 0b5eff7..8ba37ee 100644
--- a/drivers/staging/thermal_framework/governor/Makefile
+++ b/drivers/staging/thermal_framework/governor/Makefile
@@ -2,3 +2,4 @@
# Makefile for Thermal governor drivers.
#
obj-$(CONFIG_OMAP_DIE_GOVERNOR) += omap_die_governor.o
+obj-$(CONFIG_OMAP4_DUTY_CYCLE) += omap4_duty_cycle_governor.o
diff --git a/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c b/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c
new file mode 100644
index 0000000..c1d4edb
--- /dev/null
+++ b/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c
@@ -0,0 +1,199 @@
+/*
+ * Duty cycle governor
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Eugene Mandrenko <Ievgen.mandrenko@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/omap4_duty_cycle_governor.h>
+#include <plat/omap_device.h>
+
+#define NORMAL_TEMP_MONITORING_RATE 1000
+#define NORMAL_MONITORING_RATE 10000
+#define DEFAULT_TEMPERATURE 65000
+#define TEMP_THRESHOLD 1
+#define INIT_SECTION -1
+
+struct duty_governor {
+ struct pcb_sens *tpcb;
+ struct duty_cycle *tduty;
+ struct pcb_section *tpcb_sections;
+ int period;
+ int previous_temp;
+ int curr_pcb_temp;
+ int previous_pcb_temp;
+ int working_section;
+ int npcb_sections;
+ struct delayed_work duty_cycle_governor_work;
+};
+
+static struct duty_governor *t_governor;
+static struct pcb_section *pcb_sections;
+static int pcb_sections_size;
+
+void omap4_duty_pcb_section_reg(struct pcb_section *pcb_sect, int sect_size)
+{
+ pcb_sections = pcb_sect;
+ pcb_sections_size = sect_size;
+}
+
+static void omap4_duty_schedule(struct duty_governor *t_gov)
+{
+ if (!IS_ERR_OR_NULL(t_gov) &&
+ !IS_ERR_OR_NULL(t_gov->tpcb) &&
+ !IS_ERR_OR_NULL(t_gov->tduty))
+ schedule_delayed_work(&t_governor->duty_cycle_governor_work,
+ msecs_to_jiffies(0));
+}
+
+int omap4_duty_pcb_register(struct pcb_sens *tpcb)
+{
+ if (!IS_ERR_OR_NULL(t_governor)) {
+ if (t_governor->tpcb == NULL) {
+ t_governor->tpcb = tpcb;
+ t_governor->period = NORMAL_TEMP_MONITORING_RATE;
+ } else {
+ pr_err("%s:dublicate of pcb registration\n", __func__);
+
+ return -EBUSY;
+ }
+ }
+ omap4_duty_schedule(t_governor);
+
+ return 0;
+}
+static bool is_treshold(struct duty_governor *tgov)
+{
+ int delta;
+
+ delta = abs(tgov->previous_pcb_temp - tgov->curr_pcb_temp);
+
+ if (delta > TEMP_THRESHOLD)
+ return true;
+
+ return false;
+}
+
+static int omap4_duty_apply_constraint(struct duty_governor *tgov,
+ int sect_num)
+{
+ struct pcb_section *t_pcb_sections = &tgov->tpcb_sections[sect_num];
+ struct duty_cycle_params *tduty_params = &t_pcb_sections->tduty_params;
+ int dc_enabled = t_pcb_sections->duty_cycle_enabled;
+ struct duty_cycle *t_duty = tgov->tduty;
+ int ret = true;
+
+ if (tgov->working_section != sect_num) {
+ ret = tgov->tduty->enable(false, false);
+
+ if (ret)
+ return ret;
+
+ if (dc_enabled) {
+ if (t_duty->update_params(tduty_params))
+ return ret;
+
+ tgov->tduty->enable(dc_enabled, true);
+ }
+ tgov->working_section = sect_num;
+ }
+
+ return ret;
+}
+
+static void omap4_duty_update(struct duty_governor *tgov)
+{
+ int sect_num;
+
+ for (sect_num = 0; sect_num < tgov->npcb_sections; sect_num++)
+ if (tgov->tpcb_sections[sect_num].pcb_temp_level >
+ tgov->curr_pcb_temp)
+ break;
+ if (sect_num >= tgov->npcb_sections)
+ sect_num = tgov->npcb_sections - 1;
+
+ if (omap4_duty_apply_constraint(tgov, sect_num))
+ tgov->previous_pcb_temp = tgov->curr_pcb_temp;
+}
+
+static void omap4_duty_governor_delayed_work_fn(struct work_struct *work)
+{
+ if (!IS_ERR_OR_NULL(t_governor->tpcb)) {
+ if (!IS_ERR_OR_NULL(t_governor->tpcb->update_temp)) {
+ t_governor->curr_pcb_temp =
+ t_governor->tpcb->update_temp();
+ if (is_treshold(t_governor))
+ omap4_duty_update(t_governor);
+ } else {
+ pr_err("%s:update_temp() isn't defined\n", __func__);
+ }
+ }
+ schedule_delayed_work(&t_governor->duty_cycle_governor_work,
+ msecs_to_jiffies(t_governor->period));
+}
+
+int omap4_duty_cycle_register(struct duty_cycle *tduty)
+{
+ if (!IS_ERR_OR_NULL(t_governor)) {
+ if (t_governor->tduty == NULL) {
+ t_governor->tduty = tduty;
+ } else {
+ pr_err("%s:dublicate of duty cycle registration\n",
+ __func__);
+
+ return -EBUSY;
+ }
+ }
+ omap4_duty_schedule(t_governor);
+
+ return 0;
+}
+
+static int __init omap4_duty_governor_init(void)
+{
+ if (!cpu_is_omap443x())
+ return 0;
+
+ t_governor = kzalloc(sizeof(struct duty_governor), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(t_governor)) {
+ pr_err("%s:Cannot allocate memory\n", __func__);
+
+ return -ENOMEM;
+ }
+ t_governor->period = NORMAL_MONITORING_RATE;
+ t_governor->previous_temp = DEFAULT_TEMPERATURE;
+ t_governor->tpcb_sections = pcb_sections;
+ t_governor->npcb_sections = pcb_sections_size;
+ t_governor->working_section = INIT_SECTION;
+ INIT_DELAYED_WORK(&t_governor->duty_cycle_governor_work,
+ omap4_duty_governor_delayed_work_fn);
+
+ return 0;
+}
+
+static void __exit omap4_duty_governor_exit(void)
+{
+ cancel_delayed_work_sync(&t_governor->duty_cycle_governor_work);
+ kfree(t_governor);
+}
+
+early_initcall(omap4_duty_governor_init);
+module_exit(omap4_duty_governor_exit);
+
+MODULE_AUTHOR("Euvgen Mandrenko <ievgen.mandrenko@ti.com>");
+MODULE_DESCRIPTION("OMAP on-die thermal governor");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/thermal_framework/omap4_duty_cycle.c b/drivers/staging/thermal_framework/omap4_duty_cycle.c
index cf81548..896ec5c 100644
--- a/drivers/staging/thermal_framework/omap4_duty_cycle.c
+++ b/drivers/staging/thermal_framework/omap4_duty_cycle.c
@@ -30,6 +30,7 @@
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/omap4_duty_cycle_governor.h>
#include <plat/omap_device.h>
@@ -62,6 +63,7 @@ static bool enabled;
static bool saved_hotplug_enabled;
static int heating_budget;
static unsigned long t_heating_start;
+static struct duty_cycle *t_duty;
static struct workqueue_struct *duty_wq;
static struct delayed_work work_exit_cool;
@@ -556,6 +558,39 @@ static struct platform_driver omap4_duty_driver = {
.remove = __exit_p(omap4_duty_remove),
};
+static int update_params(struct duty_cycle_params *dc_params)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(&mutex_duty);
+ if (ret)
+ return ret;
+
+ cooling_rate = dc_params->cooling_rate;
+ nitro_rate = dc_params->nitro_rate;
+ nitro_percentage = dc_params->nitro_percentage;
+ nitro_interval = dc_params->nitro_interval;
+
+ mutex_unlock(&mutex_duty);
+
+ return 0;
+}
+
+static int __init omap4_duty_register(void)
+{
+ t_duty = kzalloc(sizeof(struct duty_cycle), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(t_duty)) {
+ pr_err("%s:Cannot allocate memory\n", __func__);
+
+ return -ENOMEM;
+ }
+ t_duty->enable = omap4_duty_cycle_set_enabled;
+ t_duty->update_params = update_params;
+ omap4_duty_cycle_register(t_duty);
+
+ return 0;
+}
+
/* Module Interface */
static int __init omap4_duty_module_init(void)
{
@@ -604,12 +639,18 @@ static int __init omap4_duty_module_init(void)
goto unregister_hotplug;
}
- err = platform_driver_probe(&omap4_duty_driver, omap4_duty_probe);
+ err = omap4_duty_register();
if (err)
goto exit_pdevice;
+ err = platform_driver_probe(&omap4_duty_driver, omap4_duty_probe);
+ if (err)
+ goto unregister_duty;
+
return 0;
+unregister_duty:
+ kfree(t_duty);
exit_pdevice:
platform_device_unregister(omap4_duty_device);
unregister_hotplug:
@@ -637,7 +678,7 @@ static void __exit omap4_duty_module_exit(void)
cancel_work_sync(&work_enter_cool1);
cancel_work_sync(&work_cpu1_plugin);
cancel_work_sync(&work_cpu1_plugout);
-
+ kfree(t_duty);
destroy_workqueue(duty_wq);
pr_debug("%s Done\n", __func__);
diff --git a/include/linux/omap4_duty_cycle_governor.h b/include/linux/omap4_duty_cycle_governor.h
new file mode 100644
index 0000000..4e2baa9
--- /dev/null
+++ b/include/linux/omap4_duty_cycle_governor.h
@@ -0,0 +1,47 @@
+/*
+ * Duty sycle governor
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Eugene Mandrenko <ievgen.mandrenko@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef __OMAP4_DUTY_CYCLE_GOVERNOR_H__
+#define __OMAP4_DUTY_CYCLE_GOVERNOR_H__
+
+struct pcb_sens {
+ int (*update_temp) (void);
+};
+
+struct duty_cycle_params {
+ u32 nitro_rate; /* the maximum OPP frequency */
+ u32 cooling_rate; /* the OPP used to cool off */
+ u32 nitro_interval; /* time interval to control the duty cycle */
+ u32 nitro_percentage; /* % out of nitro_interval to use max OPP */
+};
+
+struct pcb_section {
+ u32 pcb_temp_level;
+ u32 max_opp;
+ struct duty_cycle_params tduty_params;
+ bool duty_cycle_enabled;
+};
+
+struct duty_cycle {
+ int (*update_params)(struct duty_cycle_params *);
+ int (*enable)(bool val, bool update);
+};
+
+void omap4_duty_pcb_section_reg(struct pcb_section *pcb_sect, int sect_size);
+int omap4_duty_pcb_register(struct pcb_sens *tpcb);
+int omap4_duty_cycle_register(struct duty_cycle *tduty);
+#endif /*__OMAP4_DUTY_CYCLE_GOVERNOR_H__*/