PKGBUILDs/core/linux-odroidx/mdrjr.patch

1055 lines
28 KiB
Diff

diff -ruN linux/arch/arm/configs/odroidx_defconfig linux-tmu/arch/arm/configs/odroidx_defconfig
--- linux/arch/arm/configs/odroidx_defconfig 2012-10-10 09:50:53.149487413 -0300
+++ linux-tmu/arch/arm/configs/odroidx_defconfig 2012-10-12 19:02:06.761366308 -0300
@@ -570,15 +570,15 @@
CONFIG_CPU_FREQ_TABLE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
#
@@ -587,6 +587,9 @@
CONFIG_ARM_EXYNOS_CPUFREQ=y
# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
CONFIG_ARM_EXYNOS4X12_CPUFREQ=y
+# CONFIG_EXYNOS4X12_1600MHZ_SUPPORT is not set
+# CONFIG_EXYNOS4X12_1704MHZ_SUPPORT is not set
+# CONFIG_EXYNOS4X12_1800MHZ_SUPPORT is not set
# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
@@ -2833,6 +2836,7 @@
# CONFIG_MCP4725 is not set
CONFIG_PWM=y
CONFIG_PWM_SAMSUNG=y
+CONFIG_HKDK4412_TMU=y
#
# File systems
diff -ruN linux/arch/arm/mach-exynos/mach-hkdk4412.c linux-tmu/arch/arm/mach-exynos/mach-hkdk4412.c
--- linux/arch/arm/mach-exynos/mach-hkdk4412.c 2012-10-10 09:50:53.225487412 -0300
+++ linux-tmu/arch/arm/mach-exynos/mach-hkdk4412.c 2012-10-12 17:11:12.000000000 -0300
@@ -186,7 +186,7 @@
.constraints = {
.name = "VDD_ARM_1.3V",
.min_uV = 800000,
- .max_uV = 1350000,
+ .max_uV = 1400000,
.always_on = 1,
.boot_on = 1,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
diff -ruN linux/drivers/cpufreq/exynos4x12-cpufreq.c linux-tmu/drivers/cpufreq/exynos4x12-cpufreq.c
--- linux/drivers/cpufreq/exynos4x12-cpufreq.c 2012-10-10 09:50:54.693487379 -0300
+++ linux-tmu/drivers/cpufreq/exynos4x12-cpufreq.c 2012-10-12 18:20:24.000000000 -0300
@@ -20,7 +20,7 @@
#include <mach/regs-clock.h>
#include <mach/cpufreq.h>
-#define CPUFREQ_LEVEL_END (L13 + 1)
+#define CPUFREQ_LEVEL_END (L16 + 1)
static int max_support_idx;
static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
@@ -39,20 +39,23 @@
static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, 1500 * 1000},
- {L1, 1400 * 1000},
- {L2, 1300 * 1000},
- {L3, 1200 * 1000},
- {L4, 1100 * 1000},
- {L5, 1000 * 1000},
- {L6, 900 * 1000},
- {L7, 800 * 1000},
- {L8, 700 * 1000},
- {L9, 600 * 1000},
- {L10, 500 * 1000},
- {L11, 400 * 1000},
- {L12, 300 * 1000},
- {L13, 200 * 1000},
+ {L0, 1800 * 1000},
+ {L1, 1704 * 1000},
+ {L2, 1600 * 1000},
+ {L3, 1500 * 1000},
+ {L4, 1400 * 1000},
+ {L5, 1300 * 1000},
+ {L6, 1200 * 1000},
+ {L7, 1100 * 1000},
+ {L8, 1000 * 1000},
+ {L9, 900 * 1000},
+ {L10, 800 * 1000},
+ {L11, 700 * 1000},
+ {L12, 600 * 1000},
+ {L13, 500 * 1000},
+ {L14, 400 * 1000},
+ {L15, 300 * 1000},
+ {L16, 200 * 1000},
{0, CPUFREQ_TABLE_END},
};
@@ -64,46 +67,55 @@
* { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
* DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
*/
- /* ARM L0: 1500 MHz */
+ /* ARM L0: 1800 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L1: 1704 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L2: 1600 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L3: 1500 MHz */
{ 0, 3, 7, 0, 6, 1, 2, 0 },
- /* ARM L1: 1400 MHz */
+ /* ARM L4: 1400 MHz */
{ 0, 3, 7, 0, 6, 1, 2, 0 },
- /* ARM L2: 1300 MHz */
+ /* ARM L5: 1300 MHz */
{ 0, 3, 7, 0, 5, 1, 2, 0 },
- /* ARM L3: 1200 MHz */
+ /* ARM L6: 1200 MHz */
{ 0, 3, 7, 0, 5, 1, 2, 0 },
- /* ARM L4: 1100 MHz */
+ /* ARM L7: 1100 MHz */
{ 0, 3, 6, 0, 4, 1, 2, 0 },
- /* ARM L5: 1000 MHz */
+ /* ARM L8: 1000 MHz */
{ 0, 2, 5, 0, 4, 1, 1, 0 },
- /* ARM L6: 900 MHz */
+ /* ARM L9: 900 MHz */
{ 0, 2, 5, 0, 3, 1, 1, 0 },
- /* ARM L7: 800 MHz */
+ /* ARM L10: 800 MHz */
{ 0, 2, 5, 0, 3, 1, 1, 0 },
- /* ARM L8: 700 MHz */
+ /* ARM L11: 700 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L9: 600 MHz */
+ /* ARM L12: 600 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L10: 500 MHz */
+ /* ARM L13: 500 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L11: 400 MHz */
+ /* ARM L14: 400 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L12: 300 MHz */
+ /* ARM L15: 300 MHz */
{ 0, 2, 4, 0, 2, 1, 1, 0 },
- /* ARM L13: 200 MHz */
+ /* ARM L16: 200 MHz */
{ 0, 1, 3, 0, 1, 1, 1, 0 },
};
@@ -113,46 +125,56 @@
* { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
* DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
*/
- /* ARM L0: 1500 MHz */
+
+ /* ARM L0: 1800 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L1: 1704 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L2: 1600 Mhz */
+ { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+ /* ARM L3: 1500 MHz */
{ 0, 3, 7, 0, 6, 1, 2, 0 },
- /* ARM L1: 1400 MHz */
+ /* ARM L4: 1400 MHz */
{ 0, 3, 7, 0, 6, 1, 2, 0 },
- /* ARM L2: 1300 MHz */
+ /* ARM L5: 1300 MHz */
{ 0, 3, 7, 0, 5, 1, 2, 0 },
- /* ARM L3: 1200 MHz */
+ /* ARM L6: 1200 MHz */
{ 0, 3, 7, 0, 5, 1, 2, 0 },
- /* ARM L4: 1100 MHz */
+ /* ARM L7: 1100 MHz */
{ 0, 3, 6, 0, 4, 1, 2, 0 },
- /* ARM L5: 1000 MHz */
+ /* ARM L8: 1000 MHz */
{ 0, 2, 5, 0, 4, 1, 1, 0 },
- /* ARM L6: 900 MHz */
+ /* ARM L9: 900 MHz */
{ 0, 2, 5, 0, 3, 1, 1, 0 },
- /* ARM L7: 800 MHz */
+ /* ARM L10: 800 MHz */
{ 0, 2, 5, 0, 3, 1, 1, 0 },
- /* ARM L8: 700 MHz */
+ /* ARM L11: 700 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L9: 600 MHz */
+ /* ARM L12: 600 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L10: 500 MHz */
+ /* ARM L13: 500 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L11: 400 MHz */
+ /* ARM L14: 400 MHz */
{ 0, 2, 4, 0, 3, 1, 1, 0 },
- /* ARM L12: 300 MHz */
+ /* ARM L15: 300 MHz */
{ 0, 2, 4, 0, 2, 1, 1, 0 },
- /* ARM L13: 200 MHz */
+ /* ARM L16: 200 MHz */
{ 0, 1, 3, 0, 1, 1, 1, 0 },
};
@@ -160,46 +182,55 @@
/* Clock divider value for following
* { DIVCOPY, DIVHPM }
*/
- /* ARM L0: 1500 MHz */
+ /* ARM L0: 1800 Mhz */
+ { 6, 0 },
+
+ /* ARM L1: 1704 Mhz */
+ { 6, 0 },
+
+ /* ARM L2: 1600 Mhz */
+ { 6, 0 },
+
+ /* ARM L3: 1500 MHz */
{ 6, 0 },
- /* ARM L1: 1400 MHz */
+ /* ARM L4: 1400 MHz */
{ 6, 0 },
- /* ARM L2: 1300 MHz */
+ /* ARM L5: 1300 MHz */
{ 5, 0 },
- /* ARM L3: 1200 MHz */
+ /* ARM L6: 1200 MHz */
{ 5, 0 },
- /* ARM L4: 1100 MHz */
+ /* ARM L7: 1100 MHz */
{ 4, 0 },
- /* ARM L5: 1000 MHz */
+ /* ARM L8: 1000 MHz */
{ 4, 0 },
- /* ARM L6: 900 MHz */
+ /* ARM L9: 900 MHz */
{ 3, 0 },
- /* ARM L7: 800 MHz */
+ /* ARM L10: 800 MHz */
{ 3, 0 },
- /* ARM L8: 700 MHz */
+ /* ARM L11: 700 MHz */
{ 3, 0 },
- /* ARM L9: 600 MHz */
+ /* ARM L12: 600 MHz */
{ 3, 0 },
- /* ARM L10: 500 MHz */
+ /* ARM L13: 500 MHz */
{ 3, 0 },
- /* ARM L11: 400 MHz */
+ /* ARM L14: 400 MHz */
{ 3, 0 },
- /* ARM L12: 300 MHz */
+ /* ARM L15: 300 MHz */
{ 3, 0 },
- /* ARM L13: 200 MHz */
+ /* ARM L16: 200 MHz */
{ 3, 0 },
};
@@ -207,96 +238,130 @@
/* Clock divider value for following
* { DIVCOPY, DIVHPM, DIVCORES }
*/
- /* ARM L0: 1500 MHz */
+ /* ARM L0: 1800 Mhz */
+ { 6, 0, 7 },
+
+ /* ARM L1: 1704 Mhz */
+ { 6, 0, 7 },
+
+ /* ARM L2: 1600 Mhz */
+ { 6, 0, 7 },
+
+ /* ARM L3: 1500 MHz */
{ 6, 0, 7 },
- /* ARM L1: 1400 MHz */
+ /* ARM L4: 1400 MHz */
{ 6, 0, 6 },
- /* ARM L2: 1300 MHz */
+ /* ARM L5: 1300 MHz */
{ 5, 0, 6 },
- /* ARM L3: 1200 MHz */
+ /* ARM L6: 1200 MHz */
{ 5, 0, 5 },
- /* ARM L4: 1100 MHz */
+ /* ARM L7: 1100 MHz */
{ 4, 0, 5 },
- /* ARM L5: 1000 MHz */
+ /* ARM L8: 1000 MHz */
{ 4, 0, 4 },
- /* ARM L6: 900 MHz */
+ /* ARM L9: 900 MHz */
{ 3, 0, 4 },
- /* ARM L7: 800 MHz */
+ /* ARM L10: 800 MHz */
{ 3, 0, 3 },
- /* ARM L8: 700 MHz */
+ /* ARM L11: 700 MHz */
{ 3, 0, 3 },
- /* ARM L9: 600 MHz */
+ /* ARM L12: 600 MHz */
{ 3, 0, 2 },
- /* ARM L10: 500 MHz */
+ /* ARM L13: 500 MHz */
{ 3, 0, 2 },
- /* ARM L11: 400 MHz */
+ /* ARM L14: 400 MHz */
{ 3, 0, 1 },
- /* ARM L12: 300 MHz */
+ /* ARM L15: 300 MHz */
{ 3, 0, 1 },
- /* ARM L13: 200 MHz */
+ /* ARM L16: 200 MHz */
{ 3, 0, 0 },
};
static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
- /* APLL FOUT L0: 1500 MHz */
+ /* APLL FOUT L0: 1800 Mhz */
+ ((300 << 16) | (4 << 8) | (0x0)),
+
+ /* APLL FOUT L1: 1704 Mhz */
+ ((213 << 16) | (3 << 8) | (0x0)),
+
+ /* APLL FOUT L2: 1600 Mhz */
+ ((200 << 16) | (3 << 8) | (0x0)),
+
+ /* APLL FOUT L3: 1500 MHz */
((250 << 16) | (4 << 8) | (0x0)),
- /* APLL FOUT L1: 1400 MHz */
+ /* APLL FOUT L4: 1400 MHz */
((175 << 16) | (3 << 8) | (0x0)),
- /* APLL FOUT L2: 1300 MHz */
+ /* APLL FOUT L5: 1300 MHz */
((325 << 16) | (6 << 8) | (0x0)),
- /* APLL FOUT L3: 1200 MHz */
+ /* APLL FOUT L6: 1200 MHz */
((200 << 16) | (4 << 8) | (0x0)),
- /* APLL FOUT L4: 1100 MHz */
+ /* APLL FOUT L7: 1100 MHz */
((275 << 16) | (6 << 8) | (0x0)),
- /* APLL FOUT L5: 1000 MHz */
+ /* APLL FOUT L8: 1000 MHz */
((125 << 16) | (3 << 8) | (0x0)),
- /* APLL FOUT L6: 900 MHz */
+ /* APLL FOUT L9: 900 MHz */
((150 << 16) | (4 << 8) | (0x0)),
- /* APLL FOUT L7: 800 MHz */
+ /* APLL FOUT L10: 800 MHz */
((100 << 16) | (3 << 8) | (0x0)),
- /* APLL FOUT L8: 700 MHz */
+ /* APLL FOUT L11: 700 MHz */
((175 << 16) | (3 << 8) | (0x1)),
- /* APLL FOUT L9: 600 MHz */
+ /* APLL FOUT L12: 600 MHz */
((200 << 16) | (4 << 8) | (0x1)),
- /* APLL FOUT L10: 500 MHz */
+ /* APLL FOUT L13: 500 MHz */
((125 << 16) | (3 << 8) | (0x1)),
- /* APLL FOUT L11 400 MHz */
+ /* APLL FOUT L14: 400 MHz */
((100 << 16) | (3 << 8) | (0x1)),
- /* APLL FOUT L12: 300 MHz */
+ /* APLL FOUT L15: 300 MHz */
((200 << 16) | (4 << 8) | (0x2)),
- /* APLL FOUT L13: 200 MHz */
+ /* APLL FOUT L16: 200 MHz */
((100 << 16) | (3 << 8) | (0x2)),
};
static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
- 1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
- 1000000, 987500, 975000, 950000, 925000, 900000, 900000
+ 1400000, // L0
+ 1375000, // L1
+ 1300000, // L2
+ 1300000, // L3
+ 1225000, // L4
+ 1150000, // L5
+ 1100000, // L6
+ 1050000, // L7
+ 1012500, // L8
+ 987500, // L9
+ 975000, // L10
+ 962500, // L11
+ 950000, // L12
+ 925000, // L13
+ 900000, // L14
+ 900000, // L15
+ 800000, // L16
+
};
static void exynos4x12_set_clkdiv(unsigned int div_index)
@@ -420,11 +485,23 @@
{
unsigned int i;
- max_support_idx = L1;
-
- /* Not supported */
- exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
-
+ #ifdef CONFIG_EXYNOS4X12_1800MHZ_SUPPORT
+ max_support_idx = L0;
+ #elif defined(CONFIG_EXYNOS4X12_1704MHZ_SUPPORT)
+ max_support_idx = L1;
+ exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+ #elif defined(CONFIG_EXYNOS4X12_1600MHZ_SUPPORT)
+ max_support_idx = L2;
+ exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+ exynos4x12_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
+ #else
+ max_support_idx = L4;
+ exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+ exynos4x12_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
+ exynos4x12_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
+ exynos4x12_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
+ #endif
+
for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
exynos4x12_volt_table[i] = asv_voltage_4x12[i];
}
diff -ruN linux/drivers/cpufreq/Kconfig.arm linux-tmu/drivers/cpufreq/Kconfig.arm
--- linux/drivers/cpufreq/Kconfig.arm 2012-10-10 09:50:54.693487379 -0300
+++ linux-tmu/drivers/cpufreq/Kconfig.arm 2012-10-12 18:18:36.000000000 -0300
@@ -71,6 +71,21 @@
This adds the CPUFreq driver for Samsung EXYNOS4X12
SoC (EXYNOS4212 or EXYNOS4412).
+config EXYNOS4X12_1600MHZ_SUPPORT
+ bool "Max 1600MHz CPUFREQ LEVEL"
+ help
+ Max 1.6Ghz support
+
+config EXYNOS4X12_1704MHZ_SUPPORT
+ bool "Max 1704MHz CPUFREQ LEVEL"
+ help
+ Max 1.7Ghz support
+
+config EXYNOS4X12_1800MHZ_SUPPORT
+ bool "Max 1800MHz CPUFREQ LEVEL"
+ help
+ Max 1.8Ghz support
+
config ARM_EXYNOS5250_CPUFREQ
def_bool SOC_EXYNOS5250
help
diff -ruN linux/drivers/hardkernel/hkdk_tmu.c linux-tmu/drivers/hardkernel/hkdk_tmu.c
--- linux/drivers/hardkernel/hkdk_tmu.c 1969-12-31 21:00:00.000000000 -0300
+++ linux-tmu/drivers/hardkernel/hkdk_tmu.c 2012-10-12 16:21:08.000000000 -0300
@@ -0,0 +1,287 @@
+#include "hkdk_tmu.h"
+
+static ssize_t hkdk_tmu_sysfs_curr_temp(struct device *dev, struct device_attribute *attr, char *buf) {
+
+ struct s_hkdk_tmu *hkdk_tmu = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hkdk_tmu->curr_temp);
+}
+static DEVICE_ATTR(curr_temp, S_IRUGO, hkdk_tmu_sysfs_curr_temp, NULL);
+
+static void get_cur_temp(struct s_hkdk_tmu *hkdk_tmu) {
+
+ unsigned char current_temperature_uncompensated;
+ unsigned char current_temperature;
+
+ current_temperature_uncompensated = __raw_readl(hkdk_tmu->tmu_base + E_CURRENT_TEMP) & 0xff;
+
+ current_temperature = current_temperature_uncompensated - hkdk_tmu->te1 + TMU_DC_VALUE;
+
+ hkdk_tmu->curr_temp = (int) current_temperature;
+
+}
+
+static void tmu_work_out(struct work_struct *work) {
+ struct delayed_work *dw = to_delayed_work(work);
+
+ struct s_hkdk_tmu *hkdk_tmu = container_of(dw, struct s_hkdk_tmu, tmu_work);
+
+ enable_irq(hkdk_tmu->irq);
+ get_cur_temp(hkdk_tmu);
+ if (hkdk_tmu->TMU_TEMP1 == false && hkdk_tmu->curr_temp >= TMU_TEMP1_START) {
+ pr_info("HKDK Stage 1 Kick In\n");
+ hkdk_tmu->TMU_TEMP1 = true;
+ hack_setcpu_frequency(TMU_TEMP1_CPU_SPEED);
+ goto out;
+ }
+ if (hkdk_tmu->TMU_TEMP1 == true && hkdk_tmu->curr_temp <= TMU_TEMP1_STOP) {
+ pr_info("HKDK Stage 1 Kick out\n");
+ hkdk_tmu->TMU_TEMP1 = false;
+ hack_setcpu_frequency(TMU_MAX_FREQ);
+ goto out;
+ }
+ if (hkdk_tmu->TMU_TEMP2 == false && hkdk_tmu->curr_temp >= TMU_TEMP2_START) {
+ pr_info("HKDK Stage 2 Kick in\n");
+ hkdk_tmu->TMU_TEMP2 = true;
+ hack_setcpu_frequency(TMU_TEMP2_CPU_SPEED);
+ goto out;
+ }
+ if (hkdk_tmu->TMU_TEMP2 == true && hkdk_tmu->curr_temp <= TMU_TEMP2_STOP) {
+ pr_info("HKDK Stage 2 Kick out\n");
+ hkdk_tmu->TMU_TEMP2 = false;
+ hack_setcpu_frequency(TMU_TEMP1_CPU_SPEED);
+ goto out;
+ }
+
+ goto out;
+ out:
+ disable_irq_nosync(hkdk_tmu->irq);
+ queue_delayed_work_on(0, tmu_wq, &hkdk_tmu->tmu_work, usecs_to_jiffies(1500 * 1000));
+
+}
+
+static irqreturn_t tmu_irq(int irq, void *id) {
+ struct s_hkdk_tmu *info = id;
+
+ unsigned int status;
+
+ disable_irq_nosync(irq);
+
+ status = __raw_readl(info->tmu_base + INTSTAT);
+ pr_emerg("HKDK TMU: IRQ STATUS -> %d", status);
+
+ if (status & INTSTAT_RISE0) {
+ pr_emerg("Throttling interrupt occured!!!!\n");
+ __raw_writel(INTCLEAR_RISE0, info->tmu_base + INTCLEAR);
+ info->tmu_state = TMU_STATUS_THROTTLED;
+ queue_delayed_work_on(0, tmu_wq, &info->tmu_work, usecs_to_jiffies(1500 * 1000));
+ } else if (status & INTSTAT_RISE1) {
+ pr_emerg("Warning interrupt occured!!!!\n");
+ __raw_writel(INTCLEAR_RISE1, info->tmu_base + INTCLEAR);
+ info->tmu_state = TMU_STATUS_WARNING;
+ queue_delayed_work_on(0, tmu_wq, &info->tmu_work, usecs_to_jiffies(1500 * 1000));
+ } else if (status & INTSTAT_RISE2) {
+ pr_emerg("Tripping interrupt occured!!!!\n");
+ info->tmu_state = TMU_STATUS_TRIPPED;
+ __raw_writel(INTCLEAR_RISE2, info->tmu_base + INTCLEAR);
+ } else {
+ pr_err("%s: TMU interrupt error\n", __func__);
+ return -ENODEV;
+ }
+
+ return IRQ_HANDLED;
+};
+
+static int hkdk_tmu_start(struct s_hkdk_tmu *info) {
+
+ int te_temp, throttle_temp, warning_temp, trip_temp, cooling_temp = 0, rising_value, reg_info, con;
+
+ // Reload efuse falue
+ __raw_writel(TRIMINFO_RELOAD, info->tmu_base + TRIMINFO_CON);
+
+ // get the compensation parameter
+ te_temp = __raw_readl(info->tmu_base + TRIMINFO);
+ pr_emerg("HKDK TMU: Compensation Parameter is: %d", te_temp);
+
+ info->te1 = te_temp & TRIM_INFO_MASK;
+ info->te2 = ((te_temp >> 8) & TRIM_INFO_MASK);
+
+ if ((EFUSE_MIN_VALUE > info->te1) || (info->te1 > EFUSE_MAX_VALUE) || (info->te2 != 0))
+ info->te1 = info->efuse_value;
+
+ throttle_temp = TMU_TEMP1_START + info->te1 - TMU_DC_VALUE;
+ warning_temp = TMU_TEMP2_STOP + info->te1 - TMU_DC_VALUE;
+ trip_temp = TMU_TEMP2_START + info->te1 - TMU_DC_VALUE;
+
+ cooling_temp = 0;
+
+ rising_value = (throttle_temp | (warning_temp << 8) | (trip_temp << 16));
+
+ __raw_writel(rising_value, info->tmu_base + THD_TEMP_RISE);
+ __raw_writel(cooling_temp, info->tmu_base + THD_TEMP_FALL);
+
+ /* Say Hello to Exynos */
+ __raw_writel(info->slope, info->tmu_base + TMU_CON);
+
+ pr_emerg("HKDK TMU: CPU Registers Initialization Complete");
+
+ reg_info = __raw_readl(info->tmu_base + THD_TEMP_RISE);
+ pr_emerg("HKDK TMU: Rising Threshold: %x", reg_info);
+
+ __raw_writel(INTCLEARALL, info->tmu_base + INTCLEAR);
+
+ con = __raw_readl(info->tmu_base + TMU_CON);
+ con |= (MUX_ADDR_VALUE << 20 | CORE_EN);
+
+ __raw_writel(con, info->tmu_base + TMU_CON);
+
+ // Enable Interrupts
+ __raw_writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2,
+ info->tmu_base + INTEN);
+
+ return 0;
+}
+
+static int hkdk_tmu_initialize(struct platform_device *pdev) {
+
+ struct s_hkdk_tmu *info = platform_get_drvdata(pdev);
+ int en;
+
+ // pr_emerg("HKDK TMU: TMU Base: %d TMU_STATUS: %d\n", info->tmu_base, TMU_STATUS);
+
+ en = (__raw_readl(info->tmu_base + TMU_STATUS) & 0x1);
+
+ if (!en) {
+ pr_emerg("HKDK TMU: Failed to start the TMU driver\n");
+ return -ENOENT;
+ }
+
+ return hkdk_tmu_start(info);
+}
+
+static int hkdk_tmu_probe(struct platform_device *pdev) {
+
+ int ret, ret2;
+ struct resource *res;
+ struct s_hkdk_tmu *hkdk_tmu;
+
+ pr_emerg("HKDK TMU: Loaded\n");
+
+ hkdk_tmu = kzalloc(sizeof(struct s_hkdk_tmu), GFP_KERNEL);
+
+ if (!hkdk_tmu) {
+ pr_emerg("HKDK TMU: Failed to alloc memory to the structure\n");
+ return -ENOMEM;
+ }
+
+ hkdk_tmu->dev = &pdev->dev;
+
+ pr_emerg("HKDK TMU: Pdev\n");
+
+ hkdk_tmu->efuse_value = 55;
+ hkdk_tmu->slope = 0x10008802;
+ hkdk_tmu->mode = 0;
+ hkdk_tmu->te1 = 55;
+ hkdk_tmu->TMU_TEMP1 = false;
+ hkdk_tmu->TMU_TEMP2 = false;
+ hkdk_tmu->curr_temp = 10;
+ hkdk_tmu->tmu_state = 0;
+
+ pr_emerg("HKDK TMU: MAX CPU Frequency: %s", TMU_MAX_FREQ);
+ pr_emerg("HKDK TMU: Set TMU Status\n");
+
+ hkdk_tmu->irq = platform_get_irq(pdev, 0);
+ pr_emerg("HKDK TMU: Got IRQ");
+
+ if (hkdk_tmu->irq < 0) {
+ pr_emerg("HKDK TMU: No IRQ for TMU -> tmu irq: %d\n", hkdk_tmu->irq);
+ return -ENOMEM;
+ }
+
+ ret = request_irq(hkdk_tmu->irq, tmu_irq, IRQF_DISABLED, "tmu interrupt", hkdk_tmu);
+ pr_emerg("HKDK TMU: Request IRQ\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL ) {
+ pr_emerg("HKDK TMU: Failed to get memory resources\n");
+ return -ENOENT;
+ }
+
+ hkdk_tmu->ioarea = request_mem_region(res->start, res->end-res->start+1, pdev->name);
+ pr_emerg("HKDK TMU: Request IO Memory\n");
+ if (!(hkdk_tmu->ioarea))
+ pr_emerg("HKDK TMU: Something wrong at requesting the memory region\n");
+
+ hkdk_tmu->tmu_base = ioremap(res->start, (res->end - res->start) + 1);
+ pr_emerg("HKDK TMU: Remap IO Memory\n");
+ if (!(hkdk_tmu->tmu_base))
+ pr_emerg("HKDK TMU: Something wrong at the io remap\n");
+
+ platform_set_drvdata(pdev, hkdk_tmu);
+
+ ret2 = device_create_file(&pdev->dev, &dev_attr_curr_temp);
+
+ hkdk_tmu_initialize(pdev);
+ pr_emerg("HKDK TMU: Initialized\n");
+
+ tmu_wq = create_freezable_workqueue("hkdk_tmu_wq");
+ pr_emerg("HKDK TMU: Created Queue\n");
+
+ INIT_DELAYED_WORK_DEFERRABLE(&hkdk_tmu->tmu_work, tmu_work_out);
+ pr_emerg("HKDK TMU: INIT Queue\n");
+
+ queue_delayed_work_on(0, tmu_wq, &hkdk_tmu->tmu_work, usecs_to_jiffies(1500 * 1000));
+ pr_emerg("HKDK TMU: Delay Work created on the queue\n");
+
+ return 0;
+}
+
+static void hkdk_tmu_remove(void) {
+ pr_emerg("HKDK TMU Unloaded\n");
+ destroy_workqueue(tmu_wq);
+}
+
+static struct platform_driver hkdk_tmu_driver = {
+ .probe = hkdk_tmu_probe,
+ .remove = hkdk_tmu_remove,
+ .driver = {
+ .name = "hkdk_tmu",
+ },
+};
+
+static struct resource hkdk_tmu_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_TMU,
+ .end = EXYNOS4_PA_TMU + 0xFFFF -1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TMU,
+ .end = IRQ_TMU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device hkdk_device_tmu = {
+ .name = "hkdk_tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(hkdk_tmu_resource),
+ .resource = hkdk_tmu_resource,
+};
+
+
+static int __init tmu_driver_init(void) {
+ pr_emerg("HKDK TMU: Platform Device Init\n");
+ platform_device_register(&hkdk_device_tmu);
+ pr_emerg("HKDK TMU: Platform Driver Init\n");
+ return platform_driver_register(&hkdk_tmu_driver);
+}
+
+static void __exit tmu_driver_exit(void) {
+ platform_driver_unregister(&hkdk_tmu_driver);
+}
+
+module_init(tmu_driver_init);
+module_exit(tmu_driver_exit);
+
+MODULE_DESCRIPTION("TMU hack for ODROID-X");
+MODULE_LICENSE("GPL");
diff -ruN linux/drivers/hardkernel/hkdk_tmu.h linux-tmu/drivers/hardkernel/hkdk_tmu.h
--- linux/drivers/hardkernel/hkdk_tmu.h 1969-12-31 21:00:00.000000000 -0300
+++ linux-tmu/drivers/hardkernel/hkdk_tmu.h 2012-10-12 18:21:10.000000000 -0300
@@ -0,0 +1,105 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/crc32.h>
+#include <linux/interrupt.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+
+#include <stdbool.h>
+#include "samsung_info.h"
+
+
+#define TMU_TEMP1_CPU_SPEED "800000"
+#define TMU_TEMP2_CPU_SPEED "200000"
+
+#define TMU_TEMP1_START 80
+#define TMU_TEMP1_STOP 70
+
+#define TMU_TEMP2_START 100
+#define TMU_TEMP2_STOP 90
+
+#define ONLINE_FILE_PATH "/sys/devices/system/cpu/cpu0/online"
+#define CPUFREQ_FILE_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+
+#ifdef CONFIG_EXYNOS4X12_1800MHZ_SUPPORT
+ #define TMU_MAX_FREQ "1800000"
+#elif defined(CONFIG_EXYNOS4X12_1704MHZ_SUPPORT)
+ #define TMU_MAX_FREQ "1704000"
+#elif defined(CONFIG_EXYNOS4X12_1600MHZ_SUPPORT)
+ #define TMU_MAX_FREQ "1600000"
+#else
+ #define TMU_MAX_FREQ "1400000"
+#endif
+
+
+struct workqueue_struct *tmu_wq;
+
+
+char *hkdk_change_cpu(char *str, const char *cpuid) {
+ static char buffer[50];
+ strcpy(buffer, str);
+ buffer[27] = *cpuid;
+ return buffer;
+}
+
+int hkdk_write_to_file(char *aa_text, const char *file_name) {
+
+ struct file *fp = NULL;
+ char *buffer[10] = { 0 };
+ mm_segment_t oldfs = { 0 };
+
+ memset(buffer, 0x00, sizeof(buffer));
+
+ sprintf(buffer, "%s", aa_text);
+
+ fp = filp_open(file_name, O_RDWR, 0777);
+ if(IS_ERR(fp)) {
+ pr_emerg("Error while opening the file");
+ return 0;
+ }
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+
+ if (fp->f_mode & FMODE_WRITE ) {
+ int fret = fp->f_op->write(fp, (const char *)buffer, sizeof(buffer), &fp->f_pos);
+ return fret;
+ }
+
+ set_fs(oldfs);
+
+ if (fp) {
+ filp_close(fp, NULL );
+ }
+ return 0;
+}
+
+void hack_setcpu_frequency(char *frequency) {
+ /* first run, cpu0 */
+ hkdk_write_to_file(frequency, (const char*) CPUFREQ_FILE_PATH);
+
+ /* run for cpu1 */
+ hkdk_write_to_file("1", hkdk_change_cpu(ONLINE_FILE_PATH, "1"));
+ hkdk_write_to_file(frequency, hkdk_change_cpu(CPUFREQ_FILE_PATH, "1"));
+
+ /* run for cpu2 */
+ hkdk_write_to_file("1", hkdk_change_cpu(ONLINE_FILE_PATH, "2"));
+ hkdk_write_to_file(frequency, hkdk_change_cpu(CPUFREQ_FILE_PATH, "2"));
+
+ /* run for cpu3 */
+ hkdk_write_to_file("1", hkdk_change_cpu(ONLINE_FILE_PATH, "3"));
+ hkdk_write_to_file(frequency, hkdk_change_cpu(CPUFREQ_FILE_PATH, "3"));
+
+}
diff -ruN linux/drivers/hardkernel/Kconfig linux-tmu/drivers/hardkernel/Kconfig
--- linux/drivers/hardkernel/Kconfig 1969-12-31 21:00:00.000000000 -0300
+++ linux-tmu/drivers/hardkernel/Kconfig 2012-10-12 01:08:53.967369920 -0300
@@ -0,0 +1,8 @@
+config HKDK4412_TMU
+ bool "Hardkernel's ODROID(X/Q) TMU Hack"
+ default y
+ help
+ This is hack to support TMU on ODROID-X/Q running Ubuntu.
+ Its strongly recommended to Enable this.
+ Otherwise you'll experience system freezes due to high cpu
+ temperature
diff -ruN linux/drivers/hardkernel/Makefile linux-tmu/drivers/hardkernel/Makefile
--- linux/drivers/hardkernel/Makefile 1969-12-31 21:00:00.000000000 -0300
+++ linux-tmu/drivers/hardkernel/Makefile 2012-10-12 01:08:27.747364664 -0300
@@ -0,0 +1 @@
+obj-$(CONFIG_HKDK4412_TMU) += hkdk_tmu.o
diff -ruN linux/drivers/hardkernel/samsung_info.h linux-tmu/drivers/hardkernel/samsung_info.h
--- linux/drivers/hardkernel/samsung_info.h 1969-12-31 21:00:00.000000000 -0300
+++ linux-tmu/drivers/hardkernel/samsung_info.h 2012-10-12 15:59:49.000000000 -0300
@@ -0,0 +1,83 @@
+/*
+ * samsung_info.h
+ *
+ * Created on: Oct 2, 2012
+ * Author: mdrjr
+ */
+
+
+#define EXYNOS_IRQ_OFFSET (32)
+#define HKDK_IRQ_Q(x) ((x) + EXYNOS_IRQ_OFFSET)
+#define SPI_IRQ(x) HKDK_IRQ_Q(x+32)
+#define GROUP_COMBINER(x) ((x) * 8 + SPI_IRQ(128))
+#define IRQ_COMBINER(x, y) (GROUP_COMBINER(x) + y)
+
+#define E_CURRENT_TEMP (0x40)
+#define TMU_SAVE_NUM 10
+#define TMU_DC_VALUE 25
+#define EFUSE_MIN_VALUE 40
+#define EFUSE_MAX_VALUE 100
+#define TRIMINFO_RELOAD (1)
+#define TRIMINFO_CON (0x14)
+#define TRIM_INFO_MASK (0xFF)
+#define INTSTAT (0x74)
+#define INTSTAT_RISE0 (1)
+#define INTSTAT_RISE1 (1<<4)
+#define INTSTAT_RISE2 (1<<8)
+#define INTSTAT_FALL0 (1<<16)
+#define INTSTAT_FALL1 (1<<20)
+#define INTSTAT_FALL2 (1<<24)
+#define INTCLEAR_RISE0 (1)
+#define INTCLEAR_RISE1 (1<<4)
+#define INTCLEAR_RISE2 (1<<8)
+#define INTCLEAR_FALL0 (1<<16)
+#define INTCLEAR_FALL1 (1<<20)
+#define INTCLEAR_FALL2 (1<<24)
+#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | INTCLEAR_RISE2 | INTCLEAR_FALL0 | INTCLEAR_FALL1 | INTCLEAR_FALL2)
+
+#define INTCLEAR (0x78)
+#define TMU_STATUS (0x28)
+#define TRIMINFO (0x0)
+#define THD_TEMP_RISE (0x50)
+#define THD_TEMP_FALL (0x54)
+#define TMU_CON (0x20)
+#define MUX_ADDR_VALUE 6
+#define CORE_EN (1)
+#define INTEN_RISE0 (1)
+#define INTEN_RISE1 (1<<4)
+#define INTEN_RISE2 (1<<8)
+#define INTEN (0x70)
+#define IRQ_TMU IRQ_COMBINER(2, 4)
+#define EXYNOS4_PA_TMU 0x100C0000
+
+enum tmu_status_t {
+ TMU_STATUS_INIT = 0,
+ TMU_STATUS_NORMAL,
+ TMU_STATUS_THROTTLED,
+ TMU_STATUS_WARNING,
+ TMU_STATUS_TRIPPED,
+};
+
+struct s_hkdk_tmu {
+ int id;
+ void __iomem *tmu_base;
+ struct device *dev;
+ struct resource *ioarea;
+ int irq;
+ unsigned int efuse_value;
+ unsigned int slope;
+ int mode;
+ unsigned int te1;
+ unsigned int te2;
+ int tmu_state;
+
+ struct delayed_work tmu_work;
+
+ bool TMU_TEMP1;
+ bool TMU_TEMP2;
+
+ int curr_temp;
+};
+
+
+
diff -ruN linux/drivers/Kconfig linux-tmu/drivers/Kconfig
--- linux/drivers/Kconfig 2012-10-10 09:50:54.533487383 -0300
+++ linux-tmu/drivers/Kconfig 2012-10-12 01:02:09.457288826 -0300
@@ -152,4 +152,6 @@
source "drivers/pwm/Kconfig"
+source "drivers/hardkernel/Kconfig"
+
endmenu
diff -ruN linux/drivers/Makefile linux-tmu/drivers/Makefile
--- linux/drivers/Makefile 2012-10-10 09:50:54.533487383 -0300
+++ linux-tmu/drivers/Makefile 2012-10-12 01:10:47.082392597 -0300
@@ -139,3 +139,6 @@
obj-$(CONFIG_MEMORY) += memory/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
+
+# Hardkernel HKDK 4412 TMU
+obj-$(CONFIG_HKDK4412_TMU) += hardkernel/
\ No newline at end of file