* [PATCH 0/6 V4] OMAP4: Temperature sensor driver
@ 2011-08-31 17:25 Keerthy
2011-08-31 17:25 ` [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor Keerthy
` (5 more replies)
0 siblings, 6 replies; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy
The patch series for the on die temperature sensor driver.
The patch set has the device file, omap4 on die temperature sensor
hwmon driver. hwmod, clk support. The patch set compiles
on top of LO tree Master branch.
This patch series is tested for boot-up on OMAP4460. The temperature
reading and the interrupts generation on crossing the temperature
thresholds also tested.
V4:
(1) Reordered the probe sequence in the driver.
(2) Introduced iounmap in the driver in the error paths and remove function.
(3) In case of user/application programming thresholds violating t_hot > t_cold
condition, the driver automatically changes the other threshold to adhere
to the condition.
V3:
(1) Fixed comments on the return values in the device file
(2) Removed unnecessary error messages.
(3) Redundant braces removed.
(4) Implemented binary search in place of linear for temp to adc conversion.
(5) Wrong usage of EINVAL corrected.
V2:
(1) Fixed comments on return values in the driver.
(2) Moved the TEMPSOFF setting code to the activate/deactivate hooks.
(3) Used idr to pass for the device id.
Benoit Cousson (1):
OMAP4: Hwmod: OMAP temperature sensor
Keerthy (5):
OMAP4: Clock: Associate clocks for OMAP temperature sensor
OMAP4: Adding the temperature sensor register set bit fields
OMAP4460: Temperature sensor data
OMAP4: Temperature sensor device support
hwmon: OMAP4: On die temperature sensor driver
Documentation/hwmon/omap_temp_sensor | 26 +
arch/arm/mach-omap2/Makefile | 3 +-
arch/arm/mach-omap2/clock44xx_data.c | 2 +-
.../include/mach/ctrl_module_core_44xx.h | 70 ++-
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 61 ++
arch/arm/mach-omap2/temp_sensor4460_data.c | 63 ++
arch/arm/mach-omap2/temp_sensor_device.c | 188 +++++
arch/arm/plat-omap/Kconfig | 12 +
.../plat-omap/include/plat/temperature_sensor.h | 93 ++
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/omap_temp_sensor.c | 881 ++++++++++++++++++++
12 files changed, 1396 insertions(+), 15 deletions(-)
create mode 100644 Documentation/hwmon/omap_temp_sensor
create mode 100644 arch/arm/mach-omap2/temp_sensor4460_data.c
create mode 100644 arch/arm/mach-omap2/temp_sensor_device.c
create mode 100644 arch/arm/plat-omap/include/plat/temperature_sensor.h
create mode 100644 drivers/hwmon/omap_temp_sensor.c
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
@ 2011-08-31 17:25 ` Keerthy
2011-09-01 0:00 ` Paul Walmsley
2011-08-31 17:25 ` [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields Keerthy
` (4 subsequent siblings)
5 siblings, 1 reply; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, tony, rnayak
div_ts_ck feeds only the temperature sensor functional clock
and also has a clksel associated (for divider selection). Mapping this
as the functional clock for the temperature sensor in clkdev table,
so a clk_set_rate() in the driver would have the effect of changing the
temperature sensor clock rate indirectly.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Reviewed-by: Rajendra Nayak <rnayak@ti.com>
Cc: tony@atomide.com
Cc: rnayak@ti.com
---
arch/arm/mach-omap2/clock44xx_data.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 2af0e3f..4a788f4 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3187,7 +3187,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X),
CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X),
CLK(NULL, "des3des_fck", &des3des_fck, CK_443X),
- CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X),
+ CLK("omap_temp_sensor.0", "fck", &div_ts_ck, CK_446X),
CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X),
CLK(NULL, "dmic_fck", &dmic_fck, CK_443X),
CLK(NULL, "dsp_fck", &dsp_fck, CK_443X),
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
2011-08-31 17:25 ` [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor Keerthy
@ 2011-08-31 17:25 ` Keerthy
2011-09-01 0:04 ` Paul Walmsley
2011-08-31 17:25 ` [PATCH 3/6 V4] OMAP4460: Temperature sensor data Keerthy
` (3 subsequent siblings)
5 siblings, 1 reply; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, tony
OMAP4460 specific temperature sensor register bit fields are added.
Existing OMAP4 entries are renamed to OMAP4430.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: tony@atomide.com
---
.../include/mach/ctrl_module_core_44xx.h | 70 ++++++++++++++++----
1 files changed, 57 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
index 2f7ac70..725c1e1 100644
--- a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
@@ -256,19 +256,63 @@
#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT 0
#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK (0x1f << 0)
-/* TEMP_SENSOR */
-#define OMAP4_BGAP_TEMPSOFF_SHIFT 12
-#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 12)
-#define OMAP4_BGAP_TSHUT_SHIFT 11
-#define OMAP4_BGAP_TSHUT_MASK (1 << 11)
-#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
-#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
-#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 9
-#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
-#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
-#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
-#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
-#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
+/* TEMP_SENSOR OMAP4430 */
+#define OMAP4430_BGAP_TEMPSOFF_SHIFT 12
+#define OMAP4430_BGAP_TEMPSOFF_MASK (1 << 12)
+#define OMAP4430_BGAP_TSHUT_SHIFT 11
+#define OMAP4430_BGAP_TSHUT_MASK (1 << 11)
+#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
+#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
+#define OMAP4430_BGAP_TEMP_SENSOR_SOC_SHIFT 9
+#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
+#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
+#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
+#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
+#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* TEMP_SENSOR OMAP4460 */
+#define OMAP4460_BGAP_TEMPSOFF_SHIFT 13
+#define OMAP4460_BGAP_TEMPSOFF_MASK (1 << 13)
+#define OMAP4460_BGAP_TEMP_SENSOR_SOC_SHIFT 11
+#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11)
+#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
+#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
+#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
+#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* BANDGAP_CTRL */
+#define OMAP4460_SINGLE_MODE_SHIFT 31
+#define OMAP4460_SINGLE_MODE_MASK (1 << 31)
+#define OMAP4460_MASK_HOT_SHIFT 1
+#define OMAP4460_MASK_HOT_MASK (1 << 1)
+#define OMAP4460_MASK_COLD_SHIFT 0
+#define OMAP4460_MASK_COLD_MASK (1 << 0)
+
+/* BANDGAP_COUNTER */
+#define OMAP4460_COUNTER_SHIFT 0
+#define OMAP4460_COUNTER_MASK (0xffffff << 0)
+
+/* BANDGAP_THRESHOLD */
+#define OMAP4460_T_HOT_SHIFT 16
+#define OMAP4460_T_HOT_MASK (0x3ff << 16)
+#define OMAP4460_T_COLD_SHIFT 0
+#define OMAP4460_T_COLD_MASK (0x3ff << 0)
+
+/* TSHUT_THRESHOLD */
+#define OMAP4460_TSHUT_HOT_SHIFT 16
+#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
+#define OMAP4460_TSHUT_COLD_SHIFT 0
+#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
+
+/* BANDGAP_STATUS */
+#define OMAP4460_CLEAN_STOP_SHIFT 3
+#define OMAP4460_CLEAN_STOP_MASK (1 << 3)
+#define OMAP4460_BGAP_ALERT_SHIFT 2
+#define OMAP4460_BGAP_ALERT_MASK (1 << 2)
+#define OMAP4460_HOT_FLAG_SHIFT 1
+#define OMAP4460_HOT_FLAG_MASK (1 << 1)
+#define OMAP4460_COLD_FLAG_SHIFT 0
+#define OMAP4460_COLD_FLAG_MASK (1 << 0)
/* DPLL_NWELL_TRIM_0 */
#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT 29
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH 3/6 V4] OMAP4460: Temperature sensor data
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
2011-08-31 17:25 ` [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor Keerthy
2011-08-31 17:25 ` [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields Keerthy
@ 2011-08-31 17:25 ` Keerthy
2011-08-31 17:25 ` [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor Keerthy
` (2 subsequent siblings)
5 siblings, 0 replies; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, tony
The register set and the
bit fields might vary across OMAP versions. Hence
creating a structure comprising of all the registers
and bit fields to make the driver uniform for all the
versions with different register sets. The data file
contains the structure populated with register offsets
and bit fields corresponding to OMAP4460 on die sensor.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: tony@atomide.com
---
arch/arm/mach-omap2/Makefile | 2 +-
arch/arm/mach-omap2/temp_sensor4460_data.c | 63 +++++++++++++
.../plat-omap/include/plat/temperature_sensor.h | 93 ++++++++++++++++++++
3 files changed, 157 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/mach-omap2/temp_sensor4460_data.c
create mode 100644 arch/arm/plat-omap/include/plat/temperature_sensor.h
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index fb02937..2d5d981 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -86,7 +86,7 @@ obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \
cm44xx.o prcm_mpu44xx.o \
prminst44xx.o vc44xx_data.o \
- vp44xx_data.o
+ vp44xx_data.o temp_sensor4460_data.o
# OMAP voltage domains
ifeq ($(CONFIG_PM),y)
diff --git a/arch/arm/mach-omap2/temp_sensor4460_data.c b/arch/arm/mach-omap2/temp_sensor4460_data.c
new file mode 100644
index 0000000..294963d
--- /dev/null
+++ b/arch/arm/mach-omap2/temp_sensor4460_data.c
@@ -0,0 +1,63 @@
+/*
+ * OMAP4460 on die Temperature sensor data file
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@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/slab.h>
+#include "control.h"
+#include <plat/temperature_sensor.h>
+
+/*
+ * OMAP4460 has one instance of thermal sensor for MPU
+ * need to describe the individual bit fields
+ */
+struct omap_temp_sensor_registers omap_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,
+
+ .thsut_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,
+};
diff --git a/arch/arm/plat-omap/include/plat/temperature_sensor.h b/arch/arm/plat-omap/include/plat/temperature_sensor.h
new file mode 100644
index 0000000..9302ea8
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/temperature_sensor.h
@@ -0,0 +1,93 @@
+/*
+ * OMAP Temperature sensor header file
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@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 __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_TEMPERATURE_SENSOR_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_TEMPERATURE_SENSOR_H
+
+/* Offsets from the base of temperature sensor registers */
+
+#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET 0x00
+#define OMAP4460_BGAP_CTRL_OFFSET 0x4c
+#define OMAP4460_BGAP_COUNTER_OFFSET 0x50
+#define OMAP4460_BGAP_THRESHOLD_OFFSET 0x54
+#define OMAP4460_BGAP_TSHUT_OFFSET 0x58
+#define OMAP4460_BGAP_STATUS_OFFSET 0x5c
+#define OMAP4460_FUSE_OPP_BGAP -0xcc
+
+/*
+ * The register offsets and but fields might change across
+ * OMAP versions hence populating them in this structure.
+ */
+struct omap_temp_sensor_registers {
+ u32 temp_sensor_ctrl;
+ u32 bgap_tempsoff_mask;
+ u32 bgap_soc_mask;
+ u32 bgap_eocz_mask;
+ u32 bgap_dtemp_mask;
+
+ u32 bgap_mask_ctrl;
+ u32 mask_hot_mask;
+ u32 mask_cold_mask;
+
+ 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 thsut_threshold;
+ u32 tshut_hot_mask;
+ u32 tshut_cold_mask;
+
+ u32 bgap_status;
+ u32 status_clean_stop_mask;
+ u32 status_bgap_alert_mask;
+ u32 status_hot_mask;
+ u32 status_cold_mask;
+
+ u32 bgap_efuse;
+};
+
+/* @name: Name of the domain of the temperature sensor */
+struct omap_temp_sensor_dev_attr {
+ const char *name;
+};
+
+extern struct omap_temp_sensor_registers omap_mpu_temp_sensor_registers;
+
+/*
+ * omap_temp_sensor platform data
+ * @registers - pointer to register set and thier bit fields information
+ * @min_freq - The minimum frequency for temp sensor to be operational
+ * @max_freq - The maximum frequency at which temp sensor is operational
+ */
+struct omap_temp_sensor_pdata {
+ struct omap_temp_sensor_registers *registers;
+ u32 min_freq;
+ u32 max_freq;
+};
+
+#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
` (2 preceding siblings ...)
2011-08-31 17:25 ` [PATCH 3/6 V4] OMAP4460: Temperature sensor data Keerthy
@ 2011-08-31 17:25 ` Keerthy
2011-08-31 23:16 ` Paul Walmsley
2011-08-31 17:25 ` [PATCH 5/6 V4] OMAP4: Temperature sensor device support Keerthy
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
5 siblings, 1 reply; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Benoit Cousson, Keerthy, tony
From: Benoit Cousson <b-cousson@ti.com>
OMAP4460 temperature sensor hwmod cannot be auto generated
since it is part of ctrl module. Hence populating the
necessary hwmod info manually.
Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: tony@atomide.com
Cc: b-cousson@ti.com
---
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 61 ++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6201422..28bf6d3 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -29,6 +29,7 @@
#include <plat/mcbsp.h>
#include <plat/mmc.h>
#include <plat/i2c.h>
+#include <plat/temperature_sensor.h>
#include "omap_hwmod_common_data.h"
@@ -832,6 +833,63 @@ static struct omap_hwmod omap44xx_aess_hwmod = {
};
/*
+ * 'temperature_sensor' class
+ * temperature sensor module inside the bandgap / control module
+ */
+
+static struct omap_hwmod_class omap44xx_temperature_sensor_hwmod_class = {
+ .name = "temperature_sensor",
+};
+
+static struct omap_hwmod_irq_info omap44xx_temperature_sensor_irqs[] = {
+ { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_temperature_sensor_addrs[] = {
+ {
+ .pa_start = 0x4a00232c,
+ .pa_end = 0x4a00238b,
+ },
+};
+
+static struct omap_hwmod omap44xx_temperature_sensor_hwmod;
+/* l4_cfg -> ctrl_module_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__temperature_sensor = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_temperature_sensor_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_temperature_sensor_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* ctrl_module_core slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_temperature_sensor_slaves[] = {
+ &omap44xx_l4_cfg__temperature_sensor,
+};
+
+/* temperature sensor dev_attr */
+static struct omap_temp_sensor_dev_attr temp_sensor_dev_attr = {
+ .name = "mpu",
+};
+
+static struct omap_hwmod omap44xx_temperature_sensor_hwmod = {
+ .name = "temperature_sensor_mpu",
+ .class = &omap44xx_temperature_sensor_hwmod_class,
+ .mpu_irqs = omap44xx_temperature_sensor_irqs,
+ .main_clk = "bandgap_ts_fclk",
+ .slaves = omap44xx_temperature_sensor_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_temperature_sensor_slaves),
+ .clkdm_name = "l4_wkup_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
+ },
+ },
+ .dev_attr = &temp_sensor_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'bandgap' class
* bangap reference for ldo regulators
*/
@@ -5469,6 +5527,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_timer10_hwmod,
&omap44xx_timer11_hwmod,
+ /* temperature sensor hwmod */
+ &omap44xx_temperature_sensor_hwmod,
+
/* uart class */
&omap44xx_uart1_hwmod,
&omap44xx_uart2_hwmod,
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH 5/6 V4] OMAP4: Temperature sensor device support
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
` (3 preceding siblings ...)
2011-08-31 17:25 ` [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor Keerthy
@ 2011-08-31 17:25 ` Keerthy
2011-09-09 9:28 ` Jean Pihet
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
5 siblings, 1 reply; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, tony
The device file adds the device support for OMAP4
on die temperature sensor.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: tony@atomide.com
---
arch/arm/mach-omap2/Makefile | 1 +
arch/arm/mach-omap2/temp_sensor_device.c | 188 ++++++++++++++++++++++++++++++
arch/arm/plat-omap/Kconfig | 12 ++
3 files changed, 201 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-omap2/temp_sensor_device.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 2d5d981..5812fb4 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+obj-$(CONFIG_OMAP_TEMP_SENSOR) += temp_sensor_device.o
obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
# SMP support ONLY available for OMAP4
diff --git a/arch/arm/mach-omap2/temp_sensor_device.c b/arch/arm/mach-omap2/temp_sensor_device.c
new file mode 100644
index 0000000..12d6789
--- /dev/null
+++ b/arch/arm/mach-omap2/temp_sensor_device.c
@@ -0,0 +1,188 @@
+/*
+ * OMAP on die Temperature sensor device file
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@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/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
+#include <plat/omap_device.h>
+#include "pm.h"
+#include <plat/temperature_sensor.h>
+
+
+int omap_temp_sensor_device_idle(struct omap_device *od)
+{
+ struct omap_temp_sensor_registers *registers;
+ struct resource *mem;
+ void __iomem *phy_base;
+ unsigned long timeout;
+ u32 ret = 0, temp;
+
+ mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&od->pdev.dev, "no mem resource\n");
+ ret = -EINVAL;
+ goto plat_res_err;
+ }
+
+ phy_base = ioremap(mem->start, resource_size(mem));
+
+ if (!phy_base) {
+ dev_err(&od->pdev.dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ if (!strcmp(od->hwmods[0]->dev_attr, "mpu"))
+ registers = &omap_mpu_temp_sensor_registers;
+
+ temp = __raw_readl(phy_base + registers->temp_sensor_ctrl);
+ temp |= registers->bgap_tempsoff_mask;
+
+ /* BGAP_TEMPSOFF should be set to 1 before gating clock */
+ __raw_writel(temp, phy_base + registers->temp_sensor_ctrl);
+ temp = __raw_readl(phy_base + registers->bgap_status);
+ timeout = jiffies + msecs_to_jiffies(5);
+
+ /* wait till the clean stop bit is set or till the timeout expires */
+ while (!(temp | registers->status_clean_stop_mask) &&
+ !(time_after(jiffies, timeout))) {
+ temp = __raw_readl(phy_base + registers->bgap_status);
+ usleep_range(500, 2000);
+ }
+
+ if (time_after(jiffies, timeout))
+ dev_err(&od->pdev.dev, "Clean stop bit not set\n");
+
+ ret = omap_device_idle_hwmods(od);
+ iounmap(phy_base);
+plat_res_err:
+ return ret;
+}
+
+int omap_temp_sensor_device_activate(struct omap_device *od)
+{
+ struct omap_temp_sensor_registers *registers;
+ struct resource *mem;
+ void __iomem *phy_base;
+ u32 ret = 0, temp;
+
+ ret = omap_device_enable_hwmods(od);
+ if (ret < 0)
+ return ret;
+ mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&od->pdev.dev, "no mem resource\n");
+ return -EINVAL;
+ }
+
+ phy_base = ioremap(mem->start, resource_size(mem));
+ if (!phy_base) {
+ dev_err(&od->pdev.dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ if (!strcmp(od->hwmods[0]->dev_attr, "mpu"))
+ registers = &omap_mpu_temp_sensor_registers;
+
+ temp = __raw_readl(phy_base + registers->temp_sensor_ctrl);
+ temp &= ~(registers->bgap_tempsoff_mask);
+ /* BGAP_TEMPSOFF should be reset to 0 */
+ __raw_writel(temp,
+ phy_base + registers->temp_sensor_ctrl);
+ iounmap(phy_base);
+
+plat_res_err:
+ return ret;
+}
+
+static struct omap_device_pm_latency omap_temp_sensor_latency[] = {
+ {
+ .deactivate_func = omap_temp_sensor_device_idle,
+ .activate_func = omap_temp_sensor_device_activate,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ }
+};
+
+static DEFINE_IDR(temp_sensor_device_idr);
+
+static int temp_sensor_dev_init(struct omap_hwmod *oh, void *user)
+{
+ struct omap_temp_sensor_pdata *temp_sensor_pdata;
+ struct omap_device *od;
+ struct omap_temp_sensor_dev_attr *temp_sensor_dev_attr;
+ int ret = 0;
+ int num;
+
+ temp_sensor_pdata =
+ kzalloc(sizeof(*temp_sensor_pdata), GFP_KERNEL);
+ if (!temp_sensor_pdata) {
+ dev_err(&oh->od->pdev.dev,
+ "Unable to allocate memory for temp sensor pdata\n");
+ return -ENOMEM;
+ }
+
+ ret = idr_pre_get(&temp_sensor_device_idr, GFP_KERNEL);
+ if (ret < 0)
+ goto fail_id;
+ ret = idr_get_new(&temp_sensor_device_idr, temp_sensor_pdata, &num);
+ if (ret < 0)
+ goto fail_id;
+
+ temp_sensor_dev_attr = oh->dev_attr;
+ if (!strcmp(temp_sensor_dev_attr->name, "mpu")) {
+ temp_sensor_pdata->registers = &omap_mpu_temp_sensor_registers;
+ } else {
+ dev_warn(&oh->od->pdev.dev, "Invalid device attribute\n");
+ ret = -EINVAL;
+ goto fail_id;
+ }
+
+ od = omap_device_build("omap_temp_sensor", num,
+ oh, temp_sensor_pdata, sizeof(*temp_sensor_pdata),
+ omap_temp_sensor_latency,
+ ARRAY_SIZE(omap_temp_sensor_latency), 0);
+
+ if (IS_ERR(od)) {
+ dev_warn(&oh->od->pdev.dev,
+ "Could not build omap_device for %s\n", oh->name);
+ ret = PTR_ERR(od);
+ }
+
+fail_id:
+ kfree(temp_sensor_pdata);
+
+ return ret;
+}
+
+int __init omap_devinit_temp_sensor(void)
+{
+ if (!cpu_is_omap446x())
+ return 0;
+
+ return omap_hwmod_for_each_by_class("temperature_sensor",
+ temp_sensor_dev_init, NULL);
+}
+
+arch_initcall(omap_devinit_temp_sensor);
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 6e6735f..8fd8e80 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -115,6 +115,18 @@ config OMAP_MCBSP
Say Y here if you want support for the OMAP Multichannel
Buffered Serial Port.
+config OMAP_TEMP_SENSOR
+ bool "OMAP Temp Sensor Support"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y here if you want support for the temp sensor
+ on OMAP4460.
+
+ This provides the temperature of the MPU
+ subsystem. Only one instance of on die temperature
+ sensor is present.
+
config OMAP_MBOX_FWK
tristate "Mailbox framework support"
depends on ARCH_OMAP
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
@ 2011-08-31 17:37 ` Keerthy
2011-08-31 17:25 ` [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields Keerthy
` (4 subsequent siblings)
5 siblings, 0 replies; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:25 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, Jean Delvare, Guenter Roeck, lm-sensors
On chip temperature sensor driver. The driver monitors the temperature of
the MPU subsystem of the OMAP4. It sends notifications to the user space if
the temperature crosses user defined thresholds via kobject_uevent interface.
The user is allowed to configure the temperature thresholds vis sysfs nodes
exposed using hwmon interface.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: lm-sensors@lm-sensors.org
---
Documentation/hwmon/omap_temp_sensor | 26 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/omap_temp_sensor.c | 881 ++++++++++++++++++++++++++++++++++
4 files changed, 919 insertions(+), 0 deletions(-)
create mode 100644 Documentation/hwmon/omap_temp_sensor
create mode 100644 drivers/hwmon/omap_temp_sensor.c
diff --git a/Documentation/hwmon/omap_temp_sensor b/Documentation/hwmon/omap_temp_sensor
new file mode 100644
index 0000000..357f09a
--- /dev/null
+++ b/Documentation/hwmon/omap_temp_sensor
@@ -0,0 +1,26 @@
+Kernel driver omap_temp_sensor
+==============================
+
+Supported chips:
+ * Texas Instruments OMAP4460
+ Prefix: 'omap_temp_sensor'
+
+Author:
+ J Keerthy <j-keerthy@ti.com>
+
+Description
+-----------
+
+The Texas Instruments OMAP4 family of chips have a bandgap temperature sensor.
+The temperature sensor feature is used to convert the temperature of the device
+into a decimal value coded on 10 bits. An internal ADC is used for conversion.
+The recommended operating temperatures must be in the range -40 degree Celsius
+to 123 degree celsius for standard conversion.
+The thresholds are programmable and upon crossing the thresholds an interrupt
+is generated. The OMAP temperature sensor has a programmable update rate in
+milli seconds.
+(Currently the driver programs a default of 2000 milliseconds).
+
+The driver provides the common sysfs-interface for temperatures (see
+Documentation/hwmon/sysfs-interface under Temperatures).
+
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5f888f7..9c9cd8b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -323,6 +323,17 @@ config SENSORS_F71805F
This driver can also be built as a module. If so, the module
will be called f71805f.
+config SENSORS_OMAP_BANDGAP_TEMP_SENSOR
+ bool "OMAP on-die temperature sensor hwmon driver"
+ depends on HWMON && ARCH_OMAP && OMAP_TEMP_SENSOR
+ help
+ If you say yes here you get support for hardware
+ monitoring features of the OMAP on die temperature
+ sensor.
+
+ Continuous conversion programmable delay
+ mode is used for temperature conversion.
+
config SENSORS_F71882FG
tristate "Fintek F71882FG and compatibles"
help
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 28061cf..d0f89f5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_OMAP_BANDGAP_TEMP_SENSOR) += omap_temp_sensor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
new file mode 100644
index 0000000..67fa424
--- /dev/null
+++ b/drivers/hwmon/omap_temp_sensor.c
@@ -0,0 +1,881 @@
+/*
+ * OMAP4 Temperature sensor driver file
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@ti.com>
+ * Author: Moiz Sonasath <m-sonasath@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/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <plat/omap_device.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/stddef.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <plat/temperature_sensor.h>
+
+#define TSHUT_HOT 920 /* 122 deg C */
+#define TSHUT_COLD 866 /* 100 deg C */
+#define T_HOT 800 /* 73 deg C */
+#define T_COLD 795 /* 71 deg C */
+#define OMAP_ADC_START_VALUE 530
+#define OMAP_ADC_END_VALUE 923
+#define MAX_FREQ 2000000
+#define MIN_FREQ 1000000
+#define MIN_TEMP -40000
+#define MAX_TEMP 123000
+#define HYST_VAL 5000
+#define NEG_HYST_VAL -5000
+/*
+ * omap_temp_sensor structure
+ * @hwmon_dev - hwmon device pointer
+ * @pdev_dev - platform device pointer
+ * @clock - Clock pointer
+ * @registers - Pointer to structure with register offsets and bitfields
+ * @sensor_mutex - Mutex for sysfs, irq and PM
+ * @irq - MPU Irq number for thermal alert
+ * @phy_base - Physical base of the temp I/O
+ * @clk_rate - Holds current clock rate
+ * @temp_sensor_ctrl - temp sensor control register value
+ * @bg_ctrl - bandgap ctrl register value
+ * @bg_counter - bandgap counter value
+ * @bg_threshold - bandgap threshold register value
+ * @temp_sensor_tshut_threshold - bandgap tshut register value
+ * @clk_on - Manages the current clock state
+ */
+struct omap_temp_sensor {
+ struct device *hwmon_dev;
+ struct device *pdev_dev;
+ struct clk *clock;
+ struct omap_temp_sensor_registers *registers;
+ struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
+ unsigned int irq;
+ void __iomem *phy_base;
+ u32 clk_rate;
+ u32 temp_sensor_ctrl;
+ u32 bg_ctrl;
+ u32 bg_counter;
+ u32 bg_threshold;
+ u32 temp_sensor_tshut_threshold;
+ bool clk_on;
+};
+
+/*
+ * Temperature values in milli degree celsius
+ * ADC code values from 530 to 923
+ */
+static int adc_to_temp[394] = {
+ -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
+};
+
+static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
+ *temp_sensor, u32 reg)
+{
+ return __raw_readl(temp_sensor->phy_base + reg);
+}
+
+static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
+ u32 val, u32 reg)
+{
+ __raw_writel(val, temp_sensor->phy_base + reg);
+}
+
+static int adc_to_temp_conversion(int adc_val)
+{
+ return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
+}
+
+static int temp_to_adc_conversion(long temp)
+{
+ int high, low, mid;
+
+ if (temp < adc_to_temp[0] ||
+ temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
+ return -EINVAL;
+
+ high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
+ low = 0;
+ mid = (high + low) / 2;
+
+ while (low < high) {
+ if (temp < adc_to_temp[mid])
+ high = mid - 1;
+ else
+ low = mid + 1;
+ mid = (low + high) / 2;
+ }
+
+ return OMAP_ADC_START_VALUE + low;
+}
+
+static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
+ *temp_sensor, u32 counter)
+{
+ u32 val;
+
+ val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ val &= ~temp_sensor->registers->counter_mask;
+ val |= counter << __ffs(temp_sensor->registers->counter_mask);
+ omap_temp_sensor_writel(temp_sensor, val,
+ temp_sensor->registers->bgap_counter);
+}
+
+static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
+{
+ u32 val;
+
+ val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mode_ctrl);
+
+ val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
+
+ omap_temp_sensor_writel(temp_sensor, val,
+ temp_sensor->registers->bgap_mode_ctrl);
+}
+
+static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
+ *temp_sensor, u8 hot, u8 cold)
+{
+ u32 reg_val;
+
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mask_ctrl);
+ if (hot)
+ reg_val |= temp_sensor->registers->mask_hot_mask;
+ else
+ reg_val &= ~temp_sensor->registers->mask_hot_mask;
+
+ if (cold)
+ reg_val |= temp_sensor->registers->mask_cold_mask;
+ else
+ reg_val &= ~temp_sensor->registers->mask_cold_mask;
+
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_mask_ctrl);
+}
+
+static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
+{
+ int temp = adc_to_temp_conversion(adc_val);
+
+ temp += hyst_val;
+
+ *thresh_val = temp_to_adc_conversion(temp);
+}
+
+static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
+ *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
+{
+ int reg_val, cold, hot, temp;
+
+ if (set_hot) {
+ /* obtain the T cold value */
+ cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ cold = (cold & temp_sensor->registers->threshold_tcold_mask)
+ >> __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ if (t_hot < cold) {
+ /* change the t_cold to t_hot - 5000 millidegrees */
+ add_hyst(t_hot, NEG_HYST_VAL, &cold);
+ /* write the new t_cold value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &=
+ ~temp_sensor->registers->threshold_tcold_mask;
+ reg_val |= cold <<
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ t_cold = cold;
+ }
+
+ /* write the new t_hot value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &= ~temp_sensor->registers->threshold_thot_mask;
+ reg_val |= (t_hot <<
+ __ffs(temp_sensor->registers->threshold_thot_mask));
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ }
+
+ if (set_cold) {
+ /* obtain the T HOT value */
+ hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
+ __ffs(temp_sensor->registers->threshold_thot_mask);
+ if (t_cold > hot) {
+ /* change the t_hot to t_cold + 5000 millidegrees */
+ add_hyst(t_cold, HYST_VAL, &hot);
+ /* write the new t_hot value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &=
+ ~temp_sensor->registers->threshold_thot_mask;
+ reg_val |= (hot <<
+ __ffs(temp_sensor->registers->threshold_thot_mask));
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ t_hot = hot;
+ }
+
+ /* write the new t_cold value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
+ reg_val |= t_cold <<
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ }
+ /* obtain the T cold value */
+ cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ cold = (cold & temp_sensor->registers->threshold_tcold_mask)
+ >> __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ /* obtain the T HOT value */
+ hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
+ __ffs(temp_sensor->registers->threshold_thot_mask);
+
+ /* Read the current temperature */
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp &= temp_sensor->registers->bgap_dtemp_mask;
+
+ /*
+ * If current temperature is in-between the hot and cold thresholds
+ * Enable both masks or in the init case enable both masks
+ */
+ if ((temp > cold && temp < hot) || (set_cold && set_hot))
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
+
+ /*
+ * If user sets the HIGH threshold(t_hot) greater than the current
+ * temperature(temp) unmask the HOT interrupts
+ */
+ else if (hot > temp)
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
+
+ /*
+ * If user sets the LOW threshold(t_cold) lower than the current
+ * temperature(temp) unmask the COLD interrupts
+ */
+ else
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
+}
+
+/* Sysfs hook functions */
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ int temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp = (temp & temp_sensor->registers->threshold_thot_mask)
+ >> __ffs(temp_sensor->registers->threshold_thot_mask);
+ temp = adc_to_temp_conversion(temp);
+
+ return snprintf(buf, 16, "%d\n", temp);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ long val;
+ u32 t_hot;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+ if (val < MIN_TEMP - HYST_VAL)
+ return -EINVAL;
+
+ t_hot = temp_to_adc_conversion(val);
+ if (t_hot < 0)
+ return t_hot;
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
+ t_hot, 0);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
+ dev_err(dev, "invalid value\n");
+ return -EIO;
+ }
+
+ temp = adc_to_temp_conversion(temp);
+
+ return snprintf(buf, 16, "%d\n", temp);
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 t_cold;
+ long val;
+
+ if (strict_strtol(buf, 10, &val)) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ if (val > MAX_TEMP - HYST_VAL) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ t_cold = temp_to_adc_conversion(val);
+ if (t_cold < 0)
+ return t_cold;
+
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
+ t_cold);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+out:
+ return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ temp = (temp & temp_sensor->registers->counter_mask) >>
+ __ffs(temp_sensor->registers->counter_mask);
+ temp = temp * 1000 / temp_sensor->clk_rate;
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val)) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ if (val < 0)
+ return -EINVAL;
+ val *= temp_sensor->clk_rate / 1000;
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_configure_temp_sensor_counter(temp_sensor, val);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+out:
+ return count;
+}
+
+static int omap_temp_sensor_read_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ int temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp &= temp_sensor->registers->bgap_dtemp_mask;
+
+ /* look up for temperature in the table and return the temperature */
+ if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
+ return -EIO;
+
+ temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
+ set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+ show_update_interval, set_update_interval, 0);
+
+static struct attribute *omap_temp_sensor_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group omap_temp_sensor_group = {
+ .attrs = omap_temp_sensor_attributes,
+};
+
+static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
+{
+ u32 ret = 0;
+
+ if (temp_sensor->clk_on) {
+ dev_err(temp_sensor->pdev_dev, "clock already on\n");
+ goto out;
+ }
+
+ ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
+ if (ret < 0) {
+ dev_err(temp_sensor->pdev_dev, "get sync failed\n");
+ goto out;
+ }
+
+ temp_sensor->clk_on = 1;
+
+out:
+ return ret;
+}
+
+static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
+{
+ /* Gate the clock */
+ pm_runtime_put_sync(temp_sensor->hwmon_dev);
+ temp_sensor->clk_on = 0;
+}
+
+static irqreturn_t omap_talert_irq_handler(int irq, void *data)
+{
+ struct omap_temp_sensor *temp_sensor;
+ int t_hot, t_cold, temp;
+
+ temp_sensor = data;
+ mutex_lock(&temp_sensor->sensor_mutex);
+ /* Read the status of t_hot */
+ t_hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_status)
+ & temp_sensor->registers->status_hot_mask;
+
+ /* Read the status of t_cold */
+ t_cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_status)
+ & temp_sensor->registers->status_cold_mask;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->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) {
+ temp &= ~temp_sensor->registers->mask_hot_mask;
+ temp |= temp_sensor->registers->mask_cold_mask;
+ } else if (t_cold) {
+ temp &= ~temp_sensor->registers->mask_cold_mask;
+ temp |= temp_sensor->registers->mask_hot_mask;
+ }
+
+ omap_temp_sensor_writel(temp_sensor, temp,
+ temp_sensor->registers->bgap_mask_ctrl);
+
+ if (temp_sensor->hwmon_dev)
+ /* kobject_uvent to user space telling threshold crossed */
+ kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
+
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
+{
+ struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
+ struct omap_temp_sensor *temp_sensor;
+ struct resource *mem;
+ int ret = 0;
+ int clk_rate;
+ u32 max_freq, min_freq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -EINVAL;
+ }
+
+ temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
+ if (!temp_sensor) {
+ dev_err(&pdev->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&temp_sensor->sensor_mutex);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
+ if (temp_sensor->irq < 0) {
+ dev_err(&pdev->dev, "get_irq_byname failed\n");
+ ret = temp_sensor->irq;
+ goto plat_res_err;
+ }
+
+ temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
+ if (!temp_sensor->phy_base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ temp_sensor->clock = NULL;
+ temp_sensor->registers = pdata->registers;
+ temp_sensor->pdev_dev = &pdev->dev;
+
+ if (pdata->max_freq && pdata->min_freq) {
+ max_freq = pdata->max_freq;
+ min_freq = pdata->min_freq;
+ } else {
+ max_freq = MAX_FREQ;
+ min_freq = MIN_FREQ;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_irq_safe(&pdev->dev);
+
+ /*
+ * check if the efuse has a non-zero value if not
+ * it is an untrimmed sample and the temperatures
+ * may not be accurate
+ */
+
+ if (omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_efuse))
+ dev_info(&pdev->dev,
+ "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
+
+ dev_set_drvdata(&pdev->dev, temp_sensor);
+ temp_sensor->clock = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(temp_sensor->clock)) {
+ ret = PTR_ERR(temp_sensor->clock);
+ dev_err(&pdev->dev,
+ "unable to get fclk: %d\n", ret);
+ goto plat_res_err;
+ }
+
+ ret = omap_temp_sensor_clk_enable(temp_sensor);
+ if (ret)
+ goto clken_err;
+
+ clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
+ if (clk_rate < min_freq || clk_rate == 0xffffffff) {
+ ret = -ENODEV;
+ goto clken_err;
+ }
+
+ ret = clk_set_rate(temp_sensor->clock, clk_rate);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot set clock rate\n");
+ goto clken_err;
+ }
+
+ temp_sensor->clk_rate = clk_rate;
+ omap_enable_continuous_mode(temp_sensor);
+ /* 1 clk cycle */
+ omap_configure_temp_sensor_counter(temp_sensor, 1);
+
+ /* Wait till the first conversion is done wait for at least 1ms */
+ usleep_range(1000, 2000);
+
+ /* Read the temperature once due to hw issue*/
+ omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+
+ /* Set 2 seconds time as default counter */
+ omap_configure_temp_sensor_counter(temp_sensor,
+ temp_sensor->clk_rate * 2);
+
+ ret = request_threaded_irq(temp_sensor->irq, NULL,
+ omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "temp_sensor", temp_sensor);
+ if (ret) {
+ dev_err(&pdev->dev, "Request threaded irq failed.\n");
+ goto req_irq_err;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
+ if (ret) {
+ dev_err(&pdev->dev, "could not create sysfs files\n");
+ goto sysfs_create_err;
+ }
+
+ temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(temp_sensor->hwmon_dev)) {
+ dev_err(&pdev->dev, "hwmon_device_register failed.\n");
+ ret = PTR_ERR(temp_sensor->hwmon_dev);
+ goto hwmon_reg_err;
+ }
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
+ T_HOT, T_COLD);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return 0;
+
+hwmon_reg_err:
+ sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
+ &omap_temp_sensor_group);
+sysfs_create_err:
+ free_irq(temp_sensor->irq, temp_sensor);
+req_irq_err:
+ omap_temp_sensor_clk_disable(temp_sensor);
+clken_err:
+ clk_put(temp_sensor->clock);
+ iounmap(temp_sensor->phy_base);
+plat_res_err:
+ dev_set_drvdata(&pdev->dev, NULL);
+ mutex_destroy(&temp_sensor->sensor_mutex);
+ kfree(temp_sensor);
+ return ret;
+}
+
+static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
+{
+ struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(&pdev->dev);
+ sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
+ &omap_temp_sensor_group);
+ free_irq(temp_sensor->irq, temp_sensor);
+ omap_temp_sensor_clk_disable(temp_sensor);
+ clk_put(temp_sensor->clock);
+ iounmap(temp_sensor->phy_base);
+ dev_set_drvdata(&pdev->dev, NULL);
+ mutex_destroy(&temp_sensor->sensor_mutex);
+ kfree(temp_sensor);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
+{
+ temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mask_ctrl);
+ temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp_sensor->temp_sensor_tshut_threshold =
+ omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->thsut_threshold);
+}
+
+static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
+{
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->temp_sensor_ctrl,
+ temp_sensor->registers->temp_sensor_ctrl);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_ctrl,
+ temp_sensor->registers->bgap_mask_ctrl);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_counter,
+ temp_sensor->registers->bgap_counter);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_threshold,
+ temp_sensor->registers->bgap_threshold);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->temp_sensor_tshut_threshold,
+ temp_sensor->registers->thsut_threshold);
+}
+
+static int omap_temp_sensor_suspend(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_save_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_resume(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_restore_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_runtime_suspend(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_save_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_runtime_resume(struct device *dev)
+{
+ static int context_loss_count;
+ int temp;
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ temp = omap_device_get_context_loss_count(to_platform_device(dev));
+
+ if (temp != context_loss_count && context_loss_count != 0)
+ omap_temp_sensor_restore_ctxt(temp_sensor);
+
+ context_loss_count = temp;
+
+ return 0;
+}
+
+static int omap_temp_sensor_idle(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
+ omap_temp_sensor_resume)
+ SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
+ omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
+};
+
+#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver omap_temp_sensor_driver = {
+ .probe = omap_temp_sensor_probe,
+ .remove = omap_temp_sensor_remove,
+ .driver = {
+ .name = "omap_temp_sensor",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+int __init omap_temp_sensor_init(void)
+{
+ return platform_driver_register(&omap_temp_sensor_driver);
+}
+module_init(omap_temp_sensor_init);
+
+static void __exit omap_temp_sensor_exit(void)
+{
+ platform_driver_unregister(&omap_temp_sensor_driver);
+}
+module_exit(omap_temp_sensor_exit);
+
+MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
--
1.7.0.4
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor
@ 2011-08-31 17:37 ` Keerthy
0 siblings, 0 replies; 43+ messages in thread
From: Keerthy @ 2011-08-31 17:37 UTC (permalink / raw)
To: linux-omap; +Cc: Keerthy, Jean Delvare, Guenter Roeck, lm-sensors
On chip temperature sensor driver. The driver monitors the temperature of
the MPU subsystem of the OMAP4. It sends notifications to the user space if
the temperature crosses user defined thresholds via kobject_uevent interface.
The user is allowed to configure the temperature thresholds vis sysfs nodes
exposed using hwmon interface.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: lm-sensors@lm-sensors.org
---
Documentation/hwmon/omap_temp_sensor | 26 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/omap_temp_sensor.c | 881 ++++++++++++++++++++++++++++++++++
4 files changed, 919 insertions(+), 0 deletions(-)
create mode 100644 Documentation/hwmon/omap_temp_sensor
create mode 100644 drivers/hwmon/omap_temp_sensor.c
diff --git a/Documentation/hwmon/omap_temp_sensor b/Documentation/hwmon/omap_temp_sensor
new file mode 100644
index 0000000..357f09a
--- /dev/null
+++ b/Documentation/hwmon/omap_temp_sensor
@@ -0,0 +1,26 @@
+Kernel driver omap_temp_sensor
+===============
+
+Supported chips:
+ * Texas Instruments OMAP4460
+ Prefix: 'omap_temp_sensor'
+
+Author:
+ J Keerthy <j-keerthy@ti.com>
+
+Description
+-----------
+
+The Texas Instruments OMAP4 family of chips have a bandgap temperature sensor.
+The temperature sensor feature is used to convert the temperature of the device
+into a decimal value coded on 10 bits. An internal ADC is used for conversion.
+The recommended operating temperatures must be in the range -40 degree Celsius
+to 123 degree celsius for standard conversion.
+The thresholds are programmable and upon crossing the thresholds an interrupt
+is generated. The OMAP temperature sensor has a programmable update rate in
+milli seconds.
+(Currently the driver programs a default of 2000 milliseconds).
+
+The driver provides the common sysfs-interface for temperatures (see
+Documentation/hwmon/sysfs-interface under Temperatures).
+
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5f888f7..9c9cd8b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -323,6 +323,17 @@ config SENSORS_F71805F
This driver can also be built as a module. If so, the module
will be called f71805f.
+config SENSORS_OMAP_BANDGAP_TEMP_SENSOR
+ bool "OMAP on-die temperature sensor hwmon driver"
+ depends on HWMON && ARCH_OMAP && OMAP_TEMP_SENSOR
+ help
+ If you say yes here you get support for hardware
+ monitoring features of the OMAP on die temperature
+ sensor.
+
+ Continuous conversion programmable delay
+ mode is used for temperature conversion.
+
config SENSORS_F71882FG
tristate "Fintek F71882FG and compatibles"
help
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 28061cf..d0f89f5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_OMAP_BANDGAP_TEMP_SENSOR) += omap_temp_sensor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
new file mode 100644
index 0000000..67fa424
--- /dev/null
+++ b/drivers/hwmon/omap_temp_sensor.c
@@ -0,0 +1,881 @@
+/*
+ * OMAP4 Temperature sensor driver file
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@ti.com>
+ * Author: Moiz Sonasath <m-sonasath@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/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <plat/omap_device.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/stddef.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <plat/temperature_sensor.h>
+
+#define TSHUT_HOT 920 /* 122 deg C */
+#define TSHUT_COLD 866 /* 100 deg C */
+#define T_HOT 800 /* 73 deg C */
+#define T_COLD 795 /* 71 deg C */
+#define OMAP_ADC_START_VALUE 530
+#define OMAP_ADC_END_VALUE 923
+#define MAX_FREQ 2000000
+#define MIN_FREQ 1000000
+#define MIN_TEMP -40000
+#define MAX_TEMP 123000
+#define HYST_VAL 5000
+#define NEG_HYST_VAL -5000
+/*
+ * omap_temp_sensor structure
+ * @hwmon_dev - hwmon device pointer
+ * @pdev_dev - platform device pointer
+ * @clock - Clock pointer
+ * @registers - Pointer to structure with register offsets and bitfields
+ * @sensor_mutex - Mutex for sysfs, irq and PM
+ * @irq - MPU Irq number for thermal alert
+ * @phy_base - Physical base of the temp I/O
+ * @clk_rate - Holds current clock rate
+ * @temp_sensor_ctrl - temp sensor control register value
+ * @bg_ctrl - bandgap ctrl register value
+ * @bg_counter - bandgap counter value
+ * @bg_threshold - bandgap threshold register value
+ * @temp_sensor_tshut_threshold - bandgap tshut register value
+ * @clk_on - Manages the current clock state
+ */
+struct omap_temp_sensor {
+ struct device *hwmon_dev;
+ struct device *pdev_dev;
+ struct clk *clock;
+ struct omap_temp_sensor_registers *registers;
+ struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
+ unsigned int irq;
+ void __iomem *phy_base;
+ u32 clk_rate;
+ u32 temp_sensor_ctrl;
+ u32 bg_ctrl;
+ u32 bg_counter;
+ u32 bg_threshold;
+ u32 temp_sensor_tshut_threshold;
+ bool clk_on;
+};
+
+/*
+ * Temperature values in milli degree celsius
+ * ADC code values from 530 to 923
+ */
+static int adc_to_temp[394] = {
+ -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
+};
+
+static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
+ *temp_sensor, u32 reg)
+{
+ return __raw_readl(temp_sensor->phy_base + reg);
+}
+
+static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
+ u32 val, u32 reg)
+{
+ __raw_writel(val, temp_sensor->phy_base + reg);
+}
+
+static int adc_to_temp_conversion(int adc_val)
+{
+ return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
+}
+
+static int temp_to_adc_conversion(long temp)
+{
+ int high, low, mid;
+
+ if (temp < adc_to_temp[0] ||
+ temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
+ return -EINVAL;
+
+ high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
+ low = 0;
+ mid = (high + low) / 2;
+
+ while (low < high) {
+ if (temp < adc_to_temp[mid])
+ high = mid - 1;
+ else
+ low = mid + 1;
+ mid = (low + high) / 2;
+ }
+
+ return OMAP_ADC_START_VALUE + low;
+}
+
+static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
+ *temp_sensor, u32 counter)
+{
+ u32 val;
+
+ val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ val &= ~temp_sensor->registers->counter_mask;
+ val |= counter << __ffs(temp_sensor->registers->counter_mask);
+ omap_temp_sensor_writel(temp_sensor, val,
+ temp_sensor->registers->bgap_counter);
+}
+
+static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
+{
+ u32 val;
+
+ val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mode_ctrl);
+
+ val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
+
+ omap_temp_sensor_writel(temp_sensor, val,
+ temp_sensor->registers->bgap_mode_ctrl);
+}
+
+static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
+ *temp_sensor, u8 hot, u8 cold)
+{
+ u32 reg_val;
+
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mask_ctrl);
+ if (hot)
+ reg_val |= temp_sensor->registers->mask_hot_mask;
+ else
+ reg_val &= ~temp_sensor->registers->mask_hot_mask;
+
+ if (cold)
+ reg_val |= temp_sensor->registers->mask_cold_mask;
+ else
+ reg_val &= ~temp_sensor->registers->mask_cold_mask;
+
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_mask_ctrl);
+}
+
+static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
+{
+ int temp = adc_to_temp_conversion(adc_val);
+
+ temp += hyst_val;
+
+ *thresh_val = temp_to_adc_conversion(temp);
+}
+
+static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
+ *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
+{
+ int reg_val, cold, hot, temp;
+
+ if (set_hot) {
+ /* obtain the T cold value */
+ cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ cold = (cold & temp_sensor->registers->threshold_tcold_mask)
+ >> __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ if (t_hot < cold) {
+ /* change the t_cold to t_hot - 5000 millidegrees */
+ add_hyst(t_hot, NEG_HYST_VAL, &cold);
+ /* write the new t_cold value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &+ ~temp_sensor->registers->threshold_tcold_mask;
+ reg_val |= cold <<
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ t_cold = cold;
+ }
+
+ /* write the new t_hot value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &= ~temp_sensor->registers->threshold_thot_mask;
+ reg_val |= (t_hot <<
+ __ffs(temp_sensor->registers->threshold_thot_mask));
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ }
+
+ if (set_cold) {
+ /* obtain the T HOT value */
+ hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
+ __ffs(temp_sensor->registers->threshold_thot_mask);
+ if (t_cold > hot) {
+ /* change the t_hot to t_cold + 5000 millidegrees */
+ add_hyst(t_cold, HYST_VAL, &hot);
+ /* write the new t_hot value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &+ ~temp_sensor->registers->threshold_thot_mask;
+ reg_val |= (hot <<
+ __ffs(temp_sensor->registers->threshold_thot_mask));
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ t_hot = hot;
+ }
+
+ /* write the new t_cold value */
+ reg_val = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
+ reg_val |= t_cold <<
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+ omap_temp_sensor_writel(temp_sensor, reg_val,
+ temp_sensor->registers->bgap_threshold);
+ }
+ /* obtain the T cold value */
+ cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ cold = (cold & temp_sensor->registers->threshold_tcold_mask)
+ >> __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ /* obtain the T HOT value */
+ hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
+ __ffs(temp_sensor->registers->threshold_thot_mask);
+
+ /* Read the current temperature */
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp &= temp_sensor->registers->bgap_dtemp_mask;
+
+ /*
+ * If current temperature is in-between the hot and cold thresholds
+ * Enable both masks or in the init case enable both masks
+ */
+ if ((temp > cold && temp < hot) || (set_cold && set_hot))
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
+
+ /*
+ * If user sets the HIGH threshold(t_hot) greater than the current
+ * temperature(temp) unmask the HOT interrupts
+ */
+ else if (hot > temp)
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
+
+ /*
+ * If user sets the LOW threshold(t_cold) lower than the current
+ * temperature(temp) unmask the COLD interrupts
+ */
+ else
+ omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
+}
+
+/* Sysfs hook functions */
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ int temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp = (temp & temp_sensor->registers->threshold_thot_mask)
+ >> __ffs(temp_sensor->registers->threshold_thot_mask);
+ temp = adc_to_temp_conversion(temp);
+
+ return snprintf(buf, 16, "%d\n", temp);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ long val;
+ u32 t_hot;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+ if (val < MIN_TEMP - HYST_VAL)
+ return -EINVAL;
+
+ t_hot = temp_to_adc_conversion(val);
+ if (t_hot < 0)
+ return t_hot;
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
+ t_hot, 0);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
+ __ffs(temp_sensor->registers->threshold_tcold_mask);
+
+ if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
+ dev_err(dev, "invalid value\n");
+ return -EIO;
+ }
+
+ temp = adc_to_temp_conversion(temp);
+
+ return snprintf(buf, 16, "%d\n", temp);
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 t_cold;
+ long val;
+
+ if (strict_strtol(buf, 10, &val)) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ if (val > MAX_TEMP - HYST_VAL) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ t_cold = temp_to_adc_conversion(val);
+ if (t_cold < 0)
+ return t_cold;
+
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
+ t_cold);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+out:
+ return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ u32 temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ temp = (temp & temp_sensor->registers->counter_mask) >>
+ __ffs(temp_sensor->registers->counter_mask);
+ temp = temp * 1000 / temp_sensor->clk_rate;
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val)) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ if (val < 0)
+ return -EINVAL;
+ val *= temp_sensor->clk_rate / 1000;
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_configure_temp_sensor_counter(temp_sensor, val);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+out:
+ return count;
+}
+
+static int omap_temp_sensor_read_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+ int temp;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp &= temp_sensor->registers->bgap_dtemp_mask;
+
+ /* look up for temperature in the table and return the temperature */
+ if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
+ return -EIO;
+
+ temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
+ set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+ show_update_interval, set_update_interval, 0);
+
+static struct attribute *omap_temp_sensor_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group omap_temp_sensor_group = {
+ .attrs = omap_temp_sensor_attributes,
+};
+
+static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
+{
+ u32 ret = 0;
+
+ if (temp_sensor->clk_on) {
+ dev_err(temp_sensor->pdev_dev, "clock already on\n");
+ goto out;
+ }
+
+ ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
+ if (ret < 0) {
+ dev_err(temp_sensor->pdev_dev, "get sync failed\n");
+ goto out;
+ }
+
+ temp_sensor->clk_on = 1;
+
+out:
+ return ret;
+}
+
+static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
+{
+ /* Gate the clock */
+ pm_runtime_put_sync(temp_sensor->hwmon_dev);
+ temp_sensor->clk_on = 0;
+}
+
+static irqreturn_t omap_talert_irq_handler(int irq, void *data)
+{
+ struct omap_temp_sensor *temp_sensor;
+ int t_hot, t_cold, temp;
+
+ temp_sensor = data;
+ mutex_lock(&temp_sensor->sensor_mutex);
+ /* Read the status of t_hot */
+ t_hot = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_status)
+ & temp_sensor->registers->status_hot_mask;
+
+ /* Read the status of t_cold */
+ t_cold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_status)
+ & temp_sensor->registers->status_cold_mask;
+
+ temp = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->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) {
+ temp &= ~temp_sensor->registers->mask_hot_mask;
+ temp |= temp_sensor->registers->mask_cold_mask;
+ } else if (t_cold) {
+ temp &= ~temp_sensor->registers->mask_cold_mask;
+ temp |= temp_sensor->registers->mask_hot_mask;
+ }
+
+ omap_temp_sensor_writel(temp_sensor, temp,
+ temp_sensor->registers->bgap_mask_ctrl);
+
+ if (temp_sensor->hwmon_dev)
+ /* kobject_uvent to user space telling threshold crossed */
+ kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
+
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
+{
+ struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
+ struct omap_temp_sensor *temp_sensor;
+ struct resource *mem;
+ int ret = 0;
+ int clk_rate;
+ u32 max_freq, min_freq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data missing\n");
+ return -EINVAL;
+ }
+
+ temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
+ if (!temp_sensor) {
+ dev_err(&pdev->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&temp_sensor->sensor_mutex);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
+ if (temp_sensor->irq < 0) {
+ dev_err(&pdev->dev, "get_irq_byname failed\n");
+ ret = temp_sensor->irq;
+ goto plat_res_err;
+ }
+
+ temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
+ if (!temp_sensor->phy_base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto plat_res_err;
+ }
+
+ temp_sensor->clock = NULL;
+ temp_sensor->registers = pdata->registers;
+ temp_sensor->pdev_dev = &pdev->dev;
+
+ if (pdata->max_freq && pdata->min_freq) {
+ max_freq = pdata->max_freq;
+ min_freq = pdata->min_freq;
+ } else {
+ max_freq = MAX_FREQ;
+ min_freq = MIN_FREQ;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_irq_safe(&pdev->dev);
+
+ /*
+ * check if the efuse has a non-zero value if not
+ * it is an untrimmed sample and the temperatures
+ * may not be accurate
+ */
+
+ if (omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_efuse))
+ dev_info(&pdev->dev,
+ "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
+
+ dev_set_drvdata(&pdev->dev, temp_sensor);
+ temp_sensor->clock = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(temp_sensor->clock)) {
+ ret = PTR_ERR(temp_sensor->clock);
+ dev_err(&pdev->dev,
+ "unable to get fclk: %d\n", ret);
+ goto plat_res_err;
+ }
+
+ ret = omap_temp_sensor_clk_enable(temp_sensor);
+ if (ret)
+ goto clken_err;
+
+ clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
+ if (clk_rate < min_freq || clk_rate = 0xffffffff) {
+ ret = -ENODEV;
+ goto clken_err;
+ }
+
+ ret = clk_set_rate(temp_sensor->clock, clk_rate);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot set clock rate\n");
+ goto clken_err;
+ }
+
+ temp_sensor->clk_rate = clk_rate;
+ omap_enable_continuous_mode(temp_sensor);
+ /* 1 clk cycle */
+ omap_configure_temp_sensor_counter(temp_sensor, 1);
+
+ /* Wait till the first conversion is done wait for at least 1ms */
+ usleep_range(1000, 2000);
+
+ /* Read the temperature once due to hw issue*/
+ omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+
+ /* Set 2 seconds time as default counter */
+ omap_configure_temp_sensor_counter(temp_sensor,
+ temp_sensor->clk_rate * 2);
+
+ ret = request_threaded_irq(temp_sensor->irq, NULL,
+ omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "temp_sensor", temp_sensor);
+ if (ret) {
+ dev_err(&pdev->dev, "Request threaded irq failed.\n");
+ goto req_irq_err;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
+ if (ret) {
+ dev_err(&pdev->dev, "could not create sysfs files\n");
+ goto sysfs_create_err;
+ }
+
+ temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(temp_sensor->hwmon_dev)) {
+ dev_err(&pdev->dev, "hwmon_device_register failed.\n");
+ ret = PTR_ERR(temp_sensor->hwmon_dev);
+ goto hwmon_reg_err;
+ }
+
+ mutex_lock(&temp_sensor->sensor_mutex);
+ omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
+ T_HOT, T_COLD);
+ mutex_unlock(&temp_sensor->sensor_mutex);
+
+ return 0;
+
+hwmon_reg_err:
+ sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
+ &omap_temp_sensor_group);
+sysfs_create_err:
+ free_irq(temp_sensor->irq, temp_sensor);
+req_irq_err:
+ omap_temp_sensor_clk_disable(temp_sensor);
+clken_err:
+ clk_put(temp_sensor->clock);
+ iounmap(temp_sensor->phy_base);
+plat_res_err:
+ dev_set_drvdata(&pdev->dev, NULL);
+ mutex_destroy(&temp_sensor->sensor_mutex);
+ kfree(temp_sensor);
+ return ret;
+}
+
+static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
+{
+ struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(&pdev->dev);
+ sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
+ &omap_temp_sensor_group);
+ free_irq(temp_sensor->irq, temp_sensor);
+ omap_temp_sensor_clk_disable(temp_sensor);
+ clk_put(temp_sensor->clock);
+ iounmap(temp_sensor->phy_base);
+ dev_set_drvdata(&pdev->dev, NULL);
+ mutex_destroy(&temp_sensor->sensor_mutex);
+ kfree(temp_sensor);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
+{
+ temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->temp_sensor_ctrl);
+ temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_mask_ctrl);
+ temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_counter);
+ temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->bgap_threshold);
+ temp_sensor->temp_sensor_tshut_threshold + omap_temp_sensor_readl(temp_sensor,
+ temp_sensor->registers->thsut_threshold);
+}
+
+static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
+{
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->temp_sensor_ctrl,
+ temp_sensor->registers->temp_sensor_ctrl);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_ctrl,
+ temp_sensor->registers->bgap_mask_ctrl);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_counter,
+ temp_sensor->registers->bgap_counter);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->bg_threshold,
+ temp_sensor->registers->bgap_threshold);
+ omap_temp_sensor_writel(temp_sensor,
+ temp_sensor->temp_sensor_tshut_threshold,
+ temp_sensor->registers->thsut_threshold);
+}
+
+static int omap_temp_sensor_suspend(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_save_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_resume(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_restore_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_runtime_suspend(struct device *dev)
+{
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ omap_temp_sensor_save_ctxt(temp_sensor);
+
+ return 0;
+}
+
+static int omap_temp_sensor_runtime_resume(struct device *dev)
+{
+ static int context_loss_count;
+ int temp;
+ struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
+
+ temp = omap_device_get_context_loss_count(to_platform_device(dev));
+
+ if (temp != context_loss_count && context_loss_count != 0)
+ omap_temp_sensor_restore_ctxt(temp_sensor);
+
+ context_loss_count = temp;
+
+ return 0;
+}
+
+static int omap_temp_sensor_idle(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
+ omap_temp_sensor_resume)
+ SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
+ omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
+};
+
+#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver omap_temp_sensor_driver = {
+ .probe = omap_temp_sensor_probe,
+ .remove = omap_temp_sensor_remove,
+ .driver = {
+ .name = "omap_temp_sensor",
+ .pm = DEV_PM_OPS,
+ },
+};
+
+int __init omap_temp_sensor_init(void)
+{
+ return platform_driver_register(&omap_temp_sensor_driver);
+}
+module_init(omap_temp_sensor_init);
+
+static void __exit omap_temp_sensor_exit(void)
+{
+ platform_driver_unregister(&omap_temp_sensor_driver);
+}
+module_exit(omap_temp_sensor_exit);
+
+MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
--
1.7.0.4
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor
2011-08-31 17:25 ` [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor Keerthy
@ 2011-08-31 23:16 ` Paul Walmsley
2011-09-06 18:24 ` J, KEERTHY
0 siblings, 1 reply; 43+ messages in thread
From: Paul Walmsley @ 2011-08-31 23:16 UTC (permalink / raw)
To: Keerthy, Benoit Cousson; +Cc: linux-omap, tony
[-- Attachment #1: Type: TEXT/PLAIN, Size: 4474 bytes --]
Hi Keerthy, Benoît,
On Wed, 31 Aug 2011, Keerthy wrote:
> From: Benoit Cousson <b-cousson@ti.com>
>
> OMAP4460 temperature sensor hwmod cannot be auto generated
> since it is part of ctrl module. Hence populating the
> necessary hwmod info manually.
Looking at the 4460 1.x TRM Rev H, does it makes sense to create a
separate hwmod structure for this IP block? It looks to me like these
registers are integrated pretty tightly inside the SYSCTRL_GENERAL_CORE IP
block. So from a hwmod perspective, it seems to be a different situation
than, say, the RFBI block inside the DSS subsystem?
Just based on looking at Table 18-110 "Control Module Instance Summary"
and Table 18-111 "SYSCTRL_GENERAL_CORE Register Mapping Summary", it seems
to me that this IP block is best represented as an MFD. Something like
drivers/mfd/wm8350-core.c, which registers a hwmon device, which is then
driven by drivers/hwmon/wm8350-hwmon.c.
That should avoid the need for this hwmod entry too.
>
> Signed-off-by: Benoit Cousson <b-cousson@ti.com>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Cc: tony@atomide.com
> Cc: b-cousson@ti.com
> ---
> arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 61 ++++++++++++++++++++++++++++
> 1 files changed, 61 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> index 6201422..28bf6d3 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> @@ -29,6 +29,7 @@
> #include <plat/mcbsp.h>
> #include <plat/mmc.h>
> #include <plat/i2c.h>
> +#include <plat/temperature_sensor.h>
>
> #include "omap_hwmod_common_data.h"
>
> @@ -832,6 +833,63 @@ static struct omap_hwmod omap44xx_aess_hwmod = {
> };
>
> /*
> + * 'temperature_sensor' class
> + * temperature sensor module inside the bandgap / control module
> + */
> +
> +static struct omap_hwmod_class omap44xx_temperature_sensor_hwmod_class = {
> + .name = "temperature_sensor",
> +};
> +
> +static struct omap_hwmod_irq_info omap44xx_temperature_sensor_irqs[] = {
> + { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START },
> +};
> +
> +static struct omap_hwmod_addr_space omap44xx_temperature_sensor_addrs[] = {
> + {
> + .pa_start = 0x4a00232c,
> + .pa_end = 0x4a00238b,
> + },
> +};
> +
> +static struct omap_hwmod omap44xx_temperature_sensor_hwmod;
> +/* l4_cfg -> ctrl_module_core */
> +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__temperature_sensor = {
> + .master = &omap44xx_l4_cfg_hwmod,
> + .slave = &omap44xx_temperature_sensor_hwmod,
> + .clk = "l4_div_ck",
> + .addr = omap44xx_temperature_sensor_addrs,
> + .user = OCP_USER_MPU | OCP_USER_SDMA,
> +};
> +
> +/* ctrl_module_core slave ports */
> +static struct omap_hwmod_ocp_if *omap44xx_temperature_sensor_slaves[] = {
> + &omap44xx_l4_cfg__temperature_sensor,
> +};
> +
> +/* temperature sensor dev_attr */
> +static struct omap_temp_sensor_dev_attr temp_sensor_dev_attr = {
> + .name = "mpu",
> +};
> +
> +static struct omap_hwmod omap44xx_temperature_sensor_hwmod = {
> + .name = "temperature_sensor_mpu",
> + .class = &omap44xx_temperature_sensor_hwmod_class,
> + .mpu_irqs = omap44xx_temperature_sensor_irqs,
> + .main_clk = "bandgap_ts_fclk",
> + .slaves = omap44xx_temperature_sensor_slaves,
> + .slaves_cnt = ARRAY_SIZE(omap44xx_temperature_sensor_slaves),
> + .clkdm_name = "l4_wkup_clkdm",
> + .prcm = {
> + .omap4 = {
> + .clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
> + },
> + },
> + .dev_attr = &temp_sensor_dev_attr,
> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
> +};
> +
> +/*
> * 'bandgap' class
> * bangap reference for ldo regulators
> */
> @@ -5469,6 +5527,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
> &omap44xx_timer10_hwmod,
> &omap44xx_timer11_hwmod,
>
> + /* temperature sensor hwmod */
> + &omap44xx_temperature_sensor_hwmod,
> +
> /* uart class */
> &omap44xx_uart1_hwmod,
> &omap44xx_uart2_hwmod,
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
- Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
@ 2011-08-31 23:56 ` Paul Walmsley
-1 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-08-31 23:56 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
Hi,
On Wed, 31 Aug 2011, Keerthy wrote:
> On chip temperature sensor driver. The driver monitors the temperature of
> the MPU subsystem of the OMAP4. It sends notifications to the user space if
> the temperature crosses user defined thresholds via kobject_uevent interface.
> The user is allowed to configure the temperature thresholds vis sysfs nodes
> exposed using hwmon interface.
I commented in a separate post that this driver should probably use an MFD
driver for the System Control Module accesses, and then this hwmon driver
should use functions from that to access the BANDGAP temperature sensor
registers[1].
But I had another comment on this driver.
A similar sensor is available on the OMAP34xx[2], OMAP36xx[3], and
OMAP4430[4] chips. There are some register layout differences; the
thermal shutdown threshold is configurable on the 4460 but fixed on the
4430; and also I'd assume, without looking, that the temperature mapping
table is different on different chips.
So it would seem to make sense to move the chip-specific code and
data into chip-specific source files.
I could see keeping a generic filename like "omap_temp_sensor.c" if you
implemented a common interface to the bandgap sensors, ADCs and
comparators, across all those different chips. That might be worth
thinking about. But at least, this should probably be named
drivers/hwmon/omap4460_temp_sensor.c, or something similar.
- Paul
1. Walmsley, Paul. _Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature
sensor_. Posted to the linux-omap@vger.kernel.org list on Wed, 31 Aug
2011 17:16:44 -0600. Available from (among others):
http://marc.info/?l=linux-omap&m=131483260632685&w=2
2. Section 7.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP34xx
Multimedia Device Silicon Revision 3.1.x Version R (SWPU223R)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZR.zip
3. Section 13.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP36xx
Multimedia Device Silicon Revision 1.x Version V (SWPU177V)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip
4. Section 18.4.10 "Band Gap Voltage and Temperature Sensor". _OMAP4430
Multimedia Device Silicon Revision 2.x Version V (SWPU231V)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP4430_ES2.x_PUBLIC_TRM_vV.zip
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-08-31 23:56 ` Paul Walmsley
0 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-08-31 23:56 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
Hi,
On Wed, 31 Aug 2011, Keerthy wrote:
> On chip temperature sensor driver. The driver monitors the temperature of
> the MPU subsystem of the OMAP4. It sends notifications to the user space if
> the temperature crosses user defined thresholds via kobject_uevent interface.
> The user is allowed to configure the temperature thresholds vis sysfs nodes
> exposed using hwmon interface.
I commented in a separate post that this driver should probably use an MFD
driver for the System Control Module accesses, and then this hwmon driver
should use functions from that to access the BANDGAP temperature sensor
registers[1].
But I had another comment on this driver.
A similar sensor is available on the OMAP34xx[2], OMAP36xx[3], and
OMAP4430[4] chips. There are some register layout differences; the
thermal shutdown threshold is configurable on the 4460 but fixed on the
4430; and also I'd assume, without looking, that the temperature mapping
table is different on different chips.
So it would seem to make sense to move the chip-specific code and
data into chip-specific source files.
I could see keeping a generic filename like "omap_temp_sensor.c" if you
implemented a common interface to the bandgap sensors, ADCs and
comparators, across all those different chips. That might be worth
thinking about. But at least, this should probably be named
drivers/hwmon/omap4460_temp_sensor.c, or something similar.
- Paul
1. Walmsley, Paul. _Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature
sensor_. Posted to the linux-omap@vger.kernel.org list on Wed, 31 Aug
2011 17:16:44 -0600. Available from (among others):
http://marc.info/?l=linux-omap&m\x131483260632685&w=2
2. Section 7.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP34xx
Multimedia Device Silicon Revision 3.1.x Version R (SWPU223R)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZR.zip
3. Section 13.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP36xx
Multimedia Device Silicon Revision 1.x Version V (SWPU177V)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip
4. Section 18.4.10 "Band Gap Voltage and Temperature Sensor". _OMAP4430
Multimedia Device Silicon Revision 2.x Version V (SWPU231V)_ (public
version). Available from
http://focus.ti.com/pdfs/wtbu/OMAP4430_ES2.x_PUBLIC_TRM_vV.zip
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor
2011-08-31 17:25 ` [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor Keerthy
@ 2011-09-01 0:00 ` Paul Walmsley
2011-09-02 7:12 ` Rajendra Nayak
0 siblings, 1 reply; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 0:00 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, tony, rnayak
Hi,
a comment:
On Wed, 31 Aug 2011, Keerthy wrote:
> div_ts_ck feeds only the temperature sensor functional clock
> and also has a clksel associated (for divider selection). Mapping this
> as the functional clock for the temperature sensor in clkdev table,
> so a clk_set_rate() in the driver would have the effect of changing the
> temperature sensor clock rate indirectly.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Reviewed-by: Rajendra Nayak <rnayak@ti.com>
> Cc: tony@atomide.com
> Cc: rnayak@ti.com
> ---
> arch/arm/mach-omap2/clock44xx_data.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
> index 2af0e3f..4a788f4 100644
> --- a/arch/arm/mach-omap2/clock44xx_data.c
> +++ b/arch/arm/mach-omap2/clock44xx_data.c
> @@ -3187,7 +3187,7 @@ static struct omap_clk omap44xx_clks[] = {
> CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X),
> CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X),
> CLK(NULL, "des3des_fck", &des3des_fck, CK_443X),
> - CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X),
> + CLK("omap_temp_sensor.0", "fck", &div_ts_ck, CK_446X),
It shouldn't be necessary to add the device name/ID here. We're trying
to get rid of these. The omap_device code should take care of adding the
appropriate alias.
> CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X),
> CLK(NULL, "dmic_fck", &dmic_fck, CK_443X),
> CLK(NULL, "dsp_fck", &dsp_fck, CK_443X),
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
- Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields
2011-08-31 17:25 ` [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields Keerthy
@ 2011-09-01 0:04 ` Paul Walmsley
2011-09-01 2:57 ` J, KEERTHY
0 siblings, 1 reply; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 0:04 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, tony
On Wed, 31 Aug 2011, Keerthy wrote:
> OMAP4460 specific temperature sensor register bit fields are added.
> Existing OMAP4 entries are renamed to OMAP4430.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Cc: tony@atomide.com
At least one of these bitfields are incorrect. Please double-check them.
> ---
> .../include/mach/ctrl_module_core_44xx.h | 70 ++++++++++++++++----
> 1 files changed, 57 insertions(+), 13 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
> index 2f7ac70..725c1e1 100644
> --- a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
> +++ b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
> @@ -256,19 +256,63 @@
> #define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT 0
> #define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK (0x1f << 0)
>
> -/* TEMP_SENSOR */
> -#define OMAP4_BGAP_TEMPSOFF_SHIFT 12
> -#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 12)
> -#define OMAP4_BGAP_TSHUT_SHIFT 11
> -#define OMAP4_BGAP_TSHUT_MASK (1 << 11)
> -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
> -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
> -#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 9
> -#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
> -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
> -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
> -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
> -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
> +/* TEMP_SENSOR OMAP4430 */
> +#define OMAP4430_BGAP_TEMPSOFF_SHIFT 12
> +#define OMAP4430_BGAP_TEMPSOFF_MASK (1 << 12)
> +#define OMAP4430_BGAP_TSHUT_SHIFT 11
> +#define OMAP4430_BGAP_TSHUT_MASK (1 << 11)
> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_SHIFT 9
> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
For example, this bitfield is only eight bits wide on 4430.
> +
> +/* TEMP_SENSOR OMAP4460 */
> +#define OMAP4460_BGAP_TEMPSOFF_SHIFT 13
> +#define OMAP4460_BGAP_TEMPSOFF_MASK (1 << 13)
> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_SHIFT 11
> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11)
> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
> +
> +/* BANDGAP_CTRL */
> +#define OMAP4460_SINGLE_MODE_SHIFT 31
> +#define OMAP4460_SINGLE_MODE_MASK (1 << 31)
> +#define OMAP4460_MASK_HOT_SHIFT 1
> +#define OMAP4460_MASK_HOT_MASK (1 << 1)
> +#define OMAP4460_MASK_COLD_SHIFT 0
> +#define OMAP4460_MASK_COLD_MASK (1 << 0)
> +
> +/* BANDGAP_COUNTER */
> +#define OMAP4460_COUNTER_SHIFT 0
> +#define OMAP4460_COUNTER_MASK (0xffffff << 0)
> +
> +/* BANDGAP_THRESHOLD */
> +#define OMAP4460_T_HOT_SHIFT 16
> +#define OMAP4460_T_HOT_MASK (0x3ff << 16)
> +#define OMAP4460_T_COLD_SHIFT 0
> +#define OMAP4460_T_COLD_MASK (0x3ff << 0)
> +
> +/* TSHUT_THRESHOLD */
> +#define OMAP4460_TSHUT_HOT_SHIFT 16
> +#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
> +#define OMAP4460_TSHUT_COLD_SHIFT 0
> +#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
> +
> +/* BANDGAP_STATUS */
> +#define OMAP4460_CLEAN_STOP_SHIFT 3
> +#define OMAP4460_CLEAN_STOP_MASK (1 << 3)
> +#define OMAP4460_BGAP_ALERT_SHIFT 2
> +#define OMAP4460_BGAP_ALERT_MASK (1 << 2)
> +#define OMAP4460_HOT_FLAG_SHIFT 1
> +#define OMAP4460_HOT_FLAG_MASK (1 << 1)
> +#define OMAP4460_COLD_FLAG_SHIFT 0
> +#define OMAP4460_COLD_FLAG_MASK (1 << 0)
>
> /* DPLL_NWELL_TRIM_0 */
> #define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT 29
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
- Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
@ 2011-09-01 0:36 ` Paul Walmsley
-1 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 0:36 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
Hi
Some comments.
On Wed, 31 Aug 2011, Keerthy wrote:
> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
> new file mode 100644
> index 0000000..67fa424
> --- /dev/null
> +++ b/drivers/hwmon/omap_temp_sensor.c
> @@ -0,0 +1,881 @@
You've done almost all the hard work to create kerneldoc-NANO compliant
structure documentation, which is good. But a few important things are
missing. Please review Documentation/kernel-doc-nano-HOWTO.txt.
> +/*
Should be /** to indicate kerneldoc.
> + * omap_temp_sensor structure
Should be "struct omap_temp_sensor" and should include a short
description.
> + * @hwmon_dev - hwmon device pointer
> + * @pdev_dev - platform device pointer
> + * @clock - Clock pointer
> + * @registers - Pointer to structure with register offsets and bitfields
> + * @sensor_mutex - Mutex for sysfs, irq and PM
> + * @irq - MPU Irq number for thermal alert
> + * @phy_base - Physical base of the temp I/O
> + * @clk_rate - Holds current clock rate
> + * @temp_sensor_ctrl - temp sensor control register value
> + * @bg_ctrl - bandgap ctrl register value
> + * @bg_counter - bandgap counter value
> + * @bg_threshold - bandgap threshold register value
> + * @temp_sensor_tshut_threshold - bandgap tshut register value
> + * @clk_on - Manages the current clock state
> + */
> +struct omap_temp_sensor {
> + struct device *hwmon_dev;
> + struct device *pdev_dev;
> + struct clk *clock;
> + struct omap_temp_sensor_registers *registers;
> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
> + unsigned int irq;
> + void __iomem *phy_base;
> + u32 clk_rate;
> + u32 temp_sensor_ctrl;
> + u32 bg_ctrl;
> + u32 bg_counter;
> + u32 bg_threshold;
> + u32 temp_sensor_tshut_threshold;
> + bool clk_on;
> +};
> +
> +/*
> + * Temperature values in milli degree celsius
> + * ADC code values from 530 to 923
> + */
> +static int adc_to_temp[394] = {
> + -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
> +};
> +
> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
> + *temp_sensor, u32 reg)
> +{
> + return __raw_readl(temp_sensor->phy_base + reg);
> +}
> +
> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
> + u32 val, u32 reg)
> +{
> + __raw_writel(val, temp_sensor->phy_base + reg);
> +}
These are all SCM register accesses and need to go through a SCM driver.
> +
> +static int adc_to_temp_conversion(int adc_val)
> +{
> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
> +}
> +
> +static int temp_to_adc_conversion(long temp)
> +{
> + int high, low, mid;
> +
> + if (temp < adc_to_temp[0] ||
> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
> + return -EINVAL;
> +
> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
> + low = 0;
> + mid = (high + low) / 2;
> +
> + while (low < high) {
> + if (temp < adc_to_temp[mid])
> + high = mid - 1;
> + else
> + low = mid + 1;
> + mid = (low + high) / 2;
> + }
> +
> + return OMAP_ADC_START_VALUE + low;
> +}
> +
> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
> + *temp_sensor, u32 counter)
It doesn't seem necessary to include 'omap' in all these static function names.
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + val &= ~temp_sensor->registers->counter_mask;
> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_counter);
> +}
> +
> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mode_ctrl);
> +
> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
> +
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_mode_ctrl);
> +}
> +
> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
> + *temp_sensor, u8 hot, u8 cold)
Your earlier static function names didn't include 'temp_sensor', but
this one does. I'd suggest picking a standard function naming scheme
and sticking to it.
> +{
> + u32 reg_val;
> +
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + if (hot)
> + reg_val |= temp_sensor->registers->mask_hot_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
> +
> + if (cold)
> + reg_val |= temp_sensor->registers->mask_cold_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
> +
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_mask_ctrl);
> +}
> +
> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
> +{
> + int temp = adc_to_temp_conversion(adc_val);
> +
> + temp += hyst_val;
> +
> + *thresh_val = temp_to_adc_conversion(temp);
> +}
> +
> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
Is there some reason why you don't just define a
omap_temp_sensor_configure_hot_threshold()
and
omap_temp_sensor_configure_cold_threshold()
?
Seems like that would be much more straightforward and would allow the
removal of those set_{hot,cold} arguments.
> +{
> + int reg_val, cold, hot, temp;
This function is really big and should be split up into several smaller
functions. Common code should be shared if possible.
> +
> + if (set_hot) {
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
This code should be hoisted up above the if statements. Only a single
device read should be necessary to fetch both the hot and cold values.
Then the near-duplicate code below to read the hot temperature can be
removed.
In fact, given that this patch has almost the same code several times,
you should just put it into a static function or two and remove the
duplicate code.
> +
> + if (t_hot < cold) {
> + /* change the t_cold to t_hot - 5000 millidegrees */
> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &=
> + ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
Looks like there are some indentation problems here. Those are more
important than 80-column issues.
Of course, you use temp_sensor->registers so much in this function, that
many of the line length issues would go away if you used a shorter
abbreviation at the beginning of this function, like:
tsr = temp_sensor->registers;
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_cold = cold;
> + }
> +
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (t_hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> +
> + if (set_cold) {
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
See the earlier comment about hoisting.
> + if (t_cold > hot) {
> + /* change the t_hot to t_cold + 5000 millidegrees */
> + add_hyst(t_cold, HYST_VAL, &hot);
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &=
> + ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
This is a duplicate of earlier code. Please consolidate.
> + t_hot = hot;
> + }
> +
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= t_cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> +
> + /* Read the current temperature */
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /*
> + * If current temperature is in-between the hot and cold thresholds
> + * Enable both masks or in the init case enable both masks
> + */
> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> +
> + /*
> + * If user sets the HIGH threshold(t_hot) greater than the current
> + * temperature(temp) unmask the HOT interrupts
> + */
> + else if (hot > temp)
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> +
> + /*
> + * If user sets the LOW threshold(t_cold) lower than the current
> + * temperature(temp) unmask the COLD interrupts
> + */
> + else
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
This if statement is surely a violation of the spirit of
Documentation/CodingStyle, if not the text itself.
If you really need an if statement like this, try something like:
if ((temp > cold && temp < hot) || (set_cold && set_hot)) {
/*
* If current temperature is in-between the hot and cold thresholds
* Enable both masks or in the init case enable both masks
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
} else if (hot > temp) {
/*
* If user sets the HIGH threshold(t_hot) greater than the current
* temperature(temp) unmask the HOT interrupts
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
} else {
/*
* If user sets the LOW threshold(t_cold) lower than the current
* temperature(temp) unmask the COLD interrupts
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
}
> +}
> +
> +/* Sysfs hook functions */
These should be conditionally compiled out if sysfs isn't compiled in.
> +
> +static ssize_t show_temp_max(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> + u32 t_hot;
> +
> + if (strict_strtol(buf, 10, &val))
> + return -EINVAL;
> + if (val < MIN_TEMP - HYST_VAL)
> + return -EINVAL;
> +
> + t_hot = temp_to_adc_conversion(val);
> + if (t_hot < 0)
> + return t_hot;
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
> + t_hot, 0);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return count;
> +}
> +
> +static ssize_t show_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
> + dev_err(dev, "invalid value\n");
> + return -EIO;
> + }
> +
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 t_cold;
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + if (val > MAX_TEMP - HYST_VAL) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + t_cold = temp_to_adc_conversion(val);
> + if (t_cold < 0)
> + return t_cold;
> +
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
> + t_cold);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> +out:
> + return count;
> +}
> +
> +static ssize_t show_update_interval(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp = (temp & temp_sensor->registers->counter_mask) >>
> + __ffs(temp_sensor->registers->counter_mask);
> + temp = temp * 1000 / temp_sensor->clk_rate;
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static ssize_t set_update_interval(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + if (val < 0)
> + return -EINVAL;
> + val *= temp_sensor->clk_rate / 1000;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_configure_temp_sensor_counter(temp_sensor, val);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +out:
> + return count;
> +}
> +
> +static int omap_temp_sensor_read_temp(struct device *dev,
> + struct device_attribute *devattr,
> + char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /* look up for temperature in the table and return the temperature */
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
> + return -EIO;
> +
> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
> + NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
> + set_temp_max, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
> + set_temp_max_hyst, 0);
> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
> + show_update_interval, set_update_interval, 0);
> +
> +static struct attribute *omap_temp_sensor_attributes[] = {
> + &sensor_dev_attr_temp1_input.dev_attr.attr,
> + &sensor_dev_attr_temp1_max.dev_attr.attr,
> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> + &sensor_dev_attr_update_interval.dev_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group omap_temp_sensor_group = {
> + .attrs = omap_temp_sensor_attributes,
> +};
> +
> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 ret = 0;
> +
> + if (temp_sensor->clk_on) {
> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
> + goto out;
> + }
> +
> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
> + if (ret < 0) {
> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
> + goto out;
> + }
> +
> + temp_sensor->clk_on = 1;
> +
> +out:
> + return ret;
> +}
> +
> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
> +{
> + /* Gate the clock */
> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
> + temp_sensor->clk_on = 0;
> +}
> +
> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
> +{
> + struct omap_temp_sensor *temp_sensor;
> + int t_hot, t_cold, temp;
> +
> + temp_sensor = data;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + /* Read the status of t_hot */
> + t_hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_hot_mask;
> +
> + /* Read the status of t_cold */
> + t_cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_cold_mask;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->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) {
> + temp &= ~temp_sensor->registers->mask_hot_mask;
> + temp |= temp_sensor->registers->mask_cold_mask;
> + } else if (t_cold) {
> + temp &= ~temp_sensor->registers->mask_cold_mask;
> + temp |= temp_sensor->registers->mask_hot_mask;
> + }
> +
> + omap_temp_sensor_writel(temp_sensor, temp,
> + temp_sensor->registers->bgap_mask_ctrl);
> +
> + if (temp_sensor->hwmon_dev)
> + /* kobject_uvent to user space telling threshold crossed */
> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
> +
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
> + struct omap_temp_sensor *temp_sensor;
> + struct resource *mem;
> + int ret = 0;
> + int clk_rate;
> + u32 max_freq, min_freq;
> +
> + if (!pdata) {
> + dev_err(&pdev->dev, "platform data missing\n");
> + return -EINVAL;
> + }
> +
> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
> + if (!temp_sensor) {
> + dev_err(&pdev->dev, "Memory allocation failed\n");
> + return -ENOMEM;
> + }
> +
> + mutex_init(&temp_sensor->sensor_mutex);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&pdev->dev, "no mem resource\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
> + if (temp_sensor->irq < 0) {
> + dev_err(&pdev->dev, "get_irq_byname failed\n");
> + ret = temp_sensor->irq;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
> + if (!temp_sensor->phy_base) {
> + dev_err(&pdev->dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->clock = NULL;
> + temp_sensor->registers = pdata->registers;
> + temp_sensor->pdev_dev = &pdev->dev;
> +
> + if (pdata->max_freq && pdata->min_freq) {
> + max_freq = pdata->max_freq;
> + min_freq = pdata->min_freq;
> + } else {
> + max_freq = MAX_FREQ;
> + min_freq = MIN_FREQ;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_irq_safe(&pdev->dev);
> +
> + /*
> + * check if the efuse has a non-zero value if not
> + * it is an untrimmed sample and the temperatures
> + * may not be accurate
> + */
> +
> + if (omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_efuse))
> + dev_info(&pdev->dev,
> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
> +
> + dev_set_drvdata(&pdev->dev, temp_sensor);
> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
> + if (IS_ERR(temp_sensor->clock)) {
> + ret = PTR_ERR(temp_sensor->clock);
> + dev_err(&pdev->dev,
> + "unable to get fclk: %d\n", ret);
> + goto plat_res_err;
> + }
> +
> + ret = omap_temp_sensor_clk_enable(temp_sensor);
> + if (ret)
> + goto clken_err;
> +
> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
> + if (clk_rate < min_freq || clk_rate == 0xffffffff) {
> + ret = -ENODEV;
> + goto clken_err;
> + }
> +
> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
> + if (ret) {
> + dev_err(&pdev->dev, "Cannot set clock rate\n");
> + goto clken_err;
> + }
> +
> + temp_sensor->clk_rate = clk_rate;
> + omap_enable_continuous_mode(temp_sensor);
> + /* 1 clk cycle */
> + omap_configure_temp_sensor_counter(temp_sensor, 1);
> +
> + /* Wait till the first conversion is done wait for at least 1ms */
> + usleep_range(1000, 2000);
> +
> + /* Read the temperature once due to hw issue*/
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> +
> + /* Set 2 seconds time as default counter */
> + omap_configure_temp_sensor_counter(temp_sensor,
> + temp_sensor->clk_rate * 2);
> +
> + ret = request_threaded_irq(temp_sensor->irq, NULL,
> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> + "temp_sensor", temp_sensor);
> + if (ret) {
> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
> + goto req_irq_err;
> + }
> +
> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
> + if (ret) {
> + dev_err(&pdev->dev, "could not create sysfs files\n");
> + goto sysfs_create_err;
> + }
> +
> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
> + if (IS_ERR(temp_sensor->hwmon_dev)) {
> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
> + ret = PTR_ERR(temp_sensor->hwmon_dev);
> + goto hwmon_reg_err;
> + }
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
> + T_HOT, T_COLD);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return 0;
> +
> +hwmon_reg_err:
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> +sysfs_create_err:
> + free_irq(temp_sensor->irq, temp_sensor);
> +req_irq_err:
> + omap_temp_sensor_clk_disable(temp_sensor);
> +clken_err:
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> +plat_res_err:
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> + return ret;
> +}
> +
> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
> +
> + hwmon_device_unregister(&pdev->dev);
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> + free_irq(temp_sensor->irq, temp_sensor);
> + omap_temp_sensor_clk_disable(temp_sensor);
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp_sensor->temp_sensor_tshut_threshold =
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_ctrl,
> + temp_sensor->registers->temp_sensor_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_ctrl,
> + temp_sensor->registers->bgap_mask_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_counter,
> + temp_sensor->registers->bgap_counter);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_threshold,
> + temp_sensor->registers->bgap_threshold);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_tshut_threshold,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static int omap_temp_sensor_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_resume(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_resume(struct device *dev)
> +{
> + static int context_loss_count;
> + int temp;
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
> +
> + if (temp != context_loss_count && context_loss_count != 0)
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + context_loss_count = temp;
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_idle(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
> + omap_temp_sensor_resume)
> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
> +};
> +
> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
> +#else
> +#define DEV_PM_OPS NULL
> +#endif
> +
> +static struct platform_driver omap_temp_sensor_driver = {
> + .probe = omap_temp_sensor_probe,
> + .remove = omap_temp_sensor_remove,
> + .driver = {
> + .name = "omap_temp_sensor",
> + .pm = DEV_PM_OPS,
> + },
> +};
> +
> +int __init omap_temp_sensor_init(void)
> +{
> + return platform_driver_register(&omap_temp_sensor_driver);
> +}
> +module_init(omap_temp_sensor_init);
> +
> +static void __exit omap_temp_sensor_exit(void)
> +{
> + platform_driver_unregister(&omap_temp_sensor_driver);
> +}
> +module_exit(omap_temp_sensor_exit);
> +
> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
- Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-01 0:36 ` Paul Walmsley
0 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 0:36 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
Hi
Some comments.
On Wed, 31 Aug 2011, Keerthy wrote:
> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
> new file mode 100644
> index 0000000..67fa424
> --- /dev/null
> +++ b/drivers/hwmon/omap_temp_sensor.c
> @@ -0,0 +1,881 @@
You've done almost all the hard work to create kerneldoc-NANO compliant
structure documentation, which is good. But a few important things are
missing. Please review Documentation/kernel-doc-nano-HOWTO.txt.
> +/*
Should be /** to indicate kerneldoc.
> + * omap_temp_sensor structure
Should be "struct omap_temp_sensor" and should include a short
description.
> + * @hwmon_dev - hwmon device pointer
> + * @pdev_dev - platform device pointer
> + * @clock - Clock pointer
> + * @registers - Pointer to structure with register offsets and bitfields
> + * @sensor_mutex - Mutex for sysfs, irq and PM
> + * @irq - MPU Irq number for thermal alert
> + * @phy_base - Physical base of the temp I/O
> + * @clk_rate - Holds current clock rate
> + * @temp_sensor_ctrl - temp sensor control register value
> + * @bg_ctrl - bandgap ctrl register value
> + * @bg_counter - bandgap counter value
> + * @bg_threshold - bandgap threshold register value
> + * @temp_sensor_tshut_threshold - bandgap tshut register value
> + * @clk_on - Manages the current clock state
> + */
> +struct omap_temp_sensor {
> + struct device *hwmon_dev;
> + struct device *pdev_dev;
> + struct clk *clock;
> + struct omap_temp_sensor_registers *registers;
> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
> + unsigned int irq;
> + void __iomem *phy_base;
> + u32 clk_rate;
> + u32 temp_sensor_ctrl;
> + u32 bg_ctrl;
> + u32 bg_counter;
> + u32 bg_threshold;
> + u32 temp_sensor_tshut_threshold;
> + bool clk_on;
> +};
> +
> +/*
> + * Temperature values in milli degree celsius
> + * ADC code values from 530 to 923
> + */
> +static int adc_to_temp[394] = {
> + -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
> +};
> +
> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
> + *temp_sensor, u32 reg)
> +{
> + return __raw_readl(temp_sensor->phy_base + reg);
> +}
> +
> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
> + u32 val, u32 reg)
> +{
> + __raw_writel(val, temp_sensor->phy_base + reg);
> +}
These are all SCM register accesses and need to go through a SCM driver.
> +
> +static int adc_to_temp_conversion(int adc_val)
> +{
> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
> +}
> +
> +static int temp_to_adc_conversion(long temp)
> +{
> + int high, low, mid;
> +
> + if (temp < adc_to_temp[0] ||
> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
> + return -EINVAL;
> +
> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
> + low = 0;
> + mid = (high + low) / 2;
> +
> + while (low < high) {
> + if (temp < adc_to_temp[mid])
> + high = mid - 1;
> + else
> + low = mid + 1;
> + mid = (low + high) / 2;
> + }
> +
> + return OMAP_ADC_START_VALUE + low;
> +}
> +
> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
> + *temp_sensor, u32 counter)
It doesn't seem necessary to include 'omap' in all these static function names.
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + val &= ~temp_sensor->registers->counter_mask;
> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_counter);
> +}
> +
> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mode_ctrl);
> +
> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
> +
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_mode_ctrl);
> +}
> +
> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
> + *temp_sensor, u8 hot, u8 cold)
Your earlier static function names didn't include 'temp_sensor', but
this one does. I'd suggest picking a standard function naming scheme
and sticking to it.
> +{
> + u32 reg_val;
> +
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + if (hot)
> + reg_val |= temp_sensor->registers->mask_hot_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
> +
> + if (cold)
> + reg_val |= temp_sensor->registers->mask_cold_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
> +
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_mask_ctrl);
> +}
> +
> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
> +{
> + int temp = adc_to_temp_conversion(adc_val);
> +
> + temp += hyst_val;
> +
> + *thresh_val = temp_to_adc_conversion(temp);
> +}
> +
> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
Is there some reason why you don't just define a
omap_temp_sensor_configure_hot_threshold()
and
omap_temp_sensor_configure_cold_threshold()
?
Seems like that would be much more straightforward and would allow the
removal of those set_{hot,cold} arguments.
> +{
> + int reg_val, cold, hot, temp;
This function is really big and should be split up into several smaller
functions. Common code should be shared if possible.
> +
> + if (set_hot) {
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
This code should be hoisted up above the if statements. Only a single
device read should be necessary to fetch both the hot and cold values.
Then the near-duplicate code below to read the hot temperature can be
removed.
In fact, given that this patch has almost the same code several times,
you should just put it into a static function or two and remove the
duplicate code.
> +
> + if (t_hot < cold) {
> + /* change the t_cold to t_hot - 5000 millidegrees */
> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &> + ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
Looks like there are some indentation problems here. Those are more
important than 80-column issues.
Of course, you use temp_sensor->registers so much in this function, that
many of the line length issues would go away if you used a shorter
abbreviation at the beginning of this function, like:
tsr = temp_sensor->registers;
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_cold = cold;
> + }
> +
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (t_hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> +
> + if (set_cold) {
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
See the earlier comment about hoisting.
> + if (t_cold > hot) {
> + /* change the t_hot to t_cold + 5000 millidegrees */
> + add_hyst(t_cold, HYST_VAL, &hot);
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &> + ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
This is a duplicate of earlier code. Please consolidate.
> + t_hot = hot;
> + }
> +
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= t_cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> +
> + /* Read the current temperature */
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /*
> + * If current temperature is in-between the hot and cold thresholds
> + * Enable both masks or in the init case enable both masks
> + */
> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> +
> + /*
> + * If user sets the HIGH threshold(t_hot) greater than the current
> + * temperature(temp) unmask the HOT interrupts
> + */
> + else if (hot > temp)
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> +
> + /*
> + * If user sets the LOW threshold(t_cold) lower than the current
> + * temperature(temp) unmask the COLD interrupts
> + */
> + else
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
This if statement is surely a violation of the spirit of
Documentation/CodingStyle, if not the text itself.
If you really need an if statement like this, try something like:
if ((temp > cold && temp < hot) || (set_cold && set_hot)) {
/*
* If current temperature is in-between the hot and cold thresholds
* Enable both masks or in the init case enable both masks
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
} else if (hot > temp) {
/*
* If user sets the HIGH threshold(t_hot) greater than the current
* temperature(temp) unmask the HOT interrupts
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
} else {
/*
* If user sets the LOW threshold(t_cold) lower than the current
* temperature(temp) unmask the COLD interrupts
*/
omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
}
> +}
> +
> +/* Sysfs hook functions */
These should be conditionally compiled out if sysfs isn't compiled in.
> +
> +static ssize_t show_temp_max(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> + u32 t_hot;
> +
> + if (strict_strtol(buf, 10, &val))
> + return -EINVAL;
> + if (val < MIN_TEMP - HYST_VAL)
> + return -EINVAL;
> +
> + t_hot = temp_to_adc_conversion(val);
> + if (t_hot < 0)
> + return t_hot;
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
> + t_hot, 0);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return count;
> +}
> +
> +static ssize_t show_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
> + dev_err(dev, "invalid value\n");
> + return -EIO;
> + }
> +
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 t_cold;
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + if (val > MAX_TEMP - HYST_VAL) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + t_cold = temp_to_adc_conversion(val);
> + if (t_cold < 0)
> + return t_cold;
> +
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
> + t_cold);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> +out:
> + return count;
> +}
> +
> +static ssize_t show_update_interval(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp = (temp & temp_sensor->registers->counter_mask) >>
> + __ffs(temp_sensor->registers->counter_mask);
> + temp = temp * 1000 / temp_sensor->clk_rate;
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static ssize_t set_update_interval(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
> +
> + if (val < 0)
> + return -EINVAL;
> + val *= temp_sensor->clk_rate / 1000;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_configure_temp_sensor_counter(temp_sensor, val);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +out:
> + return count;
> +}
> +
> +static int omap_temp_sensor_read_temp(struct device *dev,
> + struct device_attribute *devattr,
> + char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /* look up for temperature in the table and return the temperature */
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
> + return -EIO;
> +
> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
> + NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
> + set_temp_max, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
> + set_temp_max_hyst, 0);
> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
> + show_update_interval, set_update_interval, 0);
> +
> +static struct attribute *omap_temp_sensor_attributes[] = {
> + &sensor_dev_attr_temp1_input.dev_attr.attr,
> + &sensor_dev_attr_temp1_max.dev_attr.attr,
> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> + &sensor_dev_attr_update_interval.dev_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group omap_temp_sensor_group = {
> + .attrs = omap_temp_sensor_attributes,
> +};
> +
> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 ret = 0;
> +
> + if (temp_sensor->clk_on) {
> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
> + goto out;
> + }
> +
> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
> + if (ret < 0) {
> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
> + goto out;
> + }
> +
> + temp_sensor->clk_on = 1;
> +
> +out:
> + return ret;
> +}
> +
> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
> +{
> + /* Gate the clock */
> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
> + temp_sensor->clk_on = 0;
> +}
> +
> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
> +{
> + struct omap_temp_sensor *temp_sensor;
> + int t_hot, t_cold, temp;
> +
> + temp_sensor = data;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + /* Read the status of t_hot */
> + t_hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_hot_mask;
> +
> + /* Read the status of t_cold */
> + t_cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_cold_mask;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->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) {
> + temp &= ~temp_sensor->registers->mask_hot_mask;
> + temp |= temp_sensor->registers->mask_cold_mask;
> + } else if (t_cold) {
> + temp &= ~temp_sensor->registers->mask_cold_mask;
> + temp |= temp_sensor->registers->mask_hot_mask;
> + }
> +
> + omap_temp_sensor_writel(temp_sensor, temp,
> + temp_sensor->registers->bgap_mask_ctrl);
> +
> + if (temp_sensor->hwmon_dev)
> + /* kobject_uvent to user space telling threshold crossed */
> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
> +
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
> + struct omap_temp_sensor *temp_sensor;
> + struct resource *mem;
> + int ret = 0;
> + int clk_rate;
> + u32 max_freq, min_freq;
> +
> + if (!pdata) {
> + dev_err(&pdev->dev, "platform data missing\n");
> + return -EINVAL;
> + }
> +
> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
> + if (!temp_sensor) {
> + dev_err(&pdev->dev, "Memory allocation failed\n");
> + return -ENOMEM;
> + }
> +
> + mutex_init(&temp_sensor->sensor_mutex);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&pdev->dev, "no mem resource\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
> + if (temp_sensor->irq < 0) {
> + dev_err(&pdev->dev, "get_irq_byname failed\n");
> + ret = temp_sensor->irq;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
> + if (!temp_sensor->phy_base) {
> + dev_err(&pdev->dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->clock = NULL;
> + temp_sensor->registers = pdata->registers;
> + temp_sensor->pdev_dev = &pdev->dev;
> +
> + if (pdata->max_freq && pdata->min_freq) {
> + max_freq = pdata->max_freq;
> + min_freq = pdata->min_freq;
> + } else {
> + max_freq = MAX_FREQ;
> + min_freq = MIN_FREQ;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_irq_safe(&pdev->dev);
> +
> + /*
> + * check if the efuse has a non-zero value if not
> + * it is an untrimmed sample and the temperatures
> + * may not be accurate
> + */
> +
> + if (omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_efuse))
> + dev_info(&pdev->dev,
> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
> +
> + dev_set_drvdata(&pdev->dev, temp_sensor);
> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
> + if (IS_ERR(temp_sensor->clock)) {
> + ret = PTR_ERR(temp_sensor->clock);
> + dev_err(&pdev->dev,
> + "unable to get fclk: %d\n", ret);
> + goto plat_res_err;
> + }
> +
> + ret = omap_temp_sensor_clk_enable(temp_sensor);
> + if (ret)
> + goto clken_err;
> +
> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
> + if (clk_rate < min_freq || clk_rate = 0xffffffff) {
> + ret = -ENODEV;
> + goto clken_err;
> + }
> +
> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
> + if (ret) {
> + dev_err(&pdev->dev, "Cannot set clock rate\n");
> + goto clken_err;
> + }
> +
> + temp_sensor->clk_rate = clk_rate;
> + omap_enable_continuous_mode(temp_sensor);
> + /* 1 clk cycle */
> + omap_configure_temp_sensor_counter(temp_sensor, 1);
> +
> + /* Wait till the first conversion is done wait for at least 1ms */
> + usleep_range(1000, 2000);
> +
> + /* Read the temperature once due to hw issue*/
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> +
> + /* Set 2 seconds time as default counter */
> + omap_configure_temp_sensor_counter(temp_sensor,
> + temp_sensor->clk_rate * 2);
> +
> + ret = request_threaded_irq(temp_sensor->irq, NULL,
> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> + "temp_sensor", temp_sensor);
> + if (ret) {
> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
> + goto req_irq_err;
> + }
> +
> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
> + if (ret) {
> + dev_err(&pdev->dev, "could not create sysfs files\n");
> + goto sysfs_create_err;
> + }
> +
> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
> + if (IS_ERR(temp_sensor->hwmon_dev)) {
> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
> + ret = PTR_ERR(temp_sensor->hwmon_dev);
> + goto hwmon_reg_err;
> + }
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
> + T_HOT, T_COLD);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return 0;
> +
> +hwmon_reg_err:
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> +sysfs_create_err:
> + free_irq(temp_sensor->irq, temp_sensor);
> +req_irq_err:
> + omap_temp_sensor_clk_disable(temp_sensor);
> +clken_err:
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> +plat_res_err:
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> + return ret;
> +}
> +
> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
> +
> + hwmon_device_unregister(&pdev->dev);
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> + free_irq(temp_sensor->irq, temp_sensor);
> + omap_temp_sensor_clk_disable(temp_sensor);
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp_sensor->temp_sensor_tshut_threshold > + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_ctrl,
> + temp_sensor->registers->temp_sensor_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_ctrl,
> + temp_sensor->registers->bgap_mask_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_counter,
> + temp_sensor->registers->bgap_counter);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_threshold,
> + temp_sensor->registers->bgap_threshold);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_tshut_threshold,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static int omap_temp_sensor_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_resume(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_resume(struct device *dev)
> +{
> + static int context_loss_count;
> + int temp;
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
> +
> + if (temp != context_loss_count && context_loss_count != 0)
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + context_loss_count = temp;
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_idle(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
> + omap_temp_sensor_resume)
> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
> +};
> +
> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
> +#else
> +#define DEV_PM_OPS NULL
> +#endif
> +
> +static struct platform_driver omap_temp_sensor_driver = {
> + .probe = omap_temp_sensor_probe,
> + .remove = omap_temp_sensor_remove,
> + .driver = {
> + .name = "omap_temp_sensor",
> + .pm = DEV_PM_OPS,
> + },
> +};
> +
> +int __init omap_temp_sensor_init(void)
> +{
> + return platform_driver_register(&omap_temp_sensor_driver);
> +}
> +module_init(omap_temp_sensor_init);
> +
> +static void __exit omap_temp_sensor_exit(void)
> +{
> + platform_driver_unregister(&omap_temp_sensor_driver);
> +}
> +module_exit(omap_temp_sensor_exit);
> +
> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
- Paul
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 0:36 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
@ 2011-09-01 1:49 ` Guenter Roeck
-1 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 1:49 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> Hi
>
> Some comments.
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
[ ... ]
>
> > +}
> > +
> > +/* Sysfs hook functions */
>
> These should be conditionally compiled out if sysfs isn't compiled in.
>
The whole point of the hwmon subsystem is to expose hardware monitoring information
to userland using sysfs. hwmon without sysfs doesn't make sense.
So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
But please no conditionals in the code.
Guenter
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-01 1:49 ` Guenter Roeck
0 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 1:49 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> Hi
>
> Some comments.
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
[ ... ]
>
> > +}
> > +
> > +/* Sysfs hook functions */
>
> These should be conditionally compiled out if sysfs isn't compiled in.
>
The whole point of the hwmon subsystem is to expose hardware monitoring information
to userland using sysfs. hwmon without sysfs doesn't make sense.
So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
But please no conditionals in the code.
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields
2011-09-01 0:04 ` Paul Walmsley
@ 2011-09-01 2:57 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-01 2:57 UTC (permalink / raw)
To: Paul Walmsley; +Cc: linux-omap, tony
On Thu, Sep 1, 2011 at 5:34 AM, Paul Walmsley <paul@pwsan.com> wrote:
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> OMAP4460 specific temperature sensor register bit fields are added.
>> Existing OMAP4 entries are renamed to OMAP4430.
>>
>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>> Cc: tony@atomide.com
>
> At least one of these bitfields are incorrect. Please double-check them.
>
>> ---
>> .../include/mach/ctrl_module_core_44xx.h | 70 ++++++++++++++++----
>> 1 files changed, 57 insertions(+), 13 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
>> index 2f7ac70..725c1e1 100644
>> --- a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
>> +++ b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
>> @@ -256,19 +256,63 @@
>> #define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT 0
>> #define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK (0x1f << 0)
>>
>> -/* TEMP_SENSOR */
>> -#define OMAP4_BGAP_TEMPSOFF_SHIFT 12
>> -#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 12)
>> -#define OMAP4_BGAP_TSHUT_SHIFT 11
>> -#define OMAP4_BGAP_TSHUT_MASK (1 << 11)
>> -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
>> -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
>> -#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 9
>> -#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
>> -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
>> -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
>> -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
>> -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
>> +/* TEMP_SENSOR OMAP4430 */
>> +#define OMAP4430_BGAP_TEMPSOFF_SHIFT 12
>> +#define OMAP4430_BGAP_TEMPSOFF_MASK (1 << 12)
>> +#define OMAP4430_BGAP_TSHUT_SHIFT 11
>> +#define OMAP4430_BGAP_TSHUT_MASK (1 << 11)
>> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
>> +#define OMAP4430_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
>> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_SHIFT 9
>> +#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
>> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
>> +#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
>> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
>> +#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
>
> For example, this bitfield is only eight bits wide on 4430.
I checked the 4430 TRM. It is 8 bits and the others are fine.
I will correct this.
>
>> +
>> +/* TEMP_SENSOR OMAP4460 */
>> +#define OMAP4460_BGAP_TEMPSOFF_SHIFT 13
>> +#define OMAP4460_BGAP_TEMPSOFF_MASK (1 << 13)
>> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_SHIFT 11
>> +#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11)
>> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
>> +#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
>> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
>> +#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
>> +
>> +/* BANDGAP_CTRL */
>> +#define OMAP4460_SINGLE_MODE_SHIFT 31
>> +#define OMAP4460_SINGLE_MODE_MASK (1 << 31)
>> +#define OMAP4460_MASK_HOT_SHIFT 1
>> +#define OMAP4460_MASK_HOT_MASK (1 << 1)
>> +#define OMAP4460_MASK_COLD_SHIFT 0
>> +#define OMAP4460_MASK_COLD_MASK (1 << 0)
>> +
>> +/* BANDGAP_COUNTER */
>> +#define OMAP4460_COUNTER_SHIFT 0
>> +#define OMAP4460_COUNTER_MASK (0xffffff << 0)
>> +
>> +/* BANDGAP_THRESHOLD */
>> +#define OMAP4460_T_HOT_SHIFT 16
>> +#define OMAP4460_T_HOT_MASK (0x3ff << 16)
>> +#define OMAP4460_T_COLD_SHIFT 0
>> +#define OMAP4460_T_COLD_MASK (0x3ff << 0)
>> +
>> +/* TSHUT_THRESHOLD */
>> +#define OMAP4460_TSHUT_HOT_SHIFT 16
>> +#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
>> +#define OMAP4460_TSHUT_COLD_SHIFT 0
>> +#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
>> +
>> +/* BANDGAP_STATUS */
>> +#define OMAP4460_CLEAN_STOP_SHIFT 3
>> +#define OMAP4460_CLEAN_STOP_MASK (1 << 3)
>> +#define OMAP4460_BGAP_ALERT_SHIFT 2
>> +#define OMAP4460_BGAP_ALERT_MASK (1 << 2)
>> +#define OMAP4460_HOT_FLAG_SHIFT 1
>> +#define OMAP4460_HOT_FLAG_MASK (1 << 1)
>> +#define OMAP4460_COLD_FLAG_SHIFT 0
>> +#define OMAP4460_COLD_FLAG_MASK (1 << 0)
>>
>> /* DPLL_NWELL_TRIM_0 */
>> #define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT 29
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> - Paul
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 1:49 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
@ 2011-09-01 4:09 ` Paul Walmsley
-1 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 4:09 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Wed, 31 Aug 2011, Guenter Roeck wrote:
> On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> > Hi
> >
> > Some comments.
> >
> > On Wed, 31 Aug 2011, Keerthy wrote:
> >
> [ ... ]
> >
> > > +}
> > > +
> > > +/* Sysfs hook functions */
> >
> > These should be conditionally compiled out if sysfs isn't compiled in.
> >
> The whole point of the hwmon subsystem is to expose hardware monitoring information
> to userland using sysfs. hwmon without sysfs doesn't make sense.
>
> So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> But please no conditionals in the code.
Hmm. This IP block is more than just a sensor. It also can interrupt the
CPU and/or trigger a GPIO line (to shut down the chip) if the chip
temperature crosses some thresholds. On some OMAPs, the thresholds are
fixed; on others, they are software-programmable. That functionality
shouldn't require sysfs; it's almost closer to an x86 MCE.
So based on your comments, it sounds like we should move that part of the
code to a different driver, and just leave the basic software thermal
monitoring here?
- Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-01 4:09 ` Paul Walmsley
0 siblings, 0 replies; 43+ messages in thread
From: Paul Walmsley @ 2011-09-01 4:09 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Wed, 31 Aug 2011, Guenter Roeck wrote:
> On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> > Hi
> >
> > Some comments.
> >
> > On Wed, 31 Aug 2011, Keerthy wrote:
> >
> [ ... ]
> >
> > > +}
> > > +
> > > +/* Sysfs hook functions */
> >
> > These should be conditionally compiled out if sysfs isn't compiled in.
> >
> The whole point of the hwmon subsystem is to expose hardware monitoring information
> to userland using sysfs. hwmon without sysfs doesn't make sense.
>
> So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> But please no conditionals in the code.
Hmm. This IP block is more than just a sensor. It also can interrupt the
CPU and/or trigger a GPIO line (to shut down the chip) if the chip
temperature crosses some thresholds. On some OMAPs, the thresholds are
fixed; on others, they are software-programmable. That functionality
shouldn't require sysfs; it's almost closer to an x86 MCE.
So based on your comments, it sounds like we should move that part of the
code to a different driver, and just leave the basic software thermal
monitoring here?
- Paul
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
@ 2011-09-01 4:38 ` Guenter Roeck
-1 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 4:38 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, lm-sensors
On Wed, Aug 31, 2011 at 01:25:10PM -0400, Keerthy wrote:
> On chip temperature sensor driver. The driver monitors the temperature of
> the MPU subsystem of the OMAP4. It sends notifications to the user space if
> the temperature crosses user defined thresholds via kobject_uevent interface.
> The user is allowed to configure the temperature thresholds vis sysfs nodes
> exposed using hwmon interface.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Cc: Jean Delvare <khali@linux-fr.org>
> Cc: Guenter Roeck <guenter.roeck@ericsson.com>
> Cc: lm-sensors@lm-sensors.org
> ---
> Documentation/hwmon/omap_temp_sensor | 26 +
> drivers/hwmon/Kconfig | 11 +
> drivers/hwmon/Makefile | 1 +
> drivers/hwmon/omap_temp_sensor.c | 881 ++++++++++++++++++++++++++++++++++
> 4 files changed, 919 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/hwmon/omap_temp_sensor
> create mode 100644 drivers/hwmon/omap_temp_sensor.c
>
> diff --git a/Documentation/hwmon/omap_temp_sensor b/Documentation/hwmon/omap_temp_sensor
> new file mode 100644
> index 0000000..357f09a
> --- /dev/null
> +++ b/Documentation/hwmon/omap_temp_sensor
> @@ -0,0 +1,26 @@
> +Kernel driver omap_temp_sensor
> +==============================
> +
> +Supported chips:
> + * Texas Instruments OMAP4460
> + Prefix: 'omap_temp_sensor'
> +
> +Author:
> + J Keerthy <j-keerthy@ti.com>
> +
> +Description
> +-----------
> +
> +The Texas Instruments OMAP4 family of chips have a bandgap temperature sensor.
> +The temperature sensor feature is used to convert the temperature of the device
> +into a decimal value coded on 10 bits. An internal ADC is used for conversion.
> +The recommended operating temperatures must be in the range -40 degree Celsius
> +to 123 degree celsius for standard conversion.
> +The thresholds are programmable and upon crossing the thresholds an interrupt
> +is generated. The OMAP temperature sensor has a programmable update rate in
> +milli seconds.
> +(Currently the driver programs a default of 2000 milliseconds).
> +
> +The driver provides the common sysfs-interface for temperatures (see
> +Documentation/hwmon/sysfs-interface under Temperatures).
> +
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 5f888f7..9c9cd8b 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -323,6 +323,17 @@ config SENSORS_F71805F
> This driver can also be built as a module. If so, the module
> will be called f71805f.
>
> +config SENSORS_OMAP_BANDGAP_TEMP_SENSOR
> + bool "OMAP on-die temperature sensor hwmon driver"
> + depends on HWMON && ARCH_OMAP && OMAP_TEMP_SENSOR
> + help
> + If you say yes here you get support for hardware
> + monitoring features of the OMAP on die temperature
> + sensor.
> +
> + Continuous conversion programmable delay
> + mode is used for temperature conversion.
> +
> config SENSORS_F71882FG
> tristate "Fintek F71882FG and compatibles"
> help
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 28061cf..d0f89f5 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -91,6 +91,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
> obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
> obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
> obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
> +obj-$(CONFIG_SENSORS_OMAP_BANDGAP_TEMP_SENSOR) += omap_temp_sensor.o
> obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
> obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
> obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
> new file mode 100644
> index 0000000..67fa424
> --- /dev/null
> +++ b/drivers/hwmon/omap_temp_sensor.c
> @@ -0,0 +1,881 @@
> +/*
> + * OMAP4 Temperature sensor driver file
> + *
> + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> + * Author: J Keerthy <j-keerthy@ti.com>
> + * Author: Moiz Sonasath <m-sonasath@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/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <plat/omap_device.h>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/jiffies.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/stddef.h>
> +#include <linux/sysfs.h>
> +#include <linux/err.h>
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/delay.h>
> +#include <plat/temperature_sensor.h>
> +
> +#define TSHUT_HOT 920 /* 122 deg C */
> +#define TSHUT_COLD 866 /* 100 deg C */
> +#define T_HOT 800 /* 73 deg C */
> +#define T_COLD 795 /* 71 deg C */
> +#define OMAP_ADC_START_VALUE 530
> +#define OMAP_ADC_END_VALUE 923
> +#define MAX_FREQ 2000000
> +#define MIN_FREQ 1000000
> +#define MIN_TEMP -40000
> +#define MAX_TEMP 123000
> +#define HYST_VAL 5000
> +#define NEG_HYST_VAL -5000
> +/*
> + * omap_temp_sensor structure
> + * @hwmon_dev - hwmon device pointer
> + * @pdev_dev - platform device pointer
> + * @clock - Clock pointer
> + * @registers - Pointer to structure with register offsets and bitfields
> + * @sensor_mutex - Mutex for sysfs, irq and PM
> + * @irq - MPU Irq number for thermal alert
> + * @phy_base - Physical base of the temp I/O
> + * @clk_rate - Holds current clock rate
> + * @temp_sensor_ctrl - temp sensor control register value
> + * @bg_ctrl - bandgap ctrl register value
> + * @bg_counter - bandgap counter value
> + * @bg_threshold - bandgap threshold register value
> + * @temp_sensor_tshut_threshold - bandgap tshut register value
> + * @clk_on - Manages the current clock state
> + */
> +struct omap_temp_sensor {
> + struct device *hwmon_dev;
> + struct device *pdev_dev;
> + struct clk *clock;
> + struct omap_temp_sensor_registers *registers;
> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
> + unsigned int irq;
> + void __iomem *phy_base;
> + u32 clk_rate;
> + u32 temp_sensor_ctrl;
> + u32 bg_ctrl;
> + u32 bg_counter;
> + u32 bg_threshold;
> + u32 temp_sensor_tshut_threshold;
> + bool clk_on;
> +};
> +
> +/*
> + * Temperature values in milli degree celsius
> + * ADC code values from 530 to 923
> + */
> +static int adc_to_temp[394] = {
[OMAP_ADC_END_VALUE - OMAP_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
> +};
> +
> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
> + *temp_sensor, u32 reg)
Why unsigned long ? Result is lways assigned to u32 or int.
> +{
> + return __raw_readl(temp_sensor->phy_base + reg);
> +}
> +
> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
> + u32 val, u32 reg)
> +{
> + __raw_writel(val, temp_sensor->phy_base + reg);
> +}
> +
> +static int adc_to_temp_conversion(int adc_val)
> +{
> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
> +}
> +
> +static int temp_to_adc_conversion(long temp)
> +{
> + int high, low, mid;
> +
> + if (temp < adc_to_temp[0] ||
> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
> + return -EINVAL;
> +
> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
> + low = 0;
> + mid = (high + low) / 2;
> +
> + while (low < high) {
> + if (temp < adc_to_temp[mid])
> + high = mid - 1;
> + else
> + low = mid + 1;
> + mid = (low + high) / 2;
> + }
> +
> + return OMAP_ADC_START_VALUE + low;
> +}
> +
> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
> + *temp_sensor, u32 counter)
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + val &= ~temp_sensor->registers->counter_mask;
> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_counter);
> +}
> +
> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
> +{
Please add a comment to functions which need to be called during initialization or
protected by the mutex.
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mode_ctrl);
> +
> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
> +
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_mode_ctrl);
> +}
> +
> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
> + *temp_sensor, u8 hot, u8 cold)
> +{
> + u32 reg_val;
> +
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + if (hot)
> + reg_val |= temp_sensor->registers->mask_hot_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
> +
> + if (cold)
> + reg_val |= temp_sensor->registers->mask_cold_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
> +
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_mask_ctrl);
> +}
> +
> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
> +{
> + int temp = adc_to_temp_conversion(adc_val);
> +
> + temp += hyst_val;
> +
> + *thresh_val = temp_to_adc_conversion(temp);
> +}
> +
Since you return a void, you can as well return the new value and drop the
pointer.
> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
> +{
> + int reg_val, cold, hot, temp;
> +
Why int here ?
> + if (set_hot) {
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (t_hot < cold) {
> + /* change the t_cold to t_hot - 5000 millidegrees */
> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
You might just use -HYST_VAL here.
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &=
> + ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_cold = cold;
> + }
> +
t_hot == cold: t_hot will be equal to t_cold
t_hot > t_colt: t_hot > t_cold, any difference
t_hot < t_cold: t_cold == t_hot - NEG_HYST_VAL
Seems to be inconsistent, and it seems that the condition t_hot == t_cold can still occur
(which you mentioned earlier would be invalid). If you want to define a minimum hysteresis,
you should enforce it by modifying the if statement.
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (t_hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> +
> + if (set_cold) {
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> + if (t_cold > hot) {
> + /* change the t_hot to t_cold + 5000 millidegrees */
> + add_hyst(t_cold, HYST_VAL, &hot);
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &=
> + ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_hot = hot;
> + }
> +
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= t_cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> +
> + /* Read the current temperature */
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /*
> + * If current temperature is in-between the hot and cold thresholds
> + * Enable both masks or in the init case enable both masks
> + */
> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> +
> + /*
> + * If user sets the HIGH threshold(t_hot) greater than the current
> + * temperature(temp) unmask the HOT interrupts
> + */
> + else if (hot > temp)
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> +
> + /*
> + * If user sets the LOW threshold(t_cold) lower than the current
> + * temperature(temp) unmask the COLD interrupts
> + */
> + else
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
> +}
> +
> +/* Sysfs hook functions */
> +
> +static ssize_t show_temp_max(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> + u32 t_hot;
> +
> + if (strict_strtol(buf, 10, &val))
> + return -EINVAL;
> + if (val < MIN_TEMP - HYST_VAL)
> + return -EINVAL;
MIN_TEMP + HYST_VAL ?
> +
> + t_hot = temp_to_adc_conversion(val);
> + if (t_hot < 0)
> + return t_hot;
Difficuly to accomplish since t_hot is u32.
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
> + t_hot, 0);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return count;
> +}
> +
> +static ssize_t show_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
> + dev_err(dev, "invalid value\n");
> + return -EIO;
> + }
> +
> + temp = adc_to_temp_conversion(temp);
> +
adc_to_temp_conversion can return a negative value.
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 t_cold;
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
Just return -EINVAL.
> +
> + if (val > MAX_TEMP - HYST_VAL) {
> + count = -EINVAL;
> + goto out;
Just return -EINVAL here.
> + }
> +
> + t_cold = temp_to_adc_conversion(val);
> + if (t_cold < 0)
> + return t_cold;
> +
t_cold is u32 and will never be < 0. Wondering ... doesn't gcc complain about this ?
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
> + t_cold);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> +out:
> + return count;
> +}
> +
> +static ssize_t show_update_interval(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp = (temp & temp_sensor->registers->counter_mask) >>
> + __ffs(temp_sensor->registers->counter_mask);
> + temp = temp * 1000 / temp_sensor->clk_rate;
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static ssize_t set_update_interval(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
Just return -EINVAL.
> +
> + if (val < 0)
> + return -EINVAL;
If values < 0 are not valid, might as well use strict_strtoul() above.
> + val *= temp_sensor->clk_rate / 1000;
Divide happens first here. Loss of accuracy not a problem ?
Also, no max value, and 0 is ok ?
Large values may result in negative counter values if someone enters a large number.
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_configure_temp_sensor_counter(temp_sensor, val);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +out:
> + return count;
> +}
> +
> +static int omap_temp_sensor_read_temp(struct device *dev,
> + struct device_attribute *devattr,
> + char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /* look up for temperature in the table and return the temperature */
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
> + return -EIO;
> +
> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
> +
Use adc_to_temp_conversion().
> + return sprintf(buf, "%d\n", temp);
return sprintf(buf, "%d\n", adc_to_temp_conversion(temp));
might be a bit simpler.
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
> + NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
> + set_temp_max, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
> + set_temp_max_hyst, 0);
> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
> + show_update_interval, set_update_interval, 0);
> +
> +static struct attribute *omap_temp_sensor_attributes[] = {
> + &sensor_dev_attr_temp1_input.dev_attr.attr,
> + &sensor_dev_attr_temp1_max.dev_attr.attr,
> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> + &sensor_dev_attr_update_interval.dev_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group omap_temp_sensor_group = {
> + .attrs = omap_temp_sensor_attributes,
> +};
> +
> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 ret = 0;
> +
> + if (temp_sensor->clk_on) {
> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
> + goto out;
> + }
Can never happen.
> +
> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
ret is u32.
> + if (ret < 0) {
> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
> + goto out;
return ret;
is just as good.
> + }
> +
> + temp_sensor->clk_on = 1;
> +
> +out:
> + return ret;
> +}
> +
> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
> +{
> + /* Gate the clock */
> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
> + temp_sensor->clk_on = 0;
This variable is quite useless.
> +}
> +
> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
> +{
> + struct omap_temp_sensor *temp_sensor;
> + int t_hot, t_cold, temp;
> +
Why int here ?
> + temp_sensor = data;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + /* Read the status of t_hot */
> + t_hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_hot_mask;
> +
> + /* Read the status of t_cold */
> + t_cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_cold_mask;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->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
> + */
Comment does not match the code.
> + if (t_hot) {
> + temp &= ~temp_sensor->registers->mask_hot_mask;
> + temp |= temp_sensor->registers->mask_cold_mask;
> + } else if (t_cold) {
> + temp &= ~temp_sensor->registers->mask_cold_mask;
> + temp |= temp_sensor->registers->mask_hot_mask;
> + }
> +
> + omap_temp_sensor_writel(temp_sensor, temp,
> + temp_sensor->registers->bgap_mask_ctrl);
> +
> + if (temp_sensor->hwmon_dev)
> + /* kobject_uvent to user space telling threshold crossed */
> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
> +
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
> + struct omap_temp_sensor *temp_sensor;
> + struct resource *mem;
> + int ret = 0;
> + int clk_rate;
> + u32 max_freq, min_freq;
> +
> + if (!pdata) {
> + dev_err(&pdev->dev, "platform data missing\n");
> + return -EINVAL;
> + }
> +
> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
> + if (!temp_sensor) {
> + dev_err(&pdev->dev, "Memory allocation failed\n");
> + return -ENOMEM;
> + }
> +
> + mutex_init(&temp_sensor->sensor_mutex);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&pdev->dev, "no mem resource\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
> + if (temp_sensor->irq < 0) {
> + dev_err(&pdev->dev, "get_irq_byname failed\n");
> + ret = temp_sensor->irq;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
> + if (!temp_sensor->phy_base) {
> + dev_err(&pdev->dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->clock = NULL;
> + temp_sensor->registers = pdata->registers;
> + temp_sensor->pdev_dev = &pdev->dev;
> +
> + if (pdata->max_freq && pdata->min_freq) {
> + max_freq = pdata->max_freq;
> + min_freq = pdata->min_freq;
> + } else {
> + max_freq = MAX_FREQ;
> + min_freq = MIN_FREQ;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_irq_safe(&pdev->dev);
> +
> + /*
> + * check if the efuse has a non-zero value if not
> + * it is an untrimmed sample and the temperatures
> + * may not be accurate
> + */
> +
> + if (omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_efuse))
> + dev_info(&pdev->dev,
> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
> +
> + dev_set_drvdata(&pdev->dev, temp_sensor);
> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
> + if (IS_ERR(temp_sensor->clock)) {
> + ret = PTR_ERR(temp_sensor->clock);
> + dev_err(&pdev->dev,
> + "unable to get fclk: %d\n", ret);
> + goto plat_res_err;
No iounmap in this case.
> + }
> +
> + ret = omap_temp_sensor_clk_enable(temp_sensor);
> + if (ret)
> + goto clken_err;
> +
> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
> + if (clk_rate < min_freq || clk_rate == 0xffffffff) {
> + ret = -ENODEV;
> + goto clken_err;
> + }
> +
> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
> + if (ret) {
> + dev_err(&pdev->dev, "Cannot set clock rate\n");
> + goto clken_err;
> + }
> +
> + temp_sensor->clk_rate = clk_rate;
> + omap_enable_continuous_mode(temp_sensor);
> + /* 1 clk cycle */
> + omap_configure_temp_sensor_counter(temp_sensor, 1);
> +
> + /* Wait till the first conversion is done wait for at least 1ms */
> + usleep_range(1000, 2000);
> +
> + /* Read the temperature once due to hw issue*/
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> +
> + /* Set 2 seconds time as default counter */
> + omap_configure_temp_sensor_counter(temp_sensor,
> + temp_sensor->clk_rate * 2);
> +
> + ret = request_threaded_irq(temp_sensor->irq, NULL,
> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> + "temp_sensor", temp_sensor);
> + if (ret) {
> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
> + goto req_irq_err;
> + }
> +
> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
> + if (ret) {
> + dev_err(&pdev->dev, "could not create sysfs files\n");
> + goto sysfs_create_err;
> + }
> +
> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
> + if (IS_ERR(temp_sensor->hwmon_dev)) {
> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
> + ret = PTR_ERR(temp_sensor->hwmon_dev);
> + goto hwmon_reg_err;
> + }
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
> + T_HOT, T_COLD);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return 0;
> +
> +hwmon_reg_err:
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> +sysfs_create_err:
> + free_irq(temp_sensor->irq, temp_sensor);
> +req_irq_err:
> + omap_temp_sensor_clk_disable(temp_sensor);
> +clken_err:
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> +plat_res_err:
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> + return ret;
> +}
> +
> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
> +
> + hwmon_device_unregister(&pdev->dev);
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
Kind of odd to use hwmon_dev here, and not &pdev->dev.kobj.
> + &omap_temp_sensor_group);
> + free_irq(temp_sensor->irq, temp_sensor);
Sure you don't want to disable the interrupts before freeing the irq ?
> + omap_temp_sensor_clk_disable(temp_sensor);
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp_sensor->temp_sensor_tshut_threshold =
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_ctrl,
> + temp_sensor->registers->temp_sensor_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_ctrl,
> + temp_sensor->registers->bgap_mask_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_counter,
> + temp_sensor->registers->bgap_counter);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_threshold,
> + temp_sensor->registers->bgap_threshold);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_tshut_threshold,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static int omap_temp_sensor_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_resume(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_resume(struct device *dev)
> +{
> + static int context_loss_count;
> + int temp;
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
> +
> + if (temp != context_loss_count && context_loss_count != 0)
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + context_loss_count = temp;
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_idle(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
> + omap_temp_sensor_resume)
> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
> +};
> +
> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
> +#else
> +#define DEV_PM_OPS NULL
> +#endif
> +
> +static struct platform_driver omap_temp_sensor_driver = {
> + .probe = omap_temp_sensor_probe,
> + .remove = omap_temp_sensor_remove,
> + .driver = {
> + .name = "omap_temp_sensor",
> + .pm = DEV_PM_OPS,
> + },
> +};
> +
> +int __init omap_temp_sensor_init(void)
> +{
> + return platform_driver_register(&omap_temp_sensor_driver);
> +}
> +module_init(omap_temp_sensor_init);
> +
> +static void __exit omap_temp_sensor_exit(void)
> +{
> + platform_driver_unregister(&omap_temp_sensor_driver);
> +}
> +module_exit(omap_temp_sensor_exit);
> +
> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
> --
> 1.7.0.4
>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-01 4:38 ` Guenter Roeck
0 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 4:38 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, Jean Delvare, lm-sensors
On Wed, Aug 31, 2011 at 01:25:10PM -0400, Keerthy wrote:
> On chip temperature sensor driver. The driver monitors the temperature of
> the MPU subsystem of the OMAP4. It sends notifications to the user space if
> the temperature crosses user defined thresholds via kobject_uevent interface.
> The user is allowed to configure the temperature thresholds vis sysfs nodes
> exposed using hwmon interface.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Cc: Jean Delvare <khali@linux-fr.org>
> Cc: Guenter Roeck <guenter.roeck@ericsson.com>
> Cc: lm-sensors@lm-sensors.org
> ---
> Documentation/hwmon/omap_temp_sensor | 26 +
> drivers/hwmon/Kconfig | 11 +
> drivers/hwmon/Makefile | 1 +
> drivers/hwmon/omap_temp_sensor.c | 881 ++++++++++++++++++++++++++++++++++
> 4 files changed, 919 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/hwmon/omap_temp_sensor
> create mode 100644 drivers/hwmon/omap_temp_sensor.c
>
> diff --git a/Documentation/hwmon/omap_temp_sensor b/Documentation/hwmon/omap_temp_sensor
> new file mode 100644
> index 0000000..357f09a
> --- /dev/null
> +++ b/Documentation/hwmon/omap_temp_sensor
> @@ -0,0 +1,26 @@
> +Kernel driver omap_temp_sensor
> +===============
> +
> +Supported chips:
> + * Texas Instruments OMAP4460
> + Prefix: 'omap_temp_sensor'
> +
> +Author:
> + J Keerthy <j-keerthy@ti.com>
> +
> +Description
> +-----------
> +
> +The Texas Instruments OMAP4 family of chips have a bandgap temperature sensor.
> +The temperature sensor feature is used to convert the temperature of the device
> +into a decimal value coded on 10 bits. An internal ADC is used for conversion.
> +The recommended operating temperatures must be in the range -40 degree Celsius
> +to 123 degree celsius for standard conversion.
> +The thresholds are programmable and upon crossing the thresholds an interrupt
> +is generated. The OMAP temperature sensor has a programmable update rate in
> +milli seconds.
> +(Currently the driver programs a default of 2000 milliseconds).
> +
> +The driver provides the common sysfs-interface for temperatures (see
> +Documentation/hwmon/sysfs-interface under Temperatures).
> +
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 5f888f7..9c9cd8b 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -323,6 +323,17 @@ config SENSORS_F71805F
> This driver can also be built as a module. If so, the module
> will be called f71805f.
>
> +config SENSORS_OMAP_BANDGAP_TEMP_SENSOR
> + bool "OMAP on-die temperature sensor hwmon driver"
> + depends on HWMON && ARCH_OMAP && OMAP_TEMP_SENSOR
> + help
> + If you say yes here you get support for hardware
> + monitoring features of the OMAP on die temperature
> + sensor.
> +
> + Continuous conversion programmable delay
> + mode is used for temperature conversion.
> +
> config SENSORS_F71882FG
> tristate "Fintek F71882FG and compatibles"
> help
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 28061cf..d0f89f5 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -91,6 +91,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
> obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
> obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
> obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
> +obj-$(CONFIG_SENSORS_OMAP_BANDGAP_TEMP_SENSOR) += omap_temp_sensor.o
> obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
> obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
> obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
> new file mode 100644
> index 0000000..67fa424
> --- /dev/null
> +++ b/drivers/hwmon/omap_temp_sensor.c
> @@ -0,0 +1,881 @@
> +/*
> + * OMAP4 Temperature sensor driver file
> + *
> + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> + * Author: J Keerthy <j-keerthy@ti.com>
> + * Author: Moiz Sonasath <m-sonasath@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/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <plat/omap_device.h>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/jiffies.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/stddef.h>
> +#include <linux/sysfs.h>
> +#include <linux/err.h>
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/delay.h>
> +#include <plat/temperature_sensor.h>
> +
> +#define TSHUT_HOT 920 /* 122 deg C */
> +#define TSHUT_COLD 866 /* 100 deg C */
> +#define T_HOT 800 /* 73 deg C */
> +#define T_COLD 795 /* 71 deg C */
> +#define OMAP_ADC_START_VALUE 530
> +#define OMAP_ADC_END_VALUE 923
> +#define MAX_FREQ 2000000
> +#define MIN_FREQ 1000000
> +#define MIN_TEMP -40000
> +#define MAX_TEMP 123000
> +#define HYST_VAL 5000
> +#define NEG_HYST_VAL -5000
> +/*
> + * omap_temp_sensor structure
> + * @hwmon_dev - hwmon device pointer
> + * @pdev_dev - platform device pointer
> + * @clock - Clock pointer
> + * @registers - Pointer to structure with register offsets and bitfields
> + * @sensor_mutex - Mutex for sysfs, irq and PM
> + * @irq - MPU Irq number for thermal alert
> + * @phy_base - Physical base of the temp I/O
> + * @clk_rate - Holds current clock rate
> + * @temp_sensor_ctrl - temp sensor control register value
> + * @bg_ctrl - bandgap ctrl register value
> + * @bg_counter - bandgap counter value
> + * @bg_threshold - bandgap threshold register value
> + * @temp_sensor_tshut_threshold - bandgap tshut register value
> + * @clk_on - Manages the current clock state
> + */
> +struct omap_temp_sensor {
> + struct device *hwmon_dev;
> + struct device *pdev_dev;
> + struct clk *clock;
> + struct omap_temp_sensor_registers *registers;
> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
> + unsigned int irq;
> + void __iomem *phy_base;
> + u32 clk_rate;
> + u32 temp_sensor_ctrl;
> + u32 bg_ctrl;
> + u32 bg_counter;
> + u32 bg_threshold;
> + u32 temp_sensor_tshut_threshold;
> + bool clk_on;
> +};
> +
> +/*
> + * Temperature values in milli degree celsius
> + * ADC code values from 530 to 923
> + */
> +static int adc_to_temp[394] = {
[OMAP_ADC_END_VALUE - OMAP_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
> +};
> +
> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
> + *temp_sensor, u32 reg)
Why unsigned long ? Result is lways assigned to u32 or int.
> +{
> + return __raw_readl(temp_sensor->phy_base + reg);
> +}
> +
> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
> + u32 val, u32 reg)
> +{
> + __raw_writel(val, temp_sensor->phy_base + reg);
> +}
> +
> +static int adc_to_temp_conversion(int adc_val)
> +{
> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
> +}
> +
> +static int temp_to_adc_conversion(long temp)
> +{
> + int high, low, mid;
> +
> + if (temp < adc_to_temp[0] ||
> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
> + return -EINVAL;
> +
> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
> + low = 0;
> + mid = (high + low) / 2;
> +
> + while (low < high) {
> + if (temp < adc_to_temp[mid])
> + high = mid - 1;
> + else
> + low = mid + 1;
> + mid = (low + high) / 2;
> + }
> +
> + return OMAP_ADC_START_VALUE + low;
> +}
> +
> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
> + *temp_sensor, u32 counter)
> +{
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + val &= ~temp_sensor->registers->counter_mask;
> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_counter);
> +}
> +
> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
> +{
Please add a comment to functions which need to be called during initialization or
protected by the mutex.
> + u32 val;
> +
> + val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mode_ctrl);
> +
> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
> +
> + omap_temp_sensor_writel(temp_sensor, val,
> + temp_sensor->registers->bgap_mode_ctrl);
> +}
> +
> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
> + *temp_sensor, u8 hot, u8 cold)
> +{
> + u32 reg_val;
> +
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + if (hot)
> + reg_val |= temp_sensor->registers->mask_hot_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
> +
> + if (cold)
> + reg_val |= temp_sensor->registers->mask_cold_mask;
> + else
> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
> +
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_mask_ctrl);
> +}
> +
> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
> +{
> + int temp = adc_to_temp_conversion(adc_val);
> +
> + temp += hyst_val;
> +
> + *thresh_val = temp_to_adc_conversion(temp);
> +}
> +
Since you return a void, you can as well return the new value and drop the
pointer.
> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
> +{
> + int reg_val, cold, hot, temp;
> +
Why int here ?
> + if (set_hot) {
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (t_hot < cold) {
> + /* change the t_cold to t_hot - 5000 millidegrees */
> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
You might just use -HYST_VAL here.
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &> + ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_cold = cold;
> + }
> +
t_hot = cold: t_hot will be equal to t_cold
t_hot > t_colt: t_hot > t_cold, any difference
t_hot < t_cold: t_cold = t_hot - NEG_HYST_VAL
Seems to be inconsistent, and it seems that the condition t_hot = t_cold can still occur
(which you mentioned earlier would be invalid). If you want to define a minimum hysteresis,
you should enforce it by modifying the if statement.
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (t_hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> +
> + if (set_cold) {
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> + if (t_cold > hot) {
> + /* change the t_hot to t_cold + 5000 millidegrees */
> + add_hyst(t_cold, HYST_VAL, &hot);
> + /* write the new t_hot value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &> + ~temp_sensor->registers->threshold_thot_mask;
> + reg_val |= (hot <<
> + __ffs(temp_sensor->registers->threshold_thot_mask));
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + t_hot = hot;
> + }
> +
> + /* write the new t_cold value */
> + reg_val = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
> + reg_val |= t_cold <<
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> + omap_temp_sensor_writel(temp_sensor, reg_val,
> + temp_sensor->registers->bgap_threshold);
> + }
> + /* obtain the T cold value */
> + cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + /* obtain the T HOT value */
> + hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
> + __ffs(temp_sensor->registers->threshold_thot_mask);
> +
> + /* Read the current temperature */
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /*
> + * If current temperature is in-between the hot and cold thresholds
> + * Enable both masks or in the init case enable both masks
> + */
> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> +
> + /*
> + * If user sets the HIGH threshold(t_hot) greater than the current
> + * temperature(temp) unmask the HOT interrupts
> + */
> + else if (hot > temp)
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> +
> + /*
> + * If user sets the LOW threshold(t_cold) lower than the current
> + * temperature(temp) unmask the COLD interrupts
> + */
> + else
> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
> +}
> +
> +/* Sysfs hook functions */
> +
> +static ssize_t show_temp_max(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
> + temp = adc_to_temp_conversion(temp);
> +
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> + u32 t_hot;
> +
> + if (strict_strtol(buf, 10, &val))
> + return -EINVAL;
> + if (val < MIN_TEMP - HYST_VAL)
> + return -EINVAL;
MIN_TEMP + HYST_VAL ?
> +
> + t_hot = temp_to_adc_conversion(val);
> + if (t_hot < 0)
> + return t_hot;
Difficuly to accomplish since t_hot is u32.
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
> + t_hot, 0);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return count;
> +}
> +
> +static ssize_t show_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
> + __ffs(temp_sensor->registers->threshold_tcold_mask);
> +
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
> + dev_err(dev, "invalid value\n");
> + return -EIO;
> + }
> +
> + temp = adc_to_temp_conversion(temp);
> +
adc_to_temp_conversion can return a negative value.
> + return snprintf(buf, 16, "%d\n", temp);
> +}
> +
> +static ssize_t set_temp_max_hyst(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 t_cold;
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
Just return -EINVAL.
> +
> + if (val > MAX_TEMP - HYST_VAL) {
> + count = -EINVAL;
> + goto out;
Just return -EINVAL here.
> + }
> +
> + t_cold = temp_to_adc_conversion(val);
> + if (t_cold < 0)
> + return t_cold;
> +
t_cold is u32 and will never be < 0. Wondering ... doesn't gcc complain about this ?
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
> + t_cold);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> +out:
> + return count;
> +}
> +
> +static ssize_t show_update_interval(struct device *dev,
> + struct device_attribute *devattr, char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + u32 temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp = (temp & temp_sensor->registers->counter_mask) >>
> + __ffs(temp_sensor->registers->counter_mask);
> + temp = temp * 1000 / temp_sensor->clk_rate;
> +
> + return sprintf(buf, "%d\n", temp);
> +}
> +
> +static ssize_t set_update_interval(struct device *dev,
> + struct device_attribute *devattr,
> + const char *buf, size_t count)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + long val;
> +
> + if (strict_strtol(buf, 10, &val)) {
> + count = -EINVAL;
> + goto out;
> + }
Just return -EINVAL.
> +
> + if (val < 0)
> + return -EINVAL;
If values < 0 are not valid, might as well use strict_strtoul() above.
> + val *= temp_sensor->clk_rate / 1000;
Divide happens first here. Loss of accuracy not a problem ?
Also, no max value, and 0 is ok ?
Large values may result in negative counter values if someone enters a large number.
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_configure_temp_sensor_counter(temp_sensor, val);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +out:
> + return count;
> +}
> +
> +static int omap_temp_sensor_read_temp(struct device *dev,
> + struct device_attribute *devattr,
> + char *buf)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> + int temp;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp &= temp_sensor->registers->bgap_dtemp_mask;
> +
> + /* look up for temperature in the table and return the temperature */
> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
> + return -EIO;
> +
> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
> +
Use adc_to_temp_conversion().
> + return sprintf(buf, "%d\n", temp);
return sprintf(buf, "%d\n", adc_to_temp_conversion(temp));
might be a bit simpler.
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
> + NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
> + set_temp_max, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
> + set_temp_max_hyst, 0);
> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
> + show_update_interval, set_update_interval, 0);
> +
> +static struct attribute *omap_temp_sensor_attributes[] = {
> + &sensor_dev_attr_temp1_input.dev_attr.attr,
> + &sensor_dev_attr_temp1_max.dev_attr.attr,
> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> + &sensor_dev_attr_update_interval.dev_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group omap_temp_sensor_group = {
> + .attrs = omap_temp_sensor_attributes,
> +};
> +
> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
> +{
> + u32 ret = 0;
> +
> + if (temp_sensor->clk_on) {
> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
> + goto out;
> + }
Can never happen.
> +
> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
ret is u32.
> + if (ret < 0) {
> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
> + goto out;
return ret;
is just as good.
> + }
> +
> + temp_sensor->clk_on = 1;
> +
> +out:
> + return ret;
> +}
> +
> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
> +{
> + /* Gate the clock */
> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
> + temp_sensor->clk_on = 0;
This variable is quite useless.
> +}
> +
> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
> +{
> + struct omap_temp_sensor *temp_sensor;
> + int t_hot, t_cold, temp;
> +
Why int here ?
> + temp_sensor = data;
> + mutex_lock(&temp_sensor->sensor_mutex);
> + /* Read the status of t_hot */
> + t_hot = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_hot_mask;
> +
> + /* Read the status of t_cold */
> + t_cold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_status)
> + & temp_sensor->registers->status_cold_mask;
> +
> + temp = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->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
> + */
Comment does not match the code.
> + if (t_hot) {
> + temp &= ~temp_sensor->registers->mask_hot_mask;
> + temp |= temp_sensor->registers->mask_cold_mask;
> + } else if (t_cold) {
> + temp &= ~temp_sensor->registers->mask_cold_mask;
> + temp |= temp_sensor->registers->mask_hot_mask;
> + }
> +
> + omap_temp_sensor_writel(temp_sensor, temp,
> + temp_sensor->registers->bgap_mask_ctrl);
> +
> + if (temp_sensor->hwmon_dev)
> + /* kobject_uvent to user space telling threshold crossed */
> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
> +
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
> + struct omap_temp_sensor *temp_sensor;
> + struct resource *mem;
> + int ret = 0;
> + int clk_rate;
> + u32 max_freq, min_freq;
> +
> + if (!pdata) {
> + dev_err(&pdev->dev, "platform data missing\n");
> + return -EINVAL;
> + }
> +
> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
> + if (!temp_sensor) {
> + dev_err(&pdev->dev, "Memory allocation failed\n");
> + return -ENOMEM;
> + }
> +
> + mutex_init(&temp_sensor->sensor_mutex);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&pdev->dev, "no mem resource\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
> + if (temp_sensor->irq < 0) {
> + dev_err(&pdev->dev, "get_irq_byname failed\n");
> + ret = temp_sensor->irq;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
> + if (!temp_sensor->phy_base) {
> + dev_err(&pdev->dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + temp_sensor->clock = NULL;
> + temp_sensor->registers = pdata->registers;
> + temp_sensor->pdev_dev = &pdev->dev;
> +
> + if (pdata->max_freq && pdata->min_freq) {
> + max_freq = pdata->max_freq;
> + min_freq = pdata->min_freq;
> + } else {
> + max_freq = MAX_FREQ;
> + min_freq = MIN_FREQ;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_irq_safe(&pdev->dev);
> +
> + /*
> + * check if the efuse has a non-zero value if not
> + * it is an untrimmed sample and the temperatures
> + * may not be accurate
> + */
> +
> + if (omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_efuse))
> + dev_info(&pdev->dev,
> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
> +
> + dev_set_drvdata(&pdev->dev, temp_sensor);
> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
> + if (IS_ERR(temp_sensor->clock)) {
> + ret = PTR_ERR(temp_sensor->clock);
> + dev_err(&pdev->dev,
> + "unable to get fclk: %d\n", ret);
> + goto plat_res_err;
No iounmap in this case.
> + }
> +
> + ret = omap_temp_sensor_clk_enable(temp_sensor);
> + if (ret)
> + goto clken_err;
> +
> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
> + if (clk_rate < min_freq || clk_rate = 0xffffffff) {
> + ret = -ENODEV;
> + goto clken_err;
> + }
> +
> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
> + if (ret) {
> + dev_err(&pdev->dev, "Cannot set clock rate\n");
> + goto clken_err;
> + }
> +
> + temp_sensor->clk_rate = clk_rate;
> + omap_enable_continuous_mode(temp_sensor);
> + /* 1 clk cycle */
> + omap_configure_temp_sensor_counter(temp_sensor, 1);
> +
> + /* Wait till the first conversion is done wait for at least 1ms */
> + usleep_range(1000, 2000);
> +
> + /* Read the temperature once due to hw issue*/
> + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> +
> + /* Set 2 seconds time as default counter */
> + omap_configure_temp_sensor_counter(temp_sensor,
> + temp_sensor->clk_rate * 2);
> +
> + ret = request_threaded_irq(temp_sensor->irq, NULL,
> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> + "temp_sensor", temp_sensor);
> + if (ret) {
> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
> + goto req_irq_err;
> + }
> +
> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
> + if (ret) {
> + dev_err(&pdev->dev, "could not create sysfs files\n");
> + goto sysfs_create_err;
> + }
> +
> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
> + if (IS_ERR(temp_sensor->hwmon_dev)) {
> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
> + ret = PTR_ERR(temp_sensor->hwmon_dev);
> + goto hwmon_reg_err;
> + }
> +
> + mutex_lock(&temp_sensor->sensor_mutex);
> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
> + T_HOT, T_COLD);
> + mutex_unlock(&temp_sensor->sensor_mutex);
> +
> + return 0;
> +
> +hwmon_reg_err:
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
> + &omap_temp_sensor_group);
> +sysfs_create_err:
> + free_irq(temp_sensor->irq, temp_sensor);
> +req_irq_err:
> + omap_temp_sensor_clk_disable(temp_sensor);
> +clken_err:
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> +plat_res_err:
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> + return ret;
> +}
> +
> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
> +{
> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
> +
> + hwmon_device_unregister(&pdev->dev);
> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
Kind of odd to use hwmon_dev here, and not &pdev->dev.kobj.
> + &omap_temp_sensor_group);
> + free_irq(temp_sensor->irq, temp_sensor);
Sure you don't want to disable the interrupts before freeing the irq ?
> + omap_temp_sensor_clk_disable(temp_sensor);
> + clk_put(temp_sensor->clock);
> + iounmap(temp_sensor->phy_base);
> + dev_set_drvdata(&pdev->dev, NULL);
> + mutex_destroy(&temp_sensor->sensor_mutex);
> + kfree(temp_sensor);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->temp_sensor_ctrl);
> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_mask_ctrl);
> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_counter);
> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->bgap_threshold);
> + temp_sensor->temp_sensor_tshut_threshold > + omap_temp_sensor_readl(temp_sensor,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
> +{
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_ctrl,
> + temp_sensor->registers->temp_sensor_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_ctrl,
> + temp_sensor->registers->bgap_mask_ctrl);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_counter,
> + temp_sensor->registers->bgap_counter);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->bg_threshold,
> + temp_sensor->registers->bgap_threshold);
> + omap_temp_sensor_writel(temp_sensor,
> + temp_sensor->temp_sensor_tshut_threshold,
> + temp_sensor->registers->thsut_threshold);
> +}
> +
> +static int omap_temp_sensor_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_resume(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
> +{
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + omap_temp_sensor_save_ctxt(temp_sensor);
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_runtime_resume(struct device *dev)
> +{
> + static int context_loss_count;
> + int temp;
> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
> +
> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
> +
> + if (temp != context_loss_count && context_loss_count != 0)
> + omap_temp_sensor_restore_ctxt(temp_sensor);
> +
> + context_loss_count = temp;
> +
> + return 0;
> +}
> +
> +static int omap_temp_sensor_idle(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
> + omap_temp_sensor_resume)
> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
> +};
> +
> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
> +#else
> +#define DEV_PM_OPS NULL
> +#endif
> +
> +static struct platform_driver omap_temp_sensor_driver = {
> + .probe = omap_temp_sensor_probe,
> + .remove = omap_temp_sensor_remove,
> + .driver = {
> + .name = "omap_temp_sensor",
> + .pm = DEV_PM_OPS,
> + },
> +};
> +
> +int __init omap_temp_sensor_init(void)
> +{
> + return platform_driver_register(&omap_temp_sensor_driver);
> +}
> +module_init(omap_temp_sensor_init);
> +
> +static void __exit omap_temp_sensor_exit(void)
> +{
> + platform_driver_unregister(&omap_temp_sensor_driver);
> +}
> +module_exit(omap_temp_sensor_exit);
> +
> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
> --
> 1.7.0.4
>
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 4:09 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
@ 2011-09-01 4:40 ` Guenter Roeck
-1 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 4:40 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>
> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> > > Hi
> > >
> > > Some comments.
> > >
> > > On Wed, 31 Aug 2011, Keerthy wrote:
> > >
> > [ ... ]
> > >
> > > > +}
> > > > +
> > > > +/* Sysfs hook functions */
> > >
> > > These should be conditionally compiled out if sysfs isn't compiled in.
> > >
> > The whole point of the hwmon subsystem is to expose hardware monitoring information
> > to userland using sysfs. hwmon without sysfs doesn't make sense.
> >
> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> > But please no conditionals in the code.
>
> Hmm. This IP block is more than just a sensor. It also can interrupt the
> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> temperature crosses some thresholds. On some OMAPs, the thresholds are
> fixed; on others, they are software-programmable. That functionality
> shouldn't require sysfs; it's almost closer to an x86 MCE.
>
> So based on your comments, it sounds like we should move that part of the
> code to a different driver, and just leave the basic software thermal
> monitoring here?
>
Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
as the name says, not thermal management. Maybe this entire driver should be a thermal driver
instead ?
Guenter
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-01 4:40 ` Guenter Roeck
0 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-01 4:40 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Keerthy, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>
> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> > > Hi
> > >
> > > Some comments.
> > >
> > > On Wed, 31 Aug 2011, Keerthy wrote:
> > >
> > [ ... ]
> > >
> > > > +}
> > > > +
> > > > +/* Sysfs hook functions */
> > >
> > > These should be conditionally compiled out if sysfs isn't compiled in.
> > >
> > The whole point of the hwmon subsystem is to expose hardware monitoring information
> > to userland using sysfs. hwmon without sysfs doesn't make sense.
> >
> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> > But please no conditionals in the code.
>
> Hmm. This IP block is more than just a sensor. It also can interrupt the
> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> temperature crosses some thresholds. On some OMAPs, the thresholds are
> fixed; on others, they are software-programmable. That functionality
> shouldn't require sysfs; it's almost closer to an x86 MCE.
>
> So based on your comments, it sounds like we should move that part of the
> code to a different driver, and just leave the basic software thermal
> monitoring here?
>
Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
as the name says, not thermal management. Maybe this entire driver should be a thermal driver
instead ?
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor
2011-09-01 0:00 ` Paul Walmsley
@ 2011-09-02 7:12 ` Rajendra Nayak
0 siblings, 0 replies; 43+ messages in thread
From: Rajendra Nayak @ 2011-09-02 7:12 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Keerthy, linux-omap, tony, Cousson, Benoit
Hi Paul,
On Thursday 01 September 2011 05:30 AM, Paul Walmsley wrote:
> Hi,
>
> a comment:
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> div_ts_ck feeds only the temperature sensor functional clock
>> and also has a clksel associated (for divider selection). Mapping this
>> as the functional clock for the temperature sensor in clkdev table,
>> so a clk_set_rate() in the driver would have the effect of changing the
>> temperature sensor clock rate indirectly.
>>
>> Signed-off-by: Keerthy<j-keerthy@ti.com>
>> Reviewed-by: Rajendra Nayak<rnayak@ti.com>
>> Cc: tony@atomide.com
>> Cc: rnayak@ti.com
>> ---
>> arch/arm/mach-omap2/clock44xx_data.c | 2 +-
>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
>> index 2af0e3f..4a788f4 100644
>> --- a/arch/arm/mach-omap2/clock44xx_data.c
>> +++ b/arch/arm/mach-omap2/clock44xx_data.c
>> @@ -3187,7 +3187,7 @@ static struct omap_clk omap44xx_clks[] = {
>> CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X),
>> CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X),
>> CLK(NULL, "des3des_fck", &des3des_fck, CK_443X),
>> - CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X),
>> + CLK("omap_temp_sensor.0", "fck", &div_ts_ck, CK_446X),
>
> It shouldn't be necessary to add the device name/ID here. We're trying
> to get rid of these. The omap_device code should take care of adding the
> appropriate alias.
The problem seems to be that we have 2 clock nodes modeled,
bandgap_ts_fclk with enable/disable ops, (which also happens
to be the main_clk for the bandgap hwmod) and div_ts_ck (as
parent of bandgap_ts_fclk) with clksel for divider selection.
Like you said, the clkdev entries are added by omap_device code
for bandgap_ts_fclk, however doing a clk_set_rate on it from
the driver has no effect as the clksel information is missing
and is modeled in the parent (div_ts_ck) node.
From looking at it, it makes sense to merge these 2 nodes and fix
the autogen scripts which currently generate 2 separate nodes.
what do you think?
regards,
Rajendra
>
>
>> CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X),
>> CLK(NULL, "dmic_fck", &dmic_fck, CK_443X),
>> CLK(NULL, "dsp_fck", &dsp_fck, CK_443X),
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> - Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-08-31 23:56 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
@ 2011-09-06 11:52 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 11:49 UTC (permalink / raw)
To: Paul Walmsley; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
On Thu, Sep 1, 2011 at 5:26 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi,
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> On chip temperature sensor driver. The driver monitors the temperature of
>> the MPU subsystem of the OMAP4. It sends notifications to the user space if
>> the temperature crosses user defined thresholds via kobject_uevent interface.
>> The user is allowed to configure the temperature thresholds vis sysfs nodes
>> exposed using hwmon interface.
>
> I commented in a separate post that this driver should probably use an MFD
> driver for the System Control Module accesses, and then this hwmon driver
> should use functions from that to access the BANDGAP temperature sensor
> registers[1].
>
> But I had another comment on this driver.
>
> A similar sensor is available on the OMAP34xx[2], OMAP36xx[3], and
> OMAP4430[4] chips. There are some register layout differences; the
> thermal shutdown threshold is configurable on the 4460 but fixed on the
> 4430; and also I'd assume, without looking, that the temperature mapping
> table is different on different chips.
>
> So it would seem to make sense to move the chip-specific code and
> data into chip-specific source files.
>
> I could see keeping a generic filename like "omap_temp_sensor.c" if you
> implemented a common interface to the bandgap sensors, ADCs and
> comparators, across all those different chips. That might be worth
> thinking about. But at least, this should probably be named
> drivers/hwmon/omap4460_temp_sensor.c, or something similar.
The same driver can be used for OMAP5 too.
That has 3 instances of the same sensor. So omap4460+?
>
>
> - Paul
>
> 1. Walmsley, Paul. _Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature
> sensor_. Posted to the linux-omap@vger.kernel.org list on Wed, 31 Aug
> 2011 17:16:44 -0600. Available from (among others):
> http://marc.info/?l=linux-omap&m=131483260632685&w=2
>
> 2. Section 7.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP34xx
> Multimedia Device Silicon Revision 3.1.x Version R (SWPU223R)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZR.zip
>
> 3. Section 13.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP36xx
> Multimedia Device Silicon Revision 1.x Version V (SWPU177V)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip
>
> 4. Section 18.4.10 "Band Gap Voltage and Temperature Sensor". _OMAP4430
> Multimedia Device Silicon Revision 2.x Version V (SWPU231V)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP4430_ES2.x_PUBLIC_TRM_vV.zip
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 11:52 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 11:52 UTC (permalink / raw)
To: Paul Walmsley; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
On Thu, Sep 1, 2011 at 5:26 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi,
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> On chip temperature sensor driver. The driver monitors the temperature of
>> the MPU subsystem of the OMAP4. It sends notifications to the user space if
>> the temperature crosses user defined thresholds via kobject_uevent interface.
>> The user is allowed to configure the temperature thresholds vis sysfs nodes
>> exposed using hwmon interface.
>
> I commented in a separate post that this driver should probably use an MFD
> driver for the System Control Module accesses, and then this hwmon driver
> should use functions from that to access the BANDGAP temperature sensor
> registers[1].
>
> But I had another comment on this driver.
>
> A similar sensor is available on the OMAP34xx[2], OMAP36xx[3], and
> OMAP4430[4] chips. There are some register layout differences; the
> thermal shutdown threshold is configurable on the 4460 but fixed on the
> 4430; and also I'd assume, without looking, that the temperature mapping
> table is different on different chips.
>
> So it would seem to make sense to move the chip-specific code and
> data into chip-specific source files.
>
> I could see keeping a generic filename like "omap_temp_sensor.c" if you
> implemented a common interface to the bandgap sensors, ADCs and
> comparators, across all those different chips. That might be worth
> thinking about. But at least, this should probably be named
> drivers/hwmon/omap4460_temp_sensor.c, or something similar.
The same driver can be used for OMAP5 too.
That has 3 instances of the same sensor. So omap4460+?
>
>
> - Paul
>
> 1. Walmsley, Paul. _Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature
> sensor_. Posted to the linux-omap@vger.kernel.org list on Wed, 31 Aug
> 2011 17:16:44 -0600. Available from (among others):
> http://marc.info/?l=linux-omap&m\x131483260632685&w=2
>
> 2. Section 7.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP34xx
> Multimedia Device Silicon Revision 3.1.x Version R (SWPU223R)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZR.zip
>
> 3. Section 13.4.6 "Band Gap Voltage and Temperature Sensor". _OMAP36xx
> Multimedia Device Silicon Revision 1.x Version V (SWPU177V)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip
>
> 4. Section 18.4.10 "Band Gap Voltage and Temperature Sensor". _OMAP4430
> Multimedia Device Silicon Revision 2.x Version V (SWPU231V)_ (public
> version). Available from
> http://focus.ti.com/pdfs/wtbu/OMAP4430_ES2.x_PUBLIC_TRM_vV.zip
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 0:36 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
@ 2011-09-06 17:53 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 17:50 UTC (permalink / raw)
To: Paul Walmsley; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
On Thu, Sep 1, 2011 at 6:06 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi
>
> Some comments.
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
>> new file mode 100644
>> index 0000000..67fa424
>> --- /dev/null
>> +++ b/drivers/hwmon/omap_temp_sensor.c
>> @@ -0,0 +1,881 @@
>
> You've done almost all the hard work to create kerneldoc-NANO compliant
> structure documentation, which is good. But a few important things are
> missing. Please review Documentation/kernel-doc-nano-HOWTO.txt.
Ok
>
>> +/*
>
> Should be /** to indicate kerneldoc.
Ok
>
>> + * omap_temp_sensor structure
>
> Should be "struct omap_temp_sensor" and should include a short
> description.
Ok
>
>> + * @hwmon_dev - hwmon device pointer
>> + * @pdev_dev - platform device pointer
>> + * @clock - Clock pointer
>> + * @registers - Pointer to structure with register offsets and bitfields
>> + * @sensor_mutex - Mutex for sysfs, irq and PM
>> + * @irq - MPU Irq number for thermal alert
>> + * @phy_base - Physical base of the temp I/O
>> + * @clk_rate - Holds current clock rate
>> + * @temp_sensor_ctrl - temp sensor control register value
>> + * @bg_ctrl - bandgap ctrl register value
>> + * @bg_counter - bandgap counter value
>> + * @bg_threshold - bandgap threshold register value
>> + * @temp_sensor_tshut_threshold - bandgap tshut register value
>> + * @clk_on - Manages the current clock state
>> + */
>
>> +struct omap_temp_sensor {
>> + struct device *hwmon_dev;
>> + struct device *pdev_dev;
>> + struct clk *clock;
>> + struct omap_temp_sensor_registers *registers;
>> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
>> + unsigned int irq;
>> + void __iomem *phy_base;
>> + u32 clk_rate;
>> + u32 temp_sensor_ctrl;
>> + u32 bg_ctrl;
>> + u32 bg_counter;
>> + u32 bg_threshold;
>> + u32 temp_sensor_tshut_threshold;
>> + bool clk_on;
>> +};
>> +
>> +/*
>> + * Temperature values in milli degree celsius
>> + * ADC code values from 530 to 923
>> + */
>> +static int adc_to_temp[394] = {
>> + -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
>> +};
>> +
>> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
>> + *temp_sensor, u32 reg)
>> +{
>> + return __raw_readl(temp_sensor->phy_base + reg);
>> +}
>> +
>> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
>> + u32 val, u32 reg)
>> +{
>> + __raw_writel(val, temp_sensor->phy_base + reg);
>> +}
>
> These are all SCM register accesses and need to go through a SCM driver.
Accessing SCM registers using ctrl_ functions?
>
>> +
>> +static int adc_to_temp_conversion(int adc_val)
>> +{
>> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
>> +}
>> +
>> +static int temp_to_adc_conversion(long temp)
>> +{
>> + int high, low, mid;
>> +
>> + if (temp < adc_to_temp[0] ||
>> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
>> + return -EINVAL;
>> +
>> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
>> + low = 0;
>> + mid = (high + low) / 2;
>> +
>> + while (low < high) {
>> + if (temp < adc_to_temp[mid])
>> + high = mid - 1;
>> + else
>> + low = mid + 1;
>> + mid = (low + high) / 2;
>> + }
>> +
>> + return OMAP_ADC_START_VALUE + low;
>> +}
>> +
>> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
>> + *temp_sensor, u32 counter)
>
> It doesn't seem necessary to include 'omap' in all these static function names.
>
Ok
>> +{
>> + u32 val;
>> +
>> + val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + val &= ~temp_sensor->registers->counter_mask;
>> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
>> + omap_temp_sensor_writel(temp_sensor, val,
>> + temp_sensor->registers->bgap_counter);
>> +}
>> +
>> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
>> +{
>> + u32 val;
>> +
>> + val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mode_ctrl);
>> +
>> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
>> +
>> + omap_temp_sensor_writel(temp_sensor, val,
>> + temp_sensor->registers->bgap_mode_ctrl);
>> +}
>> +
>> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
>> + *temp_sensor, u8 hot, u8 cold)
>
> Your earlier static function names didn't include 'temp_sensor', but
> this one does. I'd suggest picking a standard function naming scheme
> and sticking to it.
Ok
>
>> +{
>> + u32 reg_val;
>> +
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + if (hot)
>> + reg_val |= temp_sensor->registers->mask_hot_mask;
>> + else
>> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
>> +
>> + if (cold)
>> + reg_val |= temp_sensor->registers->mask_cold_mask;
>> + else
>> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
>> +
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> +}
>> +
>> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
>> +{
>> + int temp = adc_to_temp_conversion(adc_val);
>> +
>> + temp += hyst_val;
>> +
>> + *thresh_val = temp_to_adc_conversion(temp);
>> +}
>> +
>> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
>> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
>
> Is there some reason why you don't just define a
>
> omap_temp_sensor_configure_hot_threshold()
>
> and
>
> omap_temp_sensor_configure_cold_threshold()
>
> ?
>
> Seems like that would be much more straightforward and would allow the
> removal of those set_{hot,cold} arguments.
Kept everything in one function. I can split it into separate functions.
>
>> +{
>> + int reg_val, cold, hot, temp;
>
> This function is really big and should be split up into several smaller
> functions. Common code should be shared if possible.
Ok
>
>> +
>> + if (set_hot) {
>> + /* obtain the T cold value */
>> + cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
>> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
>
> This code should be hoisted up above the if statements. Only a single
> device read should be necessary to fetch both the hot and cold values.
> Then the near-duplicate code below to read the hot temperature can be
> removed.
>
> In fact, given that this patch has almost the same code several times,
> you should just put it into a static function or two and remove the
> duplicate code.
Ok. I will remove the duplicate code.
>
>> +
>> + if (t_hot < cold) {
>> + /* change the t_cold to t_hot - 5000 millidegrees */
>> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
>> + /* write the new t_cold value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &=
>> + ~temp_sensor->registers->threshold_tcold_mask;
>> + reg_val |= cold <<
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>
> Looks like there are some indentation problems here. Those are more
> important than 80-column issues.
>
Ok
> Of course, you use temp_sensor->registers so much in this function, that
> many of the line length issues would go away if you used a shorter
> abbreviation at the beginning of this function, like:
>
> tsr = temp_sensor->registers;
Sure. Makes the code look neat.
>
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + t_cold = cold;
>> + }
>> +
>> + /* write the new t_hot value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
>> + reg_val |= (t_hot <<
>> + __ffs(temp_sensor->registers->threshold_thot_mask));
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + }
>> +
>> + if (set_cold) {
>> + /* obtain the T HOT value */
>> + hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
>> + __ffs(temp_sensor->registers->threshold_thot_mask);
>
> See the earlier comment about hoisting.
Ok
>
>> + if (t_cold > hot) {
>> + /* change the t_hot to t_cold + 5000 millidegrees */
>> + add_hyst(t_cold, HYST_VAL, &hot);
>> + /* write the new t_hot value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &=
>> + ~temp_sensor->registers->threshold_thot_mask;
>> + reg_val |= (hot <<
>> + __ffs(temp_sensor->registers->threshold_thot_mask));
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>
> This is a duplicate of earlier code. Please consolidate.
Ok
>
>> + t_hot = hot;
>> + }
>> +
>> + /* write the new t_cold value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
>> + reg_val |= t_cold <<
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + }
>> + /* obtain the T cold value */
>> + cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
>> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
>> +
>> + /* obtain the T HOT value */
>> + hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
>> + __ffs(temp_sensor->registers->threshold_thot_mask);
>> +
>> + /* Read the current temperature */
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp &= temp_sensor->registers->bgap_dtemp_mask;
>> +
>> + /*
>> + * If current temperature is in-between the hot and cold thresholds
>> + * Enable both masks or in the init case enable both masks
>> + */
>> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
>> +
>> + /*
>> + * If user sets the HIGH threshold(t_hot) greater than the current
>> + * temperature(temp) unmask the HOT interrupts
>> + */
>> + else if (hot > temp)
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
>> +
>> + /*
>> + * If user sets the LOW threshold(t_cold) lower than the current
>> + * temperature(temp) unmask the COLD interrupts
>> + */
>> + else
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
>
> This if statement is surely a violation of the spirit of
> Documentation/CodingStyle, if not the text itself.
>
> If you really need an if statement like this, try something like:
>
> if ((temp > cold && temp < hot) || (set_cold && set_hot)) {
> /*
> * If current temperature is in-between the hot and cold thresholds
> * Enable both masks or in the init case enable both masks
> */
>
> omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> } else if (hot > temp) {
> /*
> * If user sets the HIGH threshold(t_hot) greater than the current
> * temperature(temp) unmask the HOT interrupts
> */
> omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> } else {
> /*
> * If user sets the LOW threshold(t_cold) lower than the current
> * temperature(temp) unmask the COLD interrupts
> */
> omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
> }
>
Ok
>
>> +}
>> +
>> +/* Sysfs hook functions */
>
> These should be conditionally compiled out if sysfs isn't compiled in.
>
>> +
>> +static ssize_t show_temp_max(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + int temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
>> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
>> + temp = adc_to_temp_conversion(temp);
>> +
>> + return snprintf(buf, 16, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_temp_max(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + long val;
>> + u32 t_hot;
>> +
>> + if (strict_strtol(buf, 10, &val))
>> + return -EINVAL;
>> + if (val < MIN_TEMP - HYST_VAL)
>> + return -EINVAL;
>> +
>> + t_hot = temp_to_adc_conversion(val);
>> + if (t_hot < 0)
>> + return t_hot;
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
>> + t_hot, 0);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return count;
>> +}
>> +
>> +static ssize_t show_temp_max_hyst(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>> +
>> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
>> + dev_err(dev, "invalid value\n");
>> + return -EIO;
>> + }
>> +
>> + temp = adc_to_temp_conversion(temp);
>> +
>> + return snprintf(buf, 16, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_temp_max_hyst(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 t_cold;
>> + long val;
>> +
>> + if (strict_strtol(buf, 10, &val)) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + if (val > MAX_TEMP - HYST_VAL) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + t_cold = temp_to_adc_conversion(val);
>> + if (t_cold < 0)
>> + return t_cold;
>> +
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
>> + t_cold);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> +out:
>> + return count;
>> +}
>> +
>> +static ssize_t show_update_interval(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + temp = (temp & temp_sensor->registers->counter_mask) >>
>> + __ffs(temp_sensor->registers->counter_mask);
>> + temp = temp * 1000 / temp_sensor->clk_rate;
>> +
>> + return sprintf(buf, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_update_interval(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + long val;
>> +
>> + if (strict_strtol(buf, 10, &val)) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + if (val < 0)
>> + return -EINVAL;
>> + val *= temp_sensor->clk_rate / 1000;
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_configure_temp_sensor_counter(temp_sensor, val);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +out:
>> + return count;
>> +}
>> +
>> +static int omap_temp_sensor_read_temp(struct device *dev,
>> + struct device_attribute *devattr,
>> + char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + int temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp &= temp_sensor->registers->bgap_dtemp_mask;
>> +
>> + /* look up for temperature in the table and return the temperature */
>> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
>> + return -EIO;
>> +
>> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
>> +
>> + return sprintf(buf, "%d\n", temp);
>> +}
>> +
>> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
>> + NULL, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
>> + set_temp_max, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
>> + set_temp_max_hyst, 0);
>> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
>> + show_update_interval, set_update_interval, 0);
>> +
>> +static struct attribute *omap_temp_sensor_attributes[] = {
>> + &sensor_dev_attr_temp1_input.dev_attr.attr,
>> + &sensor_dev_attr_temp1_max.dev_attr.attr,
>> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> + &sensor_dev_attr_update_interval.dev_attr.attr,
>> + NULL
>> +};
>> +
>> +static const struct attribute_group omap_temp_sensor_group = {
>> + .attrs = omap_temp_sensor_attributes,
>> +};
>> +
>> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
>> +{
>> + u32 ret = 0;
>> +
>> + if (temp_sensor->clk_on) {
>> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
>> + goto out;
>> + }
>> +
>> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
>> + if (ret < 0) {
>> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
>> + goto out;
>> + }
>> +
>> + temp_sensor->clk_on = 1;
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
>> +{
>> + /* Gate the clock */
>> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
>> + temp_sensor->clk_on = 0;
>> +}
>> +
>> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
>> +{
>> + struct omap_temp_sensor *temp_sensor;
>> + int t_hot, t_cold, temp;
>> +
>> + temp_sensor = data;
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + /* Read the status of t_hot */
>> + t_hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_status)
>> + & temp_sensor->registers->status_hot_mask;
>> +
>> + /* Read the status of t_cold */
>> + t_cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_status)
>> + & temp_sensor->registers->status_cold_mask;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->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) {
>> + temp &= ~temp_sensor->registers->mask_hot_mask;
>> + temp |= temp_sensor->registers->mask_cold_mask;
>> + } else if (t_cold) {
>> + temp &= ~temp_sensor->registers->mask_cold_mask;
>> + temp |= temp_sensor->registers->mask_hot_mask;
>> + }
>> +
>> + omap_temp_sensor_writel(temp_sensor, temp,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> +
>> + if (temp_sensor->hwmon_dev)
>> + /* kobject_uvent to user space telling threshold crossed */
>> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
>> +
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
>> +{
>> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
>> + struct omap_temp_sensor *temp_sensor;
>> + struct resource *mem;
>> + int ret = 0;
>> + int clk_rate;
>> + u32 max_freq, min_freq;
>> +
>> + if (!pdata) {
>> + dev_err(&pdev->dev, "platform data missing\n");
>> + return -EINVAL;
>> + }
>> +
>> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
>> + if (!temp_sensor) {
>> + dev_err(&pdev->dev, "Memory allocation failed\n");
>> + return -ENOMEM;
>> + }
>> +
>> + mutex_init(&temp_sensor->sensor_mutex);
>> +
>> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + if (!mem) {
>> + dev_err(&pdev->dev, "no mem resource\n");
>> + ret = -ENOMEM;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
>> + if (temp_sensor->irq < 0) {
>> + dev_err(&pdev->dev, "get_irq_byname failed\n");
>> + ret = temp_sensor->irq;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
>> + if (!temp_sensor->phy_base) {
>> + dev_err(&pdev->dev, "ioremap failed\n");
>> + ret = -ENOMEM;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->clock = NULL;
>> + temp_sensor->registers = pdata->registers;
>> + temp_sensor->pdev_dev = &pdev->dev;
>> +
>> + if (pdata->max_freq && pdata->min_freq) {
>> + max_freq = pdata->max_freq;
>> + min_freq = pdata->min_freq;
>> + } else {
>> + max_freq = MAX_FREQ;
>> + min_freq = MIN_FREQ;
>> + }
>> +
>> + pm_runtime_enable(&pdev->dev);
>> + pm_runtime_irq_safe(&pdev->dev);
>> +
>> + /*
>> + * check if the efuse has a non-zero value if not
>> + * it is an untrimmed sample and the temperatures
>> + * may not be accurate
>> + */
>> +
>> + if (omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_efuse))
>> + dev_info(&pdev->dev,
>> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
>> +
>> + dev_set_drvdata(&pdev->dev, temp_sensor);
>> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
>> + if (IS_ERR(temp_sensor->clock)) {
>> + ret = PTR_ERR(temp_sensor->clock);
>> + dev_err(&pdev->dev,
>> + "unable to get fclk: %d\n", ret);
>> + goto plat_res_err;
>> + }
>> +
>> + ret = omap_temp_sensor_clk_enable(temp_sensor);
>> + if (ret)
>> + goto clken_err;
>> +
>> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
>> + if (clk_rate < min_freq || clk_rate == 0xffffffff) {
>> + ret = -ENODEV;
>> + goto clken_err;
>> + }
>> +
>> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Cannot set clock rate\n");
>> + goto clken_err;
>> + }
>> +
>> + temp_sensor->clk_rate = clk_rate;
>> + omap_enable_continuous_mode(temp_sensor);
>> + /* 1 clk cycle */
>> + omap_configure_temp_sensor_counter(temp_sensor, 1);
>> +
>> + /* Wait till the first conversion is done wait for at least 1ms */
>> + usleep_range(1000, 2000);
>> +
>> + /* Read the temperature once due to hw issue*/
>> + omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> +
>> + /* Set 2 seconds time as default counter */
>> + omap_configure_temp_sensor_counter(temp_sensor,
>> + temp_sensor->clk_rate * 2);
>> +
>> + ret = request_threaded_irq(temp_sensor->irq, NULL,
>> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>> + "temp_sensor", temp_sensor);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
>> + goto req_irq_err;
>> + }
>> +
>> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
>> + if (ret) {
>> + dev_err(&pdev->dev, "could not create sysfs files\n");
>> + goto sysfs_create_err;
>> + }
>> +
>> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
>> + if (IS_ERR(temp_sensor->hwmon_dev)) {
>> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
>> + ret = PTR_ERR(temp_sensor->hwmon_dev);
>> + goto hwmon_reg_err;
>> + }
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
>> + T_HOT, T_COLD);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return 0;
>> +
>> +hwmon_reg_err:
>> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
>> + &omap_temp_sensor_group);
>> +sysfs_create_err:
>> + free_irq(temp_sensor->irq, temp_sensor);
>> +req_irq_err:
>> + omap_temp_sensor_clk_disable(temp_sensor);
>> +clken_err:
>> + clk_put(temp_sensor->clock);
>> + iounmap(temp_sensor->phy_base);
>> +plat_res_err:
>> + dev_set_drvdata(&pdev->dev, NULL);
>> + mutex_destroy(&temp_sensor->sensor_mutex);
>> + kfree(temp_sensor);
>> + return ret;
>> +}
>> +
>> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
>> +
>> + hwmon_device_unregister(&pdev->dev);
>> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
>> + &omap_temp_sensor_group);
>> + free_irq(temp_sensor->irq, temp_sensor);
>> + omap_temp_sensor_clk_disable(temp_sensor);
>> + clk_put(temp_sensor->clock);
>> + iounmap(temp_sensor->phy_base);
>> + dev_set_drvdata(&pdev->dev, NULL);
>> + mutex_destroy(&temp_sensor->sensor_mutex);
>> + kfree(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
>> +{
>> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp_sensor->temp_sensor_tshut_threshold =
>> + omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->thsut_threshold);
>> +}
>> +
>> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
>> +{
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->temp_sensor_ctrl,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_ctrl,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_counter,
>> + temp_sensor->registers->bgap_counter);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_threshold,
>> + temp_sensor->registers->bgap_threshold);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->temp_sensor_tshut_threshold,
>> + temp_sensor->registers->thsut_threshold);
>> +}
>> +
>> +static int omap_temp_sensor_suspend(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_save_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_resume(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_restore_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_save_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_runtime_resume(struct device *dev)
>> +{
>> + static int context_loss_count;
>> + int temp;
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
>> +
>> + if (temp != context_loss_count && context_loss_count != 0)
>> + omap_temp_sensor_restore_ctxt(temp_sensor);
>> +
>> + context_loss_count = temp;
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_idle(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
>> + omap_temp_sensor_resume)
>> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
>> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
>> +};
>> +
>> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
>> +#else
>> +#define DEV_PM_OPS NULL
>> +#endif
>> +
>> +static struct platform_driver omap_temp_sensor_driver = {
>> + .probe = omap_temp_sensor_probe,
>> + .remove = omap_temp_sensor_remove,
>> + .driver = {
>> + .name = "omap_temp_sensor",
>> + .pm = DEV_PM_OPS,
>> + },
>> +};
>> +
>> +int __init omap_temp_sensor_init(void)
>> +{
>> + return platform_driver_register(&omap_temp_sensor_driver);
>> +}
>> +module_init(omap_temp_sensor_init);
>> +
>> +static void __exit omap_temp_sensor_exit(void)
>> +{
>> + platform_driver_unregister(&omap_temp_sensor_driver);
>> +}
>> +module_exit(omap_temp_sensor_exit);
>> +
>> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:" DRIVER_NAME);
>> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> - Paul
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 17:53 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 17:53 UTC (permalink / raw)
To: Paul Walmsley; +Cc: linux-omap, Jean Delvare, Guenter Roeck, lm-sensors
On Thu, Sep 1, 2011 at 6:06 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi
>
> Some comments.
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> diff --git a/drivers/hwmon/omap_temp_sensor.c b/drivers/hwmon/omap_temp_sensor.c
>> new file mode 100644
>> index 0000000..67fa424
>> --- /dev/null
>> +++ b/drivers/hwmon/omap_temp_sensor.c
>> @@ -0,0 +1,881 @@
>
> You've done almost all the hard work to create kerneldoc-NANO compliant
> structure documentation, which is good. But a few important things are
> missing. Please review Documentation/kernel-doc-nano-HOWTO.txt.
Ok
>
>> +/*
>
> Should be /** to indicate kerneldoc.
Ok
>
>> + * omap_temp_sensor structure
>
> Should be "struct omap_temp_sensor" and should include a short
> description.
Ok
>
>> + * @hwmon_dev - hwmon device pointer
>> + * @pdev_dev - platform device pointer
>> + * @clock - Clock pointer
>> + * @registers - Pointer to structure with register offsets and bitfields
>> + * @sensor_mutex - Mutex for sysfs, irq and PM
>> + * @irq - MPU Irq number for thermal alert
>> + * @phy_base - Physical base of the temp I/O
>> + * @clk_rate - Holds current clock rate
>> + * @temp_sensor_ctrl - temp sensor control register value
>> + * @bg_ctrl - bandgap ctrl register value
>> + * @bg_counter - bandgap counter value
>> + * @bg_threshold - bandgap threshold register value
>> + * @temp_sensor_tshut_threshold - bandgap tshut register value
>> + * @clk_on - Manages the current clock state
>> + */
>
>> +struct omap_temp_sensor {
>> + struct device *hwmon_dev;
>> + struct device *pdev_dev;
>> + struct clk *clock;
>> + struct omap_temp_sensor_registers *registers;
>> + struct mutex sensor_mutex; /* Mutex for sysfs, irq and PM */
>> + unsigned int irq;
>> + void __iomem *phy_base;
>> + u32 clk_rate;
>> + u32 temp_sensor_ctrl;
>> + u32 bg_ctrl;
>> + u32 bg_counter;
>> + u32 bg_threshold;
>> + u32 temp_sensor_tshut_threshold;
>> + bool clk_on;
>> +};
>> +
>> +/*
>> + * Temperature values in milli degree celsius
>> + * ADC code values from 530 to 923
>> + */
>> +static int adc_to_temp[394] = {
>> + -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
>> +};
>> +
>> +static unsigned long omap_temp_sensor_readl(struct omap_temp_sensor
>> + *temp_sensor, u32 reg)
>> +{
>> + return __raw_readl(temp_sensor->phy_base + reg);
>> +}
>> +
>> +static void omap_temp_sensor_writel(struct omap_temp_sensor *temp_sensor,
>> + u32 val, u32 reg)
>> +{
>> + __raw_writel(val, temp_sensor->phy_base + reg);
>> +}
>
> These are all SCM register accesses and need to go through a SCM driver.
Accessing SCM registers using ctrl_ functions?
>
>> +
>> +static int adc_to_temp_conversion(int adc_val)
>> +{
>> + return adc_to_temp[adc_val - OMAP_ADC_START_VALUE];
>> +}
>> +
>> +static int temp_to_adc_conversion(long temp)
>> +{
>> + int high, low, mid;
>> +
>> + if (temp < adc_to_temp[0] ||
>> + temp > adc_to_temp[OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE])
>> + return -EINVAL;
>> +
>> + high = OMAP_ADC_END_VALUE - OMAP_ADC_START_VALUE;
>> + low = 0;
>> + mid = (high + low) / 2;
>> +
>> + while (low < high) {
>> + if (temp < adc_to_temp[mid])
>> + high = mid - 1;
>> + else
>> + low = mid + 1;
>> + mid = (low + high) / 2;
>> + }
>> +
>> + return OMAP_ADC_START_VALUE + low;
>> +}
>> +
>> +static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
>> + *temp_sensor, u32 counter)
>
> It doesn't seem necessary to include 'omap' in all these static function names.
>
Ok
>> +{
>> + u32 val;
>> +
>> + val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + val &= ~temp_sensor->registers->counter_mask;
>> + val |= counter << __ffs(temp_sensor->registers->counter_mask);
>> + omap_temp_sensor_writel(temp_sensor, val,
>> + temp_sensor->registers->bgap_counter);
>> +}
>> +
>> +static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
>> +{
>> + u32 val;
>> +
>> + val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mode_ctrl);
>> +
>> + val |= 1 << __ffs(temp_sensor->registers->mode_ctrl_mask);
>> +
>> + omap_temp_sensor_writel(temp_sensor, val,
>> + temp_sensor->registers->bgap_mode_ctrl);
>> +}
>> +
>> +static void omap_temp_sensor_unmask_interrupts(struct omap_temp_sensor
>> + *temp_sensor, u8 hot, u8 cold)
>
> Your earlier static function names didn't include 'temp_sensor', but
> this one does. I'd suggest picking a standard function naming scheme
> and sticking to it.
Ok
>
>> +{
>> + u32 reg_val;
>> +
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + if (hot)
>> + reg_val |= temp_sensor->registers->mask_hot_mask;
>> + else
>> + reg_val &= ~temp_sensor->registers->mask_hot_mask;
>> +
>> + if (cold)
>> + reg_val |= temp_sensor->registers->mask_cold_mask;
>> + else
>> + reg_val &= ~temp_sensor->registers->mask_cold_mask;
>> +
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> +}
>> +
>> +static void add_hyst(int adc_val, int hyst_val, int *thresh_val)
>> +{
>> + int temp = adc_to_temp_conversion(adc_val);
>> +
>> + temp += hyst_val;
>> +
>> + *thresh_val = temp_to_adc_conversion(temp);
>> +}
>> +
>> +static void omap_temp_sensor_configure_thresholds_mask(struct omap_temp_sensor
>> + *temp_sensor, bool set_hot, bool set_cold, int t_hot, int t_cold)
>
> Is there some reason why you don't just define a
>
> omap_temp_sensor_configure_hot_threshold()
>
> and
>
> omap_temp_sensor_configure_cold_threshold()
>
> ?
>
> Seems like that would be much more straightforward and would allow the
> removal of those set_{hot,cold} arguments.
Kept everything in one function. I can split it into separate functions.
>
>> +{
>> + int reg_val, cold, hot, temp;
>
> This function is really big and should be split up into several smaller
> functions. Common code should be shared if possible.
Ok
>
>> +
>> + if (set_hot) {
>> + /* obtain the T cold value */
>> + cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
>> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
>
> This code should be hoisted up above the if statements. Only a single
> device read should be necessary to fetch both the hot and cold values.
> Then the near-duplicate code below to read the hot temperature can be
> removed.
>
> In fact, given that this patch has almost the same code several times,
> you should just put it into a static function or two and remove the
> duplicate code.
Ok. I will remove the duplicate code.
>
>> +
>> + if (t_hot < cold) {
>> + /* change the t_cold to t_hot - 5000 millidegrees */
>> + add_hyst(t_hot, NEG_HYST_VAL, &cold);
>> + /* write the new t_cold value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &>> + ~temp_sensor->registers->threshold_tcold_mask;
>> + reg_val |= cold <<
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>
> Looks like there are some indentation problems here. Those are more
> important than 80-column issues.
>
Ok
> Of course, you use temp_sensor->registers so much in this function, that
> many of the line length issues would go away if you used a shorter
> abbreviation at the beginning of this function, like:
>
> tsr = temp_sensor->registers;
Sure. Makes the code look neat.
>
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + t_cold = cold;
>> + }
>> +
>> + /* write the new t_hot value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &= ~temp_sensor->registers->threshold_thot_mask;
>> + reg_val |= (t_hot <<
>> + __ffs(temp_sensor->registers->threshold_thot_mask));
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + }
>> +
>> + if (set_cold) {
>> + /* obtain the T HOT value */
>> + hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
>> + __ffs(temp_sensor->registers->threshold_thot_mask);
>
> See the earlier comment about hoisting.
Ok
>
>> + if (t_cold > hot) {
>> + /* change the t_hot to t_cold + 5000 millidegrees */
>> + add_hyst(t_cold, HYST_VAL, &hot);
>> + /* write the new t_hot value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &>> + ~temp_sensor->registers->threshold_thot_mask;
>> + reg_val |= (hot <<
>> + __ffs(temp_sensor->registers->threshold_thot_mask));
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>
> This is a duplicate of earlier code. Please consolidate.
Ok
>
>> + t_hot = hot;
>> + }
>> +
>> + /* write the new t_cold value */
>> + reg_val = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + reg_val &= ~temp_sensor->registers->threshold_tcold_mask;
>> + reg_val |= t_cold <<
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>> + omap_temp_sensor_writel(temp_sensor, reg_val,
>> + temp_sensor->registers->bgap_threshold);
>> + }
>> + /* obtain the T cold value */
>> + cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + cold = (cold & temp_sensor->registers->threshold_tcold_mask)
>> + >> __ffs(temp_sensor->registers->threshold_tcold_mask);
>> +
>> + /* obtain the T HOT value */
>> + hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + hot = (hot & temp_sensor->registers->threshold_thot_mask) >>
>> + __ffs(temp_sensor->registers->threshold_thot_mask);
>> +
>> + /* Read the current temperature */
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp &= temp_sensor->registers->bgap_dtemp_mask;
>> +
>> + /*
>> + * If current temperature is in-between the hot and cold thresholds
>> + * Enable both masks or in the init case enable both masks
>> + */
>> + if ((temp > cold && temp < hot) || (set_cold && set_hot))
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
>> +
>> + /*
>> + * If user sets the HIGH threshold(t_hot) greater than the current
>> + * temperature(temp) unmask the HOT interrupts
>> + */
>> + else if (hot > temp)
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
>> +
>> + /*
>> + * If user sets the LOW threshold(t_cold) lower than the current
>> + * temperature(temp) unmask the COLD interrupts
>> + */
>> + else
>> + omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
>
> This if statement is surely a violation of the spirit of
> Documentation/CodingStyle, if not the text itself.
>
> If you really need an if statement like this, try something like:
>
> if ((temp > cold && temp < hot) || (set_cold && set_hot)) {
> /*
> * If current temperature is in-between the hot and cold thresholds
> * Enable both masks or in the init case enable both masks
> */
>
> omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 1);
> } else if (hot > temp) {
> /*
> * If user sets the HIGH threshold(t_hot) greater than the current
> * temperature(temp) unmask the HOT interrupts
> */
> omap_temp_sensor_unmask_interrupts(temp_sensor, 1, 0);
> } else {
> /*
> * If user sets the LOW threshold(t_cold) lower than the current
> * temperature(temp) unmask the COLD interrupts
> */
> omap_temp_sensor_unmask_interrupts(temp_sensor, 0, 1);
> }
>
Ok
>
>> +}
>> +
>> +/* Sysfs hook functions */
>
> These should be conditionally compiled out if sysfs isn't compiled in.
>
>> +
>> +static ssize_t show_temp_max(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + int temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp = (temp & temp_sensor->registers->threshold_thot_mask)
>> + >> __ffs(temp_sensor->registers->threshold_thot_mask);
>> + temp = adc_to_temp_conversion(temp);
>> +
>> + return snprintf(buf, 16, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_temp_max(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + long val;
>> + u32 t_hot;
>> +
>> + if (strict_strtol(buf, 10, &val))
>> + return -EINVAL;
>> + if (val < MIN_TEMP - HYST_VAL)
>> + return -EINVAL;
>> +
>> + t_hot = temp_to_adc_conversion(val);
>> + if (t_hot < 0)
>> + return t_hot;
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 0,
>> + t_hot, 0);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return count;
>> +}
>> +
>> +static ssize_t show_temp_max_hyst(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp = (temp & temp_sensor->registers->threshold_tcold_mask) >>
>> + __ffs(temp_sensor->registers->threshold_tcold_mask);
>> +
>> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
>> + dev_err(dev, "invalid value\n");
>> + return -EIO;
>> + }
>> +
>> + temp = adc_to_temp_conversion(temp);
>> +
>> + return snprintf(buf, 16, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_temp_max_hyst(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 t_cold;
>> + long val;
>> +
>> + if (strict_strtol(buf, 10, &val)) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + if (val > MAX_TEMP - HYST_VAL) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + t_cold = temp_to_adc_conversion(val);
>> + if (t_cold < 0)
>> + return t_cold;
>> +
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 0, 1, 0,
>> + t_cold);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> +out:
>> + return count;
>> +}
>> +
>> +static ssize_t show_update_interval(struct device *dev,
>> + struct device_attribute *devattr, char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + u32 temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + temp = (temp & temp_sensor->registers->counter_mask) >>
>> + __ffs(temp_sensor->registers->counter_mask);
>> + temp = temp * 1000 / temp_sensor->clk_rate;
>> +
>> + return sprintf(buf, "%d\n", temp);
>> +}
>> +
>> +static ssize_t set_update_interval(struct device *dev,
>> + struct device_attribute *devattr,
>> + const char *buf, size_t count)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + long val;
>> +
>> + if (strict_strtol(buf, 10, &val)) {
>> + count = -EINVAL;
>> + goto out;
>> + }
>> +
>> + if (val < 0)
>> + return -EINVAL;
>> + val *= temp_sensor->clk_rate / 1000;
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_configure_temp_sensor_counter(temp_sensor, val);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +out:
>> + return count;
>> +}
>> +
>> +static int omap_temp_sensor_read_temp(struct device *dev,
>> + struct device_attribute *devattr,
>> + char *buf)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> + int temp;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp &= temp_sensor->registers->bgap_dtemp_mask;
>> +
>> + /* look up for temperature in the table and return the temperature */
>> + if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)
>> + return -EIO;
>> +
>> + temp = adc_to_temp[temp - OMAP_ADC_START_VALUE];
>> +
>> + return sprintf(buf, "%d\n", temp);
>> +}
>> +
>> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, omap_temp_sensor_read_temp,
>> + NULL, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
>> + set_temp_max, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_max_hyst,
>> + set_temp_max_hyst, 0);
>> +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
>> + show_update_interval, set_update_interval, 0);
>> +
>> +static struct attribute *omap_temp_sensor_attributes[] = {
>> + &sensor_dev_attr_temp1_input.dev_attr.attr,
>> + &sensor_dev_attr_temp1_max.dev_attr.attr,
>> + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> + &sensor_dev_attr_update_interval.dev_attr.attr,
>> + NULL
>> +};
>> +
>> +static const struct attribute_group omap_temp_sensor_group = {
>> + .attrs = omap_temp_sensor_attributes,
>> +};
>> +
>> +static int omap_temp_sensor_clk_enable(struct omap_temp_sensor *temp_sensor)
>> +{
>> + u32 ret = 0;
>> +
>> + if (temp_sensor->clk_on) {
>> + dev_err(temp_sensor->pdev_dev, "clock already on\n");
>> + goto out;
>> + }
>> +
>> + ret = pm_runtime_get_sync(temp_sensor->pdev_dev);
>> + if (ret < 0) {
>> + dev_err(temp_sensor->pdev_dev, "get sync failed\n");
>> + goto out;
>> + }
>> +
>> + temp_sensor->clk_on = 1;
>> +
>> +out:
>> + return ret;
>> +}
>> +
>> +static void omap_temp_sensor_clk_disable(struct omap_temp_sensor *temp_sensor)
>> +{
>> + /* Gate the clock */
>> + pm_runtime_put_sync(temp_sensor->hwmon_dev);
>> + temp_sensor->clk_on = 0;
>> +}
>> +
>> +static irqreturn_t omap_talert_irq_handler(int irq, void *data)
>> +{
>> + struct omap_temp_sensor *temp_sensor;
>> + int t_hot, t_cold, temp;
>> +
>> + temp_sensor = data;
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + /* Read the status of t_hot */
>> + t_hot = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_status)
>> + & temp_sensor->registers->status_hot_mask;
>> +
>> + /* Read the status of t_cold */
>> + t_cold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_status)
>> + & temp_sensor->registers->status_cold_mask;
>> +
>> + temp = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->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) {
>> + temp &= ~temp_sensor->registers->mask_hot_mask;
>> + temp |= temp_sensor->registers->mask_cold_mask;
>> + } else if (t_cold) {
>> + temp &= ~temp_sensor->registers->mask_cold_mask;
>> + temp |= temp_sensor->registers->mask_hot_mask;
>> + }
>> +
>> + omap_temp_sensor_writel(temp_sensor, temp,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> +
>> + if (temp_sensor->hwmon_dev)
>> + /* kobject_uvent to user space telling threshold crossed */
>> + kobject_uevent(&temp_sensor->hwmon_dev->kobj, KOBJ_CHANGE);
>> +
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
>> +{
>> + struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
>> + struct omap_temp_sensor *temp_sensor;
>> + struct resource *mem;
>> + int ret = 0;
>> + int clk_rate;
>> + u32 max_freq, min_freq;
>> +
>> + if (!pdata) {
>> + dev_err(&pdev->dev, "platform data missing\n");
>> + return -EINVAL;
>> + }
>> +
>> + temp_sensor = kzalloc(sizeof(*temp_sensor), GFP_KERNEL);
>> + if (!temp_sensor) {
>> + dev_err(&pdev->dev, "Memory allocation failed\n");
>> + return -ENOMEM;
>> + }
>> +
>> + mutex_init(&temp_sensor->sensor_mutex);
>> +
>> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + if (!mem) {
>> + dev_err(&pdev->dev, "no mem resource\n");
>> + ret = -ENOMEM;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
>> + if (temp_sensor->irq < 0) {
>> + dev_err(&pdev->dev, "get_irq_byname failed\n");
>> + ret = temp_sensor->irq;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->phy_base = ioremap(mem->start, resource_size(mem));
>> + if (!temp_sensor->phy_base) {
>> + dev_err(&pdev->dev, "ioremap failed\n");
>> + ret = -ENOMEM;
>> + goto plat_res_err;
>> + }
>> +
>> + temp_sensor->clock = NULL;
>> + temp_sensor->registers = pdata->registers;
>> + temp_sensor->pdev_dev = &pdev->dev;
>> +
>> + if (pdata->max_freq && pdata->min_freq) {
>> + max_freq = pdata->max_freq;
>> + min_freq = pdata->min_freq;
>> + } else {
>> + max_freq = MAX_FREQ;
>> + min_freq = MIN_FREQ;
>> + }
>> +
>> + pm_runtime_enable(&pdev->dev);
>> + pm_runtime_irq_safe(&pdev->dev);
>> +
>> + /*
>> + * check if the efuse has a non-zero value if not
>> + * it is an untrimmed sample and the temperatures
>> + * may not be accurate
>> + */
>> +
>> + if (omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_efuse))
>> + dev_info(&pdev->dev,
>> + "Invalid EFUSE, Non-trimmed BGAP, Temp not accurate\n");
>> +
>> + dev_set_drvdata(&pdev->dev, temp_sensor);
>> + temp_sensor->clock = clk_get(&pdev->dev, "fck");
>> + if (IS_ERR(temp_sensor->clock)) {
>> + ret = PTR_ERR(temp_sensor->clock);
>> + dev_err(&pdev->dev,
>> + "unable to get fclk: %d\n", ret);
>> + goto plat_res_err;
>> + }
>> +
>> + ret = omap_temp_sensor_clk_enable(temp_sensor);
>> + if (ret)
>> + goto clken_err;
>> +
>> + clk_rate = clk_round_rate(temp_sensor->clock, max_freq);
>> + if (clk_rate < min_freq || clk_rate = 0xffffffff) {
>> + ret = -ENODEV;
>> + goto clken_err;
>> + }
>> +
>> + ret = clk_set_rate(temp_sensor->clock, clk_rate);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Cannot set clock rate\n");
>> + goto clken_err;
>> + }
>> +
>> + temp_sensor->clk_rate = clk_rate;
>> + omap_enable_continuous_mode(temp_sensor);
>> + /* 1 clk cycle */
>> + omap_configure_temp_sensor_counter(temp_sensor, 1);
>> +
>> + /* Wait till the first conversion is done wait for at least 1ms */
>> + usleep_range(1000, 2000);
>> +
>> + /* Read the temperature once due to hw issue*/
>> + omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> +
>> + /* Set 2 seconds time as default counter */
>> + omap_configure_temp_sensor_counter(temp_sensor,
>> + temp_sensor->clk_rate * 2);
>> +
>> + ret = request_threaded_irq(temp_sensor->irq, NULL,
>> + omap_talert_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>> + "temp_sensor", temp_sensor);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Request threaded irq failed.\n");
>> + goto req_irq_err;
>> + }
>> +
>> + ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
>> + if (ret) {
>> + dev_err(&pdev->dev, "could not create sysfs files\n");
>> + goto sysfs_create_err;
>> + }
>> +
>> + temp_sensor->hwmon_dev = hwmon_device_register(&pdev->dev);
>> + if (IS_ERR(temp_sensor->hwmon_dev)) {
>> + dev_err(&pdev->dev, "hwmon_device_register failed.\n");
>> + ret = PTR_ERR(temp_sensor->hwmon_dev);
>> + goto hwmon_reg_err;
>> + }
>> +
>> + mutex_lock(&temp_sensor->sensor_mutex);
>> + omap_temp_sensor_configure_thresholds_mask(temp_sensor, 1, 1,
>> + T_HOT, T_COLD);
>> + mutex_unlock(&temp_sensor->sensor_mutex);
>> +
>> + return 0;
>> +
>> +hwmon_reg_err:
>> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
>> + &omap_temp_sensor_group);
>> +sysfs_create_err:
>> + free_irq(temp_sensor->irq, temp_sensor);
>> +req_irq_err:
>> + omap_temp_sensor_clk_disable(temp_sensor);
>> +clken_err:
>> + clk_put(temp_sensor->clock);
>> + iounmap(temp_sensor->phy_base);
>> +plat_res_err:
>> + dev_set_drvdata(&pdev->dev, NULL);
>> + mutex_destroy(&temp_sensor->sensor_mutex);
>> + kfree(temp_sensor);
>> + return ret;
>> +}
>> +
>> +static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
>> +
>> + hwmon_device_unregister(&pdev->dev);
>> + sysfs_remove_group(&temp_sensor->hwmon_dev->kobj,
>> + &omap_temp_sensor_group);
>> + free_irq(temp_sensor->irq, temp_sensor);
>> + omap_temp_sensor_clk_disable(temp_sensor);
>> + clk_put(temp_sensor->clock);
>> + iounmap(temp_sensor->phy_base);
>> + dev_set_drvdata(&pdev->dev, NULL);
>> + mutex_destroy(&temp_sensor->sensor_mutex);
>> + kfree(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
>> +{
>> + temp_sensor->temp_sensor_ctrl = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + temp_sensor->bg_ctrl = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + temp_sensor->bg_counter = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_counter);
>> + temp_sensor->bg_threshold = omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->bgap_threshold);
>> + temp_sensor->temp_sensor_tshut_threshold >> + omap_temp_sensor_readl(temp_sensor,
>> + temp_sensor->registers->thsut_threshold);
>> +}
>> +
>> +static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
>> +{
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->temp_sensor_ctrl,
>> + temp_sensor->registers->temp_sensor_ctrl);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_ctrl,
>> + temp_sensor->registers->bgap_mask_ctrl);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_counter,
>> + temp_sensor->registers->bgap_counter);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->bg_threshold,
>> + temp_sensor->registers->bgap_threshold);
>> + omap_temp_sensor_writel(temp_sensor,
>> + temp_sensor->temp_sensor_tshut_threshold,
>> + temp_sensor->registers->thsut_threshold);
>> +}
>> +
>> +static int omap_temp_sensor_suspend(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_save_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_resume(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_restore_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_runtime_suspend(struct device *dev)
>> +{
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + omap_temp_sensor_save_ctxt(temp_sensor);
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_runtime_resume(struct device *dev)
>> +{
>> + static int context_loss_count;
>> + int temp;
>> + struct omap_temp_sensor *temp_sensor = dev_get_drvdata(dev);
>> +
>> + temp = omap_device_get_context_loss_count(to_platform_device(dev));
>> +
>> + if (temp != context_loss_count && context_loss_count != 0)
>> + omap_temp_sensor_restore_ctxt(temp_sensor);
>> +
>> + context_loss_count = temp;
>> +
>> + return 0;
>> +}
>> +
>> +static int omap_temp_sensor_idle(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static const struct dev_pm_ops omap_temp_sensor_dev_pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(omap_temp_sensor_suspend,
>> + omap_temp_sensor_resume)
>> + SET_RUNTIME_PM_OPS(omap_temp_sensor_runtime_suspend,
>> + omap_temp_sensor_runtime_resume, omap_temp_sensor_idle)
>> +};
>> +
>> +#define DEV_PM_OPS (&omap_temp_sensor_dev_pm_ops)
>> +#else
>> +#define DEV_PM_OPS NULL
>> +#endif
>> +
>> +static struct platform_driver omap_temp_sensor_driver = {
>> + .probe = omap_temp_sensor_probe,
>> + .remove = omap_temp_sensor_remove,
>> + .driver = {
>> + .name = "omap_temp_sensor",
>> + .pm = DEV_PM_OPS,
>> + },
>> +};
>> +
>> +int __init omap_temp_sensor_init(void)
>> +{
>> + return platform_driver_register(&omap_temp_sensor_driver);
>> +}
>> +module_init(omap_temp_sensor_init);
>> +
>> +static void __exit omap_temp_sensor_exit(void)
>> +{
>> + platform_driver_unregister(&omap_temp_sensor_driver);
>> +}
>> +module_exit(omap_temp_sensor_exit);
>> +
>> +MODULE_DESCRIPTION("OMAP446X temperature sensor Driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:" DRIVER_NAME);
>> +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> - Paul
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 4:09 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
@ 2011-09-06 17:58 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 17:57 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Guenter Roeck, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 1, 2011 at 9:39 AM, Paul Walmsley <paul@pwsan.com> wrote:
> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>
>> On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> > Hi
>> >
>> > Some comments.
>> >
>> > On Wed, 31 Aug 2011, Keerthy wrote:
>> >
>> [ ... ]
>> >
>> > > +}
>> > > +
>> > > +/* Sysfs hook functions */
>> >
>> > These should be conditionally compiled out if sysfs isn't compiled in.
>> >
>> The whole point of the hwmon subsystem is to expose hardware monitoring information
>> to userland using sysfs. hwmon without sysfs doesn't make sense.
>>
>> So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> But please no conditionals in the code.
>
> Hmm. This IP block is more than just a sensor. It also can interrupt the
> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> temperature crosses some thresholds. On some OMAPs, the thresholds are
> fixed; on others, they are software-programmable. That functionality
> shouldn't require sysfs; it's almost closer to an x86 MCE.
The TSHUT thresholds are not even exposed through the sysfs nodes.
This driver only creates sysfs nodes for TALERT thresholds.
>
> So based on your comments, it sounds like we should move that part of the
> code to a different driver, and just leave the basic software thermal
> monitoring here?
What part of code should be moved?
This driver does just the basic hardware monitoring and exposes
configurable thresholds for t_hot and t_cold.
This does not include t_shut configuration and handling. This is
a simple hardware monitoring driver which does not cater to
Thermal management. That is being discussed separately in other
thread.
>
>
> - Paul
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 17:58 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 17:58 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Guenter Roeck, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 1, 2011 at 9:39 AM, Paul Walmsley <paul@pwsan.com> wrote:
> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>
>> On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> > Hi
>> >
>> > Some comments.
>> >
>> > On Wed, 31 Aug 2011, Keerthy wrote:
>> >
>> [ ... ]
>> >
>> > > +}
>> > > +
>> > > +/* Sysfs hook functions */
>> >
>> > These should be conditionally compiled out if sysfs isn't compiled in.
>> >
>> The whole point of the hwmon subsystem is to expose hardware monitoring information
>> to userland using sysfs. hwmon without sysfs doesn't make sense.
>>
>> So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> But please no conditionals in the code.
>
> Hmm. This IP block is more than just a sensor. It also can interrupt the
> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> temperature crosses some thresholds. On some OMAPs, the thresholds are
> fixed; on others, they are software-programmable. That functionality
> shouldn't require sysfs; it's almost closer to an x86 MCE.
The TSHUT thresholds are not even exposed through the sysfs nodes.
This driver only creates sysfs nodes for TALERT thresholds.
>
> So based on your comments, it sounds like we should move that part of the
> code to a different driver, and just leave the basic software thermal
> monitoring here?
What part of code should be moved?
This driver does just the basic hardware monitoring and exposes
configurable thresholds for t_hot and t_cold.
This does not include t_shut configuration and handling. This is
a simple hardware monitoring driver which does not cater to
Thermal management. That is being discussed separately in other
thread.
>
>
> - Paul
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 4:40 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
@ 2011-09-06 18:14 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 18:02 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>>
>> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> > > Hi
>> > >
>> > > Some comments.
>> > >
>> > > On Wed, 31 Aug 2011, Keerthy wrote:
>> > >
>> > [ ... ]
>> > >
>> > > > +}
>> > > > +
>> > > > +/* Sysfs hook functions */
>> > >
>> > > These should be conditionally compiled out if sysfs isn't compiled in.
>> > >
>> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>> >
>> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> > But please no conditionals in the code.
>>
>> Hmm. This IP block is more than just a sensor. It also can interrupt the
>> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>> temperature crosses some thresholds. On some OMAPs, the thresholds are
>> fixed; on others, they are software-programmable. That functionality
>> shouldn't require sysfs; it's almost closer to an x86 MCE.
>>
>> So based on your comments, it sounds like we should move that part of the
>> code to a different driver, and just leave the basic software thermal
>> monitoring here?
>>
> Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
> as the name says, not thermal management. Maybe this entire driver should be a thermal driver
> instead ?
This driver is not taking any action on THSUT. This is not doing the thermal
management. It is a driver exposing configurable temperature thresholds.
>
> Guenter
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-06 18:14 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
@ 2011-09-06 18:12 ` Guenter Roeck
-1 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-06 18:12 UTC (permalink / raw)
To: J, KEERTHY; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
> >>
> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> >> > > Hi
> >> > >
> >> > > Some comments.
> >> > >
> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
> >> > >
> >> > [ ... ]
> >> > >
> >> > > > +}
> >> > > > +
> >> > > > +/* Sysfs hook functions */
> >> > >
> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
> >> > >
> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
> >> >
> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> >> > But please no conditionals in the code.
> >>
> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
> >> fixed; on others, they are software-programmable. That functionality
> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
> >>
> >> So based on your comments, it sounds like we should move that part of the
> >> code to a different driver, and just leave the basic software thermal
> >> monitoring here?
> >>
> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
> > instead ?
>
> This driver is not taking any action on THSUT. This is not doing the thermal
> management. It is a driver exposing configurable temperature thresholds.
What sense would it make, then, to keep the driver around even if SYSFS
is not defined ?
Note that I am not looking at the code right now, but at the suggestion
that the driver would do something useful if SYSFS is not defined.
Question is what that is, and if that part of it should reside in a
hwmon driver.
Thanks,
Guenter
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 18:12 ` Guenter Roeck
0 siblings, 0 replies; 43+ messages in thread
From: Guenter Roeck @ 2011-09-06 18:12 UTC (permalink / raw)
To: J, KEERTHY; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
> >>
> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
> >> > > Hi
> >> > >
> >> > > Some comments.
> >> > >
> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
> >> > >
> >> > [ ... ]
> >> > >
> >> > > > +}
> >> > > > +
> >> > > > +/* Sysfs hook functions */
> >> > >
> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
> >> > >
> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
> >> >
> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
> >> > But please no conditionals in the code.
> >>
> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
> >> fixed; on others, they are software-programmable. That functionality
> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
> >>
> >> So based on your comments, it sounds like we should move that part of the
> >> code to a different driver, and just leave the basic software thermal
> >> monitoring here?
> >>
> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
> > instead ?
>
> This driver is not taking any action on THSUT. This is not doing the thermal
> management. It is a driver exposing configurable temperature thresholds.
What sense would it make, then, to keep the driver around even if SYSFS
is not defined ?
Note that I am not looking at the code right now, but at the suggestion
that the driver would do something useful if SYSFS is not defined.
Question is what that is, and if that part of it should reside in a
hwmon driver.
Thanks,
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 18:14 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 18:14 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>>
>> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> > > Hi
>> > >
>> > > Some comments.
>> > >
>> > > On Wed, 31 Aug 2011, Keerthy wrote:
>> > >
>> > [ ... ]
>> > >
>> > > > +}
>> > > > +
>> > > > +/* Sysfs hook functions */
>> > >
>> > > These should be conditionally compiled out if sysfs isn't compiled in.
>> > >
>> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>> >
>> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> > But please no conditionals in the code.
>>
>> Hmm. This IP block is more than just a sensor. It also can interrupt the
>> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>> temperature crosses some thresholds. On some OMAPs, the thresholds are
>> fixed; on others, they are software-programmable. That functionality
>> shouldn't require sysfs; it's almost closer to an x86 MCE.
>>
>> So based on your comments, it sounds like we should move that part of the
>> code to a different driver, and just leave the basic software thermal
>> monitoring here?
>>
> Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
> as the name says, not thermal management. Maybe this entire driver should be a thermal driver
> instead ?
This driver is not taking any action on THSUT. This is not doing the thermal
management. It is a driver exposing configurable temperature thresholds.
>
> Guenter
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor
2011-08-31 23:16 ` Paul Walmsley
@ 2011-09-06 18:24 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 18:24 UTC (permalink / raw)
To: Paul Walmsley; +Cc: Benoit Cousson, linux-omap, tony
On Thu, Sep 1, 2011 at 4:46 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi Keerthy, Benoît,
>
> On Wed, 31 Aug 2011, Keerthy wrote:
>
>> From: Benoit Cousson <b-cousson@ti.com>
>>
>> OMAP4460 temperature sensor hwmod cannot be auto generated
>> since it is part of ctrl module. Hence populating the
>> necessary hwmod info manually.
>
> Looking at the 4460 1.x TRM Rev H, does it makes sense to create a
> separate hwmod structure for this IP block? It looks to me like these
> registers are integrated pretty tightly inside the SYSCTRL_GENERAL_CORE IP
> block. So from a hwmod perspective, it seems to be a different situation
> than, say, the RFBI block inside the DSS subsystem?
>
> Just based on looking at Table 18-110 "Control Module Instance Summary"
> and Table 18-111 "SYSCTRL_GENERAL_CORE Register Mapping Summary", it seems
> to me that this IP block is best represented as an MFD. Something like
> drivers/mfd/wm8350-core.c, which registers a hwmon device, which is then
> driven by drivers/hwmon/wm8350-hwmon.c.
In case of OMAP4460 only one instance of thermal sensor is present.
If i take the case of OMAP5 multiple (3) instances are present. I agree
all the registers are part of SYSCTRL. Defining a hwmod i could easily
call omap_hwmod_for_each_by_class() for multiple instances. WIthout
hwmod i am not sure how to cater to this requirement. Any inputs?
>
> That should avoid the need for this hwmod entry too.
>
>>
>> Signed-off-by: Benoit Cousson <b-cousson@ti.com>
>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>> Cc: tony@atomide.com
>> Cc: b-cousson@ti.com
>> ---
>> arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 61 ++++++++++++++++++++++++++++
>> 1 files changed, 61 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
>> index 6201422..28bf6d3 100644
>> --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
>> +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
>> @@ -29,6 +29,7 @@
>> #include <plat/mcbsp.h>
>> #include <plat/mmc.h>
>> #include <plat/i2c.h>
>> +#include <plat/temperature_sensor.h>
>>
>> #include "omap_hwmod_common_data.h"
>>
>> @@ -832,6 +833,63 @@ static struct omap_hwmod omap44xx_aess_hwmod = {
>> };
>>
>> /*
>> + * 'temperature_sensor' class
>> + * temperature sensor module inside the bandgap / control module
>> + */
>> +
>> +static struct omap_hwmod_class omap44xx_temperature_sensor_hwmod_class = {
>> + .name = "temperature_sensor",
>> +};
>> +
>> +static struct omap_hwmod_irq_info omap44xx_temperature_sensor_irqs[] = {
>> + { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START },
>> +};
>> +
>> +static struct omap_hwmod_addr_space omap44xx_temperature_sensor_addrs[] = {
>> + {
>> + .pa_start = 0x4a00232c,
>> + .pa_end = 0x4a00238b,
>> + },
>> +};
>> +
>> +static struct omap_hwmod omap44xx_temperature_sensor_hwmod;
>> +/* l4_cfg -> ctrl_module_core */
>> +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__temperature_sensor = {
>> + .master = &omap44xx_l4_cfg_hwmod,
>> + .slave = &omap44xx_temperature_sensor_hwmod,
>> + .clk = "l4_div_ck",
>> + .addr = omap44xx_temperature_sensor_addrs,
>> + .user = OCP_USER_MPU | OCP_USER_SDMA,
>> +};
>> +
>> +/* ctrl_module_core slave ports */
>> +static struct omap_hwmod_ocp_if *omap44xx_temperature_sensor_slaves[] = {
>> + &omap44xx_l4_cfg__temperature_sensor,
>> +};
>> +
>> +/* temperature sensor dev_attr */
>> +static struct omap_temp_sensor_dev_attr temp_sensor_dev_attr = {
>> + .name = "mpu",
>> +};
>> +
>> +static struct omap_hwmod omap44xx_temperature_sensor_hwmod = {
>> + .name = "temperature_sensor_mpu",
>> + .class = &omap44xx_temperature_sensor_hwmod_class,
>> + .mpu_irqs = omap44xx_temperature_sensor_irqs,
>> + .main_clk = "bandgap_ts_fclk",
>> + .slaves = omap44xx_temperature_sensor_slaves,
>> + .slaves_cnt = ARRAY_SIZE(omap44xx_temperature_sensor_slaves),
>> + .clkdm_name = "l4_wkup_clkdm",
>> + .prcm = {
>> + .omap4 = {
>> + .clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
>> + },
>> + },
>> + .dev_attr = &temp_sensor_dev_attr,
>> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
>> +};
>> +
>> +/*
>> * 'bandgap' class
>> * bangap reference for ldo regulators
>> */
>> @@ -5469,6 +5527,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
>> &omap44xx_timer10_hwmod,
>> &omap44xx_timer11_hwmod,
>>
>> + /* temperature sensor hwmod */
>> + &omap44xx_temperature_sensor_hwmod,
>> +
>> /* uart class */
>> &omap44xx_uart1_hwmod,
>> &omap44xx_uart2_hwmod,
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> - Paul
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-06 18:12 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
@ 2011-09-06 18:53 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 18:41 UTC (permalink / raw)
To: guenter.roeck; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Tue, Sep 6, 2011 at 11:42 PM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
>> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
>> <guenter.roeck@ericsson.com> wrote:
>> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>> >>
>> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> >> > > Hi
>> >> > >
>> >> > > Some comments.
>> >> > >
>> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
>> >> > >
>> >> > [ ... ]
>> >> > >
>> >> > > > +}
>> >> > > > +
>> >> > > > +/* Sysfs hook functions */
>> >> > >
>> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
>> >> > >
>> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>> >> >
>> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> >> > But please no conditionals in the code.
>> >>
>> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
>> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
>> >> fixed; on others, they are software-programmable. That functionality
>> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
>> >>
>> >> So based on your comments, it sounds like we should move that part of the
>> >> code to a different driver, and just leave the basic software thermal
>> >> monitoring here?
>> >>
>> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
>> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
>> > instead ?
>>
>> This driver is not taking any action on THSUT. This is not doing the thermal
>> management. It is a driver exposing configurable temperature thresholds.
>
> What sense would it make, then, to keep the driver around even if SYSFS
> is not defined ?
SYSFS nodes are defined for t_hot and t_cold thresholds. SYSFS nodes
are not defined
for TSHUT thresholds which are different.
>
> Note that I am not looking at the code right now, but at the suggestion
> that the driver would do something useful if SYSFS is not defined.
> Question is what that is, and if that part of it should reside in a
> hwmon driver.
>
> Thanks,
> Guenter
>
>
>
--
Regards and Thanks,
Keerthy
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-06 18:53 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-06 18:53 UTC (permalink / raw)
To: guenter.roeck; +Cc: Paul Walmsley, linux-omap, Jean Delvare, lm-sensors
On Tue, Sep 6, 2011 at 11:42 PM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
>> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
>> <guenter.roeck@ericsson.com> wrote:
>> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>> >>
>> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>> >> > > Hi
>> >> > >
>> >> > > Some comments.
>> >> > >
>> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
>> >> > >
>> >> > [ ... ]
>> >> > >
>> >> > > > +}
>> >> > > > +
>> >> > > > +/* Sysfs hook functions */
>> >> > >
>> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
>> >> > >
>> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>> >> >
>> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>> >> > But please no conditionals in the code.
>> >>
>> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
>> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
>> >> fixed; on others, they are software-programmable. That functionality
>> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
>> >>
>> >> So based on your comments, it sounds like we should move that part of the
>> >> code to a different driver, and just leave the basic software thermal
>> >> monitoring here?
>> >>
>> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
>> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
>> > instead ?
>>
>> This driver is not taking any action on THSUT. This is not doing the thermal
>> management. It is a driver exposing configurable temperature thresholds.
>
> What sense would it make, then, to keep the driver around even if SYSFS
> is not defined ?
SYSFS nodes are defined for t_hot and t_cold thresholds. SYSFS nodes
are not defined
for TSHUT thresholds which are different.
>
> Note that I am not looking at the code right now, but at the suggestion
> that the driver would do something useful if SYSFS is not defined.
> Question is what that is, and if that part of it should reside in a
> hwmon driver.
>
> Thanks,
> Guenter
>
>
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-06 18:53 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
@ 2011-09-07 14:44 ` J, KEERTHY
-1 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-07 14:32 UTC (permalink / raw)
To: guenter.roeck; +Cc: Paul Walmsley, linux-omap, lm-sensors
On Wed, Sep 7, 2011 at 12:11 AM, J, KEERTHY <j-keerthy@ti.com> wrote:
> On Tue, Sep 6, 2011 at 11:42 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
>> On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
>>> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
>>> <guenter.roeck@ericsson.com> wrote:
>>> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>>> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>>> >>
>>> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>>> >> > > Hi
>>> >> > >
>>> >> > > Some comments.
>>> >> > >
>>> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
>>> >> > >
>>> >> > [ ... ]
>>> >> > >
>>> >> > > > +}
>>> >> > > > +
>>> >> > > > +/* Sysfs hook functions */
>>> >> > >
>>> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
>>> >> > >
>>> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>>> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>>> >> >
>>> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>>> >> > But please no conditionals in the code.
>>> >>
>>> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
>>> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>>> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
>>> >> fixed; on others, they are software-programmable. That functionality
>>> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
>>> >>
>>> >> So based on your comments, it sounds like we should move that part of the
>>> >> code to a different driver, and just leave the basic software thermal
>>> >> monitoring here?
>>> >>
>>> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
>>> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
>>> > instead ?
>>>
>>> This driver is not taking any action on THSUT. This is not doing the thermal
>>> management. It is a driver exposing configurable temperature thresholds.
>>
>> What sense would it make, then, to keep the driver around even if SYSFS
>> is not defined ?
>
> SYSFS nodes are defined for t_hot and t_cold thresholds. SYSFS nodes
> are not defined
> for TSHUT thresholds which are different.
The point i am trying to make here is that this is a hardware monitoring
driver with configurable thresholds. The driver reads the on-die temperature.
The thermal framework as such is being discussed in a separate thread, which
dictates the actions to be taken once the thresholds are crossed.
This driver does not take any actions but just monitors the temperatures.
TSHUT or the thermal shutdown implementation requires the driver
to perform a shutdown of the device on reaching a certain temperature
and hence is not part of this driver.
>
>>
>> Note that I am not looking at the code right now, but at the suggestion
>> that the driver would do something useful if SYSFS is not defined.
>> Question is what that is, and if that part of it should reside in a
>> hwmon driver.
>>
>> Thanks,
>> Guenter
>>
>>
>>
>
>
>
> --
> Regards and Thanks,
> Keerthy
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-07 14:44 ` J, KEERTHY
0 siblings, 0 replies; 43+ messages in thread
From: J, KEERTHY @ 2011-09-07 14:44 UTC (permalink / raw)
To: guenter.roeck; +Cc: Paul Walmsley, linux-omap, lm-sensors
On Wed, Sep 7, 2011 at 12:11 AM, J, KEERTHY <j-keerthy@ti.com> wrote:
> On Tue, Sep 6, 2011 at 11:42 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
>> On Tue, 2011-09-06 at 14:02 -0400, J, KEERTHY wrote:
>>> On Thu, Sep 1, 2011 at 10:10 AM, Guenter Roeck
>>> <guenter.roeck@ericsson.com> wrote:
>>> > On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
>>> >> On Wed, 31 Aug 2011, Guenter Roeck wrote:
>>> >>
>>> >> > On Wed, Aug 31, 2011 at 08:36:43PM -0400, Paul Walmsley wrote:
>>> >> > > Hi
>>> >> > >
>>> >> > > Some comments.
>>> >> > >
>>> >> > > On Wed, 31 Aug 2011, Keerthy wrote:
>>> >> > >
>>> >> > [ ... ]
>>> >> > >
>>> >> > > > +}
>>> >> > > > +
>>> >> > > > +/* Sysfs hook functions */
>>> >> > >
>>> >> > > These should be conditionally compiled out if sysfs isn't compiled in.
>>> >> > >
>>> >> > The whole point of the hwmon subsystem is to expose hardware monitoring information
>>> >> > to userland using sysfs. hwmon without sysfs doesn't make sense.
>>> >> >
>>> >> > So, if anything, it might make sense to disable the entire hwmon tree if sysfs is disabled.
>>> >> > But please no conditionals in the code.
>>> >>
>>> >> Hmm. This IP block is more than just a sensor. It also can interrupt the
>>> >> CPU and/or trigger a GPIO line (to shut down the chip) if the chip
>>> >> temperature crosses some thresholds. On some OMAPs, the thresholds are
>>> >> fixed; on others, they are software-programmable. That functionality
>>> >> shouldn't require sysfs; it's almost closer to an x86 MCE.
>>> >>
>>> >> So based on your comments, it sounds like we should move that part of the
>>> >> code to a different driver, and just leave the basic software thermal
>>> >> monitoring here?
>>> >>
>>> > Good point. This definitely requires some thought. hwmon is meant to be hw monitoring,
>>> > as the name says, not thermal management. Maybe this entire driver should be a thermal driver
>>> > instead ?
>>>
>>> This driver is not taking any action on THSUT. This is not doing the thermal
>>> management. It is a driver exposing configurable temperature thresholds.
>>
>> What sense would it make, then, to keep the driver around even if SYSFS
>> is not defined ?
>
> SYSFS nodes are defined for t_hot and t_cold thresholds. SYSFS nodes
> are not defined
> for TSHUT thresholds which are different.
The point i am trying to make here is that this is a hardware monitoring
driver with configurable thresholds. The driver reads the on-die temperature.
The thermal framework as such is being discussed in a separate thread, which
dictates the actions to be taken once the thresholds are crossed.
This driver does not take any actions but just monitors the temperatures.
TSHUT or the thermal shutdown implementation requires the driver
to perform a shutdown of the device on reaching a certain temperature
and hence is not part of this driver.
>
>>
>> Note that I am not looking at the code right now, but at the suggestion
>> that the driver would do something useful if SYSFS is not defined.
>> Question is what that is, and if that part of it should reside in a
>> hwmon driver.
>>
>> Thanks,
>> Guenter
>>
>>
>>
>
>
>
> --
> Regards and Thanks,
> Keerthy
>
--
Regards and Thanks,
Keerthy
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver
2011-09-01 4:40 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
@ 2011-09-08 18:39 ` Mark Brown
-1 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2011-09-08 18:39 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paul Walmsley, linux-omap, lm-sensors
On Wed, Aug 31, 2011 at 09:40:47PM -0700, Guenter Roeck wrote:
> On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> > So based on your comments, it sounds like we should move that part of the
> > code to a different driver, and just leave the basic software thermal
> > monitoring here?
> Good point. This definitely requires some thought. hwmon is meant to
> be hw monitoring, as the name says, not thermal management. Maybe this
> entire driver should be a thermal driver instead ?
There's a lot of overlap between subsystems here - as well as the
thermal management stuff where the information hwmon gathers may be a
useful input to that the information exported by hwmon can also show up
in the power supply subsystem, and there's the possible overlap with
IIO as well as obviously the hardware monitoring may be being done using
something that's basically just a generic ADC.
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature
@ 2011-09-08 18:39 ` Mark Brown
0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2011-09-08 18:39 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paul Walmsley, linux-omap, lm-sensors
On Wed, Aug 31, 2011 at 09:40:47PM -0700, Guenter Roeck wrote:
> On Thu, Sep 01, 2011 at 12:09:14AM -0400, Paul Walmsley wrote:
> > So based on your comments, it sounds like we should move that part of the
> > code to a different driver, and just leave the basic software thermal
> > monitoring here?
> Good point. This definitely requires some thought. hwmon is meant to
> be hw monitoring, as the name says, not thermal management. Maybe this
> entire driver should be a thermal driver instead ?
There's a lot of overlap between subsystems here - as well as the
thermal management stuff where the information hwmon gathers may be a
useful input to that the information exported by hwmon can also show up
in the power supply subsystem, and there's the possible overlap with
IIO as well as obviously the hardware monitoring may be being done using
something that's basically just a generic ADC.
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH 5/6 V4] OMAP4: Temperature sensor device support
2011-08-31 17:25 ` [PATCH 5/6 V4] OMAP4: Temperature sensor device support Keerthy
@ 2011-09-09 9:28 ` Jean Pihet
0 siblings, 0 replies; 43+ messages in thread
From: Jean Pihet @ 2011-09-09 9:28 UTC (permalink / raw)
To: Keerthy; +Cc: linux-omap, tony
Hi Keerthy,
On Wed, Aug 31, 2011 at 7:25 PM, Keerthy <j-keerthy@ti.com> wrote:
> The device file adds the device support for OMAP4
> on die temperature sensor.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Cc: tony@atomide.com
> ---
> arch/arm/mach-omap2/Makefile | 1 +
> arch/arm/mach-omap2/temp_sensor_device.c | 188 ++++++++++++++++++++++++++++++
> arch/arm/plat-omap/Kconfig | 12 ++
> 3 files changed, 201 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-omap2/temp_sensor_device.c
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 2d5d981..5812fb4 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
>
> obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
>
> +obj-$(CONFIG_OMAP_TEMP_SENSOR) += temp_sensor_device.o
> obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
>
> # SMP support ONLY available for OMAP4
> diff --git a/arch/arm/mach-omap2/temp_sensor_device.c b/arch/arm/mach-omap2/temp_sensor_device.c
> new file mode 100644
> index 0000000..12d6789
> --- /dev/null
> +++ b/arch/arm/mach-omap2/temp_sensor_device.c
> @@ -0,0 +1,188 @@
> +/*
> + * OMAP on die Temperature sensor device file
> + *
> + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> + * Author: J Keerthy <j-keerthy@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/delay.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/mutex.h>
> +#include <linux/idr.h>
> +#include <plat/omap_device.h>
> +#include "pm.h"
> +#include <plat/temperature_sensor.h>
> +
> +
> +int omap_temp_sensor_device_idle(struct omap_device *od)
> +{
> + struct omap_temp_sensor_registers *registers;
> + struct resource *mem;
> + void __iomem *phy_base;
> + unsigned long timeout;
> + u32 ret = 0, temp;
> +
> + mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&od->pdev.dev, "no mem resource\n");
> + ret = -EINVAL;
> + goto plat_res_err;
> + }
> +
> + phy_base = ioremap(mem->start, resource_size(mem));
> +
> + if (!phy_base) {
> + dev_err(&od->pdev.dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + if (!strcmp(od->hwmods[0]->dev_attr, "mpu"))
> + registers = &omap_mpu_temp_sensor_registers;
> +
> + temp = __raw_readl(phy_base + registers->temp_sensor_ctrl);
> + temp |= registers->bgap_tempsoff_mask;
> +
> + /* BGAP_TEMPSOFF should be set to 1 before gating clock */
> + __raw_writel(temp, phy_base + registers->temp_sensor_ctrl);
> + temp = __raw_readl(phy_base + registers->bgap_status);
> + timeout = jiffies + msecs_to_jiffies(5);
> +
> + /* wait till the clean stop bit is set or till the timeout expires */
> + while (!(temp | registers->status_clean_stop_mask) &&
> + !(time_after(jiffies, timeout))) {
> + temp = __raw_readl(phy_base + registers->bgap_status);
> + usleep_range(500, 2000);
> + }
> +
> + if (time_after(jiffies, timeout))
> + dev_err(&od->pdev.dev, "Clean stop bit not set\n");
> +
> + ret = omap_device_idle_hwmods(od);
> + iounmap(phy_base);
> +plat_res_err:
> + return ret;
> +}
> +
> +int omap_temp_sensor_device_activate(struct omap_device *od)
> +{
> + struct omap_temp_sensor_registers *registers;
> + struct resource *mem;
> + void __iomem *phy_base;
> + u32 ret = 0, temp;
> +
> + ret = omap_device_enable_hwmods(od);
> + if (ret < 0)
> + return ret;
> + mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + dev_err(&od->pdev.dev, "no mem resource\n");
> + return -EINVAL;
> + }
> +
> + phy_base = ioremap(mem->start, resource_size(mem));
> + if (!phy_base) {
> + dev_err(&od->pdev.dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto plat_res_err;
> + }
> +
> + if (!strcmp(od->hwmods[0]->dev_attr, "mpu"))
> + registers = &omap_mpu_temp_sensor_registers;
> +
> + temp = __raw_readl(phy_base + registers->temp_sensor_ctrl);
> + temp &= ~(registers->bgap_tempsoff_mask);
> + /* BGAP_TEMPSOFF should be reset to 0 */
> + __raw_writel(temp,
> + phy_base + registers->temp_sensor_ctrl);
> + iounmap(phy_base);
> +
> +plat_res_err:
> + return ret;
> +}
I do not think it is a good thing to ioremap and iounmap the resource
registers every time you need to access the device.
That should be gone in init/deinit functions instead.
Regards,
Jean
> +
> +static struct omap_device_pm_latency omap_temp_sensor_latency[] = {
> + {
> + .deactivate_func = omap_temp_sensor_device_idle,
> + .activate_func = omap_temp_sensor_device_activate,
> + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
> + }
> +};
> +
> +static DEFINE_IDR(temp_sensor_device_idr);
> +
> +static int temp_sensor_dev_init(struct omap_hwmod *oh, void *user)
> +{
> + struct omap_temp_sensor_pdata *temp_sensor_pdata;
> + struct omap_device *od;
> + struct omap_temp_sensor_dev_attr *temp_sensor_dev_attr;
> + int ret = 0;
> + int num;
> +
> + temp_sensor_pdata =
> + kzalloc(sizeof(*temp_sensor_pdata), GFP_KERNEL);
> + if (!temp_sensor_pdata) {
> + dev_err(&oh->od->pdev.dev,
> + "Unable to allocate memory for temp sensor pdata\n");
> + return -ENOMEM;
> + }
> +
> + ret = idr_pre_get(&temp_sensor_device_idr, GFP_KERNEL);
> + if (ret < 0)
> + goto fail_id;
> + ret = idr_get_new(&temp_sensor_device_idr, temp_sensor_pdata, &num);
> + if (ret < 0)
> + goto fail_id;
> +
> + temp_sensor_dev_attr = oh->dev_attr;
> + if (!strcmp(temp_sensor_dev_attr->name, "mpu")) {
> + temp_sensor_pdata->registers = &omap_mpu_temp_sensor_registers;
> + } else {
> + dev_warn(&oh->od->pdev.dev, "Invalid device attribute\n");
> + ret = -EINVAL;
> + goto fail_id;
> + }
> +
> + od = omap_device_build("omap_temp_sensor", num,
> + oh, temp_sensor_pdata, sizeof(*temp_sensor_pdata),
> + omap_temp_sensor_latency,
> + ARRAY_SIZE(omap_temp_sensor_latency), 0);
> +
> + if (IS_ERR(od)) {
> + dev_warn(&oh->od->pdev.dev,
> + "Could not build omap_device for %s\n", oh->name);
> + ret = PTR_ERR(od);
> + }
> +
> +fail_id:
> + kfree(temp_sensor_pdata);
> +
> + return ret;
> +}
> +
> +int __init omap_devinit_temp_sensor(void)
> +{
> + if (!cpu_is_omap446x())
> + return 0;
> +
> + return omap_hwmod_for_each_by_class("temperature_sensor",
> + temp_sensor_dev_init, NULL);
> +}
> +
> +arch_initcall(omap_devinit_temp_sensor);
> diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> index 6e6735f..8fd8e80 100644
> --- a/arch/arm/plat-omap/Kconfig
> +++ b/arch/arm/plat-omap/Kconfig
> @@ -115,6 +115,18 @@ config OMAP_MCBSP
> Say Y here if you want support for the OMAP Multichannel
> Buffered Serial Port.
>
> +config OMAP_TEMP_SENSOR
> + bool "OMAP Temp Sensor Support"
> + depends on ARCH_OMAP
> + default n
> + help
> + Say Y here if you want support for the temp sensor
> + on OMAP4460.
> +
> + This provides the temperature of the MPU
> + subsystem. Only one instance of on die temperature
> + sensor is present.
> +
> config OMAP_MBOX_FWK
> tristate "Mailbox framework support"
> depends on ARCH_OMAP
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2011-09-09 9:28 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-31 17:25 [PATCH 0/6 V4] OMAP4: Temperature sensor driver Keerthy
2011-08-31 17:25 ` [PATCH 1/6 V4] OMAP4: Clock: Associate clocks for OMAP temperature sensor Keerthy
2011-09-01 0:00 ` Paul Walmsley
2011-09-02 7:12 ` Rajendra Nayak
2011-08-31 17:25 ` [PATCH 2/6 V4] OMAP4: Adding the temperature sensor register set bit fields Keerthy
2011-09-01 0:04 ` Paul Walmsley
2011-09-01 2:57 ` J, KEERTHY
2011-08-31 17:25 ` [PATCH 3/6 V4] OMAP4460: Temperature sensor data Keerthy
2011-08-31 17:25 ` [PATCH 4/6 V4] OMAP4: Hwmod: OMAP temperature sensor Keerthy
2011-08-31 23:16 ` Paul Walmsley
2011-09-06 18:24 ` J, KEERTHY
2011-08-31 17:25 ` [PATCH 5/6 V4] OMAP4: Temperature sensor device support Keerthy
2011-09-09 9:28 ` Jean Pihet
2011-08-31 17:25 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Keerthy
2011-08-31 17:37 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor Keerthy
2011-08-31 23:56 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Paul Walmsley
2011-08-31 23:56 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
2011-09-06 11:49 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-06 11:52 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-01 0:36 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Paul Walmsley
2011-09-01 0:36 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
2011-09-01 1:49 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Guenter Roeck
2011-09-01 1:49 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
2011-09-01 4:09 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Paul Walmsley
2011-09-01 4:09 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Paul Walmsley
2011-09-01 4:40 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Guenter Roeck
2011-09-01 4:40 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
2011-09-06 18:02 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-06 18:14 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-06 18:12 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Guenter Roeck
2011-09-06 18:12 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
2011-09-06 18:41 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-06 18:53 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-07 14:32 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-07 14:44 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-08 18:39 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Mark Brown
2011-09-08 18:39 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Mark Brown
2011-09-06 17:57 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-06 17:58 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-06 17:50 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver J, KEERTHY
2011-09-06 17:53 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature J, KEERTHY
2011-09-01 4:38 ` [PATCH 6/6 V4] hwmon: OMAP4: On die temperature sensor driver Guenter Roeck
2011-09-01 4:38 ` [lm-sensors] [PATCH 6/6 V4] hwmon: OMAP4: On die temperature Guenter Roeck
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.