summaryrefslogtreecommitdiff
path: root/patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch')
-rw-r--r--patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch3642
1 files changed, 3642 insertions, 0 deletions
diff --git a/patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch b/patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch
new file mode 100644
index 00000000000..fc295d6aba7
--- /dev/null
+++ b/patches.tizen/0930-thermal-introduce-TI-SoC-thermal-driver.patch
@@ -0,0 +1,3642 @@
+From 8e5d1edccfd05a5ce7295adc174f6c02229a8da2 Mon Sep 17 00:00:00 2001
+From: Eduardo Valentin <eduardo.valentin@ti.com>
+Date: Wed, 15 May 2013 15:46:00 +0000
+Subject: [PATCH 0930/1302] thermal: introduce TI SoC thermal driver
+
+This patch moves the ti-soc-thermal driver out of
+the staging tree to the thermal tree.
+
+Cc: Grant Likely <grant.likely@linaro.org>
+Cc: Rob Herring <rob.herring@calxeda.com>
+Cc: Rob Landley <rob@landley.net>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Zhang Rui <rui.zhang@intel.com>
+Cc: Eduardo Valentin <eduardo.valentin@ti.com>
+Cc: J Keerthy <j-keerthy@ti.com>
+Cc: Radhesh Fadnis <radhesh.fadnis@ti.com>
+Cc: Cyril Roelandt <tipecaml@gmail.com>
+Cc: devicetree-discuss@lists.ozlabs.org
+Cc: linux-doc@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Cc: devel@driverdev.osuosl.org
+Cc: linux-pm@vger.kernel.org
+Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
+---
+ drivers/thermal/Kconfig | 3 +
+ drivers/thermal/Makefile | 2 +-
+ drivers/thermal/ti-soc-thermal/Kconfig | 48 +
+ drivers/thermal/ti-soc-thermal/Makefile | 5 +
+ drivers/thermal/ti-soc-thermal/TODO | 12 +
+ .../thermal/ti-soc-thermal/omap4-thermal-data.c | 267 ++++
+ drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h | 175 +++
+ .../thermal/ti-soc-thermal/omap5-thermal-data.c | 359 +++++
+ drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h | 200 +++
+ drivers/thermal/ti-soc-thermal/ti-bandgap.c | 1546 ++++++++++++++++++++
+ drivers/thermal/ti-soc-thermal/ti-bandgap.h | 403 +++++
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 367 +++++
+ drivers/thermal/ti-soc-thermal/ti-thermal.h | 117 ++
+ 13 files changed, 3503 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/thermal/ti-soc-thermal/Kconfig
+ create mode 100644 drivers/thermal/ti-soc-thermal/Makefile
+ create mode 100644 drivers/thermal/ti-soc-thermal/TODO
+ create mode 100644 drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
+ create mode 100644 drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
+ create mode 100644 drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
+ create mode 100644 drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
+ create mode 100644 drivers/thermal/ti-soc-thermal/ti-bandgap.c
+ create mode 100644 drivers/thermal/ti-soc-thermal/ti-bandgap.h
+ create mode 100644 drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+ create mode 100644 drivers/thermal/ti-soc-thermal/ti-thermal.h
+
+diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
+index 5e3c025..7205c70 100644
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -169,4 +169,7 @@ config INTEL_POWERCLAMP
+ enforce idle time which results in more package C-state residency. The
+ user interface is exposed via generic thermal framework.
+
++menu "Texas Instruments thermal drivers"
++source "drivers/thermal/ti-soc-thermal/Kconfig"
++endmenu
+ endif
+diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
+index c054d41..8569394 100644
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -23,4 +23,4 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
+ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
+ obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
+ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
+-
++obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
+diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
+new file mode 100644
+index 0000000..e81375f
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/Kconfig
+@@ -0,0 +1,48 @@
++config TI_SOC_THERMAL
++ tristate "Texas Instruments SoCs temperature sensor driver"
++ depends on THERMAL
++ depends on ARCH_HAS_BANDGAP
++ help
++ If you say yes here you get support for the Texas Instruments
++ OMAP4460+ on die bandgap temperature sensor support. The register
++ set is part of system control module.
++
++ This includes alert interrupts generation and also the TSHUT
++ support.
++
++config TI_THERMAL
++ bool "Texas Instruments SoCs thermal framework support"
++ depends on TI_SOC_THERMAL
++ depends on CPU_THERMAL
++ help
++ If you say yes here you want to get support for generic thermal
++ framework for the Texas Instruments on die bandgap temperature sensor.
++
++ This includes trip points definitions, extrapolation rules and
++ CPU cooling device bindings.
++
++config OMAP4_THERMAL
++ bool "Texas Instruments OMAP4 thermal support"
++ depends on TI_SOC_THERMAL
++ depends on ARCH_OMAP4
++ help
++ If you say yes here you get thermal support for the Texas Instruments
++ OMAP4 SoC family. The current chip supported are:
++ - OMAP4430
++ - OMAP4460
++ - OMAP4470
++
++ This includes alert interrupts generation and also the TSHUT
++ support.
++
++config OMAP5_THERMAL
++ bool "Texas Instruments OMAP5 thermal support"
++ depends on TI_SOC_THERMAL
++ depends on SOC_OMAP5
++ help
++ If you say yes here you get thermal support for the Texas Instruments
++ OMAP5 SoC family. The current chip supported are:
++ - OMAP5430
++
++ This includes alert interrupts generation and also the TSHUT
++ support.
+diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile
+new file mode 100644
+index 0000000..0ca034f
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/Makefile
+@@ -0,0 +1,5 @@
++obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o
++ti-soc-thermal-y := ti-bandgap.o
++ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o
++ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
++ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
+diff --git a/drivers/thermal/ti-soc-thermal/TODO b/drivers/thermal/ti-soc-thermal/TODO
+new file mode 100644
+index 0000000..7da787d
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/TODO
+@@ -0,0 +1,12 @@
++List of TODOs (by Eduardo Valentin)
++
++on ti-bandgap.c:
++- Revisit PM support
++
++on ti-thermal-common.c/ti-thermal.h:
++- Revisit need for locking
++
++generally:
++- make sure this code works on OMAP4430, OMAP4460 and OMAP5430
++
++Copy patches to Eduardo Valentin <eduardo.valentin@ti.com>
+diff --git a/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
+new file mode 100644
+index 0000000..d255d33
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
+@@ -0,0 +1,267 @@
++/*
++ * OMAP4 thermal driver.
++ *
++ * Copyright (C) 2011-2012 Texas Instruments Inc.
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@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 "ti-thermal.h"
++#include "ti-bandgap.h"
++#include "omap4xxx-bandgap.h"
++
++/*
++ * OMAP4430 has one instance of thermal sensor for MPU
++ * need to describe the individual bit fields
++ */
++static struct temp_sensor_registers
++omap4430_mpu_temp_sensor_registers = {
++ .temp_sensor_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
++ .bgap_tempsoff_mask = OMAP4430_BGAP_TEMPSOFF_MASK,
++ .bgap_soc_mask = OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK,
++ .bgap_eocz_mask = OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK,
++ .bgap_dtemp_mask = OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK,
++
++ .bgap_mode_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
++ .mode_ctrl_mask = OMAP4430_SINGLE_MODE_MASK,
++
++ .bgap_efuse = OMAP4430_FUSE_OPP_BGAP,
++};
++
++/* Thresholds and limits for OMAP4430 MPU temperature sensor */
++static struct temp_sensor_data omap4430_mpu_temp_sensor_data = {
++ .min_freq = OMAP4430_MIN_FREQ,
++ .max_freq = OMAP4430_MAX_FREQ,
++ .max_temp = OMAP4430_MAX_TEMP,
++ .min_temp = OMAP4430_MIN_TEMP,
++ .hyst_val = OMAP4430_HYST_VAL,
++};
++
++/*
++ * Temperature values in milli degree celsius
++ * ADC code values from 530 to 923
++ */
++static const int
++omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
++ -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000,
++ -20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000,
++ -5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000,
++ 13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000,
++ 32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000,
++ 48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000,
++ 66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000,
++ 83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000,
++ 100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000,
++ 117000, 118000, 120000, 122000, 123000,
++};
++
++/* OMAP4430 data */
++const struct ti_bandgap_data omap4430_data = {
++ .features = TI_BANDGAP_FEATURE_MODE_CONFIG |
++ TI_BANDGAP_FEATURE_CLK_CTRL |
++ TI_BANDGAP_FEATURE_POWER_SWITCH,
++ .fclock_name = "bandgap_fclk",
++ .div_ck_name = "bandgap_fclk",
++ .conv_table = omap4430_adc_to_temp,
++ .adc_start_val = OMAP4430_ADC_START_VALUE,
++ .adc_end_val = OMAP4430_ADC_END_VALUE,
++ .expose_sensor = ti_thermal_expose_sensor,
++ .remove_sensor = ti_thermal_remove_sensor,
++ .sensors = {
++ {
++ .registers = &omap4430_mpu_temp_sensor_registers,
++ .ts_data = &omap4430_mpu_temp_sensor_data,
++ .domain = "cpu",
++ .slope = OMAP_GRADIENT_SLOPE_4430,
++ .constant = OMAP_GRADIENT_CONST_4430,
++ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430,
++ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430,
++ .register_cooling = ti_thermal_register_cpu_cooling,
++ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
++ },
++ },
++ .sensor_count = 1,
++};
++/*
++ * OMAP4460 has one instance of thermal sensor for MPU
++ * need to describe the individual bit fields
++ */
++static struct temp_sensor_registers
++omap4460_mpu_temp_sensor_registers = {
++ .temp_sensor_ctrl = OMAP4460_TEMP_SENSOR_CTRL_OFFSET,
++ .bgap_tempsoff_mask = OMAP4460_BGAP_TEMPSOFF_MASK,
++ .bgap_soc_mask = OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK,
++ .bgap_eocz_mask = OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK,
++ .bgap_dtemp_mask = OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK,
++
++ .bgap_mask_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
++ .mask_hot_mask = OMAP4460_MASK_HOT_MASK,
++ .mask_cold_mask = OMAP4460_MASK_COLD_MASK,
++
++ .bgap_mode_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
++ .mode_ctrl_mask = OMAP4460_SINGLE_MODE_MASK,
++
++ .bgap_counter = OMAP4460_BGAP_COUNTER_OFFSET,
++ .counter_mask = OMAP4460_COUNTER_MASK,
++
++ .bgap_threshold = OMAP4460_BGAP_THRESHOLD_OFFSET,
++ .threshold_thot_mask = OMAP4460_T_HOT_MASK,
++ .threshold_tcold_mask = OMAP4460_T_COLD_MASK,
++
++ .tshut_threshold = OMAP4460_BGAP_TSHUT_OFFSET,
++ .tshut_hot_mask = OMAP4460_TSHUT_HOT_MASK,
++ .tshut_cold_mask = OMAP4460_TSHUT_COLD_MASK,
++
++ .bgap_status = OMAP4460_BGAP_STATUS_OFFSET,
++ .status_clean_stop_mask = OMAP4460_CLEAN_STOP_MASK,
++ .status_bgap_alert_mask = OMAP4460_BGAP_ALERT_MASK,
++ .status_hot_mask = OMAP4460_HOT_FLAG_MASK,
++ .status_cold_mask = OMAP4460_COLD_FLAG_MASK,
++
++ .bgap_efuse = OMAP4460_FUSE_OPP_BGAP,
++};
++
++/* Thresholds and limits for OMAP4460 MPU temperature sensor */
++static struct temp_sensor_data omap4460_mpu_temp_sensor_data = {
++ .tshut_hot = OMAP4460_TSHUT_HOT,
++ .tshut_cold = OMAP4460_TSHUT_COLD,
++ .t_hot = OMAP4460_T_HOT,
++ .t_cold = OMAP4460_T_COLD,
++ .min_freq = OMAP4460_MIN_FREQ,
++ .max_freq = OMAP4460_MAX_FREQ,
++ .max_temp = OMAP4460_MAX_TEMP,
++ .min_temp = OMAP4460_MIN_TEMP,
++ .hyst_val = OMAP4460_HYST_VAL,
++ .update_int1 = 1000,
++ .update_int2 = 2000,
++};
++
++/*
++ * Temperature values in milli degree celsius
++ * ADC code values from 530 to 923
++ */
++static const int
++omap4460_adc_to_temp[OMAP4460_ADC_END_VALUE - OMAP4460_ADC_START_VALUE + 1] = {
++ -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
++ -37800, -37300, -36800, -36400, -36000, -35600, -35200, -34800,
++ -34300, -33800, -33400, -33000, -32600, -32200, -31800, -31300,
++ -30800, -30400, -30000, -29600, -29200, -28700, -28200, -27800,
++ -27400, -27000, -26600, -26200, -25700, -25200, -24800, -24400,
++ -24000, -23600, -23200, -22700, -22200, -21800, -21400, -21000,
++ -20600, -20200, -19700, -19200, -18800, -18400, -18000, -17600,
++ -17200, -16700, -16200, -15800, -15400, -15000, -14600, -14200,
++ -13700, -13200, -12800, -12400, -12000, -11600, -11200, -10700,
++ -10200, -9800, -9400, -9000, -8600, -8200, -7700, -7200, -6800,
++ -6400, -6000, -5600, -5200, -4800, -4300, -3800, -3400, -3000,
++ -2600, -2200, -1800, -1300, -800, -400, 0, 400, 800, 1200, 1600,
++ 2100, 2600, 3000, 3400, 3800, 4200, 4600, 5100, 5600, 6000, 6400,
++ 6800, 7200, 7600, 8000, 8500, 9000, 9400, 9800, 10200, 10600, 11000,
++ 11400, 11900, 12400, 12800, 13200, 13600, 14000, 14400, 14800,
++ 15300, 15800, 16200, 16600, 17000, 17400, 17800, 18200, 18700,
++ 19200, 19600, 20000, 20400, 20800, 21200, 21600, 22100, 22600,
++ 23000, 23400, 23800, 24200, 24600, 25000, 25400, 25900, 26400,
++ 26800, 27200, 27600, 28000, 28400, 28800, 29300, 29800, 30200,
++ 30600, 31000, 31400, 31800, 32200, 32600, 33100, 33600, 34000,
++ 34400, 34800, 35200, 35600, 36000, 36400, 36800, 37300, 37800,
++ 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41100, 41600,
++ 42000, 42400, 42800, 43200, 43600, 44000, 44400, 44800, 45300,
++ 45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600, 49000,
++ 49500, 50000, 50400, 50800, 51200, 51600, 52000, 52400, 52800,
++ 53200, 53700, 54200, 54600, 55000, 55400, 55800, 56200, 56600,
++ 57000, 57400, 57800, 58200, 58700, 59200, 59600, 60000, 60400,
++ 60800, 61200, 61600, 62000, 62400, 62800, 63300, 63800, 64200,
++ 64600, 65000, 65400, 65800, 66200, 66600, 67000, 67400, 67800,
++ 68200, 68700, 69200, 69600, 70000, 70400, 70800, 71200, 71600,
++ 72000, 72400, 72800, 73200, 73600, 74100, 74600, 75000, 75400,
++ 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000,
++ 79400, 79800, 80300, 80800, 81200, 81600, 82000, 82400, 82800,
++ 83200, 83600, 84000, 84400, 84800, 85200, 85600, 86000, 86400,
++ 86800, 87300, 87800, 88200, 88600, 89000, 89400, 89800, 90200,
++ 90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400, 93800,
++ 94200, 94600, 95000, 95500, 96000, 96400, 96800, 97200, 97600,
++ 98000, 98400, 98800, 99200, 99600, 100000, 100400, 100800, 101200,
++ 101600, 102000, 102400, 102800, 103200, 103600, 104000, 104400,
++ 104800, 105200, 105600, 106100, 106600, 107000, 107400, 107800,
++ 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
++ 111400, 111800, 112200, 112600, 113000, 113400, 113800, 114200,
++ 114600, 115000, 115400, 115800, 116200, 116600, 117000, 117400,
++ 117800, 118200, 118600, 119000, 119400, 119800, 120200, 120600,
++ 121000, 121400, 121800, 122200, 122600, 123000, 123400, 123800, 124200,
++ 124600, 124900, 125000, 125000, 125000, 125000
++};
++
++/* OMAP4460 data */
++const struct ti_bandgap_data omap4460_data = {
++ .features = TI_BANDGAP_FEATURE_TSHUT |
++ TI_BANDGAP_FEATURE_TSHUT_CONFIG |
++ TI_BANDGAP_FEATURE_TALERT |
++ TI_BANDGAP_FEATURE_MODE_CONFIG |
++ TI_BANDGAP_FEATURE_POWER_SWITCH |
++ TI_BANDGAP_FEATURE_CLK_CTRL |
++ TI_BANDGAP_FEATURE_COUNTER,
++ .fclock_name = "bandgap_ts_fclk",
++ .div_ck_name = "div_ts_ck",
++ .conv_table = omap4460_adc_to_temp,
++ .adc_start_val = OMAP4460_ADC_START_VALUE,
++ .adc_end_val = OMAP4460_ADC_END_VALUE,
++ .expose_sensor = ti_thermal_expose_sensor,
++ .remove_sensor = ti_thermal_remove_sensor,
++ .report_temperature = ti_thermal_report_sensor_temperature,
++ .sensors = {
++ {
++ .registers = &omap4460_mpu_temp_sensor_registers,
++ .ts_data = &omap4460_mpu_temp_sensor_data,
++ .domain = "cpu",
++ .slope = OMAP_GRADIENT_SLOPE_4460,
++ .constant = OMAP_GRADIENT_CONST_4460,
++ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
++ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
++ .register_cooling = ti_thermal_register_cpu_cooling,
++ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
++ },
++ },
++ .sensor_count = 1,
++};
++
++/* OMAP4470 data */
++const struct ti_bandgap_data omap4470_data = {
++ .features = TI_BANDGAP_FEATURE_TSHUT |
++ TI_BANDGAP_FEATURE_TSHUT_CONFIG |
++ TI_BANDGAP_FEATURE_TALERT |
++ TI_BANDGAP_FEATURE_MODE_CONFIG |
++ TI_BANDGAP_FEATURE_POWER_SWITCH |
++ TI_BANDGAP_FEATURE_CLK_CTRL |
++ TI_BANDGAP_FEATURE_COUNTER,
++ .fclock_name = "bandgap_ts_fclk",
++ .div_ck_name = "div_ts_ck",
++ .conv_table = omap4460_adc_to_temp,
++ .adc_start_val = OMAP4460_ADC_START_VALUE,
++ .adc_end_val = OMAP4460_ADC_END_VALUE,
++ .expose_sensor = ti_thermal_expose_sensor,
++ .remove_sensor = ti_thermal_remove_sensor,
++ .report_temperature = ti_thermal_report_sensor_temperature,
++ .sensors = {
++ {
++ .registers = &omap4460_mpu_temp_sensor_registers,
++ .ts_data = &omap4460_mpu_temp_sensor_data,
++ .domain = "cpu",
++ .slope = OMAP_GRADIENT_SLOPE_4470,
++ .constant = OMAP_GRADIENT_CONST_4470,
++ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
++ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
++ .register_cooling = ti_thermal_register_cpu_cooling,
++ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
++ },
++ },
++ .sensor_count = 1,
++};
+diff --git a/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
+new file mode 100644
+index 0000000..6f2de3a
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
+@@ -0,0 +1,175 @@
++/*
++ * OMAP4xxx bandgap registers, bitfields and temperature definitions
++ *
++ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++#ifndef __OMAP4XXX_BANDGAP_H
++#define __OMAP4XXX_BANDGAP_H
++
++/**
++ * *** OMAP4430 ***
++ *
++ * Below, in sequence, are the Register definitions,
++ * the bitfields and the temperature definitions for OMAP4430.
++ */
++
++/**
++ * OMAP4430 register definitions
++ *
++ * Registers are defined as offsets. The offsets are
++ * relative to FUSE_OPP_BGAP on 4430.
++ */
++
++/* OMAP4430.FUSE_OPP_BGAP */
++#define OMAP4430_FUSE_OPP_BGAP 0x0
++
++/* OMAP4430.TEMP_SENSOR */
++#define OMAP4430_TEMP_SENSOR_CTRL_OFFSET 0xCC
++
++/**
++ * Register and bit definitions for OMAP4430
++ *
++ * All the macros bellow define the required bits for
++ * controlling temperature on OMAP4430. Bit defines are
++ * grouped by register.
++ */
++
++/* OMAP4430.TEMP_SENSOR bits */
++#define OMAP4430_BGAP_TEMPSOFF_MASK BIT(12)
++#define OMAP4430_BGAP_TSHUT_MASK BIT(11)
++#define OMAP4430_SINGLE_MODE_MASK BIT(10)
++#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK BIT(9)
++#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(8)
++#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
++
++/**
++ * Temperature limits and thresholds for OMAP4430
++ *
++ * All the macros bellow are definitions for handling the
++ * ADC conversions and representation of temperature limits
++ * and thresholds for OMAP4430.
++ */
++
++/* ADC conversion table limits */
++#define OMAP4430_ADC_START_VALUE 0
++#define OMAP4430_ADC_END_VALUE 127
++/* bandgap clock limits (no control on 4430) */
++#define OMAP4430_MAX_FREQ 32768
++#define OMAP4430_MIN_FREQ 32768
++/* sensor limits */
++#define OMAP4430_MIN_TEMP -40000
++#define OMAP4430_MAX_TEMP 125000
++#define OMAP4430_HYST_VAL 5000
++
++/**
++ * *** OMAP4460 *** Applicable for OMAP4470
++ *
++ * Below, in sequence, are the Register definitions,
++ * the bitfields and the temperature definitions for OMAP4460.
++ */
++
++/**
++ * OMAP4460 register definitions
++ *
++ * Registers are defined as offsets. The offsets are
++ * relative to FUSE_OPP_BGAP on 4460.
++ */
++
++/* OMAP4460.FUSE_OPP_BGAP */
++#define OMAP4460_FUSE_OPP_BGAP 0x0
++
++/* OMAP4460.TEMP_SENSOR */
++#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET 0xCC
++
++/* OMAP4460.BANDGAP_CTRL */
++#define OMAP4460_BGAP_CTRL_OFFSET 0x118
++
++/* OMAP4460.BANDGAP_COUNTER */
++#define OMAP4460_BGAP_COUNTER_OFFSET 0x11C
++
++/* OMAP4460.BANDGAP_THRESHOLD */
++#define OMAP4460_BGAP_THRESHOLD_OFFSET 0x120
++
++/* OMAP4460.TSHUT_THRESHOLD */
++#define OMAP4460_BGAP_TSHUT_OFFSET 0x124
++
++/* OMAP4460.BANDGAP_STATUS */
++#define OMAP4460_BGAP_STATUS_OFFSET 0x128
++
++/**
++ * Register bitfields for OMAP4460
++ *
++ * All the macros bellow define the required bits for
++ * controlling temperature on OMAP4460. Bit defines are
++ * grouped by register.
++ */
++/* OMAP4460.TEMP_SENSOR bits */
++#define OMAP4460_BGAP_TEMPSOFF_MASK BIT(13)
++#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK BIT(11)
++#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10)
++#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
++
++/* OMAP4460.BANDGAP_CTRL bits */
++#define OMAP4460_SINGLE_MODE_MASK BIT(31)
++#define OMAP4460_MASK_HOT_MASK BIT(1)
++#define OMAP4460_MASK_COLD_MASK BIT(0)
++
++/* OMAP4460.BANDGAP_COUNTER bits */
++#define OMAP4460_COUNTER_MASK (0xffffff << 0)
++
++/* OMAP4460.BANDGAP_THRESHOLD bits */
++#define OMAP4460_T_HOT_MASK (0x3ff << 16)
++#define OMAP4460_T_COLD_MASK (0x3ff << 0)
++
++/* OMAP4460.TSHUT_THRESHOLD bits */
++#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
++#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
++
++/* OMAP4460.BANDGAP_STATUS bits */
++#define OMAP4460_CLEAN_STOP_MASK BIT(3)
++#define OMAP4460_BGAP_ALERT_MASK BIT(2)
++#define OMAP4460_HOT_FLAG_MASK BIT(1)
++#define OMAP4460_COLD_FLAG_MASK BIT(0)
++
++/**
++ * Temperature limits and thresholds for OMAP4460
++ *
++ * All the macros bellow are definitions for handling the
++ * ADC conversions and representation of temperature limits
++ * and thresholds for OMAP4460.
++ */
++
++/* ADC conversion table limits */
++#define OMAP4460_ADC_START_VALUE 530
++#define OMAP4460_ADC_END_VALUE 932
++/* bandgap clock limits */
++#define OMAP4460_MAX_FREQ 1500000
++#define OMAP4460_MIN_FREQ 1000000
++/* sensor limits */
++#define OMAP4460_MIN_TEMP -40000
++#define OMAP4460_MAX_TEMP 123000
++#define OMAP4460_HYST_VAL 5000
++/* interrupts thresholds */
++#define OMAP4460_TSHUT_HOT 900 /* 122 deg C */
++#define OMAP4460_TSHUT_COLD 895 /* 100 deg C */
++#define OMAP4460_T_HOT 800 /* 73 deg C */
++#define OMAP4460_T_COLD 795 /* 71 deg C */
++
++#endif /* __OMAP4XXX_BANDGAP_H */
+diff --git a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
+new file mode 100644
+index 0000000..eff0c80
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
+@@ -0,0 +1,359 @@
++/*
++ * OMAP5 thermal driver.
++ *
++ * Copyright (C) 2011-2012 Texas Instruments Inc.
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@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 "ti-thermal.h"
++#include "ti-bandgap.h"
++#include "omap5xxx-bandgap.h"
++
++/*
++ * OMAP5430 has three instances of thermal sensor for MPU, GPU & CORE,
++ * need to describe the individual registers and bit fields.
++ */
++
++/*
++ * OMAP5430 MPU thermal sensor register offset and bit-fields
++ */
++static struct temp_sensor_registers
++omap5430_mpu_temp_sensor_registers = {
++ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET,
++ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
++ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
++ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
++
++ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
++ .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK,
++ .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK,
++ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
++ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
++ .mask_freeze_mask = OMAP5430_MASK_FREEZE_MPU_MASK,
++ .mask_clear_mask = OMAP5430_MASK_CLEAR_MPU_MASK,
++ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK,
++
++
++ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
++ .counter_mask = OMAP5430_COUNTER_MASK,
++
++ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET,
++ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
++ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
++
++ .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET,
++ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
++ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
++
++ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
++ .status_clean_stop_mask = 0x0,
++ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
++ .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK,
++ .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK,
++
++ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET,
++ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_MPU_0_OFFSET,
++ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_MPU_1_OFFSET,
++ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_MPU_2_OFFSET,
++ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_MPU_3_OFFSET,
++ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_MPU_4_OFFSET,
++ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU,
++};
++
++/*
++ * OMAP5430 GPU thermal sensor register offset and bit-fields
++ */
++static struct temp_sensor_registers
++omap5430_gpu_temp_sensor_registers = {
++ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET,
++ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
++ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
++ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
++
++ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
++ .mask_hot_mask = OMAP5430_MASK_HOT_GPU_MASK,
++ .mask_cold_mask = OMAP5430_MASK_COLD_GPU_MASK,
++ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
++ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
++ .mask_freeze_mask = OMAP5430_MASK_FREEZE_GPU_MASK,
++ .mask_clear_mask = OMAP5430_MASK_CLEAR_GPU_MASK,
++ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK,
++
++ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
++ .counter_mask = OMAP5430_COUNTER_MASK,
++
++ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET,
++ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
++ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
++
++ .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET,
++ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
++ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
++
++ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
++ .status_clean_stop_mask = 0x0,
++ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
++ .status_hot_mask = OMAP5430_HOT_GPU_FLAG_MASK,
++ .status_cold_mask = OMAP5430_COLD_GPU_FLAG_MASK,
++
++ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET,
++ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_GPU_0_OFFSET,
++ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_GPU_1_OFFSET,
++ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_GPU_2_OFFSET,
++ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_GPU_3_OFFSET,
++ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_GPU_4_OFFSET,
++
++ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU,
++};
++
++/*
++ * OMAP5430 CORE thermal sensor register offset and bit-fields
++ */
++static struct temp_sensor_registers
++omap5430_core_temp_sensor_registers = {
++ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET,
++ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
++ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
++ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
++
++ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
++ .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK,
++ .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK,
++ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
++ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
++ .mask_freeze_mask = OMAP5430_MASK_FREEZE_CORE_MASK,
++ .mask_clear_mask = OMAP5430_MASK_CLEAR_CORE_MASK,
++ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK,
++
++ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
++ .counter_mask = OMAP5430_COUNTER_MASK,
++
++ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET,
++ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
++ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
++
++ .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET,
++ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
++ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
++
++ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
++ .status_clean_stop_mask = 0x0,
++ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
++ .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK,
++ .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK,
++
++ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET,
++ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_CORE_0_OFFSET,
++ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_CORE_1_OFFSET,
++ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_CORE_2_OFFSET,
++ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_CORE_3_OFFSET,
++ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_CORE_4_OFFSET,
++
++ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE,
++};
++
++/* Thresholds and limits for OMAP5430 MPU temperature sensor */
++static struct temp_sensor_data omap5430_mpu_temp_sensor_data = {
++ .tshut_hot = OMAP5430_MPU_TSHUT_HOT,
++ .tshut_cold = OMAP5430_MPU_TSHUT_COLD,
++ .t_hot = OMAP5430_MPU_T_HOT,
++ .t_cold = OMAP5430_MPU_T_COLD,
++ .min_freq = OMAP5430_MPU_MIN_FREQ,
++ .max_freq = OMAP5430_MPU_MAX_FREQ,
++ .max_temp = OMAP5430_MPU_MAX_TEMP,
++ .min_temp = OMAP5430_MPU_MIN_TEMP,
++ .hyst_val = OMAP5430_MPU_HYST_VAL,
++ .update_int1 = 1000,
++ .update_int2 = 2000,
++};
++
++/* Thresholds and limits for OMAP5430 GPU temperature sensor */
++static struct temp_sensor_data omap5430_gpu_temp_sensor_data = {
++ .tshut_hot = OMAP5430_GPU_TSHUT_HOT,
++ .tshut_cold = OMAP5430_GPU_TSHUT_COLD,
++ .t_hot = OMAP5430_GPU_T_HOT,
++ .t_cold = OMAP5430_GPU_T_COLD,
++ .min_freq = OMAP5430_GPU_MIN_FREQ,
++ .max_freq = OMAP5430_GPU_MAX_FREQ,
++ .max_temp = OMAP5430_GPU_MAX_TEMP,
++ .min_temp = OMAP5430_GPU_MIN_TEMP,
++ .hyst_val = OMAP5430_GPU_HYST_VAL,
++ .update_int1 = 1000,
++ .update_int2 = 2000,
++};
++
++/* Thresholds and limits for OMAP5430 CORE temperature sensor */
++static struct temp_sensor_data omap5430_core_temp_sensor_data = {
++ .tshut_hot = OMAP5430_CORE_TSHUT_HOT,
++ .tshut_cold = OMAP5430_CORE_TSHUT_COLD,
++ .t_hot = OMAP5430_CORE_T_HOT,
++ .t_cold = OMAP5430_CORE_T_COLD,
++ .min_freq = OMAP5430_CORE_MIN_FREQ,
++ .max_freq = OMAP5430_CORE_MAX_FREQ,
++ .max_temp = OMAP5430_CORE_MAX_TEMP,
++ .min_temp = OMAP5430_CORE_MIN_TEMP,
++ .hyst_val = OMAP5430_CORE_HYST_VAL,
++ .update_int1 = 1000,
++ .update_int2 = 2000,
++};
++
++/*
++ * OMAP54xx ES2.0 : Temperature values in milli degree celsius
++ * ADC code values from 540 to 945
++ */
++static int
++omap5430_adc_to_temp[
++ OMAP5430_ADC_END_VALUE - OMAP5430_ADC_START_VALUE + 1] = {
++ /* Index 540 - 549 */
++ -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
++ -37800,
++ /* Index 550 - 559 */
++ -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
++ -33400,
++ /* Index 560 - 569 */
++ -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
++ -29400,
++ /* Index 570 - 579 */
++ -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
++ -25000,
++ /* Index 580 - 589 */
++ -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21600, -21400,
++ -21000,
++ /* Index 590 - 599 */
++ -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
++ -16600,
++ /* Index 600 - 609 */
++ -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
++ -12500,
++ /* Index 610 - 619 */
++ -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
++ -8200,
++ /* Index 620 - 629 */
++ -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500, -3900,
++ /* Index 630 - 639 */
++ -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200, 200,
++ /* Index 640 - 649 */
++ 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900, 4500,
++ /* Index 650 - 659 */
++ 5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200, 8600,
++ /* Index 660 - 669 */
++ 9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200, 12700,
++ /* Index 670 - 679 */
++ 13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600, 17000,
++ /* Index 680 - 689 */
++ 17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600, 21100,
++ /* Index 690 - 699 */
++ 21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000, 25400,
++ /* Index 700 - 709 */
++ 25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000, 29400,
++ /* Index 710 - 719 */
++ 29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400, 33800,
++ /* Index 720 - 729 */
++ 34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400, 37800,
++ /* Index 730 - 739 */
++ 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400, 41800,
++ /* Index 740 - 749 */
++ 42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800, 46200,
++ /* Index 750 - 759 */
++ 46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800, 50200,
++ /* Index 760 - 769 */
++ 50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800, 54200,
++ /* Index 770 - 779 */
++ 54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200, 58600,
++ /* Index 780 - 789 */
++ 59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200, 62600,
++ /* Index 790 - 799 */
++ 63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200, 66600,
++ /* Index 800 - 809 */
++ 67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200, 70600,
++ /* Index 810 - 819 */
++ 71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600, 75000,
++ /* Index 820 - 829 */
++ 75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000,
++ /* Index 830 - 839 */
++ 79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600, 83000,
++ /* Index 840 - 849 */
++ 83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600, 87000,
++ /* Index 850 - 859 */
++ 87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600, 91000,
++ /* Index 860 - 869 */
++ 91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600, 95000,
++ /* Index 870 - 879 */
++ 95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000, 99400,
++ /* Index 880 - 889 */
++ 99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
++ 103400,
++ /* Index 890 - 899 */
++ 103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
++ 107400,
++ /* Index 900 - 909 */
++ 107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
++ 111400,
++ /* Index 910 - 919 */
++ 111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
++ 115400,
++ /* Index 920 - 929 */
++ 115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
++ 119400,
++ /* Index 930 - 939 */
++ 119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000,
++ 123400,
++ /* Index 940 - 945 */
++ 123800, 1242000, 124600, 124900, 125000, 125000,
++};
++
++/* OMAP54xx ES2.0 data */
++const struct ti_bandgap_data omap5430_data = {
++ .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
++ TI_BANDGAP_FEATURE_FREEZE_BIT |
++ TI_BANDGAP_FEATURE_TALERT |
++ TI_BANDGAP_FEATURE_COUNTER_DELAY |
++ TI_BANDGAP_FEATURE_HISTORY_BUFFER,
++ .fclock_name = "l3instr_ts_gclk_div",
++ .div_ck_name = "l3instr_ts_gclk_div",
++ .conv_table = omap5430_adc_to_temp,
++ .adc_start_val = OMAP5430_ADC_START_VALUE,
++ .adc_end_val = OMAP5430_ADC_END_VALUE,
++ .expose_sensor = ti_thermal_expose_sensor,
++ .remove_sensor = ti_thermal_remove_sensor,
++ .report_temperature = ti_thermal_report_sensor_temperature,
++ .sensors = {
++ {
++ .registers = &omap5430_mpu_temp_sensor_registers,
++ .ts_data = &omap5430_mpu_temp_sensor_data,
++ .domain = "cpu",
++ .register_cooling = ti_thermal_register_cpu_cooling,
++ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
++ .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
++ .constant = OMAP_GRADIENT_CONST_5430_CPU,
++ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
++ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
++ },
++ {
++ .registers = &omap5430_gpu_temp_sensor_registers,
++ .ts_data = &omap5430_gpu_temp_sensor_data,
++ .domain = "gpu",
++ .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
++ .constant = OMAP_GRADIENT_CONST_5430_GPU,
++ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
++ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
++ },
++ {
++ .registers = &omap5430_core_temp_sensor_registers,
++ .ts_data = &omap5430_core_temp_sensor_data,
++ .domain = "core",
++ },
++ },
++ .sensor_count = 3,
++};
+diff --git a/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
+new file mode 100644
+index 0000000..400b55d
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
+@@ -0,0 +1,200 @@
++/*
++ * OMAP5xxx bandgap registers, bitfields and temperature definitions
++ *
++ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++#ifndef __OMAP5XXX_BANDGAP_H
++#define __OMAP5XXX_BANDGAP_H
++
++/**
++ * *** OMAP5430 ***
++ *
++ * Below, in sequence, are the Register definitions,
++ * the bitfields and the temperature definitions for OMAP5430.
++ */
++
++/**
++ * OMAP5430 register definitions
++ *
++ * Registers are defined as offsets. The offsets are
++ * relative to FUSE_OPP_BGAP_GPU on 5430.
++ *
++ * Register below are grouped by domain (not necessarily in offset order)
++ */
++
++/* OMAP5430.GPU register offsets */
++#define OMAP5430_FUSE_OPP_BGAP_GPU 0x0
++#define OMAP5430_TEMP_SENSOR_GPU_OFFSET 0x150
++#define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET 0x1A8
++#define OMAP5430_BGAP_TSHUT_GPU_OFFSET 0x1B4
++#define OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET 0x1C0
++#define OMAP5430_BGAP_DTEMP_GPU_0_OFFSET 0x1F4
++#define OMAP5430_BGAP_DTEMP_GPU_1_OFFSET 0x1F8
++#define OMAP5430_BGAP_DTEMP_GPU_2_OFFSET 0x1FC
++#define OMAP5430_BGAP_DTEMP_GPU_3_OFFSET 0x200
++#define OMAP5430_BGAP_DTEMP_GPU_4_OFFSET 0x204
++
++/* OMAP5430.MPU register offsets */
++#define OMAP5430_FUSE_OPP_BGAP_MPU 0x4
++#define OMAP5430_TEMP_SENSOR_MPU_OFFSET 0x14C
++#define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET 0x1A4
++#define OMAP5430_BGAP_TSHUT_MPU_OFFSET 0x1B0
++#define OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET 0x1BC
++#define OMAP5430_BGAP_DTEMP_MPU_0_OFFSET 0x1E0
++#define OMAP5430_BGAP_DTEMP_MPU_1_OFFSET 0x1E4
++#define OMAP5430_BGAP_DTEMP_MPU_2_OFFSET 0x1E8
++#define OMAP5430_BGAP_DTEMP_MPU_3_OFFSET 0x1EC
++#define OMAP5430_BGAP_DTEMP_MPU_4_OFFSET 0x1F0
++
++/* OMAP5430.MPU register offsets */
++#define OMAP5430_FUSE_OPP_BGAP_CORE 0x8
++#define OMAP5430_TEMP_SENSOR_CORE_OFFSET 0x154
++#define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET 0x1AC
++#define OMAP5430_BGAP_TSHUT_CORE_OFFSET 0x1B8
++#define OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET 0x1C4
++#define OMAP5430_BGAP_DTEMP_CORE_0_OFFSET 0x208
++#define OMAP5430_BGAP_DTEMP_CORE_1_OFFSET 0x20C
++#define OMAP5430_BGAP_DTEMP_CORE_2_OFFSET 0x210
++#define OMAP5430_BGAP_DTEMP_CORE_3_OFFSET 0x214
++#define OMAP5430_BGAP_DTEMP_CORE_4_OFFSET 0x218
++
++/* OMAP5430.common register offsets */
++#define OMAP5430_BGAP_CTRL_OFFSET 0x1A0
++#define OMAP5430_BGAP_STATUS_OFFSET 0x1C8
++
++/**
++ * Register bitfields for OMAP5430
++ *
++ * All the macros bellow define the required bits for
++ * controlling temperature on OMAP5430. Bit defines are
++ * grouped by register.
++ */
++
++/* OMAP5430.TEMP_SENSOR */
++#define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK BIT(12)
++#define OMAP5430_BGAP_TEMPSOFF_MASK BIT(11)
++#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10)
++#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
++
++/* OMAP5430.BANDGAP_CTRL */
++#define OMAP5430_MASK_SIDLEMODE_MASK (0x3 << 30)
++#define OMAP5430_MASK_COUNTER_DELAY_MASK (0x7 << 27)
++#define OMAP5430_MASK_FREEZE_CORE_MASK BIT(23)
++#define OMAP5430_MASK_FREEZE_GPU_MASK BIT(22)
++#define OMAP5430_MASK_FREEZE_MPU_MASK BIT(21)
++#define OMAP5430_MASK_CLEAR_CORE_MASK BIT(20)
++#define OMAP5430_MASK_CLEAR_GPU_MASK BIT(19)
++#define OMAP5430_MASK_CLEAR_MPU_MASK BIT(18)
++#define OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK BIT(17)
++#define OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK BIT(16)
++#define OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK BIT(15)
++#define OMAP5430_MASK_HOT_CORE_MASK BIT(5)
++#define OMAP5430_MASK_COLD_CORE_MASK BIT(4)
++#define OMAP5430_MASK_HOT_GPU_MASK BIT(3)
++#define OMAP5430_MASK_COLD_GPU_MASK BIT(2)
++#define OMAP5430_MASK_HOT_MPU_MASK BIT(1)
++#define OMAP5430_MASK_COLD_MPU_MASK BIT(0)
++
++/* OMAP5430.BANDGAP_COUNTER */
++#define OMAP5430_COUNTER_MASK (0xffffff << 0)
++
++/* OMAP5430.BANDGAP_THRESHOLD */
++#define OMAP5430_T_HOT_MASK (0x3ff << 16)
++#define OMAP5430_T_COLD_MASK (0x3ff << 0)
++
++/* OMAP5430.TSHUT_THRESHOLD */
++#define OMAP5430_TSHUT_HOT_MASK (0x3ff << 16)
++#define OMAP5430_TSHUT_COLD_MASK (0x3ff << 0)
++
++/* OMAP5430.BANDGAP_CUMUL_DTEMP_MPU */
++#define OMAP5430_CUMUL_DTEMP_MPU_MASK (0xffffffff << 0)
++
++/* OMAP5430.BANDGAP_CUMUL_DTEMP_GPU */
++#define OMAP5430_CUMUL_DTEMP_GPU_MASK (0xffffffff << 0)
++
++/* OMAP5430.BANDGAP_CUMUL_DTEMP_CORE */
++#define OMAP5430_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
++
++/* OMAP5430.BANDGAP_STATUS */
++#define OMAP5430_BGAP_ALERT_MASK BIT(31)
++#define OMAP5430_HOT_CORE_FLAG_MASK BIT(5)
++#define OMAP5430_COLD_CORE_FLAG_MASK BIT(4)
++#define OMAP5430_HOT_GPU_FLAG_MASK BIT(3)
++#define OMAP5430_COLD_GPU_FLAG_MASK BIT(2)
++#define OMAP5430_HOT_MPU_FLAG_MASK BIT(1)
++#define OMAP5430_COLD_MPU_FLAG_MASK BIT(0)
++
++/**
++ * Temperature limits and thresholds for OMAP5430
++ *
++ * All the macros bellow are definitions for handling the
++ * ADC conversions and representation of temperature limits
++ * and thresholds for OMAP5430. Definitions are grouped
++ * by temperature domain.
++ */
++
++/* OMAP5430.common temperature definitions */
++/* ADC conversion table limits */
++#define OMAP5430_ADC_START_VALUE 540
++#define OMAP5430_ADC_END_VALUE 945
++
++/* OMAP5430.GPU temperature definitions */
++/* bandgap clock limits */
++#define OMAP5430_GPU_MAX_FREQ 1500000
++#define OMAP5430_GPU_MIN_FREQ 1000000
++/* sensor limits */
++#define OMAP5430_GPU_MIN_TEMP -40000
++#define OMAP5430_GPU_MAX_TEMP 125000
++#define OMAP5430_GPU_HYST_VAL 5000
++/* interrupts thresholds */
++#define OMAP5430_GPU_TSHUT_HOT 915
++#define OMAP5430_GPU_TSHUT_COLD 900
++#define OMAP5430_GPU_T_HOT 800
++#define OMAP5430_GPU_T_COLD 795
++
++/* OMAP5430.MPU temperature definitions */
++/* bandgap clock limits */
++#define OMAP5430_MPU_MAX_FREQ 1500000
++#define OMAP5430_MPU_MIN_FREQ 1000000
++/* sensor limits */
++#define OMAP5430_MPU_MIN_TEMP -40000
++#define OMAP5430_MPU_MAX_TEMP 125000
++#define OMAP5430_MPU_HYST_VAL 5000
++/* interrupts thresholds */
++#define OMAP5430_MPU_TSHUT_HOT 915
++#define OMAP5430_MPU_TSHUT_COLD 900
++#define OMAP5430_MPU_T_HOT 800
++#define OMAP5430_MPU_T_COLD 795
++
++/* OMAP5430.CORE temperature definitions */
++/* bandgap clock limits */
++#define OMAP5430_CORE_MAX_FREQ 1500000
++#define OMAP5430_CORE_MIN_FREQ 1000000
++/* sensor limits */
++#define OMAP5430_CORE_MIN_TEMP -40000
++#define OMAP5430_CORE_MAX_TEMP 125000
++#define OMAP5430_CORE_HYST_VAL 5000
++/* interrupts thresholds */
++#define OMAP5430_CORE_TSHUT_HOT 915
++#define OMAP5430_CORE_TSHUT_COLD 900
++#define OMAP5430_CORE_T_HOT 800
++#define OMAP5430_CORE_T_COLD 795
++
++#endif /* __OMAP5XXX_BANDGAP_H */
+diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
+new file mode 100644
+index 0000000..f20c1cf
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
+@@ -0,0 +1,1546 @@
++/*
++ * TI Bandgap temperature sensor driver
++ *
++ * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
++ * Author: J Keerthy <j-keerthy@ti.com>
++ * Author: Moiz Sonasath <m-sonasath@ti.com>
++ * Couple of fixes, DT and MFD adaptation:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/export.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/reboot.h>
++#include <linux/of_device.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++#include <linux/io.h>
++
++#include "ti-bandgap.h"
++
++/*** Helper functions to access registers and their bitfields ***/
++
++/**
++ * ti_bandgap_readl() - simple read helper function
++ * @bgp: pointer to ti_bandgap structure
++ * @reg: desired register (offset) to be read
++ *
++ * Helper function to read bandgap registers. It uses the io remapped area.
++ * Return: the register value.
++ */
++static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
++{
++ return readl(bgp->base + reg);
++}
++
++/**
++ * ti_bandgap_writel() - simple write helper function
++ * @bgp: pointer to ti_bandgap structure
++ * @val: desired register value to be written
++ * @reg: desired register (offset) to be written
++ *
++ * Helper function to write bandgap registers. It uses the io remapped area.
++ */
++static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
++{
++ writel(val, bgp->base + reg);
++}
++
++/**
++ * DOC: macro to update bits.
++ *
++ * RMW_BITS() - used to read, modify and update bandgap bitfields.
++ * The value passed will be shifted.
++ */
++#define RMW_BITS(bgp, id, reg, mask, val) \
++do { \
++ struct temp_sensor_registers *t; \
++ u32 r; \
++ \
++ t = bgp->conf->sensors[(id)].registers; \
++ r = ti_bandgap_readl(bgp, t->reg); \
++ r &= ~t->mask; \
++ r |= (val) << __ffs(t->mask); \
++ ti_bandgap_writel(bgp, r, t->reg); \
++} while (0)
++
++/*** Basic helper functions ***/
++
++/**
++ * ti_bandgap_power() - controls the power state of a bandgap device
++ * @bgp: pointer to ti_bandgap structure
++ * @on: desired power state (1 - on, 0 - off)
++ *
++ * Used to power on/off a bandgap device instance. Only used on those
++ * that features tempsoff bit.
++ *
++ * Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
++ */
++static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
++{
++ int i, ret = 0;
++
++ if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ for (i = 0; i < bgp->conf->sensor_count; i++)
++ /* active on 0 */
++ RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
++
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_read_temp() - helper function to read sensor temperature
++ * @bgp: pointer to ti_bandgap structure
++ * @id: bandgap sensor id
++ *
++ * Function to concentrate the steps to read sensor temperature register.
++ * This function is desired because, depending on bandgap device version,
++ * it might be needed to freeze the bandgap state machine, before fetching
++ * the register value.
++ *
++ * Return: temperature in ADC values.
++ */
++static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
++{
++ struct temp_sensor_registers *tsr;
++ u32 temp, reg;
++
++ tsr = bgp->conf->sensors[id].registers;
++ reg = tsr->temp_sensor_ctrl;
++
++ if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
++ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
++ /*
++ * In case we cannot read from cur_dtemp / dtemp_0,
++ * then we read from the last valid temp read
++ */
++ reg = tsr->ctrl_dtemp_1;
++ }
++
++ /* read temperature */
++ temp = ti_bandgap_readl(bgp, reg);
++ temp &= tsr->bgap_dtemp_mask;
++
++ if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
++ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
++
++ return temp;
++}
++
++/*** IRQ handlers ***/
++
++/**
++ * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs
++ * @irq: IRQ number
++ * @data: private data (struct ti_bandgap *)
++ *
++ * This is the Talert handler. Use it only if bandgap device features
++ * HAS(TALERT). This handler goes over all sensors and checks their
++ * conditions and acts accordingly. In case there are events pending,
++ * it will reset the event mask to wait for the opposite event (next event).
++ * Every time there is a new event, it will be reported to thermal layer.
++ *
++ * Return: IRQ_HANDLED
++ */
++static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
++{
++ struct ti_bandgap *bgp = data;
++ struct temp_sensor_registers *tsr;
++ u32 t_hot = 0, t_cold = 0, ctrl;
++ int i;
++
++ spin_lock(&bgp->lock);
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ tsr = bgp->conf->sensors[i].registers;
++ ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
++
++ /* Read the status of t_hot */
++ t_hot = ctrl & tsr->status_hot_mask;
++
++ /* Read the status of t_cold */
++ t_cold = ctrl & tsr->status_cold_mask;
++
++ if (!t_cold && !t_hot)
++ continue;
++
++ ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
++ /*
++ * One TALERT interrupt: Two sources
++ * If the interrupt is due to t_hot then mask t_hot and
++ * and unmask t_cold else mask t_cold and unmask t_hot
++ */
++ if (t_hot) {
++ ctrl &= ~tsr->mask_hot_mask;
++ ctrl |= tsr->mask_cold_mask;
++ } else if (t_cold) {
++ ctrl &= ~tsr->mask_cold_mask;
++ ctrl |= tsr->mask_hot_mask;
++ }
++
++ ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
++
++ dev_dbg(bgp->dev,
++ "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
++ __func__, bgp->conf->sensors[i].domain,
++ t_hot, t_cold);
++
++ /* report temperature to whom may concern */
++ if (bgp->conf->report_temperature)
++ bgp->conf->report_temperature(bgp, i);
++ }
++ spin_unlock(&bgp->lock);
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
++ * @irq: IRQ number
++ * @data: private data (unused)
++ *
++ * This is the Tshut handler. Use it only if bandgap device features
++ * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
++ * the system.
++ *
++ * Return: IRQ_HANDLED
++ */
++static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data)
++{
++ pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
++ __func__);
++
++ orderly_poweroff(true);
++
++ return IRQ_HANDLED;
++}
++
++/*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/
++
++/**
++ * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
++ * @bgp: struct ti_bandgap pointer
++ * @adc_val: value in ADC representation
++ * @t: address where to write the resulting temperature in mCelsius
++ *
++ * Simple conversion from ADC representation to mCelsius. In case the ADC value
++ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
++ * The conversion table is indexed by the ADC values.
++ *
++ * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val
++ * argument is out of the ADC conv table range.
++ */
++static
++int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
++{
++ const struct ti_bandgap_data *conf = bgp->conf;
++ int ret = 0;
++
++ /* look up for temperature in the table and return the temperature */
++ if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {
++ ret = -ERANGE;
++ goto exit;
++ }
++
++ *t = bgp->conf->conv_table[adc_val - conf->adc_start_val];
++
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale
++ * @bgp: struct ti_bandgap pointer
++ * @temp: value in mCelsius
++ * @adc: address where to write the resulting temperature in ADC representation
++ *
++ * Simple conversion from mCelsius to ADC values. In case the temp value
++ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
++ * The conversion table is indexed by the ADC values.
++ *
++ * Return: 0 if conversion was successful, else -ERANGE in case the @temp
++ * argument is out of the ADC conv table range.
++ */
++static
++int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc)
++{
++ const struct ti_bandgap_data *conf = bgp->conf;
++ const int *conv_table = bgp->conf->conv_table;
++ int high, low, mid, ret = 0;
++
++ low = 0;
++ high = conf->adc_end_val - conf->adc_start_val;
++ mid = (high + low) / 2;
++
++ if (temp < conv_table[low] || temp > conv_table[high]) {
++ ret = -ERANGE;
++ goto exit;
++ }
++
++ while (low < high) {
++ if (temp < conv_table[mid])
++ high = mid - 1;
++ else
++ low = mid + 1;
++ mid = (low + high) / 2;
++ }
++
++ *adc = conf->adc_start_val + low;
++
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value
++ * @bgp: struct ti_bandgap pointer
++ * @adc_val: temperature value in ADC representation
++ * @hyst_val: hysteresis value in mCelsius
++ * @sum: address where to write the resulting temperature (in ADC scale)
++ *
++ * Adds an hysteresis value (in mCelsius) to a ADC temperature value.
++ *
++ * Return: 0 on success, -ERANGE otherwise.
++ */
++static
++int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val,
++ u32 *sum)
++{
++ int temp, ret;
++
++ /*
++ * Need to add in the mcelsius domain, so we have a temperature
++ * the conv_table range
++ */
++ ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp);
++ if (ret < 0)
++ goto exit;
++
++ temp += hyst_val;
++
++ ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum);
++
++exit:
++ return ret;
++}
++
++/*** Helper functions handling device Alert/Shutdown signals ***/
++
++/**
++ * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold
++ * @bgp: struct ti_bandgap pointer
++ * @id: bandgap sensor id
++ * @t_hot: hot temperature value to trigger alert signal
++ * @t_cold: cold temperature value to trigger alert signal
++ *
++ * Checks the requested t_hot and t_cold values and configures the IRQ event
++ * masks accordingly. Call this function only if bandgap features HAS(TALERT).
++ */
++static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id,
++ u32 t_hot, u32 t_cold)
++{
++ struct temp_sensor_registers *tsr;
++ u32 temp, reg_val;
++
++ /* Read the current on die temperature */
++ temp = ti_bandgap_read_temp(bgp, id);
++
++ tsr = bgp->conf->sensors[id].registers;
++ reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
++
++ if (temp < t_hot)
++ reg_val |= tsr->mask_hot_mask;
++ else
++ reg_val &= ~tsr->mask_hot_mask;
++
++ if (t_cold < temp)
++ reg_val |= tsr->mask_cold_mask;
++ else
++ reg_val &= ~tsr->mask_cold_mask;
++ ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl);
++}
++
++/**
++ * ti_bandgap_update_alert_threshold() - sequence to update thresholds
++ * @bgp: struct ti_bandgap pointer
++ * @id: bandgap sensor id
++ * @val: value (ADC) of a new threshold
++ * @hot: desired threshold to be updated. true if threshold hot, false if
++ * threshold cold
++ *
++ * It will program the required thresholds (hot and cold) for TALERT signal.
++ * This function can be used to update t_hot or t_cold, depending on @hot value.
++ * It checks the resulting t_hot and t_cold values, based on the new passed @val
++ * and configures the thresholds so that t_hot is always greater than t_cold.
++ * Call this function only if bandgap features HAS(TALERT).
++ *
++ * Return: 0 if no error, else corresponding error
++ */
++static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
++ int val, bool hot)
++{
++ struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data;
++ struct temp_sensor_registers *tsr;
++ u32 thresh_val, reg_val, t_hot, t_cold;
++ int err = 0;
++
++ tsr = bgp->conf->sensors[id].registers;
++
++ /* obtain the current value */
++ thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold);
++ t_cold = (thresh_val & tsr->threshold_tcold_mask) >>
++ __ffs(tsr->threshold_tcold_mask);
++ t_hot = (thresh_val & tsr->threshold_thot_mask) >>
++ __ffs(tsr->threshold_thot_mask);
++ if (hot)
++ t_hot = val;
++ else
++ t_cold = val;
++
++ if (t_cold > t_hot) {
++ if (hot)
++ err = ti_bandgap_add_hyst(bgp, t_hot,
++ -ts_data->hyst_val,
++ &t_cold);
++ else
++ err = ti_bandgap_add_hyst(bgp, t_cold,
++ ts_data->hyst_val,
++ &t_hot);
++ }
++
++ /* write the new threshold values */
++ reg_val = thresh_val &
++ ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask);
++ reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) |
++ (t_cold << __ffs(tsr->threshold_tcold_mask));
++ ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold);
++
++ if (err) {
++ dev_err(bgp->dev, "failed to reprogram thot threshold\n");
++ err = -EIO;
++ goto exit;
++ }
++
++ ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold);
++exit:
++ return err;
++}
++
++/**
++ * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
++ * @bgp: struct ti_bandgap pointer
++ * @id: bandgap sensor id
++ *
++ * Checks if the bandgap pointer is valid and if the sensor id is also
++ * applicable.
++ *
++ * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
++ * @id cannot index @bgp sensors.
++ */
++static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
++{
++ int ret = 0;
++
++ if (IS_ERR_OR_NULL(bgp)) {
++ pr_err("%s: invalid bandgap pointer\n", __func__);
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ if ((id < 0) || (id >= bgp->conf->sensor_count)) {
++ dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
++ __func__, id);
++ ret = -ERANGE;
++ }
++
++exit:
++ return ret;
++}
++
++/**
++ * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot
++ * @bgp: struct ti_bandgap pointer
++ * @id: bandgap sensor id
++ * @val: value (mCelsius) of a new threshold
++ * @hot: desired threshold to be updated. true if threshold hot, false if
++ * threshold cold
++ *
++ * It will update the required thresholds (hot and cold) for TALERT signal.
++ * This function can be used to update t_hot or t_cold, depending on @hot value.
++ * Validates the mCelsius range and update the requested threshold.
++ * Call this function only if bandgap features HAS(TALERT).
++ *
++ * Return: 0 if no error, else corresponding error value.
++ */
++static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val,
++ bool hot)
++{
++ struct temp_sensor_data *ts_data;
++ struct temp_sensor_registers *tsr;
++ u32 adc_val;
++ int ret;
++
++ ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ goto exit;
++
++ if (!TI_BANDGAP_HAS(bgp, TALERT)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ ts_data = bgp->conf->sensors[id].ts_data;
++ tsr = bgp->conf->sensors[id].registers;
++ if (hot) {
++ if (val < ts_data->min_temp + ts_data->hyst_val)
++ ret = -EINVAL;
++ } else {
++ if (val > ts_data->max_temp + ts_data->hyst_val)
++ ret = -EINVAL;
++ }
++
++ if (ret)
++ goto exit;
++
++ ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val);
++ if (ret < 0)
++ goto exit;
++
++ spin_lock(&bgp->lock);
++ ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot);
++ spin_unlock(&bgp->lock);
++
++exit:
++ return ret;
++}
++
++/**
++ * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot
++ * @bgp: struct ti_bandgap pointer
++ * @id: bandgap sensor id
++ * @val: value (mCelsius) of a threshold
++ * @hot: desired threshold to be read. true if threshold hot, false if
++ * threshold cold
++ *
++ * It will fetch the required thresholds (hot and cold) for TALERT signal.
++ * This function can be used to read t_hot or t_cold, depending on @hot value.
++ * Call this function only if bandgap features HAS(TALERT).
++ *
++ * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the
++ * corresponding error value if some operation fails.
++ */
++static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id,
++ int *val, bool hot)
++{
++ struct temp_sensor_registers *tsr;
++ u32 temp, mask;
++ int ret = 0;
++
++ ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ goto exit;
++
++ if (!TI_BANDGAP_HAS(bgp, TALERT)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ tsr = bgp->conf->sensors[id].registers;
++ if (hot)
++ mask = tsr->threshold_thot_mask;
++ else
++ mask = tsr->threshold_tcold_mask;
++
++ temp = ti_bandgap_readl(bgp, tsr->bgap_threshold);
++ temp = (temp & mask) >> __ffs(mask);
++ ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
++ if (ret) {
++ dev_err(bgp->dev, "failed to read thot\n");
++ ret = -EIO;
++ goto exit;
++ }
++
++ *val = temp;
++
++exit:
++ return ret;
++}
++
++/*** Exposed APIs ***/
++
++/**
++ * ti_bandgap_read_thot() - reads sensor current thot
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @thot: resulting current thot value
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot)
++{
++ return _ti_bandgap_read_threshold(bgp, id, thot, true);
++}
++
++/**
++ * ti_bandgap_write_thot() - sets sensor current thot
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @val: desired thot value
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val)
++{
++ return _ti_bandgap_write_threshold(bgp, id, val, true);
++}
++
++/**
++ * ti_bandgap_read_tcold() - reads sensor current tcold
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @tcold: resulting current tcold value
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold)
++{
++ return _ti_bandgap_read_threshold(bgp, id, tcold, false);
++}
++
++/**
++ * ti_bandgap_write_tcold() - sets the sensor tcold
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @val: desired tcold value
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val)
++{
++ return _ti_bandgap_write_threshold(bgp, id, val, false);
++}
++
++/**
++ * ti_bandgap_read_counter() - read the sensor counter
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: resulting update interval in miliseconds
++ */
++static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id,
++ int *interval)
++{
++ struct temp_sensor_registers *tsr;
++ int time;
++
++ tsr = bgp->conf->sensors[id].registers;
++ time = ti_bandgap_readl(bgp, tsr->bgap_counter);
++ time = (time & tsr->counter_mask) >>
++ __ffs(tsr->counter_mask);
++ time = time * 1000 / bgp->clk_rate;
++ *interval = time;
++}
++
++/**
++ * ti_bandgap_read_counter_delay() - read the sensor counter delay
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: resulting update interval in miliseconds
++ */
++static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id,
++ int *interval)
++{
++ struct temp_sensor_registers *tsr;
++ int reg_val;
++
++ tsr = bgp->conf->sensors[id].registers;
++
++ reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
++ reg_val = (reg_val & tsr->mask_counter_delay_mask) >>
++ __ffs(tsr->mask_counter_delay_mask);
++ switch (reg_val) {
++ case 0:
++ *interval = 0;
++ break;
++ case 1:
++ *interval = 1;
++ break;
++ case 2:
++ *interval = 10;
++ break;
++ case 3:
++ *interval = 100;
++ break;
++ case 4:
++ *interval = 250;
++ break;
++ case 5:
++ *interval = 500;
++ break;
++ default:
++ dev_warn(bgp->dev, "Wrong counter delay value read from register %X",
++ reg_val);
++ }
++}
++
++/**
++ * ti_bandgap_read_update_interval() - read the sensor update interval
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: resulting update interval in miliseconds
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
++ int *interval)
++{
++ int ret = 0;
++
++ ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ goto exit;
++
++ if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
++ !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ if (TI_BANDGAP_HAS(bgp, COUNTER)) {
++ ti_bandgap_read_counter(bgp, id, interval);
++ goto exit;
++ }
++
++ ti_bandgap_read_counter_delay(bgp, id, interval);
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_write_counter_delay() - set the counter_delay
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: desired update interval in miliseconds
++ *
++ * Return: 0 on success or the proper error code
++ */
++static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id,
++ u32 interval)
++{
++ int rval;
++
++ switch (interval) {
++ case 0: /* Immediate conversion */
++ rval = 0x0;
++ break;
++ case 1: /* Conversion after ever 1ms */
++ rval = 0x1;
++ break;
++ case 10: /* Conversion after ever 10ms */
++ rval = 0x2;
++ break;
++ case 100: /* Conversion after ever 100ms */
++ rval = 0x3;
++ break;
++ case 250: /* Conversion after ever 250ms */
++ rval = 0x4;
++ break;
++ case 500: /* Conversion after ever 500ms */
++ rval = 0x5;
++ break;
++ default:
++ dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval);
++ return -EINVAL;
++ }
++
++ spin_lock(&bgp->lock);
++ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval);
++ spin_unlock(&bgp->lock);
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_write_counter() - set the bandgap sensor counter
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: desired update interval in miliseconds
++ */
++static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id,
++ u32 interval)
++{
++ interval = interval * bgp->clk_rate / 1000;
++ spin_lock(&bgp->lock);
++ RMW_BITS(bgp, id, bgap_counter, counter_mask, interval);
++ spin_unlock(&bgp->lock);
++}
++
++/**
++ * ti_bandgap_write_update_interval() - set the update interval
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @interval: desired update interval in miliseconds
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_write_update_interval(struct ti_bandgap *bgp,
++ int id, u32 interval)
++{
++ int ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ goto exit;
++
++ if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
++ !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ if (TI_BANDGAP_HAS(bgp, COUNTER)) {
++ ti_bandgap_write_counter(bgp, id, interval);
++ goto exit;
++ }
++
++ ret = ti_bandgap_write_counter_delay(bgp, id, interval);
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_read_temperature() - report current temperature
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @temperature: resulting temperature
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
++ int *temperature)
++{
++ u32 temp;
++ int ret;
++
++ ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ return ret;
++
++ spin_lock(&bgp->lock);
++ temp = ti_bandgap_read_temp(bgp, id);
++ spin_unlock(&bgp->lock);
++
++ ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
++ if (ret)
++ return -EIO;
++
++ *temperature = temp;
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_set_sensor_data() - helper function to store thermal
++ * framework related data.
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ * @data: thermal framework related data to be stored
++ *
++ * Return: 0 on success or the proper error code
++ */
++int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
++{
++ int ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ return ret;
++
++ bgp->regval[id].data = data;
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_get_sensor_data() - helper function to get thermal
++ * framework related data.
++ * @bgp: pointer to bandgap instance
++ * @id: sensor id
++ *
++ * Return: data stored by set function with sensor id on success or NULL
++ */
++void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
++{
++ int ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ return ERR_PTR(ret);
++
++ return bgp->regval[id].data;
++}
++
++/*** Helper functions used during device initialization ***/
++
++/**
++ * ti_bandgap_force_single_read() - executes 1 single ADC conversion
++ * @bgp: pointer to struct ti_bandgap
++ * @id: sensor id which it is desired to read 1 temperature
++ *
++ * Used to initialize the conversion state machine and set it to a valid
++ * state. Called during device initialization and context restore events.
++ *
++ * Return: 0
++ */
++static int
++ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id)
++{
++ u32 temp = 0, counter = 1000;
++
++ /* Select single conversion mode */
++ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
++ RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
++
++ /* Start of Conversion = 1 */
++ RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
++ /* Wait until DTEMP is updated */
++ temp = ti_bandgap_read_temp(bgp, id);
++
++ while ((temp == 0) && --counter)
++ temp = ti_bandgap_read_temp(bgp, id);
++ /* REVISIT: Check correct condition for end of conversion */
++
++ /* Start of Conversion = 0 */
++ RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_set_continous_mode() - One time enabling of continuous mode
++ * @bgp: pointer to struct ti_bandgap
++ *
++ * Call this function only if HAS(MODE_CONFIG) is set. As this driver may
++ * be used for junction temperature monitoring, it is desirable that the
++ * sensors are operational all the time, so that alerts are generated
++ * properly.
++ *
++ * Return: 0
++ */
++static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp)
++{
++ int i;
++
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ /* Perform a single read just before enabling continuous */
++ ti_bandgap_force_single_read(bgp, i);
++ RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
++ }
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor
++ * @bgp: pointer to struct ti_bandgap
++ * @id: id of the individual sensor
++ * @trend: Pointer to trend.
++ *
++ * This function needs to be called to fetch the temperature trend of a
++ * Particular sensor. The function computes the difference in temperature
++ * w.r.t time. For the bandgaps with built in history buffer the temperatures
++ * are read from the buffer and for those without the Buffer -ENOTSUPP is
++ * returned.
++ *
++ * Return: 0 if no error, else return corresponding error. If no
++ * error then the trend value is passed on to trend parameter
++ */
++int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
++{
++ struct temp_sensor_registers *tsr;
++ u32 temp1, temp2, reg1, reg2;
++ int t1, t2, interval, ret = 0;
++
++ ret = ti_bandgap_validate(bgp, id);
++ if (ret)
++ goto exit;
++
++ if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
++ !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
++ ret = -ENOTSUPP;
++ goto exit;
++ }
++
++ tsr = bgp->conf->sensors[id].registers;
++
++ /* Freeze and read the last 2 valid readings */
++ reg1 = tsr->ctrl_dtemp_1;
++ reg2 = tsr->ctrl_dtemp_2;
++
++ /* read temperature from history buffer */
++ temp1 = ti_bandgap_readl(bgp, reg1);
++ temp1 &= tsr->bgap_dtemp_mask;
++
++ temp2 = ti_bandgap_readl(bgp, reg2);
++ temp2 &= tsr->bgap_dtemp_mask;
++
++ /* Convert from adc values to mCelsius temperature */
++ ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
++ if (ret)
++ goto exit;
++
++ ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
++ if (ret)
++ goto exit;
++
++ /* Fetch the update interval */
++ ret = ti_bandgap_read_update_interval(bgp, id, &interval);
++ if (ret || !interval)
++ goto exit;
++
++ *trend = (t1 - t2) / interval;
++
++ dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
++ t1, t2, *trend);
++
++exit:
++ return ret;
++}
++
++/**
++ * ti_bandgap_tshut_init() - setup and initialize tshut handling
++ * @bgp: pointer to struct ti_bandgap
++ * @pdev: pointer to device struct platform_device
++ *
++ * Call this function only in case the bandgap features HAS(TSHUT).
++ * In this case, the driver needs to handle the TSHUT signal as an IRQ.
++ * The IRQ is wired as a GPIO, and for this purpose, it is required
++ * to specify which GPIO line is used. TSHUT IRQ is fired anytime
++ * one of the bandgap sensors violates the TSHUT high/hot threshold.
++ * And in that case, the system must go off.
++ *
++ * Return: 0 if no error, else error status
++ */
++static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
++ struct platform_device *pdev)
++{
++ int gpio_nr = bgp->tshut_gpio;
++ int status;
++
++ /* Request for gpio_86 line */
++ status = gpio_request(gpio_nr, "tshut");
++ if (status < 0) {
++ dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
++ return status;
++ }
++ status = gpio_direction_input(gpio_nr);
++ if (status) {
++ dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
++ return status;
++ }
++
++ status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
++ IRQF_TRIGGER_RISING, "tshut", NULL);
++ if (status) {
++ gpio_free(gpio_nr);
++ dev_err(bgp->dev, "request irq failed for TSHUT");
++ }
++
++ return 0;
++}
++
++/**
++ * ti_bandgap_alert_init() - setup and initialize talert handling
++ * @bgp: pointer to struct ti_bandgap
++ * @pdev: pointer to device struct platform_device
++ *
++ * Call this function only in case the bandgap features HAS(TALERT).
++ * In this case, the driver needs to handle the TALERT signals as an IRQs.
++ * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold)
++ * are violated. In these situation, the driver must reprogram the thresholds,
++ * accordingly to specified policy.
++ *
++ * Return: 0 if no error, else return corresponding error.
++ */
++static int ti_bandgap_talert_init(struct ti_bandgap *bgp,
++ struct platform_device *pdev)
++{
++ int ret;
++
++ bgp->irq = platform_get_irq(pdev, 0);
++ if (bgp->irq < 0) {
++ dev_err(&pdev->dev, "get_irq failed\n");
++ return bgp->irq;
++ }
++ ret = request_threaded_irq(bgp->irq, NULL,
++ ti_bandgap_talert_irq_handler,
++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
++ "talert", bgp);
++ if (ret) {
++ dev_err(&pdev->dev, "Request threaded irq failed.\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id of_ti_bandgap_match[];
++/**
++ * ti_bandgap_build() - parse DT and setup a struct ti_bandgap
++ * @pdev: pointer to device struct platform_device
++ *
++ * Used to read the device tree properties accordingly to the bandgap
++ * matching version. Based on bandgap version and its capabilities it
++ * will build a struct ti_bandgap out of the required DT entries.
++ *
++ * Return: valid bandgap structure if successful, else returns ERR_PTR
++ * return value must be verified with IS_ERR.
++ */
++static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
++{
++ struct device_node *node = pdev->dev.of_node;
++ const struct of_device_id *of_id;
++ struct ti_bandgap *bgp;
++ struct resource *res;
++ u32 prop;
++ int i;
++
++ /* just for the sake */
++ if (!node) {
++ dev_err(&pdev->dev, "no platform information available\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
++ if (!bgp) {
++ dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ of_id = of_match_device(of_ti_bandgap_match, &pdev->dev);
++ if (of_id)
++ bgp->conf = of_id->data;
++
++ /* register shadow for context save and restore */
++ bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) *
++ bgp->conf->sensor_count, GFP_KERNEL);
++ if (!bgp) {
++ dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ i = 0;
++ do {
++ void __iomem *chunk;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
++ if (!res)
++ break;
++ chunk = devm_ioremap_resource(&pdev->dev, res);
++ if (i == 0)
++ bgp->base = chunk;
++ if (IS_ERR(chunk))
++ return ERR_CAST(chunk);
++
++ i++;
++ } while (res);
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
++ if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
++ dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
++ return ERR_PTR(-EINVAL);
++ }
++ bgp->tshut_gpio = prop;
++ if (!gpio_is_valid(bgp->tshut_gpio)) {
++ dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
++ bgp->tshut_gpio);
++ return ERR_PTR(-EINVAL);
++ }
++ }
++
++ return bgp;
++}
++
++/*** Device driver call backs ***/
++
++static
++int ti_bandgap_probe(struct platform_device *pdev)
++{
++ struct ti_bandgap *bgp;
++ int clk_rate, ret = 0, i;
++
++ bgp = ti_bandgap_build(pdev);
++ if (IS_ERR_OR_NULL(bgp)) {
++ dev_err(&pdev->dev, "failed to fetch platform data\n");
++ return PTR_ERR(bgp);
++ }
++ bgp->dev = &pdev->dev;
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
++ ret = ti_bandgap_tshut_init(bgp, pdev);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "failed to initialize system tshut IRQ\n");
++ return ret;
++ }
++ }
++
++ bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
++ ret = IS_ERR_OR_NULL(bgp->fclock);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to request fclock reference\n");
++ goto free_irqs;
++ }
++
++ bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);
++ ret = IS_ERR_OR_NULL(bgp->div_clk);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "failed to request div_ts_ck clock ref\n");
++ goto free_irqs;
++ }
++
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ struct temp_sensor_registers *tsr;
++ u32 val;
++
++ tsr = bgp->conf->sensors[i].registers;
++ /*
++ * check if the efuse has a non-zero value if not
++ * it is an untrimmed sample and the temperatures
++ * may not be accurate
++ */
++ val = ti_bandgap_readl(bgp, tsr->bgap_efuse);
++ if (ret || !val)
++ dev_info(&pdev->dev,
++ "Non-trimmed BGAP, Temp not accurate\n");
++ }
++
++ clk_rate = clk_round_rate(bgp->div_clk,
++ bgp->conf->sensors[0].ts_data->max_freq);
++ if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq ||
++ clk_rate == 0xffffffff) {
++ ret = -ENODEV;
++ dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
++ goto put_clks;
++ }
++
++ ret = clk_set_rate(bgp->div_clk, clk_rate);
++ if (ret)
++ dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
++
++ bgp->clk_rate = clk_rate;
++ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
++ clk_prepare_enable(bgp->fclock);
++
++
++ spin_lock_init(&bgp->lock);
++ bgp->dev = &pdev->dev;
++ platform_set_drvdata(pdev, bgp);
++
++ ti_bandgap_power(bgp, true);
++
++ /* Set default counter to 1 for now */
++ if (TI_BANDGAP_HAS(bgp, COUNTER))
++ for (i = 0; i < bgp->conf->sensor_count; i++)
++ RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
++
++ /* Set default thresholds for alert and shutdown */
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ struct temp_sensor_data *ts_data;
++
++ ts_data = bgp->conf->sensors[i].ts_data;
++
++ if (TI_BANDGAP_HAS(bgp, TALERT)) {
++ /* Set initial Talert thresholds */
++ RMW_BITS(bgp, i, bgap_threshold,
++ threshold_tcold_mask, ts_data->t_cold);
++ RMW_BITS(bgp, i, bgap_threshold,
++ threshold_thot_mask, ts_data->t_hot);
++ /* Enable the alert events */
++ RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
++ RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
++ }
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) {
++ /* Set initial Tshut thresholds */
++ RMW_BITS(bgp, i, tshut_threshold,
++ tshut_hot_mask, ts_data->tshut_hot);
++ RMW_BITS(bgp, i, tshut_threshold,
++ tshut_cold_mask, ts_data->tshut_cold);
++ }
++ }
++
++ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
++ ti_bandgap_set_continuous_mode(bgp);
++
++ /* Set .250 seconds time as default counter */
++ if (TI_BANDGAP_HAS(bgp, COUNTER))
++ for (i = 0; i < bgp->conf->sensor_count; i++)
++ RMW_BITS(bgp, i, bgap_counter, counter_mask,
++ bgp->clk_rate / 4);
++
++ /* Every thing is good? Then expose the sensors */
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ char *domain;
++
++ if (bgp->conf->sensors[i].register_cooling) {
++ ret = bgp->conf->sensors[i].register_cooling(bgp, i);
++ if (ret)
++ goto remove_sensors;
++ }
++
++ if (bgp->conf->expose_sensor) {
++ domain = bgp->conf->sensors[i].domain;
++ ret = bgp->conf->expose_sensor(bgp, i, domain);
++ if (ret)
++ goto remove_last_cooling;
++ }
++ }
++
++ /*
++ * Enable the Interrupts once everything is set. Otherwise irq handler
++ * might be called as soon as it is enabled where as rest of framework
++ * is still getting initialised.
++ */
++ if (TI_BANDGAP_HAS(bgp, TALERT)) {
++ ret = ti_bandgap_talert_init(bgp, pdev);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
++ i = bgp->conf->sensor_count;
++ goto disable_clk;
++ }
++ }
++
++ return 0;
++
++remove_last_cooling:
++ if (bgp->conf->sensors[i].unregister_cooling)
++ bgp->conf->sensors[i].unregister_cooling(bgp, i);
++remove_sensors:
++ for (i--; i >= 0; i--) {
++ if (bgp->conf->sensors[i].unregister_cooling)
++ bgp->conf->sensors[i].unregister_cooling(bgp, i);
++ if (bgp->conf->remove_sensor)
++ bgp->conf->remove_sensor(bgp, i);
++ }
++ ti_bandgap_power(bgp, false);
++disable_clk:
++ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
++ clk_disable_unprepare(bgp->fclock);
++put_clks:
++ clk_put(bgp->fclock);
++ clk_put(bgp->div_clk);
++free_irqs:
++ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
++ free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
++ gpio_free(bgp->tshut_gpio);
++ }
++
++ return ret;
++}
++
++static
++int ti_bandgap_remove(struct platform_device *pdev)
++{
++ struct ti_bandgap *bgp = platform_get_drvdata(pdev);
++ int i;
++
++ /* First thing is to remove sensor interfaces */
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ if (bgp->conf->sensors[i].unregister_cooling)
++ bgp->conf->sensors[i].unregister_cooling(bgp, i);
++
++ if (bgp->conf->remove_sensor)
++ bgp->conf->remove_sensor(bgp, i);
++ }
++
++ ti_bandgap_power(bgp, false);
++
++ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
++ clk_disable_unprepare(bgp->fclock);
++ clk_put(bgp->fclock);
++ clk_put(bgp->div_clk);
++
++ if (TI_BANDGAP_HAS(bgp, TALERT))
++ free_irq(bgp->irq, bgp);
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
++ free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
++ gpio_free(bgp->tshut_gpio);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
++{
++ int i;
++
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ struct temp_sensor_registers *tsr;
++ struct temp_sensor_regval *rval;
++
++ rval = &bgp->regval[i];
++ tsr = bgp->conf->sensors[i].registers;
++
++ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
++ rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
++ tsr->bgap_mode_ctrl);
++ if (TI_BANDGAP_HAS(bgp, COUNTER))
++ rval->bg_counter = ti_bandgap_readl(bgp,
++ tsr->bgap_counter);
++ if (TI_BANDGAP_HAS(bgp, TALERT)) {
++ rval->bg_threshold = ti_bandgap_readl(bgp,
++ tsr->bgap_threshold);
++ rval->bg_ctrl = ti_bandgap_readl(bgp,
++ tsr->bgap_mask_ctrl);
++ }
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
++ rval->tshut_threshold = ti_bandgap_readl(bgp,
++ tsr->tshut_threshold);
++ }
++
++ return 0;
++}
++
++static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
++{
++ int i;
++
++ for (i = 0; i < bgp->conf->sensor_count; i++) {
++ struct temp_sensor_registers *tsr;
++ struct temp_sensor_regval *rval;
++ u32 val = 0;
++
++ rval = &bgp->regval[i];
++ tsr = bgp->conf->sensors[i].registers;
++
++ if (TI_BANDGAP_HAS(bgp, COUNTER))
++ val = ti_bandgap_readl(bgp, tsr->bgap_counter);
++
++ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
++ ti_bandgap_writel(bgp, rval->tshut_threshold,
++ tsr->tshut_threshold);
++ /* Force immediate temperature measurement and update
++ * of the DTEMP field
++ */
++ ti_bandgap_force_single_read(bgp, i);
++
++ if (TI_BANDGAP_HAS(bgp, COUNTER))
++ ti_bandgap_writel(bgp, rval->bg_counter,
++ tsr->bgap_counter);
++ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
++ ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
++ tsr->bgap_mode_ctrl);
++ if (TI_BANDGAP_HAS(bgp, TALERT)) {
++ ti_bandgap_writel(bgp, rval->bg_threshold,
++ tsr->bgap_threshold);
++ ti_bandgap_writel(bgp, rval->bg_ctrl,
++ tsr->bgap_mask_ctrl);
++ }
++ }
++
++ return 0;
++}
++
++static int ti_bandgap_suspend(struct device *dev)
++{
++ struct ti_bandgap *bgp = dev_get_drvdata(dev);
++ int err;
++
++ err = ti_bandgap_save_ctxt(bgp);
++ ti_bandgap_power(bgp, false);
++
++ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
++ clk_disable_unprepare(bgp->fclock);
++
++ return err;
++}
++
++static int ti_bandgap_resume(struct device *dev)
++{
++ struct ti_bandgap *bgp = dev_get_drvdata(dev);
++
++ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
++ clk_prepare_enable(bgp->fclock);
++
++ ti_bandgap_power(bgp, true);
++
++ return ti_bandgap_restore_ctxt(bgp);
++}
++static const struct dev_pm_ops ti_bandgap_dev_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend,
++ ti_bandgap_resume)
++};
++
++#define DEV_PM_OPS (&ti_bandgap_dev_pm_ops)
++#else
++#define DEV_PM_OPS NULL
++#endif
++
++static const struct of_device_id of_ti_bandgap_match[] = {
++#ifdef CONFIG_OMAP4_THERMAL
++ {
++ .compatible = "ti,omap4430-bandgap",
++ .data = (void *)&omap4430_data,
++ },
++ {
++ .compatible = "ti,omap4460-bandgap",
++ .data = (void *)&omap4460_data,
++ },
++ {
++ .compatible = "ti,omap4470-bandgap",
++ .data = (void *)&omap4470_data,
++ },
++#endif
++#ifdef CONFIG_OMAP5_THERMAL
++ {
++ .compatible = "ti,omap5430-bandgap",
++ .data = (void *)&omap5430_data,
++ },
++#endif
++ /* Sentinel */
++ { },
++};
++MODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
++
++static struct platform_driver ti_bandgap_sensor_driver = {
++ .probe = ti_bandgap_probe,
++ .remove = ti_bandgap_remove,
++ .driver = {
++ .name = "ti-soc-thermal",
++ .pm = DEV_PM_OPS,
++ .of_match_table = of_ti_bandgap_match,
++ },
++};
++
++module_platform_driver(ti_bandgap_sensor_driver);
++
++MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:ti-soc-thermal");
++MODULE_AUTHOR("Texas Instrument Inc.");
+diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
+new file mode 100644
+index 0000000..5f4794a
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
+@@ -0,0 +1,403 @@
++/*
++ * OMAP4 Bandgap temperature sensor driver
++ *
++ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++#ifndef __TI_BANDGAP_H
++#define __TI_BANDGAP_H
++
++#include <linux/spinlock.h>
++#include <linux/types.h>
++#include <linux/err.h>
++
++/**
++ * DOC: bandgap driver data structure
++ * ==================================
++ *
++ * +----------+----------------+
++ * | struct temp_sensor_regval |
++ * +---------------------------+
++ * * (Array of)
++ * |
++ * |
++ * +-------------------+ +-----------------+
++ * | struct ti_bandgap |-->| struct device * |
++ * +----------+--------+ +-----------------+
++ * |
++ * |
++ * V
++ * +------------------------+
++ * | struct ti_bandgap_data |
++ * +------------------------+
++ * |
++ * |
++ * * (Array of)
++ * +------------+------------------------------------------------------+
++ * | +----------+------------+ +-------------------------+ |
++ * | | struct ti_temp_sensor |-->| struct temp_sensor_data | |
++ * | +-----------------------+ +------------+------------+ |
++ * | | |
++ * | + |
++ * | V |
++ * | +----------+-------------------+ |
++ * | | struct temp_sensor_registers | |
++ * | +------------------------------+ |
++ * | |
++ * +-------------------------------------------------------------------+
++ *
++ * Above is a simple diagram describing how the data structure below
++ * are organized. For each bandgap device there should be a ti_bandgap_data
++ * containing the device instance configuration, as well as, an array of
++ * sensors, representing every sensor instance present in this bandgap.
++ */
++
++/**
++ * struct temp_sensor_registers - descriptor to access registers and bitfields
++ * @temp_sensor_ctrl: TEMP_SENSOR_CTRL register offset
++ * @bgap_tempsoff_mask: mask to temp_sensor_ctrl.tempsoff
++ * @bgap_soc_mask: mask to temp_sensor_ctrl.soc
++ * @bgap_eocz_mask: mask to temp_sensor_ctrl.eocz
++ * @bgap_dtemp_mask: mask to temp_sensor_ctrl.dtemp
++ * @bgap_mask_ctrl: BANDGAP_MASK_CTRL register offset
++ * @mask_hot_mask: mask to bandgap_mask_ctrl.mask_hot
++ * @mask_cold_mask: mask to bandgap_mask_ctrl.mask_cold
++ * @mask_sidlemode_mask: mask to bandgap_mask_ctrl.mask_sidlemode
++ * @mask_counter_delay_mask: mask to bandgap_mask_ctrl.mask_counter_delay
++ * @mask_freeze_mask: mask to bandgap_mask_ctrl.mask_free
++ * @mask_clear_mask: mask to bandgap_mask_ctrl.mask_clear
++ * @mask_clear_accum_mask: mask to bandgap_mask_ctrl.mask_clear_accum
++ * @bgap_mode_ctrl: BANDGAP_MODE_CTRL register offset
++ * @mode_ctrl_mask: mask to bandgap_mode_ctrl.mode_ctrl
++ * @bgap_counter: BANDGAP_COUNTER register offset
++ * @counter_mask: mask to bandgap_counter.counter
++ * @bgap_threshold: BANDGAP_THRESHOLD register offset (TALERT thresholds)
++ * @threshold_thot_mask: mask to bandgap_threhold.thot
++ * @threshold_tcold_mask: mask to bandgap_threhold.tcold
++ * @tshut_threshold: TSHUT_THRESHOLD register offset (TSHUT thresholds)
++ * @tshut_efuse_mask: mask to tshut_threshold.tshut_efuse
++ * @tshut_efuse_shift: shift to tshut_threshold.tshut_efuse
++ * @tshut_hot_mask: mask to tshut_threhold.thot
++ * @tshut_cold_mask: mask to tshut_threhold.thot
++ * @bgap_status: BANDGAP_STATUS register offset
++ * @status_clean_stop_mask: mask to bandgap_status.clean_stop
++ * @status_bgap_alert_mask: mask to bandgap_status.bandgap_alert
++ * @status_hot_mask: mask to bandgap_status.hot
++ * @status_cold_mask: mask to bandgap_status.cold
++ * @bgap_cumul_dtemp: BANDGAP_CUMUL_DTEMP register offset
++ * @ctrl_dtemp_0: CTRL_DTEMP0 register offset
++ * @ctrl_dtemp_1: CTRL_DTEMP1 register offset
++ * @ctrl_dtemp_2: CTRL_DTEMP2 register offset
++ * @ctrl_dtemp_3: CTRL_DTEMP3 register offset
++ * @ctrl_dtemp_4: CTRL_DTEMP4 register offset
++ * @bgap_efuse: BANDGAP_EFUSE register offset
++ *
++ * The register offsets and bitfields might change across
++ * OMAP and variants versions. Hence this struct serves as a
++ * descriptor map on how to access the registers and the bitfields.
++ *
++ * This descriptor contains registers of all versions of bandgap chips.
++ * Not all versions will use all registers, depending on the available
++ * features. Please read TRMs for descriptive explanation on each bitfield.
++ */
++
++struct temp_sensor_registers {
++ u32 temp_sensor_ctrl;
++ u32 bgap_tempsoff_mask;
++ u32 bgap_soc_mask;
++ u32 bgap_eocz_mask; /* not used: but needs revisit */
++ u32 bgap_dtemp_mask;
++
++ u32 bgap_mask_ctrl;
++ u32 mask_hot_mask;
++ u32 mask_cold_mask;
++ u32 mask_sidlemode_mask; /* not used: but may be needed for pm */
++ u32 mask_counter_delay_mask;
++ u32 mask_freeze_mask;
++ u32 mask_clear_mask; /* not used: but needed for trending */
++ u32 mask_clear_accum_mask; /* not used: but needed for trending */
++
++ u32 bgap_mode_ctrl;
++ u32 mode_ctrl_mask;
++
++ u32 bgap_counter;
++ u32 counter_mask;
++
++ u32 bgap_threshold;
++ u32 threshold_thot_mask;
++ u32 threshold_tcold_mask;
++
++ u32 tshut_threshold;
++ u32 tshut_efuse_mask; /* not used */
++ u32 tshut_efuse_shift; /* not used */
++ u32 tshut_hot_mask;
++ u32 tshut_cold_mask;
++
++ u32 bgap_status;
++ u32 status_clean_stop_mask; /* not used: but needed for trending */
++ u32 status_bgap_alert_mask; /* not used */
++ u32 status_hot_mask;
++ u32 status_cold_mask;
++
++ u32 bgap_cumul_dtemp; /* not used: but needed for trending */
++ u32 ctrl_dtemp_0; /* not used: but needed for trending */
++ u32 ctrl_dtemp_1; /* not used: but needed for trending */
++ u32 ctrl_dtemp_2; /* not used: but needed for trending */
++ u32 ctrl_dtemp_3; /* not used: but needed for trending */
++ u32 ctrl_dtemp_4; /* not used: but needed for trending */
++ u32 bgap_efuse;
++};
++
++/**
++ * struct temp_sensor_data - The thresholds and limits for temperature sensors.
++ * @tshut_hot: temperature to trigger a thermal reset (initial value)
++ * @tshut_cold: temp to get the plat out of reset due to thermal (init val)
++ * @t_hot: temperature to trigger a thermal alert (high initial value)
++ * @t_cold: temperature to trigger a thermal alert (low initial value)
++ * @min_freq: sensor minimum clock rate
++ * @max_freq: sensor maximum clock rate
++ * @max_temp: sensor maximum temperature
++ * @min_temp: sensor minimum temperature
++ * @hyst_val: temperature hysteresis considered while converting ADC values
++ * @update_int1: update interval
++ * @update_int2: update interval
++ *
++ * This data structure will hold the required thresholds and temperature limits
++ * for a specific temperature sensor, like shutdown temperature, alert
++ * temperature, clock / rate used, ADC conversion limits and update intervals
++ */
++struct temp_sensor_data {
++ u32 tshut_hot;
++ u32 tshut_cold;
++ u32 t_hot;
++ u32 t_cold;
++ u32 min_freq;
++ u32 max_freq;
++ int max_temp;
++ int min_temp;
++ int hyst_val;
++ u32 update_int1; /* not used */
++ u32 update_int2; /* not used */
++};
++
++struct ti_bandgap_data;
++
++/**
++ * struct temp_sensor_regval - temperature sensor register values and priv data
++ * @bg_mode_ctrl: temp sensor control register value
++ * @bg_ctrl: bandgap ctrl register value
++ * @bg_counter: bandgap counter value
++ * @bg_threshold: bandgap threshold register value
++ * @tshut_threshold: bandgap tshut register value
++ * @data: private data
++ *
++ * Data structure to save and restore bandgap register set context. Only
++ * required registers are shadowed, when needed.
++ */
++struct temp_sensor_regval {
++ u32 bg_mode_ctrl;
++ u32 bg_ctrl;
++ u32 bg_counter;
++ u32 bg_threshold;
++ u32 tshut_threshold;
++ void *data;
++};
++
++/**
++ * struct ti_bandgap - bandgap device structure
++ * @dev: struct device pointer
++ * @base: io memory base address
++ * @conf: struct with bandgap configuration set (# sensors, conv_table, etc)
++ * @regval: temperature sensor register values
++ * @fclock: pointer to functional clock of temperature sensor
++ * @div_clk: pointer to divider clock of temperature sensor fclk
++ * @lock: spinlock for ti_bandgap structure
++ * @irq: MPU IRQ number for thermal alert
++ * @tshut_gpio: GPIO where Tshut signal is routed
++ * @clk_rate: Holds current clock rate
++ *
++ * The bandgap device structure representing the bandgap device instance.
++ * It holds most of the dynamic stuff. Configurations and sensor specific
++ * entries are inside the @conf structure.
++ */
++struct ti_bandgap {
++ struct device *dev;
++ void __iomem *base;
++ const struct ti_bandgap_data *conf;
++ struct temp_sensor_regval *regval;
++ struct clk *fclock;
++ struct clk *div_clk;
++ spinlock_t lock; /* shields this struct */
++ int irq;
++ int tshut_gpio;
++ u32 clk_rate;
++};
++
++/**
++ * struct ti_temp_sensor - bandgap temperature sensor configuration data
++ * @ts_data: pointer to struct with thresholds, limits of temperature sensor
++ * @registers: pointer to the list of register offsets and bitfields
++ * @domain: the name of the domain where the sensor is located
++ * @slope: sensor gradient slope info for hotspot extrapolation equation
++ * @constant: sensor gradient const info for hotspot extrapolation equation
++ * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation
++ * with no external influence
++ * @constant_pcb: sensor gradient const info for hotspot extrapolation equation
++ * with no external influence
++ * @register_cooling: function to describe how this sensor is going to be cooled
++ * @unregister_cooling: function to release cooling data
++ *
++ * Data structure to describe a temperature sensor handled by a bandgap device.
++ * It should provide configuration details on this sensor, such as how to
++ * access the registers affecting this sensor, shadow register buffer, how to
++ * assess the gradient from hotspot, how to cooldown the domain when sensor
++ * reports too hot temperature.
++ */
++struct ti_temp_sensor {
++ struct temp_sensor_data *ts_data;
++ struct temp_sensor_registers *registers;
++ char *domain;
++ /* for hotspot extrapolation */
++ const int slope;
++ const int constant;
++ const int slope_pcb;
++ const int constant_pcb;
++ int (*register_cooling)(struct ti_bandgap *bgp, int id);
++ int (*unregister_cooling)(struct ti_bandgap *bgp, int id);
++};
++
++/**
++ * DOC: ti bandgap feature types
++ *
++ * TI_BANDGAP_FEATURE_TSHUT - used when the thermal shutdown signal output
++ * of a bandgap device instance is routed to the processor. This means
++ * the system must react and perform the shutdown by itself (handle an
++ * IRQ, for instance).
++ *
++ * TI_BANDGAP_FEATURE_TSHUT_CONFIG - used when the bandgap device has control
++ * over the thermal shutdown configuration. This means that the thermal
++ * shutdown thresholds are programmable, for instance.
++ *
++ * TI_BANDGAP_FEATURE_TALERT - used when the bandgap device instance outputs
++ * a signal representing violation of programmable alert thresholds.
++ *
++ * TI_BANDGAP_FEATURE_MODE_CONFIG - used when it is possible to choose which
++ * mode, continuous or one shot, the bandgap device instance will operate.
++ *
++ * TI_BANDGAP_FEATURE_COUNTER - used when the bandgap device instance allows
++ * programming the update interval of its internal state machine.
++ *
++ * TI_BANDGAP_FEATURE_POWER_SWITCH - used when the bandgap device allows
++ * itself to be switched on/off.
++ *
++ * TI_BANDGAP_FEATURE_CLK_CTRL - used when the clocks feeding the bandgap
++ * device are gateable or not.
++ *
++ * TI_BANDGAP_FEATURE_FREEZE_BIT - used when the bandgap device features
++ * a history buffer that its update can be freezed/unfreezed.
++ *
++ * TI_BANDGAP_FEATURE_COUNTER_DELAY - used when the bandgap device features
++ * a delay programming based on distinct values.
++ *
++ * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features
++ * a history buffer of temperatures.
++ *
++ * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a
++ * specific feature (above) or not. Return non-zero, if yes.
++ */
++#define TI_BANDGAP_FEATURE_TSHUT BIT(0)
++#define TI_BANDGAP_FEATURE_TSHUT_CONFIG BIT(1)
++#define TI_BANDGAP_FEATURE_TALERT BIT(2)
++#define TI_BANDGAP_FEATURE_MODE_CONFIG BIT(3)
++#define TI_BANDGAP_FEATURE_COUNTER BIT(4)
++#define TI_BANDGAP_FEATURE_POWER_SWITCH BIT(5)
++#define TI_BANDGAP_FEATURE_CLK_CTRL BIT(6)
++#define TI_BANDGAP_FEATURE_FREEZE_BIT BIT(7)
++#define TI_BANDGAP_FEATURE_COUNTER_DELAY BIT(8)
++#define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9)
++#define TI_BANDGAP_HAS(b, f) \
++ ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
++
++/**
++ * struct ti_bandgap_data - ti bandgap data configuration structure
++ * @features: a bitwise flag set to describe the device features
++ * @conv_table: Pointer to ADC to temperature conversion table
++ * @adc_start_val: ADC conversion table starting value
++ * @adc_end_val: ADC conversion table ending value
++ * @fclock_name: clock name of the functional clock
++ * @div_ck_name: clock name of the clock divisor
++ * @sensor_count: count of temperature sensor within this bandgap device
++ * @report_temperature: callback to report thermal alert to thermal API
++ * @expose_sensor: callback to export sensor to thermal API
++ * @remove_sensor: callback to destroy sensor from thermal API
++ * @sensors: array of sensors present in this bandgap instance
++ *
++ * This is a data structure which should hold most of the static configuration
++ * of a bandgap device instance. It should describe which features this instance
++ * is capable of, the clock names to feed this device, the amount of sensors and
++ * their configuration representation, and how to export and unexport them to
++ * a thermal API.
++ */
++struct ti_bandgap_data {
++ unsigned int features;
++ const int *conv_table;
++ u32 adc_start_val;
++ u32 adc_end_val;
++ char *fclock_name;
++ char *div_ck_name;
++ int sensor_count;
++ int (*report_temperature)(struct ti_bandgap *bgp, int id);
++ int (*expose_sensor)(struct ti_bandgap *bgp, int id, char *domain);
++ int (*remove_sensor)(struct ti_bandgap *bgp, int id);
++
++ /* this needs to be at the end */
++ struct ti_temp_sensor sensors[];
++};
++
++int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot);
++int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val);
++int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold);
++int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val);
++int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
++ int *interval);
++int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id,
++ u32 interval);
++int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
++ int *temperature);
++int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data);
++void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id);
++int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend);
++
++#ifdef CONFIG_OMAP4_THERMAL
++extern const struct ti_bandgap_data omap4430_data;
++extern const struct ti_bandgap_data omap4460_data;
++extern const struct ti_bandgap_data omap4470_data;
++#else
++#define omap4430_data NULL
++#define omap4460_data NULL
++#define omap4470_data NULL
++#endif
++
++#ifdef CONFIG_OMAP5_THERMAL
++extern const struct ti_bandgap_data omap5430_data;
++#else
++#define omap5430_data NULL
++#endif
++
++#endif
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+new file mode 100644
+index 0000000..e3c5e67
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -0,0 +1,367 @@
++/*
++ * OMAP thermal driver interface
++ *
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/mutex.h>
++#include <linux/gfp.h>
++#include <linux/kernel.h>
++#include <linux/workqueue.h>
++#include <linux/thermal.h>
++#include <linux/cpufreq.h>
++#include <linux/cpumask.h>
++#include <linux/cpu_cooling.h>
++
++#include "ti-thermal.h"
++#include "ti-bandgap.h"
++
++/* common data structures */
++struct ti_thermal_data {
++ struct thermal_zone_device *ti_thermal;
++ struct thermal_cooling_device *cool_dev;
++ struct ti_bandgap *bgp;
++ enum thermal_device_mode mode;
++ struct work_struct thermal_wq;
++ int sensor_id;
++};
++
++static void ti_thermal_work(struct work_struct *work)
++{
++ struct ti_thermal_data *data = container_of(work,
++ struct ti_thermal_data, thermal_wq);
++
++ thermal_zone_device_update(data->ti_thermal);
++
++ dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
++ data->ti_thermal->type);
++}
++
++/**
++ * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
++ * @t: omap sensor temperature
++ * @s: omap sensor slope value
++ * @c: omap sensor const value
++ */
++static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
++{
++ int delta = t * s / 1000 + c;
++
++ if (delta < 0)
++ delta = 0;
++
++ return t + delta;
++}
++
++/* thermal zone ops */
++/* Get temperature callback function for thermal zone*/
++static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
++ unsigned long *temp)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++ struct ti_bandgap *bgp;
++ const struct ti_temp_sensor *s;
++ int ret, tmp, pcb_temp, slope, constant;
++
++ if (!data)
++ return 0;
++
++ bgp = data->bgp;
++ s = &bgp->conf->sensors[data->sensor_id];
++
++ ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
++ if (ret)
++ return ret;
++
++ pcb_temp = 0;
++ /* TODO: Introduce pcb temperature lookup */
++ /* In case pcb zone is available, use the extrapolation rule with it */
++ if (pcb_temp) {
++ tmp -= pcb_temp;
++ slope = s->slope_pcb;
++ constant = s->constant_pcb;
++ } else {
++ slope = s->slope;
++ constant = s->constant;
++ }
++ *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
++
++ return ret;
++}
++
++/* Bind callback functions for thermal zone */
++static int ti_thermal_bind(struct thermal_zone_device *thermal,
++ struct thermal_cooling_device *cdev)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++ int id;
++
++ if (IS_ERR_OR_NULL(data))
++ return -ENODEV;
++
++ /* check if this is the cooling device we registered */
++ if (data->cool_dev != cdev)
++ return 0;
++
++ id = data->sensor_id;
++
++ /* Simple thing, two trips, one passive another critical */
++ return thermal_zone_bind_cooling_device(thermal, 0, cdev,
++ /* bind with min and max states defined by cpu_cooling */
++ THERMAL_NO_LIMIT,
++ THERMAL_NO_LIMIT);
++}
++
++/* Unbind callback functions for thermal zone */
++static int ti_thermal_unbind(struct thermal_zone_device *thermal,
++ struct thermal_cooling_device *cdev)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++
++ if (IS_ERR_OR_NULL(data))
++ return -ENODEV;
++
++ /* check if this is the cooling device we registered */
++ if (data->cool_dev != cdev)
++ return 0;
++
++ /* Simple thing, two trips, one passive another critical */
++ return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
++}
++
++/* Get mode callback functions for thermal zone */
++static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
++ enum thermal_device_mode *mode)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++
++ if (data)
++ *mode = data->mode;
++
++ return 0;
++}
++
++/* Set mode callback functions for thermal zone */
++static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
++ enum thermal_device_mode mode)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++
++ if (!data->ti_thermal) {
++ dev_notice(&thermal->device, "thermal zone not registered\n");
++ return 0;
++ }
++
++ mutex_lock(&data->ti_thermal->lock);
++
++ if (mode == THERMAL_DEVICE_ENABLED)
++ data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
++ else
++ data->ti_thermal->polling_delay = 0;
++
++ mutex_unlock(&data->ti_thermal->lock);
++
++ data->mode = mode;
++ thermal_zone_device_update(data->ti_thermal);
++ dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
++ data->ti_thermal->polling_delay);
++
++ return 0;
++}
++
++/* Get trip type callback functions for thermal zone */
++static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
++ int trip, enum thermal_trip_type *type)
++{
++ if (!ti_thermal_is_valid_trip(trip))
++ return -EINVAL;
++
++ if (trip + 1 == OMAP_TRIP_NUMBER)
++ *type = THERMAL_TRIP_CRITICAL;
++ else
++ *type = THERMAL_TRIP_PASSIVE;
++
++ return 0;
++}
++
++/* Get trip temperature callback functions for thermal zone */
++static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
++ int trip, unsigned long *temp)
++{
++ if (!ti_thermal_is_valid_trip(trip))
++ return -EINVAL;
++
++ *temp = ti_thermal_get_trip_value(trip);
++
++ return 0;
++}
++
++/* Get the temperature trend callback functions for thermal zone */
++static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
++ int trip, enum thermal_trend *trend)
++{
++ struct ti_thermal_data *data = thermal->devdata;
++ struct ti_bandgap *bgp;
++ int id, tr, ret = 0;
++
++ bgp = data->bgp;
++ id = data->sensor_id;
++
++ ret = ti_bandgap_get_trend(bgp, id, &tr);
++ if (ret)
++ return ret;
++
++ if (tr > 0)
++ *trend = THERMAL_TREND_RAISING;
++ else if (tr < 0)
++ *trend = THERMAL_TREND_DROPPING;
++ else
++ *trend = THERMAL_TREND_STABLE;
++
++ return 0;
++}
++
++/* Get critical temperature callback functions for thermal zone */
++static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
++ unsigned long *temp)
++{
++ /* shutdown zone */
++ return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
++}
++
++static struct thermal_zone_device_ops ti_thermal_ops = {
++ .get_temp = ti_thermal_get_temp,
++ .get_trend = ti_thermal_get_trend,
++ .bind = ti_thermal_bind,
++ .unbind = ti_thermal_unbind,
++ .get_mode = ti_thermal_get_mode,
++ .set_mode = ti_thermal_set_mode,
++ .get_trip_type = ti_thermal_get_trip_type,
++ .get_trip_temp = ti_thermal_get_trip_temp,
++ .get_crit_temp = ti_thermal_get_crit_temp,
++};
++
++static struct ti_thermal_data
++*ti_thermal_build_data(struct ti_bandgap *bgp, int id)
++{
++ struct ti_thermal_data *data;
++
++ data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
++ if (!data) {
++ dev_err(bgp->dev, "kzalloc fail\n");
++ return NULL;
++ }
++ data->sensor_id = id;
++ data->bgp = bgp;
++ data->mode = THERMAL_DEVICE_ENABLED;
++ INIT_WORK(&data->thermal_wq, ti_thermal_work);
++
++ return data;
++}
++
++int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
++ char *domain)
++{
++ struct ti_thermal_data *data;
++
++ data = ti_bandgap_get_sensor_data(bgp, id);
++
++ if (IS_ERR_OR_NULL(data))
++ data = ti_thermal_build_data(bgp, id);
++
++ if (!data)
++ return -EINVAL;
++
++ /* Create thermal zone */
++ data->ti_thermal = thermal_zone_device_register(domain,
++ OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
++ NULL, FAST_TEMP_MONITORING_RATE,
++ FAST_TEMP_MONITORING_RATE);
++ if (IS_ERR_OR_NULL(data->ti_thermal)) {
++ dev_err(bgp->dev, "thermal zone device is NULL\n");
++ return PTR_ERR(data->ti_thermal);
++ }
++ data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
++ ti_bandgap_set_sensor_data(bgp, id, data);
++
++ return 0;
++}
++
++int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
++{
++ struct ti_thermal_data *data;
++
++ data = ti_bandgap_get_sensor_data(bgp, id);
++
++ thermal_zone_device_unregister(data->ti_thermal);
++
++ return 0;
++}
++
++int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
++{
++ struct ti_thermal_data *data;
++
++ data = ti_bandgap_get_sensor_data(bgp, id);
++
++ schedule_work(&data->thermal_wq);
++
++ return 0;
++}
++
++int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
++{
++ struct ti_thermal_data *data;
++
++ data = ti_bandgap_get_sensor_data(bgp, id);
++ if (IS_ERR_OR_NULL(data))
++ data = ti_thermal_build_data(bgp, id);
++
++ if (!data)
++ return -EINVAL;
++
++ if (!cpufreq_get_current_driver()) {
++ dev_dbg(bgp->dev, "no cpufreq driver yet\n");
++ return -EPROBE_DEFER;
++ }
++
++ /* Register cooling device */
++ data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
++ if (IS_ERR_OR_NULL(data->cool_dev)) {
++ dev_err(bgp->dev,
++ "Failed to register cpufreq cooling device\n");
++ return PTR_ERR(data->cool_dev);
++ }
++ ti_bandgap_set_sensor_data(bgp, id, data);
++
++ return 0;
++}
++
++int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
++{
++ struct ti_thermal_data *data;
++
++ data = ti_bandgap_get_sensor_data(bgp, id);
++ cpufreq_cooling_unregister(data->cool_dev);
++
++ return 0;
++}
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h
+new file mode 100644
+index 0000000..5055777
+--- /dev/null
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal.h
+@@ -0,0 +1,117 @@
++/*
++ * OMAP thermal definitions
++ *
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ * Contact:
++ * Eduardo Valentin <eduardo.valentin@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++#ifndef __TI_THERMAL_H
++#define __TI_THERMAL_H
++
++#include "ti-bandgap.h"
++
++/* sensors gradient and offsets */
++#define OMAP_GRADIENT_SLOPE_4430 0
++#define OMAP_GRADIENT_CONST_4430 20000
++#define OMAP_GRADIENT_SLOPE_4460 348
++#define OMAP_GRADIENT_CONST_4460 -9301
++#define OMAP_GRADIENT_SLOPE_4470 308
++#define OMAP_GRADIENT_CONST_4470 -7896
++
++#define OMAP_GRADIENT_SLOPE_5430_CPU 65
++#define OMAP_GRADIENT_CONST_5430_CPU -1791
++#define OMAP_GRADIENT_SLOPE_5430_GPU 117
++#define OMAP_GRADIENT_CONST_5430_GPU -2992
++
++/* PCB sensor calculation constants */
++#define OMAP_GRADIENT_SLOPE_W_PCB_4430 0
++#define OMAP_GRADIENT_CONST_W_PCB_4430 20000
++#define OMAP_GRADIENT_SLOPE_W_PCB_4460 1142
++#define OMAP_GRADIENT_CONST_W_PCB_4460 -393
++#define OMAP_GRADIENT_SLOPE_W_PCB_4470 1063
++#define OMAP_GRADIENT_CONST_W_PCB_4470 -477
++
++#define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU 100
++#define OMAP_GRADIENT_CONST_W_PCB_5430_CPU 484
++#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 464
++#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU -5102
++
++/* trip points of interest in milicelsius (at hotspot level) */
++#define OMAP_TRIP_COLD 100000
++#define OMAP_TRIP_HOT 110000
++#define OMAP_TRIP_SHUTDOWN 125000
++#define OMAP_TRIP_NUMBER 2
++#define OMAP_TRIP_STEP \
++ ((OMAP_TRIP_SHUTDOWN - OMAP_TRIP_HOT) / (OMAP_TRIP_NUMBER - 1))
++
++/* Update rates */
++#define FAST_TEMP_MONITORING_RATE 250
++
++/* helper macros */
++/**
++ * ti_thermal_get_trip_value - returns trip temperature based on index
++ * @i: trip index
++ */
++#define ti_thermal_get_trip_value(i) \
++ (OMAP_TRIP_HOT + ((i) * OMAP_TRIP_STEP))
++
++/**
++ * ti_thermal_is_valid_trip - check for trip index
++ * @i: trip index
++ */
++#define ti_thermal_is_valid_trip(trip) \
++ ((trip) >= 0 && (trip) < OMAP_TRIP_NUMBER)
++
++#ifdef CONFIG_TI_THERMAL
++int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain);
++int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id);
++int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id);
++int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id);
++int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id);
++#else
++static inline
++int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain)
++{
++ return 0;
++}
++
++static inline
++int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
++{
++ return 0;
++}
++
++static inline
++int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
++{
++ return 0;
++}
++
++static inline
++int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
++{
++ return 0;
++}
++
++static inline
++int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
++{
++ return 0;
++}
++#endif
++#endif
+--
+1.8.3.2
+