Hi Rui/Eduardo,
Submitting V6 version with all comments fixed. It is good if these patches gets
merged in this merge window. If any comments please let me know.
Thanks,
Amit Daniel
Changes in V6:
* Uses ARCH_HAS_BANDGAP config flag which is merged now in arm tree.
(http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7758/1).
* In this version patches 1, 2, 3, 4 and 30 are modified. Others are same as V5.
* Added acked by from Jonghwa Lee.
* Rebased against Thermal Maintainer next tree.
Changes in V5:
* Most of the changes in this version is as per suggestion from Jonghwa Lee. I
have retained one to one mapping of platform data with TMU instances as the
TMU's are different devices. In exynos5440 soc there is some register
sharing across multiple TMU's but in exynos5420 there is no register between
multiple TMU's, so the current implementation is useful to support both of the
above.
This patch uses localized ARCH_HAS_TMU Kconfig option and is a temporary solution
until a more generic macro ARCH_HAS_BANDGAP is introduced as per discussion in
the link https://patchwork.kernel.org/patch/2659001/.
* trip type is passed as platform data.
* HW trip is allowed only for maximum level.
* Platform data structure is now abstracted inside 1 more structure to support
multiple sensor TMU data.
Changes in V4:
Almost all the changes in this version is as per suggestion from Eduardo.The
major ones are listed below,
* Added kconfig symbol ARCH_HAS_TMU which needs to be enabled by platform. With
this change existing symbol EXYNOS_TMU_DATA is not needed.
* Movement of freq_clip_table from exynos_tmu.h to exynos_thermal_common.h is
explained in the commit logs.
* Wrote all register description documentation.
* Split 5440 TMU support patch into controller change, configuration data and
feature addition patches.
* Remove all *LINUX_* in the header files.
* Still regulator enable is kept optional but a TODO: comment is added to fix
it later.
Changes in V3:
* Added proper dependency of different exynos thermal Kconfig symbols. Basically 3
Kconfig can be enabled now and corresponds to tmu driver. exynos common part
and exynos configuration data. This issue was raised by Rui Zhang.
Changes in V2:
* Separated SOC data from TMU driver. This is as per suggestion from Eduardo.
* Merged the new file created for exynos5440 TMU controller with the existing
TMU controller code.
* Removed the DT parsing code as now the SOC specific data are cleanly put
inside the data specific file.
* Even the register definations/bitfields are treated as data as there is
some variation across SOC's.
This patchset adds TMU(Thermal management Unit) driver support for
exynos5440 platform. There are 3 instances of the TMU controllers so
necessary cleanup/re-structure is done to handle multiple thermal zone.
Patch (exynos4: Add documentation for Exynos SoC thermal bindings) from
Lukasz Majewski is already posted to mainline. Adding it here for completeness.
(http://www.mail-archive.com/[email protected]/msg17817.html)
Patch (thermal: exynos: Support thermal tripping ) from Jonghwan Choi is
added here with some changes.
(https://patchwork.kernel.org/patch/1668371/)
Patch (thermal: exynos: Support for TMU regulator defined at device tree)
is a repost of my earlier patch(https://patchwork-mail1.kernel.org/patch/2510771/)
and adds regulator support.
Patch (ARM: dts: Add device tree node for exynos5440 TMU controller) and
patch (arm: exynos: enable ARCH_HAS_TMU) can be merged through exynos platform
maintainer as this can cause merge conflict.
All these patches are based on thermal maintainers git tree,
git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git next.
Amit Daniel Kachhap (29):
thermal: exynos: Moving exynos thermal files into samsung directory
thermal: exynos: Use ARCH_HAS_BANDGAP config to know the supported
soc's
thermal: exynos: Remove un-necessary CPU_THERMAL dependency
thermal: exynos: Bifurcate exynos thermal common and tmu controller
code
thermal: exynos: Rename exynos_thermal.c to exynos_tmu.c
thermal: exynos: Move exynos_thermal.h from include/* to driver/*
folder
thermal: exynos: Bifurcate exynos tmu driver and configuration data
thermal: exynos: Add missing definations and code cleanup
thermal: exynos: Add extra entries in the tmu platform data
thermal: exynos: Move register definitions from driver to data file
thermal: exynos: Support thermal tripping
thermal: exynos: Fix to clear only the generated interrupts
thermal: exynos: Add support for instance based register/unregister
thermal: exynos: Modify private_data to appropriate name driver_data
thermal: exynos: Return success even if no cooling data supplied
thermal: exynos: Make the zone handling use trip information
thermal: exynos: Remove non DT based support
thermal: exynos: Add support to handle many instances of TMU
thermal: exynos: Add TMU features to check instead of using SOC type
thermal: exynos: use device resource management infrastructure
thermal: exynos: Add support to access common register for
multistance
thermal: exynos: Add driver support for exynos5440 TMU sensor
thermal: exynos: Add thermal configuration data for exynos5440 TMU
sensor
thermal: exynos: Fix to set the second point correction value
thermal: exynos: Add hardware mode thermal calibration support
Documentation: thermal: Explain the exynos thermal driver model
thermal: exynos: Support for TMU regulator defined at device tree
ARM: dts: Add device tree node for exynos5440 TMU controller
arm: exynos: enable ARCH_HAS_BANDGAP
Lukasz Majewski (1):
ARM: dts: thermal: exynos4: Add documentation for Exynos SoC thermal
bindings
.../devicetree/bindings/thermal/exynos-thermal.txt | 55 +
Documentation/thermal/exynos_thermal | 43 +-
arch/arm/boot/dts/exynos5440.dtsi | 30 +
arch/arm/mach-exynos/Kconfig | 5 +
drivers/thermal/Kconfig | 14 +-
drivers/thermal/Makefile | 2 +-
drivers/thermal/exynos_thermal.c | 1058 --------------------
drivers/thermal/samsung/Kconfig | 18 +
drivers/thermal/samsung/Makefile | 7 +
drivers/thermal/samsung/exynos_thermal_common.c | 413 ++++++++
drivers/thermal/samsung/exynos_thermal_common.h | 106 ++
drivers/thermal/samsung/exynos_tmu.c | 750 ++++++++++++++
drivers/thermal/samsung/exynos_tmu.h | 307 ++++++
drivers/thermal/samsung/exynos_tmu_data.c | 250 +++++
drivers/thermal/samsung/exynos_tmu_data.h | 155 +++
include/linux/platform_data/exynos_thermal.h | 119 ---
16 files changed, 2137 insertions(+), 1195 deletions(-)
create mode 100644 Documentation/devicetree/bindings/thermal/exynos-thermal.txt
delete mode 100644 drivers/thermal/exynos_thermal.c
create mode 100644 drivers/thermal/samsung/Kconfig
create mode 100644 drivers/thermal/samsung/Makefile
create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
create mode 100644 drivers/thermal/samsung/exynos_tmu.c
create mode 100644 drivers/thermal/samsung/exynos_tmu.h
create mode 100644 drivers/thermal/samsung/exynos_tmu_data.c
create mode 100644 drivers/thermal/samsung/exynos_tmu_data.h
delete mode 100644 include/linux/platform_data/exynos_thermal.h
This patch uses the recently added config sybmol ARCH_HAS_BANDGAP to enable
the TMU driver. This will allow adding support for new soc easily as now it
is the platform responsibility to enable this config symbol for a particular
soc.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index 2d3d9dc..883a8a8 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -1,6 +1,6 @@
config EXYNOS_THERMAL
tristate "Temperature sensor on Samsung EXYNOS"
- depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ depends on ARCH_HAS_BANDGAP
depends on CPU_THERMAL
help
If you say yes here you get support for TMU (Thermal Management
--
1.7.1
This patch removes the dependency on CPU_THERMAL for compiling TMU driver.
This is useful for cases when only TMU controller needs to be initialised
without cpu cooling action.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/Kconfig | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index 883a8a8..2cf31ad 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -1,7 +1,6 @@
config EXYNOS_THERMAL
tristate "Temperature sensor on Samsung EXYNOS"
depends on ARCH_HAS_BANDGAP
- depends on CPU_THERMAL
help
If you say yes here you get support for TMU (Thermal Management
Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
--
1.7.1
This code bifurcates exynos thermal implementation into common and sensor
specific parts. The common thermal code interacts with core thermal layer and
core cpufreq cooling parts and is independent of SOC specific driver. This
change is needed to cleanly add support for new TMU sensors.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/Kconfig | 19 +-
drivers/thermal/samsung/Makefile | 4 +-
drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
5 files changed, 490 insertions(+), 419 deletions(-)
create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index 2cf31ad..f8100b1 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -1,8 +1,17 @@
config EXYNOS_THERMAL
- tristate "Temperature sensor on Samsung EXYNOS"
+ tristate "Exynos thermal management unit driver"
depends on ARCH_HAS_BANDGAP
help
- If you say yes here you get support for TMU (Thermal Management
- Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
- the exynos thermal driver with the core thermal layer and cpu
- cooling API's.
+ If you say yes here you get support for the TMU (Thermal Management
+ Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
+ the TMU, reports temperature and handles cooling action if defined.
+ This driver uses the exynos core thermal API's.
+
+config EXYNOS_THERMAL_CORE
+ bool "Core thermal framework support for EXYNOS SOC's"
+ depends on EXYNOS_THERMAL
+ help
+ If you say yes here you get support for EXYNOS TMU
+ (Thermal Management Unit) common registration/unregistration
+ functions to the core thermal layer and also to use the generic
+ cpu cooling API's.
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
index 1fe6d93..6227d4f 100644
--- a/drivers/thermal/samsung/Makefile
+++ b/drivers/thermal/samsung/Makefile
@@ -1,4 +1,6 @@
#
# Samsung thermal specific Makefile
#
-obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
+obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
+exynos_soc_thermal-y := exynos_thermal.o
+exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
index 03e4bbc..5293849 100644
--- a/drivers/thermal/samsung/exynos_thermal.c
+++ b/drivers/thermal/samsung/exynos_thermal.c
@@ -21,23 +21,15 @@
*
*/
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/sysfs.h>
-#include <linux/kobject.h>
#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/platform_data/exynos_thermal.h>
-#include <linux/thermal.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu_cooling.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/exynos_thermal.h>
+
+#include "exynos_thermal_common.h"
/* Exynos generic registers */
#define EXYNOS_TMU_REG_TRIMINFO 0x0
@@ -88,16 +80,6 @@
#define EFUSE_MIN_VALUE 40
#define EFUSE_MAX_VALUE 100
-/* In-kernel thermal framework related macros & definations */
-#define SENSOR_NAME_LEN 16
-#define MAX_TRIP_COUNT 8
-#define MAX_COOLING_DEVICE 4
-#define MAX_THRESHOLD_LEVS 4
-
-#define ACTIVE_INTERVAL 500
-#define IDLE_INTERVAL 10000
-#define MCELSIUS 1000
-
#ifdef CONFIG_THERMAL_EMULATION
#define EXYNOS_EMUL_TIME 0x57F0
#define EXYNOS_EMUL_TIME_SHIFT 16
@@ -106,17 +88,6 @@
#define EXYNOS_EMUL_ENABLE 0x1
#endif /* CONFIG_THERMAL_EMULATION */
-/* CPU Zone information */
-#define PANIC_ZONE 4
-#define WARN_ZONE 3
-#define MONITOR_ZONE 2
-#define SAFE_ZONE 1
-
-#define GET_ZONE(trip) (trip + 2)
-#define GET_TRIP(zone) (zone - 2)
-
-#define EXYNOS_ZONE_COUNT 3
-
struct exynos_tmu_data {
struct exynos_tmu_platform_data *pdata;
struct resource *mem;
@@ -129,384 +100,6 @@ struct exynos_tmu_data {
u8 temp_error1, temp_error2;
};
-struct thermal_trip_point_conf {
- int trip_val[MAX_TRIP_COUNT];
- int trip_count;
- u8 trigger_falling;
-};
-
-struct thermal_cooling_conf {
- struct freq_clip_table freq_data[MAX_TRIP_COUNT];
- int freq_clip_count;
-};
-
-struct thermal_sensor_conf {
- char name[SENSOR_NAME_LEN];
- int (*read_temperature)(void *data);
- int (*write_emul_temp)(void *drv_data, unsigned long temp);
- struct thermal_trip_point_conf trip_data;
- struct thermal_cooling_conf cooling_data;
- void *private_data;
-};
-
-struct exynos_thermal_zone {
- enum thermal_device_mode mode;
- struct thermal_zone_device *therm_dev;
- struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
- unsigned int cool_dev_size;
- struct platform_device *exynos4_dev;
- struct thermal_sensor_conf *sensor_conf;
- bool bind;
-};
-
-static struct exynos_thermal_zone *th_zone;
-static void exynos_unregister_thermal(void);
-static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
-
-/* Get mode callback functions for thermal zone */
-static int exynos_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- if (th_zone)
- *mode = th_zone->mode;
- return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int exynos_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- if (!th_zone->therm_dev) {
- pr_notice("thermal zone not registered\n");
- return 0;
- }
-
- mutex_lock(&th_zone->therm_dev->lock);
-
- if (mode == THERMAL_DEVICE_ENABLED &&
- !th_zone->sensor_conf->trip_data.trigger_falling)
- th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
- else
- th_zone->therm_dev->polling_delay = 0;
-
- mutex_unlock(&th_zone->therm_dev->lock);
-
- th_zone->mode = mode;
- thermal_zone_device_update(th_zone->therm_dev);
- pr_info("thermal polling set for duration=%d msec\n",
- th_zone->therm_dev->polling_delay);
- return 0;
-}
-
-
-/* Get trip type callback functions for thermal zone */
-static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
- enum thermal_trip_type *type)
-{
- switch (GET_ZONE(trip)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- *type = THERMAL_TRIP_ACTIVE;
- break;
- case PANIC_ZONE:
- *type = THERMAL_TRIP_CRITICAL;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
- unsigned long *temp)
-{
- if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
- return -EINVAL;
-
- *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
- /* convert the temperature into millicelsius */
- *temp = *temp * MCELSIUS;
-
- return 0;
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- int ret;
- /* Panic zone */
- ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
- return ret;
-}
-
-/* Bind callback functions for thermal zone */
-static int exynos_bind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- int ret = 0, i, tab_size, level;
- struct freq_clip_table *tab_ptr, *clip_data;
- struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
- tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
- tab_size = data->cooling_data.freq_clip_count;
-
- if (tab_ptr == NULL || tab_size == 0)
- return -EINVAL;
-
- /* find the cooling device registered*/
- for (i = 0; i < th_zone->cool_dev_size; i++)
- if (cdev == th_zone->cool_dev[i])
- break;
-
- /* No matching cooling device */
- if (i == th_zone->cool_dev_size)
- return 0;
-
- /* Bind the thermal zone to the cpufreq cooling device */
- for (i = 0; i < tab_size; i++) {
- clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
- level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
- if (level == THERMAL_CSTATE_INVALID)
- return 0;
- switch (GET_ZONE(i)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- if (thermal_zone_bind_cooling_device(thermal, i, cdev,
- level, 0)) {
- pr_err("error binding cdev inst %d\n", i);
- ret = -EINVAL;
- }
- th_zone->bind = true;
- break;
- default:
- ret = -EINVAL;
- }
- }
-
- return ret;
-}
-
-/* Unbind callback functions for thermal zone */
-static int exynos_unbind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- int ret = 0, i, tab_size;
- struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
- if (th_zone->bind == false)
- return 0;
-
- tab_size = data->cooling_data.freq_clip_count;
-
- if (tab_size == 0)
- return -EINVAL;
-
- /* find the cooling device registered*/
- for (i = 0; i < th_zone->cool_dev_size; i++)
- if (cdev == th_zone->cool_dev[i])
- break;
-
- /* No matching cooling device */
- if (i == th_zone->cool_dev_size)
- return 0;
-
- /* Bind the thermal zone to the cpufreq cooling device */
- for (i = 0; i < tab_size; i++) {
- switch (GET_ZONE(i)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- if (thermal_zone_unbind_cooling_device(thermal, i,
- cdev)) {
- pr_err("error unbinding cdev inst=%d\n", i);
- ret = -EINVAL;
- }
- th_zone->bind = false;
- break;
- default:
- ret = -EINVAL;
- }
- }
- return ret;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_get_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- void *data;
-
- if (!th_zone->sensor_conf) {
- pr_info("Temperature sensor not initialised\n");
- return -EINVAL;
- }
- data = th_zone->sensor_conf->private_data;
- *temp = th_zone->sensor_conf->read_temperature(data);
- /* convert the temperature into millicelsius */
- *temp = *temp * MCELSIUS;
- return 0;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
- unsigned long temp)
-{
- void *data;
- int ret = -EINVAL;
-
- if (!th_zone->sensor_conf) {
- pr_info("Temperature sensor not initialised\n");
- return -EINVAL;
- }
- data = th_zone->sensor_conf->private_data;
- if (th_zone->sensor_conf->write_emul_temp)
- ret = th_zone->sensor_conf->write_emul_temp(data, temp);
- return ret;
-}
-
-/* Get the temperature trend */
-static int exynos_get_trend(struct thermal_zone_device *thermal,
- int trip, enum thermal_trend *trend)
-{
- int ret;
- unsigned long trip_temp;
-
- ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
- if (ret < 0)
- return ret;
-
- if (thermal->temperature >= trip_temp)
- *trend = THERMAL_TREND_RAISE_FULL;
- else
- *trend = THERMAL_TREND_DROP_FULL;
-
- return 0;
-}
-/* Operation callback functions for thermal zone */
-static struct thermal_zone_device_ops const exynos_dev_ops = {
- .bind = exynos_bind,
- .unbind = exynos_unbind,
- .get_temp = exynos_get_temp,
- .set_emul_temp = exynos_set_emul_temp,
- .get_trend = exynos_get_trend,
- .get_mode = exynos_get_mode,
- .set_mode = exynos_set_mode,
- .get_trip_type = exynos_get_trip_type,
- .get_trip_temp = exynos_get_trip_temp,
- .get_crit_temp = exynos_get_crit_temp,
-};
-
-/*
- * This function may be called from interrupt based temperature sensor
- * when threshold is changed.
- */
-static void exynos_report_trigger(void)
-{
- unsigned int i;
- char data[10];
- char *envp[] = { data, NULL };
-
- if (!th_zone || !th_zone->therm_dev)
- return;
- if (th_zone->bind == false) {
- for (i = 0; i < th_zone->cool_dev_size; i++) {
- if (!th_zone->cool_dev[i])
- continue;
- exynos_bind(th_zone->therm_dev,
- th_zone->cool_dev[i]);
- }
- }
-
- thermal_zone_device_update(th_zone->therm_dev);
-
- mutex_lock(&th_zone->therm_dev->lock);
- /* Find the level for which trip happened */
- for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
- if (th_zone->therm_dev->last_temperature <
- th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
- break;
- }
-
- if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
- !th_zone->sensor_conf->trip_data.trigger_falling) {
- if (i > 0)
- th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
- else
- th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
- }
-
- snprintf(data, sizeof(data), "%u", i);
- kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
- mutex_unlock(&th_zone->therm_dev->lock);
-}
-
-/* Register with the in-kernel thermal management */
-static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
-{
- int ret;
- struct cpumask mask_val;
-
- if (!sensor_conf || !sensor_conf->read_temperature) {
- pr_err("Temperature sensor not initialised\n");
- return -EINVAL;
- }
-
- th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
- if (!th_zone)
- return -ENOMEM;
-
- th_zone->sensor_conf = sensor_conf;
- cpumask_set_cpu(0, &mask_val);
- th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
- if (IS_ERR(th_zone->cool_dev[0])) {
- pr_err("Failed to register cpufreq cooling device\n");
- ret = -EINVAL;
- goto err_unregister;
- }
- th_zone->cool_dev_size++;
-
- th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
- EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
- sensor_conf->trip_data.trigger_falling ?
- 0 : IDLE_INTERVAL);
-
- if (IS_ERR(th_zone->therm_dev)) {
- pr_err("Failed to register thermal zone device\n");
- ret = PTR_ERR(th_zone->therm_dev);
- goto err_unregister;
- }
- th_zone->mode = THERMAL_DEVICE_ENABLED;
-
- pr_info("Exynos: Kernel Thermal management registered\n");
-
- return 0;
-
-err_unregister:
- exynos_unregister_thermal();
- return ret;
-}
-
-/* Un-Register with the in-kernel thermal management */
-static void exynos_unregister_thermal(void)
-{
- int i;
-
- if (!th_zone)
- return;
-
- if (th_zone->therm_dev)
- thermal_zone_device_unregister(th_zone->therm_dev);
-
- for (i = 0; i < th_zone->cool_dev_size; i++) {
- if (th_zone->cool_dev[i])
- cpufreq_cooling_unregister(th_zone->cool_dev[i]);
- }
-
- kfree(th_zone);
- pr_info("Exynos: Kernel Thermal management unregistered\n");
-}
-
/*
* TMU treats temperature as a mapped temperature code.
* The temperature is converted differently depending on the calibration type.
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
new file mode 100644
index 0000000..92e50bc
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -0,0 +1,384 @@
+/*
+ * exynos_thermal_common.c - Samsung EXYNOS common thermal file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Amit Daniel Kachhap <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/cpu_cooling.h>
+#include <linux/platform_data/exynos_thermal.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#include "exynos_thermal_common.h"
+
+struct exynos_thermal_zone {
+ enum thermal_device_mode mode;
+ struct thermal_zone_device *therm_dev;
+ struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
+ unsigned int cool_dev_size;
+ struct platform_device *exynos4_dev;
+ struct thermal_sensor_conf *sensor_conf;
+ bool bind;
+};
+
+static struct exynos_thermal_zone *th_zone;
+
+/* Get mode callback functions for thermal zone */
+static int exynos_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ if (th_zone)
+ *mode = th_zone->mode;
+ return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int exynos_set_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
+{
+ if (!th_zone->therm_dev) {
+ pr_notice("thermal zone not registered\n");
+ return 0;
+ }
+
+ mutex_lock(&th_zone->therm_dev->lock);
+
+ if (mode == THERMAL_DEVICE_ENABLED &&
+ !th_zone->sensor_conf->trip_data.trigger_falling)
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = 0;
+
+ mutex_unlock(&th_zone->therm_dev->lock);
+
+ th_zone->mode = mode;
+ thermal_zone_device_update(th_zone->therm_dev);
+ pr_info("thermal polling set for duration=%d msec\n",
+ th_zone->therm_dev->polling_delay);
+ return 0;
+}
+
+
+/* Get trip type callback functions for thermal zone */
+static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
+ enum thermal_trip_type *type)
+{
+ switch (GET_ZONE(trip)) {
+ case MONITOR_ZONE:
+ case WARN_ZONE:
+ *type = THERMAL_TRIP_ACTIVE;
+ break;
+ case PANIC_ZONE:
+ *type = THERMAL_TRIP_CRITICAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
+ return -EINVAL;
+
+ *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+ /* convert the temperature into millicelsius */
+ *temp = *temp * MCELSIUS;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret;
+ /* Panic zone */
+ ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0, i, tab_size, level;
+ struct freq_clip_table *tab_ptr, *clip_data;
+ struct thermal_sensor_conf *data = th_zone->sensor_conf;
+
+ tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
+ tab_size = data->cooling_data.freq_clip_count;
+
+ if (tab_ptr == NULL || tab_size == 0)
+ return -EINVAL;
+
+ /* find the cooling device registered*/
+ for (i = 0; i < th_zone->cool_dev_size; i++)
+ if (cdev == th_zone->cool_dev[i])
+ break;
+
+ /* No matching cooling device */
+ if (i == th_zone->cool_dev_size)
+ return 0;
+
+ /* Bind the thermal zone to the cpufreq cooling device */
+ for (i = 0; i < tab_size; i++) {
+ clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
+ level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
+ if (level == THERMAL_CSTATE_INVALID)
+ return 0;
+ switch (GET_ZONE(i)) {
+ case MONITOR_ZONE:
+ case WARN_ZONE:
+ if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+ level, 0)) {
+ pr_err("error binding cdev inst %d\n", i);
+ ret = -EINVAL;
+ }
+ th_zone->bind = true;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0, i, tab_size;
+ struct thermal_sensor_conf *data = th_zone->sensor_conf;
+
+ if (th_zone->bind == false)
+ return 0;
+
+ tab_size = data->cooling_data.freq_clip_count;
+
+ if (tab_size == 0)
+ return -EINVAL;
+
+ /* find the cooling device registered*/
+ for (i = 0; i < th_zone->cool_dev_size; i++)
+ if (cdev == th_zone->cool_dev[i])
+ break;
+
+ /* No matching cooling device */
+ if (i == th_zone->cool_dev_size)
+ return 0;
+
+ /* Bind the thermal zone to the cpufreq cooling device */
+ for (i = 0; i < tab_size; i++) {
+ switch (GET_ZONE(i)) {
+ case MONITOR_ZONE:
+ case WARN_ZONE:
+ if (thermal_zone_unbind_cooling_device(thermal, i,
+ cdev)) {
+ pr_err("error unbinding cdev inst=%d\n", i);
+ ret = -EINVAL;
+ }
+ th_zone->bind = false;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ void *data;
+
+ if (!th_zone->sensor_conf) {
+ pr_info("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+ data = th_zone->sensor_conf->private_data;
+ *temp = th_zone->sensor_conf->read_temperature(data);
+ /* convert the temperature into millicelsius */
+ *temp = *temp * MCELSIUS;
+ return 0;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
+ unsigned long temp)
+{
+ void *data;
+ int ret = -EINVAL;
+
+ if (!th_zone->sensor_conf) {
+ pr_info("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+ data = th_zone->sensor_conf->private_data;
+ if (th_zone->sensor_conf->write_emul_temp)
+ ret = th_zone->sensor_conf->write_emul_temp(data, temp);
+ return ret;
+}
+
+/* Get the temperature trend */
+static int exynos_get_trend(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trend *trend)
+{
+ int ret;
+ unsigned long trip_temp;
+
+ ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
+ if (ret < 0)
+ return ret;
+
+ if (thermal->temperature >= trip_temp)
+ *trend = THERMAL_TREND_RAISE_FULL;
+ else
+ *trend = THERMAL_TREND_DROP_FULL;
+
+ return 0;
+}
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops const exynos_dev_ops = {
+ .bind = exynos_bind,
+ .unbind = exynos_unbind,
+ .get_temp = exynos_get_temp,
+ .set_emul_temp = exynos_set_emul_temp,
+ .get_trend = exynos_get_trend,
+ .get_mode = exynos_get_mode,
+ .set_mode = exynos_set_mode,
+ .get_trip_type = exynos_get_trip_type,
+ .get_trip_temp = exynos_get_trip_temp,
+ .get_crit_temp = exynos_get_crit_temp,
+};
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+void exynos_report_trigger(void)
+{
+ unsigned int i;
+ char data[10];
+ char *envp[] = { data, NULL };
+
+ if (!th_zone || !th_zone->therm_dev)
+ return;
+ if (th_zone->bind == false) {
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (!th_zone->cool_dev[i])
+ continue;
+ exynos_bind(th_zone->therm_dev,
+ th_zone->cool_dev[i]);
+ }
+ }
+
+ thermal_zone_device_update(th_zone->therm_dev);
+
+ mutex_lock(&th_zone->therm_dev->lock);
+ /* Find the level for which trip happened */
+ for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
+ if (th_zone->therm_dev->last_temperature <
+ th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
+ break;
+ }
+
+ if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
+ !th_zone->sensor_conf->trip_data.trigger_falling) {
+ if (i > 0)
+ th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ }
+
+ snprintf(data, sizeof(data), "%u", i);
+ kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Register with the in-kernel thermal management */
+int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+ int ret;
+ struct cpumask mask_val;
+
+ if (!sensor_conf || !sensor_conf->read_temperature) {
+ pr_err("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+
+ th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
+ if (!th_zone)
+ return -ENOMEM;
+
+ th_zone->sensor_conf = sensor_conf;
+ cpumask_set_cpu(0, &mask_val);
+ th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
+ if (IS_ERR(th_zone->cool_dev[0])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->cool_dev_size++;
+
+ th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
+ EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
+ sensor_conf->trip_data.trigger_falling ?
+ 0 : IDLE_INTERVAL);
+
+ if (IS_ERR(th_zone->therm_dev)) {
+ pr_err("Failed to register thermal zone device\n");
+ ret = PTR_ERR(th_zone->therm_dev);
+ goto err_unregister;
+ }
+ th_zone->mode = THERMAL_DEVICE_ENABLED;
+
+ pr_info("Exynos: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ exynos_unregister_thermal();
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+void exynos_unregister_thermal(void)
+{
+ int i;
+
+ if (!th_zone)
+ return;
+
+ if (th_zone->therm_dev)
+ thermal_zone_device_unregister(th_zone->therm_dev);
+
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (th_zone->cool_dev[i])
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+ }
+
+ kfree(th_zone);
+ pr_info("Exynos: Kernel Thermal management unregistered\n");
+}
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
new file mode 100644
index 0000000..8df1848
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -0,0 +1,83 @@
+/*
+ * exynos_thermal_common.h - Samsung EXYNOS common header file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Amit Daniel Kachhap <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _EXYNOS_THERMAL_COMMON_H
+#define _EXYNOS_THERMAL_COMMON_H
+
+/* In-kernel thermal framework related macros & definations */
+#define SENSOR_NAME_LEN 16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+#define MAX_THRESHOLD_LEVS 4
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+#define MCELSIUS 1000
+
+/* CPU Zone information */
+#define PANIC_ZONE 4
+#define WARN_ZONE 3
+#define MONITOR_ZONE 2
+#define SAFE_ZONE 1
+
+#define GET_ZONE(trip) (trip + 2)
+#define GET_TRIP(zone) (zone - 2)
+
+#define EXYNOS_ZONE_COUNT 3
+
+struct thermal_trip_point_conf {
+ int trip_val[MAX_TRIP_COUNT];
+ int trip_count;
+ unsigned char trigger_falling;
+};
+
+struct thermal_cooling_conf {
+ struct freq_clip_table freq_data[MAX_TRIP_COUNT];
+ int freq_clip_count;
+};
+
+struct thermal_sensor_conf {
+ char name[SENSOR_NAME_LEN];
+ int (*read_temperature)(void *data);
+ int (*write_emul_temp)(void *drv_data, unsigned long temp);
+ struct thermal_trip_point_conf trip_data;
+ struct thermal_cooling_conf cooling_data;
+ void *private_data;
+};
+
+/*Functions used exynos based thermal sensor driver*/
+#ifdef CONFIG_EXYNOS_THERMAL_CORE
+void exynos_unregister_thermal(void);
+int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
+void exynos_report_trigger(void);
+#else
+static inline void
+exynos_unregister_thermal(void) { return; }
+
+static inline int
+exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
+
+static inline void
+exynos_report_trigger(void) { return; }
+
+#endif /* CONFIG_EXYNOS_THERMAL_CORE */
+#endif /* _EXYNOS_THERMAL_COMMON_H */
--
1.7.1
This patch renames exynos_thermal.c to exynos_tmu.c. This change is needed as
this file now just contains exynos tmu driver related codes and thermal zone
or cpufreq cooling registration related changes are not there anymore.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/Makefile | 6 +++---
.../samsung/{exynos_thermal.c => exynos_tmu.c} | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
rename drivers/thermal/samsung/{exynos_thermal.c => exynos_tmu.c} (99%)
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
index 6227d4f..22528d6 100644
--- a/drivers/thermal/samsung/Makefile
+++ b/drivers/thermal/samsung/Makefile
@@ -1,6 +1,6 @@
#
# Samsung thermal specific Makefile
#
-obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
-exynos_soc_thermal-y := exynos_thermal.o
-exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
+obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
+exynos_thermal-y := exynos_tmu.o
+exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_tmu.c
similarity index 99%
rename from drivers/thermal/samsung/exynos_thermal.c
rename to drivers/thermal/samsung/exynos_tmu.c
index 5293849..22a8874 100644
--- a/drivers/thermal/samsung/exynos_thermal.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -1,5 +1,5 @@
/*
- * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
+ * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <[email protected]>
--
1.7.1
This patch adds some extra register bitfield definations and cleans
up the code to prepare for moving register macros and definations inside
the TMU data section.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 62 +++++++++++++++++++++++++---------
1 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 5df04a1..fa33a48 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -43,9 +43,12 @@
#define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
#define EXYNOS_TMU_GAIN_SHIFT 8
+#define EXYNOS_TMU_GAIN_MASK 0xf
#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
-#define EXYNOS_TMU_CORE_ON 3
-#define EXYNOS_TMU_CORE_OFF 2
+#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
+#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
+#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
+#define EXYNOS_TMU_CORE_EN_SHIFT 0
#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
/* Exynos4210 specific registers */
@@ -63,6 +66,7 @@
#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
/* Exynos5250 and Exynos4412 specific registers */
@@ -72,17 +76,30 @@
#define EXYNOS_EMUL_CON 0x80
#define EXYNOS_TRIMINFO_RELOAD 0x1
+#define EXYNOS_TRIMINFO_SHIFT 0x0
+#define EXYNOS_TMU_RISE_INT_MASK 0x111
+#define EXYNOS_TMU_RISE_INT_SHIFT 0
+#define EXYNOS_TMU_FALL_INT_MASK 0x111
+#define EXYNOS_TMU_FALL_INT_SHIFT 12
#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
-#define EXYNOS_MUX_ADDR_VALUE 6
-#define EXYNOS_MUX_ADDR_SHIFT 20
#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
+#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
+
+#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
+#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
+#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
+#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
+#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
+#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
+#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
#define EFUSE_MIN_VALUE 40
#define EFUSE_MAX_VALUE 100
#ifdef CONFIG_THERMAL_EMULATION
#define EXYNOS_EMUL_TIME 0x57F0
+#define EXYNOS_EMUL_TIME_MASK 0xffff
#define EXYNOS_EMUL_TIME_SHIFT 16
#define EXYNOS_EMUL_DATA_SHIFT 8
#define EXYNOS_EMUL_DATA_MASK 0xFF
@@ -261,24 +278,37 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
mutex_lock(&data->lock);
clk_enable(data->clk);
- con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
- pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
+ con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
- if (data->soc == SOC_ARCH_EXYNOS) {
- con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
- con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
+ if (pdata->reference_voltage) {
+ con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
+ EXYNOS_TMU_REF_VOLTAGE_SHIFT);
+ con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
+ }
+
+ if (pdata->gain) {
+ con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
+ con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
+ }
+
+ if (pdata->noise_cancel_mode) {
+ con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
+ EXYNOS_TMU_TRIP_MODE_SHIFT);
+ con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
}
if (on) {
- con |= EXYNOS_TMU_CORE_ON;
- interrupt_en = pdata->trigger_level3_en << 12 |
- pdata->trigger_level2_en << 8 |
- pdata->trigger_level1_en << 4 |
- pdata->trigger_level0_en;
+ con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+ interrupt_en =
+ pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
+ pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
+ pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
+ pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
if (pdata->threshold_falling)
- interrupt_en |= interrupt_en << 16;
+ interrupt_en |=
+ interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
} else {
- con |= EXYNOS_TMU_CORE_OFF;
+ con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
interrupt_en = 0; /* Disable all interrupts */
}
writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
--
1.7.1
This code splits the exynos tmu driver code into SOC specific data parts.
This will simplify adding new SOC specific data to the same TMU controller.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/Kconfig | 3 +-
drivers/thermal/samsung/Makefile | 1 +
drivers/thermal/samsung/exynos_tmu.c | 67 ++-----------------------
drivers/thermal/samsung/exynos_tmu_data.c | 78 +++++++++++++++++++++++++++++
drivers/thermal/samsung/exynos_tmu_data.h | 40 +++++++++++++++
5 files changed, 125 insertions(+), 64 deletions(-)
create mode 100644 drivers/thermal/samsung/exynos_tmu_data.c
create mode 100644 drivers/thermal/samsung/exynos_tmu_data.h
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index f8100b1..b653f15 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -5,7 +5,8 @@ config EXYNOS_THERMAL
If you say yes here you get support for the TMU (Thermal Management
Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
the TMU, reports temperature and handles cooling action if defined.
- This driver uses the exynos core thermal API's.
+ This driver uses the exynos core thermal API's and TMU configuration
+ data from the supported soc's.
config EXYNOS_THERMAL_CORE
bool "Core thermal framework support for EXYNOS SOC's"
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
index 22528d6..c09d830 100644
--- a/drivers/thermal/samsung/Makefile
+++ b/drivers/thermal/samsung/Makefile
@@ -3,4 +3,5 @@
#
obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
exynos_thermal-y := exynos_tmu.o
+exynos_thermal-y += exynos_tmu_data.o
exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 6aa2fd2..5df04a1 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -30,6 +30,7 @@
#include "exynos_thermal_common.h"
#include "exynos_tmu.h"
+#include "exynos_tmu_data.h"
/* Exynos generic registers */
#define EXYNOS_TMU_REG_TRIMINFO 0x0
@@ -381,66 +382,6 @@ static struct thermal_sensor_conf exynos_sensor_conf = {
.write_emul_temp = exynos_tmu_set_emulation,
};
-#if defined(CONFIG_CPU_EXYNOS4210)
-static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
- .threshold = 80,
- .trigger_levels[0] = 5,
- .trigger_levels[1] = 20,
- .trigger_levels[2] = 30,
- .trigger_level0_en = 1,
- .trigger_level1_en = 1,
- .trigger_level2_en = 1,
- .trigger_level3_en = 0,
- .gain = 15,
- .reference_voltage = 7,
- .cal_type = TYPE_ONE_POINT_TRIMMING,
- .freq_tab[0] = {
- .freq_clip_max = 800 * 1000,
- .temp_level = 85,
- },
- .freq_tab[1] = {
- .freq_clip_max = 200 * 1000,
- .temp_level = 100,
- },
- .freq_tab_count = 2,
- .type = SOC_ARCH_EXYNOS4210,
-};
-#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
-#else
-#define EXYNOS4210_TMU_DRV_DATA (NULL)
-#endif
-
-#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
-static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
- .threshold_falling = 10,
- .trigger_levels[0] = 85,
- .trigger_levels[1] = 103,
- .trigger_levels[2] = 110,
- .trigger_level0_en = 1,
- .trigger_level1_en = 1,
- .trigger_level2_en = 1,
- .trigger_level3_en = 0,
- .gain = 8,
- .reference_voltage = 16,
- .noise_cancel_mode = 4,
- .cal_type = TYPE_ONE_POINT_TRIMMING,
- .efuse_value = 55,
- .freq_tab[0] = {
- .freq_clip_max = 800 * 1000,
- .temp_level = 85,
- },
- .freq_tab[1] = {
- .freq_clip_max = 200 * 1000,
- .temp_level = 103,
- },
- .freq_tab_count = 2,
- .type = SOC_ARCH_EXYNOS,
-};
-#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
-#else
-#define EXYNOS_TMU_DRV_DATA (NULL)
-#endif
-
#ifdef CONFIG_OF
static const struct of_device_id exynos_tmu_match[] = {
{
@@ -449,11 +390,11 @@ static const struct of_device_id exynos_tmu_match[] = {
},
{
.compatible = "samsung,exynos4412-tmu",
- .data = (void *)EXYNOS_TMU_DRV_DATA,
+ .data = (void *)EXYNOS5250_TMU_DRV_DATA,
},
{
.compatible = "samsung,exynos5250-tmu",
- .data = (void *)EXYNOS_TMU_DRV_DATA,
+ .data = (void *)EXYNOS5250_TMU_DRV_DATA,
},
{},
};
@@ -467,7 +408,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = {
},
{
.name = "exynos5250-tmu",
- .driver_data = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
+ .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
},
{ },
};
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
new file mode 100644
index 0000000..13a60ca
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -0,0 +1,78 @@
+/*
+ * exynos_tmu_data.c - Samsung EXYNOS tmu data file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Amit Daniel Kachhap <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "exynos_thermal_common.h"
+#include "exynos_tmu.h"
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
+ .threshold = 80,
+ .trigger_levels[0] = 5,
+ .trigger_levels[1] = 20,
+ .trigger_levels[2] = 30,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 0,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ .temp_level = 85,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ .temp_level = 100,
+ },
+ .freq_tab_count = 2,
+ .type = SOC_ARCH_EXYNOS4210,
+};
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
+struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
+ .threshold_falling = 10,
+ .trigger_levels[0] = 85,
+ .trigger_levels[1] = 103,
+ .trigger_levels[2] = 110,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 0,
+ .gain = 8,
+ .reference_voltage = 16,
+ .noise_cancel_mode = 4,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .efuse_value = 55,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ .temp_level = 85,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ .temp_level = 103,
+ },
+ .freq_tab_count = 2,
+ .type = SOC_ARCH_EXYNOS,
+};
+#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
new file mode 100644
index 0000000..b7835fe
--- /dev/null
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -0,0 +1,40 @@
+/*
+ * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Amit Daniel Kachhap <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _EXYNOS_TMU_DATA_H
+#define _EXYNOS_TMU_DATA_H
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
+#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA (NULL)
+#endif
+
+#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
+extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
+#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
+#else
+#define EXYNOS5250_TMU_DRV_DATA (NULL)
+#endif
+
+#endif /*_EXYNOS_TMU_DATA_H*/
--
1.7.1
This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
trigger_enable in the TMU platform data structure. Also the driver is modified
to use the data passed by these new platform memebers instead of the constant
macros. All these changes helps in separating the SOC specific data part from
the TMU driver.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
4 files changed, 86 insertions(+), 48 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index 068f56c..fd789a5 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -44,6 +44,13 @@
#define EXYNOS_ZONE_COUNT 3
+enum trigger_type {
+ THROTTLE_ACTIVE = 1,
+ THROTTLE_PASSIVE,
+ SW_TRIP,
+ HW_TRIP,
+};
+
/**
* struct freq_clip_table
* @freq_clip_max: maximum frequency allowed for this cooling state.
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index fa33a48..401ec98 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -49,7 +49,6 @@
#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
#define EXYNOS_TMU_CORE_EN_SHIFT 0
-#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
/* Exynos4210 specific registers */
#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
@@ -94,9 +93,6 @@
#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
-#define EFUSE_MIN_VALUE 40
-#define EFUSE_MAX_VALUE 100
-
#ifdef CONFIG_THERMAL_EMULATION
#define EXYNOS_EMUL_TIME 0x57F0
#define EXYNOS_EMUL_TIME_MASK 0xffff
@@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
switch (pdata->cal_type) {
case TYPE_TWO_POINT_TRIMMING:
- temp_code = (temp - 25) *
- (data->temp_error2 - data->temp_error1) /
- (85 - 25) + data->temp_error1;
+ temp_code = (temp - pdata->first_point_trim) *
+ (data->temp_error2 - data->temp_error1) /
+ (pdata->second_point_trim - pdata->first_point_trim) +
+ data->temp_error1;
break;
case TYPE_ONE_POINT_TRIMMING:
- temp_code = temp + data->temp_error1 - 25;
+ temp_code = temp + data->temp_error1 - pdata->first_point_trim;
break;
default:
- temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ temp_code = temp + pdata->default_temp_offset;
break;
}
out:
@@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
switch (pdata->cal_type) {
case TYPE_TWO_POINT_TRIMMING:
- temp = (temp_code - data->temp_error1) * (85 - 25) /
- (data->temp_error2 - data->temp_error1) + 25;
+ temp = (temp_code - data->temp_error1) *
+ (pdata->second_point_trim - pdata->first_point_trim) /
+ (data->temp_error2 - data->temp_error1) +
+ pdata->first_point_trim;
break;
case TYPE_ONE_POINT_TRIMMING:
- temp = temp_code - data->temp_error1 + 25;
+ temp = temp_code - data->temp_error1 + pdata->first_point_trim;
break;
default:
- temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ temp = temp_code - pdata->default_temp_offset;
break;
}
out:
@@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
- if ((EFUSE_MIN_VALUE > data->temp_error1) ||
- (data->temp_error1 > EFUSE_MAX_VALUE) ||
+ if ((pdata->min_efuse_value > data->temp_error1) ||
+ (data->temp_error1 > pdata->max_efuse_value) ||
(data->temp_error2 != 0))
data->temp_error1 = pdata->efuse_value;
@@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
if (on) {
con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
interrupt_en =
- pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
- pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
- pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
- pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
+ pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
+ pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
+ pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
+ pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
if (pdata->threshold_falling)
interrupt_en |=
interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
@@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
/* Register the sensor with thermal management interface */
(&exynos_sensor_conf)->private_data = data;
- exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
- pdata->trigger_level1_en + pdata->trigger_level2_en +
- pdata->trigger_level3_en;
+ exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
+ pdata->trigger_enable[1] + pdata->trigger_enable[2]+
+ pdata->trigger_enable[3];
for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
exynos_sensor_conf.trip_data.trip_val[i] =
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 9e0f887..45c697d 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -30,6 +30,11 @@ enum calibration_type {
TYPE_NONE,
};
+enum calibration_mode {
+ SW_MODE,
+ HW_MODE,
+};
+
enum soc_type {
SOC_ARCH_EXYNOS4210 = 1,
SOC_ARCH_EXYNOS,
@@ -55,18 +60,15 @@ enum soc_type {
* 3: temperature for trigger_level3 interrupt
* condition for trigger_level3 interrupt:
* current temperature > threshold + trigger_levels[3]
- * @trigger_level0_en:
- * 1 = enable trigger_level0 interrupt,
- * 0 = disable trigger_level0 interrupt
- * @trigger_level1_en:
- * 1 = enable trigger_level1 interrupt,
- * 0 = disable trigger_level1 interrupt
- * @trigger_level2_en:
- * 1 = enable trigger_level2 interrupt,
- * 0 = disable trigger_level2 interrupt
- * @trigger_level3_en:
- * 1 = enable trigger_level3 interrupt,
- * 0 = disable trigger_level3 interrupt
+ * @trigger_type: defines the type of trigger. Possible values are,
+ * THROTTLE_ACTIVE trigger type
+ * THROTTLE_PASSIVE trigger type
+ * SW_TRIP trigger type
+ * HW_TRIP
+ * @trigger_enable[]: array to denote which trigger levels are enabled.
+ * 1 = enable trigger_level[] interrupt,
+ * 0 = disable trigger_level[] interrupt
+ * @max_trigger_level: max trigger level supported by the TMU
* @gain: gain of amplifier in the positive-TC generator block
* 0 <= gain <= 15
* @reference_voltage: reference voltage of amplifier
@@ -76,7 +78,13 @@ enum soc_type {
* 000, 100, 101, 110 and 111 can be different modes
* @type: determines the type of SOC
* @efuse_value: platform defined fuse value
+ * @min_efuse_value: minimum valid trimming data
+ * @max_efuse_value: maximum valid trimming data
+ * @first_point_trim: temp value of the first point trimming
+ * @second_point_trim: temp value of the second point trimming
+ * @default_temp_offset: default temperature offset in case of no trimming
* @cal_type: calibration type for temperature
+ * @cal_mode: calibration mode for temperature
* @freq_clip_table: Table representing frequency reduction percentage.
* @freq_tab_count: Count of the above table as frequency reduction may
* applicable to only some of the trigger levels.
@@ -86,18 +94,23 @@ enum soc_type {
struct exynos_tmu_platform_data {
u8 threshold;
u8 threshold_falling;
- u8 trigger_levels[4];
- bool trigger_level0_en;
- bool trigger_level1_en;
- bool trigger_level2_en;
- bool trigger_level3_en;
-
+ u8 trigger_levels[MAX_TRIP_COUNT];
+ enum trigger_type trigger_type[MAX_TRIP_COUNT];
+ bool trigger_enable[MAX_TRIP_COUNT];
+ u8 max_trigger_level;
u8 gain;
u8 reference_voltage;
u8 noise_cancel_mode;
+
u32 efuse_value;
+ u32 min_efuse_value;
+ u32 max_efuse_value;
+ u8 first_point_trim;
+ u8 second_point_trim;
+ u8 default_temp_offset;
enum calibration_type cal_type;
+ enum calibration_mode cal_mode;
enum soc_type type;
struct freq_clip_table freq_tab[4];
unsigned int freq_tab_count;
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index 13a60ca..a187043 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -22,6 +22,7 @@
#include "exynos_thermal_common.h"
#include "exynos_tmu.h"
+#include "exynos_tmu_data.h"
#if defined(CONFIG_CPU_EXYNOS4210)
struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
@@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
.trigger_levels[0] = 5,
.trigger_levels[1] = 20,
.trigger_levels[2] = 30,
- .trigger_level0_en = 1,
- .trigger_level1_en = 1,
- .trigger_level2_en = 1,
- .trigger_level3_en = 0,
+ .trigger_enable[0] = 1,
+ .trigger_enable[1] = 1,
+ .trigger_enable[2] = 1,
+ .trigger_enable[3] = 0,
+ .trigger_type[0] = THROTTLE_ACTIVE,
+ .trigger_type[1] = THROTTLE_ACTIVE,
+ .trigger_type[2] = SW_TRIP,
+ .max_trigger_level = 4,
.gain = 15,
.reference_voltage = 7,
.cal_type = TYPE_ONE_POINT_TRIMMING,
+ .min_efuse_value = 40,
+ .max_efuse_value = 100,
+ .first_point_trim = 25,
+ .second_point_trim = 85,
+ .default_temp_offset = 50,
.freq_tab[0] = {
.freq_clip_max = 800 * 1000,
.temp_level = 85,
@@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
.trigger_levels[0] = 85,
.trigger_levels[1] = 103,
.trigger_levels[2] = 110,
- .trigger_level0_en = 1,
- .trigger_level1_en = 1,
- .trigger_level2_en = 1,
- .trigger_level3_en = 0,
+ .trigger_enable[0] = 1,
+ .trigger_enable[1] = 1,
+ .trigger_enable[2] = 1,
+ .trigger_enable[3] = 0,
+ .trigger_type[0] = THROTTLE_ACTIVE,
+ .trigger_type[1] = THROTTLE_ACTIVE,
+ .trigger_type[2] = SW_TRIP,
+ .max_trigger_level = 4,
.gain = 8,
.reference_voltage = 16,
.noise_cancel_mode = 4,
.cal_type = TYPE_ONE_POINT_TRIMMING,
.efuse_value = 55,
+ .min_efuse_value = 40,
+ .max_efuse_value = 100,
+ .first_point_trim = 25,
+ .second_point_trim = 85,
+ .default_temp_offset = 50,
.freq_tab[0] = {
.freq_clip_max = 800 * 1000,
.temp_level = 85,
--
1.7.1
This patch migrates the TMU register definition/bitfields to data file. This
is needed to support SoC's which use the same TMU controller but register
validity, offsets or bitfield may slightly vary across SOC's.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 172 +++++++++-------------------
drivers/thermal/samsung/exynos_tmu.h | 133 ++++++++++++++++++++++
drivers/thermal/samsung/exynos_tmu_data.c | 59 ++++++++++
drivers/thermal/samsung/exynos_tmu_data.h | 68 +++++++++++
4 files changed, 315 insertions(+), 117 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 401ec98..6fd776f 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -32,76 +32,6 @@
#include "exynos_tmu.h"
#include "exynos_tmu_data.h"
-/* Exynos generic registers */
-#define EXYNOS_TMU_REG_TRIMINFO 0x0
-#define EXYNOS_TMU_REG_CONTROL 0x20
-#define EXYNOS_TMU_REG_STATUS 0x28
-#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
-#define EXYNOS_TMU_REG_INTEN 0x70
-#define EXYNOS_TMU_REG_INTSTAT 0x74
-#define EXYNOS_TMU_REG_INTCLEAR 0x78
-
-#define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
-#define EXYNOS_TMU_GAIN_SHIFT 8
-#define EXYNOS_TMU_GAIN_MASK 0xf
-#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
-#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
-#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
-#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
-#define EXYNOS_TMU_CORE_EN_SHIFT 0
-
-/* Exynos4210 specific registers */
-#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
-#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
-#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
-#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
-#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
-
-#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
-#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
-#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
-#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
-#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
-#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
-
-/* Exynos5250 and Exynos4412 specific registers */
-#define EXYNOS_TMU_TRIMINFO_CON 0x14
-#define EXYNOS_THD_TEMP_RISE 0x50
-#define EXYNOS_THD_TEMP_FALL 0x54
-#define EXYNOS_EMUL_CON 0x80
-
-#define EXYNOS_TRIMINFO_RELOAD 0x1
-#define EXYNOS_TRIMINFO_SHIFT 0x0
-#define EXYNOS_TMU_RISE_INT_MASK 0x111
-#define EXYNOS_TMU_RISE_INT_SHIFT 0
-#define EXYNOS_TMU_FALL_INT_MASK 0x111
-#define EXYNOS_TMU_FALL_INT_SHIFT 12
-#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
-#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
-#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
-#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
-
-#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
-#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
-#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
-#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
-#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
-#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
-#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
-
-#ifdef CONFIG_THERMAL_EMULATION
-#define EXYNOS_EMUL_TIME 0x57F0
-#define EXYNOS_EMUL_TIME_MASK 0xffff
-#define EXYNOS_EMUL_TIME_SHIFT 16
-#define EXYNOS_EMUL_DATA_SHIFT 8
-#define EXYNOS_EMUL_DATA_MASK 0xFF
-#define EXYNOS_EMUL_ENABLE 0x1
-#endif /* CONFIG_THERMAL_EMULATION */
-
struct exynos_tmu_data {
struct exynos_tmu_platform_data *pdata;
struct resource *mem;
@@ -186,6 +116,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct exynos_tmu_registers *reg = pdata->registers;
unsigned int status, trim_info;
unsigned int rising_threshold = 0, falling_threshold = 0;
int ret = 0, threshold_code, i, trigger_levs = 0;
@@ -193,20 +124,20 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
mutex_lock(&data->lock);
clk_enable(data->clk);
- status = readb(data->base + EXYNOS_TMU_REG_STATUS);
+ status = readb(data->base + reg->tmu_status);
if (!status) {
ret = -EBUSY;
goto out;
}
- if (data->soc == SOC_ARCH_EXYNOS) {
- __raw_writel(EXYNOS_TRIMINFO_RELOAD,
- data->base + EXYNOS_TMU_TRIMINFO_CON);
- }
+ if (data->soc == SOC_ARCH_EXYNOS)
+ __raw_writel(1, data->base + reg->triminfo_ctrl);
+
/* Save trimming info in order to perform calibration */
- trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
- data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
- data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
+ trim_info = readl(data->base + reg->triminfo_data);
+ data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
+ data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
+ EXYNOS_TMU_TEMP_MASK);
if ((pdata->min_efuse_value > data->temp_error1) ||
(data->temp_error1 > pdata->max_efuse_value) ||
@@ -226,13 +157,12 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
goto out;
}
writeb(threshold_code,
- data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
+ data->base + reg->threshold_temp);
for (i = 0; i < trigger_levs; i++)
- writeb(pdata->trigger_levels[i],
- data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
+ writeb(pdata->trigger_levels[i], data->base +
+ reg->threshold_th0 + i * sizeof(reg->threshold_th0));
- writel(EXYNOS4210_TMU_INTCLEAR_VAL,
- data->base + EXYNOS_TMU_REG_INTCLEAR);
+ writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
} else if (data->soc == SOC_ARCH_EXYNOS) {
/* Write temperature code for rising and falling threshold */
for (i = 0; i < trigger_levs; i++) {
@@ -254,12 +184,13 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
}
writel(rising_threshold,
- data->base + EXYNOS_THD_TEMP_RISE);
+ data->base + reg->threshold_th0);
writel(falling_threshold,
- data->base + EXYNOS_THD_TEMP_FALL);
+ data->base + reg->threshold_th1);
- writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
- data->base + EXYNOS_TMU_REG_INTCLEAR);
+ writel((reg->inten_rise_mask << reg->inten_rise_shift) |
+ (reg->inten_fall_mask << reg->inten_fall_shift),
+ data->base + reg->tmu_intclear);
}
out:
clk_disable(data->clk);
@@ -272,46 +203,46 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct exynos_tmu_registers *reg = pdata->registers;
unsigned int con, interrupt_en;
mutex_lock(&data->lock);
clk_enable(data->clk);
- con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
+ con = readl(data->base + reg->tmu_ctrl);
if (pdata->reference_voltage) {
- con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
- EXYNOS_TMU_REF_VOLTAGE_SHIFT);
- con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
+ con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift);
+ con |= pdata->reference_voltage << reg->buf_vref_sel_shift;
}
if (pdata->gain) {
- con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
- con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
+ con &= ~(reg->buf_slope_sel_mask << reg->buf_slope_sel_shift);
+ con |= (pdata->gain << reg->buf_slope_sel_shift);
}
if (pdata->noise_cancel_mode) {
- con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
- EXYNOS_TMU_TRIP_MODE_SHIFT);
- con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
+ con &= ~(reg->therm_trip_mode_mask <<
+ reg->therm_trip_mode_shift);
+ con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
}
if (on) {
- con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+ con |= (1 << reg->core_en_shift);
interrupt_en =
- pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
- pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
- pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
- pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
+ pdata->trigger_enable[3] << reg->inten_rise3_shift |
+ pdata->trigger_enable[2] << reg->inten_rise2_shift |
+ pdata->trigger_enable[1] << reg->inten_rise1_shift |
+ pdata->trigger_enable[0] << reg->inten_rise0_shift;
if (pdata->threshold_falling)
interrupt_en |=
- interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
+ interrupt_en << reg->inten_fall0_shift;
} else {
- con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+ con &= ~(1 << reg->core_en_shift);
interrupt_en = 0; /* Disable all interrupts */
}
- writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
- writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+ writel(interrupt_en, data->base + reg->tmu_inten);
+ writel(con, data->base + reg->tmu_ctrl);
clk_disable(data->clk);
mutex_unlock(&data->lock);
@@ -319,13 +250,15 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
static int exynos_tmu_read(struct exynos_tmu_data *data)
{
+ struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct exynos_tmu_registers *reg = pdata->registers;
u8 temp_code;
int temp;
mutex_lock(&data->lock);
clk_enable(data->clk);
- temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
+ temp_code = readb(data->base + reg->tmu_cur_temp);
temp = code_to_temp(data, temp_code);
clk_disable(data->clk);
@@ -338,7 +271,9 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
{
struct exynos_tmu_data *data = drv_data;
- unsigned int reg;
+ struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct exynos_tmu_registers *reg = pdata->registers;
+ unsigned int val;
int ret = -EINVAL;
if (data->soc == SOC_ARCH_EXYNOS4210)
@@ -350,19 +285,19 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
mutex_lock(&data->lock);
clk_enable(data->clk);
- reg = readl(data->base + EXYNOS_EMUL_CON);
+ val = readl(data->base + reg->emul_con);
if (temp) {
temp /= MCELSIUS;
- reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
+ val = (EXYNOS_EMUL_TIME << reg->emul_time_shift) |
(temp_to_code(data, temp)
- << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
+ << reg->emul_temp_shift) | EXYNOS_EMUL_ENABLE;
} else {
- reg &= ~EXYNOS_EMUL_ENABLE;
+ val &= ~EXYNOS_EMUL_ENABLE;
}
- writel(reg, data->base + EXYNOS_EMUL_CON);
+ writel(val, data->base + reg->emul_con);
clk_disable(data->clk);
mutex_unlock(&data->lock);
@@ -379,17 +314,20 @@ static void exynos_tmu_work(struct work_struct *work)
{
struct exynos_tmu_data *data = container_of(work,
struct exynos_tmu_data, irq_work);
+ struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct exynos_tmu_registers *reg = pdata->registers;
exynos_report_trigger();
mutex_lock(&data->lock);
clk_enable(data->clk);
+
if (data->soc == SOC_ARCH_EXYNOS)
- writel(EXYNOS_TMU_CLEAR_RISE_INT |
- EXYNOS_TMU_CLEAR_FALL_INT,
- data->base + EXYNOS_TMU_REG_INTCLEAR);
+ writel((reg->inten_rise_mask << reg->inten_rise_shift) |
+ (reg->inten_fall_mask << reg->inten_fall_shift),
+ data->base + reg->tmu_intclear);
else
- writel(EXYNOS4210_TMU_INTCLEAR_VAL,
- data->base + EXYNOS_TMU_REG_INTCLEAR);
+ writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
+
clk_disable(data->clk);
mutex_unlock(&data->lock);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 45c697d..619a34c 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -41,6 +41,136 @@ enum soc_type {
};
/**
+ * struct exynos_tmu_register - register descriptors to access registers and
+ * bitfields. The register validity, offsets and bitfield values may vary
+ * slightly across different exynos SOC's.
+ * @triminfo_data: register containing 2 pont trimming data
+ * @triminfo_25_shift: shift bit of the 25 C trim value in triminfo_data reg.
+ * @triminfo_85_shift: shift bit of the 85 C trim value in triminfo_data reg.
+ * @triminfo_ctrl: trim info controller register.
+ * @triminfo_reload_shift: shift of triminfo reload enable bit in triminfo_ctrl
+ reg.
+ * @tmu_ctrl: TMU main controller register.
+ * @buf_vref_sel_shift: shift bits of reference voltage in tmu_ctrl register.
+ * @buf_vref_sel_mask: mask bits of reference voltage in tmu_ctrl register.
+ * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register.
+ * @therm_trip_mode_mask: mask bits of tripping mode in tmu_ctrl register.
+ * @therm_trip_en_shift: shift bits of tripping enable in tmu_ctrl register.
+ * @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
+ register.
+ * @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
+ * @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
+ tmu_ctrl register.
+ * @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
+ * @tmu_status: register drescribing the TMU status.
+ * @tmu_cur_temp: register containing the current temperature of the TMU.
+ * @tmu_cur_temp_shift: shift bits of current temp value in tmu_cur_temp
+ register.
+ * @threshold_temp: register containing the base threshold level.
+ * @threshold_th0: Register containing first set of rising levels.
+ * @threshold_th0_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th0_l1_shift: shift bits of level1 threshold temperature.
+ * @threshold_th0_l2_shift: shift bits of level2 threshold temperature.
+ * @threshold_th0_l3_shift: shift bits of level3 threshold temperature.
+ * @threshold_th1: Register containing second set of rising levels.
+ * @threshold_th1_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th1_l1_shift: shift bits of level1 threshold temperature.
+ * @threshold_th1_l2_shift: shift bits of level2 threshold temperature.
+ * @threshold_th1_l3_shift: shift bits of level3 threshold temperature.
+ * @threshold_th2: Register containing third set of rising levels.
+ * @threshold_th2_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th3: Register containing fourth set of rising levels.
+ * @threshold_th3_l0_shift: shift bits of level0 threshold temperature.
+ * @tmu_inten: register containing the different threshold interrupt
+ enable bits.
+ * @inten_rise_shift: shift bits of all rising interrupt bits.
+ * @inten_rise_mask: mask bits of all rising interrupt bits.
+ * @inten_fall_shift: shift bits of all rising interrupt bits.
+ * @inten_fall_mask: mask bits of all rising interrupt bits.
+ * @inten_rise0_shift: shift bits of rising 0 interrupt bits.
+ * @inten_rise1_shift: shift bits of rising 1 interrupt bits.
+ * @inten_rise2_shift: shift bits of rising 2 interrupt bits.
+ * @inten_rise3_shift: shift bits of rising 3 interrupt bits.
+ * @inten_fall0_shift: shift bits of falling 0 interrupt bits.
+ * @inten_fall1_shift: shift bits of falling 1 interrupt bits.
+ * @inten_fall2_shift: shift bits of falling 2 interrupt bits.
+ * @inten_fall3_shift: shift bits of falling 3 interrupt bits.
+ * @tmu_intstat: Register containing the interrupt status values.
+ * @tmu_intclear: Register for clearing the raised interrupt status.
+ * @emul_con: TMU emulation controller register.
+ * @emul_temp_shift: shift bits of emulation temperature.
+ * @emul_time_shift: shift bits of emulation time.
+ * @emul_time_mask: mask bits of emulation time.
+ */
+struct exynos_tmu_registers {
+ u32 triminfo_data;
+ u32 triminfo_25_shift;
+ u32 triminfo_85_shift;
+
+ u32 triminfo_ctrl;
+ u32 triminfo_reload_shift;
+
+ u32 tmu_ctrl;
+ u32 buf_vref_sel_shift;
+ u32 buf_vref_sel_mask;
+ u32 therm_trip_mode_shift;
+ u32 therm_trip_mode_mask;
+ u32 therm_trip_en_shift;
+ u32 buf_slope_sel_shift;
+ u32 buf_slope_sel_mask;
+ u32 therm_trip_tq_en_shift;
+ u32 core_en_shift;
+
+ u32 tmu_status;
+
+ u32 tmu_cur_temp;
+ u32 tmu_cur_temp_shift;
+
+ u32 threshold_temp;
+
+ u32 threshold_th0;
+ u32 threshold_th0_l0_shift;
+ u32 threshold_th0_l1_shift;
+ u32 threshold_th0_l2_shift;
+ u32 threshold_th0_l3_shift;
+
+ u32 threshold_th1;
+ u32 threshold_th1_l0_shift;
+ u32 threshold_th1_l1_shift;
+ u32 threshold_th1_l2_shift;
+ u32 threshold_th1_l3_shift;
+
+ u32 threshold_th2;
+ u32 threshold_th2_l0_shift;
+
+ u32 threshold_th3;
+ u32 threshold_th3_l0_shift;
+
+ u32 tmu_inten;
+ u32 inten_rise_shift;
+ u32 inten_rise_mask;
+ u32 inten_fall_shift;
+ u32 inten_fall_mask;
+ u32 inten_rise0_shift;
+ u32 inten_rise1_shift;
+ u32 inten_rise2_shift;
+ u32 inten_rise3_shift;
+ u32 inten_fall0_shift;
+ u32 inten_fall1_shift;
+ u32 inten_fall2_shift;
+ u32 inten_fall3_shift;
+
+ u32 tmu_intstat;
+
+ u32 tmu_intclear;
+
+ u32 emul_con;
+ u32 emul_temp_shift;
+ u32 emul_time_shift;
+ u32 emul_time_mask;
+};
+
+/**
* struct exynos_tmu_platform_data
* @threshold: basic temperature for generating interrupt
* 25 <= threshold <= 125 [unit: degree Celsius]
@@ -88,6 +218,8 @@ enum soc_type {
* @freq_clip_table: Table representing frequency reduction percentage.
* @freq_tab_count: Count of the above table as frequency reduction may
* applicable to only some of the trigger levels.
+ * @registers: Pointer to structure containing all the TMU controller registers
+ * and bitfields shifts and masks.
*
* This structure is required for configuration of exynos_tmu driver.
*/
@@ -114,5 +246,6 @@ struct exynos_tmu_platform_data {
enum soc_type type;
struct freq_clip_table freq_tab[4];
unsigned int freq_tab_count;
+ const struct exynos_tmu_registers *registers;
};
#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index a187043..589a519 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -25,6 +25,28 @@
#include "exynos_tmu_data.h"
#if defined(CONFIG_CPU_EXYNOS4210)
+static const struct exynos_tmu_registers exynos4210_tmu_registers = {
+ .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
+ .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+ .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+ .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
+ .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+ .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+ .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+ .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+ .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+ .tmu_status = EXYNOS_TMU_REG_STATUS,
+ .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
+ .threshold_temp = EXYNOS4210_TMU_REG_THRESHOLD_TEMP,
+ .threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0,
+ .tmu_inten = EXYNOS_TMU_REG_INTEN,
+ .inten_rise_mask = EXYNOS4210_TMU_TRIG_LEVEL_MASK,
+ .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
+ .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
+ .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
+ .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
+ .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
+};
struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
.threshold = 80,
.trigger_levels[0] = 5,
@@ -56,10 +78,46 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
},
.freq_tab_count = 2,
.type = SOC_ARCH_EXYNOS4210,
+ .registers = &exynos4210_tmu_registers,
};
#endif
#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
+static const struct exynos_tmu_registers exynos5250_tmu_registers = {
+ .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
+ .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+ .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+ .triminfo_ctrl = EXYNOS_TMU_TRIMINFO_CON,
+ .triminfo_reload_shift = EXYNOS_TRIMINFO_RELOAD_SHIFT,
+ .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
+ .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+ .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+ .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
+ .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
+ .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
+ .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+ .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+ .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+ .tmu_status = EXYNOS_TMU_REG_STATUS,
+ .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
+ .threshold_th0 = EXYNOS_THD_TEMP_RISE,
+ .threshold_th1 = EXYNOS_THD_TEMP_FALL,
+ .tmu_inten = EXYNOS_TMU_REG_INTEN,
+ .inten_rise_mask = EXYNOS_TMU_RISE_INT_MASK,
+ .inten_rise_shift = EXYNOS_TMU_RISE_INT_SHIFT,
+ .inten_fall_mask = EXYNOS_TMU_FALL_INT_MASK,
+ .inten_fall_shift = EXYNOS_TMU_FALL_INT_SHIFT,
+ .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
+ .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
+ .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
+ .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
+ .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
+ .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
+ .emul_con = EXYNOS_EMUL_CON,
+ .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
+ .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
+ .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
+};
struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
.threshold_falling = 10,
.trigger_levels[0] = 85,
@@ -93,5 +151,6 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
},
.freq_tab_count = 2,
.type = SOC_ARCH_EXYNOS,
+ .registers = &exynos5250_tmu_registers,
};
#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index b7835fe..0e2244f 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -23,6 +23,74 @@
#ifndef _EXYNOS_TMU_DATA_H
#define _EXYNOS_TMU_DATA_H
+/* Exynos generic registers */
+#define EXYNOS_TMU_REG_TRIMINFO 0x0
+#define EXYNOS_TMU_REG_CONTROL 0x20
+#define EXYNOS_TMU_REG_STATUS 0x28
+#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
+#define EXYNOS_TMU_REG_INTEN 0x70
+#define EXYNOS_TMU_REG_INTSTAT 0x74
+#define EXYNOS_TMU_REG_INTCLEAR 0x78
+
+#define EXYNOS_TMU_TEMP_MASK 0xff
+#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
+#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
+#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
+#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
+#define EXYNOS_TMU_CORE_EN_SHIFT 0
+
+/* Exynos4210 specific registers */
+#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
+#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
+#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
+#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
+
+#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
+#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
+#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
+#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
+#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
+
+/* Exynos5250 and Exynos4412 specific registers */
+#define EXYNOS_TMU_TRIMINFO_CON 0x14
+#define EXYNOS_THD_TEMP_RISE 0x50
+#define EXYNOS_THD_TEMP_FALL 0x54
+#define EXYNOS_EMUL_CON 0x80
+
+#define EXYNOS_TRIMINFO_RELOAD_SHIFT 1
+#define EXYNOS_TRIMINFO_25_SHIFT 0
+#define EXYNOS_TRIMINFO_85_SHIFT 8
+#define EXYNOS_TMU_RISE_INT_MASK 0x111
+#define EXYNOS_TMU_RISE_INT_SHIFT 0
+#define EXYNOS_TMU_FALL_INT_MASK 0x111
+#define EXYNOS_TMU_FALL_INT_SHIFT 12
+#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
+#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
+#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
+#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
+#define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
+
+#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
+#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
+#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
+#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
+#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
+#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
+#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
+
+#define EXYNOS_EMUL_TIME 0x57F0
+#define EXYNOS_EMUL_TIME_MASK 0xffff
+#define EXYNOS_EMUL_TIME_SHIFT 16
+#define EXYNOS_EMUL_DATA_SHIFT 8
+#define EXYNOS_EMUL_DATA_MASK 0xFF
+#define EXYNOS_EMUL_ENABLE 0x1
+
#if defined(CONFIG_CPU_EXYNOS4210)
extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
--
1.7.1
TMU urgently sends active-high signal (thermal trip) to PMU, and thermal
tripping by hardware logic. Thermal tripping means that PMU cuts off the
whole power of SoC by controlling external voltage regulator.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Jonghwan Choi <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 45 +++++++++++++++++++++++++---
drivers/thermal/samsung/exynos_tmu_data.c | 2 +
drivers/thermal/samsung/exynos_tmu_data.h | 2 +
3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 6fd776f..33f494e 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -117,7 +117,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata = data->pdata;
const struct exynos_tmu_registers *reg = pdata->registers;
- unsigned int status, trim_info;
+ unsigned int status, trim_info = 0, con;
unsigned int rising_threshold = 0, falling_threshold = 0;
int ret = 0, threshold_code, i, trigger_levs = 0;
@@ -144,10 +144,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
(data->temp_error2 != 0))
data->temp_error1 = pdata->efuse_value;
- /* Count trigger levels to be enabled */
- for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
- if (pdata->trigger_levels[i])
+ if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
+ dev_err(&pdev->dev, "Invalid max trigger level\n");
+ goto out;
+ }
+
+ for (i = 0; i < pdata->max_trigger_level; i++) {
+ if (!pdata->trigger_levels[i])
+ continue;
+
+ if ((pdata->trigger_type[i] == HW_TRIP) &&
+ (!pdata->trigger_levels[pdata->max_trigger_level - 1])) {
+ dev_err(&pdev->dev, "Invalid hw trigger level\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Count trigger levels except the HW trip*/
+ if (!(pdata->trigger_type[i] == HW_TRIP))
trigger_levs++;
+ }
if (data->soc == SOC_ARCH_EXYNOS4210) {
/* Write temperature code for threshold */
@@ -165,7 +181,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
} else if (data->soc == SOC_ARCH_EXYNOS) {
/* Write temperature code for rising and falling threshold */
- for (i = 0; i < trigger_levs; i++) {
+ for (i = 0;
+ i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
threshold_code = temp_to_code(data,
pdata->trigger_levels[i]);
if (threshold_code < 0) {
@@ -191,6 +208,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
writel((reg->inten_rise_mask << reg->inten_rise_shift) |
(reg->inten_fall_mask << reg->inten_fall_shift),
data->base + reg->tmu_intclear);
+
+ /* if last threshold limit is also present */
+ i = pdata->max_trigger_level - 1;
+ if (pdata->trigger_levels[i] &&
+ (pdata->trigger_type[i] == HW_TRIP)) {
+ threshold_code = temp_to_code(data,
+ pdata->trigger_levels[i]);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ rising_threshold |= threshold_code << 8 * i;
+ writel(rising_threshold,
+ data->base + reg->threshold_th0);
+ con = readl(data->base + reg->tmu_ctrl);
+ con |= (1 << reg->therm_trip_en_shift);
+ writel(con, data->base + reg->tmu_ctrl);
+ }
}
out:
clk_disable(data->clk);
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index 589a519..e7cb1cc 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -123,6 +123,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
.trigger_levels[0] = 85,
.trigger_levels[1] = 103,
.trigger_levels[2] = 110,
+ .trigger_levels[3] = 120,
.trigger_enable[0] = 1,
.trigger_enable[1] = 1,
.trigger_enable[2] = 1,
@@ -130,6 +131,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
.trigger_type[0] = THROTTLE_ACTIVE,
.trigger_type[1] = THROTTLE_ACTIVE,
.trigger_type[2] = SW_TRIP,
+ .trigger_type[3] = HW_TRIP,
.max_trigger_level = 4,
.gain = 8,
.reference_voltage = 16,
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index 0e2244f..4acf070 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -91,6 +91,8 @@
#define EXYNOS_EMUL_DATA_MASK 0xFF
#define EXYNOS_EMUL_ENABLE 0x1
+#define EXYNOS_MAX_TRIGGER_PER_REG 4
+
#if defined(CONFIG_CPU_EXYNOS4210)
extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
--
1.7.1
This code modifies the thermal driver to have multiple thermal zone
support by replacing the global thermal zone variable with device data
member of thermal_zone_device.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 36 ++++++++++++++--------
drivers/thermal/samsung/exynos_thermal_common.h | 9 +++--
drivers/thermal/samsung/exynos_tmu.c | 15 +++++----
3 files changed, 36 insertions(+), 24 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index dd49c9f..2af1e3b 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -36,12 +36,11 @@ struct exynos_thermal_zone {
bool bind;
};
-static struct exynos_thermal_zone *th_zone;
-
/* Get mode callback functions for thermal zone */
static int exynos_get_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode *mode)
{
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
if (th_zone)
*mode = th_zone->mode;
return 0;
@@ -51,25 +50,26 @@ static int exynos_get_mode(struct thermal_zone_device *thermal,
static int exynos_set_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode mode)
{
- if (!th_zone->therm_dev) {
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
+ if (!th_zone) {
pr_notice("thermal zone not registered\n");
return 0;
}
- mutex_lock(&th_zone->therm_dev->lock);
+ mutex_lock(&thermal->lock);
if (mode == THERMAL_DEVICE_ENABLED &&
!th_zone->sensor_conf->trip_data.trigger_falling)
- th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ thermal->polling_delay = IDLE_INTERVAL;
else
- th_zone->therm_dev->polling_delay = 0;
+ thermal->polling_delay = 0;
- mutex_unlock(&th_zone->therm_dev->lock);
+ mutex_unlock(&thermal->lock);
th_zone->mode = mode;
- thermal_zone_device_update(th_zone->therm_dev);
+ thermal_zone_device_update(thermal);
pr_info("thermal polling set for duration=%d msec\n",
- th_zone->therm_dev->polling_delay);
+ thermal->polling_delay);
return 0;
}
@@ -96,6 +96,8 @@ static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
unsigned long *temp)
{
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
+
if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
return -EINVAL;
@@ -122,6 +124,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
{
int ret = 0, i, tab_size, level;
struct freq_clip_table *tab_ptr, *clip_data;
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
struct thermal_sensor_conf *data = th_zone->sensor_conf;
tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
@@ -168,6 +171,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
int ret = 0, i, tab_size;
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
struct thermal_sensor_conf *data = th_zone->sensor_conf;
if (th_zone->bind == false)
@@ -210,6 +214,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
static int exynos_get_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
{
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
void *data;
if (!th_zone->sensor_conf) {
@@ -229,6 +234,7 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
{
void *data;
int ret = -EINVAL;
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
if (!th_zone->sensor_conf) {
pr_info("Temperature sensor not initialised\n");
@@ -276,11 +282,12 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
* This function may be called from interrupt based temperature sensor
* when threshold is changed.
*/
-void exynos_report_trigger(void)
+void exynos_report_trigger(struct thermal_sensor_conf *conf)
{
unsigned int i;
char data[10];
char *envp[] = { data, NULL };
+ struct exynos_thermal_zone *th_zone = conf->pzone_data;
if (!th_zone || !th_zone->therm_dev)
return;
@@ -321,6 +328,7 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
{
int ret;
struct cpumask mask_val;
+ struct exynos_thermal_zone *th_zone;
if (!sensor_conf || !sensor_conf->read_temperature) {
pr_err("Temperature sensor not initialised\n");
@@ -342,7 +350,7 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
th_zone->cool_dev_size++;
th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
- EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
+ EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
sensor_conf->trip_data.trigger_falling ?
0 : IDLE_INTERVAL);
@@ -352,20 +360,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
goto err_unregister;
}
th_zone->mode = THERMAL_DEVICE_ENABLED;
+ sensor_conf->pzone_data = th_zone;
pr_info("Exynos: Kernel Thermal management registered\n");
return 0;
err_unregister:
- exynos_unregister_thermal();
+ exynos_unregister_thermal(sensor_conf);
return ret;
}
/* Un-Register with the in-kernel thermal management */
-void exynos_unregister_thermal(void)
+void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
{
int i;
+ struct exynos_thermal_zone *th_zone = sensor_conf->pzone_data;
if (!th_zone)
return;
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index fd789a5..a845c2d 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -84,22 +84,23 @@ struct thermal_sensor_conf {
struct thermal_trip_point_conf trip_data;
struct thermal_cooling_conf cooling_data;
void *private_data;
+ void *pzone_data;
};
/*Functions used exynos based thermal sensor driver*/
#ifdef CONFIG_EXYNOS_THERMAL_CORE
-void exynos_unregister_thermal(void);
+void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
-void exynos_report_trigger(void);
+void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
#else
static inline void
-exynos_unregister_thermal(void) { return; }
+exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; }
static inline int
exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
static inline void
-exynos_report_trigger(void) { return; }
+exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; }
#endif /* CONFIG_EXYNOS_THERMAL_CORE */
#endif /* _EXYNOS_THERMAL_COMMON_H */
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index f6f63ca..a7bba69 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -345,6 +345,12 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
{ return -EINVAL; }
#endif/*CONFIG_THERMAL_EMULATION*/
+static struct thermal_sensor_conf exynos_sensor_conf = {
+ .name = "exynos-therm",
+ .read_temperature = (int (*)(void *))exynos_tmu_read,
+ .write_emul_temp = exynos_tmu_set_emulation,
+};
+
static void exynos_tmu_work(struct work_struct *work)
{
struct exynos_tmu_data *data = container_of(work,
@@ -353,7 +359,7 @@ static void exynos_tmu_work(struct work_struct *work)
const struct exynos_tmu_registers *reg = pdata->registers;
unsigned int val_irq;
- exynos_report_trigger();
+ exynos_report_trigger(&exynos_sensor_conf);
mutex_lock(&data->lock);
clk_enable(data->clk);
@@ -377,11 +383,6 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
return IRQ_HANDLED;
}
-static struct thermal_sensor_conf exynos_sensor_conf = {
- .name = "exynos-therm",
- .read_temperature = (int (*)(void *))exynos_tmu_read,
- .write_emul_temp = exynos_tmu_set_emulation,
-};
#ifdef CONFIG_OF
static const struct of_device_id exynos_tmu_match[] = {
@@ -541,7 +542,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
exynos_tmu_control(pdev, false);
- exynos_unregister_thermal();
+ exynos_unregister_thermal(&exynos_sensor_conf);
clk_unprepare(data->clk);
--
1.7.1
This patch uses the device pointer stored in the configuration structure
and converts to dev_* prints and devm API's.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 39 ++++++++++++++--------
1 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index 2873ca3..59b47e3 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -52,7 +52,8 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
{
struct exynos_thermal_zone *th_zone = thermal->devdata;
if (!th_zone) {
- pr_notice("thermal zone not registered\n");
+ dev_err(th_zone->sensor_conf->dev,
+ "thermal zone not registered\n");
return 0;
}
@@ -68,8 +69,9 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
th_zone->mode = mode;
thermal_zone_device_update(thermal);
- pr_info("thermal polling set for duration=%d msec\n",
- thermal->polling_delay);
+ dev_dbg(th_zone->sensor_conf->dev,
+ "thermal polling set for duration=%d msec\n",
+ thermal->polling_delay);
return 0;
}
@@ -159,7 +161,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
case WARN_ZONE:
if (thermal_zone_bind_cooling_device(thermal, i, cdev,
level, 0)) {
- pr_err("error binding cdev inst %d\n", i);
+ dev_err(data->dev,
+ "error unbinding cdev inst=%d\n", i);
ret = -EINVAL;
}
th_zone->bind = true;
@@ -204,7 +207,8 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
case WARN_ZONE:
if (thermal_zone_unbind_cooling_device(thermal, i,
cdev)) {
- pr_err("error unbinding cdev inst=%d\n", i);
+ dev_err(data->dev,
+ "error unbinding cdev inst=%d\n", i);
ret = -EINVAL;
}
th_zone->bind = false;
@@ -224,7 +228,8 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
void *data;
if (!th_zone->sensor_conf) {
- pr_info("Temperature sensor not initialised\n");
+ dev_err(th_zone->sensor_conf->dev,
+ "Temperature sensor not initialised\n");
return -EINVAL;
}
data = th_zone->sensor_conf->driver_data;
@@ -243,7 +248,8 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
struct exynos_thermal_zone *th_zone = thermal->devdata;
if (!th_zone->sensor_conf) {
- pr_info("Temperature sensor not initialised\n");
+ dev_err(th_zone->sensor_conf->dev,
+ "Temperature sensor not initialised\n");
return -EINVAL;
}
data = th_zone->sensor_conf->driver_data;
@@ -337,11 +343,13 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
struct exynos_thermal_zone *th_zone;
if (!sensor_conf || !sensor_conf->read_temperature) {
- pr_err("Temperature sensor not initialised\n");
+ dev_err(sensor_conf->dev,
+ "Temperature sensor not initialised\n");
return -EINVAL;
}
- th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
+ th_zone = devm_kzalloc(sensor_conf->dev,
+ sizeof(struct exynos_thermal_zone), GFP_KERNEL);
if (!th_zone)
return -ENOMEM;
@@ -350,7 +358,8 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
cpumask_set_cpu(0, &mask_val);
th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
if (IS_ERR(th_zone->cool_dev[0])) {
- pr_err("Failed to register cpufreq cooling device\n");
+ dev_err(sensor_conf->dev,
+ "Failed to register cpufreq cooling device\n");
ret = -EINVAL;
goto err_unregister;
}
@@ -364,14 +373,16 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
IDLE_INTERVAL);
if (IS_ERR(th_zone->therm_dev)) {
- pr_err("Failed to register thermal zone device\n");
+ dev_err(sensor_conf->dev,
+ "Failed to register thermal zone device\n");
ret = PTR_ERR(th_zone->therm_dev);
goto err_unregister;
}
th_zone->mode = THERMAL_DEVICE_ENABLED;
sensor_conf->pzone_data = th_zone;
- pr_info("Exynos: Kernel Thermal management registered\n");
+ dev_info(sensor_conf->dev,
+ "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
return 0;
@@ -397,6 +408,6 @@ void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
cpufreq_cooling_unregister(th_zone->cool_dev[i]);
}
- kfree(th_zone);
- pr_info("Exynos: Kernel Thermal management unregistered\n");
+ dev_info(sensor_conf->dev,
+ "Exynos: Kernel Thermal management unregistered\n");
}
--
1.7.1
From: Lukasz Majewski <[email protected]>
Proper description for Exynos4 bindings added to Documentation/devicetree/
bindings
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Kyungmin Park <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
.../devicetree/bindings/thermal/exynos-thermal.txt | 25 ++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/thermal/exynos-thermal.txt
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
new file mode 100644
index 0000000..535fd0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -0,0 +1,25 @@
+* Exynos Thermal Management Unit (TMU)
+
+** Required properties:
+
+- compatible : One of the following:
+ "samsung,exynos4412-tmu"
+ "samsung,exynos4210-tmu"
+ "samsung,exynos5250-tmu"
+- interrupt-parent : The phandle for the interrupt controller
+- reg : Address range of the thermal registers
+- interrupts : Should contain interrupt for thermal system
+- clocks : The main clock for TMU device
+- clock-names : Thermal system clock name
+
+Example:
+
+ tmu@100C0000 {
+ compatible = "samsung,exynos4412-tmu";
+ interrupt-parent = <&combiner>;
+ reg = <0x100C0000 0x100>;
+ interrupts = <2 4>;
+ clocks = <&clock 383>;
+ clock-names = "tmu_apbif";
+ status = "disabled";
+ };
--
1.7.1
This patch modifies TMU controller to add changes needed to work with
exynos5440 platform. This sensor registers 3 instance of the tmu controller
with the thermal zone and hence reports 3 temperature output. This controller
supports upto five trip points. For critical threshold the driver uses the
core driver thermal framework for shutdown.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Jungseok Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
.../devicetree/bindings/thermal/exynos-thermal.txt | 24 ++++++++-
drivers/thermal/samsung/exynos_thermal_common.h | 2 +-
drivers/thermal/samsung/exynos_tmu.c | 54 +++++++++++++++++---
drivers/thermal/samsung/exynos_tmu.h | 6 ++
drivers/thermal/samsung/exynos_tmu_data.h | 36 +++++++++++++
5 files changed, 112 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
index 0ea33f7..e6386ea 100644
--- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -6,6 +6,7 @@
"samsung,exynos4412-tmu"
"samsung,exynos4210-tmu"
"samsung,exynos5250-tmu"
+ "samsung,exynos5440-tmu"
- interrupt-parent : The phandle for the interrupt controller
- reg : Address range of the thermal registers. For soc's which has multiple
instances of TMU and some registers are shared across all TMU's like
@@ -16,7 +17,7 @@
- clocks : The main clock for TMU device
- clock-names : Thermal system clock name
-Example:
+Example 1):
tmu@100C0000 {
compatible = "samsung,exynos4412-tmu";
@@ -27,3 +28,24 @@ Example:
clock-names = "tmu_apbif";
status = "disabled";
};
+
+Example 2):
+
+ tmuctrl_0: tmuctrl@160118 {
+ compatible = "samsung,exynos5440-tmu";
+ reg = <0x160118 0x230>, <0x160368 0x10>;
+ interrupts = <0 58 0>;
+ clocks = <&clock 21>;
+ clock-names = "tmu_apbif";
+ };
+
+Note: For multi-instance tmu each instance should have an alias correctly
+numbered in "aliases" node.
+
+Example:
+
+aliases {
+ tmuctrl0 = &tmuctrl_0;
+ tmuctrl1 = &tmuctrl_1;
+ tmuctrl2 = &tmuctrl_2;
+};
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index 0c189d6..7d7c29a 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -27,7 +27,7 @@
#define SENSOR_NAME_LEN 16
#define MAX_TRIP_COUNT 8
#define MAX_COOLING_DEVICE 4
-#define MAX_THRESHOLD_LEVS 4
+#define MAX_THRESHOLD_LEVS 5
#define ACTIVE_INTERVAL 500
#define IDLE_INTERVAL 10000
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 150a869..db4035d 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -156,7 +156,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
__raw_writel(1, data->base + reg->triminfo_ctrl);
/* Save trimming info in order to perform calibration */
- trim_info = readl(data->base + reg->triminfo_data);
+ if (data->soc == SOC_ARCH_EXYNOS5440) {
+ /*
+ * For exynos5440 soc triminfo value is swapped between TMU0 and
+ * TMU2, so the below logic is needed.
+ */
+ switch (data->id) {
+ case 0:
+ trim_info = readl(data->base +
+ EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
+ break;
+ case 1:
+ trim_info = readl(data->base + reg->triminfo_data);
+ break;
+ case 2:
+ trim_info = readl(data->base -
+ EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
+ }
+ } else {
+ trim_info = readl(data->base + reg->triminfo_data);
+ }
data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
EXYNOS_TMU_TEMP_MASK);
@@ -201,7 +220,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
reg->threshold_th0 + i * sizeof(reg->threshold_th0));
writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
- } else if (data->soc == SOC_ARCH_EXYNOS) {
+ } else if (data->soc == SOC_ARCH_EXYNOS ||
+ data->soc == SOC_ARCH_EXYNOS5440) {
/* Write temperature code for rising and falling threshold */
for (i = 0;
i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
@@ -241,14 +261,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
ret = threshold_code;
goto out;
}
- rising_threshold |= threshold_code << 8 * i;
- writel(rising_threshold,
- data->base + reg->threshold_th0);
+ if (data->soc == SOC_ARCH_EXYNOS) {
+ rising_threshold |= threshold_code << 8 * i;
+ writel(rising_threshold,
+ data->base + reg->threshold_th0);
+ } else if (data->soc == SOC_ARCH_EXYNOS5440) {
+ rising_threshold =
+ threshold_code << reg->threshold_th3_l0_shift;
+ writel(rising_threshold,
+ data->base + reg->threshold_th2);
+ }
con = readl(data->base + reg->tmu_ctrl);
con |= (1 << reg->therm_trip_en_shift);
writel(con, data->base + reg->tmu_ctrl);
}
}
+ /*Clear the PMIN in the common TMU register*/
+ if (reg->tmu_pmin && !data->id)
+ writel(0, data->base_common + reg->tmu_pmin);
out:
clk_disable(data->clk);
mutex_unlock(&data->lock);
@@ -377,7 +407,14 @@ static void exynos_tmu_work(struct work_struct *work)
struct exynos_tmu_data, irq_work);
struct exynos_tmu_platform_data *pdata = data->pdata;
const struct exynos_tmu_registers *reg = pdata->registers;
- unsigned int val_irq;
+ unsigned int val_irq, val_type;
+
+ /* Find which sensor generated this interrupt */
+ if (reg->tmu_irqstatus) {
+ val_type = readl(data->base_common + reg->tmu_irqstatus);
+ if (!((val_type >> data->id) & 0x1))
+ goto out;
+ }
exynos_report_trigger(data->reg_conf);
mutex_lock(&data->lock);
@@ -390,7 +427,7 @@ static void exynos_tmu_work(struct work_struct *work)
clk_disable(data->clk);
mutex_unlock(&data->lock);
-
+out:
enable_irq(data->irq);
}
@@ -544,7 +581,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
return ret;
if (pdata->type == SOC_ARCH_EXYNOS ||
- pdata->type == SOC_ARCH_EXYNOS4210)
+ pdata->type == SOC_ARCH_EXYNOS4210 ||
+ pdata->type == SOC_ARCH_EXYNOS5440)
data->soc = pdata->type;
else {
ret = -EINVAL;
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 6f55673..73aaed7 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -38,6 +38,7 @@ enum calibration_mode {
enum soc_type {
SOC_ARCH_EXYNOS4210 = 1,
SOC_ARCH_EXYNOS,
+ SOC_ARCH_EXYNOS5440,
};
/**
@@ -129,6 +130,8 @@ enum soc_type {
* @emul_temp_shift: shift bits of emulation temperature.
* @emul_time_shift: shift bits of emulation time.
* @emul_time_mask: mask bits of emulation time.
+ * @tmu_irqstatus: register to find which TMU generated interrupts.
+ * @tmu_pmin: register to get/set the Pmin value.
*/
struct exynos_tmu_registers {
u32 triminfo_data;
@@ -196,6 +199,9 @@ struct exynos_tmu_registers {
u32 emul_temp_shift;
u32 emul_time_shift;
u32 emul_time_mask;
+
+ u32 tmu_irqstatus;
+ u32 tmu_pmin;
};
/**
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index 139dbbb..ad263e9 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -93,6 +93,42 @@
#define EXYNOS_MAX_TRIGGER_PER_REG 4
+/*exynos5440 specific registers*/
+#define EXYNOS5440_TMU_S0_7_TRIM 0x000
+#define EXYNOS5440_TMU_S0_7_CTRL 0x020
+#define EXYNOS5440_TMU_S0_7_DEBUG 0x040
+#define EXYNOS5440_TMU_S0_7_STATUS 0x060
+#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0
+#define EXYNOS5440_TMU_S0_7_TH0 0x110
+#define EXYNOS5440_TMU_S0_7_TH1 0x130
+#define EXYNOS5440_TMU_S0_7_TH2 0x150
+#define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0
+#define EXYNOS5440_TMU_S0_7_IRQEN 0x210
+#define EXYNOS5440_TMU_S0_7_IRQ 0x230
+/* exynos5440 common registers */
+#define EXYNOS5440_TMU_IRQ_STATUS 0x000
+#define EXYNOS5440_TMU_PMIN 0x004
+#define EXYNOS5440_TMU_TEMP 0x008
+
+#define EXYNOS5440_TMU_RISE_INT_MASK 0xf
+#define EXYNOS5440_TMU_RISE_INT_SHIFT 0
+#define EXYNOS5440_TMU_FALL_INT_MASK 0xf
+#define EXYNOS5440_TMU_FALL_INT_SHIFT 4
+#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0
+#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1
+#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2
+#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3
+#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4
+#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5
+#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6
+#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7
+#define EXYNOS5440_TMU_TH_RISE0_SHIFT 0
+#define EXYNOS5440_TMU_TH_RISE1_SHIFT 8
+#define EXYNOS5440_TMU_TH_RISE2_SHIFT 16
+#define EXYNOS5440_TMU_TH_RISE3_SHIFT 24
+#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
+#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
+
#if defined(CONFIG_CPU_EXYNOS4210)
extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
--
1.7.1
This patch adds configuration data for exynos5440 soc. Also register
definations for the controller are added.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 4 ++
drivers/thermal/samsung/exynos_tmu_data.c | 71 +++++++++++++++++++++++++++++
drivers/thermal/samsung/exynos_tmu_data.h | 7 +++
3 files changed, 82 insertions(+), 0 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index db4035d..a4dbc84 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -455,6 +455,10 @@ static const struct of_device_id exynos_tmu_match[] = {
.compatible = "samsung,exynos5250-tmu",
.data = (void *)EXYNOS5250_TMU_DRV_DATA,
},
+ {
+ .compatible = "samsung,exynos5440-tmu",
+ .data = (void *)EXYNOS5440_TMU_DRV_DATA,
+ },
{},
};
MODULE_DEVICE_TABLE(of, exynos_tmu_match);
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index 694557e..b34e726 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -175,3 +175,74 @@ struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
.tmu_count = 1,
};
#endif
+
+#if defined(CONFIG_SOC_EXYNOS5440)
+static const struct exynos_tmu_registers exynos5440_tmu_registers = {
+ .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
+ .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+ .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+ .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
+ .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+ .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+ .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
+ .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
+ .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
+ .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+ .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+ .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+ .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
+ .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
+ .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
+ .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
+ .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
+ .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
+ .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
+ .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
+ .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
+ .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
+ .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
+ .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
+ .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
+ .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
+ .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
+ .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
+ .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
+ .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
+ .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
+ .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
+ .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
+ .tmu_pmin = EXYNOS5440_TMU_PMIN,
+};
+
+#define EXYNOS5440_TMU_DATA \
+ .trigger_levels[0] = 100, \
+ .trigger_levels[4] = 105, \
+ .trigger_enable[0] = 1, \
+ .trigger_type[0] = SW_TRIP, \
+ .trigger_type[4] = HW_TRIP, \
+ .max_trigger_level = 5, \
+ .gain = 5, \
+ .reference_voltage = 16, \
+ .noise_cancel_mode = 4, \
+ .cal_type = TYPE_ONE_POINT_TRIMMING, \
+ .cal_mode = 0, \
+ .efuse_value = 0x5b2d, \
+ .min_efuse_value = 16, \
+ .max_efuse_value = 76, \
+ .first_point_trim = 25, \
+ .second_point_trim = 70, \
+ .default_temp_offset = 25, \
+ .type = SOC_ARCH_EXYNOS5440, \
+ .registers = &exynos5440_tmu_registers, \
+ .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
+ TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
+
+struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
+ .tmu_data = {
+ { EXYNOS5440_TMU_DATA } ,
+ { EXYNOS5440_TMU_DATA } ,
+ { EXYNOS5440_TMU_DATA } ,
+ },
+ .tmu_count = 3,
+};
+#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index ad263e9..43ce5fb 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -143,4 +143,11 @@ extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
#define EXYNOS5250_TMU_DRV_DATA (NULL)
#endif
+#if defined(CONFIG_SOC_EXYNOS5440)
+extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
+#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
+#else
+#define EXYNOS5440_TMU_DRV_DATA (NULL)
+#endif
+
#endif /*_EXYNOS_TMU_DATA_H*/
--
1.7.1
TMU probe function now checks for a device tree defined regulator.
For compatibility reasons it is allowed to probe driver even without
this regulator defined.
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Lukasz Majewski <[email protected]>
Signed-off-by: Kyungmin Park <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
.../devicetree/bindings/thermal/exynos-thermal.txt | 4 +++
drivers/thermal/samsung/exynos_tmu.c | 23 ++++++++++++++++++++
2 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
index e6386ea..284f530 100644
--- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -16,6 +16,9 @@
- interrupts : Should contain interrupt for thermal system
- clocks : The main clock for TMU device
- clock-names : Thermal system clock name
+- vtmu-supply: This entry is optional and provides the regulator node supplying
+ voltage to TMU. If needed this entry can be placed inside
+ board/platform specific dts file.
Example 1):
@@ -27,6 +30,7 @@ Example 1):
clocks = <&clock 383>;
clock-names = "tmu_apbif";
status = "disabled";
+ vtmu-supply = <&tmu_regulator_node>;
};
Example 2):
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 7a259f4..441efd5 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -29,6 +29,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include "exynos_thermal_common.h"
#include "exynos_tmu.h"
@@ -48,6 +49,7 @@
* @clk: pointer to the clock structure.
* @temp_error1: fused value of the first point trim.
* @temp_error2: fused value of the second point trim.
+ * @regulator: pointer to the TMU regulator structure.
* @reg_conf: pointer to structure to register with core thermal.
*/
struct exynos_tmu_data {
@@ -61,6 +63,7 @@ struct exynos_tmu_data {
struct mutex lock;
struct clk *clk;
u8 temp_error1, temp_error2;
+ struct regulator *regulator;
struct thermal_sensor_conf *reg_conf;
};
@@ -510,10 +513,27 @@ static int exynos_map_dt_data(struct platform_device *pdev)
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata;
struct resource res;
+ int ret;
if (!data)
return -ENODEV;
+ /*
+ * Try enabling the regulator if found
+ * TODO: Add regulator as an SOC feature, so that regulator enable
+ * is a compulsory call.
+ */
+ data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
+ if (!IS_ERR(data->regulator)) {
+ ret = regulator_enable(data->regulator);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable vtmu\n");
+ return ret;
+ }
+ } else {
+ dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
+ }
+
data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
if (data->id < 0)
data->id = 0;
@@ -680,6 +700,9 @@ static int exynos_tmu_remove(struct platform_device *pdev)
clk_unprepare(data->clk);
+ if (!IS_ERR(data->regulator))
+ regulator_disable(data->regulator);
+
return 0;
}
--
1.7.1
This patch adds device node for TMU controller. There are 3
instances of the controllers so 3 nodes are created.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
arch/arm/boot/dts/exynos5440.dtsi | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index f6b1c89..716e90c 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -16,6 +16,12 @@
interrupt-parent = <&gic>;
+ aliases {
+ tmuctrl0 = &tmuctrl_0;
+ tmuctrl1 = &tmuctrl_1;
+ tmuctrl2 = &tmuctrl_2;
+ };
+
clock: clock-controller@0x160000 {
compatible = "samsung,exynos5440-clock";
reg = <0x160000 0x1000>;
@@ -216,4 +222,28 @@
clock-names = "rtc";
status = "disabled";
};
+
+ tmuctrl_0: tmuctrl@160118 {
+ compatible = "samsung,exynos5440-tmu";
+ reg = <0x160118 0x230>, <0x160368 0x10>;
+ interrupts = <0 58 0>;
+ clocks = <&clock 21>;
+ clock-names = "tmu_apbif";
+ };
+
+ tmuctrl_1: tmuctrl@16011C {
+ compatible = "samsung,exynos5440-tmu";
+ reg = <0x16011C 0x230>, <0x160368 0x10>;
+ interrupts = <0 58 0>;
+ clocks = <&clock 21>;
+ clock-names = "tmu_apbif";
+ };
+
+ tmuctrl_2: tmuctrl@160120 {
+ compatible = "samsung,exynos5440-tmu";
+ reg = <0x160120 0x230>, <0x160368 0x10>;
+ interrupts = <0 58 0>;
+ clocks = <&clock 21>;
+ clock-names = "tmu_apbif";
+ };
};
--
1.7.1
This patch enables ARCH_HAS_BANDGAP config for exynos4210, 4212, 4412, 5250
and 5440 SOC. This config symbol is recently added to allow the platforms
to enable bandgap based temperature sensor.
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
arch/arm/mach-exynos/Kconfig | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index d19edff..d3cb5c7 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -33,6 +33,7 @@ config CPU_EXYNOS4210
bool "SAMSUNG EXYNOS4210"
default y
depends on ARCH_EXYNOS4
+ select ARCH_HAS_BANDGAP
select ARM_CPU_SUSPEND if PM
select PM_GENERIC_DOMAINS
select S5P_PM if PM
@@ -45,6 +46,7 @@ config SOC_EXYNOS4212
bool "SAMSUNG EXYNOS4212"
default y
depends on ARCH_EXYNOS4
+ select ARCH_HAS_BANDGAP
select S5P_PM if PM
select S5P_SLEEP if PM
select SAMSUNG_DMADEV
@@ -55,6 +57,7 @@ config SOC_EXYNOS4412
bool "SAMSUNG EXYNOS4412"
default y
depends on ARCH_EXYNOS4
+ select ARCH_HAS_BANDGAP
select SAMSUNG_DMADEV
help
Enable EXYNOS4412 SoC support
@@ -63,6 +66,7 @@ config SOC_EXYNOS5250
bool "SAMSUNG EXYNOS5250"
default y
depends on ARCH_EXYNOS5
+ select ARCH_HAS_BANDGAP
select PM_GENERIC_DOMAINS if PM
select S5P_PM if PM
select S5P_SLEEP if PM
@@ -76,6 +80,7 @@ config SOC_EXYNOS5440
default y
depends on ARCH_EXYNOS5
select ARCH_HAS_OPP
+ select ARCH_HAS_BANDGAP
select ARM_ARCH_TIMER
select AUTO_ZRELADDR
select PINCTRL
--
1.7.1
This patch updates the documentation to explain the driver model
and file layout.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
Documentation/thermal/exynos_thermal | 43 ++++++++++++++++++++++++++-------
1 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/Documentation/thermal/exynos_thermal b/Documentation/thermal/exynos_thermal
index 2b46f67..9010c44 100644
--- a/Documentation/thermal/exynos_thermal
+++ b/Documentation/thermal/exynos_thermal
@@ -1,17 +1,17 @@
-Kernel driver exynos4_tmu
+Kernel driver exynos_tmu
=================
Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
- Prefix: 'exynos4-tmu'
+* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
Datasheet: Not publicly available
Authors: Donggeun Kim <[email protected]>
+Authors: Amit Daniel <[email protected]>
-Description
------------
+TMU controller Description:
+---------------------------
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
The chip only exposes the measured 8-bit temperature code value
through a register.
@@ -34,9 +34,9 @@ The three equations are:
TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
Temperature code measured at 85 degree Celsius which is unchanged
-TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
+TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
+The maximum number of configurable threshold is five.
The threshold levels are defined as follows:
Level_0: current temperature > trigger_level_0 + threshold
Level_1: current temperature > trigger_level_1 + threshold
@@ -47,6 +47,31 @@ The threshold levels are defined as follows:
through the corresponding registers.
When an interrupt occurs, this driver notify kernel thermal framework
-with the function exynos4_report_trigger.
+with the function exynos_report_trigger.
Although an interrupt condition for level_0 can be set,
it can be used to synchronize the cooling action.
+
+TMU driver description:
+-----------------------
+
+The exynos thermal driver is structured as,
+
+ Kernel Core thermal framework
+ (thermal_core.c, step_wise.c, cpu_cooling.c)
+ ^
+ |
+ |
+TMU configuration data -------> TMU Driver <------> Exynos Core thermal wrapper
+(exynos_tmu_data.c) (exynos_tmu.c) (exynos_thermal_common.c)
+(exynos_tmu_data.h) (exynos_tmu.h) (exynos_thermal_common.h)
+
+a) TMU configuration data: This consist of TMU register offsets/bitfields
+ described through structure exynos_tmu_registers. Also several
+ other platform data (struct exynos_tmu_platform_data) members
+ are used to configure the TMU.
+b) TMU driver: This component initialises the TMU controller and sets different
+ thresholds. It invokes core thermal implementation with the call
+ exynos_report_trigger.
+c) Exynos Core thermal wrapper: This provides 3 wrapper function to use the
+ Kernel core thermal framework. They are exynos_unregister_thermal,
+ exynos_register_thermal and exynos_report_trigger.
--
1.7.1
This patch adds support for h/w mode calibration in the TMU controller.
soc's like 5440 support this features.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 15 +++++++++++++++
drivers/thermal/samsung/exynos_tmu.h | 6 ++++++
drivers/thermal/samsung/exynos_tmu_data.c | 2 ++
drivers/thermal/samsung/exynos_tmu_data.h | 2 ++
4 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index af0e6ca..7a259f4 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -73,6 +73,9 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
struct exynos_tmu_platform_data *pdata = data->pdata;
int temp_code;
+ if (pdata->cal_mode == HW_MODE)
+ return temp;
+
if (data->soc == SOC_ARCH_EXYNOS4210)
/* temp should range between 25 and 125 */
if (temp < 25 || temp > 125) {
@@ -107,6 +110,9 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
struct exynos_tmu_platform_data *pdata = data->pdata;
int temp;
+ if (pdata->cal_mode == HW_MODE)
+ return temp_code;
+
if (data->soc == SOC_ARCH_EXYNOS4210)
/* temp_code should range between 75 and 175 */
if (temp_code < 75 || temp_code > 175) {
@@ -155,6 +161,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
__raw_writel(1, data->base + reg->triminfo_ctrl);
+ if (pdata->cal_mode == HW_MODE)
+ goto skip_calib_data;
+
/* Save trimming info in order to perform calibration */
if (data->soc == SOC_ARCH_EXYNOS5440) {
/*
@@ -190,6 +199,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
(pdata->efuse_value >> reg->triminfo_85_shift) &
EXYNOS_TMU_TEMP_MASK;
+skip_calib_data:
if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
dev_err(&pdev->dev, "Invalid max trigger level\n");
goto out;
@@ -319,6 +329,11 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
}
+ if (pdata->cal_mode == HW_MODE) {
+ con &= ~(reg->calib_mode_mask << reg->calib_mode_shift);
+ con |= pdata->cal_type << reg->calib_mode_shift;
+ }
+
if (on) {
con |= (1 << reg->core_en_shift);
interrupt_en =
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 73aaed7..abfa1eb 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -88,6 +88,10 @@ enum soc_type {
* @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
register.
* @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
+ * @calib_mode_shift: shift bits of calibration mode value in tmu_ctrl
+ register.
+ * @calib_mode_mask: mask bits of calibration mode value in tmu_ctrl
+ register.
* @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
tmu_ctrl register.
* @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
@@ -149,6 +153,8 @@ struct exynos_tmu_registers {
u32 therm_trip_en_shift;
u32 buf_slope_sel_shift;
u32 buf_slope_sel_mask;
+ u32 calib_mode_shift;
+ u32 calib_mode_mask;
u32 therm_trip_tq_en_shift;
u32 core_en_shift;
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index b34e726..47c5d6b 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -189,6 +189,8 @@ static const struct exynos_tmu_registers exynos5440_tmu_registers = {
.therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
.buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
.buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+ .calib_mode_shift = EXYNOS_TMU_CALIB_MODE_SHIFT,
+ .calib_mode_mask = EXYNOS_TMU_CALIB_MODE_MASK,
.core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
.tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
.tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index 43ce5fb..dc7feb5 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -75,6 +75,8 @@
#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
#define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
+#define EXYNOS_TMU_CALIB_MODE_SHIFT 4
+#define EXYNOS_TMU_CALIB_MODE_MASK 0x3
#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
--
1.7.1
This patch sets the second point trimming value according to the platform
data if the register value is 0.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index a4dbc84..af0e6ca 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -180,10 +180,15 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
EXYNOS_TMU_TEMP_MASK);
- if ((pdata->min_efuse_value > data->temp_error1) ||
- (data->temp_error1 > pdata->max_efuse_value) ||
- (data->temp_error2 != 0))
- data->temp_error1 = pdata->efuse_value;
+ if (!data->temp_error1 ||
+ (pdata->min_efuse_value > data->temp_error1) ||
+ (data->temp_error1 > pdata->max_efuse_value))
+ data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
+
+ if (!data->temp_error2)
+ data->temp_error2 =
+ (pdata->efuse_value >> reg->triminfo_85_shift) &
+ EXYNOS_TMU_TEMP_MASK;
if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
dev_err(&pdev->dev, "Invalid max trigger level\n");
--
1.7.1
This patch adds support to parse one more common set of TMU register. First
set of register belongs to each instance of TMU and second set belongs to
common TMU registers.
Acked-by: Jonghwa Lee <[email protected]>
Acked-by: Kukjin Kim <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
.../devicetree/bindings/thermal/exynos-thermal.txt | 6 +++++-
drivers/thermal/samsung/exynos_tmu.c | 20 ++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
index 535fd0e..0ea33f7 100644
--- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -7,7 +7,11 @@
"samsung,exynos4210-tmu"
"samsung,exynos5250-tmu"
- interrupt-parent : The phandle for the interrupt controller
-- reg : Address range of the thermal registers
+- reg : Address range of the thermal registers. For soc's which has multiple
+ instances of TMU and some registers are shared across all TMU's like
+ interrupt related then 2 set of register has to supplied. First set
+ belongs to each instance of TMU and second set belongs to common TMU
+ registers.
- interrupts : Should contain interrupt for thermal system
- clocks : The main clock for TMU device
- clock-names : Thermal system clock name
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 877dab8..150a869 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -40,6 +40,7 @@
* @id: identifier of the one instance of the TMU controller.
* @pdata: pointer to the tmu platform/configuration data
* @base: base address of the single instance of the TMU controller.
+ * @base_common: base address of the common registers of the TMU controller.
* @irq: irq number of the TMU controller.
* @soc: id of the SOC type.
* @irq_work: pointer to the irq work structure.
@@ -53,6 +54,7 @@ struct exynos_tmu_data {
int id;
struct exynos_tmu_platform_data *pdata;
void __iomem *base;
+ void __iomem *base_common;
int irq;
enum soc_type soc;
struct work_struct irq_work;
@@ -478,6 +480,24 @@ static int exynos_map_dt_data(struct platform_device *pdev)
return -ENODEV;
}
data->pdata = pdata;
+ /*
+ * Check if the TMU shares some registers and then try to map the
+ * memory of common registers.
+ */
+ if (!TMU_SUPPORTS(pdata, SHARED_MEMORY))
+ return 0;
+
+ if (of_address_to_resource(pdev->dev.of_node, 1, &res)) {
+ dev_err(&pdev->dev, "failed to get Resource 1\n");
+ return -ENODEV;
+ }
+
+ data->base_common = devm_ioremap(&pdev->dev, res.start,
+ resource_size(&res));
+ if (!data->base) {
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ return -ENOMEM;
+ }
return 0;
}
--
1.7.1
This patch adds several features supported by TMU as bitfields.
This features varies across different SOC type and comparing
the features present in the TMU is more logical than comparing
the soc itself.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 26 +++++++++++++++---------
drivers/thermal/samsung/exynos_tmu.h | 31 +++++++++++++++++++++++++++++
drivers/thermal/samsung/exynos_tmu_data.c | 6 ++++-
3 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 1880c4e..877dab8 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -142,13 +142,15 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
mutex_lock(&data->lock);
clk_enable(data->clk);
- status = readb(data->base + reg->tmu_status);
- if (!status) {
- ret = -EBUSY;
- goto out;
+ if (TMU_SUPPORTS(pdata, READY_STATUS)) {
+ status = readb(data->base + reg->tmu_status);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
}
- if (data->soc == SOC_ARCH_EXYNOS)
+ if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
__raw_writel(1, data->base + reg->triminfo_ctrl);
/* Save trimming info in order to perform calibration */
@@ -287,7 +289,7 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
pdata->trigger_enable[2] << reg->inten_rise2_shift |
pdata->trigger_enable[1] << reg->inten_rise1_shift |
pdata->trigger_enable[0] << reg->inten_rise0_shift;
- if (pdata->threshold_falling)
+ if (TMU_SUPPORTS(pdata, FALLING_TRIP))
interrupt_en |=
interrupt_en << reg->inten_fall0_shift;
} else {
@@ -329,7 +331,7 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
unsigned int val;
int ret = -EINVAL;
- if (data->soc == SOC_ARCH_EXYNOS4210)
+ if (!TMU_SUPPORTS(pdata, EMULATION))
goto out;
if (temp && temp < MCELSIUS)
@@ -343,9 +345,13 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
if (temp) {
temp /= MCELSIUS;
- val = (EXYNOS_EMUL_TIME << reg->emul_time_shift) |
- (temp_to_code(data, temp)
- << reg->emul_temp_shift) | EXYNOS_EMUL_ENABLE;
+ if (TMU_SUPPORTS(pdata, EMUL_TIME)) {
+ val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift);
+ val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift);
+ }
+ val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift);
+ val |= (temp_to_code(data, temp) << reg->emul_temp_shift) |
+ EXYNOS_EMUL_ENABLE;
} else {
val &= ~EXYNOS_EMUL_ENABLE;
}
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index b614407..6f55673 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -41,6 +41,34 @@ enum soc_type {
};
/**
+ * EXYNOS TMU supported features.
+ * TMU_SUPPORT_EMULATION - This features is used to set user defined
+ * temperature to the TMU controller.
+ * TMU_SUPPORT_MULTI_INST - This features denotes that the soc
+ * has many instances of TMU.
+ * TMU_SUPPORT_TRIM_RELOAD - This features shows that trimming can
+ * be reloaded.
+ * TMU_SUPPORT_FALLING_TRIP - This features shows that interrupt can
+ * be registered for falling trips also.
+ * TMU_SUPPORT_READY_STATUS - This feature tells that the TMU current
+ * state(active/idle) can be checked.
+ * TMU_SUPPORT_EMUL_TIME - This features allows to set next temp emulation
+ * sample time.
+ * TMU_SUPPORT_SHARED_MEMORY - This feature tells that the different TMU
+ * sensors shares some common registers.
+ * TMU_SUPPORT - macro to compare the above features with the supplied.
+ */
+#define TMU_SUPPORT_EMULATION BIT(0)
+#define TMU_SUPPORT_MULTI_INST BIT(1)
+#define TMU_SUPPORT_TRIM_RELOAD BIT(2)
+#define TMU_SUPPORT_FALLING_TRIP BIT(3)
+#define TMU_SUPPORT_READY_STATUS BIT(4)
+#define TMU_SUPPORT_EMUL_TIME BIT(5)
+#define TMU_SUPPORT_SHARED_MEMORY BIT(6)
+
+#define TMU_SUPPORTS(a, b) (a->features & TMU_SUPPORT_ ## b)
+
+/**
* struct exynos_tmu_register - register descriptors to access registers and
* bitfields. The register validity, offsets and bitfield values may vary
* slightly across different exynos SOC's.
@@ -220,6 +248,8 @@ struct exynos_tmu_registers {
* applicable to only some of the trigger levels.
* @registers: Pointer to structure containing all the TMU controller registers
* and bitfields shifts and masks.
+ * @features: a bitfield value indicating the features supported in SOC like
+ * emulation, multi instance etc
*
* This structure is required for configuration of exynos_tmu driver.
*/
@@ -247,6 +277,7 @@ struct exynos_tmu_platform_data {
struct freq_clip_table freq_tab[4];
unsigned int freq_tab_count;
const struct exynos_tmu_registers *registers;
+ unsigned int features;
};
/**
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index 06ecfb0..694557e 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -83,6 +83,7 @@ struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
.freq_tab_count = 2,
.type = SOC_ARCH_EXYNOS4210,
.registers = &exynos4210_tmu_registers,
+ .features = TMU_SUPPORT_READY_STATUS,
},
},
.tmu_count = 1,
@@ -162,7 +163,10 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
}, \
.freq_tab_count = 2, \
.type = SOC_ARCH_EXYNOS, \
- .registers = &exynos5250_tmu_registers,
+ .registers = &exynos5250_tmu_registers, \
+ .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \
+ TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
+ TMU_SUPPORT_EMUL_TIME)
struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
.tmu_data = {
--
1.7.1
This patch adds support to handle multiple instances of the TMU controllers.
This is done by removing the static structure to register with the core thermal
and creating it dynamically for each instance of the TMU controller. The
interrupt is made shared type to handle shared interrupts. Also
the identifier of the TMU controller is extracted from device tree alias.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.h | 1 +
drivers/thermal/samsung/exynos_tmu.c | 147 ++++++++++++++++-------
drivers/thermal/samsung/exynos_tmu.h | 13 ++
drivers/thermal/samsung/exynos_tmu_data.c | 145 ++++++++++++----------
drivers/thermal/samsung/exynos_tmu_data.h | 4 +-
5 files changed, 197 insertions(+), 113 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index dd0077e..0c189d6 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -84,6 +84,7 @@ struct thermal_sensor_conf {
struct thermal_cooling_conf cooling_data;
void *driver_data;
void *pzone_data;
+ struct device *dev;
};
/*Functions used exynos based thermal sensor driver*/
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 4356118..1880c4e 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -26,15 +26,32 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include "exynos_thermal_common.h"
#include "exynos_tmu.h"
#include "exynos_tmu_data.h"
+/**
+ * struct exynos_tmu_data : A structure to hold the private data of the TMU
+ driver
+ * @id: identifier of the one instance of the TMU controller.
+ * @pdata: pointer to the tmu platform/configuration data
+ * @base: base address of the single instance of the TMU controller.
+ * @irq: irq number of the TMU controller.
+ * @soc: id of the SOC type.
+ * @irq_work: pointer to the irq work structure.
+ * @lock: lock to implement synchronization.
+ * @clk: pointer to the clock structure.
+ * @temp_error1: fused value of the first point trim.
+ * @temp_error2: fused value of the second point trim.
+ * @reg_conf: pointer to structure to register with core thermal.
+ */
struct exynos_tmu_data {
+ int id;
struct exynos_tmu_platform_data *pdata;
- struct resource *mem;
void __iomem *base;
int irq;
enum soc_type soc;
@@ -42,6 +59,7 @@ struct exynos_tmu_data {
struct mutex lock;
struct clk *clk;
u8 temp_error1, temp_error2;
+ struct thermal_sensor_conf *reg_conf;
};
/*
@@ -345,12 +363,6 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
{ return -EINVAL; }
#endif/*CONFIG_THERMAL_EMULATION*/
-static struct thermal_sensor_conf exynos_sensor_conf = {
- .name = "exynos-therm",
- .read_temperature = (int (*)(void *))exynos_tmu_read,
- .write_emul_temp = exynos_tmu_set_emulation,
-};
-
static void exynos_tmu_work(struct work_struct *work)
{
struct exynos_tmu_data *data = container_of(work,
@@ -359,7 +371,7 @@ static void exynos_tmu_work(struct work_struct *work)
const struct exynos_tmu_registers *reg = pdata->registers;
unsigned int val_irq;
- exynos_report_trigger(&exynos_sensor_conf);
+ exynos_report_trigger(data->reg_conf);
mutex_lock(&data->lock);
clk_enable(data->clk);
@@ -404,33 +416,73 @@ MODULE_DEVICE_TABLE(of, exynos_tmu_match);
#endif
static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
- struct platform_device *pdev)
+ struct platform_device *pdev, int id)
{
+ struct exynos_tmu_init_data *data_table;
+ struct exynos_tmu_platform_data *tmu_data;
#ifdef CONFIG_OF
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
if (!match)
return NULL;
- return (struct exynos_tmu_platform_data *) match->data;
+ data_table = (struct exynos_tmu_init_data *) match->data;
+ if (!data_table || id >= data_table->tmu_count)
+ return NULL;
+ tmu_data = data_table->tmu_data;
+ return (struct exynos_tmu_platform_data *) (tmu_data + id);
}
#endif
return NULL;
}
-static int exynos_tmu_probe(struct platform_device *pdev)
+static int exynos_map_dt_data(struct platform_device *pdev)
{
- struct exynos_tmu_data *data;
- struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret, i;
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos_tmu_platform_data *pdata;
+ struct resource res;
- if (!pdata)
- pdata = exynos_get_driver_data(pdev);
+ if (!data)
+ return -ENODEV;
+
+ data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
+ if (data->id < 0)
+ data->id = 0;
+ data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (data->irq <= 0) {
+ dev_err(&pdev->dev, "failed to get IRQ\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
+ dev_err(&pdev->dev, "failed to get Resource 0\n");
+ return -ENODEV;
+ }
+
+ data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
+ if (!data->base) {
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ pdata = exynos_get_driver_data(pdev, data->id);
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV;
}
+ data->pdata = pdata;
+
+ return 0;
+}
+
+static int exynos_tmu_probe(struct platform_device *pdev)
+{
+ struct exynos_tmu_data *data;
+ struct exynos_tmu_platform_data *pdata;
+ struct thermal_sensor_conf *sensor_conf;
+ int ret, i;
+
data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
GFP_KERNEL);
if (!data) {
@@ -438,21 +490,18 @@ static int exynos_tmu_probe(struct platform_device *pdev)
return -ENOMEM;
}
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0) {
- dev_err(&pdev->dev, "Failed to get platform irq\n");
- return data->irq;
- }
+ platform_set_drvdata(pdev, data);
+ mutex_init(&data->lock);
- INIT_WORK(&data->irq_work, exynos_tmu_work);
+ ret = exynos_map_dt_data(pdev);
+ if (ret)
+ return ret;
- data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(&pdev->dev, data->mem);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
+ pdata = data->pdata;
+ INIT_WORK(&data->irq_work, exynos_tmu_work);
ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
- IRQF_TRIGGER_RISING, "exynos-tmu", data);
+ IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
return ret;
@@ -477,10 +526,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
goto err_clk;
}
- data->pdata = pdata;
- platform_set_drvdata(pdev, data);
- mutex_init(&data->lock);
-
ret = exynos_tmu_initialize(pdev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize TMU\n");
@@ -489,31 +534,43 @@ static int exynos_tmu_probe(struct platform_device *pdev)
exynos_tmu_control(pdev, true);
- /* Register the sensor with thermal management interface */
- (&exynos_sensor_conf)->driver_data = data;
- exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
+ /* Allocate a structure to register with the exynos core thermal */
+ sensor_conf = devm_kzalloc(&pdev->dev,
+ sizeof(struct thermal_sensor_conf), GFP_KERNEL);
+ if (!sensor_conf) {
+ dev_err(&pdev->dev, "Failed to allocate registration struct\n");
+ ret = -ENOMEM;
+ goto err_clk;
+ }
+ data->reg_conf = sensor_conf;
+ sprintf(sensor_conf->name, "therm_zone%d", data->id);
+ sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
+ sensor_conf->write_emul_temp =
+ (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
+ sensor_conf->driver_data = data;
+ sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
pdata->trigger_enable[1] + pdata->trigger_enable[2]+
pdata->trigger_enable[3];
- for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
- exynos_sensor_conf.trip_data.trip_val[i] =
+ for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
+ sensor_conf->trip_data.trip_val[i] =
pdata->threshold + pdata->trigger_levels[i];
- exynos_sensor_conf.trip_data.trip_type[i] =
+ sensor_conf->trip_data.trip_type[i] =
pdata->trigger_type[i];
}
- exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
+ sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
- exynos_sensor_conf.cooling_data.freq_clip_count =
- pdata->freq_tab_count;
+ sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
for (i = 0; i < pdata->freq_tab_count; i++) {
- exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
+ sensor_conf->cooling_data.freq_data[i].freq_clip_max =
pdata->freq_tab[i].freq_clip_max;
- exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
+ sensor_conf->cooling_data.freq_data[i].temp_level =
pdata->freq_tab[i].temp_level;
}
-
- ret = exynos_register_thermal(&exynos_sensor_conf);
+ sensor_conf->dev = &pdev->dev;
+ /* Register the sensor with thermal management interface */
+ ret = exynos_register_thermal(sensor_conf);
if (ret) {
dev_err(&pdev->dev, "Failed to register thermal interface\n");
goto err_clk;
@@ -531,7 +588,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
exynos_tmu_control(pdev, false);
- exynos_unregister_thermal(&exynos_sensor_conf);
+ exynos_unregister_thermal(data->reg_conf);
clk_unprepare(data->clk);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 619a34c..b614407 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -248,4 +248,17 @@ struct exynos_tmu_platform_data {
unsigned int freq_tab_count;
const struct exynos_tmu_registers *registers;
};
+
+/**
+ * struct exynos_tmu_init_data
+ * @tmu_count: number of TMU instances.
+ * @tmu_data: platform data of all TMU instances.
+ * This structure is required to store data for multi-instance exynos tmu
+ * driver.
+ */
+struct exynos_tmu_init_data {
+ int tmu_count;
+ struct exynos_tmu_platform_data tmu_data[];
+};
+
#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index 7fcf183..06ecfb0 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -48,38 +48,44 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
.tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
.tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
};
-struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
- .threshold = 80,
- .trigger_levels[0] = 5,
- .trigger_levels[1] = 20,
- .trigger_levels[2] = 30,
- .trigger_enable[0] = 1,
- .trigger_enable[1] = 1,
- .trigger_enable[2] = 1,
- .trigger_enable[3] = 0,
- .trigger_type[0] = THROTTLE_ACTIVE,
- .trigger_type[1] = THROTTLE_ACTIVE,
- .trigger_type[2] = SW_TRIP,
- .max_trigger_level = 4,
- .gain = 15,
- .reference_voltage = 7,
- .cal_type = TYPE_ONE_POINT_TRIMMING,
- .min_efuse_value = 40,
- .max_efuse_value = 100,
- .first_point_trim = 25,
- .second_point_trim = 85,
- .default_temp_offset = 50,
- .freq_tab[0] = {
- .freq_clip_max = 800 * 1000,
- .temp_level = 85,
- },
- .freq_tab[1] = {
- .freq_clip_max = 200 * 1000,
- .temp_level = 100,
+
+struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
+ .tmu_data = {
+ {
+ .threshold = 80,
+ .trigger_levels[0] = 5,
+ .trigger_levels[1] = 20,
+ .trigger_levels[2] = 30,
+ .trigger_enable[0] = 1,
+ .trigger_enable[1] = 1,
+ .trigger_enable[2] = 1,
+ .trigger_enable[3] = 0,
+ .trigger_type[0] = THROTTLE_ACTIVE,
+ .trigger_type[1] = THROTTLE_ACTIVE,
+ .trigger_type[2] = SW_TRIP,
+ .max_trigger_level = 4,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .min_efuse_value = 40,
+ .max_efuse_value = 100,
+ .first_point_trim = 25,
+ .second_point_trim = 85,
+ .default_temp_offset = 50,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ .temp_level = 85,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ .temp_level = 100,
+ },
+ .freq_tab_count = 2,
+ .type = SOC_ARCH_EXYNOS4210,
+ .registers = &exynos4210_tmu_registers,
+ },
},
- .freq_tab_count = 2,
- .type = SOC_ARCH_EXYNOS4210,
- .registers = &exynos4210_tmu_registers,
+ .tmu_count = 1,
};
#endif
@@ -120,41 +126,48 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
.emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
.emul_time_mask = EXYNOS_EMUL_TIME_MASK,
};
-struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
- .threshold_falling = 10,
- .trigger_levels[0] = 85,
- .trigger_levels[1] = 103,
- .trigger_levels[2] = 110,
- .trigger_levels[3] = 120,
- .trigger_enable[0] = 1,
- .trigger_enable[1] = 1,
- .trigger_enable[2] = 1,
- .trigger_enable[3] = 0,
- .trigger_type[0] = THROTTLE_ACTIVE,
- .trigger_type[1] = THROTTLE_ACTIVE,
- .trigger_type[2] = SW_TRIP,
- .trigger_type[3] = HW_TRIP,
- .max_trigger_level = 4,
- .gain = 8,
- .reference_voltage = 16,
- .noise_cancel_mode = 4,
- .cal_type = TYPE_ONE_POINT_TRIMMING,
- .efuse_value = 55,
- .min_efuse_value = 40,
- .max_efuse_value = 100,
- .first_point_trim = 25,
- .second_point_trim = 85,
- .default_temp_offset = 50,
- .freq_tab[0] = {
- .freq_clip_max = 800 * 1000,
- .temp_level = 85,
- },
- .freq_tab[1] = {
- .freq_clip_max = 200 * 1000,
- .temp_level = 103,
- },
- .freq_tab_count = 2,
- .type = SOC_ARCH_EXYNOS,
+
+#define EXYNOS5250_TMU_DATA \
+ .threshold_falling = 10, \
+ .trigger_levels[0] = 85, \
+ .trigger_levels[1] = 103, \
+ .trigger_levels[2] = 110, \
+ .trigger_levels[3] = 120, \
+ .trigger_enable[0] = 1, \
+ .trigger_enable[1] = 1, \
+ .trigger_enable[2] = 1, \
+ .trigger_enable[3] = 0, \
+ .trigger_type[0] = THROTTLE_ACTIVE, \
+ .trigger_type[1] = THROTTLE_ACTIVE, \
+ .trigger_type[2] = SW_TRIP, \
+ .trigger_type[3] = HW_TRIP, \
+ .max_trigger_level = 4, \
+ .gain = 8, \
+ .reference_voltage = 16, \
+ .noise_cancel_mode = 4, \
+ .cal_type = TYPE_ONE_POINT_TRIMMING, \
+ .efuse_value = 55, \
+ .min_efuse_value = 40, \
+ .max_efuse_value = 100, \
+ .first_point_trim = 25, \
+ .second_point_trim = 85, \
+ .default_temp_offset = 50, \
+ .freq_tab[0] = { \
+ .freq_clip_max = 800 * 1000, \
+ .temp_level = 85, \
+ }, \
+ .freq_tab[1] = { \
+ .freq_clip_max = 200 * 1000, \
+ .temp_level = 103, \
+ }, \
+ .freq_tab_count = 2, \
+ .type = SOC_ARCH_EXYNOS, \
.registers = &exynos5250_tmu_registers,
+
+struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
+ .tmu_data = {
+ { EXYNOS5250_TMU_DATA },
+ },
+ .tmu_count = 1,
};
#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
index 4acf070..139dbbb 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.h
+++ b/drivers/thermal/samsung/exynos_tmu_data.h
@@ -94,14 +94,14 @@
#define EXYNOS_MAX_TRIGGER_PER_REG 4
#if defined(CONFIG_CPU_EXYNOS4210)
-extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
+extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
#else
#define EXYNOS4210_TMU_DRV_DATA (NULL)
#endif
#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
-extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
+extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
#else
#define EXYNOS5250_TMU_DRV_DATA (NULL)
--
1.7.1
Recently non DT support from Exynos platform is removed and hence
removing non DT support from the driver also. This will help in easy
maintainence.
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 17 +----------------
1 files changed, 1 insertions(+), 16 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index acbd295..4356118 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -403,19 +403,6 @@ static const struct of_device_id exynos_tmu_match[] = {
MODULE_DEVICE_TABLE(of, exynos_tmu_match);
#endif
-static struct platform_device_id exynos_tmu_driver_ids[] = {
- {
- .name = "exynos4210-tmu",
- .driver_data = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
- },
- {
- .name = "exynos5250-tmu",
- .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
- },
- { },
-};
-MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
-
static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
struct platform_device *pdev)
{
@@ -428,8 +415,7 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
return (struct exynos_tmu_platform_data *) match->data;
}
#endif
- return (struct exynos_tmu_platform_data *)
- platform_get_device_id(pdev)->driver_data;
+ return NULL;
}
static int exynos_tmu_probe(struct platform_device *pdev)
@@ -586,7 +572,6 @@ static struct platform_driver exynos_tmu_driver = {
},
.probe = exynos_tmu_probe,
.remove = exynos_tmu_remove,
- .id_table = exynos_tmu_driver_ids,
};
module_platform_driver(exynos_tmu_driver);
--
1.7.1
This code simplifies the zone handling to use the trip information passed
by the TMU driver and not the hardcoded macros. This also helps in adding
more zone support.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 61 +++++++++++++----------
drivers/thermal/samsung/exynos_thermal_common.h | 3 +-
drivers/thermal/samsung/exynos_tmu.c | 5 ++-
3 files changed, 40 insertions(+), 29 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index 86d39aa..2873ca3 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -78,17 +78,22 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
enum thermal_trip_type *type)
{
- switch (GET_ZONE(trip)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- *type = THERMAL_TRIP_ACTIVE;
- break;
- case PANIC_ZONE:
- *type = THERMAL_TRIP_CRITICAL;
- break;
- default:
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
+ int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+ int trip_type;
+
+ if (trip < 0 || trip >= max_trip)
return -EINVAL;
- }
+
+ trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
+
+ if (trip_type == SW_TRIP)
+ *type = THERMAL_TRIP_CRITICAL;
+ else if (trip_type == THROTTLE_ACTIVE)
+ *type = THERMAL_TRIP_ACTIVE;
+ else if (trip_type == THROTTLE_PASSIVE)
+ *type = THERMAL_TRIP_PASSIVE;
+
return 0;
}
@@ -97,8 +102,9 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
unsigned long *temp)
{
struct exynos_thermal_zone *th_zone = thermal->devdata;
+ int max_trip = th_zone->sensor_conf->trip_data.trip_count;
- if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
+ if (trip < 0 || trip >= max_trip)
return -EINVAL;
*temp = th_zone->sensor_conf->trip_data.trip_val[trip];
@@ -112,10 +118,10 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
{
- int ret;
- /* Panic zone */
- ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
- return ret;
+ struct exynos_thermal_zone *th_zone = thermal->devdata;
+ int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+ /* Get the temp of highest trip*/
+ return exynos_get_trip_temp(thermal, max_trip - 1, temp);
}
/* Bind callback functions for thermal zone */
@@ -340,19 +346,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
return -ENOMEM;
th_zone->sensor_conf = sensor_conf;
- cpumask_set_cpu(0, &mask_val);
- th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
- if (IS_ERR(th_zone->cool_dev[0])) {
- pr_err("Failed to register cpufreq cooling device\n");
- ret = -EINVAL;
- goto err_unregister;
+ if (sensor_conf->cooling_data.freq_clip_count > 0) {
+ cpumask_set_cpu(0, &mask_val);
+ th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
+ if (IS_ERR(th_zone->cool_dev[0])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->cool_dev_size++;
}
- th_zone->cool_dev_size++;
- th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
- EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
- sensor_conf->trip_data.trigger_falling ?
- 0 : IDLE_INTERVAL);
+ th_zone->therm_dev = thermal_zone_device_register(
+ sensor_conf->name, sensor_conf->trip_data.trip_count,
+ 0, th_zone, &exynos_dev_ops, NULL, 0,
+ sensor_conf->trip_data.trigger_falling ? 0 :
+ IDLE_INTERVAL);
if (IS_ERR(th_zone->therm_dev)) {
pr_err("Failed to register thermal zone device\n");
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index 1e9a326..dd0077e 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -42,8 +42,6 @@
#define GET_ZONE(trip) (trip + 2)
#define GET_TRIP(zone) (zone - 2)
-#define EXYNOS_ZONE_COUNT 3
-
enum trigger_type {
THROTTLE_ACTIVE = 1,
THROTTLE_PASSIVE,
@@ -68,6 +66,7 @@ struct freq_clip_table {
};
struct thermal_trip_point_conf {
int trip_val[MAX_TRIP_COUNT];
+ int trip_type[MAX_TRIP_COUNT];
int trip_count;
unsigned char trigger_falling;
};
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 40e0cfd..acbd295 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -509,9 +509,12 @@ static int exynos_tmu_probe(struct platform_device *pdev)
pdata->trigger_enable[1] + pdata->trigger_enable[2]+
pdata->trigger_enable[3];
- for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
+ for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
exynos_sensor_conf.trip_data.trip_val[i] =
pdata->threshold + pdata->trigger_levels[i];
+ exynos_sensor_conf.trip_data.trip_type[i] =
+ pdata->trigger_type[i];
+ }
exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
--
1.7.1
This patch removes the error return in the bind/unbind routine
as the platform may not register any cpufreq cooling data.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index 7064eb7..86d39aa 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -131,7 +131,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
tab_size = data->cooling_data.freq_clip_count;
if (tab_ptr == NULL || tab_size == 0)
- return -EINVAL;
+ return 0;
/* find the cooling device registered*/
for (i = 0; i < th_zone->cool_dev_size; i++)
@@ -180,7 +180,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
tab_size = data->cooling_data.freq_clip_count;
if (tab_size == 0)
- return -EINVAL;
+ return 0;
/* find the cooling device registered*/
for (i = 0; i < th_zone->cool_dev_size; i++)
--
1.7.1
This patch renames member private_data to driver_data of the thermal
zone registration structure as this item stores the driver related
data and uses it to call the driver related callbacks.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 4 ++--
drivers/thermal/samsung/exynos_thermal_common.h | 2 +-
drivers/thermal/samsung/exynos_tmu.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index 2af1e3b..7064eb7 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -221,7 +221,7 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
pr_info("Temperature sensor not initialised\n");
return -EINVAL;
}
- data = th_zone->sensor_conf->private_data;
+ data = th_zone->sensor_conf->driver_data;
*temp = th_zone->sensor_conf->read_temperature(data);
/* convert the temperature into millicelsius */
*temp = *temp * MCELSIUS;
@@ -240,7 +240,7 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
pr_info("Temperature sensor not initialised\n");
return -EINVAL;
}
- data = th_zone->sensor_conf->private_data;
+ data = th_zone->sensor_conf->driver_data;
if (th_zone->sensor_conf->write_emul_temp)
ret = th_zone->sensor_conf->write_emul_temp(data, temp);
return ret;
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index a845c2d..1e9a326 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -83,7 +83,7 @@ struct thermal_sensor_conf {
int (*write_emul_temp)(void *drv_data, unsigned long temp);
struct thermal_trip_point_conf trip_data;
struct thermal_cooling_conf cooling_data;
- void *private_data;
+ void *driver_data;
void *pzone_data;
};
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index a7bba69..40e0cfd 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -504,7 +504,7 @@ static int exynos_tmu_probe(struct platform_device *pdev)
exynos_tmu_control(pdev, true);
/* Register the sensor with thermal management interface */
- (&exynos_sensor_conf)->private_data = data;
+ (&exynos_sensor_conf)->driver_data = data;
exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
pdata->trigger_enable[1] + pdata->trigger_enable[2]+
pdata->trigger_enable[3];
--
1.7.1
This patch uses the TMU status register to know the generated interrupts
and only clear them in the interrupt handler.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_tmu.c | 11 +++++------
drivers/thermal/samsung/exynos_tmu_data.c | 2 ++
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 33f494e..f6f63ca 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -351,17 +351,16 @@ static void exynos_tmu_work(struct work_struct *work)
struct exynos_tmu_data, irq_work);
struct exynos_tmu_platform_data *pdata = data->pdata;
const struct exynos_tmu_registers *reg = pdata->registers;
+ unsigned int val_irq;
exynos_report_trigger();
mutex_lock(&data->lock);
clk_enable(data->clk);
- if (data->soc == SOC_ARCH_EXYNOS)
- writel((reg->inten_rise_mask << reg->inten_rise_shift) |
- (reg->inten_fall_mask << reg->inten_fall_shift),
- data->base + reg->tmu_intclear);
- else
- writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
+ /* TODO: take action based on particular interrupt */
+ val_irq = readl(data->base + reg->tmu_intstat);
+ /* clear the interrupts */
+ writel(val_irq, data->base + reg->tmu_intclear);
clk_disable(data->clk);
mutex_unlock(&data->lock);
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
index e7cb1cc..7fcf183 100644
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ b/drivers/thermal/samsung/exynos_tmu_data.c
@@ -45,6 +45,7 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
.inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
.inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
+ .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
.tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
};
struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
@@ -112,6 +113,7 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
.inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
.inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
.inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
+ .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
.tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
.emul_con = EXYNOS_EMUL_CON,
.emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
--
1.7.1
This patch renames and moves include/linux/platform_data/exynos_thermal.h to
drivers/thermal/samsung/exynos_tmu.h. This file movement is needed as exynos
SOC's are not supporting non-DT based platforms and this file now just contains
exynos tmu driver related definations.
Also struct freq_clip_table is now moved to exynos_thermal_common.c as it fixes
the compilation issue occuring because now this new tmu header file is included
in tmu driver c file and not in the common thermal header file.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/samsung/exynos_thermal_common.c | 1 -
drivers/thermal/samsung/exynos_thermal_common.h | 15 ++++++++++++
drivers/thermal/samsung/exynos_tmu.c | 2 +-
.../thermal/samsung/exynos_tmu.h | 24 ++++---------------
4 files changed, 21 insertions(+), 21 deletions(-)
rename include/linux/platform_data/exynos_thermal.h => drivers/thermal/samsung/exynos_tmu.h (84%)
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index 92e50bc..dd49c9f 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -21,7 +21,6 @@
*/
#include <linux/cpu_cooling.h>
-#include <linux/platform_data/exynos_thermal.h>
#include <linux/slab.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
index 8df1848..068f56c 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ b/drivers/thermal/samsung/exynos_thermal_common.h
@@ -44,6 +44,21 @@
#define EXYNOS_ZONE_COUNT 3
+/**
+ * struct freq_clip_table
+ * @freq_clip_max: maximum frequency allowed for this cooling state.
+ * @temp_level: Temperature level at which the temperature clipping will
+ * happen.
+ * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
+ *
+ * This structure is required to be filled and passed to the
+ * cpufreq_cooling_unregister function.
+ */
+struct freq_clip_table {
+ unsigned int freq_clip_max;
+ unsigned int temp_level;
+ const struct cpumask *mask_val;
+};
struct thermal_trip_point_conf {
int trip_val[MAX_TRIP_COUNT];
int trip_count;
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 22a8874..6aa2fd2 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -27,9 +27,9 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/exynos_thermal.h>
#include "exynos_thermal_common.h"
+#include "exynos_tmu.h"
/* Exynos generic registers */
#define EXYNOS_TMU_REG_TRIMINFO 0x0
diff --git a/include/linux/platform_data/exynos_thermal.h b/drivers/thermal/samsung/exynos_tmu.h
similarity index 84%
rename from include/linux/platform_data/exynos_thermal.h
rename to drivers/thermal/samsung/exynos_tmu.h
index da7e627..9e0f887 100644
--- a/include/linux/platform_data/exynos_thermal.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -1,8 +1,9 @@
/*
- * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
+ * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <[email protected]>
+ * Amit Daniel Kachhap <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,8 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef _LINUX_EXYNOS_THERMAL_H
-#define _LINUX_EXYNOS_THERMAL_H
+#ifndef _EXYNOS_TMU_H
+#define _EXYNOS_TMU_H
#include <linux/cpu_cooling.h>
enum calibration_type {
@@ -33,21 +34,6 @@ enum soc_type {
SOC_ARCH_EXYNOS4210 = 1,
SOC_ARCH_EXYNOS,
};
-/**
- * struct freq_clip_table
- * @freq_clip_max: maximum frequency allowed for this cooling state.
- * @temp_level: Temperature level at which the temperature clipping will
- * happen.
- * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
- *
- * This structure is required to be filled and passed to the
- * cpufreq_cooling_unregister function.
- */
-struct freq_clip_table {
- unsigned int freq_clip_max;
- unsigned int temp_level;
- const struct cpumask *mask_val;
-};
/**
* struct exynos_tmu_platform_data
@@ -116,4 +102,4 @@ struct exynos_tmu_platform_data {
struct freq_clip_table freq_tab[4];
unsigned int freq_tab_count;
};
-#endif /* _LINUX_EXYNOS_THERMAL_H */
+#endif /* _EXYNOS_TMU_H */
--
1.7.1
This movement of files is done for easy maintenance and adding more
new sensor's support for exynos platform easily . This will also help in
bifurcating exynos common, sensor driver and sensor data related parts.
Acked-by: Kukjin Kim <[email protected]>
Acked-by: Jonghwa Lee <[email protected]>
Signed-off-by: Amit Daniel Kachhap <[email protected]>
---
drivers/thermal/Kconfig | 13 +++++--------
drivers/thermal/Makefile | 2 +-
drivers/thermal/samsung/Kconfig | 9 +++++++++
drivers/thermal/samsung/Makefile | 4 ++++
drivers/thermal/{ => samsung}/exynos_thermal.c | 0
5 files changed, 19 insertions(+), 9 deletions(-)
create mode 100644 drivers/thermal/samsung/Kconfig
create mode 100644 drivers/thermal/samsung/Makefile
rename drivers/thermal/{ => samsung}/exynos_thermal.c (100%)
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index b13c2bc..ef10cf2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -114,14 +114,6 @@ config KIRKWOOD_THERMAL
Support for the Kirkwood thermal sensor driver into the Linux thermal
framework. Only kirkwood 88F6282 and 88F6283 have this sensor.
-config EXYNOS_THERMAL
- tristate "Temperature sensor on Samsung EXYNOS"
- depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
- depends on CPU_THERMAL
- help
- If you say yes here you get support for TMU (Thermal Management
- Unit) on SAMSUNG EXYNOS series of SoC.
-
config DOVE_THERMAL
tristate "Temperature sensor on Marvell Dove SoCs"
depends on ARCH_DOVE
@@ -185,4 +177,9 @@ menu "Texas Instruments thermal drivers"
source "drivers/thermal/ti-soc-thermal/Kconfig"
endmenu
+menu "Samsung thermal drivers"
+depends on PLAT_SAMSUNG
+source "drivers/thermal/samsung/Kconfig"
+endmenu
+
endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 67184a2..1f27ada 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -17,7 +17,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
-obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
+obj-y += samsung/
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
new file mode 100644
index 0000000..2d3d9dc
--- /dev/null
+++ b/drivers/thermal/samsung/Kconfig
@@ -0,0 +1,9 @@
+config EXYNOS_THERMAL
+ tristate "Temperature sensor on Samsung EXYNOS"
+ depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ depends on CPU_THERMAL
+ help
+ If you say yes here you get support for TMU (Thermal Management
+ Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
+ the exynos thermal driver with the core thermal layer and cpu
+ cooling API's.
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
new file mode 100644
index 0000000..1fe6d93
--- /dev/null
+++ b/drivers/thermal/samsung/Makefile
@@ -0,0 +1,4 @@
+#
+# Samsung thermal specific Makefile
+#
+obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
similarity index 100%
rename from drivers/thermal/exynos_thermal.c
rename to drivers/thermal/samsung/exynos_thermal.c
--
1.7.1
Amit,
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code bifurcates exynos thermal implementation into common and sensor
> specific parts. The common thermal code interacts with core thermal layer and
> core cpufreq cooling parts and is independent of SOC specific driver. This
> change is needed to cleanly add support for new TMU sensors.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/Kconfig | 19 +-
> drivers/thermal/samsung/Makefile | 4 +-
> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
> 5 files changed, 490 insertions(+), 419 deletions(-)
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index 2cf31ad..f8100b1 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -1,8 +1,17 @@
> config EXYNOS_THERMAL
> - tristate "Temperature sensor on Samsung EXYNOS"
> + tristate "Exynos thermal management unit driver"
> depends on ARCH_HAS_BANDGAP
> help
> - If you say yes here you get support for TMU (Thermal Management
> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
> - the exynos thermal driver with the core thermal layer and cpu
> - cooling API's.
> + If you say yes here you get support for the TMU (Thermal Management
> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
> + the TMU, reports temperature and handles cooling action if defined.
> + This driver uses the exynos core thermal API's.
> +
> +config EXYNOS_THERMAL_CORE
> + bool "Core thermal framework support for EXYNOS SOC's"
> + depends on EXYNOS_THERMAL
> + help
> + If you say yes here you get support for EXYNOS TMU
> + (Thermal Management Unit) common registration/unregistration
> + functions to the core thermal layer and also to use the generic
> + cpu cooling API's.
Should this one depend on CPU_THERMAL? Is it mandatory?
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> index 1fe6d93..6227d4f 100644
> --- a/drivers/thermal/samsung/Makefile
> +++ b/drivers/thermal/samsung/Makefile
> @@ -1,4 +1,6 @@
> #
> # Samsung thermal specific Makefile
> #
> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
> +exynos_soc_thermal-y := exynos_thermal.o
> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
> index 03e4bbc..5293849 100644
> --- a/drivers/thermal/samsung/exynos_thermal.c
> +++ b/drivers/thermal/samsung/exynos_thermal.c
> @@ -21,23 +21,15 @@
> *
> */
>
> -#include <linux/module.h>
> -#include <linux/err.h>
> -#include <linux/kernel.h>
> -#include <linux/slab.h>
> -#include <linux/platform_device.h>
> -#include <linux/interrupt.h>
> #include <linux/clk.h>
> -#include <linux/workqueue.h>
> -#include <linux/sysfs.h>
> -#include <linux/kobject.h>
> #include <linux/io.h>
> -#include <linux/mutex.h>
> -#include <linux/platform_data/exynos_thermal.h>
> -#include <linux/thermal.h>
> -#include <linux/cpufreq.h>
> -#include <linux/cpu_cooling.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +
> +#include "exynos_thermal_common.h"
>
> /* Exynos generic registers */
> #define EXYNOS_TMU_REG_TRIMINFO 0x0
> @@ -88,16 +80,6 @@
> #define EFUSE_MIN_VALUE 40
> #define EFUSE_MAX_VALUE 100
>
> -/* In-kernel thermal framework related macros & definations */
> -#define SENSOR_NAME_LEN 16
> -#define MAX_TRIP_COUNT 8
> -#define MAX_COOLING_DEVICE 4
> -#define MAX_THRESHOLD_LEVS 4
> -
> -#define ACTIVE_INTERVAL 500
> -#define IDLE_INTERVAL 10000
> -#define MCELSIUS 1000
> -
> #ifdef CONFIG_THERMAL_EMULATION
> #define EXYNOS_EMUL_TIME 0x57F0
> #define EXYNOS_EMUL_TIME_SHIFT 16
> @@ -106,17 +88,6 @@
> #define EXYNOS_EMUL_ENABLE 0x1
> #endif /* CONFIG_THERMAL_EMULATION */
>
> -/* CPU Zone information */
> -#define PANIC_ZONE 4
> -#define WARN_ZONE 3
> -#define MONITOR_ZONE 2
> -#define SAFE_ZONE 1
> -
> -#define GET_ZONE(trip) (trip + 2)
> -#define GET_TRIP(zone) (zone - 2)
> -
> -#define EXYNOS_ZONE_COUNT 3
> -
> struct exynos_tmu_data {
> struct exynos_tmu_platform_data *pdata;
> struct resource *mem;
> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
> u8 temp_error1, temp_error2;
> };
>
> -struct thermal_trip_point_conf {
> - int trip_val[MAX_TRIP_COUNT];
> - int trip_count;
> - u8 trigger_falling;
> -};
> -
> -struct thermal_cooling_conf {
> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> - int freq_clip_count;
> -};
> -
> -struct thermal_sensor_conf {
> - char name[SENSOR_NAME_LEN];
> - int (*read_temperature)(void *data);
> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
> - struct thermal_trip_point_conf trip_data;
> - struct thermal_cooling_conf cooling_data;
> - void *private_data;
> -};
> -
> -struct exynos_thermal_zone {
> - enum thermal_device_mode mode;
> - struct thermal_zone_device *therm_dev;
> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> - unsigned int cool_dev_size;
> - struct platform_device *exynos4_dev;
> - struct thermal_sensor_conf *sensor_conf;
> - bool bind;
> -};
> -
> -static struct exynos_thermal_zone *th_zone;
> -static void exynos_unregister_thermal(void);
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> -
> -/* Get mode callback functions for thermal zone */
> -static int exynos_get_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode *mode)
> -{
> - if (th_zone)
> - *mode = th_zone->mode;
> - return 0;
> -}
> -
> -/* Set mode callback functions for thermal zone */
> -static int exynos_set_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode mode)
> -{
> - if (!th_zone->therm_dev) {
> - pr_notice("thermal zone not registered\n");
> - return 0;
> - }
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> -
> - if (mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling)
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = 0;
> -
> - mutex_unlock(&th_zone->therm_dev->lock);
> -
> - th_zone->mode = mode;
> - thermal_zone_device_update(th_zone->therm_dev);
> - pr_info("thermal polling set for duration=%d msec\n",
> - th_zone->therm_dev->polling_delay);
> - return 0;
> -}
> -
> -
> -/* Get trip type callback functions for thermal zone */
> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> - enum thermal_trip_type *type)
> -{
> - switch (GET_ZONE(trip)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - *type = THERMAL_TRIP_ACTIVE;
> - break;
> - case PANIC_ZONE:
> - *type = THERMAL_TRIP_CRITICAL;
> - break;
> - default:
> - return -EINVAL;
> - }
> - return 0;
> -}
> -
> -/* Get trip temperature callback functions for thermal zone */
> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> - unsigned long *temp)
> -{
> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> - return -EINVAL;
> -
> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> -
> - return 0;
> -}
> -
> -/* Get critical temperature callback functions for thermal zone */
> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - int ret;
> - /* Panic zone */
> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> - return ret;
> -}
> -
> -/* Bind callback functions for thermal zone */
> -static int exynos_bind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size, level;
> - struct freq_clip_table *tab_ptr, *clip_data;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_ptr == NULL || tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> - if (level == THERMAL_CSTATE_INVALID)
> - return 0;
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> - level, 0)) {
> - pr_err("error binding cdev inst %d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = true;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> -
> - return ret;
> -}
> -
> -/* Unbind callback functions for thermal zone */
> -static int exynos_unbind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - if (th_zone->bind == false)
> - return 0;
> -
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_unbind_cooling_device(thermal, i,
> - cdev)) {
> - pr_err("error unbinding cdev inst=%d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = false;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> - return ret;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_get_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - void *data;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - *temp = th_zone->sensor_conf->read_temperature(data);
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> - return 0;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> - unsigned long temp)
> -{
> - void *data;
> - int ret = -EINVAL;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - if (th_zone->sensor_conf->write_emul_temp)
> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> - return ret;
> -}
> -
> -/* Get the temperature trend */
> -static int exynos_get_trend(struct thermal_zone_device *thermal,
> - int trip, enum thermal_trend *trend)
> -{
> - int ret;
> - unsigned long trip_temp;
> -
> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> - if (ret < 0)
> - return ret;
> -
> - if (thermal->temperature >= trip_temp)
> - *trend = THERMAL_TREND_RAISE_FULL;
> - else
> - *trend = THERMAL_TREND_DROP_FULL;
> -
> - return 0;
> -}
> -/* Operation callback functions for thermal zone */
> -static struct thermal_zone_device_ops const exynos_dev_ops = {
> - .bind = exynos_bind,
> - .unbind = exynos_unbind,
> - .get_temp = exynos_get_temp,
> - .set_emul_temp = exynos_set_emul_temp,
> - .get_trend = exynos_get_trend,
> - .get_mode = exynos_get_mode,
> - .set_mode = exynos_set_mode,
> - .get_trip_type = exynos_get_trip_type,
> - .get_trip_temp = exynos_get_trip_temp,
> - .get_crit_temp = exynos_get_crit_temp,
> -};
> -
> -/*
> - * This function may be called from interrupt based temperature sensor
> - * when threshold is changed.
> - */
> -static void exynos_report_trigger(void)
> -{
> - unsigned int i;
> - char data[10];
> - char *envp[] = { data, NULL };
> -
> - if (!th_zone || !th_zone->therm_dev)
> - return;
> - if (th_zone->bind == false) {
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (!th_zone->cool_dev[i])
> - continue;
> - exynos_bind(th_zone->therm_dev,
> - th_zone->cool_dev[i]);
> - }
> - }
> -
> - thermal_zone_device_update(th_zone->therm_dev);
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> - /* Find the level for which trip happened */
> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> - if (th_zone->therm_dev->last_temperature <
> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> - break;
> - }
> -
> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling) {
> - if (i > 0)
> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - }
> -
> - snprintf(data, sizeof(data), "%u", i);
> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> - mutex_unlock(&th_zone->therm_dev->lock);
> -}
> -
> -/* Register with the in-kernel thermal management */
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> -{
> - int ret;
> - struct cpumask mask_val;
> -
> - if (!sensor_conf || !sensor_conf->read_temperature) {
> - pr_err("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> -
> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> - if (!th_zone)
> - return -ENOMEM;
> -
> - th_zone->sensor_conf = sensor_conf;
> - cpumask_set_cpu(0, &mask_val);
> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> - if (IS_ERR(th_zone->cool_dev[0])) {
> - pr_err("Failed to register cpufreq cooling device\n");
> - ret = -EINVAL;
> - goto err_unregister;
> - }
> - th_zone->cool_dev_size++;
> -
> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> - sensor_conf->trip_data.trigger_falling ?
> - 0 : IDLE_INTERVAL);
> -
> - if (IS_ERR(th_zone->therm_dev)) {
> - pr_err("Failed to register thermal zone device\n");
> - ret = PTR_ERR(th_zone->therm_dev);
> - goto err_unregister;
> - }
> - th_zone->mode = THERMAL_DEVICE_ENABLED;
> -
> - pr_info("Exynos: Kernel Thermal management registered\n");
> -
> - return 0;
> -
> -err_unregister:
> - exynos_unregister_thermal();
> - return ret;
> -}
> -
> -/* Un-Register with the in-kernel thermal management */
> -static void exynos_unregister_thermal(void)
> -{
> - int i;
> -
> - if (!th_zone)
> - return;
> -
> - if (th_zone->therm_dev)
> - thermal_zone_device_unregister(th_zone->therm_dev);
> -
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (th_zone->cool_dev[i])
> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> - }
> -
> - kfree(th_zone);
> - pr_info("Exynos: Kernel Thermal management unregistered\n");
> -}
> -
> /*
> * TMU treats temperature as a mapped temperature code.
> * The temperature is converted differently depending on the calibration type.
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> new file mode 100644
> index 0000000..92e50bc
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -0,0 +1,384 @@
> +/*
> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/cpu_cooling.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#include "exynos_thermal_common.h"
> +
> +struct exynos_thermal_zone {
> + enum thermal_device_mode mode;
> + struct thermal_zone_device *therm_dev;
> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> + unsigned int cool_dev_size;
> + struct platform_device *exynos4_dev;
> + struct thermal_sensor_conf *sensor_conf;
> + bool bind;
> +};
> +
> +static struct exynos_thermal_zone *th_zone;
> +
> +/* Get mode callback functions for thermal zone */
> +static int exynos_get_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode *mode)
> +{
> + if (th_zone)
> + *mode = th_zone->mode;
> + return 0;
> +}
> +
> +/* Set mode callback functions for thermal zone */
> +static int exynos_set_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode mode)
> +{
> + if (!th_zone->therm_dev) {
> + pr_notice("thermal zone not registered\n");
> + return 0;
> + }
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> +
> + if (mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling)
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = 0;
> +
> + mutex_unlock(&th_zone->therm_dev->lock);
> +
> + th_zone->mode = mode;
> + thermal_zone_device_update(th_zone->therm_dev);
> + pr_info("thermal polling set for duration=%d msec\n",
> + th_zone->therm_dev->polling_delay);
> + return 0;
> +}
> +
> +
> +/* Get trip type callback functions for thermal zone */
> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> + enum thermal_trip_type *type)
> +{
> + switch (GET_ZONE(trip)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + *type = THERMAL_TRIP_ACTIVE;
> + break;
> + case PANIC_ZONE:
> + *type = THERMAL_TRIP_CRITICAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +/* Get trip temperature callback functions for thermal zone */
> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> + unsigned long *temp)
> +{
> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> + return -EINVAL;
> +
> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> +
> + return 0;
> +}
> +
> +/* Get critical temperature callback functions for thermal zone */
> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + int ret;
> + /* Panic zone */
> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> + return ret;
> +}
> +
> +/* Bind callback functions for thermal zone */
> +static int exynos_bind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size, level;
> + struct freq_clip_table *tab_ptr, *clip_data;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_ptr == NULL || tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> + if (level == THERMAL_CSTATE_INVALID)
> + return 0;
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> + level, 0)) {
> + pr_err("error binding cdev inst %d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = true;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/* Unbind callback functions for thermal zone */
> +static int exynos_unbind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + if (th_zone->bind == false)
> + return 0;
> +
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_unbind_cooling_device(thermal, i,
> + cdev)) {
> + pr_err("error unbinding cdev inst=%d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = false;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> + return ret;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_get_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + void *data;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + *temp = th_zone->sensor_conf->read_temperature(data);
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> + return 0;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> + unsigned long temp)
> +{
> + void *data;
> + int ret = -EINVAL;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + if (th_zone->sensor_conf->write_emul_temp)
> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> + return ret;
> +}
> +
> +/* Get the temperature trend */
> +static int exynos_get_trend(struct thermal_zone_device *thermal,
> + int trip, enum thermal_trend *trend)
> +{
> + int ret;
> + unsigned long trip_temp;
> +
> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> + if (ret < 0)
> + return ret;
> +
> + if (thermal->temperature >= trip_temp)
> + *trend = THERMAL_TREND_RAISE_FULL;
> + else
> + *trend = THERMAL_TREND_DROP_FULL;
> +
> + return 0;
> +}
> +/* Operation callback functions for thermal zone */
> +static struct thermal_zone_device_ops const exynos_dev_ops = {
> + .bind = exynos_bind,
> + .unbind = exynos_unbind,
> + .get_temp = exynos_get_temp,
> + .set_emul_temp = exynos_set_emul_temp,
> + .get_trend = exynos_get_trend,
> + .get_mode = exynos_get_mode,
> + .set_mode = exynos_set_mode,
> + .get_trip_type = exynos_get_trip_type,
> + .get_trip_temp = exynos_get_trip_temp,
> + .get_crit_temp = exynos_get_crit_temp,
> +};
> +
> +/*
> + * This function may be called from interrupt based temperature sensor
> + * when threshold is changed.
> + */
> +void exynos_report_trigger(void)
> +{
> + unsigned int i;
> + char data[10];
> + char *envp[] = { data, NULL };
> +
> + if (!th_zone || !th_zone->therm_dev)
> + return;
> + if (th_zone->bind == false) {
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (!th_zone->cool_dev[i])
> + continue;
> + exynos_bind(th_zone->therm_dev,
> + th_zone->cool_dev[i]);
> + }
> + }
> +
> + thermal_zone_device_update(th_zone->therm_dev);
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> + /* Find the level for which trip happened */
> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> + if (th_zone->therm_dev->last_temperature <
> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> + break;
> + }
> +
> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling) {
> + if (i > 0)
> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + }
> +
> + snprintf(data, sizeof(data), "%u", i);
> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> + mutex_unlock(&th_zone->therm_dev->lock);
> +}
> +
> +/* Register with the in-kernel thermal management */
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> +{
> + int ret;
> + struct cpumask mask_val;
> +
> + if (!sensor_conf || !sensor_conf->read_temperature) {
> + pr_err("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> +
> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> + if (!th_zone)
> + return -ENOMEM;
> +
> + th_zone->sensor_conf = sensor_conf;
> + cpumask_set_cpu(0, &mask_val);
> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> + if (IS_ERR(th_zone->cool_dev[0])) {
> + pr_err("Failed to register cpufreq cooling device\n");
> + ret = -EINVAL;
> + goto err_unregister;
> + }
> + th_zone->cool_dev_size++;
> +
> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> + sensor_conf->trip_data.trigger_falling ?
> + 0 : IDLE_INTERVAL);
> +
> + if (IS_ERR(th_zone->therm_dev)) {
> + pr_err("Failed to register thermal zone device\n");
> + ret = PTR_ERR(th_zone->therm_dev);
> + goto err_unregister;
> + }
> + th_zone->mode = THERMAL_DEVICE_ENABLED;
> +
> + pr_info("Exynos: Kernel Thermal management registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + exynos_unregister_thermal();
> + return ret;
> +}
> +
> +/* Un-Register with the in-kernel thermal management */
> +void exynos_unregister_thermal(void)
> +{
> + int i;
> +
> + if (!th_zone)
> + return;
> +
> + if (th_zone->therm_dev)
> + thermal_zone_device_unregister(th_zone->therm_dev);
> +
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (th_zone->cool_dev[i])
> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> + }
> +
> + kfree(th_zone);
> + pr_info("Exynos: Kernel Thermal management unregistered\n");
> +}
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> new file mode 100644
> index 0000000..8df1848
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -0,0 +1,83 @@
> +/*
> + * exynos_thermal_common.h - Samsung EXYNOS common header file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifndef _EXYNOS_THERMAL_COMMON_H
> +#define _EXYNOS_THERMAL_COMMON_H
> +
> +/* In-kernel thermal framework related macros & definations */
> +#define SENSOR_NAME_LEN 16
> +#define MAX_TRIP_COUNT 8
> +#define MAX_COOLING_DEVICE 4
> +#define MAX_THRESHOLD_LEVS 4
> +
> +#define ACTIVE_INTERVAL 500
> +#define IDLE_INTERVAL 10000
> +#define MCELSIUS 1000
> +
> +/* CPU Zone information */
> +#define PANIC_ZONE 4
> +#define WARN_ZONE 3
> +#define MONITOR_ZONE 2
> +#define SAFE_ZONE 1
> +
> +#define GET_ZONE(trip) (trip + 2)
> +#define GET_TRIP(zone) (zone - 2)
> +
> +#define EXYNOS_ZONE_COUNT 3
> +
> +struct thermal_trip_point_conf {
> + int trip_val[MAX_TRIP_COUNT];
> + int trip_count;
> + unsigned char trigger_falling;
> +};
> +
> +struct thermal_cooling_conf {
> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> + int freq_clip_count;
> +};
> +
> +struct thermal_sensor_conf {
> + char name[SENSOR_NAME_LEN];
> + int (*read_temperature)(void *data);
> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
> + struct thermal_trip_point_conf trip_data;
> + struct thermal_cooling_conf cooling_data;
> + void *private_data;
> +};
> +
> +/*Functions used exynos based thermal sensor driver*/
> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
> +void exynos_unregister_thermal(void);
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> +void exynos_report_trigger(void);
> +#else
> +static inline void
> +exynos_unregister_thermal(void) { return; }
> +
> +static inline int
> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
> +
> +static inline void
> +exynos_report_trigger(void) { return; }
> +
> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch uses the recently added config sybmol ARCH_HAS_BANDGAP to enable
> the TMU driver. This will allow adding support for new soc easily as now it
> is the platform responsibility to enable this config symbol for a particular
> soc.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/Kconfig | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index 2d3d9dc..883a8a8 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -1,6 +1,6 @@
> config EXYNOS_THERMAL
> tristate "Temperature sensor on Samsung EXYNOS"
> - depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
> + depends on ARCH_HAS_BANDGAP
> depends on CPU_THERMAL
> help
> If you say yes here you get support for TMU (Thermal Management
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch enables ARCH_HAS_BANDGAP config for exynos4210, 4212, 4412, 5250
> and 5440 SOC. This config symbol is recently added to allow the platforms
> to enable bandgap based temperature sensor.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> arch/arm/mach-exynos/Kconfig | 5 +++++
> 1 files changed, 5 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
> index d19edff..d3cb5c7 100644
> --- a/arch/arm/mach-exynos/Kconfig
> +++ b/arch/arm/mach-exynos/Kconfig
> @@ -33,6 +33,7 @@ config CPU_EXYNOS4210
> bool "SAMSUNG EXYNOS4210"
> default y
> depends on ARCH_EXYNOS4
> + select ARCH_HAS_BANDGAP
> select ARM_CPU_SUSPEND if PM
> select PM_GENERIC_DOMAINS
> select S5P_PM if PM
> @@ -45,6 +46,7 @@ config SOC_EXYNOS4212
> bool "SAMSUNG EXYNOS4212"
> default y
> depends on ARCH_EXYNOS4
> + select ARCH_HAS_BANDGAP
> select S5P_PM if PM
> select S5P_SLEEP if PM
> select SAMSUNG_DMADEV
> @@ -55,6 +57,7 @@ config SOC_EXYNOS4412
> bool "SAMSUNG EXYNOS4412"
> default y
> depends on ARCH_EXYNOS4
> + select ARCH_HAS_BANDGAP
> select SAMSUNG_DMADEV
> help
> Enable EXYNOS4412 SoC support
> @@ -63,6 +66,7 @@ config SOC_EXYNOS5250
> bool "SAMSUNG EXYNOS5250"
> default y
> depends on ARCH_EXYNOS5
> + select ARCH_HAS_BANDGAP
> select PM_GENERIC_DOMAINS if PM
> select S5P_PM if PM
> select S5P_SLEEP if PM
> @@ -76,6 +80,7 @@ config SOC_EXYNOS5440
> default y
> depends on ARCH_EXYNOS5
> select ARCH_HAS_OPP
> + select ARCH_HAS_BANDGAP
> select ARM_ARCH_TIMER
> select AUTO_ZRELADDR
> select PINCTRL
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This movement of files is done for easy maintenance and adding more
> new sensor's support for exynos platform easily . This will also help in
> bifurcating exynos common, sensor driver and sensor data related parts.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/Kconfig | 13 +++++--------
> drivers/thermal/Makefile | 2 +-
> drivers/thermal/samsung/Kconfig | 9 +++++++++
> drivers/thermal/samsung/Makefile | 4 ++++
> drivers/thermal/{ => samsung}/exynos_thermal.c | 0
> 5 files changed, 19 insertions(+), 9 deletions(-)
> create mode 100644 drivers/thermal/samsung/Kconfig
> create mode 100644 drivers/thermal/samsung/Makefile
> rename drivers/thermal/{ => samsung}/exynos_thermal.c (100%)
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index b13c2bc..ef10cf2 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -114,14 +114,6 @@ config KIRKWOOD_THERMAL
> Support for the Kirkwood thermal sensor driver into the Linux thermal
> framework. Only kirkwood 88F6282 and 88F6283 have this sensor.
>
> -config EXYNOS_THERMAL
> - tristate "Temperature sensor on Samsung EXYNOS"
> - depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
> - depends on CPU_THERMAL
> - help
> - If you say yes here you get support for TMU (Thermal Management
> - Unit) on SAMSUNG EXYNOS series of SoC.
> -
> config DOVE_THERMAL
> tristate "Temperature sensor on Marvell Dove SoCs"
> depends on ARCH_DOVE
> @@ -185,4 +177,9 @@ menu "Texas Instruments thermal drivers"
> source "drivers/thermal/ti-soc-thermal/Kconfig"
> endmenu
>
> +menu "Samsung thermal drivers"
> +depends on PLAT_SAMSUNG
> +source "drivers/thermal/samsung/Kconfig"
> +endmenu
> +
> endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 67184a2..1f27ada 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -17,7 +17,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
> obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
> obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
> obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> +obj-y += samsung/
> obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
> obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
> obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> new file mode 100644
> index 0000000..2d3d9dc
> --- /dev/null
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -0,0 +1,9 @@
> +config EXYNOS_THERMAL
> + tristate "Temperature sensor on Samsung EXYNOS"
> + depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
> + depends on CPU_THERMAL
> + help
> + If you say yes here you get support for TMU (Thermal Management
> + Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
> + the exynos thermal driver with the core thermal layer and cpu
> + cooling API's.
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> new file mode 100644
> index 0000000..1fe6d93
> --- /dev/null
> +++ b/drivers/thermal/samsung/Makefile
> @@ -0,0 +1,4 @@
> +#
> +# Samsung thermal specific Makefile
> +#
> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
> similarity index 100%
> rename from drivers/thermal/exynos_thermal.c
> rename to drivers/thermal/samsung/exynos_thermal.c
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch removes the dependency on CPU_THERMAL for compiling TMU driver.
> This is useful for cases when only TMU controller needs to be initialised
> without cpu cooling action.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
Please have a look on my comment on your patch 04. You may want to have
this dependency still on your core part.
> ---
> drivers/thermal/samsung/Kconfig | 1 -
> 1 files changed, 0 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index 883a8a8..2cf31ad 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -1,7 +1,6 @@
> config EXYNOS_THERMAL
> tristate "Temperature sensor on Samsung EXYNOS"
> depends on ARCH_HAS_BANDGAP
> - depends on CPU_THERMAL
> help
> If you say yes here you get support for TMU (Thermal Management
> Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code bifurcates exynos thermal implementation into common and sensor
> specific parts. The common thermal code interacts with core thermal layer and
> core cpufreq cooling parts and is independent of SOC specific driver. This
> change is needed to cleanly add support for new TMU sensors.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/Kconfig | 19 +-
> drivers/thermal/samsung/Makefile | 4 +-
> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
> 5 files changed, 490 insertions(+), 419 deletions(-)
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index 2cf31ad..f8100b1 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -1,8 +1,17 @@
> config EXYNOS_THERMAL
> - tristate "Temperature sensor on Samsung EXYNOS"
> + tristate "Exynos thermal management unit driver"
> depends on ARCH_HAS_BANDGAP
This is not really on this patch, but I think this one needs to depend
on CONFIG_OF too.
> help
> - If you say yes here you get support for TMU (Thermal Management
> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
> - the exynos thermal driver with the core thermal layer and cpu
> - cooling API's.
> + If you say yes here you get support for the TMU (Thermal Management
> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
> + the TMU, reports temperature and handles cooling action if defined.
> + This driver uses the exynos core thermal API's.
> +
> +config EXYNOS_THERMAL_CORE
> + bool "Core thermal framework support for EXYNOS SOC's"
> + depends on EXYNOS_THERMAL
> + help
> + If you say yes here you get support for EXYNOS TMU
> + (Thermal Management Unit) common registration/unregistration
> + functions to the core thermal layer and also to use the generic
> + cpu cooling API's.
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> index 1fe6d93..6227d4f 100644
> --- a/drivers/thermal/samsung/Makefile
> +++ b/drivers/thermal/samsung/Makefile
> @@ -1,4 +1,6 @@
> #
> # Samsung thermal specific Makefile
> #
> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
> +exynos_soc_thermal-y := exynos_thermal.o
> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
> index 03e4bbc..5293849 100644
> --- a/drivers/thermal/samsung/exynos_thermal.c
> +++ b/drivers/thermal/samsung/exynos_thermal.c
> @@ -21,23 +21,15 @@
> *
> */
>
> -#include <linux/module.h>
> -#include <linux/err.h>
> -#include <linux/kernel.h>
> -#include <linux/slab.h>
> -#include <linux/platform_device.h>
> -#include <linux/interrupt.h>
> #include <linux/clk.h>
> -#include <linux/workqueue.h>
> -#include <linux/sysfs.h>
> -#include <linux/kobject.h>
> #include <linux/io.h>
> -#include <linux/mutex.h>
> -#include <linux/platform_data/exynos_thermal.h>
> -#include <linux/thermal.h>
> -#include <linux/cpufreq.h>
> -#include <linux/cpu_cooling.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +
> +#include "exynos_thermal_common.h"
>
> /* Exynos generic registers */
> #define EXYNOS_TMU_REG_TRIMINFO 0x0
> @@ -88,16 +80,6 @@
> #define EFUSE_MIN_VALUE 40
> #define EFUSE_MAX_VALUE 100
>
> -/* In-kernel thermal framework related macros & definations */
> -#define SENSOR_NAME_LEN 16
> -#define MAX_TRIP_COUNT 8
> -#define MAX_COOLING_DEVICE 4
> -#define MAX_THRESHOLD_LEVS 4
> -
> -#define ACTIVE_INTERVAL 500
> -#define IDLE_INTERVAL 10000
> -#define MCELSIUS 1000
> -
> #ifdef CONFIG_THERMAL_EMULATION
> #define EXYNOS_EMUL_TIME 0x57F0
> #define EXYNOS_EMUL_TIME_SHIFT 16
> @@ -106,17 +88,6 @@
> #define EXYNOS_EMUL_ENABLE 0x1
> #endif /* CONFIG_THERMAL_EMULATION */
>
> -/* CPU Zone information */
> -#define PANIC_ZONE 4
> -#define WARN_ZONE 3
> -#define MONITOR_ZONE 2
> -#define SAFE_ZONE 1
> -
> -#define GET_ZONE(trip) (trip + 2)
> -#define GET_TRIP(zone) (zone - 2)
> -
> -#define EXYNOS_ZONE_COUNT 3
> -
> struct exynos_tmu_data {
> struct exynos_tmu_platform_data *pdata;
> struct resource *mem;
> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
> u8 temp_error1, temp_error2;
> };
>
> -struct thermal_trip_point_conf {
> - int trip_val[MAX_TRIP_COUNT];
> - int trip_count;
> - u8 trigger_falling;
> -};
> -
> -struct thermal_cooling_conf {
> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> - int freq_clip_count;
> -};
> -
> -struct thermal_sensor_conf {
> - char name[SENSOR_NAME_LEN];
> - int (*read_temperature)(void *data);
> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
> - struct thermal_trip_point_conf trip_data;
> - struct thermal_cooling_conf cooling_data;
> - void *private_data;
> -};
> -
> -struct exynos_thermal_zone {
> - enum thermal_device_mode mode;
> - struct thermal_zone_device *therm_dev;
> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> - unsigned int cool_dev_size;
> - struct platform_device *exynos4_dev;
> - struct thermal_sensor_conf *sensor_conf;
> - bool bind;
> -};
> -
> -static struct exynos_thermal_zone *th_zone;
> -static void exynos_unregister_thermal(void);
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> -
> -/* Get mode callback functions for thermal zone */
> -static int exynos_get_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode *mode)
> -{
> - if (th_zone)
> - *mode = th_zone->mode;
> - return 0;
> -}
> -
> -/* Set mode callback functions for thermal zone */
> -static int exynos_set_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode mode)
> -{
> - if (!th_zone->therm_dev) {
> - pr_notice("thermal zone not registered\n");
> - return 0;
> - }
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> -
> - if (mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling)
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = 0;
> -
> - mutex_unlock(&th_zone->therm_dev->lock);
> -
> - th_zone->mode = mode;
> - thermal_zone_device_update(th_zone->therm_dev);
> - pr_info("thermal polling set for duration=%d msec\n",
> - th_zone->therm_dev->polling_delay);
> - return 0;
> -}
> -
> -
> -/* Get trip type callback functions for thermal zone */
> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> - enum thermal_trip_type *type)
> -{
> - switch (GET_ZONE(trip)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - *type = THERMAL_TRIP_ACTIVE;
> - break;
> - case PANIC_ZONE:
> - *type = THERMAL_TRIP_CRITICAL;
> - break;
> - default:
> - return -EINVAL;
> - }
> - return 0;
> -}
> -
> -/* Get trip temperature callback functions for thermal zone */
> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> - unsigned long *temp)
> -{
> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> - return -EINVAL;
> -
> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> -
> - return 0;
> -}
> -
> -/* Get critical temperature callback functions for thermal zone */
> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - int ret;
> - /* Panic zone */
> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> - return ret;
> -}
> -
> -/* Bind callback functions for thermal zone */
> -static int exynos_bind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size, level;
> - struct freq_clip_table *tab_ptr, *clip_data;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_ptr == NULL || tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> - if (level == THERMAL_CSTATE_INVALID)
> - return 0;
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> - level, 0)) {
> - pr_err("error binding cdev inst %d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = true;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> -
> - return ret;
> -}
> -
> -/* Unbind callback functions for thermal zone */
> -static int exynos_unbind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - if (th_zone->bind == false)
> - return 0;
> -
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_unbind_cooling_device(thermal, i,
> - cdev)) {
> - pr_err("error unbinding cdev inst=%d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = false;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> - return ret;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_get_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - void *data;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - *temp = th_zone->sensor_conf->read_temperature(data);
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> - return 0;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> - unsigned long temp)
> -{
> - void *data;
> - int ret = -EINVAL;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - if (th_zone->sensor_conf->write_emul_temp)
> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> - return ret;
> -}
> -
> -/* Get the temperature trend */
> -static int exynos_get_trend(struct thermal_zone_device *thermal,
> - int trip, enum thermal_trend *trend)
> -{
> - int ret;
> - unsigned long trip_temp;
> -
> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> - if (ret < 0)
> - return ret;
> -
> - if (thermal->temperature >= trip_temp)
> - *trend = THERMAL_TREND_RAISE_FULL;
> - else
> - *trend = THERMAL_TREND_DROP_FULL;
> -
> - return 0;
> -}
> -/* Operation callback functions for thermal zone */
> -static struct thermal_zone_device_ops const exynos_dev_ops = {
> - .bind = exynos_bind,
> - .unbind = exynos_unbind,
> - .get_temp = exynos_get_temp,
> - .set_emul_temp = exynos_set_emul_temp,
> - .get_trend = exynos_get_trend,
> - .get_mode = exynos_get_mode,
> - .set_mode = exynos_set_mode,
> - .get_trip_type = exynos_get_trip_type,
> - .get_trip_temp = exynos_get_trip_temp,
> - .get_crit_temp = exynos_get_crit_temp,
> -};
> -
> -/*
> - * This function may be called from interrupt based temperature sensor
> - * when threshold is changed.
> - */
> -static void exynos_report_trigger(void)
> -{
> - unsigned int i;
> - char data[10];
> - char *envp[] = { data, NULL };
> -
> - if (!th_zone || !th_zone->therm_dev)
> - return;
> - if (th_zone->bind == false) {
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (!th_zone->cool_dev[i])
> - continue;
> - exynos_bind(th_zone->therm_dev,
> - th_zone->cool_dev[i]);
> - }
> - }
> -
> - thermal_zone_device_update(th_zone->therm_dev);
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> - /* Find the level for which trip happened */
> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> - if (th_zone->therm_dev->last_temperature <
> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> - break;
> - }
> -
> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling) {
> - if (i > 0)
> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - }
> -
> - snprintf(data, sizeof(data), "%u", i);
> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> - mutex_unlock(&th_zone->therm_dev->lock);
> -}
> -
> -/* Register with the in-kernel thermal management */
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> -{
> - int ret;
> - struct cpumask mask_val;
> -
> - if (!sensor_conf || !sensor_conf->read_temperature) {
> - pr_err("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> -
> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> - if (!th_zone)
> - return -ENOMEM;
> -
> - th_zone->sensor_conf = sensor_conf;
> - cpumask_set_cpu(0, &mask_val);
> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> - if (IS_ERR(th_zone->cool_dev[0])) {
> - pr_err("Failed to register cpufreq cooling device\n");
> - ret = -EINVAL;
> - goto err_unregister;
> - }
> - th_zone->cool_dev_size++;
> -
> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> - sensor_conf->trip_data.trigger_falling ?
> - 0 : IDLE_INTERVAL);
> -
> - if (IS_ERR(th_zone->therm_dev)) {
> - pr_err("Failed to register thermal zone device\n");
> - ret = PTR_ERR(th_zone->therm_dev);
> - goto err_unregister;
> - }
> - th_zone->mode = THERMAL_DEVICE_ENABLED;
> -
> - pr_info("Exynos: Kernel Thermal management registered\n");
> -
> - return 0;
> -
> -err_unregister:
> - exynos_unregister_thermal();
> - return ret;
> -}
> -
> -/* Un-Register with the in-kernel thermal management */
> -static void exynos_unregister_thermal(void)
> -{
> - int i;
> -
> - if (!th_zone)
> - return;
> -
> - if (th_zone->therm_dev)
> - thermal_zone_device_unregister(th_zone->therm_dev);
> -
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (th_zone->cool_dev[i])
> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> - }
> -
> - kfree(th_zone);
> - pr_info("Exynos: Kernel Thermal management unregistered\n");
> -}
> -
> /*
> * TMU treats temperature as a mapped temperature code.
> * The temperature is converted differently depending on the calibration type.
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> new file mode 100644
> index 0000000..92e50bc
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -0,0 +1,384 @@
> +/*
> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/cpu_cooling.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#include "exynos_thermal_common.h"
> +
> +struct exynos_thermal_zone {
> + enum thermal_device_mode mode;
> + struct thermal_zone_device *therm_dev;
> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> + unsigned int cool_dev_size;
> + struct platform_device *exynos4_dev;
> + struct thermal_sensor_conf *sensor_conf;
> + bool bind;
> +};
> +
> +static struct exynos_thermal_zone *th_zone;
> +
> +/* Get mode callback functions for thermal zone */
> +static int exynos_get_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode *mode)
> +{
> + if (th_zone)
> + *mode = th_zone->mode;
> + return 0;
> +}
> +
> +/* Set mode callback functions for thermal zone */
> +static int exynos_set_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode mode)
> +{
> + if (!th_zone->therm_dev) {
> + pr_notice("thermal zone not registered\n");
> + return 0;
> + }
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> +
> + if (mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling)
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = 0;
> +
> + mutex_unlock(&th_zone->therm_dev->lock);
> +
> + th_zone->mode = mode;
> + thermal_zone_device_update(th_zone->therm_dev);
> + pr_info("thermal polling set for duration=%d msec\n",
> + th_zone->therm_dev->polling_delay);
> + return 0;
> +}
> +
> +
> +/* Get trip type callback functions for thermal zone */
> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> + enum thermal_trip_type *type)
> +{
> + switch (GET_ZONE(trip)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + *type = THERMAL_TRIP_ACTIVE;
> + break;
> + case PANIC_ZONE:
> + *type = THERMAL_TRIP_CRITICAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +/* Get trip temperature callback functions for thermal zone */
> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> + unsigned long *temp)
> +{
> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> + return -EINVAL;
> +
> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> +
> + return 0;
> +}
> +
> +/* Get critical temperature callback functions for thermal zone */
> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + int ret;
> + /* Panic zone */
> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> + return ret;
> +}
> +
> +/* Bind callback functions for thermal zone */
> +static int exynos_bind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size, level;
> + struct freq_clip_table *tab_ptr, *clip_data;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_ptr == NULL || tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> + if (level == THERMAL_CSTATE_INVALID)
> + return 0;
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> + level, 0)) {
> + pr_err("error binding cdev inst %d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = true;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/* Unbind callback functions for thermal zone */
> +static int exynos_unbind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + if (th_zone->bind == false)
> + return 0;
> +
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_unbind_cooling_device(thermal, i,
> + cdev)) {
> + pr_err("error unbinding cdev inst=%d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = false;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> + return ret;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_get_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + void *data;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + *temp = th_zone->sensor_conf->read_temperature(data);
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> + return 0;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> + unsigned long temp)
> +{
> + void *data;
> + int ret = -EINVAL;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + if (th_zone->sensor_conf->write_emul_temp)
> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> + return ret;
> +}
> +
> +/* Get the temperature trend */
> +static int exynos_get_trend(struct thermal_zone_device *thermal,
> + int trip, enum thermal_trend *trend)
> +{
> + int ret;
> + unsigned long trip_temp;
> +
> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> + if (ret < 0)
> + return ret;
> +
> + if (thermal->temperature >= trip_temp)
> + *trend = THERMAL_TREND_RAISE_FULL;
> + else
> + *trend = THERMAL_TREND_DROP_FULL;
> +
> + return 0;
> +}
> +/* Operation callback functions for thermal zone */
> +static struct thermal_zone_device_ops const exynos_dev_ops = {
> + .bind = exynos_bind,
> + .unbind = exynos_unbind,
> + .get_temp = exynos_get_temp,
> + .set_emul_temp = exynos_set_emul_temp,
> + .get_trend = exynos_get_trend,
> + .get_mode = exynos_get_mode,
> + .set_mode = exynos_set_mode,
> + .get_trip_type = exynos_get_trip_type,
> + .get_trip_temp = exynos_get_trip_temp,
> + .get_crit_temp = exynos_get_crit_temp,
> +};
> +
> +/*
> + * This function may be called from interrupt based temperature sensor
> + * when threshold is changed.
> + */
> +void exynos_report_trigger(void)
> +{
> + unsigned int i;
> + char data[10];
> + char *envp[] = { data, NULL };
> +
> + if (!th_zone || !th_zone->therm_dev)
> + return;
> + if (th_zone->bind == false) {
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (!th_zone->cool_dev[i])
> + continue;
> + exynos_bind(th_zone->therm_dev,
> + th_zone->cool_dev[i]);
> + }
> + }
> +
> + thermal_zone_device_update(th_zone->therm_dev);
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> + /* Find the level for which trip happened */
> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> + if (th_zone->therm_dev->last_temperature <
> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> + break;
> + }
> +
> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling) {
> + if (i > 0)
> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + }
> +
> + snprintf(data, sizeof(data), "%u", i);
> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> + mutex_unlock(&th_zone->therm_dev->lock);
> +}
> +
> +/* Register with the in-kernel thermal management */
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> +{
> + int ret;
> + struct cpumask mask_val;
> +
> + if (!sensor_conf || !sensor_conf->read_temperature) {
> + pr_err("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> +
> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> + if (!th_zone)
> + return -ENOMEM;
> +
> + th_zone->sensor_conf = sensor_conf;
> + cpumask_set_cpu(0, &mask_val);
> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> + if (IS_ERR(th_zone->cool_dev[0])) {
> + pr_err("Failed to register cpufreq cooling device\n");
> + ret = -EINVAL;
> + goto err_unregister;
> + }
> + th_zone->cool_dev_size++;
> +
> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> + sensor_conf->trip_data.trigger_falling ?
> + 0 : IDLE_INTERVAL);
> +
> + if (IS_ERR(th_zone->therm_dev)) {
> + pr_err("Failed to register thermal zone device\n");
> + ret = PTR_ERR(th_zone->therm_dev);
> + goto err_unregister;
> + }
> + th_zone->mode = THERMAL_DEVICE_ENABLED;
> +
> + pr_info("Exynos: Kernel Thermal management registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + exynos_unregister_thermal();
> + return ret;
> +}
> +
> +/* Un-Register with the in-kernel thermal management */
> +void exynos_unregister_thermal(void)
> +{
> + int i;
> +
> + if (!th_zone)
> + return;
> +
> + if (th_zone->therm_dev)
> + thermal_zone_device_unregister(th_zone->therm_dev);
> +
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (th_zone->cool_dev[i])
> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> + }
> +
> + kfree(th_zone);
> + pr_info("Exynos: Kernel Thermal management unregistered\n");
> +}
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> new file mode 100644
> index 0000000..8df1848
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -0,0 +1,83 @@
> +/*
> + * exynos_thermal_common.h - Samsung EXYNOS common header file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifndef _EXYNOS_THERMAL_COMMON_H
> +#define _EXYNOS_THERMAL_COMMON_H
> +
> +/* In-kernel thermal framework related macros & definations */
> +#define SENSOR_NAME_LEN 16
> +#define MAX_TRIP_COUNT 8
> +#define MAX_COOLING_DEVICE 4
> +#define MAX_THRESHOLD_LEVS 4
> +
> +#define ACTIVE_INTERVAL 500
> +#define IDLE_INTERVAL 10000
> +#define MCELSIUS 1000
> +
> +/* CPU Zone information */
> +#define PANIC_ZONE 4
> +#define WARN_ZONE 3
> +#define MONITOR_ZONE 2
> +#define SAFE_ZONE 1
> +
> +#define GET_ZONE(trip) (trip + 2)
> +#define GET_TRIP(zone) (zone - 2)
> +
> +#define EXYNOS_ZONE_COUNT 3
> +
> +struct thermal_trip_point_conf {
> + int trip_val[MAX_TRIP_COUNT];
> + int trip_count;
> + unsigned char trigger_falling;
> +};
> +
> +struct thermal_cooling_conf {
> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> + int freq_clip_count;
> +};
> +
> +struct thermal_sensor_conf {
> + char name[SENSOR_NAME_LEN];
> + int (*read_temperature)(void *data);
> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
> + struct thermal_trip_point_conf trip_data;
> + struct thermal_cooling_conf cooling_data;
> + void *private_data;
> +};
> +
> +/*Functions used exynos based thermal sensor driver*/
> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
> +void exynos_unregister_thermal(void);
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> +void exynos_report_trigger(void);
> +#else
> +static inline void
> +exynos_unregister_thermal(void) { return; }
> +
> +static inline int
> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
> +
> +static inline void
> +exynos_report_trigger(void) { return; }
> +
> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch renames and moves include/linux/platform_data/exynos_thermal.h to
> drivers/thermal/samsung/exynos_tmu.h. This file movement is needed as exynos
> SOC's are not supporting non-DT based platforms and this file now just contains
> exynos tmu driver related definations.
> Also struct freq_clip_table is now moved to exynos_thermal_common.c as it fixes
> the compilation issue occuring because now this new tmu header file is included
> in tmu driver c file and not in the common thermal header file.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 1 -
> drivers/thermal/samsung/exynos_thermal_common.h | 15 ++++++++++++
> drivers/thermal/samsung/exynos_tmu.c | 2 +-
> .../thermal/samsung/exynos_tmu.h | 24 ++++---------------
> 4 files changed, 21 insertions(+), 21 deletions(-)
> rename include/linux/platform_data/exynos_thermal.h => drivers/thermal/samsung/exynos_tmu.h (84%)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index 92e50bc..dd49c9f 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -21,7 +21,6 @@
> */
>
> #include <linux/cpu_cooling.h>
> -#include <linux/platform_data/exynos_thermal.h>
> #include <linux/slab.h>
> #include <linux/thermal.h>
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index 8df1848..068f56c 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -44,6 +44,21 @@
>
> #define EXYNOS_ZONE_COUNT 3
>
> +/**
> + * struct freq_clip_table
> + * @freq_clip_max: maximum frequency allowed for this cooling state.
> + * @temp_level: Temperature level at which the temperature clipping will
> + * happen.
> + * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
> + *
> + * This structure is required to be filled and passed to the
> + * cpufreq_cooling_unregister function.
> + */
> +struct freq_clip_table {
> + unsigned int freq_clip_max;
> + unsigned int temp_level;
> + const struct cpumask *mask_val;
> +};
> struct thermal_trip_point_conf {
> int trip_val[MAX_TRIP_COUNT];
> int trip_count;
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 22a8874..6aa2fd2 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -27,9 +27,9 @@
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/platform_device.h>
> -#include <linux/platform_data/exynos_thermal.h>
>
> #include "exynos_thermal_common.h"
> +#include "exynos_tmu.h"
>
> /* Exynos generic registers */
> #define EXYNOS_TMU_REG_TRIMINFO 0x0
> diff --git a/include/linux/platform_data/exynos_thermal.h b/drivers/thermal/samsung/exynos_tmu.h
> similarity index 84%
> rename from include/linux/platform_data/exynos_thermal.h
> rename to drivers/thermal/samsung/exynos_tmu.h
> index da7e627..9e0f887 100644
> --- a/include/linux/platform_data/exynos_thermal.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -1,8 +1,9 @@
> /*
> - * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
> + * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
> *
> * Copyright (C) 2011 Samsung Electronics
> * Donggeun Kim <[email protected]>
> + * Amit Daniel Kachhap <[email protected]>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> @@ -19,8 +20,8 @@
> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> */
>
> -#ifndef _LINUX_EXYNOS_THERMAL_H
> -#define _LINUX_EXYNOS_THERMAL_H
> +#ifndef _EXYNOS_TMU_H
> +#define _EXYNOS_TMU_H
> #include <linux/cpu_cooling.h>
>
> enum calibration_type {
> @@ -33,21 +34,6 @@ enum soc_type {
> SOC_ARCH_EXYNOS4210 = 1,
> SOC_ARCH_EXYNOS,
> };
> -/**
> - * struct freq_clip_table
> - * @freq_clip_max: maximum frequency allowed for this cooling state.
> - * @temp_level: Temperature level at which the temperature clipping will
> - * happen.
> - * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
> - *
> - * This structure is required to be filled and passed to the
> - * cpufreq_cooling_unregister function.
> - */
> -struct freq_clip_table {
> - unsigned int freq_clip_max;
> - unsigned int temp_level;
> - const struct cpumask *mask_val;
> -};
>
> /**
> * struct exynos_tmu_platform_data
> @@ -116,4 +102,4 @@ struct exynos_tmu_platform_data {
> struct freq_clip_table freq_tab[4];
Because you have this struct right here, you need still to have:
+#include "exynos_thermal_common.h"
in your include list of exynos_tmu.h (this file).
A part from this minor issue, you can add my acked:
Acked-by: Eduardo Valentin <[email protected]>
> unsigned int freq_tab_count;
> };
> -#endif /* _LINUX_EXYNOS_THERMAL_H */
> +#endif /* _EXYNOS_TMU_H */
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 19-06-2013 15:18, Eduardo Valentin wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch renames and moves include/linux/platform_data/exynos_thermal.h to
>> drivers/thermal/samsung/exynos_tmu.h. This file movement is needed as exynos
>> SOC's are not supporting non-DT based platforms and this file now just contains
>> exynos tmu driver related definations.
>> Also struct freq_clip_table is now moved to exynos_thermal_common.c as it fixes
>> the compilation issue occuring because now this new tmu header file is included
>> in tmu driver c file and not in the common thermal header file.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.c | 1 -
>> drivers/thermal/samsung/exynos_thermal_common.h | 15 ++++++++++++
>> drivers/thermal/samsung/exynos_tmu.c | 2 +-
>> .../thermal/samsung/exynos_tmu.h | 24 ++++---------------
>> 4 files changed, 21 insertions(+), 21 deletions(-)
>> rename include/linux/platform_data/exynos_thermal.h => drivers/thermal/samsung/exynos_tmu.h (84%)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> index 92e50bc..dd49c9f 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -21,7 +21,6 @@
>> */
>>
>> #include <linux/cpu_cooling.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>> #include <linux/slab.h>
>> #include <linux/thermal.h>
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 8df1848..068f56c 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -44,6 +44,21 @@
>>
>> #define EXYNOS_ZONE_COUNT 3
>>
>> +/**
>> + * struct freq_clip_table
>> + * @freq_clip_max: maximum frequency allowed for this cooling state.
>> + * @temp_level: Temperature level at which the temperature clipping will
>> + * happen.
>> + * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>> + *
>> + * This structure is required to be filled and passed to the
>> + * cpufreq_cooling_unregister function.
>> + */
>> +struct freq_clip_table {
>> + unsigned int freq_clip_max;
>> + unsigned int temp_level;
>> + const struct cpumask *mask_val;
>> +};
Another minor: add an empty line here.
>> struct thermal_trip_point_conf {
>> int trip_val[MAX_TRIP_COUNT];
>> int trip_count;
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 22a8874..6aa2fd2 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -27,9 +27,9 @@
>> #include <linux/module.h>
>> #include <linux/of.h>
>> #include <linux/platform_device.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>>
>> #include "exynos_thermal_common.h"
>> +#include "exynos_tmu.h"
>>
>> /* Exynos generic registers */
>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>> diff --git a/include/linux/platform_data/exynos_thermal.h b/drivers/thermal/samsung/exynos_tmu.h
>> similarity index 84%
>> rename from include/linux/platform_data/exynos_thermal.h
>> rename to drivers/thermal/samsung/exynos_tmu.h
>> index da7e627..9e0f887 100644
>> --- a/include/linux/platform_data/exynos_thermal.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -1,8 +1,9 @@
>> /*
>> - * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
>> + * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
>> *
>> * Copyright (C) 2011 Samsung Electronics
>> * Donggeun Kim <[email protected]>
>> + * Amit Daniel Kachhap <[email protected]>
>> *
>> * This program is free software; you can redistribute it and/or modify
>> * it under the terms of the GNU General Public License as published by
>> @@ -19,8 +20,8 @@
>> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> */
>>
>> -#ifndef _LINUX_EXYNOS_THERMAL_H
>> -#define _LINUX_EXYNOS_THERMAL_H
>> +#ifndef _EXYNOS_TMU_H
>> +#define _EXYNOS_TMU_H
>> #include <linux/cpu_cooling.h>
>>
>> enum calibration_type {
>> @@ -33,21 +34,6 @@ enum soc_type {
>> SOC_ARCH_EXYNOS4210 = 1,
>> SOC_ARCH_EXYNOS,
>> };
>> -/**
>> - * struct freq_clip_table
>> - * @freq_clip_max: maximum frequency allowed for this cooling state.
>> - * @temp_level: Temperature level at which the temperature clipping will
>> - * happen.
>> - * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>> - *
>> - * This structure is required to be filled and passed to the
>> - * cpufreq_cooling_unregister function.
>> - */
>> -struct freq_clip_table {
>> - unsigned int freq_clip_max;
>> - unsigned int temp_level;
>> - const struct cpumask *mask_val;
>> -};
>>
>> /**
>> * struct exynos_tmu_platform_data
>> @@ -116,4 +102,4 @@ struct exynos_tmu_platform_data {
>> struct freq_clip_table freq_tab[4];
>
> Because you have this struct right here, you need still to have:
> +#include "exynos_thermal_common.h"
>
> in your include list of exynos_tmu.h (this file).
>
> A part from this minor issue, you can add my acked:
>
> Acked-by: Eduardo Valentin <[email protected]>
>
>> unsigned int freq_tab_count;
>> };
>> -#endif /* _LINUX_EXYNOS_THERMAL_H */
>> +#endif /* _EXYNOS_TMU_H */
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
Rui,
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code splits the exynos tmu driver code into SOC specific data parts.
> This will simplify adding new SOC specific data to the same TMU controller.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
This patch looks good to me, you may want to add my:
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/Kconfig | 3 +-
> drivers/thermal/samsung/Makefile | 1 +
> drivers/thermal/samsung/exynos_tmu.c | 67 ++-----------------------
> drivers/thermal/samsung/exynos_tmu_data.c | 78 +++++++++++++++++++++++++++++
> drivers/thermal/samsung/exynos_tmu_data.h | 40 +++++++++++++++
> 5 files changed, 125 insertions(+), 64 deletions(-)
> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.c
> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.h
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index f8100b1..b653f15 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -5,7 +5,8 @@ config EXYNOS_THERMAL
> If you say yes here you get support for the TMU (Thermal Management
> Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
> the TMU, reports temperature and handles cooling action if defined.
> - This driver uses the exynos core thermal API's.
> + This driver uses the exynos core thermal API's and TMU configuration
> + data from the supported soc's.
>
> config EXYNOS_THERMAL_CORE
> bool "Core thermal framework support for EXYNOS SOC's"
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> index 22528d6..c09d830 100644
> --- a/drivers/thermal/samsung/Makefile
> +++ b/drivers/thermal/samsung/Makefile
> @@ -3,4 +3,5 @@
> #
> obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> exynos_thermal-y := exynos_tmu.o
> +exynos_thermal-y += exynos_tmu_data.o
> exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 6aa2fd2..5df04a1 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -30,6 +30,7 @@
>
> #include "exynos_thermal_common.h"
> #include "exynos_tmu.h"
> +#include "exynos_tmu_data.h"
>
> /* Exynos generic registers */
> #define EXYNOS_TMU_REG_TRIMINFO 0x0
> @@ -381,66 +382,6 @@ static struct thermal_sensor_conf exynos_sensor_conf = {
> .write_emul_temp = exynos_tmu_set_emulation,
> };
>
> -#if defined(CONFIG_CPU_EXYNOS4210)
> -static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> - .threshold = 80,
> - .trigger_levels[0] = 5,
> - .trigger_levels[1] = 20,
> - .trigger_levels[2] = 30,
> - .trigger_level0_en = 1,
> - .trigger_level1_en = 1,
> - .trigger_level2_en = 1,
> - .trigger_level3_en = 0,
> - .gain = 15,
> - .reference_voltage = 7,
> - .cal_type = TYPE_ONE_POINT_TRIMMING,
> - .freq_tab[0] = {
> - .freq_clip_max = 800 * 1000,
> - .temp_level = 85,
> - },
> - .freq_tab[1] = {
> - .freq_clip_max = 200 * 1000,
> - .temp_level = 100,
> - },
> - .freq_tab_count = 2,
> - .type = SOC_ARCH_EXYNOS4210,
> -};
> -#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
> -#else
> -#define EXYNOS4210_TMU_DRV_DATA (NULL)
> -#endif
> -
> -#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
> -static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
> - .threshold_falling = 10,
> - .trigger_levels[0] = 85,
> - .trigger_levels[1] = 103,
> - .trigger_levels[2] = 110,
> - .trigger_level0_en = 1,
> - .trigger_level1_en = 1,
> - .trigger_level2_en = 1,
> - .trigger_level3_en = 0,
> - .gain = 8,
> - .reference_voltage = 16,
> - .noise_cancel_mode = 4,
> - .cal_type = TYPE_ONE_POINT_TRIMMING,
> - .efuse_value = 55,
> - .freq_tab[0] = {
> - .freq_clip_max = 800 * 1000,
> - .temp_level = 85,
> - },
> - .freq_tab[1] = {
> - .freq_clip_max = 200 * 1000,
> - .temp_level = 103,
> - },
> - .freq_tab_count = 2,
> - .type = SOC_ARCH_EXYNOS,
> -};
> -#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
> -#else
> -#define EXYNOS_TMU_DRV_DATA (NULL)
> -#endif
> -
> #ifdef CONFIG_OF
> static const struct of_device_id exynos_tmu_match[] = {
> {
> @@ -449,11 +390,11 @@ static const struct of_device_id exynos_tmu_match[] = {
> },
> {
> .compatible = "samsung,exynos4412-tmu",
> - .data = (void *)EXYNOS_TMU_DRV_DATA,
> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
> },
> {
> .compatible = "samsung,exynos5250-tmu",
> - .data = (void *)EXYNOS_TMU_DRV_DATA,
> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
> },
> {},
> };
> @@ -467,7 +408,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = {
> },
> {
> .name = "exynos5250-tmu",
> - .driver_data = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
> + .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
> },
> { },
> };
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> new file mode 100644
> index 0000000..13a60ca
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -0,0 +1,78 @@
> +/*
> + * exynos_tmu_data.c - Samsung EXYNOS tmu data file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include "exynos_thermal_common.h"
> +#include "exynos_tmu.h"
> +
> +#if defined(CONFIG_CPU_EXYNOS4210)
> +struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> + .threshold = 80,
> + .trigger_levels[0] = 5,
> + .trigger_levels[1] = 20,
> + .trigger_levels[2] = 30,
> + .trigger_level0_en = 1,
> + .trigger_level1_en = 1,
> + .trigger_level2_en = 1,
> + .trigger_level3_en = 0,
> + .gain = 15,
> + .reference_voltage = 7,
> + .cal_type = TYPE_ONE_POINT_TRIMMING,
> + .freq_tab[0] = {
> + .freq_clip_max = 800 * 1000,
> + .temp_level = 85,
> + },
> + .freq_tab[1] = {
> + .freq_clip_max = 200 * 1000,
> + .temp_level = 100,
> + },
> + .freq_tab_count = 2,
> + .type = SOC_ARCH_EXYNOS4210,
> +};
> +#endif
> +
> +#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
> +struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> + .threshold_falling = 10,
> + .trigger_levels[0] = 85,
> + .trigger_levels[1] = 103,
> + .trigger_levels[2] = 110,
> + .trigger_level0_en = 1,
> + .trigger_level1_en = 1,
> + .trigger_level2_en = 1,
> + .trigger_level3_en = 0,
> + .gain = 8,
> + .reference_voltage = 16,
> + .noise_cancel_mode = 4,
> + .cal_type = TYPE_ONE_POINT_TRIMMING,
> + .efuse_value = 55,
> + .freq_tab[0] = {
> + .freq_clip_max = 800 * 1000,
> + .temp_level = 85,
> + },
> + .freq_tab[1] = {
> + .freq_clip_max = 200 * 1000,
> + .temp_level = 103,
> + },
> + .freq_tab_count = 2,
> + .type = SOC_ARCH_EXYNOS,
> +};
> +#endif
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> new file mode 100644
> index 0000000..b7835fe
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -0,0 +1,40 @@
> +/*
> + * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifndef _EXYNOS_TMU_DATA_H
> +#define _EXYNOS_TMU_DATA_H
> +
> +#if defined(CONFIG_CPU_EXYNOS4210)
> +extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
> +#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
> +#else
> +#define EXYNOS4210_TMU_DRV_DATA (NULL)
> +#endif
> +
> +#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
> +extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
> +#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
> +#else
> +#define EXYNOS5250_TMU_DRV_DATA (NULL)
> +#endif
> +
> +#endif /*_EXYNOS_TMU_DATA_H*/
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 19-06-2013 15:35, Eduardo Valentin wrote:
> Rui,
>
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This code splits the exynos tmu driver code into SOC specific data parts.
>> This will simplify adding new SOC specific data to the same TMU controller.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>
> This patch looks good to me, you may want to add my:
>
> Acked-by: Eduardo Valentin <[email protected]>
Yet another minor before adding my ack, sorry this one almost fell into
the cracks (see below):
>
>> ---
>> drivers/thermal/samsung/Kconfig | 3 +-
>> drivers/thermal/samsung/Makefile | 1 +
>> drivers/thermal/samsung/exynos_tmu.c | 67 ++-----------------------
>> drivers/thermal/samsung/exynos_tmu_data.c | 78 +++++++++++++++++++++++++++++
>> drivers/thermal/samsung/exynos_tmu_data.h | 40 +++++++++++++++
>> 5 files changed, 125 insertions(+), 64 deletions(-)
>> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.c
>> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.h
>>
>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>> index f8100b1..b653f15 100644
>> --- a/drivers/thermal/samsung/Kconfig
>> +++ b/drivers/thermal/samsung/Kconfig
>> @@ -5,7 +5,8 @@ config EXYNOS_THERMAL
>> If you say yes here you get support for the TMU (Thermal Management
>> Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>> the TMU, reports temperature and handles cooling action if defined.
>> - This driver uses the exynos core thermal API's.
>> + This driver uses the exynos core thermal API's and TMU configuration
>> + data from the supported soc's.
>>
>> config EXYNOS_THERMAL_CORE
>> bool "Core thermal framework support for EXYNOS SOC's"
>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>> index 22528d6..c09d830 100644
>> --- a/drivers/thermal/samsung/Makefile
>> +++ b/drivers/thermal/samsung/Makefile
>> @@ -3,4 +3,5 @@
>> #
>> obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>> exynos_thermal-y := exynos_tmu.o
>> +exynos_thermal-y += exynos_tmu_data.o
>> exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 6aa2fd2..5df04a1 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -30,6 +30,7 @@
>>
>> #include "exynos_thermal_common.h"
>> #include "exynos_tmu.h"
>> +#include "exynos_tmu_data.h"
>>
>> /* Exynos generic registers */
>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>> @@ -381,66 +382,6 @@ static struct thermal_sensor_conf exynos_sensor_conf = {
>> .write_emul_temp = exynos_tmu_set_emulation,
>> };
>>
>> -#if defined(CONFIG_CPU_EXYNOS4210)
>> -static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> - .threshold = 80,
>> - .trigger_levels[0] = 5,
>> - .trigger_levels[1] = 20,
>> - .trigger_levels[2] = 30,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> - .gain = 15,
>> - .reference_voltage = 7,
>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>> - .freq_tab[0] = {
>> - .freq_clip_max = 800 * 1000,
>> - .temp_level = 85,
>> - },
>> - .freq_tab[1] = {
>> - .freq_clip_max = 200 * 1000,
>> - .temp_level = 100,
>> - },
>> - .freq_tab_count = 2,
>> - .type = SOC_ARCH_EXYNOS4210,
>> -};
>> -#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>> -#else
>> -#define EXYNOS4210_TMU_DRV_DATA (NULL)
>> -#endif
>> -
>> -#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
>> -static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
>> - .threshold_falling = 10,
>> - .trigger_levels[0] = 85,
>> - .trigger_levels[1] = 103,
>> - .trigger_levels[2] = 110,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> - .gain = 8,
>> - .reference_voltage = 16,
>> - .noise_cancel_mode = 4,
>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>> - .efuse_value = 55,
>> - .freq_tab[0] = {
>> - .freq_clip_max = 800 * 1000,
>> - .temp_level = 85,
>> - },
>> - .freq_tab[1] = {
>> - .freq_clip_max = 200 * 1000,
>> - .temp_level = 103,
>> - },
>> - .freq_tab_count = 2,
>> - .type = SOC_ARCH_EXYNOS,
>> -};
>> -#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
>> -#else
>> -#define EXYNOS_TMU_DRV_DATA (NULL)
>> -#endif
>> -
>> #ifdef CONFIG_OF
>> static const struct of_device_id exynos_tmu_match[] = {
>> {
>> @@ -449,11 +390,11 @@ static const struct of_device_id exynos_tmu_match[] = {
>> },
>> {
>> .compatible = "samsung,exynos4412-tmu",
>> - .data = (void *)EXYNOS_TMU_DRV_DATA,
>> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>> },
>> {
>> .compatible = "samsung,exynos5250-tmu",
>> - .data = (void *)EXYNOS_TMU_DRV_DATA,
>> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>> },
>> {},
>> };
>> @@ -467,7 +408,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = {
>> },
>> {
>> .name = "exynos5250-tmu",
>> - .driver_data = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
>> + .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
>> },
>> { },
>> };
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>> new file mode 100644
>> index 0000000..13a60ca
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * exynos_tmu_data.c - Samsung EXYNOS tmu data file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#include "exynos_thermal_common.h"
You have to:
+#include "exynos_tmu_data.h"
Otherwise, you will get:
CC [M] drivers/thermal/samsung/exynos_tmu.o
drivers/thermal/samsung/exynos_tmu_data.c:27:39: warning: symbol
'exynos4210_default_tmu_data' was not declared. Should it be static?
drivers/thermal/samsung/exynos_tmu_data.c:53:39: warning: symbol
'exynos5250_default_tmu_data' was not declared. Should it be static?
>> +#include "exynos_tmu.h"
>> +
>> +#if defined(CONFIG_CPU_EXYNOS4210)
>> +struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> + .threshold = 80,
>> + .trigger_levels[0] = 5,
>> + .trigger_levels[1] = 20,
>> + .trigger_levels[2] = 30,
>> + .trigger_level0_en = 1,
>> + .trigger_level1_en = 1,
>> + .trigger_level2_en = 1,
>> + .trigger_level3_en = 0,
>> + .gain = 15,
>> + .reference_voltage = 7,
>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>> + .freq_tab[0] = {
>> + .freq_clip_max = 800 * 1000,
>> + .temp_level = 85,
>> + },
>> + .freq_tab[1] = {
>> + .freq_clip_max = 200 * 1000,
>> + .temp_level = 100,
>> + },
>> + .freq_tab_count = 2,
>> + .type = SOC_ARCH_EXYNOS4210,
>> +};
>> +#endif
>> +
>> +#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
>> +struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>> + .threshold_falling = 10,
>> + .trigger_levels[0] = 85,
>> + .trigger_levels[1] = 103,
>> + .trigger_levels[2] = 110,
>> + .trigger_level0_en = 1,
>> + .trigger_level1_en = 1,
>> + .trigger_level2_en = 1,
>> + .trigger_level3_en = 0,
>> + .gain = 8,
>> + .reference_voltage = 16,
>> + .noise_cancel_mode = 4,
>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>> + .efuse_value = 55,
>> + .freq_tab[0] = {
>> + .freq_clip_max = 800 * 1000,
>> + .temp_level = 85,
>> + },
>> + .freq_tab[1] = {
>> + .freq_clip_max = 200 * 1000,
>> + .temp_level = 103,
>> + },
>> + .freq_tab_count = 2,
>> + .type = SOC_ARCH_EXYNOS,
>> +};
>> +#endif
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>> new file mode 100644
>> index 0000000..b7835fe
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>> @@ -0,0 +1,40 @@
>> +/*
>> + * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#ifndef _EXYNOS_TMU_DATA_H
>> +#define _EXYNOS_TMU_DATA_H
>> +
>> +#if defined(CONFIG_CPU_EXYNOS4210)
>> +extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
>> +#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>> +#else
>> +#define EXYNOS4210_TMU_DRV_DATA (NULL)
>> +#endif
>> +
>> +#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
>> +extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
>> +#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
>> +#else
>> +#define EXYNOS5250_TMU_DRV_DATA (NULL)
>> +#endif
>> +
>> +#endif /*_EXYNOS_TMU_DATA_H*/
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds some extra register bitfield definations and cleans
> up the code to prepare for moving register macros and definations inside
> the TMU data section.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 62 +++++++++++++++++++++++++---------
> 1 files changed, 46 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 5df04a1..fa33a48 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -43,9 +43,12 @@
>
> #define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
> #define EXYNOS_TMU_GAIN_SHIFT 8
> +#define EXYNOS_TMU_GAIN_MASK 0xf
> #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
> -#define EXYNOS_TMU_CORE_ON 3
> -#define EXYNOS_TMU_CORE_OFF 2
> +#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
> +#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
> +#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
> +#define EXYNOS_TMU_CORE_EN_SHIFT 0
> #define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>
> /* Exynos4210 specific registers */
> @@ -63,6 +66,7 @@
> #define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
> #define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
> #define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
> +#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
> #define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
>
> /* Exynos5250 and Exynos4412 specific registers */
> @@ -72,17 +76,30 @@
> #define EXYNOS_EMUL_CON 0x80
>
> #define EXYNOS_TRIMINFO_RELOAD 0x1
> +#define EXYNOS_TRIMINFO_SHIFT 0x0
> +#define EXYNOS_TMU_RISE_INT_MASK 0x111
> +#define EXYNOS_TMU_RISE_INT_SHIFT 0
> +#define EXYNOS_TMU_FALL_INT_MASK 0x111
> +#define EXYNOS_TMU_FALL_INT_SHIFT 12
> #define EXYNOS_TMU_CLEAR_RISE_INT 0x111
> #define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
> -#define EXYNOS_MUX_ADDR_VALUE 6
> -#define EXYNOS_MUX_ADDR_SHIFT 20
> #define EXYNOS_TMU_TRIP_MODE_SHIFT 13
> +#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
> +
> +#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
> +#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
> +#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
> +#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
> +#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
> +#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
> +#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>
> #define EFUSE_MIN_VALUE 40
> #define EFUSE_MAX_VALUE 100
>
> #ifdef CONFIG_THERMAL_EMULATION
> #define EXYNOS_EMUL_TIME 0x57F0
> +#define EXYNOS_EMUL_TIME_MASK 0xffff
> #define EXYNOS_EMUL_TIME_SHIFT 16
> #define EXYNOS_EMUL_DATA_SHIFT 8
> #define EXYNOS_EMUL_DATA_MASK 0xFF
> @@ -261,24 +278,37 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
> - pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
> + con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
>
> - if (data->soc == SOC_ARCH_EXYNOS) {
> - con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
> - con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
> + if (pdata->reference_voltage) {
> + con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
> + EXYNOS_TMU_REF_VOLTAGE_SHIFT);
> + con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
> + }
> +
> + if (pdata->gain) {
> + con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
> + con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
> + }
> +
> + if (pdata->noise_cancel_mode) {
> + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
> + EXYNOS_TMU_TRIP_MODE_SHIFT);
> + con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
> }
>
> if (on) {
> - con |= EXYNOS_TMU_CORE_ON;
Before, in order to turn core on you had:
con = con | 3;
now you do:
con = con | (1 << 0);
To me, before you would set bit 1 and 0, now you set bit 0.
> - interrupt_en = pdata->trigger_level3_en << 12 |
> - pdata->trigger_level2_en << 8 |
> - pdata->trigger_level1_en << 4 |
> - pdata->trigger_level0_en;
> + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> + interrupt_en =
> + pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
> + pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
> + pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
> + pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
> if (pdata->threshold_falling)
> - interrupt_en |= interrupt_en << 16;
> + interrupt_en |=
> + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
> } else {
> - con |= EXYNOS_TMU_CORE_OFF;
> + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
Before, in order to turno core off you had:
con = con | 2;
now you do:
con = con & ~(1 << 0);
To me, before you would set bit 2, now you clear bit 0.
Using the approach on this patch looks correct to me if you have 1 bit
core_en for instance.
so, Is this a fix?
Just to be clear, is this what you want ?
> interrupt_en = 0; /* Disable all interrupts */
> }
> writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
> trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
> trigger_enable in the TMU platform data structure. Also the driver is modified
> to use the data passed by these new platform memebers instead of the constant
> macros. All these changes helps in separating the SOC specific data part from
> the TMU driver.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
> drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
> drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
> drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
> 4 files changed, 86 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index 068f56c..fd789a5 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -44,6 +44,13 @@
>
> #define EXYNOS_ZONE_COUNT 3
>
> +enum trigger_type {
> + THROTTLE_ACTIVE = 1,
> + THROTTLE_PASSIVE,
> + SW_TRIP,
> + HW_TRIP,
> +};
> +
> /**
> * struct freq_clip_table
> * @freq_clip_max: maximum frequency allowed for this cooling state.
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index fa33a48..401ec98 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -49,7 +49,6 @@
> #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
> #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
> #define EXYNOS_TMU_CORE_EN_SHIFT 0
> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>
> /* Exynos4210 specific registers */
> #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
> @@ -94,9 +93,6 @@
> #define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
> #define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>
> -#define EFUSE_MIN_VALUE 40
> -#define EFUSE_MAX_VALUE 100
> -
> #ifdef CONFIG_THERMAL_EMULATION
> #define EXYNOS_EMUL_TIME 0x57F0
> #define EXYNOS_EMUL_TIME_MASK 0xffff
> @@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>
> switch (pdata->cal_type) {
> case TYPE_TWO_POINT_TRIMMING:
> - temp_code = (temp - 25) *
> - (data->temp_error2 - data->temp_error1) /
> - (85 - 25) + data->temp_error1;
> + temp_code = (temp - pdata->first_point_trim) *
> + (data->temp_error2 - data->temp_error1) /
> + (pdata->second_point_trim - pdata->first_point_trim) +
> + data->temp_error1;
> break;
> case TYPE_ONE_POINT_TRIMMING:
> - temp_code = temp + data->temp_error1 - 25;
> + temp_code = temp + data->temp_error1 - pdata->first_point_trim;
> break;
> default:
> - temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
> + temp_code = temp + pdata->default_temp_offset;
> break;
> }
> out:
> @@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>
> switch (pdata->cal_type) {
> case TYPE_TWO_POINT_TRIMMING:
> - temp = (temp_code - data->temp_error1) * (85 - 25) /
> - (data->temp_error2 - data->temp_error1) + 25;
> + temp = (temp_code - data->temp_error1) *
> + (pdata->second_point_trim - pdata->first_point_trim) /
> + (data->temp_error2 - data->temp_error1) +
> + pdata->first_point_trim;
> break;
> case TYPE_ONE_POINT_TRIMMING:
> - temp = temp_code - data->temp_error1 + 25;
> + temp = temp_code - data->temp_error1 + pdata->first_point_trim;
> break;
> default:
> - temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
> + temp = temp_code - pdata->default_temp_offset;
> break;
> }
> out:
> @@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
> data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
>
> - if ((EFUSE_MIN_VALUE > data->temp_error1) ||
> - (data->temp_error1 > EFUSE_MAX_VALUE) ||
> + if ((pdata->min_efuse_value > data->temp_error1) ||
> + (data->temp_error1 > pdata->max_efuse_value) ||
> (data->temp_error2 != 0))
> data->temp_error1 = pdata->efuse_value;
>
> @@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
> if (on) {
> con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> interrupt_en =
> - pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
> - pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
> - pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
> - pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
> + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
> + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
> + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
> + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
> if (pdata->threshold_falling)
> interrupt_en |=
> interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
> @@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>
> /* Register the sensor with thermal management interface */
> (&exynos_sensor_conf)->private_data = data;
> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
> - pdata->trigger_level1_en + pdata->trigger_level2_en +
> - pdata->trigger_level3_en;
> + exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
> + pdata->trigger_enable[1] + pdata->trigger_enable[2]+
> + pdata->trigger_enable[3];
>
> for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
> exynos_sensor_conf.trip_data.trip_val[i] =
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 9e0f887..45c697d 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -30,6 +30,11 @@ enum calibration_type {
> TYPE_NONE,
> };
>
> +enum calibration_mode {
> + SW_MODE,
> + HW_MODE,
> +};
> +
> enum soc_type {
> SOC_ARCH_EXYNOS4210 = 1,
> SOC_ARCH_EXYNOS,
> @@ -55,18 +60,15 @@ enum soc_type {
> * 3: temperature for trigger_level3 interrupt
> * condition for trigger_level3 interrupt:
> * current temperature > threshold + trigger_levels[3]
> - * @trigger_level0_en:
> - * 1 = enable trigger_level0 interrupt,
> - * 0 = disable trigger_level0 interrupt
> - * @trigger_level1_en:
> - * 1 = enable trigger_level1 interrupt,
> - * 0 = disable trigger_level1 interrupt
> - * @trigger_level2_en:
> - * 1 = enable trigger_level2 interrupt,
> - * 0 = disable trigger_level2 interrupt
> - * @trigger_level3_en:
> - * 1 = enable trigger_level3 interrupt,
> - * 0 = disable trigger_level3 interrupt
> + * @trigger_type: defines the type of trigger. Possible values are,
> + * THROTTLE_ACTIVE trigger type
> + * THROTTLE_PASSIVE trigger type
> + * SW_TRIP trigger type
> + * HW_TRIP
> + * @trigger_enable[]: array to denote which trigger levels are enabled.
> + * 1 = enable trigger_level[] interrupt,
> + * 0 = disable trigger_level[] interrupt
> + * @max_trigger_level: max trigger level supported by the TMU
> * @gain: gain of amplifier in the positive-TC generator block
> * 0 <= gain <= 15
> * @reference_voltage: reference voltage of amplifier
> @@ -76,7 +78,13 @@ enum soc_type {
> * 000, 100, 101, 110 and 111 can be different modes
> * @type: determines the type of SOC
> * @efuse_value: platform defined fuse value
> + * @min_efuse_value: minimum valid trimming data
> + * @max_efuse_value: maximum valid trimming data
> + * @first_point_trim: temp value of the first point trimming
> + * @second_point_trim: temp value of the second point trimming
> + * @default_temp_offset: default temperature offset in case of no trimming
> * @cal_type: calibration type for temperature
> + * @cal_mode: calibration mode for temperature
> * @freq_clip_table: Table representing frequency reduction percentage.
> * @freq_tab_count: Count of the above table as frequency reduction may
> * applicable to only some of the trigger levels.
> @@ -86,18 +94,23 @@ enum soc_type {
> struct exynos_tmu_platform_data {
> u8 threshold;
> u8 threshold_falling;
> - u8 trigger_levels[4];
> - bool trigger_level0_en;
> - bool trigger_level1_en;
> - bool trigger_level2_en;
> - bool trigger_level3_en;
> -
> + u8 trigger_levels[MAX_TRIP_COUNT];
> + enum trigger_type trigger_type[MAX_TRIP_COUNT];
> + bool trigger_enable[MAX_TRIP_COUNT];
> + u8 max_trigger_level;
> u8 gain;
> u8 reference_voltage;
> u8 noise_cancel_mode;
> +
> u32 efuse_value;
> + u32 min_efuse_value;
> + u32 max_efuse_value;
> + u8 first_point_trim;
> + u8 second_point_trim;
> + u8 default_temp_offset;
>
> enum calibration_type cal_type;
> + enum calibration_mode cal_mode;
> enum soc_type type;
> struct freq_clip_table freq_tab[4];
> unsigned int freq_tab_count;
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index 13a60ca..a187043 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -22,6 +22,7 @@
>
> #include "exynos_thermal_common.h"
> #include "exynos_tmu.h"
> +#include "exynos_tmu_data.h"
This change needs to be moved to the patch that you added this file.
Check comment on patch 07/30.
>
> #if defined(CONFIG_CPU_EXYNOS4210)
> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> @@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> .trigger_levels[0] = 5,
> .trigger_levels[1] = 20,
> .trigger_levels[2] = 30,
> - .trigger_level0_en = 1,
> - .trigger_level1_en = 1,
> - .trigger_level2_en = 1,
> - .trigger_level3_en = 0,
> + .trigger_enable[0] = 1,
> + .trigger_enable[1] = 1,
> + .trigger_enable[2] = 1,
> + .trigger_enable[3] = 0,
> + .trigger_type[0] = THROTTLE_ACTIVE,
> + .trigger_type[1] = THROTTLE_ACTIVE,
> + .trigger_type[2] = SW_TRIP,
is there any issues if trigger_type[3] is 0? there is no defined value
for 0. (0 means undefined on your enum definition).
> + .max_trigger_level = 4,
> .gain = 15,
> .reference_voltage = 7,
> .cal_type = TYPE_ONE_POINT_TRIMMING,
> + .min_efuse_value = 40,
> + .max_efuse_value = 100,
> + .first_point_trim = 25,
> + .second_point_trim = 85,
> + .default_temp_offset = 50,
> .freq_tab[0] = {
> .freq_clip_max = 800 * 1000,
> .temp_level = 85,
> @@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> .trigger_levels[0] = 85,
> .trigger_levels[1] = 103,
> .trigger_levels[2] = 110,
> - .trigger_level0_en = 1,
> - .trigger_level1_en = 1,
> - .trigger_level2_en = 1,
> - .trigger_level3_en = 0,
> + .trigger_enable[0] = 1,
> + .trigger_enable[1] = 1,
> + .trigger_enable[2] = 1,
> + .trigger_enable[3] = 0,
> + .trigger_type[0] = THROTTLE_ACTIVE,
> + .trigger_type[1] = THROTTLE_ACTIVE,
> + .trigger_type[2] = SW_TRIP,
> + .max_trigger_level = 4,
> .gain = 8,
> .reference_voltage = 16,
> .noise_cancel_mode = 4,
> .cal_type = TYPE_ONE_POINT_TRIMMING,
> .efuse_value = 55,
> + .min_efuse_value = 40,
> + .max_efuse_value = 100,
> + .first_point_trim = 25,
> + .second_point_trim = 85,
> + .default_temp_offset = 50,
> .freq_tab[0] = {
> .freq_clip_max = 800 * 1000,
> .temp_level = 85,
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 19-06-2013 16:19, Eduardo Valentin wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
>> trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
>> trigger_enable in the TMU platform data structure. Also the driver is modified
>> to use the data passed by these new platform memebers instead of the constant
>> macros. All these changes helps in separating the SOC specific data part from
>> the TMU driver.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
>> drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
>> drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
>> drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
>> 4 files changed, 86 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 068f56c..fd789a5 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -44,6 +44,13 @@
>>
>> #define EXYNOS_ZONE_COUNT 3
>>
>> +enum trigger_type {
>> + THROTTLE_ACTIVE = 1,
>> + THROTTLE_PASSIVE,
>> + SW_TRIP,
>> + HW_TRIP,
>> +};
>> +
>> /**
>> * struct freq_clip_table
>> * @freq_clip_max: maximum frequency allowed for this cooling state.
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index fa33a48..401ec98 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -49,7 +49,6 @@
>> #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>> #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>> #define EXYNOS_TMU_CORE_EN_SHIFT 0
>> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>
>> /* Exynos4210 specific registers */
>> #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
>> @@ -94,9 +93,6 @@
>> #define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>> #define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>
>> -#define EFUSE_MIN_VALUE 40
>> -#define EFUSE_MAX_VALUE 100
>> -
>> #ifdef CONFIG_THERMAL_EMULATION
>> #define EXYNOS_EMUL_TIME 0x57F0
>> #define EXYNOS_EMUL_TIME_MASK 0xffff
>> @@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>>
>> switch (pdata->cal_type) {
>> case TYPE_TWO_POINT_TRIMMING:
>> - temp_code = (temp - 25) *
>> - (data->temp_error2 - data->temp_error1) /
>> - (85 - 25) + data->temp_error1;
>> + temp_code = (temp - pdata->first_point_trim) *
>> + (data->temp_error2 - data->temp_error1) /
>> + (pdata->second_point_trim - pdata->first_point_trim) +
>> + data->temp_error1;
>> break;
>> case TYPE_ONE_POINT_TRIMMING:
>> - temp_code = temp + data->temp_error1 - 25;
>> + temp_code = temp + data->temp_error1 - pdata->first_point_trim;
>> break;
>> default:
>> - temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> + temp_code = temp + pdata->default_temp_offset;
>> break;
>> }
>> out:
>> @@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>>
>> switch (pdata->cal_type) {
>> case TYPE_TWO_POINT_TRIMMING:
>> - temp = (temp_code - data->temp_error1) * (85 - 25) /
>> - (data->temp_error2 - data->temp_error1) + 25;
>> + temp = (temp_code - data->temp_error1) *
>> + (pdata->second_point_trim - pdata->first_point_trim) /
>> + (data->temp_error2 - data->temp_error1) +
>> + pdata->first_point_trim;
>> break;
>> case TYPE_ONE_POINT_TRIMMING:
>> - temp = temp_code - data->temp_error1 + 25;
>> + temp = temp_code - data->temp_error1 + pdata->first_point_trim;
>> break;
>> default:
>> - temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> + temp = temp_code - pdata->default_temp_offset;
>> break;
>> }
>> out:
>> @@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>> data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
>> data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
>>
>> - if ((EFUSE_MIN_VALUE > data->temp_error1) ||
>> - (data->temp_error1 > EFUSE_MAX_VALUE) ||
>> + if ((pdata->min_efuse_value > data->temp_error1) ||
>> + (data->temp_error1 > pdata->max_efuse_value) ||
>> (data->temp_error2 != 0))
>> data->temp_error1 = pdata->efuse_value;
>>
>> @@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>> if (on) {
>> con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>> interrupt_en =
>> - pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>> - pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>> - pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>> - pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>> + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>> + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>> + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>> + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>> if (pdata->threshold_falling)
>> interrupt_en |=
>> interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>> @@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>
>> /* Register the sensor with thermal management interface */
>> (&exynos_sensor_conf)->private_data = data;
>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
>> - pdata->trigger_level1_en + pdata->trigger_level2_en +
>> - pdata->trigger_level3_en;
>> + exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>> + pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>> + pdata->trigger_enable[3];
>>
>> for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>> exynos_sensor_conf.trip_data.trip_val[i] =
>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>> index 9e0f887..45c697d 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -30,6 +30,11 @@ enum calibration_type {
>> TYPE_NONE,
>> };
>>
>> +enum calibration_mode {
>> + SW_MODE,
>> + HW_MODE,
>> +};
>> +
>> enum soc_type {
>> SOC_ARCH_EXYNOS4210 = 1,
>> SOC_ARCH_EXYNOS,
>> @@ -55,18 +60,15 @@ enum soc_type {
>> * 3: temperature for trigger_level3 interrupt
>> * condition for trigger_level3 interrupt:
>> * current temperature > threshold + trigger_levels[3]
>> - * @trigger_level0_en:
>> - * 1 = enable trigger_level0 interrupt,
>> - * 0 = disable trigger_level0 interrupt
>> - * @trigger_level1_en:
>> - * 1 = enable trigger_level1 interrupt,
>> - * 0 = disable trigger_level1 interrupt
>> - * @trigger_level2_en:
>> - * 1 = enable trigger_level2 interrupt,
>> - * 0 = disable trigger_level2 interrupt
>> - * @trigger_level3_en:
>> - * 1 = enable trigger_level3 interrupt,
>> - * 0 = disable trigger_level3 interrupt
>> + * @trigger_type: defines the type of trigger. Possible values are,
>> + * THROTTLE_ACTIVE trigger type
>> + * THROTTLE_PASSIVE trigger type
>> + * SW_TRIP trigger type
>> + * HW_TRIP
>> + * @trigger_enable[]: array to denote which trigger levels are enabled.
>> + * 1 = enable trigger_level[] interrupt,
>> + * 0 = disable trigger_level[] interrupt
>> + * @max_trigger_level: max trigger level supported by the TMU
>> * @gain: gain of amplifier in the positive-TC generator block
>> * 0 <= gain <= 15
>> * @reference_voltage: reference voltage of amplifier
>> @@ -76,7 +78,13 @@ enum soc_type {
>> * 000, 100, 101, 110 and 111 can be different modes
>> * @type: determines the type of SOC
>> * @efuse_value: platform defined fuse value
>> + * @min_efuse_value: minimum valid trimming data
>> + * @max_efuse_value: maximum valid trimming data
>> + * @first_point_trim: temp value of the first point trimming
>> + * @second_point_trim: temp value of the second point trimming
>> + * @default_temp_offset: default temperature offset in case of no trimming
>> * @cal_type: calibration type for temperature
>> + * @cal_mode: calibration mode for temperature
>> * @freq_clip_table: Table representing frequency reduction percentage.
>> * @freq_tab_count: Count of the above table as frequency reduction may
>> * applicable to only some of the trigger levels.
>> @@ -86,18 +94,23 @@ enum soc_type {
>> struct exynos_tmu_platform_data {
>> u8 threshold;
>> u8 threshold_falling;
>> - u8 trigger_levels[4];
>> - bool trigger_level0_en;
>> - bool trigger_level1_en;
>> - bool trigger_level2_en;
>> - bool trigger_level3_en;
>> -
>> + u8 trigger_levels[MAX_TRIP_COUNT];
>> + enum trigger_type trigger_type[MAX_TRIP_COUNT];
>> + bool trigger_enable[MAX_TRIP_COUNT];
>> + u8 max_trigger_level;
>> u8 gain;
>> u8 reference_voltage;
>> u8 noise_cancel_mode;
>> +
>> u32 efuse_value;
>> + u32 min_efuse_value;
>> + u32 max_efuse_value;
>> + u8 first_point_trim;
>> + u8 second_point_trim;
>> + u8 default_temp_offset;
>>
>> enum calibration_type cal_type;
>> + enum calibration_mode cal_mode;
>> enum soc_type type;
>> struct freq_clip_table freq_tab[4];
>> unsigned int freq_tab_count;
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>> index 13a60ca..a187043 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>> @@ -22,6 +22,7 @@
>>
>> #include "exynos_thermal_common.h"
>> #include "exynos_tmu.h"
>> +#include "exynos_tmu_data.h"
>
> This change needs to be moved to the patch that you added this file.
> Check comment on patch 07/30.
>>
>> #if defined(CONFIG_CPU_EXYNOS4210)
>> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> @@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> .trigger_levels[0] = 5,
>> .trigger_levels[1] = 20,
>> .trigger_levels[2] = 30,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> + .trigger_enable[0] = 1,
>> + .trigger_enable[1] = 1,
>> + .trigger_enable[2] = 1,
>> + .trigger_enable[3] = 0,
This change added this sparse warning on your driver:
drivers/thermal/samsung/exynos_tmu_data.c:34:10: warning: Initializer
entry defined twice
drivers/thermal/samsung/exynos_tmu_data.c:35:10: also defined here
>> + .trigger_type[0] = THROTTLE_ACTIVE,
>> + .trigger_type[1] = THROTTLE_ACTIVE,
>> + .trigger_type[2] = SW_TRIP,
>
> is there any issues if trigger_type[3] is 0? there is no defined value
> for 0. (0 means undefined on your enum definition).
>
>
>> + .max_trigger_level = 4,
>> .gain = 15,
>> .reference_voltage = 7,
>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>> + .min_efuse_value = 40,
>> + .max_efuse_value = 100,
>> + .first_point_trim = 25,
>> + .second_point_trim = 85,
>> + .default_temp_offset = 50,
>> .freq_tab[0] = {
>> .freq_clip_max = 800 * 1000,
>> .temp_level = 85,
>> @@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>> .trigger_levels[0] = 85,
>> .trigger_levels[1] = 103,
>> .trigger_levels[2] = 110,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> + .trigger_enable[0] = 1,
>> + .trigger_enable[1] = 1,
>> + .trigger_enable[2] = 1,
>> + .trigger_enable[3] = 0,
This change add this sparse warning on your driver:
drivers/thermal/samsung/exynos_tmu_data.c:69:10: warning: Initializer
entry defined twice
drivers/thermal/samsung/exynos_tmu_data.c:70:10: also defined here
>> + .trigger_type[0] = THROTTLE_ACTIVE,
>> + .trigger_type[1] = THROTTLE_ACTIVE,
>> + .trigger_type[2] = SW_TRIP,
>> + .max_trigger_level = 4,
>> .gain = 8,
>> .reference_voltage = 16,
>> .noise_cancel_mode = 4,
>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>> .efuse_value = 55,
>> + .min_efuse_value = 40,
>> + .max_efuse_value = 100,
>> + .first_point_trim = 25,
>> + .second_point_trim = 85,
>> + .default_temp_offset = 50,
>> .freq_tab[0] = {
>> .freq_clip_max = 800 * 1000,
>> .temp_level = 85,
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch migrates the TMU register definition/bitfields to data file. This
> is needed to support SoC's which use the same TMU controller but register
> validity, offsets or bitfield may slightly vary across SOC's.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 172 +++++++++-------------------
> drivers/thermal/samsung/exynos_tmu.h | 133 ++++++++++++++++++++++
> drivers/thermal/samsung/exynos_tmu_data.c | 59 ++++++++++
> drivers/thermal/samsung/exynos_tmu_data.h | 68 +++++++++++
> 4 files changed, 315 insertions(+), 117 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 401ec98..6fd776f 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -32,76 +32,6 @@
> #include "exynos_tmu.h"
> #include "exynos_tmu_data.h"
>
> -/* Exynos generic registers */
> -#define EXYNOS_TMU_REG_TRIMINFO 0x0
> -#define EXYNOS_TMU_REG_CONTROL 0x20
> -#define EXYNOS_TMU_REG_STATUS 0x28
> -#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
> -#define EXYNOS_TMU_REG_INTEN 0x70
> -#define EXYNOS_TMU_REG_INTSTAT 0x74
> -#define EXYNOS_TMU_REG_INTCLEAR 0x78
> -
> -#define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
> -#define EXYNOS_TMU_GAIN_SHIFT 8
> -#define EXYNOS_TMU_GAIN_MASK 0xf
> -#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
> -#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
> -#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
> -#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
> -#define EXYNOS_TMU_CORE_EN_SHIFT 0
> -
> -/* Exynos4210 specific registers */
> -#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
> -#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
> -#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
> -#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
> -#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
> -
> -#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
> -#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
> -#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
> -#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
> -#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
> -#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
> -
> -/* Exynos5250 and Exynos4412 specific registers */
> -#define EXYNOS_TMU_TRIMINFO_CON 0x14
> -#define EXYNOS_THD_TEMP_RISE 0x50
> -#define EXYNOS_THD_TEMP_FALL 0x54
> -#define EXYNOS_EMUL_CON 0x80
> -
> -#define EXYNOS_TRIMINFO_RELOAD 0x1
> -#define EXYNOS_TRIMINFO_SHIFT 0x0
> -#define EXYNOS_TMU_RISE_INT_MASK 0x111
> -#define EXYNOS_TMU_RISE_INT_SHIFT 0
> -#define EXYNOS_TMU_FALL_INT_MASK 0x111
> -#define EXYNOS_TMU_FALL_INT_SHIFT 12
> -#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
> -#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
> -#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
> -#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
> -
> -#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
> -#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
> -#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
> -#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
> -#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
> -#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
> -#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -#define EXYNOS_EMUL_TIME 0x57F0
> -#define EXYNOS_EMUL_TIME_MASK 0xffff
> -#define EXYNOS_EMUL_TIME_SHIFT 16
> -#define EXYNOS_EMUL_DATA_SHIFT 8
> -#define EXYNOS_EMUL_DATA_MASK 0xFF
> -#define EXYNOS_EMUL_ENABLE 0x1
> -#endif /* CONFIG_THERMAL_EMULATION */
> -
> struct exynos_tmu_data {
> struct exynos_tmu_platform_data *pdata;
> struct resource *mem;
> @@ -186,6 +116,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> {
> struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> struct exynos_tmu_platform_data *pdata = data->pdata;
> + const struct exynos_tmu_registers *reg = pdata->registers;
> unsigned int status, trim_info;
> unsigned int rising_threshold = 0, falling_threshold = 0;
> int ret = 0, threshold_code, i, trigger_levs = 0;
> @@ -193,20 +124,20 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> + status = readb(data->base + reg->tmu_status);
> if (!status) {
> ret = -EBUSY;
> goto out;
> }
>
> - if (data->soc == SOC_ARCH_EXYNOS) {
> - __raw_writel(EXYNOS_TRIMINFO_RELOAD,
> - data->base + EXYNOS_TMU_TRIMINFO_CON);
> - }
> + if (data->soc == SOC_ARCH_EXYNOS)
> + __raw_writel(1, data->base + reg->triminfo_ctrl);
> +
> /* Save trimming info in order to perform calibration */
> - trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> - data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
> - data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
> + trim_info = readl(data->base + reg->triminfo_data);
> + data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
> + data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
> + EXYNOS_TMU_TEMP_MASK);
>
> if ((pdata->min_efuse_value > data->temp_error1) ||
> (data->temp_error1 > pdata->max_efuse_value) ||
> @@ -226,13 +157,12 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> goto out;
> }
> writeb(threshold_code,
> - data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
> + data->base + reg->threshold_temp);
> for (i = 0; i < trigger_levs; i++)
> - writeb(pdata->trigger_levels[i],
> - data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> + writeb(pdata->trigger_levels[i], data->base +
> + reg->threshold_th0 + i * sizeof(reg->threshold_th0));
>
> - writel(EXYNOS4210_TMU_INTCLEAR_VAL,
> - data->base + EXYNOS_TMU_REG_INTCLEAR);
> + writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
> } else if (data->soc == SOC_ARCH_EXYNOS) {
> /* Write temperature code for rising and falling threshold */
> for (i = 0; i < trigger_levs; i++) {
> @@ -254,12 +184,13 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> }
>
> writel(rising_threshold,
> - data->base + EXYNOS_THD_TEMP_RISE);
> + data->base + reg->threshold_th0);
> writel(falling_threshold,
> - data->base + EXYNOS_THD_TEMP_FALL);
> + data->base + reg->threshold_th1);
>
> - writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
> - data->base + EXYNOS_TMU_REG_INTCLEAR);
> + writel((reg->inten_rise_mask << reg->inten_rise_shift) |
> + (reg->inten_fall_mask << reg->inten_fall_shift),
> + data->base + reg->tmu_intclear);
> }
> out:
> clk_disable(data->clk);
> @@ -272,46 +203,46 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
> {
> struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> struct exynos_tmu_platform_data *pdata = data->pdata;
> + const struct exynos_tmu_registers *reg = pdata->registers;
> unsigned int con, interrupt_en;
>
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> + con = readl(data->base + reg->tmu_ctrl);
>
> if (pdata->reference_voltage) {
> - con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
> - EXYNOS_TMU_REF_VOLTAGE_SHIFT);
> - con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
> + con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift);
> + con |= pdata->reference_voltage << reg->buf_vref_sel_shift;
> }
>
> if (pdata->gain) {
> - con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
> - con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
> + con &= ~(reg->buf_slope_sel_mask << reg->buf_slope_sel_shift);
> + con |= (pdata->gain << reg->buf_slope_sel_shift);
> }
>
> if (pdata->noise_cancel_mode) {
> - con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
> - EXYNOS_TMU_TRIP_MODE_SHIFT);
> - con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
> + con &= ~(reg->therm_trip_mode_mask <<
> + reg->therm_trip_mode_shift);
> + con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
> }
>
> if (on) {
> - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> + con |= (1 << reg->core_en_shift);
> interrupt_en =
> - pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
> - pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
> - pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
> - pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
> + pdata->trigger_enable[3] << reg->inten_rise3_shift |
> + pdata->trigger_enable[2] << reg->inten_rise2_shift |
> + pdata->trigger_enable[1] << reg->inten_rise1_shift |
> + pdata->trigger_enable[0] << reg->inten_rise0_shift;
> if (pdata->threshold_falling)
> interrupt_en |=
> - interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
> + interrupt_en << reg->inten_fall0_shift;
> } else {
> - con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> + con &= ~(1 << reg->core_en_shift);
> interrupt_en = 0; /* Disable all interrupts */
> }
> - writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
> - writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> + writel(interrupt_en, data->base + reg->tmu_inten);
> + writel(con, data->base + reg->tmu_ctrl);
>
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
> @@ -319,13 +250,15 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>
> static int exynos_tmu_read(struct exynos_tmu_data *data)
> {
> + struct exynos_tmu_platform_data *pdata = data->pdata;
> + const struct exynos_tmu_registers *reg = pdata->registers;
> u8 temp_code;
> int temp;
>
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
> + temp_code = readb(data->base + reg->tmu_cur_temp);
> temp = code_to_temp(data, temp_code);
>
> clk_disable(data->clk);
> @@ -338,7 +271,9 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
> static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> {
> struct exynos_tmu_data *data = drv_data;
> - unsigned int reg;
> + struct exynos_tmu_platform_data *pdata = data->pdata;
> + const struct exynos_tmu_registers *reg = pdata->registers;
> + unsigned int val;
> int ret = -EINVAL;
>
> if (data->soc == SOC_ARCH_EXYNOS4210)
> @@ -350,19 +285,19 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - reg = readl(data->base + EXYNOS_EMUL_CON);
> + val = readl(data->base + reg->emul_con);
>
> if (temp) {
> temp /= MCELSIUS;
>
> - reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
> + val = (EXYNOS_EMUL_TIME << reg->emul_time_shift) |
> (temp_to_code(data, temp)
> - << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
> + << reg->emul_temp_shift) | EXYNOS_EMUL_ENABLE;
> } else {
> - reg &= ~EXYNOS_EMUL_ENABLE;
> + val &= ~EXYNOS_EMUL_ENABLE;
> }
>
> - writel(reg, data->base + EXYNOS_EMUL_CON);
> + writel(val, data->base + reg->emul_con);
>
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
> @@ -379,17 +314,20 @@ static void exynos_tmu_work(struct work_struct *work)
> {
> struct exynos_tmu_data *data = container_of(work,
> struct exynos_tmu_data, irq_work);
> + struct exynos_tmu_platform_data *pdata = data->pdata;
> + const struct exynos_tmu_registers *reg = pdata->registers;
>
> exynos_report_trigger();
> mutex_lock(&data->lock);
> clk_enable(data->clk);
> +
> if (data->soc == SOC_ARCH_EXYNOS)
> - writel(EXYNOS_TMU_CLEAR_RISE_INT |
> - EXYNOS_TMU_CLEAR_FALL_INT,
> - data->base + EXYNOS_TMU_REG_INTCLEAR);
> + writel((reg->inten_rise_mask << reg->inten_rise_shift) |
> + (reg->inten_fall_mask << reg->inten_fall_shift),
> + data->base + reg->tmu_intclear);
> else
> - writel(EXYNOS4210_TMU_INTCLEAR_VAL,
> - data->base + EXYNOS_TMU_REG_INTCLEAR);
> + writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
> +
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 45c697d..619a34c 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -41,6 +41,136 @@ enum soc_type {
> };
>
> /**
> + * struct exynos_tmu_register - register descriptors to access registers and
> + * bitfields. The register validity, offsets and bitfield values may vary
> + * slightly across different exynos SOC's.
> + * @triminfo_data: register containing 2 pont trimming data
> + * @triminfo_25_shift: shift bit of the 25 C trim value in triminfo_data reg.
> + * @triminfo_85_shift: shift bit of the 85 C trim value in triminfo_data reg.
> + * @triminfo_ctrl: trim info controller register.
> + * @triminfo_reload_shift: shift of triminfo reload enable bit in triminfo_ctrl
> + reg.
> + * @tmu_ctrl: TMU main controller register.
> + * @buf_vref_sel_shift: shift bits of reference voltage in tmu_ctrl register.
> + * @buf_vref_sel_mask: mask bits of reference voltage in tmu_ctrl register.
> + * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register.
> + * @therm_trip_mode_mask: mask bits of tripping mode in tmu_ctrl register.
> + * @therm_trip_en_shift: shift bits of tripping enable in tmu_ctrl register.
> + * @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
> + register.
> + * @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
> + * @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
> + tmu_ctrl register.
> + * @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
> + * @tmu_status: register drescribing the TMU status.
> + * @tmu_cur_temp: register containing the current temperature of the TMU.
> + * @tmu_cur_temp_shift: shift bits of current temp value in tmu_cur_temp
> + register.
> + * @threshold_temp: register containing the base threshold level.
> + * @threshold_th0: Register containing first set of rising levels.
> + * @threshold_th0_l0_shift: shift bits of level0 threshold temperature.
> + * @threshold_th0_l1_shift: shift bits of level1 threshold temperature.
> + * @threshold_th0_l2_shift: shift bits of level2 threshold temperature.
> + * @threshold_th0_l3_shift: shift bits of level3 threshold temperature.
> + * @threshold_th1: Register containing second set of rising levels.
> + * @threshold_th1_l0_shift: shift bits of level0 threshold temperature.
> + * @threshold_th1_l1_shift: shift bits of level1 threshold temperature.
> + * @threshold_th1_l2_shift: shift bits of level2 threshold temperature.
> + * @threshold_th1_l3_shift: shift bits of level3 threshold temperature.
> + * @threshold_th2: Register containing third set of rising levels.
> + * @threshold_th2_l0_shift: shift bits of level0 threshold temperature.
> + * @threshold_th3: Register containing fourth set of rising levels.
> + * @threshold_th3_l0_shift: shift bits of level0 threshold temperature.
> + * @tmu_inten: register containing the different threshold interrupt
> + enable bits.
> + * @inten_rise_shift: shift bits of all rising interrupt bits.
> + * @inten_rise_mask: mask bits of all rising interrupt bits.
> + * @inten_fall_shift: shift bits of all rising interrupt bits.
> + * @inten_fall_mask: mask bits of all rising interrupt bits.
> + * @inten_rise0_shift: shift bits of rising 0 interrupt bits.
> + * @inten_rise1_shift: shift bits of rising 1 interrupt bits.
> + * @inten_rise2_shift: shift bits of rising 2 interrupt bits.
> + * @inten_rise3_shift: shift bits of rising 3 interrupt bits.
> + * @inten_fall0_shift: shift bits of falling 0 interrupt bits.
> + * @inten_fall1_shift: shift bits of falling 1 interrupt bits.
> + * @inten_fall2_shift: shift bits of falling 2 interrupt bits.
> + * @inten_fall3_shift: shift bits of falling 3 interrupt bits.
> + * @tmu_intstat: Register containing the interrupt status values.
> + * @tmu_intclear: Register for clearing the raised interrupt status.
> + * @emul_con: TMU emulation controller register.
> + * @emul_temp_shift: shift bits of emulation temperature.
> + * @emul_time_shift: shift bits of emulation time.
> + * @emul_time_mask: mask bits of emulation time.
> + */
> +struct exynos_tmu_registers {
> + u32 triminfo_data;
> + u32 triminfo_25_shift;
> + u32 triminfo_85_shift;
> +
> + u32 triminfo_ctrl;
> + u32 triminfo_reload_shift;
> +
> + u32 tmu_ctrl;
> + u32 buf_vref_sel_shift;
> + u32 buf_vref_sel_mask;
> + u32 therm_trip_mode_shift;
> + u32 therm_trip_mode_mask;
> + u32 therm_trip_en_shift;
> + u32 buf_slope_sel_shift;
> + u32 buf_slope_sel_mask;
> + u32 therm_trip_tq_en_shift;
> + u32 core_en_shift;
> +
> + u32 tmu_status;
> +
> + u32 tmu_cur_temp;
> + u32 tmu_cur_temp_shift;
> +
> + u32 threshold_temp;
> +
> + u32 threshold_th0;
> + u32 threshold_th0_l0_shift;
> + u32 threshold_th0_l1_shift;
> + u32 threshold_th0_l2_shift;
> + u32 threshold_th0_l3_shift;
> +
> + u32 threshold_th1;
> + u32 threshold_th1_l0_shift;
> + u32 threshold_th1_l1_shift;
> + u32 threshold_th1_l2_shift;
> + u32 threshold_th1_l3_shift;
> +
> + u32 threshold_th2;
> + u32 threshold_th2_l0_shift;
> +
> + u32 threshold_th3;
> + u32 threshold_th3_l0_shift;
> +
> + u32 tmu_inten;
> + u32 inten_rise_shift;
> + u32 inten_rise_mask;
> + u32 inten_fall_shift;
> + u32 inten_fall_mask;
> + u32 inten_rise0_shift;
> + u32 inten_rise1_shift;
> + u32 inten_rise2_shift;
> + u32 inten_rise3_shift;
> + u32 inten_fall0_shift;
> + u32 inten_fall1_shift;
> + u32 inten_fall2_shift;
> + u32 inten_fall3_shift;
> +
> + u32 tmu_intstat;
> +
> + u32 tmu_intclear;
> +
> + u32 emul_con;
> + u32 emul_temp_shift;
> + u32 emul_time_shift;
> + u32 emul_time_mask;
> +};
> +
> +/**
> * struct exynos_tmu_platform_data
> * @threshold: basic temperature for generating interrupt
> * 25 <= threshold <= 125 [unit: degree Celsius]
> @@ -88,6 +218,8 @@ enum soc_type {
> * @freq_clip_table: Table representing frequency reduction percentage.
> * @freq_tab_count: Count of the above table as frequency reduction may
> * applicable to only some of the trigger levels.
> + * @registers: Pointer to structure containing all the TMU controller registers
> + * and bitfields shifts and masks.
> *
> * This structure is required for configuration of exynos_tmu driver.
> */
> @@ -114,5 +246,6 @@ struct exynos_tmu_platform_data {
> enum soc_type type;
> struct freq_clip_table freq_tab[4];
> unsigned int freq_tab_count;
> + const struct exynos_tmu_registers *registers;
> };
> #endif /* _EXYNOS_TMU_H */
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index a187043..589a519 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -25,6 +25,28 @@
> #include "exynos_tmu_data.h"
>
> #if defined(CONFIG_CPU_EXYNOS4210)
> +static const struct exynos_tmu_registers exynos4210_tmu_registers = {
> + .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
> + .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
> + .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
> + .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
> + .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
> + .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
> + .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
> + .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
> + .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
> + .tmu_status = EXYNOS_TMU_REG_STATUS,
> + .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
> + .threshold_temp = EXYNOS4210_TMU_REG_THRESHOLD_TEMP,
> + .threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0,
> + .tmu_inten = EXYNOS_TMU_REG_INTEN,
> + .inten_rise_mask = EXYNOS4210_TMU_TRIG_LEVEL_MASK,
> + .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
> + .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
> + .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
> + .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
> + .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
> +};
> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> .threshold = 80,
> .trigger_levels[0] = 5,
> @@ -56,10 +78,46 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> },
> .freq_tab_count = 2,
> .type = SOC_ARCH_EXYNOS4210,
> + .registers = &exynos4210_tmu_registers,
> };
> #endif
>
> #if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
> +static const struct exynos_tmu_registers exynos5250_tmu_registers = {
> + .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
> + .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
> + .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
> + .triminfo_ctrl = EXYNOS_TMU_TRIMINFO_CON,
> + .triminfo_reload_shift = EXYNOS_TRIMINFO_RELOAD_SHIFT,
> + .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
> + .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
> + .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
> + .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
> + .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
> + .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
> + .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
> + .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
> + .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
> + .tmu_status = EXYNOS_TMU_REG_STATUS,
> + .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
> + .threshold_th0 = EXYNOS_THD_TEMP_RISE,
> + .threshold_th1 = EXYNOS_THD_TEMP_FALL,
> + .tmu_inten = EXYNOS_TMU_REG_INTEN,
> + .inten_rise_mask = EXYNOS_TMU_RISE_INT_MASK,
> + .inten_rise_shift = EXYNOS_TMU_RISE_INT_SHIFT,
> + .inten_fall_mask = EXYNOS_TMU_FALL_INT_MASK,
> + .inten_fall_shift = EXYNOS_TMU_FALL_INT_SHIFT,
> + .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
> + .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
> + .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
> + .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
> + .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
> + .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
> + .emul_con = EXYNOS_EMUL_CON,
> + .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
> + .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
> + .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
> +};
> struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> .threshold_falling = 10,
> .trigger_levels[0] = 85,
> @@ -93,5 +151,6 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> },
> .freq_tab_count = 2,
> .type = SOC_ARCH_EXYNOS,
> + .registers = &exynos5250_tmu_registers,
> };
> #endif
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index b7835fe..0e2244f 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -23,6 +23,74 @@
> #ifndef _EXYNOS_TMU_DATA_H
> #define _EXYNOS_TMU_DATA_H
>
> +/* Exynos generic registers */
> +#define EXYNOS_TMU_REG_TRIMINFO 0x0
> +#define EXYNOS_TMU_REG_CONTROL 0x20
> +#define EXYNOS_TMU_REG_STATUS 0x28
> +#define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
> +#define EXYNOS_TMU_REG_INTEN 0x70
> +#define EXYNOS_TMU_REG_INTSTAT 0x74
> +#define EXYNOS_TMU_REG_INTCLEAR 0x78
> +
> +#define EXYNOS_TMU_TEMP_MASK 0xff
> +#define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
> +#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
> +#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
> +#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
> +#define EXYNOS_TMU_CORE_EN_SHIFT 0
> +
> +/* Exynos4210 specific registers */
> +#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
> +#define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
> +#define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
> +#define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
> +#define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
> +
> +#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
> +#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
> +#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
> +#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
> +#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
> +#define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
> +
> +/* Exynos5250 and Exynos4412 specific registers */
> +#define EXYNOS_TMU_TRIMINFO_CON 0x14
> +#define EXYNOS_THD_TEMP_RISE 0x50
> +#define EXYNOS_THD_TEMP_FALL 0x54
> +#define EXYNOS_EMUL_CON 0x80
> +
> +#define EXYNOS_TRIMINFO_RELOAD_SHIFT 1
> +#define EXYNOS_TRIMINFO_25_SHIFT 0
> +#define EXYNOS_TRIMINFO_85_SHIFT 8
> +#define EXYNOS_TMU_RISE_INT_MASK 0x111
> +#define EXYNOS_TMU_RISE_INT_SHIFT 0
> +#define EXYNOS_TMU_FALL_INT_MASK 0x111
> +#define EXYNOS_TMU_FALL_INT_SHIFT 12
> +#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
> +#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
> +#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
> +#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
> +#define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
> +
> +#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
> +#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
> +#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
> +#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
> +#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
> +#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
> +#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
> +
> +#define EXYNOS_EMUL_TIME 0x57F0
> +#define EXYNOS_EMUL_TIME_MASK 0xffff
> +#define EXYNOS_EMUL_TIME_SHIFT 16
> +#define EXYNOS_EMUL_DATA_SHIFT 8
> +#define EXYNOS_EMUL_DATA_MASK 0xFF
> +#define EXYNOS_EMUL_ENABLE 0x1
> +
> #if defined(CONFIG_CPU_EXYNOS4210)
> extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> TMU urgently sends active-high signal (thermal trip) to PMU, and thermal
> tripping by hardware logic. Thermal tripping means that PMU cuts off the
> whole power of SoC by controlling external voltage regulator.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Jonghwan Choi <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 45 +++++++++++++++++++++++++---
> drivers/thermal/samsung/exynos_tmu_data.c | 2 +
> drivers/thermal/samsung/exynos_tmu_data.h | 2 +
> 3 files changed, 44 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 6fd776f..33f494e 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -117,7 +117,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> struct exynos_tmu_platform_data *pdata = data->pdata;
> const struct exynos_tmu_registers *reg = pdata->registers;
> - unsigned int status, trim_info;
> + unsigned int status, trim_info = 0, con;
> unsigned int rising_threshold = 0, falling_threshold = 0;
> int ret = 0, threshold_code, i, trigger_levs = 0;
>
> @@ -144,10 +144,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> (data->temp_error2 != 0))
> data->temp_error1 = pdata->efuse_value;
>
> - /* Count trigger levels to be enabled */
> - for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
> - if (pdata->trigger_levels[i])
> + if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
> + dev_err(&pdev->dev, "Invalid max trigger level\n");
> + goto out;
> + }
> +
> + for (i = 0; i < pdata->max_trigger_level; i++) {
> + if (!pdata->trigger_levels[i])
> + continue;
> +
> + if ((pdata->trigger_type[i] == HW_TRIP) &&
> + (!pdata->trigger_levels[pdata->max_trigger_level - 1])) {
> + dev_err(&pdev->dev, "Invalid hw trigger level\n");
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + /* Count trigger levels except the HW trip*/
> + if (!(pdata->trigger_type[i] == HW_TRIP))
> trigger_levs++;
> + }
>
> if (data->soc == SOC_ARCH_EXYNOS4210) {
> /* Write temperature code for threshold */
> @@ -165,7 +181,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
> } else if (data->soc == SOC_ARCH_EXYNOS) {
> /* Write temperature code for rising and falling threshold */
> - for (i = 0; i < trigger_levs; i++) {
> + for (i = 0;
> + i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
> threshold_code = temp_to_code(data,
> pdata->trigger_levels[i]);
> if (threshold_code < 0) {
> @@ -191,6 +208,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> writel((reg->inten_rise_mask << reg->inten_rise_shift) |
> (reg->inten_fall_mask << reg->inten_fall_shift),
> data->base + reg->tmu_intclear);
> +
> + /* if last threshold limit is also present */
> + i = pdata->max_trigger_level - 1;
> + if (pdata->trigger_levels[i] &&
> + (pdata->trigger_type[i] == HW_TRIP)) {
> + threshold_code = temp_to_code(data,
> + pdata->trigger_levels[i]);
> + if (threshold_code < 0) {
> + ret = threshold_code;
> + goto out;
> + }
> + rising_threshold |= threshold_code << 8 * i;
> + writel(rising_threshold,
> + data->base + reg->threshold_th0);
> + con = readl(data->base + reg->tmu_ctrl);
> + con |= (1 << reg->therm_trip_en_shift);
> + writel(con, data->base + reg->tmu_ctrl);
> + }
> }
> out:
> clk_disable(data->clk);
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index 589a519..e7cb1cc 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -123,6 +123,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> .trigger_levels[0] = 85,
> .trigger_levels[1] = 103,
> .trigger_levels[2] = 110,
> + .trigger_levels[3] = 120,
> .trigger_enable[0] = 1,
> .trigger_enable[1] = 1,
> .trigger_enable[2] = 1,
> @@ -130,6 +131,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> .trigger_type[0] = THROTTLE_ACTIVE,
> .trigger_type[1] = THROTTLE_ACTIVE,
> .trigger_type[2] = SW_TRIP,
> + .trigger_type[3] = HW_TRIP,
> .max_trigger_level = 4,
> .gain = 8,
> .reference_voltage = 16,
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index 0e2244f..4acf070 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -91,6 +91,8 @@
> #define EXYNOS_EMUL_DATA_MASK 0xFF
> #define EXYNOS_EMUL_ENABLE 0x1
>
> +#define EXYNOS_MAX_TRIGGER_PER_REG 4
> +
> #if defined(CONFIG_CPU_EXYNOS4210)
> extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch uses the TMU status register to know the generated interrupts
> and only clear them in the interrupt handler.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
Acked-by: Eduardo Valentin <[email protected]>
> drivers/thermal/samsung/exynos_tmu.c | 11 +++++------
> drivers/thermal/samsung/exynos_tmu_data.c | 2 ++
> 2 files changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 33f494e..f6f63ca 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -351,17 +351,16 @@ static void exynos_tmu_work(struct work_struct *work)
> struct exynos_tmu_data, irq_work);
> struct exynos_tmu_platform_data *pdata = data->pdata;
> const struct exynos_tmu_registers *reg = pdata->registers;
> + unsigned int val_irq;
>
> exynos_report_trigger();
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - if (data->soc == SOC_ARCH_EXYNOS)
> - writel((reg->inten_rise_mask << reg->inten_rise_shift) |
> - (reg->inten_fall_mask << reg->inten_fall_shift),
> - data->base + reg->tmu_intclear);
> - else
> - writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
> + /* TODO: take action based on particular interrupt */
> + val_irq = readl(data->base + reg->tmu_intstat);
> + /* clear the interrupts */
> + writel(val_irq, data->base + reg->tmu_intclear);
>
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index e7cb1cc..7fcf183 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -45,6 +45,7 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
> .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
> .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
> .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
> + .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
> .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
> };
> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> @@ -112,6 +113,7 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
> .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
> .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
> .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
> + .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
> .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
> .emul_con = EXYNOS_EMUL_CON,
> .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
Hi,
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code modifies the thermal driver to have multiple thermal zone
> support by replacing the global thermal zone variable with device data
> member of thermal_zone_device.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 36 ++++++++++++++--------
> drivers/thermal/samsung/exynos_thermal_common.h | 9 +++--
> drivers/thermal/samsung/exynos_tmu.c | 15 +++++----
> 3 files changed, 36 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index dd49c9f..2af1e3b 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -36,12 +36,11 @@ struct exynos_thermal_zone {
> bool bind;
> };
>
> -static struct exynos_thermal_zone *th_zone;
> -
> /* Get mode callback functions for thermal zone */
> static int exynos_get_mode(struct thermal_zone_device *thermal,
> enum thermal_device_mode *mode)
> {
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> if (th_zone)
> *mode = th_zone->mode;
> return 0;
> @@ -51,25 +50,26 @@ static int exynos_get_mode(struct thermal_zone_device *thermal,
> static int exynos_set_mode(struct thermal_zone_device *thermal,
> enum thermal_device_mode mode)
> {
> - if (!th_zone->therm_dev) {
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> + if (!th_zone) {
> pr_notice("thermal zone not registered\n");
> return 0;
> }
>
> - mutex_lock(&th_zone->therm_dev->lock);
> + mutex_lock(&thermal->lock);
>
> if (mode == THERMAL_DEVICE_ENABLED &&
> !th_zone->sensor_conf->trip_data.trigger_falling)
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + thermal->polling_delay = IDLE_INTERVAL;
> else
> - th_zone->therm_dev->polling_delay = 0;
> + thermal->polling_delay = 0;
>
> - mutex_unlock(&th_zone->therm_dev->lock);
> + mutex_unlock(&thermal->lock);
>
> th_zone->mode = mode;
> - thermal_zone_device_update(th_zone->therm_dev);
> + thermal_zone_device_update(thermal);
> pr_info("thermal polling set for duration=%d msec\n",
> - th_zone->therm_dev->polling_delay);
> + thermal->polling_delay);
> return 0;
> }
>
> @@ -96,6 +96,8 @@ static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> unsigned long *temp)
> {
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> +
> if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> return -EINVAL;
>
> @@ -122,6 +124,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
> {
> int ret = 0, i, tab_size, level;
> struct freq_clip_table *tab_ptr, *clip_data;
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> struct thermal_sensor_conf *data = th_zone->sensor_conf;
>
> tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> @@ -168,6 +171,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
> struct thermal_cooling_device *cdev)
> {
> int ret = 0, i, tab_size;
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> struct thermal_sensor_conf *data = th_zone->sensor_conf;
>
> if (th_zone->bind == false)
> @@ -210,6 +214,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
> static int exynos_get_temp(struct thermal_zone_device *thermal,
> unsigned long *temp)
> {
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> void *data;
>
> if (!th_zone->sensor_conf) {
> @@ -229,6 +234,7 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> {
> void *data;
> int ret = -EINVAL;
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
>
> if (!th_zone->sensor_conf) {
> pr_info("Temperature sensor not initialised\n");
> @@ -276,11 +282,12 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
> * This function may be called from interrupt based temperature sensor
> * when threshold is changed.
> */
> -void exynos_report_trigger(void)
> +void exynos_report_trigger(struct thermal_sensor_conf *conf)
> {
> unsigned int i;
> char data[10];
> char *envp[] = { data, NULL };
> + struct exynos_thermal_zone *th_zone = conf->pzone_data;
>
> if (!th_zone || !th_zone->therm_dev)
> return;
> @@ -321,6 +328,7 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> {
> int ret;
> struct cpumask mask_val;
> + struct exynos_thermal_zone *th_zone;
>
> if (!sensor_conf || !sensor_conf->read_temperature) {
> pr_err("Temperature sensor not initialised\n");
> @@ -342,7 +350,7 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> th_zone->cool_dev_size++;
>
> th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> + EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
> sensor_conf->trip_data.trigger_falling ?
> 0 : IDLE_INTERVAL);
>
> @@ -352,20 +360,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> goto err_unregister;
> }
> th_zone->mode = THERMAL_DEVICE_ENABLED;
> + sensor_conf->pzone_data = th_zone;
>
> pr_info("Exynos: Kernel Thermal management registered\n");
>
> return 0;
>
> err_unregister:
> - exynos_unregister_thermal();
> + exynos_unregister_thermal(sensor_conf);
> return ret;
> }
>
> /* Un-Register with the in-kernel thermal management */
> -void exynos_unregister_thermal(void)
> +void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
> {
> int i;
> + struct exynos_thermal_zone *th_zone = sensor_conf->pzone_data;
>
> if (!th_zone)
> return;
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index fd789a5..a845c2d 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -84,22 +84,23 @@ struct thermal_sensor_conf {
> struct thermal_trip_point_conf trip_data;
> struct thermal_cooling_conf cooling_data;
> void *private_data;
> + void *pzone_data;
> };
>
> /*Functions used exynos based thermal sensor driver*/
> #ifdef CONFIG_EXYNOS_THERMAL_CORE
> -void exynos_unregister_thermal(void);
> +void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
> int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> -void exynos_report_trigger(void);
> +void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
> #else
> static inline void
> -exynos_unregister_thermal(void) { return; }
> +exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; }
>
> static inline int
> exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
>
> static inline void
> -exynos_report_trigger(void) { return; }
> +exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; }
>
> #endif /* CONFIG_EXYNOS_THERMAL_CORE */
> #endif /* _EXYNOS_THERMAL_COMMON_H */
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index f6f63ca..a7bba69 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -345,6 +345,12 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> { return -EINVAL; }
> #endif/*CONFIG_THERMAL_EMULATION*/
>
> +static struct thermal_sensor_conf exynos_sensor_conf = {
> + .name = "exynos-therm",
> + .read_temperature = (int (*)(void *))exynos_tmu_read,
> + .write_emul_temp = exynos_tmu_set_emulation,
> +};
> +
> static void exynos_tmu_work(struct work_struct *work)
> {
> struct exynos_tmu_data *data = container_of(work,
> @@ -353,7 +359,7 @@ static void exynos_tmu_work(struct work_struct *work)
> const struct exynos_tmu_registers *reg = pdata->registers;
> unsigned int val_irq;
>
> - exynos_report_trigger();
> + exynos_report_trigger(&exynos_sensor_conf);
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> @@ -377,11 +383,6 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
>
> return IRQ_HANDLED;
> }
> -static struct thermal_sensor_conf exynos_sensor_conf = {
> - .name = "exynos-therm",
> - .read_temperature = (int (*)(void *))exynos_tmu_read,
> - .write_emul_temp = exynos_tmu_set_emulation,
> -};
>
> #ifdef CONFIG_OF
> static const struct of_device_id exynos_tmu_match[] = {
> @@ -541,7 +542,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
>
> exynos_tmu_control(pdev, false);
>
> - exynos_unregister_thermal();
> + exynos_unregister_thermal(&exynos_sensor_conf);
>
> clk_unprepare(data->clk);
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch renames member private_data to driver_data of the thermal
> zone registration structure as this item stores the driver related
> data and uses it to call the driver related callbacks.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 4 ++--
> drivers/thermal/samsung/exynos_thermal_common.h | 2 +-
> drivers/thermal/samsung/exynos_tmu.c | 2 +-
> 3 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index 2af1e3b..7064eb7 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -221,7 +221,7 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
> pr_info("Temperature sensor not initialised\n");
> return -EINVAL;
> }
> - data = th_zone->sensor_conf->private_data;
> + data = th_zone->sensor_conf->driver_data;
> *temp = th_zone->sensor_conf->read_temperature(data);
> /* convert the temperature into millicelsius */
> *temp = *temp * MCELSIUS;
> @@ -240,7 +240,7 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> pr_info("Temperature sensor not initialised\n");
> return -EINVAL;
> }
> - data = th_zone->sensor_conf->private_data;
> + data = th_zone->sensor_conf->driver_data;
> if (th_zone->sensor_conf->write_emul_temp)
> ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> return ret;
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index a845c2d..1e9a326 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -83,7 +83,7 @@ struct thermal_sensor_conf {
> int (*write_emul_temp)(void *drv_data, unsigned long temp);
> struct thermal_trip_point_conf trip_data;
> struct thermal_cooling_conf cooling_data;
> - void *private_data;
> + void *driver_data;
> void *pzone_data;
> };
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index a7bba69..40e0cfd 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -504,7 +504,7 @@ static int exynos_tmu_probe(struct platform_device *pdev)
> exynos_tmu_control(pdev, true);
>
> /* Register the sensor with thermal management interface */
> - (&exynos_sensor_conf)->private_data = data;
> + (&exynos_sensor_conf)->driver_data = data;
> exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
> pdata->trigger_enable[3];
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch removes the error return in the bind/unbind routine
> as the platform may not register any cpufreq cooling data.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index 7064eb7..86d39aa 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -131,7 +131,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
> tab_size = data->cooling_data.freq_clip_count;
>
> if (tab_ptr == NULL || tab_size == 0)
> - return -EINVAL;
> + return 0;
>
> /* find the cooling device registered*/
> for (i = 0; i < th_zone->cool_dev_size; i++)
> @@ -180,7 +180,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
> tab_size = data->cooling_data.freq_clip_count;
>
> if (tab_size == 0)
> - return -EINVAL;
> + return 0;
>
> /* find the cooling device registered*/
> for (i = 0; i < th_zone->cool_dev_size; i++)
>
I have one question before acking this one: what happens if one
registers a TMU with no freq tab? Say the case where you have three
sensors, just like SOC_ARCH_EXYNOS5440. Would you register
cpufreq_cooling device for all of them? In other way, are you having 3
cpufreq_cooling devices?
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code simplifies the zone handling to use the trip information passed
> by the TMU driver and not the hardcoded macros. This also helps in adding
> more zone support.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 61 +++++++++++++----------
> drivers/thermal/samsung/exynos_thermal_common.h | 3 +-
> drivers/thermal/samsung/exynos_tmu.c | 5 ++-
> 3 files changed, 40 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index 86d39aa..2873ca3 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -78,17 +78,22 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
> static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> enum thermal_trip_type *type)
> {
> - switch (GET_ZONE(trip)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - *type = THERMAL_TRIP_ACTIVE;
> - break;
> - case PANIC_ZONE:
> - *type = THERMAL_TRIP_CRITICAL;
> - break;
> - default:
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
> + int trip_type;
> +
> + if (trip < 0 || trip >= max_trip)
> return -EINVAL;
> - }
> +
> + trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
> +
> + if (trip_type == SW_TRIP)
> + *type = THERMAL_TRIP_CRITICAL;
> + else if (trip_type == THROTTLE_ACTIVE)
> + *type = THERMAL_TRIP_ACTIVE;
> + else if (trip_type == THROTTLE_PASSIVE)
> + *type = THERMAL_TRIP_PASSIVE;
> +
> return 0;
> }
>
> @@ -97,8 +102,9 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> unsigned long *temp)
> {
> struct exynos_thermal_zone *th_zone = thermal->devdata;
> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>
> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> + if (trip < 0 || trip >= max_trip)
> return -EINVAL;
>
> *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> @@ -112,10 +118,10 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> unsigned long *temp)
> {
> - int ret;
> - /* Panic zone */
> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> - return ret;
> + struct exynos_thermal_zone *th_zone = thermal->devdata;
> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
> + /* Get the temp of highest trip*/
> + return exynos_get_trip_temp(thermal, max_trip - 1, temp);
> }
>
> /* Bind callback functions for thermal zone */
> @@ -340,19 +346,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> return -ENOMEM;
>
> th_zone->sensor_conf = sensor_conf;
> - cpumask_set_cpu(0, &mask_val);
> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> - if (IS_ERR(th_zone->cool_dev[0])) {
> - pr_err("Failed to register cpufreq cooling device\n");
> - ret = -EINVAL;
> - goto err_unregister;
> + if (sensor_conf->cooling_data.freq_clip_count > 0) {
> + cpumask_set_cpu(0, &mask_val);
> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
Did you mean th_zone->cool_dev[th_zone->cool_dev_size] ?
I think the logic behind the allocation of these cpufreq cooling devices
needs to be revisited. You always assigned to cool_dev[0], but you
always iterate the array until cool_dev_size. Remember that
cool_dev_size now is per th_zone, not global.
> + if (IS_ERR(th_zone->cool_dev[0])) {
> + pr_err("Failed to register cpufreq cooling device\n");
> + ret = -EINVAL;
> + goto err_unregister;
> + }
> + th_zone->cool_dev_size++;
> }
> - th_zone->cool_dev_size++;
>
> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> - EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
> - sensor_conf->trip_data.trigger_falling ?
> - 0 : IDLE_INTERVAL);
> + th_zone->therm_dev = thermal_zone_device_register(
> + sensor_conf->name, sensor_conf->trip_data.trip_count,
> + 0, th_zone, &exynos_dev_ops, NULL, 0,
> + sensor_conf->trip_data.trigger_falling ? 0 :
> + IDLE_INTERVAL);
>
> if (IS_ERR(th_zone->therm_dev)) {
> pr_err("Failed to register thermal zone device\n");
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index 1e9a326..dd0077e 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -42,8 +42,6 @@
> #define GET_ZONE(trip) (trip + 2)
> #define GET_TRIP(zone) (zone - 2)
>
> -#define EXYNOS_ZONE_COUNT 3
> -
> enum trigger_type {
> THROTTLE_ACTIVE = 1,
> THROTTLE_PASSIVE,
> @@ -68,6 +66,7 @@ struct freq_clip_table {
> };
> struct thermal_trip_point_conf {
> int trip_val[MAX_TRIP_COUNT];
> + int trip_type[MAX_TRIP_COUNT];
> int trip_count;
> unsigned char trigger_falling;
> };
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 40e0cfd..acbd295 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -509,9 +509,12 @@ static int exynos_tmu_probe(struct platform_device *pdev)
> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
> pdata->trigger_enable[3];
>
> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
> + for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
> exynos_sensor_conf.trip_data.trip_val[i] =
> pdata->threshold + pdata->trigger_levels[i];
> + exynos_sensor_conf.trip_data.trip_type[i] =
> + pdata->trigger_type[i];
> + }
>
> exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 19-06-2013 18:54, Eduardo Valentin wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch removes the error return in the bind/unbind routine
>> as the platform may not register any cpufreq cooling data.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.c | 4 ++--
>> 1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> index 7064eb7..86d39aa 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -131,7 +131,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
>> tab_size = data->cooling_data.freq_clip_count;
>>
>> if (tab_ptr == NULL || tab_size == 0)
>> - return -EINVAL;
>> + return 0;
>>
>> /* find the cooling device registered*/
>> for (i = 0; i < th_zone->cool_dev_size; i++)
>> @@ -180,7 +180,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
>> tab_size = data->cooling_data.freq_clip_count;
>>
>> if (tab_size == 0)
>> - return -EINVAL;
>> + return 0;
>>
>> /* find the cooling device registered*/
>> for (i = 0; i < th_zone->cool_dev_size; i++)
>>
>
> I have one question before acking this one: what happens if one
> registers a TMU with no freq tab? Say the case where you have three
> sensors, just like SOC_ARCH_EXYNOS5440. Would you register
> cpufreq_cooling device for all of them? In other way, are you having 3
> cpufreq_cooling devices?
I am actually fine with this patch. just saw that you adjust things on
patch 16.
Acked-by: Eduardo Valentin <[email protected]>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> Recently non DT support from Exynos platform is removed and hence
> removing non DT support from the driver also. This will help in easy
> maintainence.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 17 +----------------
> 1 files changed, 1 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index acbd295..4356118 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -403,19 +403,6 @@ static const struct of_device_id exynos_tmu_match[] = {
> MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> #endif
>
> -static struct platform_device_id exynos_tmu_driver_ids[] = {
> - {
> - .name = "exynos4210-tmu",
> - .driver_data = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
> - },
> - {
> - .name = "exynos5250-tmu",
> - .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
> - },
> - { },
> -};
> -MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
> -
> static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
> struct platform_device *pdev)
> {
> @@ -428,8 +415,7 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
> return (struct exynos_tmu_platform_data *) match->data;
> }
> #endif
> - return (struct exynos_tmu_platform_data *)
> - platform_get_device_id(pdev)->driver_data;
> + return NULL;
> }
>
> static int exynos_tmu_probe(struct platform_device *pdev)
> @@ -586,7 +572,6 @@ static struct platform_driver exynos_tmu_driver = {
> },
> .probe = exynos_tmu_probe,
> .remove = exynos_tmu_remove,
> - .id_table = exynos_tmu_driver_ids,
> };
>
> module_platform_driver(exynos_tmu_driver);
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds support to handle multiple instances of the TMU controllers.
> This is done by removing the static structure to register with the core thermal
> and creating it dynamically for each instance of the TMU controller. The
> interrupt is made shared type to handle shared interrupts. Also
> the identifier of the TMU controller is extracted from device tree alias.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.h | 1 +
> drivers/thermal/samsung/exynos_tmu.c | 147 ++++++++++++++++-------
> drivers/thermal/samsung/exynos_tmu.h | 13 ++
> drivers/thermal/samsung/exynos_tmu_data.c | 145 ++++++++++++----------
> drivers/thermal/samsung/exynos_tmu_data.h | 4 +-
> 5 files changed, 197 insertions(+), 113 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index dd0077e..0c189d6 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -84,6 +84,7 @@ struct thermal_sensor_conf {
> struct thermal_cooling_conf cooling_data;
> void *driver_data;
> void *pzone_data;
> + struct device *dev;
> };
>
> /*Functions used exynos based thermal sensor driver*/
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 4356118..1880c4e 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -26,15 +26,32 @@
> #include <linux/interrupt.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> #include <linux/platform_device.h>
>
> #include "exynos_thermal_common.h"
> #include "exynos_tmu.h"
> #include "exynos_tmu_data.h"
>
> +/**
> + * struct exynos_tmu_data : A structure to hold the private data of the TMU
> + driver
> + * @id: identifier of the one instance of the TMU controller.
> + * @pdata: pointer to the tmu platform/configuration data
> + * @base: base address of the single instance of the TMU controller.
> + * @irq: irq number of the TMU controller.
> + * @soc: id of the SOC type.
> + * @irq_work: pointer to the irq work structure.
> + * @lock: lock to implement synchronization.
> + * @clk: pointer to the clock structure.
> + * @temp_error1: fused value of the first point trim.
> + * @temp_error2: fused value of the second point trim.
> + * @reg_conf: pointer to structure to register with core thermal.
> + */
> struct exynos_tmu_data {
> + int id;
> struct exynos_tmu_platform_data *pdata;
> - struct resource *mem;
> void __iomem *base;
> int irq;
> enum soc_type soc;
> @@ -42,6 +59,7 @@ struct exynos_tmu_data {
> struct mutex lock;
> struct clk *clk;
> u8 temp_error1, temp_error2;
> + struct thermal_sensor_conf *reg_conf;
> };
>
> /*
> @@ -345,12 +363,6 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> { return -EINVAL; }
> #endif/*CONFIG_THERMAL_EMULATION*/
>
> -static struct thermal_sensor_conf exynos_sensor_conf = {
> - .name = "exynos-therm",
> - .read_temperature = (int (*)(void *))exynos_tmu_read,
> - .write_emul_temp = exynos_tmu_set_emulation,
> -};
> -
> static void exynos_tmu_work(struct work_struct *work)
> {
> struct exynos_tmu_data *data = container_of(work,
> @@ -359,7 +371,7 @@ static void exynos_tmu_work(struct work_struct *work)
> const struct exynos_tmu_registers *reg = pdata->registers;
> unsigned int val_irq;
>
> - exynos_report_trigger(&exynos_sensor_conf);
> + exynos_report_trigger(data->reg_conf);
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> @@ -404,33 +416,73 @@ MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> #endif
>
> static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
> - struct platform_device *pdev)
> + struct platform_device *pdev, int id)
> {
> + struct exynos_tmu_init_data *data_table;
> + struct exynos_tmu_platform_data *tmu_data;
> #ifdef CONFIG_OF
> if (pdev->dev.of_node) {
> const struct of_device_id *match;
> match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
> if (!match)
> return NULL;
> - return (struct exynos_tmu_platform_data *) match->data;
> + data_table = (struct exynos_tmu_init_data *) match->data;
> + if (!data_table || id >= data_table->tmu_count)
> + return NULL;
> + tmu_data = data_table->tmu_data;
> + return (struct exynos_tmu_platform_data *) (tmu_data + id);
> }
> #endif
> return NULL;
> }
>
> -static int exynos_tmu_probe(struct platform_device *pdev)
> +static int exynos_map_dt_data(struct platform_device *pdev)
> {
> - struct exynos_tmu_data *data;
> - struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
> - int ret, i;
> + struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> + struct exynos_tmu_platform_data *pdata;
> + struct resource res;
>
> - if (!pdata)
> - pdata = exynos_get_driver_data(pdev);
> + if (!data)
> + return -ENODEV;
> +
> + data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
> + if (data->id < 0)
> + data->id = 0;
>
> + data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
> + if (data->irq <= 0) {
> + dev_err(&pdev->dev, "failed to get IRQ\n");
> + return -ENODEV;
> + }
> +
> + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
> + dev_err(&pdev->dev, "failed to get Resource 0\n");
> + return -ENODEV;
> + }
> +
> + data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
> + if (!data->base) {
> + dev_err(&pdev->dev, "Failed to ioremap memory\n");
> + return -EADDRNOTAVAIL;
> + }
> +
> + pdata = exynos_get_driver_data(pdev, data->id);
> if (!pdata) {
> dev_err(&pdev->dev, "No platform init data supplied.\n");
> return -ENODEV;
> }
> + data->pdata = pdata;
> +
> + return 0;
> +}
> +
> +static int exynos_tmu_probe(struct platform_device *pdev)
> +{
> + struct exynos_tmu_data *data;
> + struct exynos_tmu_platform_data *pdata;
> + struct thermal_sensor_conf *sensor_conf;
> + int ret, i;
> +
> data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
> GFP_KERNEL);
> if (!data) {
> @@ -438,21 +490,18 @@ static int exynos_tmu_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> - data->irq = platform_get_irq(pdev, 0);
> - if (data->irq < 0) {
> - dev_err(&pdev->dev, "Failed to get platform irq\n");
> - return data->irq;
> - }
> + platform_set_drvdata(pdev, data);
> + mutex_init(&data->lock);
>
> - INIT_WORK(&data->irq_work, exynos_tmu_work);
> + ret = exynos_map_dt_data(pdev);
> + if (ret)
> + return ret;
>
> - data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - data->base = devm_ioremap_resource(&pdev->dev, data->mem);
> - if (IS_ERR(data->base))
> - return PTR_ERR(data->base);
> + pdata = data->pdata;
>
> + INIT_WORK(&data->irq_work, exynos_tmu_work);
> ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
> - IRQF_TRIGGER_RISING, "exynos-tmu", data);
> + IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
Lets think about this poing: You request the IRQ before data->reg_conf
is allocated (below). Does it mean, from this point you can get called
to the IRQ handler even if reg_conf is not set? What happens then? I see
your irqhandler/worker use it.
> if (ret) {
> dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
> return ret;
> @@ -477,10 +526,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
> goto err_clk;
> }
>
> - data->pdata = pdata;
> - platform_set_drvdata(pdev, data);
> - mutex_init(&data->lock);
> -
> ret = exynos_tmu_initialize(pdev);
> if (ret) {
> dev_err(&pdev->dev, "Failed to initialize TMU\n");
> @@ -489,31 +534,43 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>
> exynos_tmu_control(pdev, true);
>
> - /* Register the sensor with thermal management interface */
> - (&exynos_sensor_conf)->driver_data = data;
> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
> + /* Allocate a structure to register with the exynos core thermal */
> + sensor_conf = devm_kzalloc(&pdev->dev,
> + sizeof(struct thermal_sensor_conf), GFP_KERNEL);
> + if (!sensor_conf) {
> + dev_err(&pdev->dev, "Failed to allocate registration struct\n");
> + ret = -ENOMEM;
> + goto err_clk;
> + }
> + data->reg_conf = sensor_conf;
> + sprintf(sensor_conf->name, "therm_zone%d", data->id);
> + sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
> + sensor_conf->write_emul_temp =
> + (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
> + sensor_conf->driver_data = data;
> + sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
> pdata->trigger_enable[3];
>
> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
> - exynos_sensor_conf.trip_data.trip_val[i] =
> + for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
> + sensor_conf->trip_data.trip_val[i] =
> pdata->threshold + pdata->trigger_levels[i];
> - exynos_sensor_conf.trip_data.trip_type[i] =
> + sensor_conf->trip_data.trip_type[i] =
> pdata->trigger_type[i];
> }
>
> - exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
> + sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
>
> - exynos_sensor_conf.cooling_data.freq_clip_count =
> - pdata->freq_tab_count;
> + sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
> for (i = 0; i < pdata->freq_tab_count; i++) {
> - exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
> + sensor_conf->cooling_data.freq_data[i].freq_clip_max =
> pdata->freq_tab[i].freq_clip_max;
> - exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
> + sensor_conf->cooling_data.freq_data[i].temp_level =
> pdata->freq_tab[i].temp_level;
> }
> -
> - ret = exynos_register_thermal(&exynos_sensor_conf);
> + sensor_conf->dev = &pdev->dev;
> + /* Register the sensor with thermal management interface */
> + ret = exynos_register_thermal(sensor_conf);
> if (ret) {
> dev_err(&pdev->dev, "Failed to register thermal interface\n");
> goto err_clk;
> @@ -531,7 +588,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
>
> exynos_tmu_control(pdev, false);
>
> - exynos_unregister_thermal(&exynos_sensor_conf);
> + exynos_unregister_thermal(data->reg_conf);
>
> clk_unprepare(data->clk);
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 619a34c..b614407 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -248,4 +248,17 @@ struct exynos_tmu_platform_data {
> unsigned int freq_tab_count;
> const struct exynos_tmu_registers *registers;
> };
> +
> +/**
> + * struct exynos_tmu_init_data
> + * @tmu_count: number of TMU instances.
> + * @tmu_data: platform data of all TMU instances.
> + * This structure is required to store data for multi-instance exynos tmu
> + * driver.
> + */
> +struct exynos_tmu_init_data {
> + int tmu_count;
> + struct exynos_tmu_platform_data tmu_data[];
> +};
> +
> #endif /* _EXYNOS_TMU_H */
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index 7fcf183..06ecfb0 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -48,38 +48,44 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
> .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
> .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
> };
> -struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
> - .threshold = 80,
> - .trigger_levels[0] = 5,
> - .trigger_levels[1] = 20,
> - .trigger_levels[2] = 30,
> - .trigger_enable[0] = 1,
> - .trigger_enable[1] = 1,
> - .trigger_enable[2] = 1,
> - .trigger_enable[3] = 0,
> - .trigger_type[0] = THROTTLE_ACTIVE,
> - .trigger_type[1] = THROTTLE_ACTIVE,
> - .trigger_type[2] = SW_TRIP,
> - .max_trigger_level = 4,
> - .gain = 15,
> - .reference_voltage = 7,
> - .cal_type = TYPE_ONE_POINT_TRIMMING,
> - .min_efuse_value = 40,
> - .max_efuse_value = 100,
> - .first_point_trim = 25,
> - .second_point_trim = 85,
> - .default_temp_offset = 50,
> - .freq_tab[0] = {
> - .freq_clip_max = 800 * 1000,
> - .temp_level = 85,
> - },
> - .freq_tab[1] = {
> - .freq_clip_max = 200 * 1000,
> - .temp_level = 100,
> +
> +struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
> + .tmu_data = {
> + {
> + .threshold = 80,
> + .trigger_levels[0] = 5,
> + .trigger_levels[1] = 20,
> + .trigger_levels[2] = 30,
> + .trigger_enable[0] = 1,
> + .trigger_enable[1] = 1,
> + .trigger_enable[2] = 1,
> + .trigger_enable[3] = 0,
> + .trigger_type[0] = THROTTLE_ACTIVE,
> + .trigger_type[1] = THROTTLE_ACTIVE,
> + .trigger_type[2] = SW_TRIP,
> + .max_trigger_level = 4,
> + .gain = 15,
> + .reference_voltage = 7,
> + .cal_type = TYPE_ONE_POINT_TRIMMING,
> + .min_efuse_value = 40,
> + .max_efuse_value = 100,
> + .first_point_trim = 25,
> + .second_point_trim = 85,
> + .default_temp_offset = 50,
> + .freq_tab[0] = {
> + .freq_clip_max = 800 * 1000,
> + .temp_level = 85,
> + },
> + .freq_tab[1] = {
> + .freq_clip_max = 200 * 1000,
> + .temp_level = 100,
> + },
> + .freq_tab_count = 2,
> + .type = SOC_ARCH_EXYNOS4210,
> + .registers = &exynos4210_tmu_registers,
> + },
> },
> - .freq_tab_count = 2,
> - .type = SOC_ARCH_EXYNOS4210,
> - .registers = &exynos4210_tmu_registers,
> + .tmu_count = 1,
> };
> #endif
>
> @@ -120,41 +126,48 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
> .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
> .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
> };
> -struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
> - .threshold_falling = 10,
> - .trigger_levels[0] = 85,
> - .trigger_levels[1] = 103,
> - .trigger_levels[2] = 110,
> - .trigger_levels[3] = 120,
> - .trigger_enable[0] = 1,
> - .trigger_enable[1] = 1,
> - .trigger_enable[2] = 1,
> - .trigger_enable[3] = 0,
> - .trigger_type[0] = THROTTLE_ACTIVE,
> - .trigger_type[1] = THROTTLE_ACTIVE,
> - .trigger_type[2] = SW_TRIP,
> - .trigger_type[3] = HW_TRIP,
> - .max_trigger_level = 4,
> - .gain = 8,
> - .reference_voltage = 16,
> - .noise_cancel_mode = 4,
> - .cal_type = TYPE_ONE_POINT_TRIMMING,
> - .efuse_value = 55,
> - .min_efuse_value = 40,
> - .max_efuse_value = 100,
> - .first_point_trim = 25,
> - .second_point_trim = 85,
> - .default_temp_offset = 50,
> - .freq_tab[0] = {
> - .freq_clip_max = 800 * 1000,
> - .temp_level = 85,
> - },
> - .freq_tab[1] = {
> - .freq_clip_max = 200 * 1000,
> - .temp_level = 103,
> - },
> - .freq_tab_count = 2,
> - .type = SOC_ARCH_EXYNOS,
> +
> +#define EXYNOS5250_TMU_DATA \
> + .threshold_falling = 10, \
> + .trigger_levels[0] = 85, \
> + .trigger_levels[1] = 103, \
> + .trigger_levels[2] = 110, \
> + .trigger_levels[3] = 120, \
> + .trigger_enable[0] = 1, \
> + .trigger_enable[1] = 1, \
> + .trigger_enable[2] = 1, \
> + .trigger_enable[3] = 0, \
> + .trigger_type[0] = THROTTLE_ACTIVE, \
> + .trigger_type[1] = THROTTLE_ACTIVE, \
> + .trigger_type[2] = SW_TRIP, \
> + .trigger_type[3] = HW_TRIP, \
> + .max_trigger_level = 4, \
> + .gain = 8, \
> + .reference_voltage = 16, \
> + .noise_cancel_mode = 4, \
> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
> + .efuse_value = 55, \
> + .min_efuse_value = 40, \
> + .max_efuse_value = 100, \
> + .first_point_trim = 25, \
> + .second_point_trim = 85, \
> + .default_temp_offset = 50, \
> + .freq_tab[0] = { \
> + .freq_clip_max = 800 * 1000, \
> + .temp_level = 85, \
> + }, \
> + .freq_tab[1] = { \
> + .freq_clip_max = 200 * 1000, \
> + .temp_level = 103, \
> + }, \
> + .freq_tab_count = 2, \
> + .type = SOC_ARCH_EXYNOS, \
> .registers = &exynos5250_tmu_registers,
> +
> +struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
> + .tmu_data = {
> + { EXYNOS5250_TMU_DATA },
> + },
> + .tmu_count = 1,
> };
> #endif
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index 4acf070..139dbbb 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -94,14 +94,14 @@
> #define EXYNOS_MAX_TRIGGER_PER_REG 4
>
> #if defined(CONFIG_CPU_EXYNOS4210)
> -extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
> +extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
> #else
> #define EXYNOS4210_TMU_DRV_DATA (NULL)
> #endif
>
> #if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
> -extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
> +extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
> #define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
> #else
> #define EXYNOS5250_TMU_DRV_DATA (NULL)
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds several features supported by TMU as bitfields.
> This features varies across different SOC type and comparing
> the features present in the TMU is more logical than comparing
> the soc itself.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 26 +++++++++++++++---------
> drivers/thermal/samsung/exynos_tmu.h | 31 +++++++++++++++++++++++++++++
> drivers/thermal/samsung/exynos_tmu_data.c | 6 ++++-
> 3 files changed, 52 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 1880c4e..877dab8 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -142,13 +142,15 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> mutex_lock(&data->lock);
> clk_enable(data->clk);
>
> - status = readb(data->base + reg->tmu_status);
> - if (!status) {
> - ret = -EBUSY;
> - goto out;
> + if (TMU_SUPPORTS(pdata, READY_STATUS)) {
> + status = readb(data->base + reg->tmu_status);
> + if (!status) {
> + ret = -EBUSY;
> + goto out;
> + }
> }
>
> - if (data->soc == SOC_ARCH_EXYNOS)
> + if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
> __raw_writel(1, data->base + reg->triminfo_ctrl);
>
> /* Save trimming info in order to perform calibration */
> @@ -287,7 +289,7 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
> pdata->trigger_enable[2] << reg->inten_rise2_shift |
> pdata->trigger_enable[1] << reg->inten_rise1_shift |
> pdata->trigger_enable[0] << reg->inten_rise0_shift;
> - if (pdata->threshold_falling)
> + if (TMU_SUPPORTS(pdata, FALLING_TRIP))
> interrupt_en |=
> interrupt_en << reg->inten_fall0_shift;
> } else {
> @@ -329,7 +331,7 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> unsigned int val;
> int ret = -EINVAL;
>
> - if (data->soc == SOC_ARCH_EXYNOS4210)
> + if (!TMU_SUPPORTS(pdata, EMULATION))
> goto out;
>
> if (temp && temp < MCELSIUS)
> @@ -343,9 +345,13 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
> if (temp) {
> temp /= MCELSIUS;
>
> - val = (EXYNOS_EMUL_TIME << reg->emul_time_shift) |
> - (temp_to_code(data, temp)
> - << reg->emul_temp_shift) | EXYNOS_EMUL_ENABLE;
> + if (TMU_SUPPORTS(pdata, EMUL_TIME)) {
> + val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift);
> + val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift);
> + }
> + val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift);
> + val |= (temp_to_code(data, temp) << reg->emul_temp_shift) |
> + EXYNOS_EMUL_ENABLE;
> } else {
> val &= ~EXYNOS_EMUL_ENABLE;
> }
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index b614407..6f55673 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -41,6 +41,34 @@ enum soc_type {
> };
>
> /**
> + * EXYNOS TMU supported features.
> + * TMU_SUPPORT_EMULATION - This features is used to set user defined
> + * temperature to the TMU controller.
> + * TMU_SUPPORT_MULTI_INST - This features denotes that the soc
> + * has many instances of TMU.
> + * TMU_SUPPORT_TRIM_RELOAD - This features shows that trimming can
> + * be reloaded.
> + * TMU_SUPPORT_FALLING_TRIP - This features shows that interrupt can
> + * be registered for falling trips also.
> + * TMU_SUPPORT_READY_STATUS - This feature tells that the TMU current
> + * state(active/idle) can be checked.
> + * TMU_SUPPORT_EMUL_TIME - This features allows to set next temp emulation
> + * sample time.
> + * TMU_SUPPORT_SHARED_MEMORY - This feature tells that the different TMU
> + * sensors shares some common registers.
> + * TMU_SUPPORT - macro to compare the above features with the supplied.
> + */
> +#define TMU_SUPPORT_EMULATION BIT(0)
> +#define TMU_SUPPORT_MULTI_INST BIT(1)
> +#define TMU_SUPPORT_TRIM_RELOAD BIT(2)
> +#define TMU_SUPPORT_FALLING_TRIP BIT(3)
> +#define TMU_SUPPORT_READY_STATUS BIT(4)
> +#define TMU_SUPPORT_EMUL_TIME BIT(5)
> +#define TMU_SUPPORT_SHARED_MEMORY BIT(6)
> +
> +#define TMU_SUPPORTS(a, b) (a->features & TMU_SUPPORT_ ## b)
> +
> +/**
> * struct exynos_tmu_register - register descriptors to access registers and
> * bitfields. The register validity, offsets and bitfield values may vary
> * slightly across different exynos SOC's.
> @@ -220,6 +248,8 @@ struct exynos_tmu_registers {
> * applicable to only some of the trigger levels.
> * @registers: Pointer to structure containing all the TMU controller registers
> * and bitfields shifts and masks.
> + * @features: a bitfield value indicating the features supported in SOC like
> + * emulation, multi instance etc
> *
> * This structure is required for configuration of exynos_tmu driver.
> */
> @@ -247,6 +277,7 @@ struct exynos_tmu_platform_data {
> struct freq_clip_table freq_tab[4];
> unsigned int freq_tab_count;
> const struct exynos_tmu_registers *registers;
> + unsigned int features;
> };
>
> /**
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index 06ecfb0..694557e 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -83,6 +83,7 @@ struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
> .freq_tab_count = 2,
> .type = SOC_ARCH_EXYNOS4210,
> .registers = &exynos4210_tmu_registers,
> + .features = TMU_SUPPORT_READY_STATUS,
> },
> },
> .tmu_count = 1,
> @@ -162,7 +163,10 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
> }, \
> .freq_tab_count = 2, \
> .type = SOC_ARCH_EXYNOS, \
> - .registers = &exynos5250_tmu_registers,
> + .registers = &exynos5250_tmu_registers, \
> + .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \
> + TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
> + TMU_SUPPORT_EMUL_TIME)
>
> struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
> .tmu_data = {
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch uses the device pointer stored in the configuration structure
> and converts to dev_* prints and devm API's.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_thermal_common.c | 39 ++++++++++++++--------
> 1 files changed, 25 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> index 2873ca3..59b47e3 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.c
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -52,7 +52,8 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
> {
> struct exynos_thermal_zone *th_zone = thermal->devdata;
> if (!th_zone) {
> - pr_notice("thermal zone not registered\n");
> + dev_err(th_zone->sensor_conf->dev,
> + "thermal zone not registered\n");
> return 0;
> }
>
> @@ -68,8 +69,9 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
>
> th_zone->mode = mode;
> thermal_zone_device_update(thermal);
> - pr_info("thermal polling set for duration=%d msec\n",
> - thermal->polling_delay);
> + dev_dbg(th_zone->sensor_conf->dev,
> + "thermal polling set for duration=%d msec\n",
> + thermal->polling_delay);
> return 0;
> }
>
> @@ -159,7 +161,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
> case WARN_ZONE:
> if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> level, 0)) {
> - pr_err("error binding cdev inst %d\n", i);
> + dev_err(data->dev,
> + "error unbinding cdev inst=%d\n", i);
> ret = -EINVAL;
> }
> th_zone->bind = true;
> @@ -204,7 +207,8 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
> case WARN_ZONE:
> if (thermal_zone_unbind_cooling_device(thermal, i,
> cdev)) {
> - pr_err("error unbinding cdev inst=%d\n", i);
> + dev_err(data->dev,
> + "error unbinding cdev inst=%d\n", i);
> ret = -EINVAL;
> }
> th_zone->bind = false;
> @@ -224,7 +228,8 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
> void *data;
>
> if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> + dev_err(th_zone->sensor_conf->dev,
> + "Temperature sensor not initialised\n");
> return -EINVAL;
> }
> data = th_zone->sensor_conf->driver_data;
> @@ -243,7 +248,8 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> struct exynos_thermal_zone *th_zone = thermal->devdata;
>
> if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> + dev_err(th_zone->sensor_conf->dev,
> + "Temperature sensor not initialised\n");
> return -EINVAL;
> }
> data = th_zone->sensor_conf->driver_data;
> @@ -337,11 +343,13 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> struct exynos_thermal_zone *th_zone;
>
> if (!sensor_conf || !sensor_conf->read_temperature) {
> - pr_err("Temperature sensor not initialised\n");
> + dev_err(sensor_conf->dev,
> + "Temperature sensor not initialised\n");
> return -EINVAL;
> }
>
> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> + th_zone = devm_kzalloc(sensor_conf->dev,
> + sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> if (!th_zone)
> return -ENOMEM;
>
> @@ -350,7 +358,8 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> cpumask_set_cpu(0, &mask_val);
> th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> if (IS_ERR(th_zone->cool_dev[0])) {
> - pr_err("Failed to register cpufreq cooling device\n");
> + dev_err(sensor_conf->dev,
> + "Failed to register cpufreq cooling device\n");
> ret = -EINVAL;
> goto err_unregister;
> }
> @@ -364,14 +373,16 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> IDLE_INTERVAL);
>
> if (IS_ERR(th_zone->therm_dev)) {
> - pr_err("Failed to register thermal zone device\n");
> + dev_err(sensor_conf->dev,
> + "Failed to register thermal zone device\n");
> ret = PTR_ERR(th_zone->therm_dev);
> goto err_unregister;
> }
> th_zone->mode = THERMAL_DEVICE_ENABLED;
> sensor_conf->pzone_data = th_zone;
>
> - pr_info("Exynos: Kernel Thermal management registered\n");
> + dev_info(sensor_conf->dev,
> + "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
>
> return 0;
>
> @@ -397,6 +408,6 @@ void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
> cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> }
>
> - kfree(th_zone);
> - pr_info("Exynos: Kernel Thermal management unregistered\n");
> + dev_info(sensor_conf->dev,
> + "Exynos: Kernel Thermal management unregistered\n");
> }
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> From: Lukasz Majewski <[email protected]>
>
> Proper description for Exynos4 bindings added to Documentation/devicetree/
> bindings
>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Kyungmin Park <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 25 ++++++++++++++++++++
> 1 files changed, 25 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>
> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> new file mode 100644
> index 0000000..535fd0e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> @@ -0,0 +1,25 @@
> +* Exynos Thermal Management Unit (TMU)
> +
> +** Required properties:
> +
> +- compatible : One of the following:
> + "samsung,exynos4412-tmu"
> + "samsung,exynos4210-tmu"
> + "samsung,exynos5250-tmu"
> +- interrupt-parent : The phandle for the interrupt controller
> +- reg : Address range of the thermal registers
> +- interrupts : Should contain interrupt for thermal system
> +- clocks : The main clock for TMU device
> +- clock-names : Thermal system clock name
Should this include the documentation on the alias needed by patch 18?
tmuctrl?
> +
> +Example:
> +
> + tmu@100C0000 {
> + compatible = "samsung,exynos4412-tmu";
> + interrupt-parent = <&combiner>;
> + reg = <0x100C0000 0x100>;
> + interrupts = <2 4>;
> + clocks = <&clock 383>;
> + clock-names = "tmu_apbif";
> + status = "disabled";
> + };
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds support to parse one more common set of TMU register. First
> set of register belongs to each instance of TMU and second set belongs to
> common TMU registers.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
This patch is fine:
Acked-by: Eduardo Valentin <[email protected]>
But please read my concern on next patch.
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 6 +++++-
> drivers/thermal/samsung/exynos_tmu.c | 20 ++++++++++++++++++++
> 2 files changed, 25 insertions(+), 1 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> index 535fd0e..0ea33f7 100644
> --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> @@ -7,7 +7,11 @@
> "samsung,exynos4210-tmu"
> "samsung,exynos5250-tmu"
> - interrupt-parent : The phandle for the interrupt controller
> -- reg : Address range of the thermal registers
> +- reg : Address range of the thermal registers. For soc's which has multiple
> + instances of TMU and some registers are shared across all TMU's like
> + interrupt related then 2 set of register has to supplied. First set
> + belongs to each instance of TMU and second set belongs to common TMU
> + registers.
> - interrupts : Should contain interrupt for thermal system
> - clocks : The main clock for TMU device
> - clock-names : Thermal system clock name
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 877dab8..150a869 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -40,6 +40,7 @@
> * @id: identifier of the one instance of the TMU controller.
> * @pdata: pointer to the tmu platform/configuration data
> * @base: base address of the single instance of the TMU controller.
> + * @base_common: base address of the common registers of the TMU controller.
> * @irq: irq number of the TMU controller.
> * @soc: id of the SOC type.
> * @irq_work: pointer to the irq work structure.
> @@ -53,6 +54,7 @@ struct exynos_tmu_data {
> int id;
> struct exynos_tmu_platform_data *pdata;
> void __iomem *base;
> + void __iomem *base_common;
> int irq;
> enum soc_type soc;
> struct work_struct irq_work;
> @@ -478,6 +480,24 @@ static int exynos_map_dt_data(struct platform_device *pdev)
> return -ENODEV;
> }
> data->pdata = pdata;
> + /*
> + * Check if the TMU shares some registers and then try to map the
> + * memory of common registers.
> + */
> + if (!TMU_SUPPORTS(pdata, SHARED_MEMORY))
> + return 0;
> +
> + if (of_address_to_resource(pdev->dev.of_node, 1, &res)) {
> + dev_err(&pdev->dev, "failed to get Resource 1\n");
> + return -ENODEV;
> + }
> +
> + data->base_common = devm_ioremap(&pdev->dev, res.start,
> + resource_size(&res));
> + if (!data->base) {
> + dev_err(&pdev->dev, "Failed to ioremap memory\n");
> + return -ENOMEM;
> + }
>
> return 0;
> }
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch modifies TMU controller to add changes needed to work with
> exynos5440 platform. This sensor registers 3 instance of the tmu controller
> with the thermal zone and hence reports 3 temperature output. This controller
> supports upto five trip points. For critical threshold the driver uses the
> core driver thermal framework for shutdown.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Jungseok Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 24 ++++++++-
> drivers/thermal/samsung/exynos_thermal_common.h | 2 +-
> drivers/thermal/samsung/exynos_tmu.c | 54 +++++++++++++++++---
> drivers/thermal/samsung/exynos_tmu.h | 6 ++
> drivers/thermal/samsung/exynos_tmu_data.h | 36 +++++++++++++
> 5 files changed, 112 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> index 0ea33f7..e6386ea 100644
> --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> @@ -6,6 +6,7 @@
> "samsung,exynos4412-tmu"
> "samsung,exynos4210-tmu"
> "samsung,exynos5250-tmu"
> + "samsung,exynos5440-tmu"
> - interrupt-parent : The phandle for the interrupt controller
> - reg : Address range of the thermal registers. For soc's which has multiple
> instances of TMU and some registers are shared across all TMU's like
> @@ -16,7 +17,7 @@
> - clocks : The main clock for TMU device
> - clock-names : Thermal system clock name
>
> -Example:
> +Example 1):
>
> tmu@100C0000 {
> compatible = "samsung,exynos4412-tmu";
> @@ -27,3 +28,24 @@ Example:
> clock-names = "tmu_apbif";
> status = "disabled";
> };
> +
> +Example 2):
> +
> + tmuctrl_0: tmuctrl@160118 {
> + compatible = "samsung,exynos5440-tmu";
> + reg = <0x160118 0x230>, <0x160368 0x10>;
> + interrupts = <0 58 0>;
> + clocks = <&clock 21>;
> + clock-names = "tmu_apbif";
> + };
> +
> +Note: For multi-instance tmu each instance should have an alias correctly
> +numbered in "aliases" node.
> +
> +Example:
> +
> +aliases {
> + tmuctrl0 = &tmuctrl_0;
> + tmuctrl1 = &tmuctrl_1;
> + tmuctrl2 = &tmuctrl_2;
> +};
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> index 0c189d6..7d7c29a 100644
> --- a/drivers/thermal/samsung/exynos_thermal_common.h
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -27,7 +27,7 @@
> #define SENSOR_NAME_LEN 16
> #define MAX_TRIP_COUNT 8
> #define MAX_COOLING_DEVICE 4
> -#define MAX_THRESHOLD_LEVS 4
> +#define MAX_THRESHOLD_LEVS 5
>
> #define ACTIVE_INTERVAL 500
> #define IDLE_INTERVAL 10000
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 150a869..db4035d 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -156,7 +156,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> __raw_writel(1, data->base + reg->triminfo_ctrl);
>
> /* Save trimming info in order to perform calibration */
> - trim_info = readl(data->base + reg->triminfo_data);
> + if (data->soc == SOC_ARCH_EXYNOS5440) {
should this become some bit at your pdata->features? TMU_SUPPORTS(pdata,
TRIMINFO) for instance?
> + /*
> + * For exynos5440 soc triminfo value is swapped between TMU0 and
> + * TMU2, so the below logic is needed.
> + */
> + switch (data->id) {
> + case 0:
> + trim_info = readl(data->base +
> + EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
> + break;
> + case 1:
> + trim_info = readl(data->base + reg->triminfo_data);
> + break;
> + case 2:
> + trim_info = readl(data->base -
> + EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
> + }
> + } else {
> + trim_info = readl(data->base + reg->triminfo_data);
> + }
> data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
> data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
> EXYNOS_TMU_TEMP_MASK);
> @@ -201,7 +220,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> reg->threshold_th0 + i * sizeof(reg->threshold_th0));
>
> writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
> - } else if (data->soc == SOC_ARCH_EXYNOS) {
> + } else if (data->soc == SOC_ARCH_EXYNOS ||
> + data->soc == SOC_ARCH_EXYNOS5440) {
> /* Write temperature code for rising and falling threshold */
> for (i = 0;
> i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
> @@ -241,14 +261,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> ret = threshold_code;
> goto out;
> }
> - rising_threshold |= threshold_code << 8 * i;
> - writel(rising_threshold,
> - data->base + reg->threshold_th0);
> + if (data->soc == SOC_ARCH_EXYNOS) {
> + rising_threshold |= threshold_code << 8 * i;
> + writel(rising_threshold,
> + data->base + reg->threshold_th0);
> + } else if (data->soc == SOC_ARCH_EXYNOS5440) {
Can these ifs be translated to some TMU_SUPPORTS()?
Just wondering if it is possible to get rid of data->soc flags and use
only features or represent the shifts as fields inside your pdata.
> + rising_threshold =
> + threshold_code << reg->threshold_th3_l0_shift;
> + writel(rising_threshold,
> + data->base + reg->threshold_th2);
> + }
> con = readl(data->base + reg->tmu_ctrl);
> con |= (1 << reg->therm_trip_en_shift);
> writel(con, data->base + reg->tmu_ctrl);
> }
> }
> + /*Clear the PMIN in the common TMU register*/
> + if (reg->tmu_pmin && !data->id)
> + writel(0, data->base_common + reg->tmu_pmin);
What happens to other TMU instances when one of them performs this
operation? does it need to serialized?
> out:
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
> @@ -377,7 +407,14 @@ static void exynos_tmu_work(struct work_struct *work)
> struct exynos_tmu_data, irq_work);
> struct exynos_tmu_platform_data *pdata = data->pdata;
> const struct exynos_tmu_registers *reg = pdata->registers;
> - unsigned int val_irq;
> + unsigned int val_irq, val_type;
> +
> + /* Find which sensor generated this interrupt */
> + if (reg->tmu_irqstatus) {
> + val_type = readl(data->base_common + reg->tmu_irqstatus);
> + if (!((val_type >> data->id) & 0x1))
> + goto out;
> + }
>
> exynos_report_trigger(data->reg_conf);
> mutex_lock(&data->lock);
> @@ -390,7 +427,7 @@ static void exynos_tmu_work(struct work_struct *work)
>
> clk_disable(data->clk);
> mutex_unlock(&data->lock);
> -
> +out:
> enable_irq(data->irq);
> }
>
> @@ -544,7 +581,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
> return ret;
>
> if (pdata->type == SOC_ARCH_EXYNOS ||
> - pdata->type == SOC_ARCH_EXYNOS4210)
> + pdata->type == SOC_ARCH_EXYNOS4210 ||
> + pdata->type == SOC_ARCH_EXYNOS5440)
> data->soc = pdata->type;
> else {
> ret = -EINVAL;
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 6f55673..73aaed7 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -38,6 +38,7 @@ enum calibration_mode {
> enum soc_type {
> SOC_ARCH_EXYNOS4210 = 1,
> SOC_ARCH_EXYNOS,
> + SOC_ARCH_EXYNOS5440,
> };
>
> /**
> @@ -129,6 +130,8 @@ enum soc_type {
> * @emul_temp_shift: shift bits of emulation temperature.
> * @emul_time_shift: shift bits of emulation time.
> * @emul_time_mask: mask bits of emulation time.
> + * @tmu_irqstatus: register to find which TMU generated interrupts.
> + * @tmu_pmin: register to get/set the Pmin value.
> */
> struct exynos_tmu_registers {
> u32 triminfo_data;
> @@ -196,6 +199,9 @@ struct exynos_tmu_registers {
> u32 emul_temp_shift;
> u32 emul_time_shift;
> u32 emul_time_mask;
> +
> + u32 tmu_irqstatus;
> + u32 tmu_pmin;
> };
>
> /**
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index 139dbbb..ad263e9 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -93,6 +93,42 @@
>
> #define EXYNOS_MAX_TRIGGER_PER_REG 4
>
> +/*exynos5440 specific registers*/
> +#define EXYNOS5440_TMU_S0_7_TRIM 0x000
> +#define EXYNOS5440_TMU_S0_7_CTRL 0x020
> +#define EXYNOS5440_TMU_S0_7_DEBUG 0x040
> +#define EXYNOS5440_TMU_S0_7_STATUS 0x060
> +#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0
> +#define EXYNOS5440_TMU_S0_7_TH0 0x110
> +#define EXYNOS5440_TMU_S0_7_TH1 0x130
> +#define EXYNOS5440_TMU_S0_7_TH2 0x150
> +#define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0
> +#define EXYNOS5440_TMU_S0_7_IRQEN 0x210
> +#define EXYNOS5440_TMU_S0_7_IRQ 0x230
> +/* exynos5440 common registers */
> +#define EXYNOS5440_TMU_IRQ_STATUS 0x000
> +#define EXYNOS5440_TMU_PMIN 0x004
> +#define EXYNOS5440_TMU_TEMP 0x008
> +
> +#define EXYNOS5440_TMU_RISE_INT_MASK 0xf
> +#define EXYNOS5440_TMU_RISE_INT_SHIFT 0
> +#define EXYNOS5440_TMU_FALL_INT_MASK 0xf
> +#define EXYNOS5440_TMU_FALL_INT_SHIFT 4
> +#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0
> +#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1
> +#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2
> +#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3
> +#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4
> +#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5
> +#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6
> +#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7
> +#define EXYNOS5440_TMU_TH_RISE0_SHIFT 0
> +#define EXYNOS5440_TMU_TH_RISE1_SHIFT 8
> +#define EXYNOS5440_TMU_TH_RISE2_SHIFT 16
> +#define EXYNOS5440_TMU_TH_RISE3_SHIFT 24
> +#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
> +#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
> +
> #if defined(CONFIG_CPU_EXYNOS4210)
> extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds configuration data for exynos5440 soc. Also register
> definations for the controller are added.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 4 ++
> drivers/thermal/samsung/exynos_tmu_data.c | 71 +++++++++++++++++++++++++++++
> drivers/thermal/samsung/exynos_tmu_data.h | 7 +++
> 3 files changed, 82 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index db4035d..a4dbc84 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -455,6 +455,10 @@ static const struct of_device_id exynos_tmu_match[] = {
> .compatible = "samsung,exynos5250-tmu",
> .data = (void *)EXYNOS5250_TMU_DRV_DATA,
> },
> + {
> + .compatible = "samsung,exynos5440-tmu",
> + .data = (void *)EXYNOS5440_TMU_DRV_DATA,
> + },
> {},
> };
> MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index 694557e..b34e726 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -175,3 +175,74 @@ struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
> .tmu_count = 1,
> };
> #endif
> +
> +#if defined(CONFIG_SOC_EXYNOS5440)
> +static const struct exynos_tmu_registers exynos5440_tmu_registers = {
> + .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
> + .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
> + .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
> + .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
> + .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
> + .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
> + .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
> + .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
> + .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
> + .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
> + .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
> + .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
> + .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
> + .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
> + .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
> + .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
> + .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
> + .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
> + .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
> + .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
> + .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
> + .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
> + .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
> + .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
> + .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
> + .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
> + .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
> + .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
> + .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
> + .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
> + .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
> + .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
> + .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
> + .tmu_pmin = EXYNOS5440_TMU_PMIN,
> +};
> +
> +#define EXYNOS5440_TMU_DATA \
> + .trigger_levels[0] = 100, \
> + .trigger_levels[4] = 105, \
> + .trigger_enable[0] = 1, \
> + .trigger_type[0] = SW_TRIP, \
> + .trigger_type[4] = HW_TRIP, \
No active / passive cooling?
> + .max_trigger_level = 5, \
> + .gain = 5, \
> + .reference_voltage = 16, \
> + .noise_cancel_mode = 4, \
> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
> + .cal_mode = 0, \
> + .efuse_value = 0x5b2d, \
> + .min_efuse_value = 16, \
> + .max_efuse_value = 76, \
> + .first_point_trim = 25, \
> + .second_point_trim = 70, \
> + .default_temp_offset = 25, \
> + .type = SOC_ARCH_EXYNOS5440, \
> + .registers = &exynos5440_tmu_registers, \
> + .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
> + TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
No freq table on 5440? hmm.. So no cpufreq_cooling then? Any reason why
not? I suppose one of these 3 sensors are on your CPU domain, right?
> +
> +struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
> + .tmu_data = {
> + { EXYNOS5440_TMU_DATA } ,
> + { EXYNOS5440_TMU_DATA } ,
> + { EXYNOS5440_TMU_DATA } ,
> + },
> + .tmu_count = 3,
> +};
> +#endif
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index ad263e9..43ce5fb 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -143,4 +143,11 @@ extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
> #define EXYNOS5250_TMU_DRV_DATA (NULL)
> #endif
>
> +#if defined(CONFIG_SOC_EXYNOS5440)
> +extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
> +#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
> +#else
> +#define EXYNOS5440_TMU_DRV_DATA (NULL)
> +#endif
> +
> #endif /*_EXYNOS_TMU_DATA_H*/
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch sets the second point trimming value according to the platform
> data if the register value is 0.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 13 +++++++++----
> 1 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index a4dbc84..af0e6ca 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -180,10 +180,15 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
> EXYNOS_TMU_TEMP_MASK);
>
> - if ((pdata->min_efuse_value > data->temp_error1) ||
> - (data->temp_error1 > pdata->max_efuse_value) ||
> - (data->temp_error2 != 0))
> - data->temp_error1 = pdata->efuse_value;
> + if (!data->temp_error1 ||
> + (pdata->min_efuse_value > data->temp_error1) ||
> + (data->temp_error1 > pdata->max_efuse_value))
> + data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
> +
> + if (!data->temp_error2)
> + data->temp_error2 =
> + (pdata->efuse_value >> reg->triminfo_85_shift) &
> + EXYNOS_TMU_TEMP_MASK;
>
> if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
> dev_err(&pdev->dev, "Invalid max trigger level\n");
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds support for h/w mode calibration in the TMU controller.
> soc's like 5440 support this features.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
> ---
> drivers/thermal/samsung/exynos_tmu.c | 15 +++++++++++++++
> drivers/thermal/samsung/exynos_tmu.h | 6 ++++++
> drivers/thermal/samsung/exynos_tmu_data.c | 2 ++
> drivers/thermal/samsung/exynos_tmu_data.h | 2 ++
> 4 files changed, 25 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index af0e6ca..7a259f4 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -73,6 +73,9 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
> struct exynos_tmu_platform_data *pdata = data->pdata;
> int temp_code;
>
> + if (pdata->cal_mode == HW_MODE)
> + return temp;
> +
> if (data->soc == SOC_ARCH_EXYNOS4210)
> /* temp should range between 25 and 125 */
> if (temp < 25 || temp > 125) {
> @@ -107,6 +110,9 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
> struct exynos_tmu_platform_data *pdata = data->pdata;
> int temp;
>
> + if (pdata->cal_mode == HW_MODE)
> + return temp_code;
> +
> if (data->soc == SOC_ARCH_EXYNOS4210)
> /* temp_code should range between 75 and 175 */
> if (temp_code < 75 || temp_code > 175) {
> @@ -155,6 +161,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
> __raw_writel(1, data->base + reg->triminfo_ctrl);
>
> + if (pdata->cal_mode == HW_MODE)
> + goto skip_calib_data;
> +
> /* Save trimming info in order to perform calibration */
> if (data->soc == SOC_ARCH_EXYNOS5440) {
> /*
> @@ -190,6 +199,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
> (pdata->efuse_value >> reg->triminfo_85_shift) &
> EXYNOS_TMU_TEMP_MASK;
>
> +skip_calib_data:
> if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
> dev_err(&pdev->dev, "Invalid max trigger level\n");
> goto out;
> @@ -319,6 +329,11 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
> con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
> }
>
> + if (pdata->cal_mode == HW_MODE) {
> + con &= ~(reg->calib_mode_mask << reg->calib_mode_shift);
> + con |= pdata->cal_type << reg->calib_mode_shift;
cal_type is an enum and you don't set any constant value to those
enumerations. are you sure you want to rely on it for bit field handling?
> + }
> +
> if (on) {
> con |= (1 << reg->core_en_shift);
> interrupt_en =
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 73aaed7..abfa1eb 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -88,6 +88,10 @@ enum soc_type {
> * @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
> register.
> * @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
> + * @calib_mode_shift: shift bits of calibration mode value in tmu_ctrl
> + register.
> + * @calib_mode_mask: mask bits of calibration mode value in tmu_ctrl
> + register.
> * @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
> tmu_ctrl register.
> * @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
> @@ -149,6 +153,8 @@ struct exynos_tmu_registers {
> u32 therm_trip_en_shift;
> u32 buf_slope_sel_shift;
> u32 buf_slope_sel_mask;
> + u32 calib_mode_shift;
> + u32 calib_mode_mask;
> u32 therm_trip_tq_en_shift;
> u32 core_en_shift;
>
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
> index b34e726..47c5d6b 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.c
> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
> @@ -189,6 +189,8 @@ static const struct exynos_tmu_registers exynos5440_tmu_registers = {
> .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
> .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
> .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
> + .calib_mode_shift = EXYNOS_TMU_CALIB_MODE_SHIFT,
> + .calib_mode_mask = EXYNOS_TMU_CALIB_MODE_MASK,
> .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
> .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
> .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
> index 43ce5fb..dc7feb5 100644
> --- a/drivers/thermal/samsung/exynos_tmu_data.h
> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
> @@ -75,6 +75,8 @@
> #define EXYNOS_TMU_TRIP_MODE_SHIFT 13
> #define EXYNOS_TMU_TRIP_MODE_MASK 0x7
> #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
> +#define EXYNOS_TMU_CALIB_MODE_SHIFT 4
> +#define EXYNOS_TMU_CALIB_MODE_MASK 0x3
>
> #define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
> #define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch updates the documentation to explain the driver model
> and file layout.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> Documentation/thermal/exynos_thermal | 43 ++++++++++++++++++++++++++-------
> 1 files changed, 34 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/thermal/exynos_thermal b/Documentation/thermal/exynos_thermal
> index 2b46f67..9010c44 100644
> --- a/Documentation/thermal/exynos_thermal
> +++ b/Documentation/thermal/exynos_thermal
> @@ -1,17 +1,17 @@
> -Kernel driver exynos4_tmu
> +Kernel driver exynos_tmu
> =================
>
> Supported chips:
> -* ARM SAMSUNG EXYNOS4 series of SoC
> - Prefix: 'exynos4-tmu'
> +* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
> Datasheet: Not publicly available
>
> Authors: Donggeun Kim <[email protected]>
> +Authors: Amit Daniel <[email protected]>
>
> -Description
> ------------
> +TMU controller Description:
> +---------------------------
>
> -This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
> +This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
>
> The chip only exposes the measured 8-bit temperature code value
> through a register.
> @@ -34,9 +34,9 @@ The three equations are:
> TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
> Temperature code measured at 85 degree Celsius which is unchanged
>
> -TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
> +TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
> when temperature exceeds pre-defined levels.
> -The maximum number of configurable threshold is four.
> +The maximum number of configurable threshold is five.
> The threshold levels are defined as follows:
> Level_0: current temperature > trigger_level_0 + threshold
> Level_1: current temperature > trigger_level_1 + threshold
> @@ -47,6 +47,31 @@ The threshold levels are defined as follows:
> through the corresponding registers.
>
> When an interrupt occurs, this driver notify kernel thermal framework
> -with the function exynos4_report_trigger.
> +with the function exynos_report_trigger.
> Although an interrupt condition for level_0 can be set,
> it can be used to synchronize the cooling action.
> +
> +TMU driver description:
> +-----------------------
> +
> +The exynos thermal driver is structured as,
> +
> + Kernel Core thermal framework
> + (thermal_core.c, step_wise.c, cpu_cooling.c)
> + ^
> + |
> + |
> +TMU configuration data -------> TMU Driver <------> Exynos Core thermal wrapper
> +(exynos_tmu_data.c) (exynos_tmu.c) (exynos_thermal_common.c)
> +(exynos_tmu_data.h) (exynos_tmu.h) (exynos_thermal_common.h)
> +
> +a) TMU configuration data: This consist of TMU register offsets/bitfields
> + described through structure exynos_tmu_registers. Also several
> + other platform data (struct exynos_tmu_platform_data) members
> + are used to configure the TMU.
> +b) TMU driver: This component initialises the TMU controller and sets different
> + thresholds. It invokes core thermal implementation with the call
> + exynos_report_trigger.
> +c) Exynos Core thermal wrapper: This provides 3 wrapper function to use the
> + Kernel core thermal framework. They are exynos_unregister_thermal,
> + exynos_register_thermal and exynos_report_trigger.
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> TMU probe function now checks for a device tree defined regulator.
> For compatibility reasons it is allowed to probe driver even without
> this regulator defined.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Lukasz Majewski <[email protected]>
> Signed-off-by: Kyungmin Park <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 4 +++
> drivers/thermal/samsung/exynos_tmu.c | 23 ++++++++++++++++++++
> 2 files changed, 27 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> index e6386ea..284f530 100644
> --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> @@ -16,6 +16,9 @@
> - interrupts : Should contain interrupt for thermal system
> - clocks : The main clock for TMU device
> - clock-names : Thermal system clock name
> +- vtmu-supply: This entry is optional and provides the regulator node supplying
> + voltage to TMU. If needed this entry can be placed inside
> + board/platform specific dts file.
>
> Example 1):
>
> @@ -27,6 +30,7 @@ Example 1):
> clocks = <&clock 383>;
> clock-names = "tmu_apbif";
> status = "disabled";
> + vtmu-supply = <&tmu_regulator_node>;
> };
>
> Example 2):
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index 7a259f4..441efd5 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -29,6 +29,7 @@
> #include <linux/of_address.h>
> #include <linux/of_irq.h>
> #include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
>
> #include "exynos_thermal_common.h"
> #include "exynos_tmu.h"
> @@ -48,6 +49,7 @@
> * @clk: pointer to the clock structure.
> * @temp_error1: fused value of the first point trim.
> * @temp_error2: fused value of the second point trim.
> + * @regulator: pointer to the TMU regulator structure.
> * @reg_conf: pointer to structure to register with core thermal.
> */
> struct exynos_tmu_data {
> @@ -61,6 +63,7 @@ struct exynos_tmu_data {
> struct mutex lock;
> struct clk *clk;
> u8 temp_error1, temp_error2;
> + struct regulator *regulator;
> struct thermal_sensor_conf *reg_conf;
> };
>
> @@ -510,10 +513,27 @@ static int exynos_map_dt_data(struct platform_device *pdev)
> struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> struct exynos_tmu_platform_data *pdata;
> struct resource res;
> + int ret;
>
> if (!data)
> return -ENODEV;
>
> + /*
> + * Try enabling the regulator if found
> + * TODO: Add regulator as an SOC feature, so that regulator enable
> + * is a compulsory call.
> + */
> + data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
> + if (!IS_ERR(data->regulator)) {
> + ret = regulator_enable(data->regulator);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to enable vtmu\n");
> + return ret;
> + }
> + } else {
> + dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
> + }
> +
> data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
> if (data->id < 0)
> data->id = 0;
> @@ -680,6 +700,9 @@ static int exynos_tmu_remove(struct platform_device *pdev)
>
> clk_unprepare(data->clk);
>
> + if (!IS_ERR(data->regulator))
> + regulator_disable(data->regulator);
> +
> return 0;
> }
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This patch adds device node for TMU controller. There are 3
> instances of the controllers so 3 nodes are created.
>
> Acked-by: Jonghwa Lee <[email protected]>
> Acked-by: Kukjin Kim <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Reviewed-by: Eduardo Valentin <[email protected]>
> ---
> arch/arm/boot/dts/exynos5440.dtsi | 30 ++++++++++++++++++++++++++++++
> 1 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
> index f6b1c89..716e90c 100644
> --- a/arch/arm/boot/dts/exynos5440.dtsi
> +++ b/arch/arm/boot/dts/exynos5440.dtsi
> @@ -16,6 +16,12 @@
>
> interrupt-parent = <&gic>;
>
> + aliases {
> + tmuctrl0 = &tmuctrl_0;
> + tmuctrl1 = &tmuctrl_1;
> + tmuctrl2 = &tmuctrl_2;
> + };
> +
> clock: clock-controller@0x160000 {
> compatible = "samsung,exynos5440-clock";
> reg = <0x160000 0x1000>;
> @@ -216,4 +222,28 @@
> clock-names = "rtc";
> status = "disabled";
> };
> +
> + tmuctrl_0: tmuctrl@160118 {
> + compatible = "samsung,exynos5440-tmu";
> + reg = <0x160118 0x230>, <0x160368 0x10>;
> + interrupts = <0 58 0>;
> + clocks = <&clock 21>;
> + clock-names = "tmu_apbif";
> + };
> +
> + tmuctrl_1: tmuctrl@16011C {
> + compatible = "samsung,exynos5440-tmu";
> + reg = <0x16011C 0x230>, <0x160368 0x10>;
> + interrupts = <0 58 0>;
> + clocks = <&clock 21>;
> + clock-names = "tmu_apbif";
> + };
> +
> + tmuctrl_2: tmuctrl@160120 {
> + compatible = "samsung,exynos5440-tmu";
> + reg = <0x160120 0x230>, <0x160368 0x10>;
> + interrupts = <0 58 0>;
> + clocks = <&clock 21>;
> + clock-names = "tmu_apbif";
> + };
> };
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On Thu, Jun 20, 2013 at 12:15 AM, Eduardo Valentin
<[email protected]> wrote:
> Amit,
>
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This code bifurcates exynos thermal implementation into common and sensor
>> specific parts. The common thermal code interacts with core thermal layer and
>> core cpufreq cooling parts and is independent of SOC specific driver. This
>> change is needed to cleanly add support for new TMU sensors.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/Kconfig | 19 +-
>> drivers/thermal/samsung/Makefile | 4 +-
>> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
>> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
>> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
>> 5 files changed, 490 insertions(+), 419 deletions(-)
>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>>
>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>> index 2cf31ad..f8100b1 100644
>> --- a/drivers/thermal/samsung/Kconfig
>> +++ b/drivers/thermal/samsung/Kconfig
>> @@ -1,8 +1,17 @@
>> config EXYNOS_THERMAL
>> - tristate "Temperature sensor on Samsung EXYNOS"
>> + tristate "Exynos thermal management unit driver"
>> depends on ARCH_HAS_BANDGAP
>> help
>> - If you say yes here you get support for TMU (Thermal Management
>> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
>> - the exynos thermal driver with the core thermal layer and cpu
>> - cooling API's.
>> + If you say yes here you get support for the TMU (Thermal Management
>> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>> + the TMU, reports temperature and handles cooling action if defined.
>> + This driver uses the exynos core thermal API's.
>> +
>> +config EXYNOS_THERMAL_CORE
>> + bool "Core thermal framework support for EXYNOS SOC's"
>> + depends on EXYNOS_THERMAL
>> + help
>> + If you say yes here you get support for EXYNOS TMU
>> + (Thermal Management Unit) common registration/unregistration
>> + functions to the core thermal layer and also to use the generic
>> + cpu cooling API's.
> Should this one depend on CPU_THERMAL? Is it mandatory?
Hi Eduardo,
No it is not mandatory. If CPU_THERMAL is not present then cooling
device is not created and only temp/trip_points etc sysfs are created.
Thanks,
Amit Daniel
>
>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>> index 1fe6d93..6227d4f 100644
>> --- a/drivers/thermal/samsung/Makefile
>> +++ b/drivers/thermal/samsung/Makefile
>> @@ -1,4 +1,6 @@
>> #
>> # Samsung thermal specific Makefile
>> #
>> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
>> +exynos_soc_thermal-y := exynos_thermal.o
>> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
>> index 03e4bbc..5293849 100644
>> --- a/drivers/thermal/samsung/exynos_thermal.c
>> +++ b/drivers/thermal/samsung/exynos_thermal.c
>> @@ -21,23 +21,15 @@
>> *
>> */
>>
>> -#include <linux/module.h>
>> -#include <linux/err.h>
>> -#include <linux/kernel.h>
>> -#include <linux/slab.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/interrupt.h>
>> #include <linux/clk.h>
>> -#include <linux/workqueue.h>
>> -#include <linux/sysfs.h>
>> -#include <linux/kobject.h>
>> #include <linux/io.h>
>> -#include <linux/mutex.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>> -#include <linux/thermal.h>
>> -#include <linux/cpufreq.h>
>> -#include <linux/cpu_cooling.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> #include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +
>> +#include "exynos_thermal_common.h"
>>
>> /* Exynos generic registers */
>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>> @@ -88,16 +80,6 @@
>> #define EFUSE_MIN_VALUE 40
>> #define EFUSE_MAX_VALUE 100
>>
>> -/* In-kernel thermal framework related macros & definations */
>> -#define SENSOR_NAME_LEN 16
>> -#define MAX_TRIP_COUNT 8
>> -#define MAX_COOLING_DEVICE 4
>> -#define MAX_THRESHOLD_LEVS 4
>> -
>> -#define ACTIVE_INTERVAL 500
>> -#define IDLE_INTERVAL 10000
>> -#define MCELSIUS 1000
>> -
>> #ifdef CONFIG_THERMAL_EMULATION
>> #define EXYNOS_EMUL_TIME 0x57F0
>> #define EXYNOS_EMUL_TIME_SHIFT 16
>> @@ -106,17 +88,6 @@
>> #define EXYNOS_EMUL_ENABLE 0x1
>> #endif /* CONFIG_THERMAL_EMULATION */
>>
>> -/* CPU Zone information */
>> -#define PANIC_ZONE 4
>> -#define WARN_ZONE 3
>> -#define MONITOR_ZONE 2
>> -#define SAFE_ZONE 1
>> -
>> -#define GET_ZONE(trip) (trip + 2)
>> -#define GET_TRIP(zone) (zone - 2)
>> -
>> -#define EXYNOS_ZONE_COUNT 3
>> -
>> struct exynos_tmu_data {
>> struct exynos_tmu_platform_data *pdata;
>> struct resource *mem;
>> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
>> u8 temp_error1, temp_error2;
>> };
>>
>> -struct thermal_trip_point_conf {
>> - int trip_val[MAX_TRIP_COUNT];
>> - int trip_count;
>> - u8 trigger_falling;
>> -};
>> -
>> -struct thermal_cooling_conf {
>> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> - int freq_clip_count;
>> -};
>> -
>> -struct thermal_sensor_conf {
>> - char name[SENSOR_NAME_LEN];
>> - int (*read_temperature)(void *data);
>> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> - struct thermal_trip_point_conf trip_data;
>> - struct thermal_cooling_conf cooling_data;
>> - void *private_data;
>> -};
>> -
>> -struct exynos_thermal_zone {
>> - enum thermal_device_mode mode;
>> - struct thermal_zone_device *therm_dev;
>> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> - unsigned int cool_dev_size;
>> - struct platform_device *exynos4_dev;
>> - struct thermal_sensor_conf *sensor_conf;
>> - bool bind;
>> -};
>> -
>> -static struct exynos_thermal_zone *th_zone;
>> -static void exynos_unregister_thermal(void);
>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>> -
>> -/* Get mode callback functions for thermal zone */
>> -static int exynos_get_mode(struct thermal_zone_device *thermal,
>> - enum thermal_device_mode *mode)
>> -{
>> - if (th_zone)
>> - *mode = th_zone->mode;
>> - return 0;
>> -}
>> -
>> -/* Set mode callback functions for thermal zone */
>> -static int exynos_set_mode(struct thermal_zone_device *thermal,
>> - enum thermal_device_mode mode)
>> -{
>> - if (!th_zone->therm_dev) {
>> - pr_notice("thermal zone not registered\n");
>> - return 0;
>> - }
>> -
>> - mutex_lock(&th_zone->therm_dev->lock);
>> -
>> - if (mode == THERMAL_DEVICE_ENABLED &&
>> - !th_zone->sensor_conf->trip_data.trigger_falling)
>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> - else
>> - th_zone->therm_dev->polling_delay = 0;
>> -
>> - mutex_unlock(&th_zone->therm_dev->lock);
>> -
>> - th_zone->mode = mode;
>> - thermal_zone_device_update(th_zone->therm_dev);
>> - pr_info("thermal polling set for duration=%d msec\n",
>> - th_zone->therm_dev->polling_delay);
>> - return 0;
>> -}
>> -
>> -
>> -/* Get trip type callback functions for thermal zone */
>> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>> - enum thermal_trip_type *type)
>> -{
>> - switch (GET_ZONE(trip)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - *type = THERMAL_TRIP_ACTIVE;
>> - break;
>> - case PANIC_ZONE:
>> - *type = THERMAL_TRIP_CRITICAL;
>> - break;
>> - default:
>> - return -EINVAL;
>> - }
>> - return 0;
>> -}
>> -
>> -/* Get trip temperature callback functions for thermal zone */
>> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> - unsigned long *temp)
>> -{
>> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> - return -EINVAL;
>> -
>> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> - /* convert the temperature into millicelsius */
>> - *temp = *temp * MCELSIUS;
>> -
>> - return 0;
>> -}
>> -
>> -/* Get critical temperature callback functions for thermal zone */
>> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> - unsigned long *temp)
>> -{
>> - int ret;
>> - /* Panic zone */
>> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> - return ret;
>> -}
>> -
>> -/* Bind callback functions for thermal zone */
>> -static int exynos_bind(struct thermal_zone_device *thermal,
>> - struct thermal_cooling_device *cdev)
>> -{
>> - int ret = 0, i, tab_size, level;
>> - struct freq_clip_table *tab_ptr, *clip_data;
>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> - tab_size = data->cooling_data.freq_clip_count;
>> -
>> - if (tab_ptr == NULL || tab_size == 0)
>> - return -EINVAL;
>> -
>> - /* find the cooling device registered*/
>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>> - if (cdev == th_zone->cool_dev[i])
>> - break;
>> -
>> - /* No matching cooling device */
>> - if (i == th_zone->cool_dev_size)
>> - return 0;
>> -
>> - /* Bind the thermal zone to the cpufreq cooling device */
>> - for (i = 0; i < tab_size; i++) {
>> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>> - if (level == THERMAL_CSTATE_INVALID)
>> - return 0;
>> - switch (GET_ZONE(i)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>> - level, 0)) {
>> - pr_err("error binding cdev inst %d\n", i);
>> - ret = -EINVAL;
>> - }
>> - th_zone->bind = true;
>> - break;
>> - default:
>> - ret = -EINVAL;
>> - }
>> - }
>> -
>> - return ret;
>> -}
>> -
>> -/* Unbind callback functions for thermal zone */
>> -static int exynos_unbind(struct thermal_zone_device *thermal,
>> - struct thermal_cooling_device *cdev)
>> -{
>> - int ret = 0, i, tab_size;
>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> - if (th_zone->bind == false)
>> - return 0;
>> -
>> - tab_size = data->cooling_data.freq_clip_count;
>> -
>> - if (tab_size == 0)
>> - return -EINVAL;
>> -
>> - /* find the cooling device registered*/
>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>> - if (cdev == th_zone->cool_dev[i])
>> - break;
>> -
>> - /* No matching cooling device */
>> - if (i == th_zone->cool_dev_size)
>> - return 0;
>> -
>> - /* Bind the thermal zone to the cpufreq cooling device */
>> - for (i = 0; i < tab_size; i++) {
>> - switch (GET_ZONE(i)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - if (thermal_zone_unbind_cooling_device(thermal, i,
>> - cdev)) {
>> - pr_err("error unbinding cdev inst=%d\n", i);
>> - ret = -EINVAL;
>> - }
>> - th_zone->bind = false;
>> - break;
>> - default:
>> - ret = -EINVAL;
>> - }
>> - }
>> - return ret;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_get_temp(struct thermal_zone_device *thermal,
>> - unsigned long *temp)
>> -{
>> - void *data;
>> -
>> - if (!th_zone->sensor_conf) {
>> - pr_info("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> - data = th_zone->sensor_conf->private_data;
>> - *temp = th_zone->sensor_conf->read_temperature(data);
>> - /* convert the temperature into millicelsius */
>> - *temp = *temp * MCELSIUS;
>> - return 0;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> - unsigned long temp)
>> -{
>> - void *data;
>> - int ret = -EINVAL;
>> -
>> - if (!th_zone->sensor_conf) {
>> - pr_info("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> - data = th_zone->sensor_conf->private_data;
>> - if (th_zone->sensor_conf->write_emul_temp)
>> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> - return ret;
>> -}
>> -
>> -/* Get the temperature trend */
>> -static int exynos_get_trend(struct thermal_zone_device *thermal,
>> - int trip, enum thermal_trend *trend)
>> -{
>> - int ret;
>> - unsigned long trip_temp;
>> -
>> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> - if (ret < 0)
>> - return ret;
>> -
>> - if (thermal->temperature >= trip_temp)
>> - *trend = THERMAL_TREND_RAISE_FULL;
>> - else
>> - *trend = THERMAL_TREND_DROP_FULL;
>> -
>> - return 0;
>> -}
>> -/* Operation callback functions for thermal zone */
>> -static struct thermal_zone_device_ops const exynos_dev_ops = {
>> - .bind = exynos_bind,
>> - .unbind = exynos_unbind,
>> - .get_temp = exynos_get_temp,
>> - .set_emul_temp = exynos_set_emul_temp,
>> - .get_trend = exynos_get_trend,
>> - .get_mode = exynos_get_mode,
>> - .set_mode = exynos_set_mode,
>> - .get_trip_type = exynos_get_trip_type,
>> - .get_trip_temp = exynos_get_trip_temp,
>> - .get_crit_temp = exynos_get_crit_temp,
>> -};
>> -
>> -/*
>> - * This function may be called from interrupt based temperature sensor
>> - * when threshold is changed.
>> - */
>> -static void exynos_report_trigger(void)
>> -{
>> - unsigned int i;
>> - char data[10];
>> - char *envp[] = { data, NULL };
>> -
>> - if (!th_zone || !th_zone->therm_dev)
>> - return;
>> - if (th_zone->bind == false) {
>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>> - if (!th_zone->cool_dev[i])
>> - continue;
>> - exynos_bind(th_zone->therm_dev,
>> - th_zone->cool_dev[i]);
>> - }
>> - }
>> -
>> - thermal_zone_device_update(th_zone->therm_dev);
>> -
>> - mutex_lock(&th_zone->therm_dev->lock);
>> - /* Find the level for which trip happened */
>> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> - if (th_zone->therm_dev->last_temperature <
>> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>> - break;
>> - }
>> -
>> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> - !th_zone->sensor_conf->trip_data.trigger_falling) {
>> - if (i > 0)
>> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>> - else
>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> - }
>> -
>> - snprintf(data, sizeof(data), "%u", i);
>> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>> - mutex_unlock(&th_zone->therm_dev->lock);
>> -}
>> -
>> -/* Register with the in-kernel thermal management */
>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> -{
>> - int ret;
>> - struct cpumask mask_val;
>> -
>> - if (!sensor_conf || !sensor_conf->read_temperature) {
>> - pr_err("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> -
>> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> - if (!th_zone)
>> - return -ENOMEM;
>> -
>> - th_zone->sensor_conf = sensor_conf;
>> - cpumask_set_cpu(0, &mask_val);
>> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> - if (IS_ERR(th_zone->cool_dev[0])) {
>> - pr_err("Failed to register cpufreq cooling device\n");
>> - ret = -EINVAL;
>> - goto err_unregister;
>> - }
>> - th_zone->cool_dev_size++;
>> -
>> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>> - sensor_conf->trip_data.trigger_falling ?
>> - 0 : IDLE_INTERVAL);
>> -
>> - if (IS_ERR(th_zone->therm_dev)) {
>> - pr_err("Failed to register thermal zone device\n");
>> - ret = PTR_ERR(th_zone->therm_dev);
>> - goto err_unregister;
>> - }
>> - th_zone->mode = THERMAL_DEVICE_ENABLED;
>> -
>> - pr_info("Exynos: Kernel Thermal management registered\n");
>> -
>> - return 0;
>> -
>> -err_unregister:
>> - exynos_unregister_thermal();
>> - return ret;
>> -}
>> -
>> -/* Un-Register with the in-kernel thermal management */
>> -static void exynos_unregister_thermal(void)
>> -{
>> - int i;
>> -
>> - if (!th_zone)
>> - return;
>> -
>> - if (th_zone->therm_dev)
>> - thermal_zone_device_unregister(th_zone->therm_dev);
>> -
>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>> - if (th_zone->cool_dev[i])
>> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>> - }
>> -
>> - kfree(th_zone);
>> - pr_info("Exynos: Kernel Thermal management unregistered\n");
>> -}
>> -
>> /*
>> * TMU treats temperature as a mapped temperature code.
>> * The temperature is converted differently depending on the calibration type.
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> new file mode 100644
>> index 0000000..92e50bc
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -0,0 +1,384 @@
>> +/*
>> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#include <linux/cpu_cooling.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +#include <linux/slab.h>
>> +#include <linux/thermal.h>
>> +
>> +#include "exynos_thermal_common.h"
>> +
>> +struct exynos_thermal_zone {
>> + enum thermal_device_mode mode;
>> + struct thermal_zone_device *therm_dev;
>> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> + unsigned int cool_dev_size;
>> + struct platform_device *exynos4_dev;
>> + struct thermal_sensor_conf *sensor_conf;
>> + bool bind;
>> +};
>> +
>> +static struct exynos_thermal_zone *th_zone;
>> +
>> +/* Get mode callback functions for thermal zone */
>> +static int exynos_get_mode(struct thermal_zone_device *thermal,
>> + enum thermal_device_mode *mode)
>> +{
>> + if (th_zone)
>> + *mode = th_zone->mode;
>> + return 0;
>> +}
>> +
>> +/* Set mode callback functions for thermal zone */
>> +static int exynos_set_mode(struct thermal_zone_device *thermal,
>> + enum thermal_device_mode mode)
>> +{
>> + if (!th_zone->therm_dev) {
>> + pr_notice("thermal zone not registered\n");
>> + return 0;
>> + }
>> +
>> + mutex_lock(&th_zone->therm_dev->lock);
>> +
>> + if (mode == THERMAL_DEVICE_ENABLED &&
>> + !th_zone->sensor_conf->trip_data.trigger_falling)
>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> + else
>> + th_zone->therm_dev->polling_delay = 0;
>> +
>> + mutex_unlock(&th_zone->therm_dev->lock);
>> +
>> + th_zone->mode = mode;
>> + thermal_zone_device_update(th_zone->therm_dev);
>> + pr_info("thermal polling set for duration=%d msec\n",
>> + th_zone->therm_dev->polling_delay);
>> + return 0;
>> +}
>> +
>> +
>> +/* Get trip type callback functions for thermal zone */
>> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>> + enum thermal_trip_type *type)
>> +{
>> + switch (GET_ZONE(trip)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + *type = THERMAL_TRIP_ACTIVE;
>> + break;
>> + case PANIC_ZONE:
>> + *type = THERMAL_TRIP_CRITICAL;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + return 0;
>> +}
>> +
>> +/* Get trip temperature callback functions for thermal zone */
>> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> + unsigned long *temp)
>> +{
>> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> + return -EINVAL;
>> +
>> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> + /* convert the temperature into millicelsius */
>> + *temp = *temp * MCELSIUS;
>> +
>> + return 0;
>> +}
>> +
>> +/* Get critical temperature callback functions for thermal zone */
>> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> + unsigned long *temp)
>> +{
>> + int ret;
>> + /* Panic zone */
>> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> + return ret;
>> +}
>> +
>> +/* Bind callback functions for thermal zone */
>> +static int exynos_bind(struct thermal_zone_device *thermal,
>> + struct thermal_cooling_device *cdev)
>> +{
>> + int ret = 0, i, tab_size, level;
>> + struct freq_clip_table *tab_ptr, *clip_data;
>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> + tab_size = data->cooling_data.freq_clip_count;
>> +
>> + if (tab_ptr == NULL || tab_size == 0)
>> + return -EINVAL;
>> +
>> + /* find the cooling device registered*/
>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>> + if (cdev == th_zone->cool_dev[i])
>> + break;
>> +
>> + /* No matching cooling device */
>> + if (i == th_zone->cool_dev_size)
>> + return 0;
>> +
>> + /* Bind the thermal zone to the cpufreq cooling device */
>> + for (i = 0; i < tab_size; i++) {
>> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>> + if (level == THERMAL_CSTATE_INVALID)
>> + return 0;
>> + switch (GET_ZONE(i)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>> + level, 0)) {
>> + pr_err("error binding cdev inst %d\n", i);
>> + ret = -EINVAL;
>> + }
>> + th_zone->bind = true;
>> + break;
>> + default:
>> + ret = -EINVAL;
>> + }
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +/* Unbind callback functions for thermal zone */
>> +static int exynos_unbind(struct thermal_zone_device *thermal,
>> + struct thermal_cooling_device *cdev)
>> +{
>> + int ret = 0, i, tab_size;
>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> + if (th_zone->bind == false)
>> + return 0;
>> +
>> + tab_size = data->cooling_data.freq_clip_count;
>> +
>> + if (tab_size == 0)
>> + return -EINVAL;
>> +
>> + /* find the cooling device registered*/
>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>> + if (cdev == th_zone->cool_dev[i])
>> + break;
>> +
>> + /* No matching cooling device */
>> + if (i == th_zone->cool_dev_size)
>> + return 0;
>> +
>> + /* Bind the thermal zone to the cpufreq cooling device */
>> + for (i = 0; i < tab_size; i++) {
>> + switch (GET_ZONE(i)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + if (thermal_zone_unbind_cooling_device(thermal, i,
>> + cdev)) {
>> + pr_err("error unbinding cdev inst=%d\n", i);
>> + ret = -EINVAL;
>> + }
>> + th_zone->bind = false;
>> + break;
>> + default:
>> + ret = -EINVAL;
>> + }
>> + }
>> + return ret;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_get_temp(struct thermal_zone_device *thermal,
>> + unsigned long *temp)
>> +{
>> + void *data;
>> +
>> + if (!th_zone->sensor_conf) {
>> + pr_info("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> + data = th_zone->sensor_conf->private_data;
>> + *temp = th_zone->sensor_conf->read_temperature(data);
>> + /* convert the temperature into millicelsius */
>> + *temp = *temp * MCELSIUS;
>> + return 0;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> + unsigned long temp)
>> +{
>> + void *data;
>> + int ret = -EINVAL;
>> +
>> + if (!th_zone->sensor_conf) {
>> + pr_info("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> + data = th_zone->sensor_conf->private_data;
>> + if (th_zone->sensor_conf->write_emul_temp)
>> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> + return ret;
>> +}
>> +
>> +/* Get the temperature trend */
>> +static int exynos_get_trend(struct thermal_zone_device *thermal,
>> + int trip, enum thermal_trend *trend)
>> +{
>> + int ret;
>> + unsigned long trip_temp;
>> +
>> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (thermal->temperature >= trip_temp)
>> + *trend = THERMAL_TREND_RAISE_FULL;
>> + else
>> + *trend = THERMAL_TREND_DROP_FULL;
>> +
>> + return 0;
>> +}
>> +/* Operation callback functions for thermal zone */
>> +static struct thermal_zone_device_ops const exynos_dev_ops = {
>> + .bind = exynos_bind,
>> + .unbind = exynos_unbind,
>> + .get_temp = exynos_get_temp,
>> + .set_emul_temp = exynos_set_emul_temp,
>> + .get_trend = exynos_get_trend,
>> + .get_mode = exynos_get_mode,
>> + .set_mode = exynos_set_mode,
>> + .get_trip_type = exynos_get_trip_type,
>> + .get_trip_temp = exynos_get_trip_temp,
>> + .get_crit_temp = exynos_get_crit_temp,
>> +};
>> +
>> +/*
>> + * This function may be called from interrupt based temperature sensor
>> + * when threshold is changed.
>> + */
>> +void exynos_report_trigger(void)
>> +{
>> + unsigned int i;
>> + char data[10];
>> + char *envp[] = { data, NULL };
>> +
>> + if (!th_zone || !th_zone->therm_dev)
>> + return;
>> + if (th_zone->bind == false) {
>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>> + if (!th_zone->cool_dev[i])
>> + continue;
>> + exynos_bind(th_zone->therm_dev,
>> + th_zone->cool_dev[i]);
>> + }
>> + }
>> +
>> + thermal_zone_device_update(th_zone->therm_dev);
>> +
>> + mutex_lock(&th_zone->therm_dev->lock);
>> + /* Find the level for which trip happened */
>> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> + if (th_zone->therm_dev->last_temperature <
>> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>> + break;
>> + }
>> +
>> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> + !th_zone->sensor_conf->trip_data.trigger_falling) {
>> + if (i > 0)
>> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>> + else
>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> + }
>> +
>> + snprintf(data, sizeof(data), "%u", i);
>> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>> + mutex_unlock(&th_zone->therm_dev->lock);
>> +}
>> +
>> +/* Register with the in-kernel thermal management */
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> +{
>> + int ret;
>> + struct cpumask mask_val;
>> +
>> + if (!sensor_conf || !sensor_conf->read_temperature) {
>> + pr_err("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> +
>> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> + if (!th_zone)
>> + return -ENOMEM;
>> +
>> + th_zone->sensor_conf = sensor_conf;
>> + cpumask_set_cpu(0, &mask_val);
>> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> + if (IS_ERR(th_zone->cool_dev[0])) {
>> + pr_err("Failed to register cpufreq cooling device\n");
>> + ret = -EINVAL;
>> + goto err_unregister;
>> + }
>> + th_zone->cool_dev_size++;
>> +
>> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>> + sensor_conf->trip_data.trigger_falling ?
>> + 0 : IDLE_INTERVAL);
>> +
>> + if (IS_ERR(th_zone->therm_dev)) {
>> + pr_err("Failed to register thermal zone device\n");
>> + ret = PTR_ERR(th_zone->therm_dev);
>> + goto err_unregister;
>> + }
>> + th_zone->mode = THERMAL_DEVICE_ENABLED;
>> +
>> + pr_info("Exynos: Kernel Thermal management registered\n");
>> +
>> + return 0;
>> +
>> +err_unregister:
>> + exynos_unregister_thermal();
>> + return ret;
>> +}
>> +
>> +/* Un-Register with the in-kernel thermal management */
>> +void exynos_unregister_thermal(void)
>> +{
>> + int i;
>> +
>> + if (!th_zone)
>> + return;
>> +
>> + if (th_zone->therm_dev)
>> + thermal_zone_device_unregister(th_zone->therm_dev);
>> +
>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>> + if (th_zone->cool_dev[i])
>> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>> + }
>> +
>> + kfree(th_zone);
>> + pr_info("Exynos: Kernel Thermal management unregistered\n");
>> +}
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> new file mode 100644
>> index 0000000..8df1848
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -0,0 +1,83 @@
>> +/*
>> + * exynos_thermal_common.h - Samsung EXYNOS common header file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#ifndef _EXYNOS_THERMAL_COMMON_H
>> +#define _EXYNOS_THERMAL_COMMON_H
>> +
>> +/* In-kernel thermal framework related macros & definations */
>> +#define SENSOR_NAME_LEN 16
>> +#define MAX_TRIP_COUNT 8
>> +#define MAX_COOLING_DEVICE 4
>> +#define MAX_THRESHOLD_LEVS 4
>> +
>> +#define ACTIVE_INTERVAL 500
>> +#define IDLE_INTERVAL 10000
>> +#define MCELSIUS 1000
>> +
>> +/* CPU Zone information */
>> +#define PANIC_ZONE 4
>> +#define WARN_ZONE 3
>> +#define MONITOR_ZONE 2
>> +#define SAFE_ZONE 1
>> +
>> +#define GET_ZONE(trip) (trip + 2)
>> +#define GET_TRIP(zone) (zone - 2)
>> +
>> +#define EXYNOS_ZONE_COUNT 3
>> +
>> +struct thermal_trip_point_conf {
>> + int trip_val[MAX_TRIP_COUNT];
>> + int trip_count;
>> + unsigned char trigger_falling;
>> +};
>> +
>> +struct thermal_cooling_conf {
>> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> + int freq_clip_count;
>> +};
>> +
>> +struct thermal_sensor_conf {
>> + char name[SENSOR_NAME_LEN];
>> + int (*read_temperature)(void *data);
>> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> + struct thermal_trip_point_conf trip_data;
>> + struct thermal_cooling_conf cooling_data;
>> + void *private_data;
>> +};
>> +
>> +/*Functions used exynos based thermal sensor driver*/
>> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
>> +void exynos_unregister_thermal(void);
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>> +void exynos_report_trigger(void);
>> +#else
>> +static inline void
>> +exynos_unregister_thermal(void) { return; }
>> +
>> +static inline int
>> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
>> +
>> +static inline void
>> +exynos_report_trigger(void) { return; }
>> +
>> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
>> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi Eduardo,
On Thu, Jun 20, 2013 at 1:25 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch adds some extra register bitfield definations and cleans
>> up the code to prepare for moving register macros and definations inside
>> the TMU data section.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_tmu.c | 62 +++++++++++++++++++++++++---------
>> 1 files changed, 46 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 5df04a1..fa33a48 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -43,9 +43,12 @@
>>
>> #define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
>> #define EXYNOS_TMU_GAIN_SHIFT 8
>> +#define EXYNOS_TMU_GAIN_MASK 0xf
>> #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
>> -#define EXYNOS_TMU_CORE_ON 3
>> -#define EXYNOS_TMU_CORE_OFF 2
>> +#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>> +#define EXYNOS_TMU_CORE_EN_SHIFT 0
>> #define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>
>> /* Exynos4210 specific registers */
>> @@ -63,6 +66,7 @@
>> #define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
>> #define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
>> #define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
>> +#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
>> #define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
>>
>> /* Exynos5250 and Exynos4412 specific registers */
>> @@ -72,17 +76,30 @@
>> #define EXYNOS_EMUL_CON 0x80
>>
>> #define EXYNOS_TRIMINFO_RELOAD 0x1
>> +#define EXYNOS_TRIMINFO_SHIFT 0x0
>> +#define EXYNOS_TMU_RISE_INT_MASK 0x111
>> +#define EXYNOS_TMU_RISE_INT_SHIFT 0
>> +#define EXYNOS_TMU_FALL_INT_MASK 0x111
>> +#define EXYNOS_TMU_FALL_INT_SHIFT 12
>> #define EXYNOS_TMU_CLEAR_RISE_INT 0x111
>> #define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
>> -#define EXYNOS_MUX_ADDR_VALUE 6
>> -#define EXYNOS_MUX_ADDR_SHIFT 20
>> #define EXYNOS_TMU_TRIP_MODE_SHIFT 13
>> +#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
>> +
>> +#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
>> +#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
>> +#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
>> +#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
>> +#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
>> +#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>> +#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>
>> #define EFUSE_MIN_VALUE 40
>> #define EFUSE_MAX_VALUE 100
>>
>> #ifdef CONFIG_THERMAL_EMULATION
>> #define EXYNOS_EMUL_TIME 0x57F0
>> +#define EXYNOS_EMUL_TIME_MASK 0xffff
>> #define EXYNOS_EMUL_TIME_SHIFT 16
>> #define EXYNOS_EMUL_DATA_SHIFT 8
>> #define EXYNOS_EMUL_DATA_MASK 0xFF
>> @@ -261,24 +278,37 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>> mutex_lock(&data->lock);
>> clk_enable(data->clk);
>>
>> - con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
>> - pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
>> + con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
>>
>> - if (data->soc == SOC_ARCH_EXYNOS) {
>> - con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
>> - con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
>> + if (pdata->reference_voltage) {
>> + con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
>> + EXYNOS_TMU_REF_VOLTAGE_SHIFT);
>> + con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
>> + }
>> +
>> + if (pdata->gain) {
>> + con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
>> + con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
>> + }
>> +
>> + if (pdata->noise_cancel_mode) {
>> + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
>> + EXYNOS_TMU_TRIP_MODE_SHIFT);
>> + con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
>> }
>>
>> if (on) {
>> - con |= EXYNOS_TMU_CORE_ON;
>
>
>
> Before, in order to turn core on you had:
> con = con | 3;
>
> now you do:
> con = con | (1 << 0);
>
> To me, before you would set bit 1 and 0, now you set bit 0.
>
>
>> - interrupt_en = pdata->trigger_level3_en << 12 |
>> - pdata->trigger_level2_en << 8 |
>> - pdata->trigger_level1_en << 4 |
>> - pdata->trigger_level0_en;
>> + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>> + interrupt_en =
>> + pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>> + pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>> + pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>> + pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>> if (pdata->threshold_falling)
>> - interrupt_en |= interrupt_en << 16;
>> + interrupt_en |=
>> + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>> } else {
>> - con |= EXYNOS_TMU_CORE_OFF;
>> + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
>
>
> Before, in order to turno core off you had:
> con = con | 2;
>
> now you do:
> con = con & ~(1 << 0);
>
> To me, before you would set bit 2, now you clear bit 0.
>
> Using the approach on this patch looks correct to me if you have 1 bit
> core_en for instance.
>
> so, Is this a fix?
>
> Just to be clear, is this what you want ?
Yes you are right. Bit 0 is the actual enable bit. Bit 1 is the
reserve bit and its default value is 1. Earlier both bits are used to
turn on/off the controller which was wrong so this patch rectifies it.
Thanks,
Amit
>
>> interrupt_en = 0; /* Disable all interrupts */
>> }
>> writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On Thu, Jun 20, 2013 at 12:31 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This code bifurcates exynos thermal implementation into common and sensor
>> specific parts. The common thermal code interacts with core thermal layer and
>> core cpufreq cooling parts and is independent of SOC specific driver. This
>> change is needed to cleanly add support for new TMU sensors.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/Kconfig | 19 +-
>> drivers/thermal/samsung/Makefile | 4 +-
>> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
>> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
>> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
>> 5 files changed, 490 insertions(+), 419 deletions(-)
>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>>
>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>> index 2cf31ad..f8100b1 100644
>> --- a/drivers/thermal/samsung/Kconfig
>> +++ b/drivers/thermal/samsung/Kconfig
>> @@ -1,8 +1,17 @@
>> config EXYNOS_THERMAL
>> - tristate "Temperature sensor on Samsung EXYNOS"
>> + tristate "Exynos thermal management unit driver"
>> depends on ARCH_HAS_BANDGAP
>
> This is not really on this patch, but I think this one needs to depend
> on CONFIG_OF too.
In the driver CONFIG_OF is used for DT api's so this is not needed here.
>
>> help
>> - If you say yes here you get support for TMU (Thermal Management
>> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
>> - the exynos thermal driver with the core thermal layer and cpu
>> - cooling API's.
>> + If you say yes here you get support for the TMU (Thermal Management
>> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>> + the TMU, reports temperature and handles cooling action if defined.
>> + This driver uses the exynos core thermal API's.
>> +
>> +config EXYNOS_THERMAL_CORE
>> + bool "Core thermal framework support for EXYNOS SOC's"
>> + depends on EXYNOS_THERMAL
>> + help
>> + If you say yes here you get support for EXYNOS TMU
>> + (Thermal Management Unit) common registration/unregistration
>> + functions to the core thermal layer and also to use the generic
>> + cpu cooling API's.
>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>> index 1fe6d93..6227d4f 100644
>> --- a/drivers/thermal/samsung/Makefile
>> +++ b/drivers/thermal/samsung/Makefile
>> @@ -1,4 +1,6 @@
>> #
>> # Samsung thermal specific Makefile
>> #
>> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
>> +exynos_soc_thermal-y := exynos_thermal.o
>> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
>> index 03e4bbc..5293849 100644
>> --- a/drivers/thermal/samsung/exynos_thermal.c
>> +++ b/drivers/thermal/samsung/exynos_thermal.c
>> @@ -21,23 +21,15 @@
>> *
>> */
>>
>> -#include <linux/module.h>
>> -#include <linux/err.h>
>> -#include <linux/kernel.h>
>> -#include <linux/slab.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/interrupt.h>
>> #include <linux/clk.h>
>> -#include <linux/workqueue.h>
>> -#include <linux/sysfs.h>
>> -#include <linux/kobject.h>
>> #include <linux/io.h>
>> -#include <linux/mutex.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>> -#include <linux/thermal.h>
>> -#include <linux/cpufreq.h>
>> -#include <linux/cpu_cooling.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> #include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +
>> +#include "exynos_thermal_common.h"
>>
>> /* Exynos generic registers */
>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>> @@ -88,16 +80,6 @@
>> #define EFUSE_MIN_VALUE 40
>> #define EFUSE_MAX_VALUE 100
>>
>> -/* In-kernel thermal framework related macros & definations */
>> -#define SENSOR_NAME_LEN 16
>> -#define MAX_TRIP_COUNT 8
>> -#define MAX_COOLING_DEVICE 4
>> -#define MAX_THRESHOLD_LEVS 4
>> -
>> -#define ACTIVE_INTERVAL 500
>> -#define IDLE_INTERVAL 10000
>> -#define MCELSIUS 1000
>> -
>> #ifdef CONFIG_THERMAL_EMULATION
>> #define EXYNOS_EMUL_TIME 0x57F0
>> #define EXYNOS_EMUL_TIME_SHIFT 16
>> @@ -106,17 +88,6 @@
>> #define EXYNOS_EMUL_ENABLE 0x1
>> #endif /* CONFIG_THERMAL_EMULATION */
>>
>> -/* CPU Zone information */
>> -#define PANIC_ZONE 4
>> -#define WARN_ZONE 3
>> -#define MONITOR_ZONE 2
>> -#define SAFE_ZONE 1
>> -
>> -#define GET_ZONE(trip) (trip + 2)
>> -#define GET_TRIP(zone) (zone - 2)
>> -
>> -#define EXYNOS_ZONE_COUNT 3
>> -
>> struct exynos_tmu_data {
>> struct exynos_tmu_platform_data *pdata;
>> struct resource *mem;
>> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
>> u8 temp_error1, temp_error2;
>> };
>>
>> -struct thermal_trip_point_conf {
>> - int trip_val[MAX_TRIP_COUNT];
>> - int trip_count;
>> - u8 trigger_falling;
>> -};
>> -
>> -struct thermal_cooling_conf {
>> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> - int freq_clip_count;
>> -};
>> -
>> -struct thermal_sensor_conf {
>> - char name[SENSOR_NAME_LEN];
>> - int (*read_temperature)(void *data);
>> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> - struct thermal_trip_point_conf trip_data;
>> - struct thermal_cooling_conf cooling_data;
>> - void *private_data;
>> -};
>> -
>> -struct exynos_thermal_zone {
>> - enum thermal_device_mode mode;
>> - struct thermal_zone_device *therm_dev;
>> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> - unsigned int cool_dev_size;
>> - struct platform_device *exynos4_dev;
>> - struct thermal_sensor_conf *sensor_conf;
>> - bool bind;
>> -};
>> -
>> -static struct exynos_thermal_zone *th_zone;
>> -static void exynos_unregister_thermal(void);
>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>> -
>> -/* Get mode callback functions for thermal zone */
>> -static int exynos_get_mode(struct thermal_zone_device *thermal,
>> - enum thermal_device_mode *mode)
>> -{
>> - if (th_zone)
>> - *mode = th_zone->mode;
>> - return 0;
>> -}
>> -
>> -/* Set mode callback functions for thermal zone */
>> -static int exynos_set_mode(struct thermal_zone_device *thermal,
>> - enum thermal_device_mode mode)
>> -{
>> - if (!th_zone->therm_dev) {
>> - pr_notice("thermal zone not registered\n");
>> - return 0;
>> - }
>> -
>> - mutex_lock(&th_zone->therm_dev->lock);
>> -
>> - if (mode == THERMAL_DEVICE_ENABLED &&
>> - !th_zone->sensor_conf->trip_data.trigger_falling)
>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> - else
>> - th_zone->therm_dev->polling_delay = 0;
>> -
>> - mutex_unlock(&th_zone->therm_dev->lock);
>> -
>> - th_zone->mode = mode;
>> - thermal_zone_device_update(th_zone->therm_dev);
>> - pr_info("thermal polling set for duration=%d msec\n",
>> - th_zone->therm_dev->polling_delay);
>> - return 0;
>> -}
>> -
>> -
>> -/* Get trip type callback functions for thermal zone */
>> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>> - enum thermal_trip_type *type)
>> -{
>> - switch (GET_ZONE(trip)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - *type = THERMAL_TRIP_ACTIVE;
>> - break;
>> - case PANIC_ZONE:
>> - *type = THERMAL_TRIP_CRITICAL;
>> - break;
>> - default:
>> - return -EINVAL;
>> - }
>> - return 0;
>> -}
>> -
>> -/* Get trip temperature callback functions for thermal zone */
>> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> - unsigned long *temp)
>> -{
>> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> - return -EINVAL;
>> -
>> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> - /* convert the temperature into millicelsius */
>> - *temp = *temp * MCELSIUS;
>> -
>> - return 0;
>> -}
>> -
>> -/* Get critical temperature callback functions for thermal zone */
>> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> - unsigned long *temp)
>> -{
>> - int ret;
>> - /* Panic zone */
>> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> - return ret;
>> -}
>> -
>> -/* Bind callback functions for thermal zone */
>> -static int exynos_bind(struct thermal_zone_device *thermal,
>> - struct thermal_cooling_device *cdev)
>> -{
>> - int ret = 0, i, tab_size, level;
>> - struct freq_clip_table *tab_ptr, *clip_data;
>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> - tab_size = data->cooling_data.freq_clip_count;
>> -
>> - if (tab_ptr == NULL || tab_size == 0)
>> - return -EINVAL;
>> -
>> - /* find the cooling device registered*/
>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>> - if (cdev == th_zone->cool_dev[i])
>> - break;
>> -
>> - /* No matching cooling device */
>> - if (i == th_zone->cool_dev_size)
>> - return 0;
>> -
>> - /* Bind the thermal zone to the cpufreq cooling device */
>> - for (i = 0; i < tab_size; i++) {
>> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>> - if (level == THERMAL_CSTATE_INVALID)
>> - return 0;
>> - switch (GET_ZONE(i)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>> - level, 0)) {
>> - pr_err("error binding cdev inst %d\n", i);
>> - ret = -EINVAL;
>> - }
>> - th_zone->bind = true;
>> - break;
>> - default:
>> - ret = -EINVAL;
>> - }
>> - }
>> -
>> - return ret;
>> -}
>> -
>> -/* Unbind callback functions for thermal zone */
>> -static int exynos_unbind(struct thermal_zone_device *thermal,
>> - struct thermal_cooling_device *cdev)
>> -{
>> - int ret = 0, i, tab_size;
>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> - if (th_zone->bind == false)
>> - return 0;
>> -
>> - tab_size = data->cooling_data.freq_clip_count;
>> -
>> - if (tab_size == 0)
>> - return -EINVAL;
>> -
>> - /* find the cooling device registered*/
>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>> - if (cdev == th_zone->cool_dev[i])
>> - break;
>> -
>> - /* No matching cooling device */
>> - if (i == th_zone->cool_dev_size)
>> - return 0;
>> -
>> - /* Bind the thermal zone to the cpufreq cooling device */
>> - for (i = 0; i < tab_size; i++) {
>> - switch (GET_ZONE(i)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - if (thermal_zone_unbind_cooling_device(thermal, i,
>> - cdev)) {
>> - pr_err("error unbinding cdev inst=%d\n", i);
>> - ret = -EINVAL;
>> - }
>> - th_zone->bind = false;
>> - break;
>> - default:
>> - ret = -EINVAL;
>> - }
>> - }
>> - return ret;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_get_temp(struct thermal_zone_device *thermal,
>> - unsigned long *temp)
>> -{
>> - void *data;
>> -
>> - if (!th_zone->sensor_conf) {
>> - pr_info("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> - data = th_zone->sensor_conf->private_data;
>> - *temp = th_zone->sensor_conf->read_temperature(data);
>> - /* convert the temperature into millicelsius */
>> - *temp = *temp * MCELSIUS;
>> - return 0;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> - unsigned long temp)
>> -{
>> - void *data;
>> - int ret = -EINVAL;
>> -
>> - if (!th_zone->sensor_conf) {
>> - pr_info("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> - data = th_zone->sensor_conf->private_data;
>> - if (th_zone->sensor_conf->write_emul_temp)
>> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> - return ret;
>> -}
>> -
>> -/* Get the temperature trend */
>> -static int exynos_get_trend(struct thermal_zone_device *thermal,
>> - int trip, enum thermal_trend *trend)
>> -{
>> - int ret;
>> - unsigned long trip_temp;
>> -
>> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> - if (ret < 0)
>> - return ret;
>> -
>> - if (thermal->temperature >= trip_temp)
>> - *trend = THERMAL_TREND_RAISE_FULL;
>> - else
>> - *trend = THERMAL_TREND_DROP_FULL;
>> -
>> - return 0;
>> -}
>> -/* Operation callback functions for thermal zone */
>> -static struct thermal_zone_device_ops const exynos_dev_ops = {
>> - .bind = exynos_bind,
>> - .unbind = exynos_unbind,
>> - .get_temp = exynos_get_temp,
>> - .set_emul_temp = exynos_set_emul_temp,
>> - .get_trend = exynos_get_trend,
>> - .get_mode = exynos_get_mode,
>> - .set_mode = exynos_set_mode,
>> - .get_trip_type = exynos_get_trip_type,
>> - .get_trip_temp = exynos_get_trip_temp,
>> - .get_crit_temp = exynos_get_crit_temp,
>> -};
>> -
>> -/*
>> - * This function may be called from interrupt based temperature sensor
>> - * when threshold is changed.
>> - */
>> -static void exynos_report_trigger(void)
>> -{
>> - unsigned int i;
>> - char data[10];
>> - char *envp[] = { data, NULL };
>> -
>> - if (!th_zone || !th_zone->therm_dev)
>> - return;
>> - if (th_zone->bind == false) {
>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>> - if (!th_zone->cool_dev[i])
>> - continue;
>> - exynos_bind(th_zone->therm_dev,
>> - th_zone->cool_dev[i]);
>> - }
>> - }
>> -
>> - thermal_zone_device_update(th_zone->therm_dev);
>> -
>> - mutex_lock(&th_zone->therm_dev->lock);
>> - /* Find the level for which trip happened */
>> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> - if (th_zone->therm_dev->last_temperature <
>> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>> - break;
>> - }
>> -
>> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> - !th_zone->sensor_conf->trip_data.trigger_falling) {
>> - if (i > 0)
>> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>> - else
>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> - }
>> -
>> - snprintf(data, sizeof(data), "%u", i);
>> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>> - mutex_unlock(&th_zone->therm_dev->lock);
>> -}
>> -
>> -/* Register with the in-kernel thermal management */
>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> -{
>> - int ret;
>> - struct cpumask mask_val;
>> -
>> - if (!sensor_conf || !sensor_conf->read_temperature) {
>> - pr_err("Temperature sensor not initialised\n");
>> - return -EINVAL;
>> - }
>> -
>> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> - if (!th_zone)
>> - return -ENOMEM;
>> -
>> - th_zone->sensor_conf = sensor_conf;
>> - cpumask_set_cpu(0, &mask_val);
>> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> - if (IS_ERR(th_zone->cool_dev[0])) {
>> - pr_err("Failed to register cpufreq cooling device\n");
>> - ret = -EINVAL;
>> - goto err_unregister;
>> - }
>> - th_zone->cool_dev_size++;
>> -
>> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>> - sensor_conf->trip_data.trigger_falling ?
>> - 0 : IDLE_INTERVAL);
>> -
>> - if (IS_ERR(th_zone->therm_dev)) {
>> - pr_err("Failed to register thermal zone device\n");
>> - ret = PTR_ERR(th_zone->therm_dev);
>> - goto err_unregister;
>> - }
>> - th_zone->mode = THERMAL_DEVICE_ENABLED;
>> -
>> - pr_info("Exynos: Kernel Thermal management registered\n");
>> -
>> - return 0;
>> -
>> -err_unregister:
>> - exynos_unregister_thermal();
>> - return ret;
>> -}
>> -
>> -/* Un-Register with the in-kernel thermal management */
>> -static void exynos_unregister_thermal(void)
>> -{
>> - int i;
>> -
>> - if (!th_zone)
>> - return;
>> -
>> - if (th_zone->therm_dev)
>> - thermal_zone_device_unregister(th_zone->therm_dev);
>> -
>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>> - if (th_zone->cool_dev[i])
>> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>> - }
>> -
>> - kfree(th_zone);
>> - pr_info("Exynos: Kernel Thermal management unregistered\n");
>> -}
>> -
>> /*
>> * TMU treats temperature as a mapped temperature code.
>> * The temperature is converted differently depending on the calibration type.
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> new file mode 100644
>> index 0000000..92e50bc
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -0,0 +1,384 @@
>> +/*
>> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#include <linux/cpu_cooling.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +#include <linux/slab.h>
>> +#include <linux/thermal.h>
>> +
>> +#include "exynos_thermal_common.h"
>> +
>> +struct exynos_thermal_zone {
>> + enum thermal_device_mode mode;
>> + struct thermal_zone_device *therm_dev;
>> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> + unsigned int cool_dev_size;
>> + struct platform_device *exynos4_dev;
>> + struct thermal_sensor_conf *sensor_conf;
>> + bool bind;
>> +};
>> +
>> +static struct exynos_thermal_zone *th_zone;
>> +
>> +/* Get mode callback functions for thermal zone */
>> +static int exynos_get_mode(struct thermal_zone_device *thermal,
>> + enum thermal_device_mode *mode)
>> +{
>> + if (th_zone)
>> + *mode = th_zone->mode;
>> + return 0;
>> +}
>> +
>> +/* Set mode callback functions for thermal zone */
>> +static int exynos_set_mode(struct thermal_zone_device *thermal,
>> + enum thermal_device_mode mode)
>> +{
>> + if (!th_zone->therm_dev) {
>> + pr_notice("thermal zone not registered\n");
>> + return 0;
>> + }
>> +
>> + mutex_lock(&th_zone->therm_dev->lock);
>> +
>> + if (mode == THERMAL_DEVICE_ENABLED &&
>> + !th_zone->sensor_conf->trip_data.trigger_falling)
>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> + else
>> + th_zone->therm_dev->polling_delay = 0;
>> +
>> + mutex_unlock(&th_zone->therm_dev->lock);
>> +
>> + th_zone->mode = mode;
>> + thermal_zone_device_update(th_zone->therm_dev);
>> + pr_info("thermal polling set for duration=%d msec\n",
>> + th_zone->therm_dev->polling_delay);
>> + return 0;
>> +}
>> +
>> +
>> +/* Get trip type callback functions for thermal zone */
>> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>> + enum thermal_trip_type *type)
>> +{
>> + switch (GET_ZONE(trip)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + *type = THERMAL_TRIP_ACTIVE;
>> + break;
>> + case PANIC_ZONE:
>> + *type = THERMAL_TRIP_CRITICAL;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + return 0;
>> +}
>> +
>> +/* Get trip temperature callback functions for thermal zone */
>> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> + unsigned long *temp)
>> +{
>> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> + return -EINVAL;
>> +
>> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> + /* convert the temperature into millicelsius */
>> + *temp = *temp * MCELSIUS;
>> +
>> + return 0;
>> +}
>> +
>> +/* Get critical temperature callback functions for thermal zone */
>> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> + unsigned long *temp)
>> +{
>> + int ret;
>> + /* Panic zone */
>> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> + return ret;
>> +}
>> +
>> +/* Bind callback functions for thermal zone */
>> +static int exynos_bind(struct thermal_zone_device *thermal,
>> + struct thermal_cooling_device *cdev)
>> +{
>> + int ret = 0, i, tab_size, level;
>> + struct freq_clip_table *tab_ptr, *clip_data;
>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> + tab_size = data->cooling_data.freq_clip_count;
>> +
>> + if (tab_ptr == NULL || tab_size == 0)
>> + return -EINVAL;
>> +
>> + /* find the cooling device registered*/
>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>> + if (cdev == th_zone->cool_dev[i])
>> + break;
>> +
>> + /* No matching cooling device */
>> + if (i == th_zone->cool_dev_size)
>> + return 0;
>> +
>> + /* Bind the thermal zone to the cpufreq cooling device */
>> + for (i = 0; i < tab_size; i++) {
>> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>> + if (level == THERMAL_CSTATE_INVALID)
>> + return 0;
>> + switch (GET_ZONE(i)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>> + level, 0)) {
>> + pr_err("error binding cdev inst %d\n", i);
>> + ret = -EINVAL;
>> + }
>> + th_zone->bind = true;
>> + break;
>> + default:
>> + ret = -EINVAL;
>> + }
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +/* Unbind callback functions for thermal zone */
>> +static int exynos_unbind(struct thermal_zone_device *thermal,
>> + struct thermal_cooling_device *cdev)
>> +{
>> + int ret = 0, i, tab_size;
>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> + if (th_zone->bind == false)
>> + return 0;
>> +
>> + tab_size = data->cooling_data.freq_clip_count;
>> +
>> + if (tab_size == 0)
>> + return -EINVAL;
>> +
>> + /* find the cooling device registered*/
>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>> + if (cdev == th_zone->cool_dev[i])
>> + break;
>> +
>> + /* No matching cooling device */
>> + if (i == th_zone->cool_dev_size)
>> + return 0;
>> +
>> + /* Bind the thermal zone to the cpufreq cooling device */
>> + for (i = 0; i < tab_size; i++) {
>> + switch (GET_ZONE(i)) {
>> + case MONITOR_ZONE:
>> + case WARN_ZONE:
>> + if (thermal_zone_unbind_cooling_device(thermal, i,
>> + cdev)) {
>> + pr_err("error unbinding cdev inst=%d\n", i);
>> + ret = -EINVAL;
>> + }
>> + th_zone->bind = false;
>> + break;
>> + default:
>> + ret = -EINVAL;
>> + }
>> + }
>> + return ret;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_get_temp(struct thermal_zone_device *thermal,
>> + unsigned long *temp)
>> +{
>> + void *data;
>> +
>> + if (!th_zone->sensor_conf) {
>> + pr_info("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> + data = th_zone->sensor_conf->private_data;
>> + *temp = th_zone->sensor_conf->read_temperature(data);
>> + /* convert the temperature into millicelsius */
>> + *temp = *temp * MCELSIUS;
>> + return 0;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> + unsigned long temp)
>> +{
>> + void *data;
>> + int ret = -EINVAL;
>> +
>> + if (!th_zone->sensor_conf) {
>> + pr_info("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> + data = th_zone->sensor_conf->private_data;
>> + if (th_zone->sensor_conf->write_emul_temp)
>> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> + return ret;
>> +}
>> +
>> +/* Get the temperature trend */
>> +static int exynos_get_trend(struct thermal_zone_device *thermal,
>> + int trip, enum thermal_trend *trend)
>> +{
>> + int ret;
>> + unsigned long trip_temp;
>> +
>> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (thermal->temperature >= trip_temp)
>> + *trend = THERMAL_TREND_RAISE_FULL;
>> + else
>> + *trend = THERMAL_TREND_DROP_FULL;
>> +
>> + return 0;
>> +}
>> +/* Operation callback functions for thermal zone */
>> +static struct thermal_zone_device_ops const exynos_dev_ops = {
>> + .bind = exynos_bind,
>> + .unbind = exynos_unbind,
>> + .get_temp = exynos_get_temp,
>> + .set_emul_temp = exynos_set_emul_temp,
>> + .get_trend = exynos_get_trend,
>> + .get_mode = exynos_get_mode,
>> + .set_mode = exynos_set_mode,
>> + .get_trip_type = exynos_get_trip_type,
>> + .get_trip_temp = exynos_get_trip_temp,
>> + .get_crit_temp = exynos_get_crit_temp,
>> +};
>> +
>> +/*
>> + * This function may be called from interrupt based temperature sensor
>> + * when threshold is changed.
>> + */
>> +void exynos_report_trigger(void)
>> +{
>> + unsigned int i;
>> + char data[10];
>> + char *envp[] = { data, NULL };
>> +
>> + if (!th_zone || !th_zone->therm_dev)
>> + return;
>> + if (th_zone->bind == false) {
>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>> + if (!th_zone->cool_dev[i])
>> + continue;
>> + exynos_bind(th_zone->therm_dev,
>> + th_zone->cool_dev[i]);
>> + }
>> + }
>> +
>> + thermal_zone_device_update(th_zone->therm_dev);
>> +
>> + mutex_lock(&th_zone->therm_dev->lock);
>> + /* Find the level for which trip happened */
>> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> + if (th_zone->therm_dev->last_temperature <
>> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>> + break;
>> + }
>> +
>> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> + !th_zone->sensor_conf->trip_data.trigger_falling) {
>> + if (i > 0)
>> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>> + else
>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> + }
>> +
>> + snprintf(data, sizeof(data), "%u", i);
>> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>> + mutex_unlock(&th_zone->therm_dev->lock);
>> +}
>> +
>> +/* Register with the in-kernel thermal management */
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> +{
>> + int ret;
>> + struct cpumask mask_val;
>> +
>> + if (!sensor_conf || !sensor_conf->read_temperature) {
>> + pr_err("Temperature sensor not initialised\n");
>> + return -EINVAL;
>> + }
>> +
>> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> + if (!th_zone)
>> + return -ENOMEM;
>> +
>> + th_zone->sensor_conf = sensor_conf;
>> + cpumask_set_cpu(0, &mask_val);
>> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> + if (IS_ERR(th_zone->cool_dev[0])) {
>> + pr_err("Failed to register cpufreq cooling device\n");
>> + ret = -EINVAL;
>> + goto err_unregister;
>> + }
>> + th_zone->cool_dev_size++;
>> +
>> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>> + sensor_conf->trip_data.trigger_falling ?
>> + 0 : IDLE_INTERVAL);
>> +
>> + if (IS_ERR(th_zone->therm_dev)) {
>> + pr_err("Failed to register thermal zone device\n");
>> + ret = PTR_ERR(th_zone->therm_dev);
>> + goto err_unregister;
>> + }
>> + th_zone->mode = THERMAL_DEVICE_ENABLED;
>> +
>> + pr_info("Exynos: Kernel Thermal management registered\n");
>> +
>> + return 0;
>> +
>> +err_unregister:
>> + exynos_unregister_thermal();
>> + return ret;
>> +}
>> +
>> +/* Un-Register with the in-kernel thermal management */
>> +void exynos_unregister_thermal(void)
>> +{
>> + int i;
>> +
>> + if (!th_zone)
>> + return;
>> +
>> + if (th_zone->therm_dev)
>> + thermal_zone_device_unregister(th_zone->therm_dev);
>> +
>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>> + if (th_zone->cool_dev[i])
>> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>> + }
>> +
>> + kfree(th_zone);
>> + pr_info("Exynos: Kernel Thermal management unregistered\n");
>> +}
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> new file mode 100644
>> index 0000000..8df1848
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -0,0 +1,83 @@
>> +/*
>> + * exynos_thermal_common.h - Samsung EXYNOS common header file
>> + *
>> + * Copyright (C) 2013 Samsung Electronics
>> + * Amit Daniel Kachhap <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#ifndef _EXYNOS_THERMAL_COMMON_H
>> +#define _EXYNOS_THERMAL_COMMON_H
>> +
>> +/* In-kernel thermal framework related macros & definations */
>> +#define SENSOR_NAME_LEN 16
>> +#define MAX_TRIP_COUNT 8
>> +#define MAX_COOLING_DEVICE 4
>> +#define MAX_THRESHOLD_LEVS 4
>> +
>> +#define ACTIVE_INTERVAL 500
>> +#define IDLE_INTERVAL 10000
>> +#define MCELSIUS 1000
>> +
>> +/* CPU Zone information */
>> +#define PANIC_ZONE 4
>> +#define WARN_ZONE 3
>> +#define MONITOR_ZONE 2
>> +#define SAFE_ZONE 1
>> +
>> +#define GET_ZONE(trip) (trip + 2)
>> +#define GET_TRIP(zone) (zone - 2)
>> +
>> +#define EXYNOS_ZONE_COUNT 3
>> +
>> +struct thermal_trip_point_conf {
>> + int trip_val[MAX_TRIP_COUNT];
>> + int trip_count;
>> + unsigned char trigger_falling;
>> +};
>> +
>> +struct thermal_cooling_conf {
>> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> + int freq_clip_count;
>> +};
>> +
>> +struct thermal_sensor_conf {
>> + char name[SENSOR_NAME_LEN];
>> + int (*read_temperature)(void *data);
>> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> + struct thermal_trip_point_conf trip_data;
>> + struct thermal_cooling_conf cooling_data;
>> + void *private_data;
>> +};
>> +
>> +/*Functions used exynos based thermal sensor driver*/
>> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
>> +void exynos_unregister_thermal(void);
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>> +void exynos_report_trigger(void);
>> +#else
>> +static inline void
>> +exynos_unregister_thermal(void) { return; }
>> +
>> +static inline int
>> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
>> +
>> +static inline void
>> +exynos_report_trigger(void) { return; }
>> +
>> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
>> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi
On Thu, Jun 20, 2013 at 12:48 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch renames and moves include/linux/platform_data/exynos_thermal.h to
>> drivers/thermal/samsung/exynos_tmu.h. This file movement is needed as exynos
>> SOC's are not supporting non-DT based platforms and this file now just contains
>> exynos tmu driver related definations.
>> Also struct freq_clip_table is now moved to exynos_thermal_common.c as it fixes
>> the compilation issue occuring because now this new tmu header file is included
>> in tmu driver c file and not in the common thermal header file.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.c | 1 -
>> drivers/thermal/samsung/exynos_thermal_common.h | 15 ++++++++++++
>> drivers/thermal/samsung/exynos_tmu.c | 2 +-
>> .../thermal/samsung/exynos_tmu.h | 24 ++++---------------
>> 4 files changed, 21 insertions(+), 21 deletions(-)
>> rename include/linux/platform_data/exynos_thermal.h => drivers/thermal/samsung/exynos_tmu.h (84%)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> index 92e50bc..dd49c9f 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -21,7 +21,6 @@
>> */
>>
>> #include <linux/cpu_cooling.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>> #include <linux/slab.h>
>> #include <linux/thermal.h>
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 8df1848..068f56c 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -44,6 +44,21 @@
>>
>> #define EXYNOS_ZONE_COUNT 3
>>
>> +/**
>> + * struct freq_clip_table
>> + * @freq_clip_max: maximum frequency allowed for this cooling state.
>> + * @temp_level: Temperature level at which the temperature clipping will
>> + * happen.
>> + * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>> + *
>> + * This structure is required to be filled and passed to the
>> + * cpufreq_cooling_unregister function.
>> + */
>> +struct freq_clip_table {
>> + unsigned int freq_clip_max;
>> + unsigned int temp_level;
>> + const struct cpumask *mask_val;
>> +};
>> struct thermal_trip_point_conf {
>> int trip_val[MAX_TRIP_COUNT];
>> int trip_count;
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 22a8874..6aa2fd2 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -27,9 +27,9 @@
>> #include <linux/module.h>
>> #include <linux/of.h>
>> #include <linux/platform_device.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>>
>> #include "exynos_thermal_common.h"
>> +#include "exynos_tmu.h"
>>
>> /* Exynos generic registers */
>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>> diff --git a/include/linux/platform_data/exynos_thermal.h b/drivers/thermal/samsung/exynos_tmu.h
>> similarity index 84%
>> rename from include/linux/platform_data/exynos_thermal.h
>> rename to drivers/thermal/samsung/exynos_tmu.h
>> index da7e627..9e0f887 100644
>> --- a/include/linux/platform_data/exynos_thermal.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -1,8 +1,9 @@
>> /*
>> - * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
>> + * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
>> *
>> * Copyright (C) 2011 Samsung Electronics
>> * Donggeun Kim <[email protected]>
>> + * Amit Daniel Kachhap <[email protected]>
>> *
>> * This program is free software; you can redistribute it and/or modify
>> * it under the terms of the GNU General Public License as published by
>> @@ -19,8 +20,8 @@
>> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> */
>>
>> -#ifndef _LINUX_EXYNOS_THERMAL_H
>> -#define _LINUX_EXYNOS_THERMAL_H
>> +#ifndef _EXYNOS_TMU_H
>> +#define _EXYNOS_TMU_H
>> #include <linux/cpu_cooling.h>
>>
>> enum calibration_type {
>> @@ -33,21 +34,6 @@ enum soc_type {
>> SOC_ARCH_EXYNOS4210 = 1,
>> SOC_ARCH_EXYNOS,
>> };
>> -/**
>> - * struct freq_clip_table
>> - * @freq_clip_max: maximum frequency allowed for this cooling state.
>> - * @temp_level: Temperature level at which the temperature clipping will
>> - * happen.
>> - * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>> - *
>> - * This structure is required to be filled and passed to the
>> - * cpufreq_cooling_unregister function.
>> - */
>> -struct freq_clip_table {
>> - unsigned int freq_clip_max;
>> - unsigned int temp_level;
>> - const struct cpumask *mask_val;
>> -};
>>
>> /**
>> * struct exynos_tmu_platform_data
>> @@ -116,4 +102,4 @@ struct exynos_tmu_platform_data {
>> struct freq_clip_table freq_tab[4];
>
> Because you have this struct right here, you need still to have:
> +#include "exynos_thermal_common.h"
>
> in your include list of exynos_tmu.h (this file).
>
> A part from this minor issue, you can add my acked:
>
> Acked-by: Eduardo Valentin <[email protected]>
Ok will re-submit with this change.
Thanks,
Amit Daniel
>
>> unsigned int freq_tab_count;
>> };
>> -#endif /* _LINUX_EXYNOS_THERMAL_H */
>> +#endif /* _EXYNOS_TMU_H */
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On Thu, Jun 20, 2013 at 12:50 AM, Eduardo Valentin
<[email protected]> wrote:
> On 19-06-2013 15:18, Eduardo Valentin wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This patch renames and moves include/linux/platform_data/exynos_thermal.h to
>>> drivers/thermal/samsung/exynos_tmu.h. This file movement is needed as exynos
>>> SOC's are not supporting non-DT based platforms and this file now just contains
>>> exynos tmu driver related definations.
>>> Also struct freq_clip_table is now moved to exynos_thermal_common.c as it fixes
>>> the compilation issue occuring because now this new tmu header file is included
>>> in tmu driver c file and not in the common thermal header file.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_thermal_common.c | 1 -
>>> drivers/thermal/samsung/exynos_thermal_common.h | 15 ++++++++++++
>>> drivers/thermal/samsung/exynos_tmu.c | 2 +-
>>> .../thermal/samsung/exynos_tmu.h | 24 ++++---------------
>>> 4 files changed, 21 insertions(+), 21 deletions(-)
>>> rename include/linux/platform_data/exynos_thermal.h => drivers/thermal/samsung/exynos_tmu.h (84%)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>>> index 92e50bc..dd49c9f 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>>> @@ -21,7 +21,6 @@
>>> */
>>>
>>> #include <linux/cpu_cooling.h>
>>> -#include <linux/platform_data/exynos_thermal.h>
>>> #include <linux/slab.h>
>>> #include <linux/thermal.h>
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> index 8df1848..068f56c 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -44,6 +44,21 @@
>>>
>>> #define EXYNOS_ZONE_COUNT 3
>>>
>>> +/**
>>> + * struct freq_clip_table
>>> + * @freq_clip_max: maximum frequency allowed for this cooling state.
>>> + * @temp_level: Temperature level at which the temperature clipping will
>>> + * happen.
>>> + * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>>> + *
>>> + * This structure is required to be filled and passed to the
>>> + * cpufreq_cooling_unregister function.
>>> + */
>>> +struct freq_clip_table {
>>> + unsigned int freq_clip_max;
>>> + unsigned int temp_level;
>>> + const struct cpumask *mask_val;
>>> +};
>
> Another minor: add an empty line here.
Ok
>
>>> struct thermal_trip_point_conf {
>>> int trip_val[MAX_TRIP_COUNT];
>>> int trip_count;
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index 22a8874..6aa2fd2 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -27,9 +27,9 @@
>>> #include <linux/module.h>
>>> #include <linux/of.h>
>>> #include <linux/platform_device.h>
>>> -#include <linux/platform_data/exynos_thermal.h>
>>>
>>> #include "exynos_thermal_common.h"
>>> +#include "exynos_tmu.h"
>>>
>>> /* Exynos generic registers */
>>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>>> diff --git a/include/linux/platform_data/exynos_thermal.h b/drivers/thermal/samsung/exynos_tmu.h
>>> similarity index 84%
>>> rename from include/linux/platform_data/exynos_thermal.h
>>> rename to drivers/thermal/samsung/exynos_tmu.h
>>> index da7e627..9e0f887 100644
>>> --- a/include/linux/platform_data/exynos_thermal.h
>>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>>> @@ -1,8 +1,9 @@
>>> /*
>>> - * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
>>> + * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
>>> *
>>> * Copyright (C) 2011 Samsung Electronics
>>> * Donggeun Kim <[email protected]>
>>> + * Amit Daniel Kachhap <[email protected]>
>>> *
>>> * This program is free software; you can redistribute it and/or modify
>>> * it under the terms of the GNU General Public License as published by
>>> @@ -19,8 +20,8 @@
>>> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>>> */
>>>
>>> -#ifndef _LINUX_EXYNOS_THERMAL_H
>>> -#define _LINUX_EXYNOS_THERMAL_H
>>> +#ifndef _EXYNOS_TMU_H
>>> +#define _EXYNOS_TMU_H
>>> #include <linux/cpu_cooling.h>
>>>
>>> enum calibration_type {
>>> @@ -33,21 +34,6 @@ enum soc_type {
>>> SOC_ARCH_EXYNOS4210 = 1,
>>> SOC_ARCH_EXYNOS,
>>> };
>>> -/**
>>> - * struct freq_clip_table
>>> - * @freq_clip_max: maximum frequency allowed for this cooling state.
>>> - * @temp_level: Temperature level at which the temperature clipping will
>>> - * happen.
>>> - * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
>>> - *
>>> - * This structure is required to be filled and passed to the
>>> - * cpufreq_cooling_unregister function.
>>> - */
>>> -struct freq_clip_table {
>>> - unsigned int freq_clip_max;
>>> - unsigned int temp_level;
>>> - const struct cpumask *mask_val;
>>> -};
>>>
>>> /**
>>> * struct exynos_tmu_platform_data
>>> @@ -116,4 +102,4 @@ struct exynos_tmu_platform_data {
>>> struct freq_clip_table freq_tab[4];
>>
>> Because you have this struct right here, you need still to have:
>> +#include "exynos_thermal_common.h"
>>
>> in your include list of exynos_tmu.h (this file).
>>
>> A part from this minor issue, you can add my acked:
>>
>> Acked-by: Eduardo Valentin <[email protected]>
>>
>>> unsigned int freq_tab_count;
>>> };
>>> -#endif /* _LINUX_EXYNOS_THERMAL_H */
>>> +#endif /* _EXYNOS_TMU_H */
>>>
>>
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On Thu, Jun 20, 2013 at 1:13 AM, Eduardo Valentin
<[email protected]> wrote:
> On 19-06-2013 15:35, Eduardo Valentin wrote:
>> Rui,
>>
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This code splits the exynos tmu driver code into SOC specific data parts.
>>> This will simplify adding new SOC specific data to the same TMU controller.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>
>> This patch looks good to me, you may want to add my:
>>
>> Acked-by: Eduardo Valentin <[email protected]>
>
> Yet another minor before adding my ack, sorry this one almost fell into
> the cracks (see below):
>
>>
>>> ---
>>> drivers/thermal/samsung/Kconfig | 3 +-
>>> drivers/thermal/samsung/Makefile | 1 +
>>> drivers/thermal/samsung/exynos_tmu.c | 67 ++-----------------------
>>> drivers/thermal/samsung/exynos_tmu_data.c | 78 +++++++++++++++++++++++++++++
>>> drivers/thermal/samsung/exynos_tmu_data.h | 40 +++++++++++++++
>>> 5 files changed, 125 insertions(+), 64 deletions(-)
>>> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.c
>>> create mode 100644 drivers/thermal/samsung/exynos_tmu_data.h
>>>
>>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>>> index f8100b1..b653f15 100644
>>> --- a/drivers/thermal/samsung/Kconfig
>>> +++ b/drivers/thermal/samsung/Kconfig
>>> @@ -5,7 +5,8 @@ config EXYNOS_THERMAL
>>> If you say yes here you get support for the TMU (Thermal Management
>>> Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>>> the TMU, reports temperature and handles cooling action if defined.
>>> - This driver uses the exynos core thermal API's.
>>> + This driver uses the exynos core thermal API's and TMU configuration
>>> + data from the supported soc's.
>>>
>>> config EXYNOS_THERMAL_CORE
>>> bool "Core thermal framework support for EXYNOS SOC's"
>>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>>> index 22528d6..c09d830 100644
>>> --- a/drivers/thermal/samsung/Makefile
>>> +++ b/drivers/thermal/samsung/Makefile
>>> @@ -3,4 +3,5 @@
>>> #
>>> obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>>> exynos_thermal-y := exynos_tmu.o
>>> +exynos_thermal-y += exynos_tmu_data.o
>>> exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index 6aa2fd2..5df04a1 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -30,6 +30,7 @@
>>>
>>> #include "exynos_thermal_common.h"
>>> #include "exynos_tmu.h"
>>> +#include "exynos_tmu_data.h"
>>>
>>> /* Exynos generic registers */
>>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>>> @@ -381,66 +382,6 @@ static struct thermal_sensor_conf exynos_sensor_conf = {
>>> .write_emul_temp = exynos_tmu_set_emulation,
>>> };
>>>
>>> -#if defined(CONFIG_CPU_EXYNOS4210)
>>> -static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>> - .threshold = 80,
>>> - .trigger_levels[0] = 5,
>>> - .trigger_levels[1] = 20,
>>> - .trigger_levels[2] = 30,
>>> - .trigger_level0_en = 1,
>>> - .trigger_level1_en = 1,
>>> - .trigger_level2_en = 1,
>>> - .trigger_level3_en = 0,
>>> - .gain = 15,
>>> - .reference_voltage = 7,
>>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> - .freq_tab[0] = {
>>> - .freq_clip_max = 800 * 1000,
>>> - .temp_level = 85,
>>> - },
>>> - .freq_tab[1] = {
>>> - .freq_clip_max = 200 * 1000,
>>> - .temp_level = 100,
>>> - },
>>> - .freq_tab_count = 2,
>>> - .type = SOC_ARCH_EXYNOS4210,
>>> -};
>>> -#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>>> -#else
>>> -#define EXYNOS4210_TMU_DRV_DATA (NULL)
>>> -#endif
>>> -
>>> -#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
>>> -static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
>>> - .threshold_falling = 10,
>>> - .trigger_levels[0] = 85,
>>> - .trigger_levels[1] = 103,
>>> - .trigger_levels[2] = 110,
>>> - .trigger_level0_en = 1,
>>> - .trigger_level1_en = 1,
>>> - .trigger_level2_en = 1,
>>> - .trigger_level3_en = 0,
>>> - .gain = 8,
>>> - .reference_voltage = 16,
>>> - .noise_cancel_mode = 4,
>>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> - .efuse_value = 55,
>>> - .freq_tab[0] = {
>>> - .freq_clip_max = 800 * 1000,
>>> - .temp_level = 85,
>>> - },
>>> - .freq_tab[1] = {
>>> - .freq_clip_max = 200 * 1000,
>>> - .temp_level = 103,
>>> - },
>>> - .freq_tab_count = 2,
>>> - .type = SOC_ARCH_EXYNOS,
>>> -};
>>> -#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
>>> -#else
>>> -#define EXYNOS_TMU_DRV_DATA (NULL)
>>> -#endif
>>> -
>>> #ifdef CONFIG_OF
>>> static const struct of_device_id exynos_tmu_match[] = {
>>> {
>>> @@ -449,11 +390,11 @@ static const struct of_device_id exynos_tmu_match[] = {
>>> },
>>> {
>>> .compatible = "samsung,exynos4412-tmu",
>>> - .data = (void *)EXYNOS_TMU_DRV_DATA,
>>> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>>> },
>>> {
>>> .compatible = "samsung,exynos5250-tmu",
>>> - .data = (void *)EXYNOS_TMU_DRV_DATA,
>>> + .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>>> },
>>> {},
>>> };
>>> @@ -467,7 +408,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = {
>>> },
>>> {
>>> .name = "exynos5250-tmu",
>>> - .driver_data = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
>>> + .driver_data = (kernel_ulong_t)EXYNOS5250_TMU_DRV_DATA,
>>> },
>>> { },
>>> };
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>>> new file mode 100644
>>> index 0000000..13a60ca
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>>> @@ -0,0 +1,78 @@
>>> +/*
>>> + * exynos_tmu_data.c - Samsung EXYNOS tmu data file
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics
>>> + * Amit Daniel Kachhap <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>>> + *
>>> + */
>>> +
>>> +#include "exynos_thermal_common.h"
>
> You have to:
> +#include "exynos_tmu_data.h"
>
> Otherwise, you will get:
> CC [M] drivers/thermal/samsung/exynos_tmu.o
> drivers/thermal/samsung/exynos_tmu_data.c:27:39: warning: symbol
> 'exynos4210_default_tmu_data' was not declared. Should it be static?
> drivers/thermal/samsung/exynos_tmu_data.c:53:39: warning: symbol
> 'exynos5250_default_tmu_data' was not declared. Should it be static?
Ok.
>
>
>>> +#include "exynos_tmu.h"
>
>>> +
>>> +#if defined(CONFIG_CPU_EXYNOS4210)
>>> +struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>> + .threshold = 80,
>>> + .trigger_levels[0] = 5,
>>> + .trigger_levels[1] = 20,
>>> + .trigger_levels[2] = 30,
>>> + .trigger_level0_en = 1,
>>> + .trigger_level1_en = 1,
>>> + .trigger_level2_en = 1,
>>> + .trigger_level3_en = 0,
>>> + .gain = 15,
>>> + .reference_voltage = 7,
>>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> + .freq_tab[0] = {
>>> + .freq_clip_max = 800 * 1000,
>>> + .temp_level = 85,
>>> + },
>>> + .freq_tab[1] = {
>>> + .freq_clip_max = 200 * 1000,
>>> + .temp_level = 100,
>>> + },
>>> + .freq_tab_count = 2,
>>> + .type = SOC_ARCH_EXYNOS4210,
>>> +};
>>> +#endif
>>> +
>>> +#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
>>> +struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>>> + .threshold_falling = 10,
>>> + .trigger_levels[0] = 85,
>>> + .trigger_levels[1] = 103,
>>> + .trigger_levels[2] = 110,
>>> + .trigger_level0_en = 1,
>>> + .trigger_level1_en = 1,
>>> + .trigger_level2_en = 1,
>>> + .trigger_level3_en = 0,
>>> + .gain = 8,
>>> + .reference_voltage = 16,
>>> + .noise_cancel_mode = 4,
>>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> + .efuse_value = 55,
>>> + .freq_tab[0] = {
>>> + .freq_clip_max = 800 * 1000,
>>> + .temp_level = 85,
>>> + },
>>> + .freq_tab[1] = {
>>> + .freq_clip_max = 200 * 1000,
>>> + .temp_level = 103,
>>> + },
>>> + .freq_tab_count = 2,
>>> + .type = SOC_ARCH_EXYNOS,
>>> +};
>>> +#endif
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>>> new file mode 100644
>>> index 0000000..b7835fe
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>>> @@ -0,0 +1,40 @@
>>> +/*
>>> + * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics
>>> + * Amit Daniel Kachhap <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>>> + *
>>> + */
>>> +
>>> +#ifndef _EXYNOS_TMU_DATA_H
>>> +#define _EXYNOS_TMU_DATA_H
>>> +
>>> +#if defined(CONFIG_CPU_EXYNOS4210)
>>> +extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
>>> +#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>>> +#else
>>> +#define EXYNOS4210_TMU_DRV_DATA (NULL)
>>> +#endif
>>> +
>>> +#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
>>> +extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
>>> +#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
>>> +#else
>>> +#define EXYNOS5250_TMU_DRV_DATA (NULL)
>>> +#endif
>>> +
>>> +#endif /*_EXYNOS_TMU_DATA_H*/
>>>
>>
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi Eduardo,
On Thu, Jun 20, 2013 at 1:49 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
>> trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
>> trigger_enable in the TMU platform data structure. Also the driver is modified
>> to use the data passed by these new platform memebers instead of the constant
>> macros. All these changes helps in separating the SOC specific data part from
>> the TMU driver.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
>> drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
>> drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
>> drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
>> 4 files changed, 86 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 068f56c..fd789a5 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -44,6 +44,13 @@
>>
>> #define EXYNOS_ZONE_COUNT 3
>>
>> +enum trigger_type {
>> + THROTTLE_ACTIVE = 1,
>> + THROTTLE_PASSIVE,
>> + SW_TRIP,
>> + HW_TRIP,
>> +};
>> +
>> /**
>> * struct freq_clip_table
>> * @freq_clip_max: maximum frequency allowed for this cooling state.
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index fa33a48..401ec98 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -49,7 +49,6 @@
>> #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>> #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>> #define EXYNOS_TMU_CORE_EN_SHIFT 0
>> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>
>> /* Exynos4210 specific registers */
>> #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
>> @@ -94,9 +93,6 @@
>> #define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>> #define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>
>> -#define EFUSE_MIN_VALUE 40
>> -#define EFUSE_MAX_VALUE 100
>> -
>> #ifdef CONFIG_THERMAL_EMULATION
>> #define EXYNOS_EMUL_TIME 0x57F0
>> #define EXYNOS_EMUL_TIME_MASK 0xffff
>> @@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>>
>> switch (pdata->cal_type) {
>> case TYPE_TWO_POINT_TRIMMING:
>> - temp_code = (temp - 25) *
>> - (data->temp_error2 - data->temp_error1) /
>> - (85 - 25) + data->temp_error1;
>> + temp_code = (temp - pdata->first_point_trim) *
>> + (data->temp_error2 - data->temp_error1) /
>> + (pdata->second_point_trim - pdata->first_point_trim) +
>> + data->temp_error1;
>> break;
>> case TYPE_ONE_POINT_TRIMMING:
>> - temp_code = temp + data->temp_error1 - 25;
>> + temp_code = temp + data->temp_error1 - pdata->first_point_trim;
>> break;
>> default:
>> - temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> + temp_code = temp + pdata->default_temp_offset;
>> break;
>> }
>> out:
>> @@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>>
>> switch (pdata->cal_type) {
>> case TYPE_TWO_POINT_TRIMMING:
>> - temp = (temp_code - data->temp_error1) * (85 - 25) /
>> - (data->temp_error2 - data->temp_error1) + 25;
>> + temp = (temp_code - data->temp_error1) *
>> + (pdata->second_point_trim - pdata->first_point_trim) /
>> + (data->temp_error2 - data->temp_error1) +
>> + pdata->first_point_trim;
>> break;
>> case TYPE_ONE_POINT_TRIMMING:
>> - temp = temp_code - data->temp_error1 + 25;
>> + temp = temp_code - data->temp_error1 + pdata->first_point_trim;
>> break;
>> default:
>> - temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> + temp = temp_code - pdata->default_temp_offset;
>> break;
>> }
>> out:
>> @@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>> data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
>> data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
>>
>> - if ((EFUSE_MIN_VALUE > data->temp_error1) ||
>> - (data->temp_error1 > EFUSE_MAX_VALUE) ||
>> + if ((pdata->min_efuse_value > data->temp_error1) ||
>> + (data->temp_error1 > pdata->max_efuse_value) ||
>> (data->temp_error2 != 0))
>> data->temp_error1 = pdata->efuse_value;
>>
>> @@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>> if (on) {
>> con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>> interrupt_en =
>> - pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>> - pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>> - pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>> - pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>> + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>> + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>> + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>> + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>> if (pdata->threshold_falling)
>> interrupt_en |=
>> interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>> @@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>
>> /* Register the sensor with thermal management interface */
>> (&exynos_sensor_conf)->private_data = data;
>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
>> - pdata->trigger_level1_en + pdata->trigger_level2_en +
>> - pdata->trigger_level3_en;
>> + exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>> + pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>> + pdata->trigger_enable[3];
>>
>> for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>> exynos_sensor_conf.trip_data.trip_val[i] =
>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>> index 9e0f887..45c697d 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -30,6 +30,11 @@ enum calibration_type {
>> TYPE_NONE,
>> };
>>
>> +enum calibration_mode {
>> + SW_MODE,
>> + HW_MODE,
>> +};
>> +
>> enum soc_type {
>> SOC_ARCH_EXYNOS4210 = 1,
>> SOC_ARCH_EXYNOS,
>> @@ -55,18 +60,15 @@ enum soc_type {
>> * 3: temperature for trigger_level3 interrupt
>> * condition for trigger_level3 interrupt:
>> * current temperature > threshold + trigger_levels[3]
>> - * @trigger_level0_en:
>> - * 1 = enable trigger_level0 interrupt,
>> - * 0 = disable trigger_level0 interrupt
>> - * @trigger_level1_en:
>> - * 1 = enable trigger_level1 interrupt,
>> - * 0 = disable trigger_level1 interrupt
>> - * @trigger_level2_en:
>> - * 1 = enable trigger_level2 interrupt,
>> - * 0 = disable trigger_level2 interrupt
>> - * @trigger_level3_en:
>> - * 1 = enable trigger_level3 interrupt,
>> - * 0 = disable trigger_level3 interrupt
>> + * @trigger_type: defines the type of trigger. Possible values are,
>> + * THROTTLE_ACTIVE trigger type
>> + * THROTTLE_PASSIVE trigger type
>> + * SW_TRIP trigger type
>> + * HW_TRIP
>> + * @trigger_enable[]: array to denote which trigger levels are enabled.
>> + * 1 = enable trigger_level[] interrupt,
>> + * 0 = disable trigger_level[] interrupt
>> + * @max_trigger_level: max trigger level supported by the TMU
>> * @gain: gain of amplifier in the positive-TC generator block
>> * 0 <= gain <= 15
>> * @reference_voltage: reference voltage of amplifier
>> @@ -76,7 +78,13 @@ enum soc_type {
>> * 000, 100, 101, 110 and 111 can be different modes
>> * @type: determines the type of SOC
>> * @efuse_value: platform defined fuse value
>> + * @min_efuse_value: minimum valid trimming data
>> + * @max_efuse_value: maximum valid trimming data
>> + * @first_point_trim: temp value of the first point trimming
>> + * @second_point_trim: temp value of the second point trimming
>> + * @default_temp_offset: default temperature offset in case of no trimming
>> * @cal_type: calibration type for temperature
>> + * @cal_mode: calibration mode for temperature
>> * @freq_clip_table: Table representing frequency reduction percentage.
>> * @freq_tab_count: Count of the above table as frequency reduction may
>> * applicable to only some of the trigger levels.
>> @@ -86,18 +94,23 @@ enum soc_type {
>> struct exynos_tmu_platform_data {
>> u8 threshold;
>> u8 threshold_falling;
>> - u8 trigger_levels[4];
>> - bool trigger_level0_en;
>> - bool trigger_level1_en;
>> - bool trigger_level2_en;
>> - bool trigger_level3_en;
>> -
>> + u8 trigger_levels[MAX_TRIP_COUNT];
>> + enum trigger_type trigger_type[MAX_TRIP_COUNT];
>> + bool trigger_enable[MAX_TRIP_COUNT];
>> + u8 max_trigger_level;
>> u8 gain;
>> u8 reference_voltage;
>> u8 noise_cancel_mode;
>> +
>> u32 efuse_value;
>> + u32 min_efuse_value;
>> + u32 max_efuse_value;
>> + u8 first_point_trim;
>> + u8 second_point_trim;
>> + u8 default_temp_offset;
>>
>> enum calibration_type cal_type;
>> + enum calibration_mode cal_mode;
>> enum soc_type type;
>> struct freq_clip_table freq_tab[4];
>> unsigned int freq_tab_count;
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>> index 13a60ca..a187043 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>> @@ -22,6 +22,7 @@
>>
>> #include "exynos_thermal_common.h"
>> #include "exynos_tmu.h"
>> +#include "exynos_tmu_data.h"
>
> This change needs to be moved to the patch that you added this file.
> Check comment on patch 07/30.
yes right.
>>
>> #if defined(CONFIG_CPU_EXYNOS4210)
>> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> @@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> .trigger_levels[0] = 5,
>> .trigger_levels[1] = 20,
>> .trigger_levels[2] = 30,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> + .trigger_enable[0] = 1,
>> + .trigger_enable[1] = 1,
>> + .trigger_enable[2] = 1,
>> + .trigger_enable[3] = 0,
>> + .trigger_type[0] = THROTTLE_ACTIVE,
>> + .trigger_type[1] = THROTTLE_ACTIVE,
>> + .trigger_type[2] = SW_TRIP,
>
> is there any issues if trigger_type[3] is 0? there is no defined value
> for 0. (0 means undefined on your enum definition).
Basically trigger_type[3]=0 means uninitialised also. I want this field to be
strictly initialised so did not used 0 in enum.
>
>
>> + .max_trigger_level = 4,
>> .gain = 15,
>> .reference_voltage = 7,
>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>> + .min_efuse_value = 40,
>> + .max_efuse_value = 100,
>> + .first_point_trim = 25,
>> + .second_point_trim = 85,
>> + .default_temp_offset = 50,
>> .freq_tab[0] = {
>> .freq_clip_max = 800 * 1000,
>> .temp_level = 85,
>> @@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>> .trigger_levels[0] = 85,
>> .trigger_levels[1] = 103,
>> .trigger_levels[2] = 110,
>> - .trigger_level0_en = 1,
>> - .trigger_level1_en = 1,
>> - .trigger_level2_en = 1,
>> - .trigger_level3_en = 0,
>> + .trigger_enable[0] = 1,
>> + .trigger_enable[1] = 1,
>> + .trigger_enable[2] = 1,
>> + .trigger_enable[3] = 0,
>> + .trigger_type[0] = THROTTLE_ACTIVE,
>> + .trigger_type[1] = THROTTLE_ACTIVE,
>> + .trigger_type[2] = SW_TRIP,
>> + .max_trigger_level = 4,
>> .gain = 8,
>> .reference_voltage = 16,
>> .noise_cancel_mode = 4,
>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>> .efuse_value = 55,
>> + .min_efuse_value = 40,
>> + .max_efuse_value = 100,
>> + .first_point_trim = 25,
>> + .second_point_trim = 85,
>> + .default_temp_offset = 50,
>> .freq_tab[0] = {
>> .freq_clip_max = 800 * 1000,
>> .temp_level = 85,
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi,
On Thu, Jun 20, 2013 at 2:22 AM, Eduardo Valentin
<[email protected]> wrote:
> On 19-06-2013 16:19, Eduardo Valentin wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
>>> trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
>>> trigger_enable in the TMU platform data structure. Also the driver is modified
>>> to use the data passed by these new platform memebers instead of the constant
>>> macros. All these changes helps in separating the SOC specific data part from
>>> the TMU driver.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
>>> drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
>>> drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
>>> drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
>>> 4 files changed, 86 insertions(+), 48 deletions(-)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> index 068f56c..fd789a5 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -44,6 +44,13 @@
>>>
>>> #define EXYNOS_ZONE_COUNT 3
>>>
>>> +enum trigger_type {
>>> + THROTTLE_ACTIVE = 1,
>>> + THROTTLE_PASSIVE,
>>> + SW_TRIP,
>>> + HW_TRIP,
>>> +};
>>> +
>>> /**
>>> * struct freq_clip_table
>>> * @freq_clip_max: maximum frequency allowed for this cooling state.
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index fa33a48..401ec98 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -49,7 +49,6 @@
>>> #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>>> #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>>> #define EXYNOS_TMU_CORE_EN_SHIFT 0
>>> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>>
>>> /* Exynos4210 specific registers */
>>> #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
>>> @@ -94,9 +93,6 @@
>>> #define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>>> #define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>>
>>> -#define EFUSE_MIN_VALUE 40
>>> -#define EFUSE_MAX_VALUE 100
>>> -
>>> #ifdef CONFIG_THERMAL_EMULATION
>>> #define EXYNOS_EMUL_TIME 0x57F0
>>> #define EXYNOS_EMUL_TIME_MASK 0xffff
>>> @@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>>>
>>> switch (pdata->cal_type) {
>>> case TYPE_TWO_POINT_TRIMMING:
>>> - temp_code = (temp - 25) *
>>> - (data->temp_error2 - data->temp_error1) /
>>> - (85 - 25) + data->temp_error1;
>>> + temp_code = (temp - pdata->first_point_trim) *
>>> + (data->temp_error2 - data->temp_error1) /
>>> + (pdata->second_point_trim - pdata->first_point_trim) +
>>> + data->temp_error1;
>>> break;
>>> case TYPE_ONE_POINT_TRIMMING:
>>> - temp_code = temp + data->temp_error1 - 25;
>>> + temp_code = temp + data->temp_error1 - pdata->first_point_trim;
>>> break;
>>> default:
>>> - temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>>> + temp_code = temp + pdata->default_temp_offset;
>>> break;
>>> }
>>> out:
>>> @@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>>>
>>> switch (pdata->cal_type) {
>>> case TYPE_TWO_POINT_TRIMMING:
>>> - temp = (temp_code - data->temp_error1) * (85 - 25) /
>>> - (data->temp_error2 - data->temp_error1) + 25;
>>> + temp = (temp_code - data->temp_error1) *
>>> + (pdata->second_point_trim - pdata->first_point_trim) /
>>> + (data->temp_error2 - data->temp_error1) +
>>> + pdata->first_point_trim;
>>> break;
>>> case TYPE_ONE_POINT_TRIMMING:
>>> - temp = temp_code - data->temp_error1 + 25;
>>> + temp = temp_code - data->temp_error1 + pdata->first_point_trim;
>>> break;
>>> default:
>>> - temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>>> + temp = temp_code - pdata->default_temp_offset;
>>> break;
>>> }
>>> out:
>>> @@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>>> data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
>>> data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
>>>
>>> - if ((EFUSE_MIN_VALUE > data->temp_error1) ||
>>> - (data->temp_error1 > EFUSE_MAX_VALUE) ||
>>> + if ((pdata->min_efuse_value > data->temp_error1) ||
>>> + (data->temp_error1 > pdata->max_efuse_value) ||
>>> (data->temp_error2 != 0))
>>> data->temp_error1 = pdata->efuse_value;
>>>
>>> @@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>>> if (on) {
>>> con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>> interrupt_en =
>>> - pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>> - pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>> - pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>> - pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>> + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>> + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>> + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>> + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>> if (pdata->threshold_falling)
>>> interrupt_en |=
>>> interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>>> @@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>>
>>> /* Register the sensor with thermal management interface */
>>> (&exynos_sensor_conf)->private_data = data;
>>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
>>> - pdata->trigger_level1_en + pdata->trigger_level2_en +
>>> - pdata->trigger_level3_en;
>>> + exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>>> + pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>>> + pdata->trigger_enable[3];
>>>
>>> for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>>> exynos_sensor_conf.trip_data.trip_val[i] =
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>>> index 9e0f887..45c697d 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.h
>>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>>> @@ -30,6 +30,11 @@ enum calibration_type {
>>> TYPE_NONE,
>>> };
>>>
>>> +enum calibration_mode {
>>> + SW_MODE,
>>> + HW_MODE,
>>> +};
>>> +
>>> enum soc_type {
>>> SOC_ARCH_EXYNOS4210 = 1,
>>> SOC_ARCH_EXYNOS,
>>> @@ -55,18 +60,15 @@ enum soc_type {
>>> * 3: temperature for trigger_level3 interrupt
>>> * condition for trigger_level3 interrupt:
>>> * current temperature > threshold + trigger_levels[3]
>>> - * @trigger_level0_en:
>>> - * 1 = enable trigger_level0 interrupt,
>>> - * 0 = disable trigger_level0 interrupt
>>> - * @trigger_level1_en:
>>> - * 1 = enable trigger_level1 interrupt,
>>> - * 0 = disable trigger_level1 interrupt
>>> - * @trigger_level2_en:
>>> - * 1 = enable trigger_level2 interrupt,
>>> - * 0 = disable trigger_level2 interrupt
>>> - * @trigger_level3_en:
>>> - * 1 = enable trigger_level3 interrupt,
>>> - * 0 = disable trigger_level3 interrupt
>>> + * @trigger_type: defines the type of trigger. Possible values are,
>>> + * THROTTLE_ACTIVE trigger type
>>> + * THROTTLE_PASSIVE trigger type
>>> + * SW_TRIP trigger type
>>> + * HW_TRIP
>>> + * @trigger_enable[]: array to denote which trigger levels are enabled.
>>> + * 1 = enable trigger_level[] interrupt,
>>> + * 0 = disable trigger_level[] interrupt
>>> + * @max_trigger_level: max trigger level supported by the TMU
>>> * @gain: gain of amplifier in the positive-TC generator block
>>> * 0 <= gain <= 15
>>> * @reference_voltage: reference voltage of amplifier
>>> @@ -76,7 +78,13 @@ enum soc_type {
>>> * 000, 100, 101, 110 and 111 can be different modes
>>> * @type: determines the type of SOC
>>> * @efuse_value: platform defined fuse value
>>> + * @min_efuse_value: minimum valid trimming data
>>> + * @max_efuse_value: maximum valid trimming data
>>> + * @first_point_trim: temp value of the first point trimming
>>> + * @second_point_trim: temp value of the second point trimming
>>> + * @default_temp_offset: default temperature offset in case of no trimming
>>> * @cal_type: calibration type for temperature
>>> + * @cal_mode: calibration mode for temperature
>>> * @freq_clip_table: Table representing frequency reduction percentage.
>>> * @freq_tab_count: Count of the above table as frequency reduction may
>>> * applicable to only some of the trigger levels.
>>> @@ -86,18 +94,23 @@ enum soc_type {
>>> struct exynos_tmu_platform_data {
>>> u8 threshold;
>>> u8 threshold_falling;
>>> - u8 trigger_levels[4];
>>> - bool trigger_level0_en;
>>> - bool trigger_level1_en;
>>> - bool trigger_level2_en;
>>> - bool trigger_level3_en;
>>> -
>>> + u8 trigger_levels[MAX_TRIP_COUNT];
>>> + enum trigger_type trigger_type[MAX_TRIP_COUNT];
>>> + bool trigger_enable[MAX_TRIP_COUNT];
>>> + u8 max_trigger_level;
>>> u8 gain;
>>> u8 reference_voltage;
>>> u8 noise_cancel_mode;
>>> +
>>> u32 efuse_value;
>>> + u32 min_efuse_value;
>>> + u32 max_efuse_value;
>>> + u8 first_point_trim;
>>> + u8 second_point_trim;
>>> + u8 default_temp_offset;
>>>
>>> enum calibration_type cal_type;
>>> + enum calibration_mode cal_mode;
>>> enum soc_type type;
>>> struct freq_clip_table freq_tab[4];
>>> unsigned int freq_tab_count;
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>>> index 13a60ca..a187043 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>>> @@ -22,6 +22,7 @@
>>>
>>> #include "exynos_thermal_common.h"
>>> #include "exynos_tmu.h"
>>> +#include "exynos_tmu_data.h"
>>
>> This change needs to be moved to the patch that you added this file.
>> Check comment on patch 07/30.
>>>
>>> #if defined(CONFIG_CPU_EXYNOS4210)
>>> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>> @@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>> .trigger_levels[0] = 5,
>>> .trigger_levels[1] = 20,
>>> .trigger_levels[2] = 30,
>>> - .trigger_level0_en = 1,
>>> - .trigger_level1_en = 1,
>>> - .trigger_level2_en = 1,
>>> - .trigger_level3_en = 0,
>>> + .trigger_enable[0] = 1,
>>> + .trigger_enable[1] = 1,
>>> + .trigger_enable[2] = 1,
>>> + .trigger_enable[3] = 0,
>
> This change added this sparse warning on your driver:
> drivers/thermal/samsung/exynos_tmu_data.c:34:10: warning: Initializer
> entry defined twice
> drivers/thermal/samsung/exynos_tmu_data.c:35:10: also defined here
It seems sparse tool has some issue in bool assignment checkinh and it
is not fixed yet.
http://lkml.indiana.edu/hypermail/linux/kernel/1005.0/02153.html
so leaving it as of now.
Thanks,
Amit D
>
>
>>> + .trigger_type[0] = THROTTLE_ACTIVE,
>>> + .trigger_type[1] = THROTTLE_ACTIVE,
>>> + .trigger_type[2] = SW_TRIP,
>>
>> is there any issues if trigger_type[3] is 0? there is no defined value
>> for 0. (0 means undefined on your enum definition).
>>
>>
>>> + .max_trigger_level = 4,
>>> .gain = 15,
>>> .reference_voltage = 7,
>>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> + .min_efuse_value = 40,
>>> + .max_efuse_value = 100,
>>> + .first_point_trim = 25,
>>> + .second_point_trim = 85,
>>> + .default_temp_offset = 50,
>>> .freq_tab[0] = {
>>> .freq_clip_max = 800 * 1000,
>>> .temp_level = 85,
>>> @@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>>> .trigger_levels[0] = 85,
>>> .trigger_levels[1] = 103,
>>> .trigger_levels[2] = 110,
>>> - .trigger_level0_en = 1,
>>> - .trigger_level1_en = 1,
>>> - .trigger_level2_en = 1,
>>> - .trigger_level3_en = 0,
>>> + .trigger_enable[0] = 1,
>>> + .trigger_enable[1] = 1,
>>> + .trigger_enable[2] = 1,
>>> + .trigger_enable[3] = 0,
>
>
> This change add this sparse warning on your driver:
> drivers/thermal/samsung/exynos_tmu_data.c:69:10: warning: Initializer
> entry defined twice
> drivers/thermal/samsung/exynos_tmu_data.c:70:10: also defined here
>
>
>>> + .trigger_type[0] = THROTTLE_ACTIVE,
>>> + .trigger_type[1] = THROTTLE_ACTIVE,
>>> + .trigger_type[2] = SW_TRIP,
>>> + .max_trigger_level = 4,
>>> .gain = 8,
>>> .reference_voltage = 16,
>>> .noise_cancel_mode = 4,
>>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> .efuse_value = 55,
>>> + .min_efuse_value = 40,
>>> + .max_efuse_value = 100,
>>> + .first_point_trim = 25,
>>> + .second_point_trim = 85,
>>> + .default_temp_offset = 50,
>>> .freq_tab[0] = {
>>> .freq_clip_max = 800 * 1000,
>>> .temp_level = 85,
>>>
>>
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi
On Thu, Jun 20, 2013 at 4:33 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This code simplifies the zone handling to use the trip information passed
>> by the TMU driver and not the hardcoded macros. This also helps in adding
>> more zone support.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.c | 61 +++++++++++++----------
>> drivers/thermal/samsung/exynos_thermal_common.h | 3 +-
>> drivers/thermal/samsung/exynos_tmu.c | 5 ++-
>> 3 files changed, 40 insertions(+), 29 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>> index 86d39aa..2873ca3 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>> @@ -78,17 +78,22 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
>> static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>> enum thermal_trip_type *type)
>> {
>> - switch (GET_ZONE(trip)) {
>> - case MONITOR_ZONE:
>> - case WARN_ZONE:
>> - *type = THERMAL_TRIP_ACTIVE;
>> - break;
>> - case PANIC_ZONE:
>> - *type = THERMAL_TRIP_CRITICAL;
>> - break;
>> - default:
>> + struct exynos_thermal_zone *th_zone = thermal->devdata;
>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>> + int trip_type;
>> +
>> + if (trip < 0 || trip >= max_trip)
>> return -EINVAL;
>> - }
>> +
>> + trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
>> +
>> + if (trip_type == SW_TRIP)
>> + *type = THERMAL_TRIP_CRITICAL;
>> + else if (trip_type == THROTTLE_ACTIVE)
>> + *type = THERMAL_TRIP_ACTIVE;
>> + else if (trip_type == THROTTLE_PASSIVE)
>> + *type = THERMAL_TRIP_PASSIVE;
>> +
>> return 0;
>> }
>>
>> @@ -97,8 +102,9 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> unsigned long *temp)
>> {
>> struct exynos_thermal_zone *th_zone = thermal->devdata;
>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>>
>> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> + if (trip < 0 || trip >= max_trip)
>> return -EINVAL;
>>
>> *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> @@ -112,10 +118,10 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>> static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> unsigned long *temp)
>> {
>> - int ret;
>> - /* Panic zone */
>> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> - return ret;
>> + struct exynos_thermal_zone *th_zone = thermal->devdata;
>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>> + /* Get the temp of highest trip*/
>> + return exynos_get_trip_temp(thermal, max_trip - 1, temp);
>> }
>>
>> /* Bind callback functions for thermal zone */
>> @@ -340,19 +346,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> return -ENOMEM;
>>
>> th_zone->sensor_conf = sensor_conf;
>> - cpumask_set_cpu(0, &mask_val);
>> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> - if (IS_ERR(th_zone->cool_dev[0])) {
>> - pr_err("Failed to register cpufreq cooling device\n");
>> - ret = -EINVAL;
>> - goto err_unregister;
>> + if (sensor_conf->cooling_data.freq_clip_count > 0) {
>> + cpumask_set_cpu(0, &mask_val);
>> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>
> Did you mean th_zone->cool_dev[th_zone->cool_dev_size] ?
Yes.
>
> I think the logic behind the allocation of these cpufreq cooling devices
> needs to be revisited. You always assigned to cool_dev[0], but you
> always iterate the array until cool_dev_size. Remember that
> cool_dev_size now is per th_zone, not global.
I have kept an array of cooling devices to add other type of cooling
devices in the same thermal zone in future. For current use case
although it does not make sense and only one cpufreq cooling device is
present
>
>> + if (IS_ERR(th_zone->cool_dev[0])) {
>> + pr_err("Failed to register cpufreq cooling device\n");
>> + ret = -EINVAL;
>> + goto err_unregister;
>> + }
>> + th_zone->cool_dev_size++;
>> }
>> - th_zone->cool_dev_size++;
>>
>> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>> - EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
>> - sensor_conf->trip_data.trigger_falling ?
>> - 0 : IDLE_INTERVAL);
>> + th_zone->therm_dev = thermal_zone_device_register(
>> + sensor_conf->name, sensor_conf->trip_data.trip_count,
>> + 0, th_zone, &exynos_dev_ops, NULL, 0,
>> + sensor_conf->trip_data.trigger_falling ? 0 :
>> + IDLE_INTERVAL);
>>
>> if (IS_ERR(th_zone->therm_dev)) {
>> pr_err("Failed to register thermal zone device\n");
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 1e9a326..dd0077e 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -42,8 +42,6 @@
>> #define GET_ZONE(trip) (trip + 2)
>> #define GET_TRIP(zone) (zone - 2)
>>
>> -#define EXYNOS_ZONE_COUNT 3
>> -
>> enum trigger_type {
>> THROTTLE_ACTIVE = 1,
>> THROTTLE_PASSIVE,
>> @@ -68,6 +66,7 @@ struct freq_clip_table {
>> };
>> struct thermal_trip_point_conf {
>> int trip_val[MAX_TRIP_COUNT];
>> + int trip_type[MAX_TRIP_COUNT];
>> int trip_count;
>> unsigned char trigger_falling;
>> };
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 40e0cfd..acbd295 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -509,9 +509,12 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>> pdata->trigger_enable[3];
>>
>> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>> + for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
>> exynos_sensor_conf.trip_data.trip_val[i] =
>> pdata->threshold + pdata->trigger_levels[i];
>> + exynos_sensor_conf.trip_data.trip_type[i] =
>> + pdata->trigger_type[i];
>> + }
>>
>> exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
>>
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi Eduardo,
On Thu, Jun 20, 2013 at 4:57 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch adds support to handle multiple instances of the TMU controllers.
>> This is done by removing the static structure to register with the core thermal
>> and creating it dynamically for each instance of the TMU controller. The
>> interrupt is made shared type to handle shared interrupts. Also
>> the identifier of the TMU controller is extracted from device tree alias.
>>
>> Acked-by: Kukjin Kim <[email protected]>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_thermal_common.h | 1 +
>> drivers/thermal/samsung/exynos_tmu.c | 147 ++++++++++++++++-------
>> drivers/thermal/samsung/exynos_tmu.h | 13 ++
>> drivers/thermal/samsung/exynos_tmu_data.c | 145 ++++++++++++----------
>> drivers/thermal/samsung/exynos_tmu_data.h | 4 +-
>> 5 files changed, 197 insertions(+), 113 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index dd0077e..0c189d6 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -84,6 +84,7 @@ struct thermal_sensor_conf {
>> struct thermal_cooling_conf cooling_data;
>> void *driver_data;
>> void *pzone_data;
>> + struct device *dev;
>> };
>>
>> /*Functions used exynos based thermal sensor driver*/
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 4356118..1880c4e 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -26,15 +26,32 @@
>> #include <linux/interrupt.h>
>> #include <linux/module.h>
>> #include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> #include <linux/platform_device.h>
>>
>> #include "exynos_thermal_common.h"
>> #include "exynos_tmu.h"
>> #include "exynos_tmu_data.h"
>>
>> +/**
>> + * struct exynos_tmu_data : A structure to hold the private data of the TMU
>> + driver
>> + * @id: identifier of the one instance of the TMU controller.
>> + * @pdata: pointer to the tmu platform/configuration data
>> + * @base: base address of the single instance of the TMU controller.
>> + * @irq: irq number of the TMU controller.
>> + * @soc: id of the SOC type.
>> + * @irq_work: pointer to the irq work structure.
>> + * @lock: lock to implement synchronization.
>> + * @clk: pointer to the clock structure.
>> + * @temp_error1: fused value of the first point trim.
>> + * @temp_error2: fused value of the second point trim.
>> + * @reg_conf: pointer to structure to register with core thermal.
>> + */
>> struct exynos_tmu_data {
>> + int id;
>> struct exynos_tmu_platform_data *pdata;
>> - struct resource *mem;
>> void __iomem *base;
>> int irq;
>> enum soc_type soc;
>> @@ -42,6 +59,7 @@ struct exynos_tmu_data {
>> struct mutex lock;
>> struct clk *clk;
>> u8 temp_error1, temp_error2;
>> + struct thermal_sensor_conf *reg_conf;
>> };
>>
>> /*
>> @@ -345,12 +363,6 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
>> { return -EINVAL; }
>> #endif/*CONFIG_THERMAL_EMULATION*/
>>
>> -static struct thermal_sensor_conf exynos_sensor_conf = {
>> - .name = "exynos-therm",
>> - .read_temperature = (int (*)(void *))exynos_tmu_read,
>> - .write_emul_temp = exynos_tmu_set_emulation,
>> -};
>> -
>> static void exynos_tmu_work(struct work_struct *work)
>> {
>> struct exynos_tmu_data *data = container_of(work,
>> @@ -359,7 +371,7 @@ static void exynos_tmu_work(struct work_struct *work)
>> const struct exynos_tmu_registers *reg = pdata->registers;
>> unsigned int val_irq;
>>
>> - exynos_report_trigger(&exynos_sensor_conf);
>> + exynos_report_trigger(data->reg_conf);
>> mutex_lock(&data->lock);
>> clk_enable(data->clk);
>>
>> @@ -404,33 +416,73 @@ MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>> #endif
>>
>> static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
>> - struct platform_device *pdev)
>> + struct platform_device *pdev, int id)
>> {
>> + struct exynos_tmu_init_data *data_table;
>> + struct exynos_tmu_platform_data *tmu_data;
>> #ifdef CONFIG_OF
>> if (pdev->dev.of_node) {
>> const struct of_device_id *match;
>> match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
>> if (!match)
>> return NULL;
>> - return (struct exynos_tmu_platform_data *) match->data;
>> + data_table = (struct exynos_tmu_init_data *) match->data;
>> + if (!data_table || id >= data_table->tmu_count)
>> + return NULL;
>> + tmu_data = data_table->tmu_data;
>> + return (struct exynos_tmu_platform_data *) (tmu_data + id);
>> }
>> #endif
>> return NULL;
>> }
>>
>> -static int exynos_tmu_probe(struct platform_device *pdev)
>> +static int exynos_map_dt_data(struct platform_device *pdev)
>> {
>> - struct exynos_tmu_data *data;
>> - struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
>> - int ret, i;
>> + struct exynos_tmu_data *data = platform_get_drvdata(pdev);
>> + struct exynos_tmu_platform_data *pdata;
>> + struct resource res;
>>
>> - if (!pdata)
>> - pdata = exynos_get_driver_data(pdev);
>> + if (!data)
>> + return -ENODEV;
>> +
>> + data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
>> + if (data->id < 0)
>> + data->id = 0;
>>
>> + data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
>> + if (data->irq <= 0) {
>> + dev_err(&pdev->dev, "failed to get IRQ\n");
>> + return -ENODEV;
>> + }
>> +
>> + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
>> + dev_err(&pdev->dev, "failed to get Resource 0\n");
>> + return -ENODEV;
>> + }
>> +
>> + data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
>> + if (!data->base) {
>> + dev_err(&pdev->dev, "Failed to ioremap memory\n");
>> + return -EADDRNOTAVAIL;
>> + }
>> +
>> + pdata = exynos_get_driver_data(pdev, data->id);
>> if (!pdata) {
>> dev_err(&pdev->dev, "No platform init data supplied.\n");
>> return -ENODEV;
>> }
>> + data->pdata = pdata;
>> +
>> + return 0;
>> +}
>> +
>> +static int exynos_tmu_probe(struct platform_device *pdev)
>> +{
>> + struct exynos_tmu_data *data;
>> + struct exynos_tmu_platform_data *pdata;
>> + struct thermal_sensor_conf *sensor_conf;
>> + int ret, i;
>> +
>> data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
>> GFP_KERNEL);
>> if (!data) {
>> @@ -438,21 +490,18 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>> return -ENOMEM;
>> }
>>
>> - data->irq = platform_get_irq(pdev, 0);
>> - if (data->irq < 0) {
>> - dev_err(&pdev->dev, "Failed to get platform irq\n");
>> - return data->irq;
>> - }
>> + platform_set_drvdata(pdev, data);
>> + mutex_init(&data->lock);
>>
>> - INIT_WORK(&data->irq_work, exynos_tmu_work);
>> + ret = exynos_map_dt_data(pdev);
>> + if (ret)
>> + return ret;
>>
>> - data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> - data->base = devm_ioremap_resource(&pdev->dev, data->mem);
>> - if (IS_ERR(data->base))
>> - return PTR_ERR(data->base);
>> + pdata = data->pdata;
>>
>> + INIT_WORK(&data->irq_work, exynos_tmu_work);
>> ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
>> - IRQF_TRIGGER_RISING, "exynos-tmu", data);
>> + IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
>
> Lets think about this poing: You request the IRQ before data->reg_conf
> is allocated (below). Does it mean, from this point you can get called
> to the IRQ handler even if reg_conf is not set? What happens then? I see
> your irqhandler/worker use it.
Good catch. Will put a check in the IRQ handler.
Thanks,
Amit Daniel
>
>> if (ret) {
>> dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
>> return ret;
>> @@ -477,10 +526,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>> goto err_clk;
>> }
>>
>> - data->pdata = pdata;
>> - platform_set_drvdata(pdev, data);
>> - mutex_init(&data->lock);
>> -
>> ret = exynos_tmu_initialize(pdev);
>> if (ret) {
>> dev_err(&pdev->dev, "Failed to initialize TMU\n");
>> @@ -489,31 +534,43 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>
>> exynos_tmu_control(pdev, true);
>>
>> - /* Register the sensor with thermal management interface */
>> - (&exynos_sensor_conf)->driver_data = data;
>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>> + /* Allocate a structure to register with the exynos core thermal */
>> + sensor_conf = devm_kzalloc(&pdev->dev,
>> + sizeof(struct thermal_sensor_conf), GFP_KERNEL);
>> + if (!sensor_conf) {
>> + dev_err(&pdev->dev, "Failed to allocate registration struct\n");
>> + ret = -ENOMEM;
>> + goto err_clk;
>> + }
>> + data->reg_conf = sensor_conf;
>> + sprintf(sensor_conf->name, "therm_zone%d", data->id);
>> + sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
>> + sensor_conf->write_emul_temp =
>> + (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
>> + sensor_conf->driver_data = data;
>> + sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
>> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>> pdata->trigger_enable[3];
>>
>> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
>> - exynos_sensor_conf.trip_data.trip_val[i] =
>> + for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
>> + sensor_conf->trip_data.trip_val[i] =
>> pdata->threshold + pdata->trigger_levels[i];
>> - exynos_sensor_conf.trip_data.trip_type[i] =
>> + sensor_conf->trip_data.trip_type[i] =
>> pdata->trigger_type[i];
>> }
>>
>> - exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
>> + sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
>>
>> - exynos_sensor_conf.cooling_data.freq_clip_count =
>> - pdata->freq_tab_count;
>> + sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
>> for (i = 0; i < pdata->freq_tab_count; i++) {
>> - exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
>> + sensor_conf->cooling_data.freq_data[i].freq_clip_max =
>> pdata->freq_tab[i].freq_clip_max;
>> - exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
>> + sensor_conf->cooling_data.freq_data[i].temp_level =
>> pdata->freq_tab[i].temp_level;
>> }
>> -
>> - ret = exynos_register_thermal(&exynos_sensor_conf);
>> + sensor_conf->dev = &pdev->dev;
>> + /* Register the sensor with thermal management interface */
>> + ret = exynos_register_thermal(sensor_conf);
>> if (ret) {
>> dev_err(&pdev->dev, "Failed to register thermal interface\n");
>> goto err_clk;
>> @@ -531,7 +588,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
>>
>> exynos_tmu_control(pdev, false);
>>
>> - exynos_unregister_thermal(&exynos_sensor_conf);
>> + exynos_unregister_thermal(data->reg_conf);
>>
>> clk_unprepare(data->clk);
>>
>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>> index 619a34c..b614407 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -248,4 +248,17 @@ struct exynos_tmu_platform_data {
>> unsigned int freq_tab_count;
>> const struct exynos_tmu_registers *registers;
>> };
>> +
>> +/**
>> + * struct exynos_tmu_init_data
>> + * @tmu_count: number of TMU instances.
>> + * @tmu_data: platform data of all TMU instances.
>> + * This structure is required to store data for multi-instance exynos tmu
>> + * driver.
>> + */
>> +struct exynos_tmu_init_data {
>> + int tmu_count;
>> + struct exynos_tmu_platform_data tmu_data[];
>> +};
>> +
>> #endif /* _EXYNOS_TMU_H */
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>> index 7fcf183..06ecfb0 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>> @@ -48,38 +48,44 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
>> .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
>> .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
>> };
>> -struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>> - .threshold = 80,
>> - .trigger_levels[0] = 5,
>> - .trigger_levels[1] = 20,
>> - .trigger_levels[2] = 30,
>> - .trigger_enable[0] = 1,
>> - .trigger_enable[1] = 1,
>> - .trigger_enable[2] = 1,
>> - .trigger_enable[3] = 0,
>> - .trigger_type[0] = THROTTLE_ACTIVE,
>> - .trigger_type[1] = THROTTLE_ACTIVE,
>> - .trigger_type[2] = SW_TRIP,
>> - .max_trigger_level = 4,
>> - .gain = 15,
>> - .reference_voltage = 7,
>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>> - .min_efuse_value = 40,
>> - .max_efuse_value = 100,
>> - .first_point_trim = 25,
>> - .second_point_trim = 85,
>> - .default_temp_offset = 50,
>> - .freq_tab[0] = {
>> - .freq_clip_max = 800 * 1000,
>> - .temp_level = 85,
>> - },
>> - .freq_tab[1] = {
>> - .freq_clip_max = 200 * 1000,
>> - .temp_level = 100,
>> +
>> +struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
>> + .tmu_data = {
>> + {
>> + .threshold = 80,
>> + .trigger_levels[0] = 5,
>> + .trigger_levels[1] = 20,
>> + .trigger_levels[2] = 30,
>> + .trigger_enable[0] = 1,
>> + .trigger_enable[1] = 1,
>> + .trigger_enable[2] = 1,
>> + .trigger_enable[3] = 0,
>> + .trigger_type[0] = THROTTLE_ACTIVE,
>> + .trigger_type[1] = THROTTLE_ACTIVE,
>> + .trigger_type[2] = SW_TRIP,
>> + .max_trigger_level = 4,
>> + .gain = 15,
>> + .reference_voltage = 7,
>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>> + .min_efuse_value = 40,
>> + .max_efuse_value = 100,
>> + .first_point_trim = 25,
>> + .second_point_trim = 85,
>> + .default_temp_offset = 50,
>> + .freq_tab[0] = {
>> + .freq_clip_max = 800 * 1000,
>> + .temp_level = 85,
>> + },
>> + .freq_tab[1] = {
>> + .freq_clip_max = 200 * 1000,
>> + .temp_level = 100,
>> + },
>> + .freq_tab_count = 2,
>> + .type = SOC_ARCH_EXYNOS4210,
>> + .registers = &exynos4210_tmu_registers,
>> + },
>> },
>> - .freq_tab_count = 2,
>> - .type = SOC_ARCH_EXYNOS4210,
>> - .registers = &exynos4210_tmu_registers,
>> + .tmu_count = 1,
>> };
>> #endif
>>
>> @@ -120,41 +126,48 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
>> .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
>> .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
>> };
>> -struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>> - .threshold_falling = 10,
>> - .trigger_levels[0] = 85,
>> - .trigger_levels[1] = 103,
>> - .trigger_levels[2] = 110,
>> - .trigger_levels[3] = 120,
>> - .trigger_enable[0] = 1,
>> - .trigger_enable[1] = 1,
>> - .trigger_enable[2] = 1,
>> - .trigger_enable[3] = 0,
>> - .trigger_type[0] = THROTTLE_ACTIVE,
>> - .trigger_type[1] = THROTTLE_ACTIVE,
>> - .trigger_type[2] = SW_TRIP,
>> - .trigger_type[3] = HW_TRIP,
>> - .max_trigger_level = 4,
>> - .gain = 8,
>> - .reference_voltage = 16,
>> - .noise_cancel_mode = 4,
>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>> - .efuse_value = 55,
>> - .min_efuse_value = 40,
>> - .max_efuse_value = 100,
>> - .first_point_trim = 25,
>> - .second_point_trim = 85,
>> - .default_temp_offset = 50,
>> - .freq_tab[0] = {
>> - .freq_clip_max = 800 * 1000,
>> - .temp_level = 85,
>> - },
>> - .freq_tab[1] = {
>> - .freq_clip_max = 200 * 1000,
>> - .temp_level = 103,
>> - },
>> - .freq_tab_count = 2,
>> - .type = SOC_ARCH_EXYNOS,
>> +
>> +#define EXYNOS5250_TMU_DATA \
>> + .threshold_falling = 10, \
>> + .trigger_levels[0] = 85, \
>> + .trigger_levels[1] = 103, \
>> + .trigger_levels[2] = 110, \
>> + .trigger_levels[3] = 120, \
>> + .trigger_enable[0] = 1, \
>> + .trigger_enable[1] = 1, \
>> + .trigger_enable[2] = 1, \
>> + .trigger_enable[3] = 0, \
>> + .trigger_type[0] = THROTTLE_ACTIVE, \
>> + .trigger_type[1] = THROTTLE_ACTIVE, \
>> + .trigger_type[2] = SW_TRIP, \
>> + .trigger_type[3] = HW_TRIP, \
>> + .max_trigger_level = 4, \
>> + .gain = 8, \
>> + .reference_voltage = 16, \
>> + .noise_cancel_mode = 4, \
>> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
>> + .efuse_value = 55, \
>> + .min_efuse_value = 40, \
>> + .max_efuse_value = 100, \
>> + .first_point_trim = 25, \
>> + .second_point_trim = 85, \
>> + .default_temp_offset = 50, \
>> + .freq_tab[0] = { \
>> + .freq_clip_max = 800 * 1000, \
>> + .temp_level = 85, \
>> + }, \
>> + .freq_tab[1] = { \
>> + .freq_clip_max = 200 * 1000, \
>> + .temp_level = 103, \
>> + }, \
>> + .freq_tab_count = 2, \
>> + .type = SOC_ARCH_EXYNOS, \
>> .registers = &exynos5250_tmu_registers,
>> +
>> +struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
>> + .tmu_data = {
>> + { EXYNOS5250_TMU_DATA },
>> + },
>> + .tmu_count = 1,
>> };
>> #endif
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>> index 4acf070..139dbbb 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.h
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>> @@ -94,14 +94,14 @@
>> #define EXYNOS_MAX_TRIGGER_PER_REG 4
>>
>> #if defined(CONFIG_CPU_EXYNOS4210)
>> -extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
>> +extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
>> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>> #else
>> #define EXYNOS4210_TMU_DRV_DATA (NULL)
>> #endif
>>
>> #if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
>> -extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
>> +extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
>> #define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
>> #else
>> #define EXYNOS5250_TMU_DRV_DATA (NULL)
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
> This code bifurcates exynos thermal implementation into common and sensor
> specific parts. The common thermal code interacts with core thermal layer and
> core cpufreq cooling parts and is independent of SOC specific driver. This
> change is needed to cleanly add support for new TMU sensors.
>
> Acked-by: Kukjin Kim <[email protected]>
> Acked-by: Jonghwa Lee <[email protected]>
> Signed-off-by: Amit Daniel Kachhap <[email protected]>
Acked-by: Eduardo Valentin <[email protected]>
> ---
> drivers/thermal/samsung/Kconfig | 19 +-
> drivers/thermal/samsung/Makefile | 4 +-
> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
> 5 files changed, 490 insertions(+), 419 deletions(-)
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>
> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
> index 2cf31ad..f8100b1 100644
> --- a/drivers/thermal/samsung/Kconfig
> +++ b/drivers/thermal/samsung/Kconfig
> @@ -1,8 +1,17 @@
> config EXYNOS_THERMAL
> - tristate "Temperature sensor on Samsung EXYNOS"
> + tristate "Exynos thermal management unit driver"
> depends on ARCH_HAS_BANDGAP
> help
> - If you say yes here you get support for TMU (Thermal Management
> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
> - the exynos thermal driver with the core thermal layer and cpu
> - cooling API's.
> + If you say yes here you get support for the TMU (Thermal Management
> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
> + the TMU, reports temperature and handles cooling action if defined.
> + This driver uses the exynos core thermal API's.
> +
> +config EXYNOS_THERMAL_CORE
> + bool "Core thermal framework support for EXYNOS SOC's"
> + depends on EXYNOS_THERMAL
> + help
> + If you say yes here you get support for EXYNOS TMU
> + (Thermal Management Unit) common registration/unregistration
> + functions to the core thermal layer and also to use the generic
> + cpu cooling API's.
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> index 1fe6d93..6227d4f 100644
> --- a/drivers/thermal/samsung/Makefile
> +++ b/drivers/thermal/samsung/Makefile
> @@ -1,4 +1,6 @@
> #
> # Samsung thermal specific Makefile
> #
> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
> +exynos_soc_thermal-y := exynos_thermal.o
> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
> index 03e4bbc..5293849 100644
> --- a/drivers/thermal/samsung/exynos_thermal.c
> +++ b/drivers/thermal/samsung/exynos_thermal.c
> @@ -21,23 +21,15 @@
> *
> */
>
> -#include <linux/module.h>
> -#include <linux/err.h>
> -#include <linux/kernel.h>
> -#include <linux/slab.h>
> -#include <linux/platform_device.h>
> -#include <linux/interrupt.h>
> #include <linux/clk.h>
> -#include <linux/workqueue.h>
> -#include <linux/sysfs.h>
> -#include <linux/kobject.h>
> #include <linux/io.h>
> -#include <linux/mutex.h>
> -#include <linux/platform_data/exynos_thermal.h>
> -#include <linux/thermal.h>
> -#include <linux/cpufreq.h>
> -#include <linux/cpu_cooling.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +
> +#include "exynos_thermal_common.h"
>
> /* Exynos generic registers */
> #define EXYNOS_TMU_REG_TRIMINFO 0x0
> @@ -88,16 +80,6 @@
> #define EFUSE_MIN_VALUE 40
> #define EFUSE_MAX_VALUE 100
>
> -/* In-kernel thermal framework related macros & definations */
> -#define SENSOR_NAME_LEN 16
> -#define MAX_TRIP_COUNT 8
> -#define MAX_COOLING_DEVICE 4
> -#define MAX_THRESHOLD_LEVS 4
> -
> -#define ACTIVE_INTERVAL 500
> -#define IDLE_INTERVAL 10000
> -#define MCELSIUS 1000
> -
> #ifdef CONFIG_THERMAL_EMULATION
> #define EXYNOS_EMUL_TIME 0x57F0
> #define EXYNOS_EMUL_TIME_SHIFT 16
> @@ -106,17 +88,6 @@
> #define EXYNOS_EMUL_ENABLE 0x1
> #endif /* CONFIG_THERMAL_EMULATION */
>
> -/* CPU Zone information */
> -#define PANIC_ZONE 4
> -#define WARN_ZONE 3
> -#define MONITOR_ZONE 2
> -#define SAFE_ZONE 1
> -
> -#define GET_ZONE(trip) (trip + 2)
> -#define GET_TRIP(zone) (zone - 2)
> -
> -#define EXYNOS_ZONE_COUNT 3
> -
> struct exynos_tmu_data {
> struct exynos_tmu_platform_data *pdata;
> struct resource *mem;
> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
> u8 temp_error1, temp_error2;
> };
>
> -struct thermal_trip_point_conf {
> - int trip_val[MAX_TRIP_COUNT];
> - int trip_count;
> - u8 trigger_falling;
> -};
> -
> -struct thermal_cooling_conf {
> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> - int freq_clip_count;
> -};
> -
> -struct thermal_sensor_conf {
> - char name[SENSOR_NAME_LEN];
> - int (*read_temperature)(void *data);
> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
> - struct thermal_trip_point_conf trip_data;
> - struct thermal_cooling_conf cooling_data;
> - void *private_data;
> -};
> -
> -struct exynos_thermal_zone {
> - enum thermal_device_mode mode;
> - struct thermal_zone_device *therm_dev;
> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> - unsigned int cool_dev_size;
> - struct platform_device *exynos4_dev;
> - struct thermal_sensor_conf *sensor_conf;
> - bool bind;
> -};
> -
> -static struct exynos_thermal_zone *th_zone;
> -static void exynos_unregister_thermal(void);
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> -
> -/* Get mode callback functions for thermal zone */
> -static int exynos_get_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode *mode)
> -{
> - if (th_zone)
> - *mode = th_zone->mode;
> - return 0;
> -}
> -
> -/* Set mode callback functions for thermal zone */
> -static int exynos_set_mode(struct thermal_zone_device *thermal,
> - enum thermal_device_mode mode)
> -{
> - if (!th_zone->therm_dev) {
> - pr_notice("thermal zone not registered\n");
> - return 0;
> - }
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> -
> - if (mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling)
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = 0;
> -
> - mutex_unlock(&th_zone->therm_dev->lock);
> -
> - th_zone->mode = mode;
> - thermal_zone_device_update(th_zone->therm_dev);
> - pr_info("thermal polling set for duration=%d msec\n",
> - th_zone->therm_dev->polling_delay);
> - return 0;
> -}
> -
> -
> -/* Get trip type callback functions for thermal zone */
> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> - enum thermal_trip_type *type)
> -{
> - switch (GET_ZONE(trip)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - *type = THERMAL_TRIP_ACTIVE;
> - break;
> - case PANIC_ZONE:
> - *type = THERMAL_TRIP_CRITICAL;
> - break;
> - default:
> - return -EINVAL;
> - }
> - return 0;
> -}
> -
> -/* Get trip temperature callback functions for thermal zone */
> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> - unsigned long *temp)
> -{
> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> - return -EINVAL;
> -
> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> -
> - return 0;
> -}
> -
> -/* Get critical temperature callback functions for thermal zone */
> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - int ret;
> - /* Panic zone */
> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> - return ret;
> -}
> -
> -/* Bind callback functions for thermal zone */
> -static int exynos_bind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size, level;
> - struct freq_clip_table *tab_ptr, *clip_data;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_ptr == NULL || tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> - if (level == THERMAL_CSTATE_INVALID)
> - return 0;
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> - level, 0)) {
> - pr_err("error binding cdev inst %d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = true;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> -
> - return ret;
> -}
> -
> -/* Unbind callback functions for thermal zone */
> -static int exynos_unbind(struct thermal_zone_device *thermal,
> - struct thermal_cooling_device *cdev)
> -{
> - int ret = 0, i, tab_size;
> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
> -
> - if (th_zone->bind == false)
> - return 0;
> -
> - tab_size = data->cooling_data.freq_clip_count;
> -
> - if (tab_size == 0)
> - return -EINVAL;
> -
> - /* find the cooling device registered*/
> - for (i = 0; i < th_zone->cool_dev_size; i++)
> - if (cdev == th_zone->cool_dev[i])
> - break;
> -
> - /* No matching cooling device */
> - if (i == th_zone->cool_dev_size)
> - return 0;
> -
> - /* Bind the thermal zone to the cpufreq cooling device */
> - for (i = 0; i < tab_size; i++) {
> - switch (GET_ZONE(i)) {
> - case MONITOR_ZONE:
> - case WARN_ZONE:
> - if (thermal_zone_unbind_cooling_device(thermal, i,
> - cdev)) {
> - pr_err("error unbinding cdev inst=%d\n", i);
> - ret = -EINVAL;
> - }
> - th_zone->bind = false;
> - break;
> - default:
> - ret = -EINVAL;
> - }
> - }
> - return ret;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_get_temp(struct thermal_zone_device *thermal,
> - unsigned long *temp)
> -{
> - void *data;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - *temp = th_zone->sensor_conf->read_temperature(data);
> - /* convert the temperature into millicelsius */
> - *temp = *temp * MCELSIUS;
> - return 0;
> -}
> -
> -/* Get temperature callback functions for thermal zone */
> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> - unsigned long temp)
> -{
> - void *data;
> - int ret = -EINVAL;
> -
> - if (!th_zone->sensor_conf) {
> - pr_info("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> - data = th_zone->sensor_conf->private_data;
> - if (th_zone->sensor_conf->write_emul_temp)
> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> - return ret;
> -}
> -
> -/* Get the temperature trend */
> -static int exynos_get_trend(struct thermal_zone_device *thermal,
> - int trip, enum thermal_trend *trend)
> -{
> - int ret;
> - unsigned long trip_temp;
> -
> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> - if (ret < 0)
> - return ret;
> -
> - if (thermal->temperature >= trip_temp)
> - *trend = THERMAL_TREND_RAISE_FULL;
> - else
> - *trend = THERMAL_TREND_DROP_FULL;
> -
> - return 0;
> -}
> -/* Operation callback functions for thermal zone */
> -static struct thermal_zone_device_ops const exynos_dev_ops = {
> - .bind = exynos_bind,
> - .unbind = exynos_unbind,
> - .get_temp = exynos_get_temp,
> - .set_emul_temp = exynos_set_emul_temp,
> - .get_trend = exynos_get_trend,
> - .get_mode = exynos_get_mode,
> - .set_mode = exynos_set_mode,
> - .get_trip_type = exynos_get_trip_type,
> - .get_trip_temp = exynos_get_trip_temp,
> - .get_crit_temp = exynos_get_crit_temp,
> -};
> -
> -/*
> - * This function may be called from interrupt based temperature sensor
> - * when threshold is changed.
> - */
> -static void exynos_report_trigger(void)
> -{
> - unsigned int i;
> - char data[10];
> - char *envp[] = { data, NULL };
> -
> - if (!th_zone || !th_zone->therm_dev)
> - return;
> - if (th_zone->bind == false) {
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (!th_zone->cool_dev[i])
> - continue;
> - exynos_bind(th_zone->therm_dev,
> - th_zone->cool_dev[i]);
> - }
> - }
> -
> - thermal_zone_device_update(th_zone->therm_dev);
> -
> - mutex_lock(&th_zone->therm_dev->lock);
> - /* Find the level for which trip happened */
> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> - if (th_zone->therm_dev->last_temperature <
> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> - break;
> - }
> -
> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> - !th_zone->sensor_conf->trip_data.trigger_falling) {
> - if (i > 0)
> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> - else
> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> - }
> -
> - snprintf(data, sizeof(data), "%u", i);
> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> - mutex_unlock(&th_zone->therm_dev->lock);
> -}
> -
> -/* Register with the in-kernel thermal management */
> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> -{
> - int ret;
> - struct cpumask mask_val;
> -
> - if (!sensor_conf || !sensor_conf->read_temperature) {
> - pr_err("Temperature sensor not initialised\n");
> - return -EINVAL;
> - }
> -
> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> - if (!th_zone)
> - return -ENOMEM;
> -
> - th_zone->sensor_conf = sensor_conf;
> - cpumask_set_cpu(0, &mask_val);
> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> - if (IS_ERR(th_zone->cool_dev[0])) {
> - pr_err("Failed to register cpufreq cooling device\n");
> - ret = -EINVAL;
> - goto err_unregister;
> - }
> - th_zone->cool_dev_size++;
> -
> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> - sensor_conf->trip_data.trigger_falling ?
> - 0 : IDLE_INTERVAL);
> -
> - if (IS_ERR(th_zone->therm_dev)) {
> - pr_err("Failed to register thermal zone device\n");
> - ret = PTR_ERR(th_zone->therm_dev);
> - goto err_unregister;
> - }
> - th_zone->mode = THERMAL_DEVICE_ENABLED;
> -
> - pr_info("Exynos: Kernel Thermal management registered\n");
> -
> - return 0;
> -
> -err_unregister:
> - exynos_unregister_thermal();
> - return ret;
> -}
> -
> -/* Un-Register with the in-kernel thermal management */
> -static void exynos_unregister_thermal(void)
> -{
> - int i;
> -
> - if (!th_zone)
> - return;
> -
> - if (th_zone->therm_dev)
> - thermal_zone_device_unregister(th_zone->therm_dev);
> -
> - for (i = 0; i < th_zone->cool_dev_size; i++) {
> - if (th_zone->cool_dev[i])
> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> - }
> -
> - kfree(th_zone);
> - pr_info("Exynos: Kernel Thermal management unregistered\n");
> -}
> -
> /*
> * TMU treats temperature as a mapped temperature code.
> * The temperature is converted differently depending on the calibration type.
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
> new file mode 100644
> index 0000000..92e50bc
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
> @@ -0,0 +1,384 @@
> +/*
> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/cpu_cooling.h>
> +#include <linux/platform_data/exynos_thermal.h>
> +#include <linux/slab.h>
> +#include <linux/thermal.h>
> +
> +#include "exynos_thermal_common.h"
> +
> +struct exynos_thermal_zone {
> + enum thermal_device_mode mode;
> + struct thermal_zone_device *therm_dev;
> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
> + unsigned int cool_dev_size;
> + struct platform_device *exynos4_dev;
> + struct thermal_sensor_conf *sensor_conf;
> + bool bind;
> +};
> +
> +static struct exynos_thermal_zone *th_zone;
> +
> +/* Get mode callback functions for thermal zone */
> +static int exynos_get_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode *mode)
> +{
> + if (th_zone)
> + *mode = th_zone->mode;
> + return 0;
> +}
> +
> +/* Set mode callback functions for thermal zone */
> +static int exynos_set_mode(struct thermal_zone_device *thermal,
> + enum thermal_device_mode mode)
> +{
> + if (!th_zone->therm_dev) {
> + pr_notice("thermal zone not registered\n");
> + return 0;
> + }
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> +
> + if (mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling)
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = 0;
> +
> + mutex_unlock(&th_zone->therm_dev->lock);
> +
> + th_zone->mode = mode;
> + thermal_zone_device_update(th_zone->therm_dev);
> + pr_info("thermal polling set for duration=%d msec\n",
> + th_zone->therm_dev->polling_delay);
> + return 0;
> +}
> +
> +
> +/* Get trip type callback functions for thermal zone */
> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
> + enum thermal_trip_type *type)
> +{
> + switch (GET_ZONE(trip)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + *type = THERMAL_TRIP_ACTIVE;
> + break;
> + case PANIC_ZONE:
> + *type = THERMAL_TRIP_CRITICAL;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +/* Get trip temperature callback functions for thermal zone */
> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
> + unsigned long *temp)
> +{
> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
> + return -EINVAL;
> +
> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> +
> + return 0;
> +}
> +
> +/* Get critical temperature callback functions for thermal zone */
> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + int ret;
> + /* Panic zone */
> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
> + return ret;
> +}
> +
> +/* Bind callback functions for thermal zone */
> +static int exynos_bind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size, level;
> + struct freq_clip_table *tab_ptr, *clip_data;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_ptr == NULL || tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
> + if (level == THERMAL_CSTATE_INVALID)
> + return 0;
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
> + level, 0)) {
> + pr_err("error binding cdev inst %d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = true;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/* Unbind callback functions for thermal zone */
> +static int exynos_unbind(struct thermal_zone_device *thermal,
> + struct thermal_cooling_device *cdev)
> +{
> + int ret = 0, i, tab_size;
> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
> +
> + if (th_zone->bind == false)
> + return 0;
> +
> + tab_size = data->cooling_data.freq_clip_count;
> +
> + if (tab_size == 0)
> + return -EINVAL;
> +
> + /* find the cooling device registered*/
> + for (i = 0; i < th_zone->cool_dev_size; i++)
> + if (cdev == th_zone->cool_dev[i])
> + break;
> +
> + /* No matching cooling device */
> + if (i == th_zone->cool_dev_size)
> + return 0;
> +
> + /* Bind the thermal zone to the cpufreq cooling device */
> + for (i = 0; i < tab_size; i++) {
> + switch (GET_ZONE(i)) {
> + case MONITOR_ZONE:
> + case WARN_ZONE:
> + if (thermal_zone_unbind_cooling_device(thermal, i,
> + cdev)) {
> + pr_err("error unbinding cdev inst=%d\n", i);
> + ret = -EINVAL;
> + }
> + th_zone->bind = false;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + }
> + return ret;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_get_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> +{
> + void *data;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + *temp = th_zone->sensor_conf->read_temperature(data);
> + /* convert the temperature into millicelsius */
> + *temp = *temp * MCELSIUS;
> + return 0;
> +}
> +
> +/* Get temperature callback functions for thermal zone */
> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
> + unsigned long temp)
> +{
> + void *data;
> + int ret = -EINVAL;
> +
> + if (!th_zone->sensor_conf) {
> + pr_info("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> + data = th_zone->sensor_conf->private_data;
> + if (th_zone->sensor_conf->write_emul_temp)
> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
> + return ret;
> +}
> +
> +/* Get the temperature trend */
> +static int exynos_get_trend(struct thermal_zone_device *thermal,
> + int trip, enum thermal_trend *trend)
> +{
> + int ret;
> + unsigned long trip_temp;
> +
> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
> + if (ret < 0)
> + return ret;
> +
> + if (thermal->temperature >= trip_temp)
> + *trend = THERMAL_TREND_RAISE_FULL;
> + else
> + *trend = THERMAL_TREND_DROP_FULL;
> +
> + return 0;
> +}
> +/* Operation callback functions for thermal zone */
> +static struct thermal_zone_device_ops const exynos_dev_ops = {
> + .bind = exynos_bind,
> + .unbind = exynos_unbind,
> + .get_temp = exynos_get_temp,
> + .set_emul_temp = exynos_set_emul_temp,
> + .get_trend = exynos_get_trend,
> + .get_mode = exynos_get_mode,
> + .set_mode = exynos_set_mode,
> + .get_trip_type = exynos_get_trip_type,
> + .get_trip_temp = exynos_get_trip_temp,
> + .get_crit_temp = exynos_get_crit_temp,
> +};
> +
> +/*
> + * This function may be called from interrupt based temperature sensor
> + * when threshold is changed.
> + */
> +void exynos_report_trigger(void)
> +{
> + unsigned int i;
> + char data[10];
> + char *envp[] = { data, NULL };
> +
> + if (!th_zone || !th_zone->therm_dev)
> + return;
> + if (th_zone->bind == false) {
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (!th_zone->cool_dev[i])
> + continue;
> + exynos_bind(th_zone->therm_dev,
> + th_zone->cool_dev[i]);
> + }
> + }
> +
> + thermal_zone_device_update(th_zone->therm_dev);
> +
> + mutex_lock(&th_zone->therm_dev->lock);
> + /* Find the level for which trip happened */
> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
> + if (th_zone->therm_dev->last_temperature <
> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
> + break;
> + }
> +
> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
> + !th_zone->sensor_conf->trip_data.trigger_falling) {
> + if (i > 0)
> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
> + else
> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
> + }
> +
> + snprintf(data, sizeof(data), "%u", i);
> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
> + mutex_unlock(&th_zone->therm_dev->lock);
> +}
> +
> +/* Register with the in-kernel thermal management */
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
> +{
> + int ret;
> + struct cpumask mask_val;
> +
> + if (!sensor_conf || !sensor_conf->read_temperature) {
> + pr_err("Temperature sensor not initialised\n");
> + return -EINVAL;
> + }
> +
> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
> + if (!th_zone)
> + return -ENOMEM;
> +
> + th_zone->sensor_conf = sensor_conf;
> + cpumask_set_cpu(0, &mask_val);
> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
> + if (IS_ERR(th_zone->cool_dev[0])) {
> + pr_err("Failed to register cpufreq cooling device\n");
> + ret = -EINVAL;
> + goto err_unregister;
> + }
> + th_zone->cool_dev_size++;
> +
> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
> + sensor_conf->trip_data.trigger_falling ?
> + 0 : IDLE_INTERVAL);
> +
> + if (IS_ERR(th_zone->therm_dev)) {
> + pr_err("Failed to register thermal zone device\n");
> + ret = PTR_ERR(th_zone->therm_dev);
> + goto err_unregister;
> + }
> + th_zone->mode = THERMAL_DEVICE_ENABLED;
> +
> + pr_info("Exynos: Kernel Thermal management registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + exynos_unregister_thermal();
> + return ret;
> +}
> +
> +/* Un-Register with the in-kernel thermal management */
> +void exynos_unregister_thermal(void)
> +{
> + int i;
> +
> + if (!th_zone)
> + return;
> +
> + if (th_zone->therm_dev)
> + thermal_zone_device_unregister(th_zone->therm_dev);
> +
> + for (i = 0; i < th_zone->cool_dev_size; i++) {
> + if (th_zone->cool_dev[i])
> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
> + }
> +
> + kfree(th_zone);
> + pr_info("Exynos: Kernel Thermal management unregistered\n");
> +}
> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
> new file mode 100644
> index 0000000..8df1848
> --- /dev/null
> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
> @@ -0,0 +1,83 @@
> +/*
> + * exynos_thermal_common.h - Samsung EXYNOS common header file
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + * Amit Daniel Kachhap <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifndef _EXYNOS_THERMAL_COMMON_H
> +#define _EXYNOS_THERMAL_COMMON_H
> +
> +/* In-kernel thermal framework related macros & definations */
> +#define SENSOR_NAME_LEN 16
> +#define MAX_TRIP_COUNT 8
> +#define MAX_COOLING_DEVICE 4
> +#define MAX_THRESHOLD_LEVS 4
> +
> +#define ACTIVE_INTERVAL 500
> +#define IDLE_INTERVAL 10000
> +#define MCELSIUS 1000
> +
> +/* CPU Zone information */
> +#define PANIC_ZONE 4
> +#define WARN_ZONE 3
> +#define MONITOR_ZONE 2
> +#define SAFE_ZONE 1
> +
> +#define GET_ZONE(trip) (trip + 2)
> +#define GET_TRIP(zone) (zone - 2)
> +
> +#define EXYNOS_ZONE_COUNT 3
> +
> +struct thermal_trip_point_conf {
> + int trip_val[MAX_TRIP_COUNT];
> + int trip_count;
> + unsigned char trigger_falling;
> +};
> +
> +struct thermal_cooling_conf {
> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
> + int freq_clip_count;
> +};
> +
> +struct thermal_sensor_conf {
> + char name[SENSOR_NAME_LEN];
> + int (*read_temperature)(void *data);
> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
> + struct thermal_trip_point_conf trip_data;
> + struct thermal_cooling_conf cooling_data;
> + void *private_data;
> +};
> +
> +/*Functions used exynos based thermal sensor driver*/
> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
> +void exynos_unregister_thermal(void);
> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
> +void exynos_report_trigger(void);
> +#else
> +static inline void
> +exynos_unregister_thermal(void) { return; }
> +
> +static inline int
> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
> +
> +static inline void
> +exynos_report_trigger(void) { return; }
> +
> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 21-06-2013 04:50, amit daniel kachhap wrote:
> Hi,
>
> On Thu, Jun 20, 2013 at 2:22 AM, Eduardo Valentin
> <[email protected]> wrote:
>> On 19-06-2013 16:19, Eduardo Valentin wrote:
>>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>>> This patch adds entries min_efuse_value, max_efuse_value, default_temp_offset,
>>>> trigger_type, cal_type, trim_first_point, trim_second_point, max_trigger_level
>>>> trigger_enable in the TMU platform data structure. Also the driver is modified
>>>> to use the data passed by these new platform memebers instead of the constant
>>>> macros. All these changes helps in separating the SOC specific data part from
>>>> the TMU driver.
>>>>
>>>> Acked-by: Kukjin Kim <[email protected]>
>>>> Acked-by: Jonghwa Lee <[email protected]>
>>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>>> ---
>>>> drivers/thermal/samsung/exynos_thermal_common.h | 7 +++
>>>> drivers/thermal/samsung/exynos_tmu.c | 43 ++++++++++----------
>>>> drivers/thermal/samsung/exynos_tmu.h | 49 ++++++++++++++--------
>>>> drivers/thermal/samsung/exynos_tmu_data.c | 35 ++++++++++++----
>>>> 4 files changed, 86 insertions(+), 48 deletions(-)
>>>>
>>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>>> index 068f56c..fd789a5 100644
>>>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>>> @@ -44,6 +44,13 @@
>>>>
>>>> #define EXYNOS_ZONE_COUNT 3
>>>>
>>>> +enum trigger_type {
>>>> + THROTTLE_ACTIVE = 1,
>>>> + THROTTLE_PASSIVE,
>>>> + SW_TRIP,
>>>> + HW_TRIP,
>>>> +};
>>>> +
>>>> /**
>>>> * struct freq_clip_table
>>>> * @freq_clip_max: maximum frequency allowed for this cooling state.
>>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>>> index fa33a48..401ec98 100644
>>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>>> @@ -49,7 +49,6 @@
>>>> #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>>>> #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>>>> #define EXYNOS_TMU_CORE_EN_SHIFT 0
>>>> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>>>
>>>> /* Exynos4210 specific registers */
>>>> #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
>>>> @@ -94,9 +93,6 @@
>>>> #define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>>>> #define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>>>
>>>> -#define EFUSE_MIN_VALUE 40
>>>> -#define EFUSE_MAX_VALUE 100
>>>> -
>>>> #ifdef CONFIG_THERMAL_EMULATION
>>>> #define EXYNOS_EMUL_TIME 0x57F0
>>>> #define EXYNOS_EMUL_TIME_MASK 0xffff
>>>> @@ -136,15 +132,16 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>>>>
>>>> switch (pdata->cal_type) {
>>>> case TYPE_TWO_POINT_TRIMMING:
>>>> - temp_code = (temp - 25) *
>>>> - (data->temp_error2 - data->temp_error1) /
>>>> - (85 - 25) + data->temp_error1;
>>>> + temp_code = (temp - pdata->first_point_trim) *
>>>> + (data->temp_error2 - data->temp_error1) /
>>>> + (pdata->second_point_trim - pdata->first_point_trim) +
>>>> + data->temp_error1;
>>>> break;
>>>> case TYPE_ONE_POINT_TRIMMING:
>>>> - temp_code = temp + data->temp_error1 - 25;
>>>> + temp_code = temp + data->temp_error1 - pdata->first_point_trim;
>>>> break;
>>>> default:
>>>> - temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>>>> + temp_code = temp + pdata->default_temp_offset;
>>>> break;
>>>> }
>>>> out:
>>>> @@ -169,14 +166,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>>>>
>>>> switch (pdata->cal_type) {
>>>> case TYPE_TWO_POINT_TRIMMING:
>>>> - temp = (temp_code - data->temp_error1) * (85 - 25) /
>>>> - (data->temp_error2 - data->temp_error1) + 25;
>>>> + temp = (temp_code - data->temp_error1) *
>>>> + (pdata->second_point_trim - pdata->first_point_trim) /
>>>> + (data->temp_error2 - data->temp_error1) +
>>>> + pdata->first_point_trim;
>>>> break;
>>>> case TYPE_ONE_POINT_TRIMMING:
>>>> - temp = temp_code - data->temp_error1 + 25;
>>>> + temp = temp_code - data->temp_error1 + pdata->first_point_trim;
>>>> break;
>>>> default:
>>>> - temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>>>> + temp = temp_code - pdata->default_temp_offset;
>>>> break;
>>>> }
>>>> out:
>>>> @@ -209,8 +208,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>>>> data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
>>>> data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
>>>>
>>>> - if ((EFUSE_MIN_VALUE > data->temp_error1) ||
>>>> - (data->temp_error1 > EFUSE_MAX_VALUE) ||
>>>> + if ((pdata->min_efuse_value > data->temp_error1) ||
>>>> + (data->temp_error1 > pdata->max_efuse_value) ||
>>>> (data->temp_error2 != 0))
>>>> data->temp_error1 = pdata->efuse_value;
>>>>
>>>> @@ -300,10 +299,10 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>>>> if (on) {
>>>> con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>>> interrupt_en =
>>>> - pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>>> - pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>>> - pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>>> - pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>>> + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>>> + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>>> + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>>> + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>>> if (pdata->threshold_falling)
>>>> interrupt_en |=
>>>> interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>>>> @@ -533,9 +532,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>>>
>>>> /* Register the sensor with thermal management interface */
>>>> (&exynos_sensor_conf)->private_data = data;
>>>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
>>>> - pdata->trigger_level1_en + pdata->trigger_level2_en +
>>>> - pdata->trigger_level3_en;
>>>> + exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>>>> + pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>>>> + pdata->trigger_enable[3];
>>>>
>>>> for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>>>> exynos_sensor_conf.trip_data.trip_val[i] =
>>>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>>>> index 9e0f887..45c697d 100644
>>>> --- a/drivers/thermal/samsung/exynos_tmu.h
>>>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>>>> @@ -30,6 +30,11 @@ enum calibration_type {
>>>> TYPE_NONE,
>>>> };
>>>>
>>>> +enum calibration_mode {
>>>> + SW_MODE,
>>>> + HW_MODE,
>>>> +};
>>>> +
>>>> enum soc_type {
>>>> SOC_ARCH_EXYNOS4210 = 1,
>>>> SOC_ARCH_EXYNOS,
>>>> @@ -55,18 +60,15 @@ enum soc_type {
>>>> * 3: temperature for trigger_level3 interrupt
>>>> * condition for trigger_level3 interrupt:
>>>> * current temperature > threshold + trigger_levels[3]
>>>> - * @trigger_level0_en:
>>>> - * 1 = enable trigger_level0 interrupt,
>>>> - * 0 = disable trigger_level0 interrupt
>>>> - * @trigger_level1_en:
>>>> - * 1 = enable trigger_level1 interrupt,
>>>> - * 0 = disable trigger_level1 interrupt
>>>> - * @trigger_level2_en:
>>>> - * 1 = enable trigger_level2 interrupt,
>>>> - * 0 = disable trigger_level2 interrupt
>>>> - * @trigger_level3_en:
>>>> - * 1 = enable trigger_level3 interrupt,
>>>> - * 0 = disable trigger_level3 interrupt
>>>> + * @trigger_type: defines the type of trigger. Possible values are,
>>>> + * THROTTLE_ACTIVE trigger type
>>>> + * THROTTLE_PASSIVE trigger type
>>>> + * SW_TRIP trigger type
>>>> + * HW_TRIP
>>>> + * @trigger_enable[]: array to denote which trigger levels are enabled.
>>>> + * 1 = enable trigger_level[] interrupt,
>>>> + * 0 = disable trigger_level[] interrupt
>>>> + * @max_trigger_level: max trigger level supported by the TMU
>>>> * @gain: gain of amplifier in the positive-TC generator block
>>>> * 0 <= gain <= 15
>>>> * @reference_voltage: reference voltage of amplifier
>>>> @@ -76,7 +78,13 @@ enum soc_type {
>>>> * 000, 100, 101, 110 and 111 can be different modes
>>>> * @type: determines the type of SOC
>>>> * @efuse_value: platform defined fuse value
>>>> + * @min_efuse_value: minimum valid trimming data
>>>> + * @max_efuse_value: maximum valid trimming data
>>>> + * @first_point_trim: temp value of the first point trimming
>>>> + * @second_point_trim: temp value of the second point trimming
>>>> + * @default_temp_offset: default temperature offset in case of no trimming
>>>> * @cal_type: calibration type for temperature
>>>> + * @cal_mode: calibration mode for temperature
>>>> * @freq_clip_table: Table representing frequency reduction percentage.
>>>> * @freq_tab_count: Count of the above table as frequency reduction may
>>>> * applicable to only some of the trigger levels.
>>>> @@ -86,18 +94,23 @@ enum soc_type {
>>>> struct exynos_tmu_platform_data {
>>>> u8 threshold;
>>>> u8 threshold_falling;
>>>> - u8 trigger_levels[4];
>>>> - bool trigger_level0_en;
>>>> - bool trigger_level1_en;
>>>> - bool trigger_level2_en;
>>>> - bool trigger_level3_en;
>>>> -
>>>> + u8 trigger_levels[MAX_TRIP_COUNT];
>>>> + enum trigger_type trigger_type[MAX_TRIP_COUNT];
>>>> + bool trigger_enable[MAX_TRIP_COUNT];
>>>> + u8 max_trigger_level;
>>>> u8 gain;
>>>> u8 reference_voltage;
>>>> u8 noise_cancel_mode;
>>>> +
>>>> u32 efuse_value;
>>>> + u32 min_efuse_value;
>>>> + u32 max_efuse_value;
>>>> + u8 first_point_trim;
>>>> + u8 second_point_trim;
>>>> + u8 default_temp_offset;
>>>>
>>>> enum calibration_type cal_type;
>>>> + enum calibration_mode cal_mode;
>>>> enum soc_type type;
>>>> struct freq_clip_table freq_tab[4];
>>>> unsigned int freq_tab_count;
>>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>>>> index 13a60ca..a187043 100644
>>>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>>>> @@ -22,6 +22,7 @@
>>>>
>>>> #include "exynos_thermal_common.h"
>>>> #include "exynos_tmu.h"
>>>> +#include "exynos_tmu_data.h"
>>>
>>> This change needs to be moved to the patch that you added this file.
>>> Check comment on patch 07/30.
>>>>
>>>> #if defined(CONFIG_CPU_EXYNOS4210)
>>>> struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>>> @@ -29,13 +30,22 @@ struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>>> .trigger_levels[0] = 5,
>>>> .trigger_levels[1] = 20,
>>>> .trigger_levels[2] = 30,
>>>> - .trigger_level0_en = 1,
>>>> - .trigger_level1_en = 1,
>>>> - .trigger_level2_en = 1,
>>>> - .trigger_level3_en = 0,
>>>> + .trigger_enable[0] = 1,
>>>> + .trigger_enable[1] = 1,
>>>> + .trigger_enable[2] = 1,
>>>> + .trigger_enable[3] = 0,
>>
>> This change added this sparse warning on your driver:
>> drivers/thermal/samsung/exynos_tmu_data.c:34:10: warning: Initializer
>> entry defined twice
>> drivers/thermal/samsung/exynos_tmu_data.c:35:10: also defined here
> It seems sparse tool has some issue in bool assignment checkinh and it
> is not fixed yet.
> http://lkml.indiana.edu/hypermail/linux/kernel/1005.0/02153.html
> so leaving it as of now.
OK. Looks like in the latter part of your series you change the code to
use macros. sparse then will not see this.
Talking about bool, don't you want to use true/false instead of 1/0, for
clarity?
>
> Thanks,
> Amit D
>>
>>
>>>> + .trigger_type[0] = THROTTLE_ACTIVE,
>>>> + .trigger_type[1] = THROTTLE_ACTIVE,
>>>> + .trigger_type[2] = SW_TRIP,
>>>
>>> is there any issues if trigger_type[3] is 0? there is no defined value
>>> for 0. (0 means undefined on your enum definition).
>>>
>>>
>>>> + .max_trigger_level = 4,
>>>> .gain = 15,
>>>> .reference_voltage = 7,
>>>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>>>> + .min_efuse_value = 40,
>>>> + .max_efuse_value = 100,
>>>> + .first_point_trim = 25,
>>>> + .second_point_trim = 85,
>>>> + .default_temp_offset = 50,
>>>> .freq_tab[0] = {
>>>> .freq_clip_max = 800 * 1000,
>>>> .temp_level = 85,
>>>> @@ -55,15 +65,24 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>>>> .trigger_levels[0] = 85,
>>>> .trigger_levels[1] = 103,
>>>> .trigger_levels[2] = 110,
>>>> - .trigger_level0_en = 1,
>>>> - .trigger_level1_en = 1,
>>>> - .trigger_level2_en = 1,
>>>> - .trigger_level3_en = 0,
>>>> + .trigger_enable[0] = 1,
>>>> + .trigger_enable[1] = 1,
>>>> + .trigger_enable[2] = 1,
>>>> + .trigger_enable[3] = 0,
>>
>>
>> This change add this sparse warning on your driver:
>> drivers/thermal/samsung/exynos_tmu_data.c:69:10: warning: Initializer
>> entry defined twice
>> drivers/thermal/samsung/exynos_tmu_data.c:70:10: also defined here
>>
>>
>>>> + .trigger_type[0] = THROTTLE_ACTIVE,
>>>> + .trigger_type[1] = THROTTLE_ACTIVE,
>>>> + .trigger_type[2] = SW_TRIP,
>>>> + .max_trigger_level = 4,
>>>> .gain = 8,
>>>> .reference_voltage = 16,
>>>> .noise_cancel_mode = 4,
>>>> .cal_type = TYPE_ONE_POINT_TRIMMING,
>>>> .efuse_value = 55,
>>>> + .min_efuse_value = 40,
>>>> + .max_efuse_value = 100,
>>>> + .first_point_trim = 25,
>>>> + .second_point_trim = 85,
>>>> + .default_temp_offset = 50,
>>>> .freq_tab[0] = {
>>>> .freq_clip_max = 800 * 1000,
>>>> .temp_level = 85,
>>>>
>>>
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 21-06-2013 08:46, amit daniel kachhap wrote:
> Hi Eduardo,
>
> On Thu, Jun 20, 2013 at 4:57 AM, Eduardo Valentin
> <[email protected]> wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This patch adds support to handle multiple instances of the TMU controllers.
>>> This is done by removing the static structure to register with the core thermal
>>> and creating it dynamically for each instance of the TMU controller. The
>>> interrupt is made shared type to handle shared interrupts. Also
>>> the identifier of the TMU controller is extracted from device tree alias.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_thermal_common.h | 1 +
>>> drivers/thermal/samsung/exynos_tmu.c | 147 ++++++++++++++++-------
>>> drivers/thermal/samsung/exynos_tmu.h | 13 ++
>>> drivers/thermal/samsung/exynos_tmu_data.c | 145 ++++++++++++----------
>>> drivers/thermal/samsung/exynos_tmu_data.h | 4 +-
>>> 5 files changed, 197 insertions(+), 113 deletions(-)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> index dd0077e..0c189d6 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -84,6 +84,7 @@ struct thermal_sensor_conf {
>>> struct thermal_cooling_conf cooling_data;
>>> void *driver_data;
>>> void *pzone_data;
>>> + struct device *dev;
>>> };
>>>
>>> /*Functions used exynos based thermal sensor driver*/
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index 4356118..1880c4e 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -26,15 +26,32 @@
>>> #include <linux/interrupt.h>
>>> #include <linux/module.h>
>>> #include <linux/of.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> #include <linux/platform_device.h>
>>>
>>> #include "exynos_thermal_common.h"
>>> #include "exynos_tmu.h"
>>> #include "exynos_tmu_data.h"
>>>
>>> +/**
>>> + * struct exynos_tmu_data : A structure to hold the private data of the TMU
>>> + driver
>>> + * @id: identifier of the one instance of the TMU controller.
>>> + * @pdata: pointer to the tmu platform/configuration data
>>> + * @base: base address of the single instance of the TMU controller.
>>> + * @irq: irq number of the TMU controller.
>>> + * @soc: id of the SOC type.
>>> + * @irq_work: pointer to the irq work structure.
>>> + * @lock: lock to implement synchronization.
>>> + * @clk: pointer to the clock structure.
>>> + * @temp_error1: fused value of the first point trim.
>>> + * @temp_error2: fused value of the second point trim.
>>> + * @reg_conf: pointer to structure to register with core thermal.
>>> + */
>>> struct exynos_tmu_data {
>>> + int id;
>>> struct exynos_tmu_platform_data *pdata;
>>> - struct resource *mem;
>>> void __iomem *base;
>>> int irq;
>>> enum soc_type soc;
>>> @@ -42,6 +59,7 @@ struct exynos_tmu_data {
>>> struct mutex lock;
>>> struct clk *clk;
>>> u8 temp_error1, temp_error2;
>>> + struct thermal_sensor_conf *reg_conf;
>>> };
>>>
>>> /*
>>> @@ -345,12 +363,6 @@ static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
>>> { return -EINVAL; }
>>> #endif/*CONFIG_THERMAL_EMULATION*/
>>>
>>> -static struct thermal_sensor_conf exynos_sensor_conf = {
>>> - .name = "exynos-therm",
>>> - .read_temperature = (int (*)(void *))exynos_tmu_read,
>>> - .write_emul_temp = exynos_tmu_set_emulation,
>>> -};
>>> -
>>> static void exynos_tmu_work(struct work_struct *work)
>>> {
>>> struct exynos_tmu_data *data = container_of(work,
>>> @@ -359,7 +371,7 @@ static void exynos_tmu_work(struct work_struct *work)
>>> const struct exynos_tmu_registers *reg = pdata->registers;
>>> unsigned int val_irq;
>>>
>>> - exynos_report_trigger(&exynos_sensor_conf);
>>> + exynos_report_trigger(data->reg_conf);
>>> mutex_lock(&data->lock);
>>> clk_enable(data->clk);
>>>
>>> @@ -404,33 +416,73 @@ MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>>> #endif
>>>
>>> static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
>>> - struct platform_device *pdev)
>>> + struct platform_device *pdev, int id)
>>> {
>>> + struct exynos_tmu_init_data *data_table;
>>> + struct exynos_tmu_platform_data *tmu_data;
>>> #ifdef CONFIG_OF
>>> if (pdev->dev.of_node) {
>>> const struct of_device_id *match;
>>> match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
>>> if (!match)
>>> return NULL;
>>> - return (struct exynos_tmu_platform_data *) match->data;
>>> + data_table = (struct exynos_tmu_init_data *) match->data;
>>> + if (!data_table || id >= data_table->tmu_count)
>>> + return NULL;
>>> + tmu_data = data_table->tmu_data;
>>> + return (struct exynos_tmu_platform_data *) (tmu_data + id);
>>> }
>>> #endif
>>> return NULL;
>>> }
>>>
>>> -static int exynos_tmu_probe(struct platform_device *pdev)
>>> +static int exynos_map_dt_data(struct platform_device *pdev)
>>> {
>>> - struct exynos_tmu_data *data;
>>> - struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
>>> - int ret, i;
>>> + struct exynos_tmu_data *data = platform_get_drvdata(pdev);
>>> + struct exynos_tmu_platform_data *pdata;
>>> + struct resource res;
>>>
>>> - if (!pdata)
>>> - pdata = exynos_get_driver_data(pdev);
>>> + if (!data)
>>> + return -ENODEV;
>>> +
>>> + data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
>>> + if (data->id < 0)
>>> + data->id = 0;
>>>
>>> + data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
>>> + if (data->irq <= 0) {
>>> + dev_err(&pdev->dev, "failed to get IRQ\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
>>> + dev_err(&pdev->dev, "failed to get Resource 0\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
>>> + if (!data->base) {
>>> + dev_err(&pdev->dev, "Failed to ioremap memory\n");
>>> + return -EADDRNOTAVAIL;
>>> + }
>>> +
>>> + pdata = exynos_get_driver_data(pdev, data->id);
>>> if (!pdata) {
>>> dev_err(&pdev->dev, "No platform init data supplied.\n");
>>> return -ENODEV;
>>> }
>>> + data->pdata = pdata;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int exynos_tmu_probe(struct platform_device *pdev)
>>> +{
>>> + struct exynos_tmu_data *data;
>>> + struct exynos_tmu_platform_data *pdata;
>>> + struct thermal_sensor_conf *sensor_conf;
>>> + int ret, i;
>>> +
>>> data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
>>> GFP_KERNEL);
>>> if (!data) {
>>> @@ -438,21 +490,18 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>> return -ENOMEM;
>>> }
>>>
>>> - data->irq = platform_get_irq(pdev, 0);
>>> - if (data->irq < 0) {
>>> - dev_err(&pdev->dev, "Failed to get platform irq\n");
>>> - return data->irq;
>>> - }
>>> + platform_set_drvdata(pdev, data);
>>> + mutex_init(&data->lock);
>>>
>>> - INIT_WORK(&data->irq_work, exynos_tmu_work);
>>> + ret = exynos_map_dt_data(pdev);
>>> + if (ret)
>>> + return ret;
>>>
>>> - data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> - data->base = devm_ioremap_resource(&pdev->dev, data->mem);
>>> - if (IS_ERR(data->base))
>>> - return PTR_ERR(data->base);
>>> + pdata = data->pdata;
>>>
>>> + INIT_WORK(&data->irq_work, exynos_tmu_work);
>>> ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
>>> - IRQF_TRIGGER_RISING, "exynos-tmu", data);
>>> + IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
>>
>> Lets think about this poing: You request the IRQ before data->reg_conf
>> is allocated (below). Does it mean, from this point you can get called
>> to the IRQ handler even if reg_conf is not set? What happens then? I see
>> your irqhandler/worker use it.
>
> Good catch. Will put a check in the IRQ handler.
Consider also moving the IRQ request to a point where your driver is
capable of serving IRQs already.
>
> Thanks,
> Amit Daniel
>>
>>> if (ret) {
>>> dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
>>> return ret;
>>> @@ -477,10 +526,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>> goto err_clk;
>>> }
>>>
>>> - data->pdata = pdata;
>>> - platform_set_drvdata(pdev, data);
>>> - mutex_init(&data->lock);
>>> -
>>> ret = exynos_tmu_initialize(pdev);
>>> if (ret) {
>>> dev_err(&pdev->dev, "Failed to initialize TMU\n");
>>> @@ -489,31 +534,43 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>>
>>> exynos_tmu_control(pdev, true);
>>>
>>> - /* Register the sensor with thermal management interface */
>>> - (&exynos_sensor_conf)->driver_data = data;
>>> - exynos_sensor_conf.trip_data.trip_count = pdata->trigger_enable[0] +
>>> + /* Allocate a structure to register with the exynos core thermal */
>>> + sensor_conf = devm_kzalloc(&pdev->dev,
>>> + sizeof(struct thermal_sensor_conf), GFP_KERNEL);
>>> + if (!sensor_conf) {
>>> + dev_err(&pdev->dev, "Failed to allocate registration struct\n");
>>> + ret = -ENOMEM;
>>> + goto err_clk;
>>> + }
>>> + data->reg_conf = sensor_conf;
>>> + sprintf(sensor_conf->name, "therm_zone%d", data->id);
>>> + sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
>>> + sensor_conf->write_emul_temp =
>>> + (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
>>> + sensor_conf->driver_data = data;
>>> + sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
>>> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>>> pdata->trigger_enable[3];
>>>
>>> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
>>> - exynos_sensor_conf.trip_data.trip_val[i] =
>>> + for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
>>> + sensor_conf->trip_data.trip_val[i] =
>>> pdata->threshold + pdata->trigger_levels[i];
>>> - exynos_sensor_conf.trip_data.trip_type[i] =
>>> + sensor_conf->trip_data.trip_type[i] =
>>> pdata->trigger_type[i];
>>> }
>>>
>>> - exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
>>> + sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
>>>
>>> - exynos_sensor_conf.cooling_data.freq_clip_count =
>>> - pdata->freq_tab_count;
>>> + sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
>>> for (i = 0; i < pdata->freq_tab_count; i++) {
>>> - exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
>>> + sensor_conf->cooling_data.freq_data[i].freq_clip_max =
>>> pdata->freq_tab[i].freq_clip_max;
>>> - exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
>>> + sensor_conf->cooling_data.freq_data[i].temp_level =
>>> pdata->freq_tab[i].temp_level;
>>> }
>>> -
>>> - ret = exynos_register_thermal(&exynos_sensor_conf);
>>> + sensor_conf->dev = &pdev->dev;
>>> + /* Register the sensor with thermal management interface */
>>> + ret = exynos_register_thermal(sensor_conf);
>>> if (ret) {
>>> dev_err(&pdev->dev, "Failed to register thermal interface\n");
>>> goto err_clk;
>>> @@ -531,7 +588,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
>>>
>>> exynos_tmu_control(pdev, false);
>>>
>>> - exynos_unregister_thermal(&exynos_sensor_conf);
>>> + exynos_unregister_thermal(data->reg_conf);
>>>
>>> clk_unprepare(data->clk);
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>>> index 619a34c..b614407 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.h
>>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>>> @@ -248,4 +248,17 @@ struct exynos_tmu_platform_data {
>>> unsigned int freq_tab_count;
>>> const struct exynos_tmu_registers *registers;
>>> };
>>> +
>>> +/**
>>> + * struct exynos_tmu_init_data
>>> + * @tmu_count: number of TMU instances.
>>> + * @tmu_data: platform data of all TMU instances.
>>> + * This structure is required to store data for multi-instance exynos tmu
>>> + * driver.
>>> + */
>>> +struct exynos_tmu_init_data {
>>> + int tmu_count;
>>> + struct exynos_tmu_platform_data tmu_data[];
>>> +};
>>> +
>>> #endif /* _EXYNOS_TMU_H */
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>>> index 7fcf183..06ecfb0 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>>> @@ -48,38 +48,44 @@ static const struct exynos_tmu_registers exynos4210_tmu_registers = {
>>> .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
>>> .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
>>> };
>>> -struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
>>> - .threshold = 80,
>>> - .trigger_levels[0] = 5,
>>> - .trigger_levels[1] = 20,
>>> - .trigger_levels[2] = 30,
>>> - .trigger_enable[0] = 1,
>>> - .trigger_enable[1] = 1,
>>> - .trigger_enable[2] = 1,
>>> - .trigger_enable[3] = 0,
>>> - .trigger_type[0] = THROTTLE_ACTIVE,
>>> - .trigger_type[1] = THROTTLE_ACTIVE,
>>> - .trigger_type[2] = SW_TRIP,
>>> - .max_trigger_level = 4,
>>> - .gain = 15,
>>> - .reference_voltage = 7,
>>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> - .min_efuse_value = 40,
>>> - .max_efuse_value = 100,
>>> - .first_point_trim = 25,
>>> - .second_point_trim = 85,
>>> - .default_temp_offset = 50,
>>> - .freq_tab[0] = {
>>> - .freq_clip_max = 800 * 1000,
>>> - .temp_level = 85,
>>> - },
>>> - .freq_tab[1] = {
>>> - .freq_clip_max = 200 * 1000,
>>> - .temp_level = 100,
>>> +
>>> +struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
>>> + .tmu_data = {
>>> + {
>>> + .threshold = 80,
>>> + .trigger_levels[0] = 5,
>>> + .trigger_levels[1] = 20,
>>> + .trigger_levels[2] = 30,
>>> + .trigger_enable[0] = 1,
>>> + .trigger_enable[1] = 1,
>>> + .trigger_enable[2] = 1,
>>> + .trigger_enable[3] = 0,
>>> + .trigger_type[0] = THROTTLE_ACTIVE,
>>> + .trigger_type[1] = THROTTLE_ACTIVE,
>>> + .trigger_type[2] = SW_TRIP,
>>> + .max_trigger_level = 4,
>>> + .gain = 15,
>>> + .reference_voltage = 7,
>>> + .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> + .min_efuse_value = 40,
>>> + .max_efuse_value = 100,
>>> + .first_point_trim = 25,
>>> + .second_point_trim = 85,
>>> + .default_temp_offset = 50,
>>> + .freq_tab[0] = {
>>> + .freq_clip_max = 800 * 1000,
>>> + .temp_level = 85,
>>> + },
>>> + .freq_tab[1] = {
>>> + .freq_clip_max = 200 * 1000,
>>> + .temp_level = 100,
>>> + },
>>> + .freq_tab_count = 2,
>>> + .type = SOC_ARCH_EXYNOS4210,
>>> + .registers = &exynos4210_tmu_registers,
>>> + },
>>> },
>>> - .freq_tab_count = 2,
>>> - .type = SOC_ARCH_EXYNOS4210,
>>> - .registers = &exynos4210_tmu_registers,
>>> + .tmu_count = 1,
>>> };
>>> #endif
>>>
>>> @@ -120,41 +126,48 @@ static const struct exynos_tmu_registers exynos5250_tmu_registers = {
>>> .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
>>> .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
>>> };
>>> -struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
>>> - .threshold_falling = 10,
>>> - .trigger_levels[0] = 85,
>>> - .trigger_levels[1] = 103,
>>> - .trigger_levels[2] = 110,
>>> - .trigger_levels[3] = 120,
>>> - .trigger_enable[0] = 1,
>>> - .trigger_enable[1] = 1,
>>> - .trigger_enable[2] = 1,
>>> - .trigger_enable[3] = 0,
>>> - .trigger_type[0] = THROTTLE_ACTIVE,
>>> - .trigger_type[1] = THROTTLE_ACTIVE,
>>> - .trigger_type[2] = SW_TRIP,
>>> - .trigger_type[3] = HW_TRIP,
>>> - .max_trigger_level = 4,
>>> - .gain = 8,
>>> - .reference_voltage = 16,
>>> - .noise_cancel_mode = 4,
>>> - .cal_type = TYPE_ONE_POINT_TRIMMING,
>>> - .efuse_value = 55,
>>> - .min_efuse_value = 40,
>>> - .max_efuse_value = 100,
>>> - .first_point_trim = 25,
>>> - .second_point_trim = 85,
>>> - .default_temp_offset = 50,
>>> - .freq_tab[0] = {
>>> - .freq_clip_max = 800 * 1000,
>>> - .temp_level = 85,
>>> - },
>>> - .freq_tab[1] = {
>>> - .freq_clip_max = 200 * 1000,
>>> - .temp_level = 103,
>>> - },
>>> - .freq_tab_count = 2,
>>> - .type = SOC_ARCH_EXYNOS,
>>> +
>>> +#define EXYNOS5250_TMU_DATA \
>>> + .threshold_falling = 10, \
>>> + .trigger_levels[0] = 85, \
>>> + .trigger_levels[1] = 103, \
>>> + .trigger_levels[2] = 110, \
>>> + .trigger_levels[3] = 120, \
>>> + .trigger_enable[0] = 1, \
>>> + .trigger_enable[1] = 1, \
>>> + .trigger_enable[2] = 1, \
>>> + .trigger_enable[3] = 0, \
>>> + .trigger_type[0] = THROTTLE_ACTIVE, \
>>> + .trigger_type[1] = THROTTLE_ACTIVE, \
>>> + .trigger_type[2] = SW_TRIP, \
>>> + .trigger_type[3] = HW_TRIP, \
>>> + .max_trigger_level = 4, \
>>> + .gain = 8, \
>>> + .reference_voltage = 16, \
>>> + .noise_cancel_mode = 4, \
>>> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
>>> + .efuse_value = 55, \
>>> + .min_efuse_value = 40, \
>>> + .max_efuse_value = 100, \
>>> + .first_point_trim = 25, \
>>> + .second_point_trim = 85, \
>>> + .default_temp_offset = 50, \
>>> + .freq_tab[0] = { \
>>> + .freq_clip_max = 800 * 1000, \
>>> + .temp_level = 85, \
>>> + }, \
>>> + .freq_tab[1] = { \
>>> + .freq_clip_max = 200 * 1000, \
>>> + .temp_level = 103, \
>>> + }, \
>>> + .freq_tab_count = 2, \
>>> + .type = SOC_ARCH_EXYNOS, \
>>> .registers = &exynos5250_tmu_registers,
>>> +
>>> +struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
>>> + .tmu_data = {
>>> + { EXYNOS5250_TMU_DATA },
>>> + },
>>> + .tmu_count = 1,
>>> };
>>> #endif
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>>> index 4acf070..139dbbb 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu_data.h
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>>> @@ -94,14 +94,14 @@
>>> #define EXYNOS_MAX_TRIGGER_PER_REG 4
>>>
>>> #if defined(CONFIG_CPU_EXYNOS4210)
>>> -extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
>>> +extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
>>> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>>> #else
>>> #define EXYNOS4210_TMU_DRV_DATA (NULL)
>>> #endif
>>>
>>> #if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
>>> -extern struct exynos_tmu_platform_data const exynos5250_default_tmu_data;
>>> +extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
>>> #define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
>>> #else
>>> #define EXYNOS5250_TMU_DRV_DATA (NULL)
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 20-06-2013 21:50, amit daniel kachhap wrote:
> On Thu, Jun 20, 2013 at 12:15 AM, Eduardo Valentin
> <[email protected]> wrote:
>> Amit,
>>
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This code bifurcates exynos thermal implementation into common and sensor
>>> specific parts. The common thermal code interacts with core thermal layer and
>>> core cpufreq cooling parts and is independent of SOC specific driver. This
>>> change is needed to cleanly add support for new TMU sensors.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/Kconfig | 19 +-
>>> drivers/thermal/samsung/Makefile | 4 +-
>>> drivers/thermal/samsung/exynos_thermal.c | 419 +----------------------
>>> drivers/thermal/samsung/exynos_thermal_common.c | 384 +++++++++++++++++++++
>>> drivers/thermal/samsung/exynos_thermal_common.h | 83 +++++
>>> 5 files changed, 490 insertions(+), 419 deletions(-)
>>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
>>> create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>>>
>>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>>> index 2cf31ad..f8100b1 100644
>>> --- a/drivers/thermal/samsung/Kconfig
>>> +++ b/drivers/thermal/samsung/Kconfig
>>> @@ -1,8 +1,17 @@
>>> config EXYNOS_THERMAL
>>> - tristate "Temperature sensor on Samsung EXYNOS"
>>> + tristate "Exynos thermal management unit driver"
>>> depends on ARCH_HAS_BANDGAP
>>> help
>>> - If you say yes here you get support for TMU (Thermal Management
>>> - Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
>>> - the exynos thermal driver with the core thermal layer and cpu
>>> - cooling API's.
>>> + If you say yes here you get support for the TMU (Thermal Management
>>> + Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>>> + the TMU, reports temperature and handles cooling action if defined.
>>> + This driver uses the exynos core thermal API's.
>>> +
>>> +config EXYNOS_THERMAL_CORE
>>> + bool "Core thermal framework support for EXYNOS SOC's"
>>> + depends on EXYNOS_THERMAL
>>> + help
>>> + If you say yes here you get support for EXYNOS TMU
>>> + (Thermal Management Unit) common registration/unregistration
>>> + functions to the core thermal layer and also to use the generic
>>> + cpu cooling API's.
>> Should this one depend on CPU_THERMAL? Is it mandatory?
> Hi Eduardo,
>
> No it is not mandatory. If CPU_THERMAL is not present then cooling
> device is not created and only temp/trip_points etc sysfs are created.
OK.
>
> Thanks,
> Amit Daniel
>>
>>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>>> index 1fe6d93..6227d4f 100644
>>> --- a/drivers/thermal/samsung/Makefile
>>> +++ b/drivers/thermal/samsung/Makefile
>>> @@ -1,4 +1,6 @@
>>> #
>>> # Samsung thermal specific Makefile
>>> #
>>> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>>> +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_soc_thermal.o
>>> +exynos_soc_thermal-y := exynos_thermal.o
>>> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>>> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
>>> index 03e4bbc..5293849 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal.c
>>> +++ b/drivers/thermal/samsung/exynos_thermal.c
>>> @@ -21,23 +21,15 @@
>>> *
>>> */
>>>
>>> -#include <linux/module.h>
>>> -#include <linux/err.h>
>>> -#include <linux/kernel.h>
>>> -#include <linux/slab.h>
>>> -#include <linux/platform_device.h>
>>> -#include <linux/interrupt.h>
>>> #include <linux/clk.h>
>>> -#include <linux/workqueue.h>
>>> -#include <linux/sysfs.h>
>>> -#include <linux/kobject.h>
>>> #include <linux/io.h>
>>> -#include <linux/mutex.h>
>>> -#include <linux/platform_data/exynos_thermal.h>
>>> -#include <linux/thermal.h>
>>> -#include <linux/cpufreq.h>
>>> -#include <linux/cpu_cooling.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/module.h>
>>> #include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/platform_data/exynos_thermal.h>
>>> +
>>> +#include "exynos_thermal_common.h"
>>>
>>> /* Exynos generic registers */
>>> #define EXYNOS_TMU_REG_TRIMINFO 0x0
>>> @@ -88,16 +80,6 @@
>>> #define EFUSE_MIN_VALUE 40
>>> #define EFUSE_MAX_VALUE 100
>>>
>>> -/* In-kernel thermal framework related macros & definations */
>>> -#define SENSOR_NAME_LEN 16
>>> -#define MAX_TRIP_COUNT 8
>>> -#define MAX_COOLING_DEVICE 4
>>> -#define MAX_THRESHOLD_LEVS 4
>>> -
>>> -#define ACTIVE_INTERVAL 500
>>> -#define IDLE_INTERVAL 10000
>>> -#define MCELSIUS 1000
>>> -
>>> #ifdef CONFIG_THERMAL_EMULATION
>>> #define EXYNOS_EMUL_TIME 0x57F0
>>> #define EXYNOS_EMUL_TIME_SHIFT 16
>>> @@ -106,17 +88,6 @@
>>> #define EXYNOS_EMUL_ENABLE 0x1
>>> #endif /* CONFIG_THERMAL_EMULATION */
>>>
>>> -/* CPU Zone information */
>>> -#define PANIC_ZONE 4
>>> -#define WARN_ZONE 3
>>> -#define MONITOR_ZONE 2
>>> -#define SAFE_ZONE 1
>>> -
>>> -#define GET_ZONE(trip) (trip + 2)
>>> -#define GET_TRIP(zone) (zone - 2)
>>> -
>>> -#define EXYNOS_ZONE_COUNT 3
>>> -
>>> struct exynos_tmu_data {
>>> struct exynos_tmu_platform_data *pdata;
>>> struct resource *mem;
>>> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
>>> u8 temp_error1, temp_error2;
>>> };
>>>
>>> -struct thermal_trip_point_conf {
>>> - int trip_val[MAX_TRIP_COUNT];
>>> - int trip_count;
>>> - u8 trigger_falling;
>>> -};
>>> -
>>> -struct thermal_cooling_conf {
>>> - struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>>> - int freq_clip_count;
>>> -};
>>> -
>>> -struct thermal_sensor_conf {
>>> - char name[SENSOR_NAME_LEN];
>>> - int (*read_temperature)(void *data);
>>> - int (*write_emul_temp)(void *drv_data, unsigned long temp);
>>> - struct thermal_trip_point_conf trip_data;
>>> - struct thermal_cooling_conf cooling_data;
>>> - void *private_data;
>>> -};
>>> -
>>> -struct exynos_thermal_zone {
>>> - enum thermal_device_mode mode;
>>> - struct thermal_zone_device *therm_dev;
>>> - struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>>> - unsigned int cool_dev_size;
>>> - struct platform_device *exynos4_dev;
>>> - struct thermal_sensor_conf *sensor_conf;
>>> - bool bind;
>>> -};
>>> -
>>> -static struct exynos_thermal_zone *th_zone;
>>> -static void exynos_unregister_thermal(void);
>>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>>> -
>>> -/* Get mode callback functions for thermal zone */
>>> -static int exynos_get_mode(struct thermal_zone_device *thermal,
>>> - enum thermal_device_mode *mode)
>>> -{
>>> - if (th_zone)
>>> - *mode = th_zone->mode;
>>> - return 0;
>>> -}
>>> -
>>> -/* Set mode callback functions for thermal zone */
>>> -static int exynos_set_mode(struct thermal_zone_device *thermal,
>>> - enum thermal_device_mode mode)
>>> -{
>>> - if (!th_zone->therm_dev) {
>>> - pr_notice("thermal zone not registered\n");
>>> - return 0;
>>> - }
>>> -
>>> - mutex_lock(&th_zone->therm_dev->lock);
>>> -
>>> - if (mode == THERMAL_DEVICE_ENABLED &&
>>> - !th_zone->sensor_conf->trip_data.trigger_falling)
>>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> - else
>>> - th_zone->therm_dev->polling_delay = 0;
>>> -
>>> - mutex_unlock(&th_zone->therm_dev->lock);
>>> -
>>> - th_zone->mode = mode;
>>> - thermal_zone_device_update(th_zone->therm_dev);
>>> - pr_info("thermal polling set for duration=%d msec\n",
>>> - th_zone->therm_dev->polling_delay);
>>> - return 0;
>>> -}
>>> -
>>> -
>>> -/* Get trip type callback functions for thermal zone */
>>> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>>> - enum thermal_trip_type *type)
>>> -{
>>> - switch (GET_ZONE(trip)) {
>>> - case MONITOR_ZONE:
>>> - case WARN_ZONE:
>>> - *type = THERMAL_TRIP_ACTIVE;
>>> - break;
>>> - case PANIC_ZONE:
>>> - *type = THERMAL_TRIP_CRITICAL;
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> - return 0;
>>> -}
>>> -
>>> -/* Get trip temperature callback functions for thermal zone */
>>> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>>> - unsigned long *temp)
>>> -{
>>> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>>> - return -EINVAL;
>>> -
>>> - *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>>> - /* convert the temperature into millicelsius */
>>> - *temp = *temp * MCELSIUS;
>>> -
>>> - return 0;
>>> -}
>>> -
>>> -/* Get critical temperature callback functions for thermal zone */
>>> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>>> - unsigned long *temp)
>>> -{
>>> - int ret;
>>> - /* Panic zone */
>>> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>>> - return ret;
>>> -}
>>> -
>>> -/* Bind callback functions for thermal zone */
>>> -static int exynos_bind(struct thermal_zone_device *thermal,
>>> - struct thermal_cooling_device *cdev)
>>> -{
>>> - int ret = 0, i, tab_size, level;
>>> - struct freq_clip_table *tab_ptr, *clip_data;
>>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>>> -
>>> - tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>>> - tab_size = data->cooling_data.freq_clip_count;
>>> -
>>> - if (tab_ptr == NULL || tab_size == 0)
>>> - return -EINVAL;
>>> -
>>> - /* find the cooling device registered*/
>>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>>> - if (cdev == th_zone->cool_dev[i])
>>> - break;
>>> -
>>> - /* No matching cooling device */
>>> - if (i == th_zone->cool_dev_size)
>>> - return 0;
>>> -
>>> - /* Bind the thermal zone to the cpufreq cooling device */
>>> - for (i = 0; i < tab_size; i++) {
>>> - clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>>> - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>>> - if (level == THERMAL_CSTATE_INVALID)
>>> - return 0;
>>> - switch (GET_ZONE(i)) {
>>> - case MONITOR_ZONE:
>>> - case WARN_ZONE:
>>> - if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>>> - level, 0)) {
>>> - pr_err("error binding cdev inst %d\n", i);
>>> - ret = -EINVAL;
>>> - }
>>> - th_zone->bind = true;
>>> - break;
>>> - default:
>>> - ret = -EINVAL;
>>> - }
>>> - }
>>> -
>>> - return ret;
>>> -}
>>> -
>>> -/* Unbind callback functions for thermal zone */
>>> -static int exynos_unbind(struct thermal_zone_device *thermal,
>>> - struct thermal_cooling_device *cdev)
>>> -{
>>> - int ret = 0, i, tab_size;
>>> - struct thermal_sensor_conf *data = th_zone->sensor_conf;
>>> -
>>> - if (th_zone->bind == false)
>>> - return 0;
>>> -
>>> - tab_size = data->cooling_data.freq_clip_count;
>>> -
>>> - if (tab_size == 0)
>>> - return -EINVAL;
>>> -
>>> - /* find the cooling device registered*/
>>> - for (i = 0; i < th_zone->cool_dev_size; i++)
>>> - if (cdev == th_zone->cool_dev[i])
>>> - break;
>>> -
>>> - /* No matching cooling device */
>>> - if (i == th_zone->cool_dev_size)
>>> - return 0;
>>> -
>>> - /* Bind the thermal zone to the cpufreq cooling device */
>>> - for (i = 0; i < tab_size; i++) {
>>> - switch (GET_ZONE(i)) {
>>> - case MONITOR_ZONE:
>>> - case WARN_ZONE:
>>> - if (thermal_zone_unbind_cooling_device(thermal, i,
>>> - cdev)) {
>>> - pr_err("error unbinding cdev inst=%d\n", i);
>>> - ret = -EINVAL;
>>> - }
>>> - th_zone->bind = false;
>>> - break;
>>> - default:
>>> - ret = -EINVAL;
>>> - }
>>> - }
>>> - return ret;
>>> -}
>>> -
>>> -/* Get temperature callback functions for thermal zone */
>>> -static int exynos_get_temp(struct thermal_zone_device *thermal,
>>> - unsigned long *temp)
>>> -{
>>> - void *data;
>>> -
>>> - if (!th_zone->sensor_conf) {
>>> - pr_info("Temperature sensor not initialised\n");
>>> - return -EINVAL;
>>> - }
>>> - data = th_zone->sensor_conf->private_data;
>>> - *temp = th_zone->sensor_conf->read_temperature(data);
>>> - /* convert the temperature into millicelsius */
>>> - *temp = *temp * MCELSIUS;
>>> - return 0;
>>> -}
>>> -
>>> -/* Get temperature callback functions for thermal zone */
>>> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>>> - unsigned long temp)
>>> -{
>>> - void *data;
>>> - int ret = -EINVAL;
>>> -
>>> - if (!th_zone->sensor_conf) {
>>> - pr_info("Temperature sensor not initialised\n");
>>> - return -EINVAL;
>>> - }
>>> - data = th_zone->sensor_conf->private_data;
>>> - if (th_zone->sensor_conf->write_emul_temp)
>>> - ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>>> - return ret;
>>> -}
>>> -
>>> -/* Get the temperature trend */
>>> -static int exynos_get_trend(struct thermal_zone_device *thermal,
>>> - int trip, enum thermal_trend *trend)
>>> -{
>>> - int ret;
>>> - unsigned long trip_temp;
>>> -
>>> - ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>>> - if (ret < 0)
>>> - return ret;
>>> -
>>> - if (thermal->temperature >= trip_temp)
>>> - *trend = THERMAL_TREND_RAISE_FULL;
>>> - else
>>> - *trend = THERMAL_TREND_DROP_FULL;
>>> -
>>> - return 0;
>>> -}
>>> -/* Operation callback functions for thermal zone */
>>> -static struct thermal_zone_device_ops const exynos_dev_ops = {
>>> - .bind = exynos_bind,
>>> - .unbind = exynos_unbind,
>>> - .get_temp = exynos_get_temp,
>>> - .set_emul_temp = exynos_set_emul_temp,
>>> - .get_trend = exynos_get_trend,
>>> - .get_mode = exynos_get_mode,
>>> - .set_mode = exynos_set_mode,
>>> - .get_trip_type = exynos_get_trip_type,
>>> - .get_trip_temp = exynos_get_trip_temp,
>>> - .get_crit_temp = exynos_get_crit_temp,
>>> -};
>>> -
>>> -/*
>>> - * This function may be called from interrupt based temperature sensor
>>> - * when threshold is changed.
>>> - */
>>> -static void exynos_report_trigger(void)
>>> -{
>>> - unsigned int i;
>>> - char data[10];
>>> - char *envp[] = { data, NULL };
>>> -
>>> - if (!th_zone || !th_zone->therm_dev)
>>> - return;
>>> - if (th_zone->bind == false) {
>>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>>> - if (!th_zone->cool_dev[i])
>>> - continue;
>>> - exynos_bind(th_zone->therm_dev,
>>> - th_zone->cool_dev[i]);
>>> - }
>>> - }
>>> -
>>> - thermal_zone_device_update(th_zone->therm_dev);
>>> -
>>> - mutex_lock(&th_zone->therm_dev->lock);
>>> - /* Find the level for which trip happened */
>>> - for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>>> - if (th_zone->therm_dev->last_temperature <
>>> - th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>>> - break;
>>> - }
>>> -
>>> - if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>>> - !th_zone->sensor_conf->trip_data.trigger_falling) {
>>> - if (i > 0)
>>> - th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>>> - else
>>> - th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> - }
>>> -
>>> - snprintf(data, sizeof(data), "%u", i);
>>> - kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>>> - mutex_unlock(&th_zone->therm_dev->lock);
>>> -}
>>> -
>>> -/* Register with the in-kernel thermal management */
>>> -static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>>> -{
>>> - int ret;
>>> - struct cpumask mask_val;
>>> -
>>> - if (!sensor_conf || !sensor_conf->read_temperature) {
>>> - pr_err("Temperature sensor not initialised\n");
>>> - return -EINVAL;
>>> - }
>>> -
>>> - th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>>> - if (!th_zone)
>>> - return -ENOMEM;
>>> -
>>> - th_zone->sensor_conf = sensor_conf;
>>> - cpumask_set_cpu(0, &mask_val);
>>> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>>> - if (IS_ERR(th_zone->cool_dev[0])) {
>>> - pr_err("Failed to register cpufreq cooling device\n");
>>> - ret = -EINVAL;
>>> - goto err_unregister;
>>> - }
>>> - th_zone->cool_dev_size++;
>>> -
>>> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>>> - EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>>> - sensor_conf->trip_data.trigger_falling ?
>>> - 0 : IDLE_INTERVAL);
>>> -
>>> - if (IS_ERR(th_zone->therm_dev)) {
>>> - pr_err("Failed to register thermal zone device\n");
>>> - ret = PTR_ERR(th_zone->therm_dev);
>>> - goto err_unregister;
>>> - }
>>> - th_zone->mode = THERMAL_DEVICE_ENABLED;
>>> -
>>> - pr_info("Exynos: Kernel Thermal management registered\n");
>>> -
>>> - return 0;
>>> -
>>> -err_unregister:
>>> - exynos_unregister_thermal();
>>> - return ret;
>>> -}
>>> -
>>> -/* Un-Register with the in-kernel thermal management */
>>> -static void exynos_unregister_thermal(void)
>>> -{
>>> - int i;
>>> -
>>> - if (!th_zone)
>>> - return;
>>> -
>>> - if (th_zone->therm_dev)
>>> - thermal_zone_device_unregister(th_zone->therm_dev);
>>> -
>>> - for (i = 0; i < th_zone->cool_dev_size; i++) {
>>> - if (th_zone->cool_dev[i])
>>> - cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>>> - }
>>> -
>>> - kfree(th_zone);
>>> - pr_info("Exynos: Kernel Thermal management unregistered\n");
>>> -}
>>> -
>>> /*
>>> * TMU treats temperature as a mapped temperature code.
>>> * The temperature is converted differently depending on the calibration type.
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>>> new file mode 100644
>>> index 0000000..92e50bc
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>>> @@ -0,0 +1,384 @@
>>> +/*
>>> + * exynos_thermal_common.c - Samsung EXYNOS common thermal file
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics
>>> + * Amit Daniel Kachhap <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>>> + *
>>> + */
>>> +
>>> +#include <linux/cpu_cooling.h>
>>> +#include <linux/platform_data/exynos_thermal.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#include "exynos_thermal_common.h"
>>> +
>>> +struct exynos_thermal_zone {
>>> + enum thermal_device_mode mode;
>>> + struct thermal_zone_device *therm_dev;
>>> + struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>>> + unsigned int cool_dev_size;
>>> + struct platform_device *exynos4_dev;
>>> + struct thermal_sensor_conf *sensor_conf;
>>> + bool bind;
>>> +};
>>> +
>>> +static struct exynos_thermal_zone *th_zone;
>>> +
>>> +/* Get mode callback functions for thermal zone */
>>> +static int exynos_get_mode(struct thermal_zone_device *thermal,
>>> + enum thermal_device_mode *mode)
>>> +{
>>> + if (th_zone)
>>> + *mode = th_zone->mode;
>>> + return 0;
>>> +}
>>> +
>>> +/* Set mode callback functions for thermal zone */
>>> +static int exynos_set_mode(struct thermal_zone_device *thermal,
>>> + enum thermal_device_mode mode)
>>> +{
>>> + if (!th_zone->therm_dev) {
>>> + pr_notice("thermal zone not registered\n");
>>> + return 0;
>>> + }
>>> +
>>> + mutex_lock(&th_zone->therm_dev->lock);
>>> +
>>> + if (mode == THERMAL_DEVICE_ENABLED &&
>>> + !th_zone->sensor_conf->trip_data.trigger_falling)
>>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> + else
>>> + th_zone->therm_dev->polling_delay = 0;
>>> +
>>> + mutex_unlock(&th_zone->therm_dev->lock);
>>> +
>>> + th_zone->mode = mode;
>>> + thermal_zone_device_update(th_zone->therm_dev);
>>> + pr_info("thermal polling set for duration=%d msec\n",
>>> + th_zone->therm_dev->polling_delay);
>>> + return 0;
>>> +}
>>> +
>>> +
>>> +/* Get trip type callback functions for thermal zone */
>>> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>>> + enum thermal_trip_type *type)
>>> +{
>>> + switch (GET_ZONE(trip)) {
>>> + case MONITOR_ZONE:
>>> + case WARN_ZONE:
>>> + *type = THERMAL_TRIP_ACTIVE;
>>> + break;
>>> + case PANIC_ZONE:
>>> + *type = THERMAL_TRIP_CRITICAL;
>>> + break;
>>> + default:
>>> + return -EINVAL;
>>> + }
>>> + return 0;
>>> +}
>>> +
>>> +/* Get trip temperature callback functions for thermal zone */
>>> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>>> + unsigned long *temp)
>>> +{
>>> + if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>>> + return -EINVAL;
>>> +
>>> + *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>>> + /* convert the temperature into millicelsius */
>>> + *temp = *temp * MCELSIUS;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/* Get critical temperature callback functions for thermal zone */
>>> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>>> + unsigned long *temp)
>>> +{
>>> + int ret;
>>> + /* Panic zone */
>>> + ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>>> + return ret;
>>> +}
>>> +
>>> +/* Bind callback functions for thermal zone */
>>> +static int exynos_bind(struct thermal_zone_device *thermal,
>>> + struct thermal_cooling_device *cdev)
>>> +{
>>> + int ret = 0, i, tab_size, level;
>>> + struct freq_clip_table *tab_ptr, *clip_data;
>>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>>> +
>>> + tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>>> + tab_size = data->cooling_data.freq_clip_count;
>>> +
>>> + if (tab_ptr == NULL || tab_size == 0)
>>> + return -EINVAL;
>>> +
>>> + /* find the cooling device registered*/
>>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>>> + if (cdev == th_zone->cool_dev[i])
>>> + break;
>>> +
>>> + /* No matching cooling device */
>>> + if (i == th_zone->cool_dev_size)
>>> + return 0;
>>> +
>>> + /* Bind the thermal zone to the cpufreq cooling device */
>>> + for (i = 0; i < tab_size; i++) {
>>> + clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>>> + level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>>> + if (level == THERMAL_CSTATE_INVALID)
>>> + return 0;
>>> + switch (GET_ZONE(i)) {
>>> + case MONITOR_ZONE:
>>> + case WARN_ZONE:
>>> + if (thermal_zone_bind_cooling_device(thermal, i, cdev,
>>> + level, 0)) {
>>> + pr_err("error binding cdev inst %d\n", i);
>>> + ret = -EINVAL;
>>> + }
>>> + th_zone->bind = true;
>>> + break;
>>> + default:
>>> + ret = -EINVAL;
>>> + }
>>> + }
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +/* Unbind callback functions for thermal zone */
>>> +static int exynos_unbind(struct thermal_zone_device *thermal,
>>> + struct thermal_cooling_device *cdev)
>>> +{
>>> + int ret = 0, i, tab_size;
>>> + struct thermal_sensor_conf *data = th_zone->sensor_conf;
>>> +
>>> + if (th_zone->bind == false)
>>> + return 0;
>>> +
>>> + tab_size = data->cooling_data.freq_clip_count;
>>> +
>>> + if (tab_size == 0)
>>> + return -EINVAL;
>>> +
>>> + /* find the cooling device registered*/
>>> + for (i = 0; i < th_zone->cool_dev_size; i++)
>>> + if (cdev == th_zone->cool_dev[i])
>>> + break;
>>> +
>>> + /* No matching cooling device */
>>> + if (i == th_zone->cool_dev_size)
>>> + return 0;
>>> +
>>> + /* Bind the thermal zone to the cpufreq cooling device */
>>> + for (i = 0; i < tab_size; i++) {
>>> + switch (GET_ZONE(i)) {
>>> + case MONITOR_ZONE:
>>> + case WARN_ZONE:
>>> + if (thermal_zone_unbind_cooling_device(thermal, i,
>>> + cdev)) {
>>> + pr_err("error unbinding cdev inst=%d\n", i);
>>> + ret = -EINVAL;
>>> + }
>>> + th_zone->bind = false;
>>> + break;
>>> + default:
>>> + ret = -EINVAL;
>>> + }
>>> + }
>>> + return ret;
>>> +}
>>> +
>>> +/* Get temperature callback functions for thermal zone */
>>> +static int exynos_get_temp(struct thermal_zone_device *thermal,
>>> + unsigned long *temp)
>>> +{
>>> + void *data;
>>> +
>>> + if (!th_zone->sensor_conf) {
>>> + pr_info("Temperature sensor not initialised\n");
>>> + return -EINVAL;
>>> + }
>>> + data = th_zone->sensor_conf->private_data;
>>> + *temp = th_zone->sensor_conf->read_temperature(data);
>>> + /* convert the temperature into millicelsius */
>>> + *temp = *temp * MCELSIUS;
>>> + return 0;
>>> +}
>>> +
>>> +/* Get temperature callback functions for thermal zone */
>>> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>>> + unsigned long temp)
>>> +{
>>> + void *data;
>>> + int ret = -EINVAL;
>>> +
>>> + if (!th_zone->sensor_conf) {
>>> + pr_info("Temperature sensor not initialised\n");
>>> + return -EINVAL;
>>> + }
>>> + data = th_zone->sensor_conf->private_data;
>>> + if (th_zone->sensor_conf->write_emul_temp)
>>> + ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>>> + return ret;
>>> +}
>>> +
>>> +/* Get the temperature trend */
>>> +static int exynos_get_trend(struct thermal_zone_device *thermal,
>>> + int trip, enum thermal_trend *trend)
>>> +{
>>> + int ret;
>>> + unsigned long trip_temp;
>>> +
>>> + ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>>> + if (ret < 0)
>>> + return ret;
>>> +
>>> + if (thermal->temperature >= trip_temp)
>>> + *trend = THERMAL_TREND_RAISE_FULL;
>>> + else
>>> + *trend = THERMAL_TREND_DROP_FULL;
>>> +
>>> + return 0;
>>> +}
>>> +/* Operation callback functions for thermal zone */
>>> +static struct thermal_zone_device_ops const exynos_dev_ops = {
>>> + .bind = exynos_bind,
>>> + .unbind = exynos_unbind,
>>> + .get_temp = exynos_get_temp,
>>> + .set_emul_temp = exynos_set_emul_temp,
>>> + .get_trend = exynos_get_trend,
>>> + .get_mode = exynos_get_mode,
>>> + .set_mode = exynos_set_mode,
>>> + .get_trip_type = exynos_get_trip_type,
>>> + .get_trip_temp = exynos_get_trip_temp,
>>> + .get_crit_temp = exynos_get_crit_temp,
>>> +};
>>> +
>>> +/*
>>> + * This function may be called from interrupt based temperature sensor
>>> + * when threshold is changed.
>>> + */
>>> +void exynos_report_trigger(void)
>>> +{
>>> + unsigned int i;
>>> + char data[10];
>>> + char *envp[] = { data, NULL };
>>> +
>>> + if (!th_zone || !th_zone->therm_dev)
>>> + return;
>>> + if (th_zone->bind == false) {
>>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>>> + if (!th_zone->cool_dev[i])
>>> + continue;
>>> + exynos_bind(th_zone->therm_dev,
>>> + th_zone->cool_dev[i]);
>>> + }
>>> + }
>>> +
>>> + thermal_zone_device_update(th_zone->therm_dev);
>>> +
>>> + mutex_lock(&th_zone->therm_dev->lock);
>>> + /* Find the level for which trip happened */
>>> + for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>>> + if (th_zone->therm_dev->last_temperature <
>>> + th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
>>> + break;
>>> + }
>>> +
>>> + if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>>> + !th_zone->sensor_conf->trip_data.trigger_falling) {
>>> + if (i > 0)
>>> + th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
>>> + else
>>> + th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> + }
>>> +
>>> + snprintf(data, sizeof(data), "%u", i);
>>> + kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
>>> + mutex_unlock(&th_zone->therm_dev->lock);
>>> +}
>>> +
>>> +/* Register with the in-kernel thermal management */
>>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>>> +{
>>> + int ret;
>>> + struct cpumask mask_val;
>>> +
>>> + if (!sensor_conf || !sensor_conf->read_temperature) {
>>> + pr_err("Temperature sensor not initialised\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>>> + if (!th_zone)
>>> + return -ENOMEM;
>>> +
>>> + th_zone->sensor_conf = sensor_conf;
>>> + cpumask_set_cpu(0, &mask_val);
>>> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>>> + if (IS_ERR(th_zone->cool_dev[0])) {
>>> + pr_err("Failed to register cpufreq cooling device\n");
>>> + ret = -EINVAL;
>>> + goto err_unregister;
>>> + }
>>> + th_zone->cool_dev_size++;
>>> +
>>> + th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>>> + EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
>>> + sensor_conf->trip_data.trigger_falling ?
>>> + 0 : IDLE_INTERVAL);
>>> +
>>> + if (IS_ERR(th_zone->therm_dev)) {
>>> + pr_err("Failed to register thermal zone device\n");
>>> + ret = PTR_ERR(th_zone->therm_dev);
>>> + goto err_unregister;
>>> + }
>>> + th_zone->mode = THERMAL_DEVICE_ENABLED;
>>> +
>>> + pr_info("Exynos: Kernel Thermal management registered\n");
>>> +
>>> + return 0;
>>> +
>>> +err_unregister:
>>> + exynos_unregister_thermal();
>>> + return ret;
>>> +}
>>> +
>>> +/* Un-Register with the in-kernel thermal management */
>>> +void exynos_unregister_thermal(void)
>>> +{
>>> + int i;
>>> +
>>> + if (!th_zone)
>>> + return;
>>> +
>>> + if (th_zone->therm_dev)
>>> + thermal_zone_device_unregister(th_zone->therm_dev);
>>> +
>>> + for (i = 0; i < th_zone->cool_dev_size; i++) {
>>> + if (th_zone->cool_dev[i])
>>> + cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>>> + }
>>> +
>>> + kfree(th_zone);
>>> + pr_info("Exynos: Kernel Thermal management unregistered\n");
>>> +}
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> new file mode 100644
>>> index 0000000..8df1848
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -0,0 +1,83 @@
>>> +/*
>>> + * exynos_thermal_common.h - Samsung EXYNOS common header file
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics
>>> + * Amit Daniel Kachhap <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>>> + *
>>> + */
>>> +
>>> +#ifndef _EXYNOS_THERMAL_COMMON_H
>>> +#define _EXYNOS_THERMAL_COMMON_H
>>> +
>>> +/* In-kernel thermal framework related macros & definations */
>>> +#define SENSOR_NAME_LEN 16
>>> +#define MAX_TRIP_COUNT 8
>>> +#define MAX_COOLING_DEVICE 4
>>> +#define MAX_THRESHOLD_LEVS 4
>>> +
>>> +#define ACTIVE_INTERVAL 500
>>> +#define IDLE_INTERVAL 10000
>>> +#define MCELSIUS 1000
>>> +
>>> +/* CPU Zone information */
>>> +#define PANIC_ZONE 4
>>> +#define WARN_ZONE 3
>>> +#define MONITOR_ZONE 2
>>> +#define SAFE_ZONE 1
>>> +
>>> +#define GET_ZONE(trip) (trip + 2)
>>> +#define GET_TRIP(zone) (zone - 2)
>>> +
>>> +#define EXYNOS_ZONE_COUNT 3
>>> +
>>> +struct thermal_trip_point_conf {
>>> + int trip_val[MAX_TRIP_COUNT];
>>> + int trip_count;
>>> + unsigned char trigger_falling;
>>> +};
>>> +
>>> +struct thermal_cooling_conf {
>>> + struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>>> + int freq_clip_count;
>>> +};
>>> +
>>> +struct thermal_sensor_conf {
>>> + char name[SENSOR_NAME_LEN];
>>> + int (*read_temperature)(void *data);
>>> + int (*write_emul_temp)(void *drv_data, unsigned long temp);
>>> + struct thermal_trip_point_conf trip_data;
>>> + struct thermal_cooling_conf cooling_data;
>>> + void *private_data;
>>> +};
>>> +
>>> +/*Functions used exynos based thermal sensor driver*/
>>> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
>>> +void exynos_unregister_thermal(void);
>>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>>> +void exynos_report_trigger(void);
>>> +#else
>>> +static inline void
>>> +exynos_unregister_thermal(void) { return; }
>>> +
>>> +static inline int
>>> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
>>> +
>>> +static inline void
>>> +exynos_report_trigger(void) { return; }
>>> +
>>> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
>>> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On 20-06-2013 22:01, amit daniel kachhap wrote:
> Hi Eduardo,
>
> On Thu, Jun 20, 2013 at 1:25 AM, Eduardo Valentin
> <[email protected]> wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This patch adds some extra register bitfield definations and cleans
>>> up the code to prepare for moving register macros and definations inside
>>> the TMU data section.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_tmu.c | 62 +++++++++++++++++++++++++---------
>>> 1 files changed, 46 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index 5df04a1..fa33a48 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -43,9 +43,12 @@
>>>
>>> #define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
>>> #define EXYNOS_TMU_GAIN_SHIFT 8
>>> +#define EXYNOS_TMU_GAIN_MASK 0xf
>>> #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
>>> -#define EXYNOS_TMU_CORE_ON 3
>>> -#define EXYNOS_TMU_CORE_OFF 2
>>> +#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
>>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>>> +#define EXYNOS_TMU_CORE_EN_SHIFT 0
>>> #define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>>
>>> /* Exynos4210 specific registers */
>>> @@ -63,6 +66,7 @@
>>> #define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
>>> #define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
>>> #define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
>>> +#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
>>> #define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
>>>
>>> /* Exynos5250 and Exynos4412 specific registers */
>>> @@ -72,17 +76,30 @@
>>> #define EXYNOS_EMUL_CON 0x80
>>>
>>> #define EXYNOS_TRIMINFO_RELOAD 0x1
>>> +#define EXYNOS_TRIMINFO_SHIFT 0x0
>>> +#define EXYNOS_TMU_RISE_INT_MASK 0x111
>>> +#define EXYNOS_TMU_RISE_INT_SHIFT 0
>>> +#define EXYNOS_TMU_FALL_INT_MASK 0x111
>>> +#define EXYNOS_TMU_FALL_INT_SHIFT 12
>>> #define EXYNOS_TMU_CLEAR_RISE_INT 0x111
>>> #define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
>>> -#define EXYNOS_MUX_ADDR_VALUE 6
>>> -#define EXYNOS_MUX_ADDR_SHIFT 20
>>> #define EXYNOS_TMU_TRIP_MODE_SHIFT 13
>>> +#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
>>> +
>>> +#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
>>> +#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
>>> +#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
>>> +#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
>>> +#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
>>> +#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>>> +#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>>
>>> #define EFUSE_MIN_VALUE 40
>>> #define EFUSE_MAX_VALUE 100
>>>
>>> #ifdef CONFIG_THERMAL_EMULATION
>>> #define EXYNOS_EMUL_TIME 0x57F0
>>> +#define EXYNOS_EMUL_TIME_MASK 0xffff
>>> #define EXYNOS_EMUL_TIME_SHIFT 16
>>> #define EXYNOS_EMUL_DATA_SHIFT 8
>>> #define EXYNOS_EMUL_DATA_MASK 0xFF
>>> @@ -261,24 +278,37 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>>> mutex_lock(&data->lock);
>>> clk_enable(data->clk);
>>>
>>> - con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
>>> - pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
>>> + con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
>>>
>>> - if (data->soc == SOC_ARCH_EXYNOS) {
>>> - con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
>>> - con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
>>> + if (pdata->reference_voltage) {
>>> + con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
>>> + EXYNOS_TMU_REF_VOLTAGE_SHIFT);
>>> + con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
>>> + }
>>> +
>>> + if (pdata->gain) {
>>> + con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
>>> + con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
>>> + }
>>> +
>>> + if (pdata->noise_cancel_mode) {
>>> + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
>>> + EXYNOS_TMU_TRIP_MODE_SHIFT);
>>> + con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
>>> }
>>>
>>> if (on) {
>>> - con |= EXYNOS_TMU_CORE_ON;
>>
>>
>>
>> Before, in order to turn core on you had:
>> con = con | 3;
>>
>> now you do:
>> con = con | (1 << 0);
>>
>> To me, before you would set bit 1 and 0, now you set bit 0.
>>
>>
>>> - interrupt_en = pdata->trigger_level3_en << 12 |
>>> - pdata->trigger_level2_en << 8 |
>>> - pdata->trigger_level1_en << 4 |
>>> - pdata->trigger_level0_en;
>>> + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>> + interrupt_en =
>>> + pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>> + pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>> + pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>> + pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>> if (pdata->threshold_falling)
>>> - interrupt_en |= interrupt_en << 16;
>>> + interrupt_en |=
>>> + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>>> } else {
>>> - con |= EXYNOS_TMU_CORE_OFF;
>>> + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>
>>
>> Before, in order to turno core off you had:
>> con = con | 2;
>>
>> now you do:
>> con = con & ~(1 << 0);
>>
>> To me, before you would set bit 2, now you clear bit 0.
>>
>> Using the approach on this patch looks correct to me if you have 1 bit
>> core_en for instance.
>>
>> so, Is this a fix?
>>
>> Just to be clear, is this what you want ?
> Yes you are right. Bit 0 is the actual enable bit. Bit 1 is the
> reserve bit and its default value is 1. Earlier both bits are used to
> turn on/off the controller which was wrong so this patch rectifies it.
Care to mention this in your patch description? It is good for code history.
>
> Thanks,
> Amit
>>
>>> interrupt_en = 0; /* Disable all interrupts */
>>> }
>>> writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
On Thu, Jun 20, 2013 at 5:15 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> From: Lukasz Majewski <[email protected]>
>>
>> Proper description for Exynos4 bindings added to Documentation/devicetree/
>> bindings
>>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Signed-off-by: Lukasz Majewski <[email protected]>
>> Signed-off-by: Kyungmin Park <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> .../devicetree/bindings/thermal/exynos-thermal.txt | 25 ++++++++++++++++++++
>> 1 files changed, 25 insertions(+), 0 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>>
>> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>> new file mode 100644
>> index 0000000..535fd0e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>> @@ -0,0 +1,25 @@
>> +* Exynos Thermal Management Unit (TMU)
>> +
>> +** Required properties:
>> +
>> +- compatible : One of the following:
>> + "samsung,exynos4412-tmu"
>> + "samsung,exynos4210-tmu"
>> + "samsung,exynos5250-tmu"
>> +- interrupt-parent : The phandle for the interrupt controller
>> +- reg : Address range of the thermal registers
>> +- interrupts : Should contain interrupt for thermal system
>> +- clocks : The main clock for TMU device
>> +- clock-names : Thermal system clock name
>
> Should this include the documentation on the alias needed by patch 18?
> tmuctrl?
>Yes right it should be there. Actually It is there in the later patches. Will re-submit this patch in proper order.
>
>> +
>> +Example:
>> +
>> + tmu@100C0000 {
>> + compatible = "samsung,exynos4412-tmu";
>> + interrupt-parent = <&combiner>;
>> + reg = <0x100C0000 0x100>;
>> + interrupts = <2 4>;
>> + clocks = <&clock 383>;
>> + clock-names = "tmu_apbif";
>> + status = "disabled";
>> + };
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On 21-06-2013 08:30, amit daniel kachhap wrote:
> Hi
>
> On Thu, Jun 20, 2013 at 4:33 AM, Eduardo Valentin
> <[email protected]> wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This code simplifies the zone handling to use the trip information passed
>>> by the TMU driver and not the hardcoded macros. This also helps in adding
>>> more zone support.
>>>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_thermal_common.c | 61 +++++++++++++----------
>>> drivers/thermal/samsung/exynos_thermal_common.h | 3 +-
>>> drivers/thermal/samsung/exynos_tmu.c | 5 ++-
>>> 3 files changed, 40 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>>> index 86d39aa..2873ca3 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.c
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>>> @@ -78,17 +78,22 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
>>> static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
>>> enum thermal_trip_type *type)
>>> {
>>> - switch (GET_ZONE(trip)) {
>>> - case MONITOR_ZONE:
>>> - case WARN_ZONE:
>>> - *type = THERMAL_TRIP_ACTIVE;
>>> - break;
>>> - case PANIC_ZONE:
>>> - *type = THERMAL_TRIP_CRITICAL;
>>> - break;
>>> - default:
>>> + struct exynos_thermal_zone *th_zone = thermal->devdata;
>>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>>> + int trip_type;
>>> +
>>> + if (trip < 0 || trip >= max_trip)
>>> return -EINVAL;
>>> - }
>>> +
>>> + trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
>>> +
>>> + if (trip_type == SW_TRIP)
>>> + *type = THERMAL_TRIP_CRITICAL;
>>> + else if (trip_type == THROTTLE_ACTIVE)
>>> + *type = THERMAL_TRIP_ACTIVE;
>>> + else if (trip_type == THROTTLE_PASSIVE)
>>> + *type = THERMAL_TRIP_PASSIVE;
>>> +
>>> return 0;
>>> }
>>>
>>> @@ -97,8 +102,9 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>>> unsigned long *temp)
>>> {
>>> struct exynos_thermal_zone *th_zone = thermal->devdata;
>>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>>>
>>> - if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>>> + if (trip < 0 || trip >= max_trip)
>>> return -EINVAL;
>>>
>>> *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>>> @@ -112,10 +118,10 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
>>> static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>>> unsigned long *temp)
>>> {
>>> - int ret;
>>> - /* Panic zone */
>>> - ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>>> - return ret;
>>> + struct exynos_thermal_zone *th_zone = thermal->devdata;
>>> + int max_trip = th_zone->sensor_conf->trip_data.trip_count;
>>> + /* Get the temp of highest trip*/
>>> + return exynos_get_trip_temp(thermal, max_trip - 1, temp);
>>> }
>>>
>>> /* Bind callback functions for thermal zone */
>>> @@ -340,19 +346,22 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>>> return -ENOMEM;
>>>
>>> th_zone->sensor_conf = sensor_conf;
>>> - cpumask_set_cpu(0, &mask_val);
>>> - th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>>> - if (IS_ERR(th_zone->cool_dev[0])) {
>>> - pr_err("Failed to register cpufreq cooling device\n");
>>> - ret = -EINVAL;
>>> - goto err_unregister;
>>> + if (sensor_conf->cooling_data.freq_clip_count > 0) {
>>> + cpumask_set_cpu(0, &mask_val);
>>> + th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>>
>> Did you mean th_zone->cool_dev[th_zone->cool_dev_size] ?
> Yes.
>>
>> I think the logic behind the allocation of these cpufreq cooling devices
>> needs to be revisited. You always assigned to cool_dev[0], but you
>> always iterate the array until cool_dev_size. Remember that
>> cool_dev_size now is per th_zone, not global.
> I have kept an array of cooling devices to add other type of cooling
> devices in the same thermal zone in future. For current use case
> although it does not make sense and only one cpufreq cooling device is
> present
I would at least put a TODO mark. This code can easily evolve to a bug.
What it would be better is to have a proper flag/way to say how you want
to do the cooling on a specific TMU. Now you rely on the fact that you
either cool with cpufreq if freq table is present or you don't cool.
This is not scalable to what you are planing to do.
>>
>>> + if (IS_ERR(th_zone->cool_dev[0])) {
>>> + pr_err("Failed to register cpufreq cooling device\n");
>>> + ret = -EINVAL;
>>> + goto err_unregister;
>>> + }
>>> + th_zone->cool_dev_size++;
>>> }
>>> - th_zone->cool_dev_size++;
>>>
>>> - th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
>>> - EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops, NULL, 0,
>>> - sensor_conf->trip_data.trigger_falling ?
>>> - 0 : IDLE_INTERVAL);
>>> + th_zone->therm_dev = thermal_zone_device_register(
>>> + sensor_conf->name, sensor_conf->trip_data.trip_count,
>>> + 0, th_zone, &exynos_dev_ops, NULL, 0,
>>> + sensor_conf->trip_data.trigger_falling ? 0 :
>>> + IDLE_INTERVAL);
>>>
>>> if (IS_ERR(th_zone->therm_dev)) {
>>> pr_err("Failed to register thermal zone device\n");
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> index 1e9a326..dd0077e 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -42,8 +42,6 @@
>>> #define GET_ZONE(trip) (trip + 2)
>>> #define GET_TRIP(zone) (zone - 2)
>>>
>>> -#define EXYNOS_ZONE_COUNT 3
>>> -
>>> enum trigger_type {
>>> THROTTLE_ACTIVE = 1,
>>> THROTTLE_PASSIVE,
>>> @@ -68,6 +66,7 @@ struct freq_clip_table {
>>> };
>>> struct thermal_trip_point_conf {
>>> int trip_val[MAX_TRIP_COUNT];
>>> + int trip_type[MAX_TRIP_COUNT];
>>> int trip_count;
>>> unsigned char trigger_falling;
>>> };
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index 40e0cfd..acbd295 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -509,9 +509,12 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>>> pdata->trigger_enable[1] + pdata->trigger_enable[2]+
>>> pdata->trigger_enable[3];
>>>
>>> - for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>>> + for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++) {
>>> exynos_sensor_conf.trip_data.trip_val[i] =
>>> pdata->threshold + pdata->trigger_levels[i];
>>> + exynos_sensor_conf.trip_data.trip_type[i] =
>>> + pdata->trigger_type[i];
>>> + }
>>>
>>> exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
>>>
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
>
>
--
You have got to be excited about what you are doing. (L. Lamport)
Eduardo Valentin
Hi Eduardo,
On Thu, Jun 20, 2013 at 7:36 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch modifies TMU controller to add changes needed to work with
>> exynos5440 platform. This sensor registers 3 instance of the tmu controller
>> with the thermal zone and hence reports 3 temperature output. This controller
>> supports upto five trip points. For critical threshold the driver uses the
>> core driver thermal framework for shutdown.
>>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Acked-by: Kukjin Kim <[email protected]>
>> Signed-off-by: Jungseok Lee <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> .../devicetree/bindings/thermal/exynos-thermal.txt | 24 ++++++++-
>> drivers/thermal/samsung/exynos_thermal_common.h | 2 +-
>> drivers/thermal/samsung/exynos_tmu.c | 54 +++++++++++++++++---
>> drivers/thermal/samsung/exynos_tmu.h | 6 ++
>> drivers/thermal/samsung/exynos_tmu_data.h | 36 +++++++++++++
>> 5 files changed, 112 insertions(+), 10 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>> index 0ea33f7..e6386ea 100644
>> --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
>> @@ -6,6 +6,7 @@
>> "samsung,exynos4412-tmu"
>> "samsung,exynos4210-tmu"
>> "samsung,exynos5250-tmu"
>> + "samsung,exynos5440-tmu"
>> - interrupt-parent : The phandle for the interrupt controller
>> - reg : Address range of the thermal registers. For soc's which has multiple
>> instances of TMU and some registers are shared across all TMU's like
>> @@ -16,7 +17,7 @@
>> - clocks : The main clock for TMU device
>> - clock-names : Thermal system clock name
>>
>> -Example:
>> +Example 1):
>>
>> tmu@100C0000 {
>> compatible = "samsung,exynos4412-tmu";
>> @@ -27,3 +28,24 @@ Example:
>> clock-names = "tmu_apbif";
>> status = "disabled";
>> };
>> +
>> +Example 2):
>> +
>> + tmuctrl_0: tmuctrl@160118 {
>> + compatible = "samsung,exynos5440-tmu";
>> + reg = <0x160118 0x230>, <0x160368 0x10>;
>> + interrupts = <0 58 0>;
>> + clocks = <&clock 21>;
>> + clock-names = "tmu_apbif";
>> + };
>> +
>> +Note: For multi-instance tmu each instance should have an alias correctly
>> +numbered in "aliases" node.
>> +
>> +Example:
>> +
>> +aliases {
>> + tmuctrl0 = &tmuctrl_0;
>> + tmuctrl1 = &tmuctrl_1;
>> + tmuctrl2 = &tmuctrl_2;
>> +};
>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>> index 0c189d6..7d7c29a 100644
>> --- a/drivers/thermal/samsung/exynos_thermal_common.h
>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>> @@ -27,7 +27,7 @@
>> #define SENSOR_NAME_LEN 16
>> #define MAX_TRIP_COUNT 8
>> #define MAX_COOLING_DEVICE 4
>> -#define MAX_THRESHOLD_LEVS 4
>> +#define MAX_THRESHOLD_LEVS 5
>>
>> #define ACTIVE_INTERVAL 500
>> #define IDLE_INTERVAL 10000
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index 150a869..db4035d 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -156,7 +156,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>> __raw_writel(1, data->base + reg->triminfo_ctrl);
>>
>> /* Save trimming info in order to perform calibration */
>> - trim_info = readl(data->base + reg->triminfo_data);
>> + if (data->soc == SOC_ARCH_EXYNOS5440) {
>
> should this become some bit at your pdata->features? TMU_SUPPORTS(pdata,
> TRIMINFO) for instance?
Initially I also thought of getting rid of SOC checks completely but
they have been retained in some rare cases.
Here this a limitation in the h/w and very specific to exynos5440. So
not sure if this can be added as a feature.
>
>> + /*
>> + * For exynos5440 soc triminfo value is swapped between TMU0 and
>> + * TMU2, so the below logic is needed.
>> + */
>> + switch (data->id) {
>> + case 0:
>> + trim_info = readl(data->base +
>> + EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
>> + break;
>> + case 1:
>> + trim_info = readl(data->base + reg->triminfo_data);
>> + break;
>> + case 2:
>> + trim_info = readl(data->base -
>> + EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
>> + }
>> + } else {
>> + trim_info = readl(data->base + reg->triminfo_data);
>> + }
>> data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
>> data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
>> EXYNOS_TMU_TEMP_MASK);
>> @@ -201,7 +220,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>> reg->threshold_th0 + i * sizeof(reg->threshold_th0));
>>
>> writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
>> - } else if (data->soc == SOC_ARCH_EXYNOS) {
>> + } else if (data->soc == SOC_ARCH_EXYNOS ||
>> + data->soc == SOC_ARCH_EXYNOS5440) {
>> /* Write temperature code for rising and falling threshold */
>> for (i = 0;
>> i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
>> @@ -241,14 +261,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
>> ret = threshold_code;
>> goto out;
>> }
>> - rising_threshold |= threshold_code << 8 * i;
>> - writel(rising_threshold,
>> - data->base + reg->threshold_th0);
>> + if (data->soc == SOC_ARCH_EXYNOS) {
>> + rising_threshold |= threshold_code << 8 * i;
>> + writel(rising_threshold,
>> + data->base + reg->threshold_th0);
>> + } else if (data->soc == SOC_ARCH_EXYNOS5440) {
>
> Can these ifs be translated to some TMU_SUPPORTS()?
>
> Just wondering if it is possible to get rid of data->soc flags and use
> only features or represent the shifts as fields inside your pdata.
Here soc check can be removed. Will repost with this change.
>
>> + rising_threshold =
>> + threshold_code << reg->threshold_th3_l0_shift;
>> + writel(rising_threshold,
>> + data->base + reg->threshold_th2);
>> + }
>> con = readl(data->base + reg->tmu_ctrl);
>> con |= (1 << reg->therm_trip_en_shift);
>> writel(con, data->base + reg->tmu_ctrl);
>> }
>> }
>> + /*Clear the PMIN in the common TMU register*/
>> + if (reg->tmu_pmin && !data->id)
>> + writel(0, data->base_common + reg->tmu_pmin);
>
> What happens to other TMU instances when one of them performs this
> operation? does it need to serialized?
This is one time setting for all the instances and currently I have
done it for first TMU with aliad ID as 0. This register belongs to the
common set.
>
>> out:
>> clk_disable(data->clk);
>> mutex_unlock(&data->lock);
>> @@ -377,7 +407,14 @@ static void exynos_tmu_work(struct work_struct *work)
>> struct exynos_tmu_data, irq_work);
>> struct exynos_tmu_platform_data *pdata = data->pdata;
>> const struct exynos_tmu_registers *reg = pdata->registers;
>> - unsigned int val_irq;
>> + unsigned int val_irq, val_type;
>> +
>> + /* Find which sensor generated this interrupt */
>> + if (reg->tmu_irqstatus) {
>> + val_type = readl(data->base_common + reg->tmu_irqstatus);
>> + if (!((val_type >> data->id) & 0x1))
>> + goto out;
>> + }
>>
>> exynos_report_trigger(data->reg_conf);
>> mutex_lock(&data->lock);
>> @@ -390,7 +427,7 @@ static void exynos_tmu_work(struct work_struct *work)
>>
>> clk_disable(data->clk);
>> mutex_unlock(&data->lock);
>> -
>> +out:
>> enable_irq(data->irq);
>> }
>>
>> @@ -544,7 +581,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>> return ret;
>>
>> if (pdata->type == SOC_ARCH_EXYNOS ||
>> - pdata->type == SOC_ARCH_EXYNOS4210)
>> + pdata->type == SOC_ARCH_EXYNOS4210 ||
>> + pdata->type == SOC_ARCH_EXYNOS5440)
>> data->soc = pdata->type;
>> else {
>> ret = -EINVAL;
>> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
>> index 6f55673..73aaed7 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.h
>> +++ b/drivers/thermal/samsung/exynos_tmu.h
>> @@ -38,6 +38,7 @@ enum calibration_mode {
>> enum soc_type {
>> SOC_ARCH_EXYNOS4210 = 1,
>> SOC_ARCH_EXYNOS,
>> + SOC_ARCH_EXYNOS5440,
>> };
>>
>> /**
>> @@ -129,6 +130,8 @@ enum soc_type {
>> * @emul_temp_shift: shift bits of emulation temperature.
>> * @emul_time_shift: shift bits of emulation time.
>> * @emul_time_mask: mask bits of emulation time.
>> + * @tmu_irqstatus: register to find which TMU generated interrupts.
>> + * @tmu_pmin: register to get/set the Pmin value.
>> */
>> struct exynos_tmu_registers {
>> u32 triminfo_data;
>> @@ -196,6 +199,9 @@ struct exynos_tmu_registers {
>> u32 emul_temp_shift;
>> u32 emul_time_shift;
>> u32 emul_time_mask;
>> +
>> + u32 tmu_irqstatus;
>> + u32 tmu_pmin;
>> };
>>
>> /**
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>> index 139dbbb..ad263e9 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.h
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>> @@ -93,6 +93,42 @@
>>
>> #define EXYNOS_MAX_TRIGGER_PER_REG 4
>>
>> +/*exynos5440 specific registers*/
>> +#define EXYNOS5440_TMU_S0_7_TRIM 0x000
>> +#define EXYNOS5440_TMU_S0_7_CTRL 0x020
>> +#define EXYNOS5440_TMU_S0_7_DEBUG 0x040
>> +#define EXYNOS5440_TMU_S0_7_STATUS 0x060
>> +#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0
>> +#define EXYNOS5440_TMU_S0_7_TH0 0x110
>> +#define EXYNOS5440_TMU_S0_7_TH1 0x130
>> +#define EXYNOS5440_TMU_S0_7_TH2 0x150
>> +#define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0
>> +#define EXYNOS5440_TMU_S0_7_IRQEN 0x210
>> +#define EXYNOS5440_TMU_S0_7_IRQ 0x230
>> +/* exynos5440 common registers */
>> +#define EXYNOS5440_TMU_IRQ_STATUS 0x000
>> +#define EXYNOS5440_TMU_PMIN 0x004
>> +#define EXYNOS5440_TMU_TEMP 0x008
>> +
>> +#define EXYNOS5440_TMU_RISE_INT_MASK 0xf
>> +#define EXYNOS5440_TMU_RISE_INT_SHIFT 0
>> +#define EXYNOS5440_TMU_FALL_INT_MASK 0xf
>> +#define EXYNOS5440_TMU_FALL_INT_SHIFT 4
>> +#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0
>> +#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1
>> +#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2
>> +#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3
>> +#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4
>> +#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5
>> +#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6
>> +#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7
>> +#define EXYNOS5440_TMU_TH_RISE0_SHIFT 0
>> +#define EXYNOS5440_TMU_TH_RISE1_SHIFT 8
>> +#define EXYNOS5440_TMU_TH_RISE2_SHIFT 16
>> +#define EXYNOS5440_TMU_TH_RISE3_SHIFT 24
>> +#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
>> +#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
>> +
>> #if defined(CONFIG_CPU_EXYNOS4210)
>> extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
>> #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
Hi,
On Thu, Jun 20, 2013 at 7:48 AM, Eduardo Valentin
<[email protected]> wrote:
> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>> This patch adds configuration data for exynos5440 soc. Also register
>> definations for the controller are added.
>>
>> Acked-by: Jonghwa Lee <[email protected]>
>> Acked-by: Kukjin Kim <[email protected]>
>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>> ---
>> drivers/thermal/samsung/exynos_tmu.c | 4 ++
>> drivers/thermal/samsung/exynos_tmu_data.c | 71 +++++++++++++++++++++++++++++
>> drivers/thermal/samsung/exynos_tmu_data.h | 7 +++
>> 3 files changed, 82 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>> index db4035d..a4dbc84 100644
>> --- a/drivers/thermal/samsung/exynos_tmu.c
>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>> @@ -455,6 +455,10 @@ static const struct of_device_id exynos_tmu_match[] = {
>> .compatible = "samsung,exynos5250-tmu",
>> .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>> },
>> + {
>> + .compatible = "samsung,exynos5440-tmu",
>> + .data = (void *)EXYNOS5440_TMU_DRV_DATA,
>> + },
>> {},
>> };
>> MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>> index 694557e..b34e726 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>> @@ -175,3 +175,74 @@ struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
>> .tmu_count = 1,
>> };
>> #endif
>> +
>> +#if defined(CONFIG_SOC_EXYNOS5440)
>> +static const struct exynos_tmu_registers exynos5440_tmu_registers = {
>> + .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
>> + .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
>> + .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
>> + .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
>> + .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
>> + .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
>> + .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
>> + .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
>> + .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
>> + .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
>> + .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
>> + .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
>> + .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
>> + .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
>> + .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
>> + .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
>> + .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
>> + .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
>> + .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
>> + .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
>> + .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
>> + .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
>> + .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
>> + .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
>> + .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
>> + .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
>> + .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
>> + .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
>> + .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
>> + .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
>> + .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
>> + .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
>> + .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
>> + .tmu_pmin = EXYNOS5440_TMU_PMIN,
>> +};
>> +
>> +#define EXYNOS5440_TMU_DATA \
>> + .trigger_levels[0] = 100, \
>> + .trigger_levels[4] = 105, \
>> + .trigger_enable[0] = 1, \
>> + .trigger_type[0] = SW_TRIP, \
>> + .trigger_type[4] = HW_TRIP, \
>
> No active / passive cooling?
>
>> + .max_trigger_level = 5, \
>> + .gain = 5, \
>> + .reference_voltage = 16, \
>> + .noise_cancel_mode = 4, \
>> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
>> + .cal_mode = 0, \
>> + .efuse_value = 0x5b2d, \
>> + .min_efuse_value = 16, \
>> + .max_efuse_value = 76, \
>> + .first_point_trim = 25, \
>> + .second_point_trim = 70, \
>> + .default_temp_offset = 25, \
>> + .type = SOC_ARCH_EXYNOS5440, \
>> + .registers = &exynos5440_tmu_registers, \
>> + .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
>> + TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
>
> No freq table on 5440? hmm.. So no cpufreq_cooling then? Any reason why
> not? I suppose one of these 3 sensors are on your CPU domain, right?
In 5440 no cpufreq cooling is needed. Only sw trip and hw trip is sufficient.
Thanks,
Amit Daniel
>
>> +
>> +struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
>> + .tmu_data = {
>> + { EXYNOS5440_TMU_DATA } ,
>> + { EXYNOS5440_TMU_DATA } ,
>> + { EXYNOS5440_TMU_DATA } ,
>> + },
>> + .tmu_count = 3,
>> +};
>> +#endif
>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>> index ad263e9..43ce5fb 100644
>> --- a/drivers/thermal/samsung/exynos_tmu_data.h
>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>> @@ -143,4 +143,11 @@ extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
>> #define EXYNOS5250_TMU_DRV_DATA (NULL)
>> #endif
>>
>> +#if defined(CONFIG_SOC_EXYNOS5440)
>> +extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
>> +#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
>> +#else
>> +#define EXYNOS5440_TMU_DRV_DATA (NULL)
>> +#endif
>> +
>> #endif /*_EXYNOS_TMU_DATA_H*/
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>
On Fri, Jun 21, 2013 at 8:49 PM, amit daniel kachhap
<[email protected]> wrote:
> Hi,
>
> On Thu, Jun 20, 2013 at 7:48 AM, Eduardo Valentin
> <[email protected]> wrote:
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This patch adds configuration data for exynos5440 soc. Also register
>>> definations for the controller are added.
>>>
>>> Acked-by: Jonghwa Lee <[email protected]>
>>> Acked-by: Kukjin Kim <[email protected]>
>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>> ---
>>> drivers/thermal/samsung/exynos_tmu.c | 4 ++
>>> drivers/thermal/samsung/exynos_tmu_data.c | 71 +++++++++++++++++++++++++++++
>>> drivers/thermal/samsung/exynos_tmu_data.h | 7 +++
>>> 3 files changed, 82 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>> index db4035d..a4dbc84 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>> @@ -455,6 +455,10 @@ static const struct of_device_id exynos_tmu_match[] = {
>>> .compatible = "samsung,exynos5250-tmu",
>>> .data = (void *)EXYNOS5250_TMU_DRV_DATA,
>>> },
>>> + {
>>> + .compatible = "samsung,exynos5440-tmu",
>>> + .data = (void *)EXYNOS5440_TMU_DRV_DATA,
>>> + },
>>> {},
>>> };
>>> MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
>>> index 694557e..b34e726 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu_data.c
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.c
>>> @@ -175,3 +175,74 @@ struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
>>> .tmu_count = 1,
>>> };
>>> #endif
>>> +
>>> +#if defined(CONFIG_SOC_EXYNOS5440)
>>> +static const struct exynos_tmu_registers exynos5440_tmu_registers = {
>>> + .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
>>> + .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
>>> + .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
>>> + .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
>>> + .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
>>> + .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
>>> + .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
>>> + .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
>>> + .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
>>> + .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
>>> + .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
>>> + .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
>>> + .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
>>> + .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
>>> + .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
>>> + .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
>>> + .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
>>> + .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
>>> + .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
>>> + .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
>>> + .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
>>> + .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
>>> + .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
>>> + .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
>>> + .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
>>> + .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
>>> + .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
>>> + .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
>>> + .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
>>> + .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
>>> + .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
>>> + .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
>>> + .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
>>> + .tmu_pmin = EXYNOS5440_TMU_PMIN,
>>> +};
>>> +
>>> +#define EXYNOS5440_TMU_DATA \
>>> + .trigger_levels[0] = 100, \
>>> + .trigger_levels[4] = 105, \
>>> + .trigger_enable[0] = 1, \
>>> + .trigger_type[0] = SW_TRIP, \
>>> + .trigger_type[4] = HW_TRIP, \
>>
>> No active / passive cooling?
>>
>>> + .max_trigger_level = 5, \
>>> + .gain = 5, \
>>> + .reference_voltage = 16, \
>>> + .noise_cancel_mode = 4, \
>>> + .cal_type = TYPE_ONE_POINT_TRIMMING, \
>>> + .cal_mode = 0, \
>>> + .efuse_value = 0x5b2d, \
>>> + .min_efuse_value = 16, \
>>> + .max_efuse_value = 76, \
>>> + .first_point_trim = 25, \
>>> + .second_point_trim = 70, \
>>> + .default_temp_offset = 25, \
>>> + .type = SOC_ARCH_EXYNOS5440, \
>>> + .registers = &exynos5440_tmu_registers, \
>>> + .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
>>> + TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
>>
>> No freq table on 5440? hmm.. So no cpufreq_cooling then? Any reason why
>> not? I suppose one of these 3 sensors are on your CPU domain, right?
> In 5440 no cpufreq cooling is needed. Only sw trip and hw trip is sufficient.
Infact all sensors are cpu related at some positions.
>
> Thanks,
> Amit Daniel
>>
>>> +
>>> +struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
>>> + .tmu_data = {
>>> + { EXYNOS5440_TMU_DATA } ,
>>> + { EXYNOS5440_TMU_DATA } ,
>>> + { EXYNOS5440_TMU_DATA } ,
>>> + },
>>> + .tmu_count = 3,
>>> +};
>>> +#endif
>>> diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
>>> index ad263e9..43ce5fb 100644
>>> --- a/drivers/thermal/samsung/exynos_tmu_data.h
>>> +++ b/drivers/thermal/samsung/exynos_tmu_data.h
>>> @@ -143,4 +143,11 @@ extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
>>> #define EXYNOS5250_TMU_DRV_DATA (NULL)
>>> #endif
>>>
>>> +#if defined(CONFIG_SOC_EXYNOS5440)
>>> +extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
>>> +#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
>>> +#else
>>> +#define EXYNOS5440_TMU_DRV_DATA (NULL)
>>> +#endif
>>> +
>>> #endif /*_EXYNOS_TMU_DATA_H*/
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
On Fri, Jun 21, 2013 at 8:01 PM, Eduardo Valentin
<[email protected]> wrote:
> On 20-06-2013 22:01, amit daniel kachhap wrote:
>> Hi Eduardo,
>>
>> On Thu, Jun 20, 2013 at 1:25 AM, Eduardo Valentin
>> <[email protected]> wrote:
>>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>>> This patch adds some extra register bitfield definations and cleans
>>>> up the code to prepare for moving register macros and definations inside
>>>> the TMU data section.
>>>>
>>>> Acked-by: Kukjin Kim <[email protected]>
>>>> Acked-by: Jonghwa Lee <[email protected]>
>>>> Signed-off-by: Amit Daniel Kachhap <[email protected]>
>>>> ---
>>>> drivers/thermal/samsung/exynos_tmu.c | 62 +++++++++++++++++++++++++---------
>>>> 1 files changed, 46 insertions(+), 16 deletions(-)
>>>>
>>>> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
>>>> index 5df04a1..fa33a48 100644
>>>> --- a/drivers/thermal/samsung/exynos_tmu.c
>>>> +++ b/drivers/thermal/samsung/exynos_tmu.c
>>>> @@ -43,9 +43,12 @@
>>>>
>>>> #define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
>>>> #define EXYNOS_TMU_GAIN_SHIFT 8
>>>> +#define EXYNOS_TMU_GAIN_MASK 0xf
>>>> #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
>>>> -#define EXYNOS_TMU_CORE_ON 3
>>>> -#define EXYNOS_TMU_CORE_OFF 2
>>>> +#define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f
>>>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf
>>>> +#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
>>>> +#define EXYNOS_TMU_CORE_EN_SHIFT 0
>>>> #define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
>>>>
>>>> /* Exynos4210 specific registers */
>>>> @@ -63,6 +66,7 @@
>>>> #define EXYNOS4210_TMU_TRIG_LEVEL1_MASK 0x10
>>>> #define EXYNOS4210_TMU_TRIG_LEVEL2_MASK 0x100
>>>> #define EXYNOS4210_TMU_TRIG_LEVEL3_MASK 0x1000
>>>> +#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
>>>> #define EXYNOS4210_TMU_INTCLEAR_VAL 0x1111
>>>>
>>>> /* Exynos5250 and Exynos4412 specific registers */
>>>> @@ -72,17 +76,30 @@
>>>> #define EXYNOS_EMUL_CON 0x80
>>>>
>>>> #define EXYNOS_TRIMINFO_RELOAD 0x1
>>>> +#define EXYNOS_TRIMINFO_SHIFT 0x0
>>>> +#define EXYNOS_TMU_RISE_INT_MASK 0x111
>>>> +#define EXYNOS_TMU_RISE_INT_SHIFT 0
>>>> +#define EXYNOS_TMU_FALL_INT_MASK 0x111
>>>> +#define EXYNOS_TMU_FALL_INT_SHIFT 12
>>>> #define EXYNOS_TMU_CLEAR_RISE_INT 0x111
>>>> #define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
>>>> -#define EXYNOS_MUX_ADDR_VALUE 6
>>>> -#define EXYNOS_MUX_ADDR_SHIFT 20
>>>> #define EXYNOS_TMU_TRIP_MODE_SHIFT 13
>>>> +#define EXYNOS_TMU_TRIP_MODE_MASK 0x7
>>>> +
>>>> +#define EXYNOS_TMU_INTEN_RISE0_SHIFT 0
>>>> +#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4
>>>> +#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8
>>>> +#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12
>>>> +#define EXYNOS_TMU_INTEN_FALL0_SHIFT 16
>>>> +#define EXYNOS_TMU_INTEN_FALL1_SHIFT 20
>>>> +#define EXYNOS_TMU_INTEN_FALL2_SHIFT 24
>>>>
>>>> #define EFUSE_MIN_VALUE 40
>>>> #define EFUSE_MAX_VALUE 100
>>>>
>>>> #ifdef CONFIG_THERMAL_EMULATION
>>>> #define EXYNOS_EMUL_TIME 0x57F0
>>>> +#define EXYNOS_EMUL_TIME_MASK 0xffff
>>>> #define EXYNOS_EMUL_TIME_SHIFT 16
>>>> #define EXYNOS_EMUL_DATA_SHIFT 8
>>>> #define EXYNOS_EMUL_DATA_MASK 0xFF
>>>> @@ -261,24 +278,37 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>>>> mutex_lock(&data->lock);
>>>> clk_enable(data->clk);
>>>>
>>>> - con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
>>>> - pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
>>>> + con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
>>>>
>>>> - if (data->soc == SOC_ARCH_EXYNOS) {
>>>> - con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
>>>> - con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
>>>> + if (pdata->reference_voltage) {
>>>> + con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
>>>> + EXYNOS_TMU_REF_VOLTAGE_SHIFT);
>>>> + con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
>>>> + }
>>>> +
>>>> + if (pdata->gain) {
>>>> + con &= ~(EXYNOS_TMU_GAIN_MASK << EXYNOS_TMU_GAIN_SHIFT);
>>>> + con |= (pdata->gain << EXYNOS_TMU_GAIN_SHIFT);
>>>> + }
>>>> +
>>>> + if (pdata->noise_cancel_mode) {
>>>> + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK <<
>>>> + EXYNOS_TMU_TRIP_MODE_SHIFT);
>>>> + con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT);
>>>> }
>>>>
>>>> if (on) {
>>>> - con |= EXYNOS_TMU_CORE_ON;
>>>
>>>
>>>
>>> Before, in order to turn core on you had:
>>> con = con | 3;
>>>
>>> now you do:
>>> con = con | (1 << 0);
>>>
>>> To me, before you would set bit 1 and 0, now you set bit 0.
>>>
>>>
>>>> - interrupt_en = pdata->trigger_level3_en << 12 |
>>>> - pdata->trigger_level2_en << 8 |
>>>> - pdata->trigger_level1_en << 4 |
>>>> - pdata->trigger_level0_en;
>>>> + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>>> + interrupt_en =
>>>> + pdata->trigger_level3_en << EXYNOS_TMU_INTEN_RISE3_SHIFT |
>>>> + pdata->trigger_level2_en << EXYNOS_TMU_INTEN_RISE2_SHIFT |
>>>> + pdata->trigger_level1_en << EXYNOS_TMU_INTEN_RISE1_SHIFT |
>>>> + pdata->trigger_level0_en << EXYNOS_TMU_INTEN_RISE0_SHIFT;
>>>> if (pdata->threshold_falling)
>>>> - interrupt_en |= interrupt_en << 16;
>>>> + interrupt_en |=
>>>> + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
>>>> } else {
>>>> - con |= EXYNOS_TMU_CORE_OFF;
>>>> + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
>>>
>>>
>>> Before, in order to turno core off you had:
>>> con = con | 2;
>>>
>>> now you do:
>>> con = con & ~(1 << 0);
>>>
>>> To me, before you would set bit 2, now you clear bit 0.
>>>
>>> Using the approach on this patch looks correct to me if you have 1 bit
>>> core_en for instance.
>>>
>>> so, Is this a fix?
>>>
>>> Just to be clear, is this what you want ?
>> Yes you are right. Bit 0 is the actual enable bit. Bit 1 is the
>> reserve bit and its default value is 1. Earlier both bits are used to
>> turn on/off the controller which was wrong so this patch rectifies it.
>
> Care to mention this in your patch description? It is good for code history.
Ok
>
>>
>> Thanks,
>> Amit
>>>
>>>> interrupt_en = 0; /* Disable all interrupts */
>>>> }
>>>> writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
>>>>
>>>
>>>
>>> --
>>> You have got to be excited about what you are doing. (L. Lamport)
>>>
>>> Eduardo Valentin
>>>
>>
>>
>
>
> --
> You have got to be excited about what you are doing. (L. Lamport)
>
> Eduardo Valentin
>