* [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
Changes since V1:
*Moved the sensor driver to driver/thermal folder from driver/hwmon folder
as suggested by Mark Brown and Guenter Roeck
*Added notifier support to notify the registered drivers of any cpu cooling
action. The driver can modify the default cooling behaviour(eg set different
max clip frequency).
*The percentage based frequency replaced with absolute clipped frequency.
*Some more conditional checks when setting max frequency.
*Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
THERMAL_TRIP_STATE_INSTANCE
*Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
eduardo.valentin@ti.com implemented.
*Removed cooling stats through debugfs patch
*The V1 based can be found here,
https://lkml.org/lkml/2012/2/22/123
http://lkml.org/lkml/2012/3/3/32
Changes since RFC:
*Changed the cpu cooling registration/unregistration API's to instance based
*Changed the STATE_ACTIVE trip type to pass correct instance id
*Adding support to restore back the policy->max_freq after doing frequency
clipping.
*Moved the trip cooling stats from sysfs node to debugfs node as suggested
by Greg KH greg@kroah.com
*Incorporated several review comments from eduardo.valentin@ti.com
*Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
*Some changes according to the changes in common cpu cooling APIs
*The RFC based patches can be found here,
https://lkml.org/lkml/2011/12/13/186
https://lkml.org/lkml/2011/12/21/169
Brief Description:
1) The generic cooling devices code is placed inside driver/thermal/* as
placing inside acpi folder will need un-necessary enabling of acpi code. This
codes is architecture independent.
2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
cooling device instance number and may be helpful for cpufreq cooling devices
to take the correct cooling action. This trip type avoids the temperature
comparision check again inside the cooling handler.
3) This patchset adds generic cpu cooling low level implementation through
frequency clipping and cpu hotplug. In future, other cpu related cooling
devices may be added here. An ACPI version of this already exists
(drivers/acpi/processor_thermal.c). But this will be useful for platforms
like ARM using the generic thermal interface along with the generic cpu
cooling devices. The cooling device registration API's return cooling device
pointers which can be easily binded with the thermal zone trip points.
The important APIs exposed are,
a)struct thermal_cooling_device *cpufreq_cooling_register(
struct freq_clip_table *tab_ptr, unsigned int tab_size,
const struct cpumask *mask_val)
b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
4) Samsung exynos platform thermal implementation is done using the generic
cpu cooling APIs and the new trip type. The temperature sensor driver present
in the hwmon folder(registered as hwmon driver) is moved to thermal folder
and registered as a thermal driver.
All this patchset is based on Kernel version 3.3-rc7
A simple data/control flow diagrams is shown below,
Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
| |
\|/ |
Cpufreq cooling device <---------------
Amit Daniel Kachhap (6):
thermal: Add a new trip type to use cooling device instance number
thermal: Add generic cpufreq cooling implementation
thermal: Add generic cpuhotplug cooling implementation
hwmon: exynos4: Move thermal sensor driver to driver/thermal
directory
thermal: exynos4: Register the tmu sensor with the kernel thermal
layer
ARM: exynos4: Add thermal sensor driver platform device support
Documentation/hwmon/exynos4_tmu | 81 ---
Documentation/thermal/cpu-cooling-api.txt | 76 +++
Documentation/thermal/exynos4_tmu | 52 ++
Documentation/thermal/sysfs-api.txt | 4 +-
arch/arm/mach-exynos/Kconfig | 11 +
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 +
arch/arm/mach-exynos/dev-tmu.c | 39 ++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------
drivers/thermal/Kconfig | 21 +
drivers/thermal/Makefile | 2 +
drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
drivers/thermal/thermal_sys.c | 45 ++-
include/linux/cpu_cooling.h | 78 +++
include/linux/platform_data/exynos4_tmu.h | 7 +
include/linux/thermal.h | 1 +
23 files changed, 1660 insertions(+), 611 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 Documentation/thermal/exynos4_tmu
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 drivers/thermal/exynos4_thermal.c
create mode 100644 include/linux/cpu_cooling.h
^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
Changes since V1:
*Moved the sensor driver to driver/thermal folder from driver/hwmon folder
as suggested by Mark Brown and Guenter Roeck
*Added notifier support to notify the registered drivers of any cpu cooling
action. The driver can modify the default cooling behaviour(eg set different
max clip frequency).
*The percentage based frequency replaced with absolute clipped frequency.
*Some more conditional checks when setting max frequency.
*Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
THERMAL_TRIP_STATE_INSTANCE
*Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
eduardo.valentin@ti.com implemented.
*Removed cooling stats through debugfs patch
*The V1 based can be found here,
https://lkml.org/lkml/2012/2/22/123
http://lkml.org/lkml/2012/3/3/32
Changes since RFC:
*Changed the cpu cooling registration/unregistration API's to instance based
*Changed the STATE_ACTIVE trip type to pass correct instance id
*Adding support to restore back the policy->max_freq after doing frequency
clipping.
*Moved the trip cooling stats from sysfs node to debugfs node as suggested
by Greg KH greg@kroah.com
*Incorporated several review comments from eduardo.valentin@ti.com
*Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
*Some changes according to the changes in common cpu cooling APIs
*The RFC based patches can be found here,
https://lkml.org/lkml/2011/12/13/186
https://lkml.org/lkml/2011/12/21/169
Brief Description:
1) The generic cooling devices code is placed inside driver/thermal/* as
placing inside acpi folder will need un-necessary enabling of acpi code. This
codes is architecture independent.
2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
cooling device instance number and may be helpful for cpufreq cooling devices
to take the correct cooling action. This trip type avoids the temperature
comparision check again inside the cooling handler.
3) This patchset adds generic cpu cooling low level implementation through
frequency clipping and cpu hotplug. In future, other cpu related cooling
devices may be added here. An ACPI version of this already exists
(drivers/acpi/processor_thermal.c). But this will be useful for platforms
like ARM using the generic thermal interface along with the generic cpu
cooling devices. The cooling device registration API's return cooling device
pointers which can be easily binded with the thermal zone trip points.
The important APIs exposed are,
a)struct thermal_cooling_device *cpufreq_cooling_register(
struct freq_clip_table *tab_ptr, unsigned int tab_size,
const struct cpumask *mask_val)
b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
4) Samsung exynos platform thermal implementation is done using the generic
cpu cooling APIs and the new trip type. The temperature sensor driver present
in the hwmon folder(registered as hwmon driver) is moved to thermal folder
and registered as a thermal driver.
All this patchset is based on Kernel version 3.3-rc7
A simple data/control flow diagrams is shown below,
Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
| |
\|/ |
Cpufreq cooling device <---------------
Amit Daniel Kachhap (6):
thermal: Add a new trip type to use cooling device instance number
thermal: Add generic cpufreq cooling implementation
thermal: Add generic cpuhotplug cooling implementation
hwmon: exynos4: Move thermal sensor driver to driver/thermal
directory
thermal: exynos4: Register the tmu sensor with the kernel thermal
layer
ARM: exynos4: Add thermal sensor driver platform device support
Documentation/hwmon/exynos4_tmu | 81 ---
Documentation/thermal/cpu-cooling-api.txt | 76 +++
Documentation/thermal/exynos4_tmu | 52 ++
Documentation/thermal/sysfs-api.txt | 4 +-
arch/arm/mach-exynos/Kconfig | 11 +
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 +
arch/arm/mach-exynos/dev-tmu.c | 39 ++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------
drivers/thermal/Kconfig | 21 +
drivers/thermal/Makefile | 2 +
drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
drivers/thermal/thermal_sys.c | 45 ++-
include/linux/cpu_cooling.h | 78 +++
include/linux/platform_data/exynos4_tmu.h | 7 +
include/linux/thermal.h | 1 +
23 files changed, 1660 insertions(+), 611 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 Documentation/thermal/exynos4_tmu
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 drivers/thermal/exynos4_thermal.c
create mode 100644 include/linux/cpu_cooling.h
^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH V2 1/6] thermal: Add a new trip type to use cooling device instance number
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds a new trip type THERMAL_TRIP_STATE_INSTANCE. This
trip behaves same as THERMAL_TRIP_ACTIVE but also passes the cooling
device instance number. This helps the cooling device registered as
different instances to perform appropriate cooling action decision in
the set_cur_state call back function.
Also since the trip temperature's are in ascending order so some logic
is put in place to skip the un-necessary checks.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/sysfs-api.txt | 4 +-
drivers/thermal/thermal_sys.c | 45 ++++++++++++++++++++++++++++++++--
include/linux/thermal.h | 1 +
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 1733ab9..9a7c69c 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -184,8 +184,8 @@ trip_point_[0-*]_temp
trip_point_[0-*]_type
Strings which indicate the type of the trip point.
- E.g. it can be one of critical, hot, passive, active[0-*] for ACPI
- thermal zone.
+ E.g. it can be one of critical, hot, passive, active[0-1],
+ state-instance[0-*] for ACPI thermal zone.
RO, Optional
cdev[0-*]
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 220ce7e..9fc2150 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -192,6 +192,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_STATE_INSTANCE:
+ return sprintf(buf, "state-instance\n");
default:
return sprintf(buf, "unknown\n");
}
@@ -1034,10 +1036,10 @@ EXPORT_SYMBOL(thermal_cooling_device_unregister);
void thermal_zone_device_update(struct thermal_zone_device *tz)
{
- int count, ret = 0;
- long temp, trip_temp;
+ int count, ret = 0, inst_id;
+ long temp, trip_temp, max_state, last_trip_change = 0;
enum thermal_trip_type trip_type;
- struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device_instance *instance, *state_instance;
struct thermal_cooling_device *cdev;
mutex_lock(&tz->lock);
@@ -1086,6 +1088,43 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
cdev->ops->set_cur_state(cdev, 0);
}
break;
+ case THERMAL_TRIP_STATE_INSTANCE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ if (temp <= last_trip_change)
+ continue;
+
+ inst_id = 0;
+ /*
+ *For this instance how many instance of same
+ *cooling device occured before
+ */
+
+ list_for_each_entry(state_instance,
+ &tz->cooling_devices, node) {
+ if (instance->cdev ==
+ state_instance->cdev)
+ inst_id++;
+ if (state_instance->trip == count)
+ break;
+ }
+
+ cdev = instance->cdev;
+ cdev->ops->get_max_state(cdev, &max_state);
+
+ if ((temp >= trip_temp) &&
+ (inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+ else if ((temp < trip_temp) &&
+ (--inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+
+ last_trip_change = trip_temp;
+ }
+ break;
case THERMAL_TRIP_PASSIVE:
if (temp >= trip_temp || tz->passive)
thermal_zone_device_passive(tz, temp,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 796f1ff..583fbda 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -42,6 +42,7 @@ enum thermal_trip_type {
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_STATE_INSTANCE,
};
struct thermal_zone_device_ops {
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 1/6] thermal: Add a new trip type to use cooling device instance number
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This patch adds a new trip type THERMAL_TRIP_STATE_INSTANCE. This
trip behaves same as THERMAL_TRIP_ACTIVE but also passes the cooling
device instance number. This helps the cooling device registered as
different instances to perform appropriate cooling action decision in
the set_cur_state call back function.
Also since the trip temperature's are in ascending order so some logic
is put in place to skip the un-necessary checks.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/sysfs-api.txt | 4 +-
drivers/thermal/thermal_sys.c | 45 ++++++++++++++++++++++++++++++++--
include/linux/thermal.h | 1 +
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 1733ab9..9a7c69c 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -184,8 +184,8 @@ trip_point_[0-*]_temp
trip_point_[0-*]_type
Strings which indicate the type of the trip point.
- E.g. it can be one of critical, hot, passive, active[0-*] for ACPI
- thermal zone.
+ E.g. it can be one of critical, hot, passive, active[0-1],
+ state-instance[0-*] for ACPI thermal zone.
RO, Optional
cdev[0-*]
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 220ce7e..9fc2150 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -192,6 +192,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_STATE_INSTANCE:
+ return sprintf(buf, "state-instance\n");
default:
return sprintf(buf, "unknown\n");
}
@@ -1034,10 +1036,10 @@ EXPORT_SYMBOL(thermal_cooling_device_unregister);
void thermal_zone_device_update(struct thermal_zone_device *tz)
{
- int count, ret = 0;
- long temp, trip_temp;
+ int count, ret = 0, inst_id;
+ long temp, trip_temp, max_state, last_trip_change = 0;
enum thermal_trip_type trip_type;
- struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device_instance *instance, *state_instance;
struct thermal_cooling_device *cdev;
mutex_lock(&tz->lock);
@@ -1086,6 +1088,43 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
cdev->ops->set_cur_state(cdev, 0);
}
break;
+ case THERMAL_TRIP_STATE_INSTANCE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ if (temp <= last_trip_change)
+ continue;
+
+ inst_id = 0;
+ /*
+ *For this instance how many instance of same
+ *cooling device occured before
+ */
+
+ list_for_each_entry(state_instance,
+ &tz->cooling_devices, node) {
+ if (instance->cdev ==
+ state_instance->cdev)
+ inst_id++;
+ if (state_instance->trip == count)
+ break;
+ }
+
+ cdev = instance->cdev;
+ cdev->ops->get_max_state(cdev, &max_state);
+
+ if ((temp >= trip_temp) &&
+ (inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+ else if ((temp < trip_temp) &&
+ (--inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+
+ last_trip_change = trip_temp;
+ }
+ break;
case THERMAL_TRIP_PASSIVE:
if (temp >= trip_temp || tz->passive)
thermal_zone_device_passive(tz, temp,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 796f1ff..583fbda 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -42,6 +42,7 @@ enum thermal_trip_type {
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_STATE_INSTANCE,
};
struct thermal_zone_device_ops {
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 2/6] thermal: Add generic cpufreq cooling implementation
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds support for generic cpu thermal cooling low level
implementations using frequency scaling up/down based on the registration
parameters. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing clipping frequency . The drivers can also register to recieve
notification about any cooling action called. Even the driver can effect
the cooling action by modifying the default data such as freq_clip_max if
needed.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 60 +++++
drivers/thermal/Kconfig | 11 +
drivers/thermal/Makefile | 1 +
drivers/thermal/cpu_cooling.c | 359 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 61 +++++
5 files changed, 492 insertions(+), 0 deletions(-)
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 include/linux/cpu_cooling.h
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
new file mode 100644
index 0000000..3720341
--- /dev/null
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -0,0 +1,60 @@
+CPU cooling APIs How To
+===================================
+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 9 March 2012
+
+Copyright (c) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+
+The generic cpu cooling(freq clipping, cpuhotplug) provides
+registration/unregistration APIs to the caller. The binding of the cooling
+devices to the trip point is left for the user. The registration APIs returns
+the cooling device pointer.
+
+1. cpu cooling APIs
+
+1.1 cpufreq registration/unregistration APIs
+1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpufreq cooling device with the name
+ "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+ cooling devices.
+
+ tab_ptr: The table containing the maximum value of frequency to be clipped
+ for each cooling state.
+ .freq_clip_max: Value of frequency to be clipped for each allowed
+ cpus.
+ tab_size: the total number of cpufreq cooling states.
+ mask_val: all the allowed cpu's where frequency clipping can happen.
+
+1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+ cdev: Cooling device pointer which has to be unregistered.
+
+
+2. CPU cooling action notifier interface
+
+2.1 int cputherm_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
+
+2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f7f71b2..df738f2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -18,3 +18,14 @@ config THERMAL_HWMON
depends on THERMAL
depends on HWMON=y || HWMON=THERMAL
default y
+
+config CPU_THERMAL
+ bool "generic cpu cooling support"
+ depends on THERMAL && CPU_FREQ
+ help
+ This implements the generic cpu cooling mechanism through frequency
+ reduction, cpu hotplug and any other ways of reducing temperature. An
+ ACPI version of this already exists(drivers/acpi/processor_thermal.c).
+ This will be useful for platforms using the generic thermal interface
+ and not the ACPI interface.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31108a0..655cbc4 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
+obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
new file mode 100644
index 0000000..ee2c96d
--- /dev/null
+++ b/drivers/thermal/cpu_cooling.c
@@ -0,0 +1,359 @@
+/*
+ * linux/drivers/thermal/cpu_cooling.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/cpu_cooling.h>
+
+struct cpufreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ struct freq_clip_table *tab_ptr;
+ unsigned int tab_size;
+ unsigned int cpufreq_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpufreq_list);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
+static DEFINE_IDR(cpufreq_idr);
+static DEFINE_PER_CPU(unsigned int, max_policy_freq);
+static struct freq_clip_table *notify_table;
+static int notify_state;
+static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+ int err;
+again:
+ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+ return -ENOMEM;
+
+ if (lock)
+ mutex_lock(lock);
+ err = idr_get_new(idr, NULL, id);
+ if (lock)
+ mutex_unlock(lock);
+ if (unlikely(err == -EAGAIN))
+ goto again;
+ else if (unlikely(err))
+ return err;
+
+ *id = *id & MAX_ID_MASK;
+ return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+ if (lock)
+ mutex_lock(lock);
+ idr_remove(idr, id);
+ if (lock)
+ mutex_unlock(lock);
+}
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_register(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_register_notifier);
+
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_unregister(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_unregister_notifier);
+
+/*Below codes defines functions to be used for cpufreq as cooling device*/
+static bool is_cpufreq_valid(int cpu)
+{
+ struct cpufreq_policy policy;
+ return !cpufreq_get_policy(&policy, cpu) ? true : false;
+}
+
+static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+ unsigned long cooling_state)
+{
+ unsigned int event, cpuid;
+ struct freq_clip_table *th_table;
+
+ if (cooling_state > cpufreq_device->tab_size)
+ return -EINVAL;
+
+ cpufreq_device->cpufreq_state = cooling_state;
+
+ /*cpufreq thermal notifier uses this cpufreq device pointer*/
+ notify_state = cooling_state;
+
+ if (notify_state > 0) {
+ th_table = &(cpufreq_device->tab_ptr[cooling_state - 1]);
+ memcpy(notify_table, th_table, sizeof(struct freq_clip_table));
+ event = CPUFREQ_COOLING_TYPE;
+ blocking_notifier_call_chain(&cputherm_state_notifier_list,
+ event, notify_table);
+ }
+
+ for_each_cpu(cpuid, cpufreq_device->allowed_cpus) {
+ if (is_cpufreq_valid(cpuid))
+ cpufreq_update_policy(cpuid);
+ }
+
+ notify_state = -1;
+
+ return 0;
+}
+
+static int cpufreq_thermal_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned long max_freq = 0;
+
+ if ((event != CPUFREQ_ADJUST) || (notify_state == -1))
+ return 0;
+
+ if (notify_state > 0) {
+ max_freq = notify_table->freq_clip_max;
+
+ if (per_cpu(max_policy_freq, policy->cpu) == 0)
+ per_cpu(max_policy_freq, policy->cpu) = policy->max;
+ } else {
+ if (per_cpu(max_policy_freq, policy->cpu) != 0) {
+ max_freq = per_cpu(max_policy_freq, policy->cpu);
+ per_cpu(max_policy_freq, policy->cpu) = 0;
+ } else {
+ max_freq = policy->max;
+ }
+ }
+
+ /* Never exceed user_policy.max*/
+ if (max_freq > policy->user_policy.max)
+ max_freq = policy->user_policy.max;
+
+ if (policy->max != max_freq)
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+
+ return 0;
+}
+
+/*
+ * cpufreq cooling device callback functions
+ */
+static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->tab_size;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->cpufreq_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+/*This cooling may be as PASSIVE/ACTIVE type*/
+static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ if (!ret)
+ ret = cpufreq_apply_cooling(cpufreq_device, state);
+
+ return ret;
+}
+
+/* bind cpufreq callbacks to cpufreq cooling device */
+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+ .get_max_state = cpufreq_get_max_state,
+ .get_cur_state = cpufreq_get_cur_state,
+ .set_cur_state = cpufreq_set_cur_state,
+};
+
+static struct notifier_block thermal_cpufreq_notifier_block = {
+ .notifier_call = cpufreq_thermal_notifier,
+};
+
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0, id = 0, i;
+
+ if (tab_ptr == NULL || tab_size == 0)
+ return ERR_PTR(-EINVAL);
+
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
+ cpufreq_dev_count++;
+
+ cpufreq_dev =
+ kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL);
+
+ if (!cpufreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (cpufreq_dev_count == 0) {
+ notify_table = kzalloc(sizeof(struct freq_clip_table),
+ GFP_KERNEL);
+ if (!notify_table) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ cpufreq_dev->tab_ptr = tab_ptr;
+ cpufreq_dev->tab_size = tab_size;
+ cpufreq_dev->allowed_cpus = mask_val;
+
+ /* Initialize all the tab_ptr->mask_val to the passed mask_val */
+ for (i = 0; i < tab_size; i++)
+ ((struct freq_clip_table *)&tab_ptr[i])->mask_val = mask_val;
+
+ ret = get_idr(&cpufreq_idr, &cooling_cpufreq_lock, &cpufreq_dev->id);
+ if (ret) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
+ &cpufreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock,
+ cpufreq_dev->id);
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ cpufreq_dev->id = id;
+ cpufreq_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpufreq_lock);
+ list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Register the notifier for first cpufreq cooling device*/
+ if (cpufreq_dev_count == 0)
+ cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpufreq_cooling_register);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
+ if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
+ break;
+ cpufreq_dev_count++;
+ }
+
+ if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpufreq_lock);
+ return;
+ }
+
+ list_del(&cpufreq_dev->node);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Unregister the notifier for the last cpufreq cooling device*/
+ if (cpufreq_dev_count == 1) {
+ cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ kfree(notify_table);
+ }
+
+ thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock, cpufreq_dev->id);
+ kfree(cpufreq_dev);
+}
+EXPORT_SYMBOL(cpufreq_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
new file mode 100644
index 0000000..12efa01
--- /dev/null
+++ b/include/linux/cpu_cooling.h
@@ -0,0 +1,61 @@
+/*
+ * linux/include/linux/cpu_cooling.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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 __CPU_COOLING_H__
+#define __CPU_COOLING_H__
+
+#include <linux/thermal.h>
+
+#define CPUFREQ_COOLING_TYPE 0
+#define CPUHOTPLUG_COOLING_TYPE 1
+
+struct freq_clip_table {
+ unsigned int freq_clip_max;
+ unsigned int temp_level;
+ const struct cpumask *mask_val;
+};
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list);
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#ifdef CONFIG_CPU_FREQ
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_CPU_FREQ*/
+static inline struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpufreq_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_CPU_FREQ*/
+
+#endif /* __CPU_COOLING_H__ */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 2/6] thermal: Add generic cpufreq cooling implementation
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This patch adds support for generic cpu thermal cooling low level
implementations using frequency scaling up/down based on the registration
parameters. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing clipping frequency . The drivers can also register to recieve
notification about any cooling action called. Even the driver can effect
the cooling action by modifying the default data such as freq_clip_max if
needed.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 60 +++++
drivers/thermal/Kconfig | 11 +
drivers/thermal/Makefile | 1 +
drivers/thermal/cpu_cooling.c | 359 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 61 +++++
5 files changed, 492 insertions(+), 0 deletions(-)
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 include/linux/cpu_cooling.h
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
new file mode 100644
index 0000000..3720341
--- /dev/null
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -0,0 +1,60 @@
+CPU cooling APIs How To
+===================================
+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 9 March 2012
+
+Copyright (c) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+
+The generic cpu cooling(freq clipping, cpuhotplug) provides
+registration/unregistration APIs to the caller. The binding of the cooling
+devices to the trip point is left for the user. The registration APIs returns
+the cooling device pointer.
+
+1. cpu cooling APIs
+
+1.1 cpufreq registration/unregistration APIs
+1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpufreq cooling device with the name
+ "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+ cooling devices.
+
+ tab_ptr: The table containing the maximum value of frequency to be clipped
+ for each cooling state.
+ .freq_clip_max: Value of frequency to be clipped for each allowed
+ cpus.
+ tab_size: the total number of cpufreq cooling states.
+ mask_val: all the allowed cpu's where frequency clipping can happen.
+
+1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+ cdev: Cooling device pointer which has to be unregistered.
+
+
+2. CPU cooling action notifier interface
+
+2.1 int cputherm_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
+
+2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f7f71b2..df738f2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -18,3 +18,14 @@ config THERMAL_HWMON
depends on THERMAL
depends on HWMON=y || HWMON=THERMAL
default y
+
+config CPU_THERMAL
+ bool "generic cpu cooling support"
+ depends on THERMAL && CPU_FREQ
+ help
+ This implements the generic cpu cooling mechanism through frequency
+ reduction, cpu hotplug and any other ways of reducing temperature. An
+ ACPI version of this already exists(drivers/acpi/processor_thermal.c).
+ This will be useful for platforms using the generic thermal interface
+ and not the ACPI interface.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31108a0..655cbc4 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
+obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
new file mode 100644
index 0000000..ee2c96d
--- /dev/null
+++ b/drivers/thermal/cpu_cooling.c
@@ -0,0 +1,359 @@
+/*
+ * linux/drivers/thermal/cpu_cooling.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/cpu_cooling.h>
+
+struct cpufreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ struct freq_clip_table *tab_ptr;
+ unsigned int tab_size;
+ unsigned int cpufreq_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpufreq_list);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
+static DEFINE_IDR(cpufreq_idr);
+static DEFINE_PER_CPU(unsigned int, max_policy_freq);
+static struct freq_clip_table *notify_table;
+static int notify_state;
+static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+ int err;
+again:
+ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+ return -ENOMEM;
+
+ if (lock)
+ mutex_lock(lock);
+ err = idr_get_new(idr, NULL, id);
+ if (lock)
+ mutex_unlock(lock);
+ if (unlikely(err == -EAGAIN))
+ goto again;
+ else if (unlikely(err))
+ return err;
+
+ *id = *id & MAX_ID_MASK;
+ return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+ if (lock)
+ mutex_lock(lock);
+ idr_remove(idr, id);
+ if (lock)
+ mutex_unlock(lock);
+}
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_register(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_register_notifier);
+
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_unregister(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_unregister_notifier);
+
+/*Below codes defines functions to be used for cpufreq as cooling device*/
+static bool is_cpufreq_valid(int cpu)
+{
+ struct cpufreq_policy policy;
+ return !cpufreq_get_policy(&policy, cpu) ? true : false;
+}
+
+static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+ unsigned long cooling_state)
+{
+ unsigned int event, cpuid;
+ struct freq_clip_table *th_table;
+
+ if (cooling_state > cpufreq_device->tab_size)
+ return -EINVAL;
+
+ cpufreq_device->cpufreq_state = cooling_state;
+
+ /*cpufreq thermal notifier uses this cpufreq device pointer*/
+ notify_state = cooling_state;
+
+ if (notify_state > 0) {
+ th_table = &(cpufreq_device->tab_ptr[cooling_state - 1]);
+ memcpy(notify_table, th_table, sizeof(struct freq_clip_table));
+ event = CPUFREQ_COOLING_TYPE;
+ blocking_notifier_call_chain(&cputherm_state_notifier_list,
+ event, notify_table);
+ }
+
+ for_each_cpu(cpuid, cpufreq_device->allowed_cpus) {
+ if (is_cpufreq_valid(cpuid))
+ cpufreq_update_policy(cpuid);
+ }
+
+ notify_state = -1;
+
+ return 0;
+}
+
+static int cpufreq_thermal_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned long max_freq = 0;
+
+ if ((event != CPUFREQ_ADJUST) || (notify_state == -1))
+ return 0;
+
+ if (notify_state > 0) {
+ max_freq = notify_table->freq_clip_max;
+
+ if (per_cpu(max_policy_freq, policy->cpu) == 0)
+ per_cpu(max_policy_freq, policy->cpu) = policy->max;
+ } else {
+ if (per_cpu(max_policy_freq, policy->cpu) != 0) {
+ max_freq = per_cpu(max_policy_freq, policy->cpu);
+ per_cpu(max_policy_freq, policy->cpu) = 0;
+ } else {
+ max_freq = policy->max;
+ }
+ }
+
+ /* Never exceed user_policy.max*/
+ if (max_freq > policy->user_policy.max)
+ max_freq = policy->user_policy.max;
+
+ if (policy->max != max_freq)
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+
+ return 0;
+}
+
+/*
+ * cpufreq cooling device callback functions
+ */
+static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->tab_size;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->cpufreq_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+/*This cooling may be as PASSIVE/ACTIVE type*/
+static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ if (!ret)
+ ret = cpufreq_apply_cooling(cpufreq_device, state);
+
+ return ret;
+}
+
+/* bind cpufreq callbacks to cpufreq cooling device */
+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+ .get_max_state = cpufreq_get_max_state,
+ .get_cur_state = cpufreq_get_cur_state,
+ .set_cur_state = cpufreq_set_cur_state,
+};
+
+static struct notifier_block thermal_cpufreq_notifier_block = {
+ .notifier_call = cpufreq_thermal_notifier,
+};
+
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0, id = 0, i;
+
+ if (tab_ptr == NULL || tab_size == 0)
+ return ERR_PTR(-EINVAL);
+
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
+ cpufreq_dev_count++;
+
+ cpufreq_dev =
+ kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL);
+
+ if (!cpufreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (cpufreq_dev_count == 0) {
+ notify_table = kzalloc(sizeof(struct freq_clip_table),
+ GFP_KERNEL);
+ if (!notify_table) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ cpufreq_dev->tab_ptr = tab_ptr;
+ cpufreq_dev->tab_size = tab_size;
+ cpufreq_dev->allowed_cpus = mask_val;
+
+ /* Initialize all the tab_ptr->mask_val to the passed mask_val */
+ for (i = 0; i < tab_size; i++)
+ ((struct freq_clip_table *)&tab_ptr[i])->mask_val = mask_val;
+
+ ret = get_idr(&cpufreq_idr, &cooling_cpufreq_lock, &cpufreq_dev->id);
+ if (ret) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
+ &cpufreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock,
+ cpufreq_dev->id);
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ cpufreq_dev->id = id;
+ cpufreq_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpufreq_lock);
+ list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Register the notifier for first cpufreq cooling device*/
+ if (cpufreq_dev_count == 0)
+ cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpufreq_cooling_register);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
+ if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
+ break;
+ cpufreq_dev_count++;
+ }
+
+ if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpufreq_lock);
+ return;
+ }
+
+ list_del(&cpufreq_dev->node);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Unregister the notifier for the last cpufreq cooling device*/
+ if (cpufreq_dev_count == 1) {
+ cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ kfree(notify_table);
+ }
+
+ thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock, cpufreq_dev->id);
+ kfree(cpufreq_dev);
+}
+EXPORT_SYMBOL(cpufreq_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
new file mode 100644
index 0000000..12efa01
--- /dev/null
+++ b/include/linux/cpu_cooling.h
@@ -0,0 +1,61 @@
+/*
+ * linux/include/linux/cpu_cooling.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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 __CPU_COOLING_H__
+#define __CPU_COOLING_H__
+
+#include <linux/thermal.h>
+
+#define CPUFREQ_COOLING_TYPE 0
+#define CPUHOTPLUG_COOLING_TYPE 1
+
+struct freq_clip_table {
+ unsigned int freq_clip_max;
+ unsigned int temp_level;
+ const struct cpumask *mask_val;
+};
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list);
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#ifdef CONFIG_CPU_FREQ
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_CPU_FREQ*/
+static inline struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpufreq_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_CPU_FREQ*/
+
+#endif /* __CPU_COOLING_H__ */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds support for generic cpu thermal cooling low level
implementations using cpuhotplug based on the thermal level requested
from user. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing the cpumask.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 16 +++
drivers/thermal/Kconfig | 2 +-
drivers/thermal/cpu_cooling.c | 170 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 17 +++
4 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
index 3720341..6eb648e 100644
--- a/Documentation/thermal/cpu-cooling-api.txt
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -38,6 +38,22 @@ the cooling device pointer.
cdev: Cooling device pointer which has to be unregistered.
+1.2 cpuhotplug registration APIs
+1.2.1 struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpuhotplug cooling device with the name
+ "cpu-hotplug-%x". This api can support multiple instances of cpuhotplug
+ cooling devices.
+
+ mask_val: all the allowed cpu's which can be hotplugged out.
+
+1.1.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpuhotplug-%x" cooling
+ device.
+
+ cdev: Cooling device pointer which has to be unregistered.
2. CPU cooling action notifier interface
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index df738f2..24c43e3 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -21,7 +21,7 @@ config THERMAL_HWMON
config CPU_THERMAL
bool "generic cpu cooling support"
- depends on THERMAL && CPU_FREQ
+ depends on THERMAL && CPU_FREQ && HOTPLUG_CPU
help
This implements the generic cpu cooling mechanism through frequency
reduction, cpu hotplug and any other ways of reducing temperature. An
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index ee2c96d..1f3aa79 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -46,6 +46,19 @@ static DEFINE_IDR(cpufreq_idr);
static DEFINE_PER_CPU(unsigned int, max_policy_freq);
static struct freq_clip_table *notify_table;
static int notify_state;
+
+struct hotplug_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int hotplug_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpuhotplug_list);
+static DEFINE_MUTEX(cooling_cpuhotplug_lock);
+static DEFINE_IDR(cpuhotplug_idr);
+
static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
@@ -357,3 +370,160 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
kfree(cpufreq_dev);
}
EXPORT_SYMBOL(cpufreq_cooling_unregister);
+
+/*
+ * cpu hotplug cooling device callback functions
+ */
+static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = 1;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = hotplug_dev->hotplug_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+/*This cooling may be as ACTIVE type*/
+static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int cpuid, this_cpu = smp_processor_id();
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
+ return -EINVAL;
+
+ if (hotplug_dev->hotplug_state == state)
+ return 0;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ if (state == 1) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_down(cpuid);
+ }
+ } else if (state == 0) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (!cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_up(cpuid);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ hotplug_dev->hotplug_state = state;
+
+ return 0;
+}
+/* bind hotplug callbacks to cpu hotplug cooling device */
+static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
+ .get_max_state = cpuhotplug_get_max_state,
+ .get_cur_state = cpuhotplug_get_cur_state,
+ .set_cur_state = cpuhotplug_set_cur_state,
+};
+
+struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct hotplug_cooling_device *hotplug_dev;
+ int ret = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+
+ hotplug_dev =
+ kzalloc(sizeof(struct hotplug_cooling_device), GFP_KERNEL);
+
+ if (!hotplug_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ &hotplug_dev->id);
+ if (ret) {
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "cpu-hotplug-%u", hotplug_dev->id);
+
+ hotplug_dev->hotplug_state = 0;
+ hotplug_dev->allowed_cpus = mask_val;
+ cool_dev = thermal_cooling_device_register(dev_name, hotplug_dev,
+ &cpuhotplug_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ hotplug_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_add_tail(&hotplug_dev->node, &cooling_cpuhotplug_list);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_register);
+
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct hotplug_cooling_device *hotplug_dev = NULL;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return;
+ }
+
+ list_del(&hotplug_dev->node);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ thermal_cooling_device_unregister(hotplug_dev->cool_dev);
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 12efa01..5a3698c 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -57,5 +57,22 @@ static inline void cpufreq_cooling_unregister(
return;
}
#endif /*CONFIG_CPU_FREQ*/
+#ifdef CONFIG_HOTPLUG_CPU
+extern struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val);
+
+extern void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_HOTPLUG_CPU*/
+static inline struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpuhotplug_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_HOTPLUG_CPU*/
#endif /* __CPU_COOLING_H__ */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This patch adds support for generic cpu thermal cooling low level
implementations using cpuhotplug based on the thermal level requested
from user. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing the cpumask.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 16 +++
drivers/thermal/Kconfig | 2 +-
drivers/thermal/cpu_cooling.c | 170 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 17 +++
4 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
index 3720341..6eb648e 100644
--- a/Documentation/thermal/cpu-cooling-api.txt
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -38,6 +38,22 @@ the cooling device pointer.
cdev: Cooling device pointer which has to be unregistered.
+1.2 cpuhotplug registration APIs
+1.2.1 struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpuhotplug cooling device with the name
+ "cpu-hotplug-%x". This api can support multiple instances of cpuhotplug
+ cooling devices.
+
+ mask_val: all the allowed cpu's which can be hotplugged out.
+
+1.1.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpuhotplug-%x" cooling
+ device.
+
+ cdev: Cooling device pointer which has to be unregistered.
2. CPU cooling action notifier interface
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index df738f2..24c43e3 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -21,7 +21,7 @@ config THERMAL_HWMON
config CPU_THERMAL
bool "generic cpu cooling support"
- depends on THERMAL && CPU_FREQ
+ depends on THERMAL && CPU_FREQ && HOTPLUG_CPU
help
This implements the generic cpu cooling mechanism through frequency
reduction, cpu hotplug and any other ways of reducing temperature. An
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index ee2c96d..1f3aa79 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -46,6 +46,19 @@ static DEFINE_IDR(cpufreq_idr);
static DEFINE_PER_CPU(unsigned int, max_policy_freq);
static struct freq_clip_table *notify_table;
static int notify_state;
+
+struct hotplug_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int hotplug_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpuhotplug_list);
+static DEFINE_MUTEX(cooling_cpuhotplug_lock);
+static DEFINE_IDR(cpuhotplug_idr);
+
static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
@@ -357,3 +370,160 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
kfree(cpufreq_dev);
}
EXPORT_SYMBOL(cpufreq_cooling_unregister);
+
+/*
+ * cpu hotplug cooling device callback functions
+ */
+static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = 1;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = hotplug_dev->hotplug_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+/*This cooling may be as ACTIVE type*/
+static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int cpuid, this_cpu = smp_processor_id();
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
+ return -EINVAL;
+
+ if (hotplug_dev->hotplug_state == state)
+ return 0;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ if (state == 1) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_down(cpuid);
+ }
+ } else if (state == 0) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (!cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_up(cpuid);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ hotplug_dev->hotplug_state = state;
+
+ return 0;
+}
+/* bind hotplug callbacks to cpu hotplug cooling device */
+static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
+ .get_max_state = cpuhotplug_get_max_state,
+ .get_cur_state = cpuhotplug_get_cur_state,
+ .set_cur_state = cpuhotplug_set_cur_state,
+};
+
+struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct hotplug_cooling_device *hotplug_dev;
+ int ret = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+
+ hotplug_dev =
+ kzalloc(sizeof(struct hotplug_cooling_device), GFP_KERNEL);
+
+ if (!hotplug_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ &hotplug_dev->id);
+ if (ret) {
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "cpu-hotplug-%u", hotplug_dev->id);
+
+ hotplug_dev->hotplug_state = 0;
+ hotplug_dev->allowed_cpus = mask_val;
+ cool_dev = thermal_cooling_device_register(dev_name, hotplug_dev,
+ &cpuhotplug_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ hotplug_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_add_tail(&hotplug_dev->node, &cooling_cpuhotplug_list);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_register);
+
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct hotplug_cooling_device *hotplug_dev = NULL;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return;
+ }
+
+ list_del(&hotplug_dev->node);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ thermal_cooling_device_unregister(hotplug_dev->cool_dev);
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 12efa01..5a3698c 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -57,5 +57,22 @@ static inline void cpufreq_cooling_unregister(
return;
}
#endif /*CONFIG_CPU_FREQ*/
+#ifdef CONFIG_HOTPLUG_CPU
+extern struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val);
+
+extern void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_HOTPLUG_CPU*/
+static inline struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpuhotplug_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_HOTPLUG_CPU*/
#endif /* __CPU_COOLING_H__ */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 4/6] hwmon: exynos4: Move thermal sensor driver to driver/thermal directory
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This movement is needed because the hwmon entries and corresponding
sysfs interface is a duplicate of utilities already provided by
driver/thermal/thermal_sys.c. The goal is to place it in thermal folder
and add necessary functions to use the in-kernel thermal interfaces.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
---
Documentation/hwmon/exynos4_tmu | 81 ------
Documentation/thermal/exynos4_tmu | 52 ++++
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------------------------
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 1 +
drivers/thermal/exynos4_thermal.c | 409 +++++++++++++++++++++++++++++
8 files changed, 472 insertions(+), 606 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/exynos4_tmu
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/exynos4_thermal.c
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu
deleted file mode 100644
index c3c6b41..0000000
--- a/Documentation/hwmon/exynos4_tmu
+++ /dev/null
@@ -1,81 +0,0 @@
-Kernel driver exynos4_tmu
-=================
-
-Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
- Prefix: 'exynos4-tmu'
- Datasheet: Not publicly available
-
-Authors: Donggeun Kim <dg77.kim@samsung.com>
-
-Description
------------
-
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
-
-The chip only exposes the measured 8-bit temperature code value
-through a register.
-Temperature can be taken from the temperature code.
-There are three equations converting from temperature to temperature code.
-
-The three equations are:
- 1. Two point trimming
- Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
-
- 2. One point trimming
- Tc = T + TI1 - 25
-
- 3. No trimming
- Tc = T + 50
-
- Tc: Temperature code, T: Temperature,
- TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
- Temperature code measured at 25 degree Celsius which is unchanged
- 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
-when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
-The threshold levels are defined as follows:
- Level_0: current temperature > trigger_level_0 + threshold
- Level_1: current temperature > trigger_level_1 + threshold
- Level_2: current temperature > trigger_level_2 + threshold
- Level_3: current temperature > trigger_level_3 + threshold
-
- The threshold and each trigger_level are set
- through the corresponding registers.
-
-When an interrupt occurs, this driver notify user space of
-one of four threshold levels for the interrupt
-through kobject_uevent_env and sysfs_notify functions.
-Although an interrupt condition for level_0 can be set,
-it is not notified to user space through sysfs_notify function.
-
-Sysfs Interface
----------------
-name name of the temperature sensor
- RO
-
-temp1_input temperature
- RO
-
-temp1_max temperature for level_1 interrupt
- RO
-
-temp1_crit temperature for level_2 interrupt
- RO
-
-temp1_emergency temperature for level_3 interrupt
- RO
-
-temp1_max_alarm alarm for level_1 interrupt
- RO
-
-temp1_crit_alarm
- alarm for level_2 interrupt
- RO
-
-temp1_emergency_alarm
- alarm for level_3 interrupt
- RO
diff --git a/Documentation/thermal/exynos4_tmu b/Documentation/thermal/exynos4_tmu
new file mode 100644
index 0000000..2b46f67
--- /dev/null
+++ b/Documentation/thermal/exynos4_tmu
@@ -0,0 +1,52 @@
+Kernel driver exynos4_tmu
+=================
+
+Supported chips:
+* ARM SAMSUNG EXYNOS4 series of SoC
+ Prefix: 'exynos4-tmu'
+ Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+
+Description
+-----------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+ 1. Two point trimming
+ Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+ 2. One point trimming
+ Tc = T + TI1 - 25
+
+ 3. No trimming
+ Tc = T + 50
+
+ Tc: Temperature code, T: Temperature,
+ TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+ Temperature code measured at 25 degree Celsius which is unchanged
+ 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
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is four.
+The threshold levels are defined as follows:
+ Level_0: current temperature > trigger_level_0 + threshold
+ Level_1: current temperature > trigger_level_1 + threshold
+ Level_2: current temperature > trigger_level_2 + threshold
+ Level_3: current temperature > trigger_level_3 + threshold
+
+ The threshold and each trigger_level are set
+ through the corresponding registers.
+
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos4_report_trigger.
+Although an interrupt condition for level_0 can be set,
+it can be used to synchronize the cooling action.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index dad895f..5a29885 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -313,16 +313,6 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
-config SENSORS_EXYNOS4_TMU
- tristate "Temperature sensor on Samsung EXYNOS4"
- depends on ARCH_EXYNOS4
- help
- If you say yes here you get support for TMU (Thermal Managment
- Unit) on SAMSUNG EXYNOS4 series of SoC.
-
- This driver can also be built as a module. If so, the module
- will be called exynos4-tmu.
-
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..228a4b7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
-obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c
deleted file mode 100644
index f2359a0..0000000
--- a/drivers/hwmon/exynos4_tmu.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
- *
- * Copyright (C) 2011 Samsung Electronics
- * Donggeun Kim <dg77.kim@samsung.com>
- *
- * 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/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/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
-#include <linux/platform_data/exynos4_tmu.h>
-
-#define EXYNOS4_TMU_REG_TRIMINFO 0x0
-#define EXYNOS4_TMU_REG_CONTROL 0x20
-#define EXYNOS4_TMU_REG_STATUS 0x28
-#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
-#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
-#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
-#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
-#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
-#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
-#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
-#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
-#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
-#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
-#define EXYNOS4_TMU_REG_INTEN 0x70
-#define EXYNOS4_TMU_REG_INTSTAT 0x74
-#define EXYNOS4_TMU_REG_INTCLEAR 0x78
-
-#define EXYNOS4_TMU_GAIN_SHIFT 8
-#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
-
-#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
-#define EXYNOS4_TMU_CORE_ON 3
-#define EXYNOS4_TMU_CORE_OFF 2
-#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
-#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
-#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
-#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
-#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
-#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
-
-struct exynos4_tmu_data {
- struct exynos4_tmu_platform_data *pdata;
- struct device *hwmon_dev;
- struct resource *mem;
- void __iomem *base;
- int irq;
- struct work_struct irq_work;
- struct mutex lock;
- struct clk *clk;
- u8 temp_error1, temp_error2;
-};
-
-/*
- * TMU treats temperature as a mapped temperature code.
- * The temperature is converted differently depending on the calibration type.
- */
-static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp_code;
-
- /* temp should range between 25 and 125 */
- if (temp < 25 || temp > 125) {
- temp_code = -EINVAL;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp_code = (temp - 25) *
- (data->temp_error2 - data->temp_error1) /
- (85 - 25) + data->temp_error1;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp_code = temp + data->temp_error1 - 25;
- break;
- default:
- temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp_code;
-}
-
-/*
- * Calculate a temperature value from a temperature code.
- * The unit of the temperature is degree Celsius.
- */
-static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
-
- /* temp_code should range between 75 and 175 */
- if (temp_code < 75 || temp_code > 175) {
- temp = -ENODATA;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp = (temp_code - data->temp_error1) * (85 - 25) /
- (data->temp_error2 - data->temp_error1) + 25;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp = temp_code - data->temp_error1 + 25;
- break;
- default:
- temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp;
-}
-
-static int exynos4_tmu_initialize(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int status, trim_info;
- int ret = 0, threshold_code;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
- if (!status) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Save trimming info in order to perform calibration */
- trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
- data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
- data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
-
- /* Write temperature code for threshold */
- threshold_code = temp_to_code(data, pdata->threshold);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
- }
- writeb(threshold_code,
- data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
-
- writeb(pdata->trigger_levels[0],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
- writeb(pdata->trigger_levels[1],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
- writeb(pdata->trigger_levels[2],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
- writeb(pdata->trigger_levels[3],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL,
- data->base + EXYNOS4_TMU_REG_INTCLEAR);
-out:
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return ret;
-}
-
-static void exynos4_tmu_control(struct platform_device *pdev, bool on)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int con, interrupt_en;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
- pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
- if (on) {
- con |= EXYNOS4_TMU_CORE_ON;
- interrupt_en = pdata->trigger_level3_en << 12 |
- pdata->trigger_level2_en << 8 |
- pdata->trigger_level1_en << 4 |
- pdata->trigger_level0_en;
- } else {
- con |= EXYNOS4_TMU_CORE_OFF;
- interrupt_en = 0; /* Disable all interrupts */
- }
- writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
- writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static int exynos4_tmu_read(struct exynos4_tmu_data *data)
-{
- u8 temp_code;
- int temp;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
- temp = code_to_temp(data, temp_code);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return temp;
-}
-
-static void exynos4_tmu_work(struct work_struct *work)
-{
- struct exynos4_tmu_data *data = container_of(work,
- struct exynos4_tmu_data, irq_work);
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
-
- kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
-
- enable_irq(data->irq);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static irqreturn_t exynos4_tmu_irq(int irq, void *id)
-{
- struct exynos4_tmu_data *data = id;
-
- disable_irq_nosync(irq);
- schedule_work(&data->irq_work);
-
- return IRQ_HANDLED;
-}
-
-static ssize_t exynos4_tmu_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "exynos4-tmu\n");
-}
-
-static ssize_t exynos4_tmu_show_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- int ret;
-
- ret = exynos4_tmu_read(data);
- if (ret < 0)
- return ret;
-
- /* convert from degree Celsius to millidegree Celsius */
- return sprintf(buf, "%d\n", ret * 1000);
-}
-
-static ssize_t exynos4_tmu_show_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
- unsigned int trigger_level;
-
- temp = exynos4_tmu_read(data);
- if (temp < 0)
- return temp;
-
- trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%d\n", !!(temp > trigger_level));
-}
-
-static ssize_t exynos4_tmu_show_level(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int temp = pdata->threshold +
- pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%u\n", temp * 1000);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
-
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
- exynos4_tmu_show_level, NULL, 3);
-
-static struct attribute *exynos4_tmu_attributes[] = {
- &dev_attr_name.attr,
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group exynos4_tmu_attr_group = {
- .attrs = exynos4_tmu_attributes,
-};
-
-static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data;
- struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform init data supplied.\n");
- return -ENODEV;
- }
-
- data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "Failed to allocate driver structure\n");
- return -ENOMEM;
- }
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0) {
- ret = data->irq;
- dev_err(&pdev->dev, "Failed to get platform irq\n");
- goto err_free;
- }
-
- INIT_WORK(&data->irq_work, exynos4_tmu_work);
-
- data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!data->mem) {
- ret = -ENOENT;
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- goto err_free;
- }
-
- data->mem = request_mem_region(data->mem->start,
- resource_size(data->mem), pdev->name);
- if (!data->mem) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to request memory region\n");
- goto err_free;
- }
-
- data->base = ioremap(data->mem->start, resource_size(data->mem));
- if (!data->base) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to ioremap memory\n");
- goto err_mem_region;
- }
-
- ret = request_irq(data->irq, exynos4_tmu_irq,
- IRQF_TRIGGER_RISING,
- "exynos4-tmu", data);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
- goto err_io_remap;
- }
-
- data->clk = clk_get(NULL, "tmu_apbif");
- if (IS_ERR(data->clk)) {
- ret = PTR_ERR(data->clk);
- dev_err(&pdev->dev, "Failed to get clock\n");
- goto err_irq;
- }
-
- data->pdata = pdata;
- platform_set_drvdata(pdev, data);
- mutex_init(&data->lock);
-
- ret = exynos4_tmu_initialize(pdev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to initialize TMU\n");
- goto err_clk;
- }
-
- ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create sysfs group\n");
- goto err_clk;
- }
-
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- dev_err(&pdev->dev, "Failed to register hwmon device\n");
- goto err_create_group;
- }
-
- exynos4_tmu_control(pdev, true);
-
- return 0;
-
-err_create_group:
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-err_clk:
- platform_set_drvdata(pdev, NULL);
- clk_put(data->clk);
-err_irq:
- free_irq(data->irq, data);
-err_io_remap:
- iounmap(data->base);
-err_mem_region:
- release_mem_region(data->mem->start, resource_size(data->mem));
-err_free:
- kfree(data);
-
- return ret;
-}
-
-static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-
- exynos4_tmu_control(pdev, false);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-
- clk_put(data->clk);
-
- free_irq(data->irq, data);
-
- iounmap(data->base);
- release_mem_region(data->mem->start, resource_size(data->mem));
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(data);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
-{
- exynos4_tmu_control(pdev, false);
-
- return 0;
-}
-
-static int exynos4_tmu_resume(struct platform_device *pdev)
-{
- exynos4_tmu_initialize(pdev);
- exynos4_tmu_control(pdev, true);
-
- return 0;
-}
-#else
-#define exynos4_tmu_suspend NULL
-#define exynos4_tmu_resume NULL
-#endif
-
-static struct platform_driver exynos4_tmu_driver = {
- .driver = {
- .name = "exynos4-tmu",
- .owner = THIS_MODULE,
- },
- .probe = exynos4_tmu_probe,
- .remove = __devexit_p(exynos4_tmu_remove),
- .suspend = exynos4_tmu_suspend,
- .resume = exynos4_tmu_resume,
-};
-
-module_platform_driver(exynos4_tmu_driver);
-
-MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:exynos4-tmu");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 24c43e3..5c5a43c 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -29,3 +29,13 @@ config CPU_THERMAL
This will be useful for platforms using the generic thermal interface
and not the ACPI interface.
If you want this support, you should say Y or M here.
+
+config SENSORS_EXYNOS4_TMU
+ tristate "Temperature sensor on Samsung EXYNOS4"
+ depends on ARCH_EXYNOS4 && THERMAL
+ help
+ If you say yes here you get support for TMU (Thermal Managment
+ Unit) on SAMSUNG EXYNOS4 series of SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called exynos4-tmu.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 655cbc4..d2d01e9 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_THERMAL) += thermal_sys.o
obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
+obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_thermal.o
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
new file mode 100644
index 0000000..ff708d5
--- /dev/null
+++ b/drivers/thermal/exynos4_thermal.c
@@ -0,0 +1,409 @@
+/*
+ * exynos4_thermal.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ * Amit Daniel Kachhap <amit.kachhap@linaro.org>
+ *
+ * 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/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/exynos4_tmu.h>
+
+#define EXYNOS4_TMU_REG_TRIMINFO 0x0
+#define EXYNOS4_TMU_REG_CONTROL 0x20
+#define EXYNOS4_TMU_REG_STATUS 0x28
+#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
+#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
+#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
+#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
+#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
+#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
+#define EXYNOS4_TMU_REG_INTEN 0x70
+#define EXYNOS4_TMU_REG_INTSTAT 0x74
+#define EXYNOS4_TMU_REG_INTCLEAR 0x78
+
+#define EXYNOS4_TMU_GAIN_SHIFT 8
+#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
+
+#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
+#define EXYNOS4_TMU_CORE_ON 3
+#define EXYNOS4_TMU_CORE_OFF 2
+#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
+#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
+#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
+#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
+#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+
+struct exynos4_tmu_data {
+ struct exynos4_tmu_platform_data *pdata;
+ struct resource *mem;
+ void __iomem *base;
+ int irq;
+ struct work_struct irq_work;
+ struct mutex lock;
+ struct clk *clk;
+ u8 temp_error1, temp_error2;
+};
+
+/*
+ * TMU treats temperature as a mapped temperature code.
+ * The temperature is converted differently depending on the calibration type.
+ */
+static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp_code;
+
+ /* temp should range between 25 and 125 */
+ if (temp < 25 || temp > 125) {
+ temp_code = -EINVAL;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp_code = (temp - 25) *
+ (data->temp_error2 - data->temp_error1) /
+ (85 - 25) + data->temp_error1;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp_code = temp + data->temp_error1 - 25;
+ break;
+ default:
+ temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp_code;
+}
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree Celsius.
+ */
+static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp;
+
+ /* temp_code should range between 75 and 175 */
+ if (temp_code < 75 || temp_code > 175) {
+ temp = -ENODATA;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp = (temp_code - data->temp_error1) * (85 - 25) /
+ (data->temp_error2 - data->temp_error1) + 25;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp = temp_code - data->temp_error1 + 25;
+ break;
+ default:
+ temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp;
+}
+
+static int exynos4_tmu_initialize(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int status, trim_info;
+ int ret = 0, threshold_code;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Save trimming info in order to perform calibration */
+ trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
+ data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
+ data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
+
+ /* Write temperature code for threshold */
+ threshold_code = temp_to_code(data, pdata->threshold);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ writeb(threshold_code,
+ data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
+
+ writeb(pdata->trigger_levels[0],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
+ writeb(pdata->trigger_levels[1],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
+ writeb(pdata->trigger_levels[2],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
+ writeb(pdata->trigger_levels[3],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL,
+ data->base + EXYNOS4_TMU_REG_INTCLEAR);
+out:
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static void exynos4_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int con, interrupt_en;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
+ pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
+ if (on) {
+ con |= EXYNOS4_TMU_CORE_ON;
+ interrupt_en = pdata->trigger_level3_en << 12 |
+ pdata->trigger_level2_en << 8 |
+ pdata->trigger_level1_en << 4 |
+ pdata->trigger_level0_en;
+ } else {
+ con |= EXYNOS4_TMU_CORE_OFF;
+ interrupt_en = 0; /* Disable all interrupts */
+ }
+ writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
+ writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static int exynos4_tmu_read(struct exynos4_tmu_data *data)
+{
+ u8 temp_code;
+ int temp;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
+ temp = code_to_temp(data, temp_code);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return temp;
+}
+
+static void exynos4_tmu_work(struct work_struct *work)
+{
+ struct exynos4_tmu_data *data = container_of(work,
+ struct exynos4_tmu_data, irq_work);
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
+
+ enable_irq(data->irq);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static irqreturn_t exynos4_tmu_irq(int irq, void *id)
+{
+ struct exynos4_tmu_data *data = id;
+
+ disable_irq_nosync(irq);
+ schedule_work(&data->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data;
+ struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform init data supplied.\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0) {
+ ret = data->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ goto err_free;
+ }
+
+ INIT_WORK(&data->irq_work, exynos4_tmu_work);
+
+ data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!data->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ goto err_free;
+ }
+
+ data->mem = request_mem_region(data->mem->start,
+ resource_size(data->mem), pdev->name);
+ if (!data->mem) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to request memory region\n");
+ goto err_free;
+ }
+
+ data->base = ioremap(data->mem->start, resource_size(data->mem));
+ if (!data->base) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ goto err_mem_region;
+ }
+
+ ret = request_irq(data->irq, exynos4_tmu_irq,
+ IRQF_TRIGGER_RISING,
+ "exynos4-tmu", data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
+ goto err_io_remap;
+ }
+
+ data->clk = clk_get(NULL, "tmu_apbif");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ goto err_irq;
+ }
+
+ data->pdata = pdata;
+ platform_set_drvdata(pdev, data);
+ mutex_init(&data->lock);
+
+ ret = exynos4_tmu_initialize(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize TMU\n");
+ goto err_clk;
+ }
+
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+err_clk:
+ platform_set_drvdata(pdev, NULL);
+ clk_put(data->clk);
+err_irq:
+ free_irq(data->irq, data);
+err_io_remap:
+ iounmap(data->base);
+err_mem_region:
+ release_mem_region(data->mem->start, resource_size(data->mem));
+err_free:
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+
+ exynos4_tmu_control(pdev, false);
+
+ clk_put(data->clk);
+
+ free_irq(data->irq, data);
+
+ iounmap(data->base);
+ release_mem_region(data->mem->start, resource_size(data->mem));
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ exynos4_tmu_control(pdev, false);
+
+ return 0;
+}
+
+static int exynos4_tmu_resume(struct platform_device *pdev)
+{
+ exynos4_tmu_initialize(pdev);
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+}
+#else
+#define exynos4_tmu_suspend NULL
+#define exynos4_tmu_resume NULL
+#endif
+
+static struct platform_driver exynos4_tmu_driver = {
+ .driver = {
+ .name = "exynos4-tmu",
+ .owner = THIS_MODULE,
+ },
+ .probe = exynos4_tmu_probe,
+ .remove = __devexit_p(exynos4_tmu_remove),
+ .suspend = exynos4_tmu_suspend,
+ .resume = exynos4_tmu_resume,
+};
+
+module_platform_driver(exynos4_tmu_driver);
+
+MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos4-tmu");
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 4/6] hwmon: exynos4: Move thermal sensor driver to driver/thermal directory
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This movement is needed because the hwmon entries and corresponding
sysfs interface is a duplicate of utilities already provided by
driver/thermal/thermal_sys.c. The goal is to place it in thermal folder
and add necessary functions to use the in-kernel thermal interfaces.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
---
Documentation/hwmon/exynos4_tmu | 81 ------
Documentation/thermal/exynos4_tmu | 52 ++++
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------------------------
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 1 +
drivers/thermal/exynos4_thermal.c | 409 +++++++++++++++++++++++++++++
8 files changed, 472 insertions(+), 606 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/exynos4_tmu
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/exynos4_thermal.c
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu
deleted file mode 100644
index c3c6b41..0000000
--- a/Documentation/hwmon/exynos4_tmu
+++ /dev/null
@@ -1,81 +0,0 @@
-Kernel driver exynos4_tmu
-=================
-
-Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
- Prefix: 'exynos4-tmu'
- Datasheet: Not publicly available
-
-Authors: Donggeun Kim <dg77.kim@samsung.com>
-
-Description
------------
-
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
-
-The chip only exposes the measured 8-bit temperature code value
-through a register.
-Temperature can be taken from the temperature code.
-There are three equations converting from temperature to temperature code.
-
-The three equations are:
- 1. Two point trimming
- Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
-
- 2. One point trimming
- Tc = T + TI1 - 25
-
- 3. No trimming
- Tc = T + 50
-
- Tc: Temperature code, T: Temperature,
- TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
- Temperature code measured at 25 degree Celsius which is unchanged
- 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
-when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
-The threshold levels are defined as follows:
- Level_0: current temperature > trigger_level_0 + threshold
- Level_1: current temperature > trigger_level_1 + threshold
- Level_2: current temperature > trigger_level_2 + threshold
- Level_3: current temperature > trigger_level_3 + threshold
-
- The threshold and each trigger_level are set
- through the corresponding registers.
-
-When an interrupt occurs, this driver notify user space of
-one of four threshold levels for the interrupt
-through kobject_uevent_env and sysfs_notify functions.
-Although an interrupt condition for level_0 can be set,
-it is not notified to user space through sysfs_notify function.
-
-Sysfs Interface
----------------
-name name of the temperature sensor
- RO
-
-temp1_input temperature
- RO
-
-temp1_max temperature for level_1 interrupt
- RO
-
-temp1_crit temperature for level_2 interrupt
- RO
-
-temp1_emergency temperature for level_3 interrupt
- RO
-
-temp1_max_alarm alarm for level_1 interrupt
- RO
-
-temp1_crit_alarm
- alarm for level_2 interrupt
- RO
-
-temp1_emergency_alarm
- alarm for level_3 interrupt
- RO
diff --git a/Documentation/thermal/exynos4_tmu b/Documentation/thermal/exynos4_tmu
new file mode 100644
index 0000000..2b46f67
--- /dev/null
+++ b/Documentation/thermal/exynos4_tmu
@@ -0,0 +1,52 @@
+Kernel driver exynos4_tmu
+=================
+
+Supported chips:
+* ARM SAMSUNG EXYNOS4 series of SoC
+ Prefix: 'exynos4-tmu'
+ Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+
+Description
+-----------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+ 1. Two point trimming
+ Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+ 2. One point trimming
+ Tc = T + TI1 - 25
+
+ 3. No trimming
+ Tc = T + 50
+
+ Tc: Temperature code, T: Temperature,
+ TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+ Temperature code measured at 25 degree Celsius which is unchanged
+ 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
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is four.
+The threshold levels are defined as follows:
+ Level_0: current temperature > trigger_level_0 + threshold
+ Level_1: current temperature > trigger_level_1 + threshold
+ Level_2: current temperature > trigger_level_2 + threshold
+ Level_3: current temperature > trigger_level_3 + threshold
+
+ The threshold and each trigger_level are set
+ through the corresponding registers.
+
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos4_report_trigger.
+Although an interrupt condition for level_0 can be set,
+it can be used to synchronize the cooling action.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index dad895f..5a29885 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -313,16 +313,6 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
-config SENSORS_EXYNOS4_TMU
- tristate "Temperature sensor on Samsung EXYNOS4"
- depends on ARCH_EXYNOS4
- help
- If you say yes here you get support for TMU (Thermal Managment
- Unit) on SAMSUNG EXYNOS4 series of SoC.
-
- This driver can also be built as a module. If so, the module
- will be called exynos4-tmu.
-
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..228a4b7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
-obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c
deleted file mode 100644
index f2359a0..0000000
--- a/drivers/hwmon/exynos4_tmu.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
- *
- * Copyright (C) 2011 Samsung Electronics
- * Donggeun Kim <dg77.kim@samsung.com>
- *
- * 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/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/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
-#include <linux/platform_data/exynos4_tmu.h>
-
-#define EXYNOS4_TMU_REG_TRIMINFO 0x0
-#define EXYNOS4_TMU_REG_CONTROL 0x20
-#define EXYNOS4_TMU_REG_STATUS 0x28
-#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
-#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
-#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
-#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
-#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
-#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
-#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
-#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
-#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
-#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
-#define EXYNOS4_TMU_REG_INTEN 0x70
-#define EXYNOS4_TMU_REG_INTSTAT 0x74
-#define EXYNOS4_TMU_REG_INTCLEAR 0x78
-
-#define EXYNOS4_TMU_GAIN_SHIFT 8
-#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
-
-#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
-#define EXYNOS4_TMU_CORE_ON 3
-#define EXYNOS4_TMU_CORE_OFF 2
-#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
-#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
-#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
-#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
-#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
-#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
-
-struct exynos4_tmu_data {
- struct exynos4_tmu_platform_data *pdata;
- struct device *hwmon_dev;
- struct resource *mem;
- void __iomem *base;
- int irq;
- struct work_struct irq_work;
- struct mutex lock;
- struct clk *clk;
- u8 temp_error1, temp_error2;
-};
-
-/*
- * TMU treats temperature as a mapped temperature code.
- * The temperature is converted differently depending on the calibration type.
- */
-static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp_code;
-
- /* temp should range between 25 and 125 */
- if (temp < 25 || temp > 125) {
- temp_code = -EINVAL;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp_code = (temp - 25) *
- (data->temp_error2 - data->temp_error1) /
- (85 - 25) + data->temp_error1;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp_code = temp + data->temp_error1 - 25;
- break;
- default:
- temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp_code;
-}
-
-/*
- * Calculate a temperature value from a temperature code.
- * The unit of the temperature is degree Celsius.
- */
-static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
-
- /* temp_code should range between 75 and 175 */
- if (temp_code < 75 || temp_code > 175) {
- temp = -ENODATA;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp = (temp_code - data->temp_error1) * (85 - 25) /
- (data->temp_error2 - data->temp_error1) + 25;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp = temp_code - data->temp_error1 + 25;
- break;
- default:
- temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp;
-}
-
-static int exynos4_tmu_initialize(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int status, trim_info;
- int ret = 0, threshold_code;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
- if (!status) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Save trimming info in order to perform calibration */
- trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
- data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
- data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
-
- /* Write temperature code for threshold */
- threshold_code = temp_to_code(data, pdata->threshold);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
- }
- writeb(threshold_code,
- data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
-
- writeb(pdata->trigger_levels[0],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
- writeb(pdata->trigger_levels[1],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
- writeb(pdata->trigger_levels[2],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
- writeb(pdata->trigger_levels[3],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL,
- data->base + EXYNOS4_TMU_REG_INTCLEAR);
-out:
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return ret;
-}
-
-static void exynos4_tmu_control(struct platform_device *pdev, bool on)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int con, interrupt_en;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
- pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
- if (on) {
- con |= EXYNOS4_TMU_CORE_ON;
- interrupt_en = pdata->trigger_level3_en << 12 |
- pdata->trigger_level2_en << 8 |
- pdata->trigger_level1_en << 4 |
- pdata->trigger_level0_en;
- } else {
- con |= EXYNOS4_TMU_CORE_OFF;
- interrupt_en = 0; /* Disable all interrupts */
- }
- writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
- writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static int exynos4_tmu_read(struct exynos4_tmu_data *data)
-{
- u8 temp_code;
- int temp;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
- temp = code_to_temp(data, temp_code);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return temp;
-}
-
-static void exynos4_tmu_work(struct work_struct *work)
-{
- struct exynos4_tmu_data *data = container_of(work,
- struct exynos4_tmu_data, irq_work);
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
-
- kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
-
- enable_irq(data->irq);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static irqreturn_t exynos4_tmu_irq(int irq, void *id)
-{
- struct exynos4_tmu_data *data = id;
-
- disable_irq_nosync(irq);
- schedule_work(&data->irq_work);
-
- return IRQ_HANDLED;
-}
-
-static ssize_t exynos4_tmu_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "exynos4-tmu\n");
-}
-
-static ssize_t exynos4_tmu_show_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- int ret;
-
- ret = exynos4_tmu_read(data);
- if (ret < 0)
- return ret;
-
- /* convert from degree Celsius to millidegree Celsius */
- return sprintf(buf, "%d\n", ret * 1000);
-}
-
-static ssize_t exynos4_tmu_show_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
- unsigned int trigger_level;
-
- temp = exynos4_tmu_read(data);
- if (temp < 0)
- return temp;
-
- trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%d\n", !!(temp > trigger_level));
-}
-
-static ssize_t exynos4_tmu_show_level(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int temp = pdata->threshold +
- pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%u\n", temp * 1000);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
-
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
- exynos4_tmu_show_level, NULL, 3);
-
-static struct attribute *exynos4_tmu_attributes[] = {
- &dev_attr_name.attr,
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group exynos4_tmu_attr_group = {
- .attrs = exynos4_tmu_attributes,
-};
-
-static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data;
- struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform init data supplied.\n");
- return -ENODEV;
- }
-
- data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "Failed to allocate driver structure\n");
- return -ENOMEM;
- }
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0) {
- ret = data->irq;
- dev_err(&pdev->dev, "Failed to get platform irq\n");
- goto err_free;
- }
-
- INIT_WORK(&data->irq_work, exynos4_tmu_work);
-
- data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!data->mem) {
- ret = -ENOENT;
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- goto err_free;
- }
-
- data->mem = request_mem_region(data->mem->start,
- resource_size(data->mem), pdev->name);
- if (!data->mem) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to request memory region\n");
- goto err_free;
- }
-
- data->base = ioremap(data->mem->start, resource_size(data->mem));
- if (!data->base) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to ioremap memory\n");
- goto err_mem_region;
- }
-
- ret = request_irq(data->irq, exynos4_tmu_irq,
- IRQF_TRIGGER_RISING,
- "exynos4-tmu", data);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
- goto err_io_remap;
- }
-
- data->clk = clk_get(NULL, "tmu_apbif");
- if (IS_ERR(data->clk)) {
- ret = PTR_ERR(data->clk);
- dev_err(&pdev->dev, "Failed to get clock\n");
- goto err_irq;
- }
-
- data->pdata = pdata;
- platform_set_drvdata(pdev, data);
- mutex_init(&data->lock);
-
- ret = exynos4_tmu_initialize(pdev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to initialize TMU\n");
- goto err_clk;
- }
-
- ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create sysfs group\n");
- goto err_clk;
- }
-
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- dev_err(&pdev->dev, "Failed to register hwmon device\n");
- goto err_create_group;
- }
-
- exynos4_tmu_control(pdev, true);
-
- return 0;
-
-err_create_group:
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-err_clk:
- platform_set_drvdata(pdev, NULL);
- clk_put(data->clk);
-err_irq:
- free_irq(data->irq, data);
-err_io_remap:
- iounmap(data->base);
-err_mem_region:
- release_mem_region(data->mem->start, resource_size(data->mem));
-err_free:
- kfree(data);
-
- return ret;
-}
-
-static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-
- exynos4_tmu_control(pdev, false);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-
- clk_put(data->clk);
-
- free_irq(data->irq, data);
-
- iounmap(data->base);
- release_mem_region(data->mem->start, resource_size(data->mem));
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(data);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
-{
- exynos4_tmu_control(pdev, false);
-
- return 0;
-}
-
-static int exynos4_tmu_resume(struct platform_device *pdev)
-{
- exynos4_tmu_initialize(pdev);
- exynos4_tmu_control(pdev, true);
-
- return 0;
-}
-#else
-#define exynos4_tmu_suspend NULL
-#define exynos4_tmu_resume NULL
-#endif
-
-static struct platform_driver exynos4_tmu_driver = {
- .driver = {
- .name = "exynos4-tmu",
- .owner = THIS_MODULE,
- },
- .probe = exynos4_tmu_probe,
- .remove = __devexit_p(exynos4_tmu_remove),
- .suspend = exynos4_tmu_suspend,
- .resume = exynos4_tmu_resume,
-};
-
-module_platform_driver(exynos4_tmu_driver);
-
-MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:exynos4-tmu");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 24c43e3..5c5a43c 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -29,3 +29,13 @@ config CPU_THERMAL
This will be useful for platforms using the generic thermal interface
and not the ACPI interface.
If you want this support, you should say Y or M here.
+
+config SENSORS_EXYNOS4_TMU
+ tristate "Temperature sensor on Samsung EXYNOS4"
+ depends on ARCH_EXYNOS4 && THERMAL
+ help
+ If you say yes here you get support for TMU (Thermal Managment
+ Unit) on SAMSUNG EXYNOS4 series of SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called exynos4-tmu.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 655cbc4..d2d01e9 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_THERMAL) += thermal_sys.o
obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
+obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_thermal.o
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
new file mode 100644
index 0000000..ff708d5
--- /dev/null
+++ b/drivers/thermal/exynos4_thermal.c
@@ -0,0 +1,409 @@
+/*
+ * exynos4_thermal.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ * Amit Daniel Kachhap <amit.kachhap@linaro.org>
+ *
+ * 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/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/exynos4_tmu.h>
+
+#define EXYNOS4_TMU_REG_TRIMINFO 0x0
+#define EXYNOS4_TMU_REG_CONTROL 0x20
+#define EXYNOS4_TMU_REG_STATUS 0x28
+#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
+#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
+#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
+#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
+#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
+#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
+#define EXYNOS4_TMU_REG_INTEN 0x70
+#define EXYNOS4_TMU_REG_INTSTAT 0x74
+#define EXYNOS4_TMU_REG_INTCLEAR 0x78
+
+#define EXYNOS4_TMU_GAIN_SHIFT 8
+#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
+
+#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
+#define EXYNOS4_TMU_CORE_ON 3
+#define EXYNOS4_TMU_CORE_OFF 2
+#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
+#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
+#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
+#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
+#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+
+struct exynos4_tmu_data {
+ struct exynos4_tmu_platform_data *pdata;
+ struct resource *mem;
+ void __iomem *base;
+ int irq;
+ struct work_struct irq_work;
+ struct mutex lock;
+ struct clk *clk;
+ u8 temp_error1, temp_error2;
+};
+
+/*
+ * TMU treats temperature as a mapped temperature code.
+ * The temperature is converted differently depending on the calibration type.
+ */
+static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp_code;
+
+ /* temp should range between 25 and 125 */
+ if (temp < 25 || temp > 125) {
+ temp_code = -EINVAL;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp_code = (temp - 25) *
+ (data->temp_error2 - data->temp_error1) /
+ (85 - 25) + data->temp_error1;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp_code = temp + data->temp_error1 - 25;
+ break;
+ default:
+ temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp_code;
+}
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree Celsius.
+ */
+static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp;
+
+ /* temp_code should range between 75 and 175 */
+ if (temp_code < 75 || temp_code > 175) {
+ temp = -ENODATA;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp = (temp_code - data->temp_error1) * (85 - 25) /
+ (data->temp_error2 - data->temp_error1) + 25;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp = temp_code - data->temp_error1 + 25;
+ break;
+ default:
+ temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp;
+}
+
+static int exynos4_tmu_initialize(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int status, trim_info;
+ int ret = 0, threshold_code;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Save trimming info in order to perform calibration */
+ trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
+ data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
+ data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
+
+ /* Write temperature code for threshold */
+ threshold_code = temp_to_code(data, pdata->threshold);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ writeb(threshold_code,
+ data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
+
+ writeb(pdata->trigger_levels[0],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
+ writeb(pdata->trigger_levels[1],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
+ writeb(pdata->trigger_levels[2],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
+ writeb(pdata->trigger_levels[3],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL,
+ data->base + EXYNOS4_TMU_REG_INTCLEAR);
+out:
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static void exynos4_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int con, interrupt_en;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
+ pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
+ if (on) {
+ con |= EXYNOS4_TMU_CORE_ON;
+ interrupt_en = pdata->trigger_level3_en << 12 |
+ pdata->trigger_level2_en << 8 |
+ pdata->trigger_level1_en << 4 |
+ pdata->trigger_level0_en;
+ } else {
+ con |= EXYNOS4_TMU_CORE_OFF;
+ interrupt_en = 0; /* Disable all interrupts */
+ }
+ writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
+ writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static int exynos4_tmu_read(struct exynos4_tmu_data *data)
+{
+ u8 temp_code;
+ int temp;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
+ temp = code_to_temp(data, temp_code);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return temp;
+}
+
+static void exynos4_tmu_work(struct work_struct *work)
+{
+ struct exynos4_tmu_data *data = container_of(work,
+ struct exynos4_tmu_data, irq_work);
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
+
+ enable_irq(data->irq);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static irqreturn_t exynos4_tmu_irq(int irq, void *id)
+{
+ struct exynos4_tmu_data *data = id;
+
+ disable_irq_nosync(irq);
+ schedule_work(&data->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data;
+ struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform init data supplied.\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0) {
+ ret = data->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ goto err_free;
+ }
+
+ INIT_WORK(&data->irq_work, exynos4_tmu_work);
+
+ data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!data->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ goto err_free;
+ }
+
+ data->mem = request_mem_region(data->mem->start,
+ resource_size(data->mem), pdev->name);
+ if (!data->mem) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to request memory region\n");
+ goto err_free;
+ }
+
+ data->base = ioremap(data->mem->start, resource_size(data->mem));
+ if (!data->base) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ goto err_mem_region;
+ }
+
+ ret = request_irq(data->irq, exynos4_tmu_irq,
+ IRQF_TRIGGER_RISING,
+ "exynos4-tmu", data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
+ goto err_io_remap;
+ }
+
+ data->clk = clk_get(NULL, "tmu_apbif");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ goto err_irq;
+ }
+
+ data->pdata = pdata;
+ platform_set_drvdata(pdev, data);
+ mutex_init(&data->lock);
+
+ ret = exynos4_tmu_initialize(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize TMU\n");
+ goto err_clk;
+ }
+
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+err_clk:
+ platform_set_drvdata(pdev, NULL);
+ clk_put(data->clk);
+err_irq:
+ free_irq(data->irq, data);
+err_io_remap:
+ iounmap(data->base);
+err_mem_region:
+ release_mem_region(data->mem->start, resource_size(data->mem));
+err_free:
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+
+ exynos4_tmu_control(pdev, false);
+
+ clk_put(data->clk);
+
+ free_irq(data->irq, data);
+
+ iounmap(data->base);
+ release_mem_region(data->mem->start, resource_size(data->mem));
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ exynos4_tmu_control(pdev, false);
+
+ return 0;
+}
+
+static int exynos4_tmu_resume(struct platform_device *pdev)
+{
+ exynos4_tmu_initialize(pdev);
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+}
+#else
+#define exynos4_tmu_suspend NULL
+#define exynos4_tmu_resume NULL
+#endif
+
+static struct platform_driver exynos4_tmu_driver = {
+ .driver = {
+ .name = "exynos4-tmu",
+ .owner = THIS_MODULE,
+ },
+ .probe = exynos4_tmu_probe,
+ .remove = __devexit_p(exynos4_tmu_remove),
+ .suspend = exynos4_tmu_suspend,
+ .resume = exynos4_tmu_resume,
+};
+
+module_platform_driver(exynos4_tmu_driver);
+
+MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos4-tmu");
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 5/6] thermal: exynos4: Register the tmu sensor with the kernel thermal layer
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This code added creates a link between temperature sensors, linux thermal
framework and cooling devices for samsung exynos platform. This layer
monitors the temperature from the sensor and informs the generic thermal
layer to take the necessary cooling action.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
drivers/thermal/exynos4_thermal.c | 342 ++++++++++++++++++++++++++++-
include/linux/platform_data/exynos4_tmu.h | 7 +
2 files changed, 345 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index ff708d5..e5be944 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -33,8 +33,11 @@
#include <linux/kobject.h>
#include <linux/io.h>
#include <linux/mutex.h>
-
+#include <linux/err.h>
#include <linux/platform_data/exynos4_tmu.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
#define EXYNOS4_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_CONTROL 0x20
@@ -66,6 +69,22 @@
#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+#define SENSOR_NAME_LEN 16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+
+/* 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)
+
struct exynos4_tmu_data {
struct exynos4_tmu_platform_data *pdata;
struct resource *mem;
@@ -77,6 +96,296 @@ struct exynos4_tmu_data {
u8 temp_error1, temp_error2;
};
+struct thermal_trip_point_conf {
+ int trip_val[MAX_TRIP_COUNT];
+ int trip_count;
+};
+
+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);
+ struct thermal_trip_point_conf trip_data;
+ struct thermal_cooling_conf cooling_data;
+ void *private_data;
+};
+
+struct exynos4_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;
+};
+
+static struct exynos4_thermal_zone *th_zone;
+static void exynos4_unregister_thermal(void);
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf);
+
+/* Get mode callback functions for thermal zone */
+static int exynos4_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 exynos4_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->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;
+}
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+static void exynos4_report_trigger(void)
+{
+ unsigned int i;
+ char data[2];
+ char *envp[] = { data, NULL };
+
+ if (!th_zone || !th_zone->therm_dev)
+ return;
+
+ 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] * 1000)
+ break;
+ }
+
+ if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
+ if (i > 0)
+ th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ }
+
+ sprintf(data, "%u", i);
+ kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Get trip type callback functions for thermal zone */
+static int exynos4_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_STATE_INSTANCE;
+ break;
+ case PANIC_ZONE:
+ *type = THERMAL_TRIP_CRITICAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos4_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ if (trip < 0 || trip > 2)
+ return -EINVAL;
+
+ *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+ /* convert the temperature into millicelsius */
+ *temp = *temp * 1000;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos4_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret = 0;
+ /* Panic zone */
+ ret = exynos4_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos4_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ /* if the cooling device is the one from exynos4 bind it */
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error binding cooling dev inst 0\n");
+ return -EINVAL;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error binding cooling dev inst 1\n");
+ ret = -EINVAL;
+ goto error_bind1;
+ }
+
+ return ret;
+error_bind1:
+ thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos4_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error unbinding cooling dev inst 0\n");
+ ret = -EINVAL;
+ }
+ if (thermal_zone_unbind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error unbinding cooling dev inst 1\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos4_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 * 1000;
+ return 0;
+}
+
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops exynos4_dev_ops = {
+ .bind = exynos4_bind,
+ .unbind = exynos4_unbind,
+ .get_temp = exynos4_get_temp,
+ .get_mode = exynos4_get_mode,
+ .set_mode = exynos4_set_mode,
+ .get_trip_type = exynos4_get_trip_type,
+ .get_trip_temp = exynos4_get_trip_temp,
+ .get_crit_temp = exynos4_get_crit_temp,
+};
+
+/* Register with the in-kernel thermal management */
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+ int ret, count, tab_size;
+ struct freq_clip_table *tab_ptr;
+
+ if (!sensor_conf || !sensor_conf->read_temperature) {
+ pr_err("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+
+ th_zone = kzalloc(sizeof(struct exynos4_thermal_zone), GFP_KERNEL);
+ if (!th_zone) {
+ ret = -ENOMEM;
+ goto err_unregister;
+ }
+
+ th_zone->sensor_conf = sensor_conf;
+
+ tab_ptr = (struct freq_clip_table *)sensor_conf->cooling_data.freq_data;
+ tab_size = sensor_conf->cooling_data.freq_clip_count;
+
+ /* Register the cpufreq cooling device */
+ th_zone->cool_dev_size = 1;
+ count = 0;
+ th_zone->cool_dev[count] = cpufreq_cooling_register(
+ (struct freq_clip_table *)&(tab_ptr[count]),
+ tab_size, cpumask_of(0));
+
+ if (IS_ERR(th_zone->cool_dev[count])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ th_zone->cool_dev_size = 0;
+ goto err_unregister;
+ }
+
+ th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
+ 3, NULL, &exynos4_dev_ops, 0, 0, 0, IDLE_INTERVAL);
+
+ if (IS_ERR(th_zone->therm_dev)) {
+ pr_err("Failed to register thermal zone device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->mode = THERMAL_DEVICE_ENABLED;
+
+ pr_info("Exynos: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ exynos4_unregister_thermal();
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+static void exynos4_unregister_thermal(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (th_zone && th_zone->cool_dev[i])
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+ }
+
+ if (th_zone && th_zone->therm_dev)
+ thermal_zone_device_unregister(th_zone->therm_dev);
+
+ 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.
@@ -243,10 +552,10 @@ static void exynos4_tmu_work(struct work_struct *work)
writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
- enable_irq(data->irq);
-
clk_disable(data->clk);
mutex_unlock(&data->lock);
+ exynos4_report_trigger();
+ enable_irq(data->irq);
}
static irqreturn_t exynos4_tmu_irq(int irq, void *id)
@@ -259,11 +568,16 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id)
return IRQ_HANDLED;
}
+static struct thermal_sensor_conf exynos4_sensor_conf = {
+ .name = "exynos4-therm",
+ .read_temperature = (int (*)(void *))exynos4_tmu_read,
+};
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
+ int ret, i;
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -334,6 +648,24 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
exynos4_tmu_control(pdev, true);
+ /*Register the sensor with thermal management interface*/
+ (&exynos4_sensor_conf)->private_data = data;
+ exynos4_sensor_conf.trip_data.trip_count = 3;
+ for (i = 0; i < exynos4_sensor_conf.trip_data.trip_count; i++)
+ exynos4_sensor_conf.trip_data.trip_val[i] =
+ pdata->threshold + pdata->trigger_levels[i + 1];
+
+ exynos4_sensor_conf.cooling_data.freq_clip_count =
+ pdata->freq_tab_count;
+ for (i = 0; i < pdata->freq_tab_count; i++)
+ exynos4_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
+ pdata->freq_tab[i].freq_clip_max;
+
+ ret = exynos4_register_thermal(&exynos4_sensor_conf);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register thermal interface\n");
+ goto err_clk;
+ }
return 0;
err_clk:
platform_set_drvdata(pdev, NULL);
@@ -356,6 +688,8 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
exynos4_tmu_control(pdev, false);
+ exynos4_unregister_thermal();
+
clk_put(data->clk);
free_irq(data->irq, data);
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h
index 39e038c..ae32f19 100644
--- a/include/linux/platform_data/exynos4_tmu.h
+++ b/include/linux/platform_data/exynos4_tmu.h
@@ -21,6 +21,7 @@
#ifndef _LINUX_EXYNOS4_TMU_H
#define _LINUX_EXYNOS4_TMU_H
+#include <linux/cpu_cooling.h>
enum calibration_type {
TYPE_ONE_POINT_TRIMMING,
@@ -64,6 +65,9 @@ enum calibration_type {
* in the positive-TC generator block
* 0 <= reference_voltage <= 31
* @cal_type: calibration type 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.
*
* This structure is required for configuration of exynos4_tmu driver.
*/
@@ -79,5 +83,8 @@ struct exynos4_tmu_platform_data {
u8 reference_voltage;
enum calibration_type cal_type;
+
+ struct freq_clip_table freq_tab[4];
+ unsigned int freq_tab_count;
};
#endif /* _LINUX_EXYNOS4_TMU_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 5/6] thermal: exynos4: Register the tmu sensor with the kernel thermal layer
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This code added creates a link between temperature sensors, linux thermal
framework and cooling devices for samsung exynos platform. This layer
monitors the temperature from the sensor and informs the generic thermal
layer to take the necessary cooling action.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
drivers/thermal/exynos4_thermal.c | 342 ++++++++++++++++++++++++++++-
include/linux/platform_data/exynos4_tmu.h | 7 +
2 files changed, 345 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index ff708d5..e5be944 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -33,8 +33,11 @@
#include <linux/kobject.h>
#include <linux/io.h>
#include <linux/mutex.h>
-
+#include <linux/err.h>
#include <linux/platform_data/exynos4_tmu.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
#define EXYNOS4_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_CONTROL 0x20
@@ -66,6 +69,22 @@
#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+#define SENSOR_NAME_LEN 16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+
+/* 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)
+
struct exynos4_tmu_data {
struct exynos4_tmu_platform_data *pdata;
struct resource *mem;
@@ -77,6 +96,296 @@ struct exynos4_tmu_data {
u8 temp_error1, temp_error2;
};
+struct thermal_trip_point_conf {
+ int trip_val[MAX_TRIP_COUNT];
+ int trip_count;
+};
+
+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);
+ struct thermal_trip_point_conf trip_data;
+ struct thermal_cooling_conf cooling_data;
+ void *private_data;
+};
+
+struct exynos4_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;
+};
+
+static struct exynos4_thermal_zone *th_zone;
+static void exynos4_unregister_thermal(void);
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf);
+
+/* Get mode callback functions for thermal zone */
+static int exynos4_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 exynos4_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->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;
+}
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+static void exynos4_report_trigger(void)
+{
+ unsigned int i;
+ char data[2];
+ char *envp[] = { data, NULL };
+
+ if (!th_zone || !th_zone->therm_dev)
+ return;
+
+ 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] * 1000)
+ break;
+ }
+
+ if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
+ if (i > 0)
+ th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ }
+
+ sprintf(data, "%u", i);
+ kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Get trip type callback functions for thermal zone */
+static int exynos4_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_STATE_INSTANCE;
+ break;
+ case PANIC_ZONE:
+ *type = THERMAL_TRIP_CRITICAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos4_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ if (trip < 0 || trip > 2)
+ return -EINVAL;
+
+ *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+ /* convert the temperature into millicelsius */
+ *temp = *temp * 1000;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos4_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret = 0;
+ /* Panic zone */
+ ret = exynos4_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos4_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ /* if the cooling device is the one from exynos4 bind it */
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error binding cooling dev inst 0\n");
+ return -EINVAL;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error binding cooling dev inst 1\n");
+ ret = -EINVAL;
+ goto error_bind1;
+ }
+
+ return ret;
+error_bind1:
+ thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos4_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error unbinding cooling dev inst 0\n");
+ ret = -EINVAL;
+ }
+ if (thermal_zone_unbind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error unbinding cooling dev inst 1\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos4_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 * 1000;
+ return 0;
+}
+
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops exynos4_dev_ops = {
+ .bind = exynos4_bind,
+ .unbind = exynos4_unbind,
+ .get_temp = exynos4_get_temp,
+ .get_mode = exynos4_get_mode,
+ .set_mode = exynos4_set_mode,
+ .get_trip_type = exynos4_get_trip_type,
+ .get_trip_temp = exynos4_get_trip_temp,
+ .get_crit_temp = exynos4_get_crit_temp,
+};
+
+/* Register with the in-kernel thermal management */
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+ int ret, count, tab_size;
+ struct freq_clip_table *tab_ptr;
+
+ if (!sensor_conf || !sensor_conf->read_temperature) {
+ pr_err("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+
+ th_zone = kzalloc(sizeof(struct exynos4_thermal_zone), GFP_KERNEL);
+ if (!th_zone) {
+ ret = -ENOMEM;
+ goto err_unregister;
+ }
+
+ th_zone->sensor_conf = sensor_conf;
+
+ tab_ptr = (struct freq_clip_table *)sensor_conf->cooling_data.freq_data;
+ tab_size = sensor_conf->cooling_data.freq_clip_count;
+
+ /* Register the cpufreq cooling device */
+ th_zone->cool_dev_size = 1;
+ count = 0;
+ th_zone->cool_dev[count] = cpufreq_cooling_register(
+ (struct freq_clip_table *)&(tab_ptr[count]),
+ tab_size, cpumask_of(0));
+
+ if (IS_ERR(th_zone->cool_dev[count])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ th_zone->cool_dev_size = 0;
+ goto err_unregister;
+ }
+
+ th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
+ 3, NULL, &exynos4_dev_ops, 0, 0, 0, IDLE_INTERVAL);
+
+ if (IS_ERR(th_zone->therm_dev)) {
+ pr_err("Failed to register thermal zone device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->mode = THERMAL_DEVICE_ENABLED;
+
+ pr_info("Exynos: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ exynos4_unregister_thermal();
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+static void exynos4_unregister_thermal(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (th_zone && th_zone->cool_dev[i])
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+ }
+
+ if (th_zone && th_zone->therm_dev)
+ thermal_zone_device_unregister(th_zone->therm_dev);
+
+ 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.
@@ -243,10 +552,10 @@ static void exynos4_tmu_work(struct work_struct *work)
writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
- enable_irq(data->irq);
-
clk_disable(data->clk);
mutex_unlock(&data->lock);
+ exynos4_report_trigger();
+ enable_irq(data->irq);
}
static irqreturn_t exynos4_tmu_irq(int irq, void *id)
@@ -259,11 +568,16 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id)
return IRQ_HANDLED;
}
+static struct thermal_sensor_conf exynos4_sensor_conf = {
+ .name = "exynos4-therm",
+ .read_temperature = (int (*)(void *))exynos4_tmu_read,
+};
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
+ int ret, i;
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -334,6 +648,24 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
exynos4_tmu_control(pdev, true);
+ /*Register the sensor with thermal management interface*/
+ (&exynos4_sensor_conf)->private_data = data;
+ exynos4_sensor_conf.trip_data.trip_count = 3;
+ for (i = 0; i < exynos4_sensor_conf.trip_data.trip_count; i++)
+ exynos4_sensor_conf.trip_data.trip_val[i] =
+ pdata->threshold + pdata->trigger_levels[i + 1];
+
+ exynos4_sensor_conf.cooling_data.freq_clip_count =
+ pdata->freq_tab_count;
+ for (i = 0; i < pdata->freq_tab_count; i++)
+ exynos4_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
+ pdata->freq_tab[i].freq_clip_max;
+
+ ret = exynos4_register_thermal(&exynos4_sensor_conf);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register thermal interface\n");
+ goto err_clk;
+ }
return 0;
err_clk:
platform_set_drvdata(pdev, NULL);
@@ -356,6 +688,8 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
exynos4_tmu_control(pdev, false);
+ exynos4_unregister_thermal();
+
clk_put(data->clk);
free_irq(data->irq, data);
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h
index 39e038c..ae32f19 100644
--- a/include/linux/platform_data/exynos4_tmu.h
+++ b/include/linux/platform_data/exynos4_tmu.h
@@ -21,6 +21,7 @@
#ifndef _LINUX_EXYNOS4_TMU_H
#define _LINUX_EXYNOS4_TMU_H
+#include <linux/cpu_cooling.h>
enum calibration_type {
TYPE_ONE_POINT_TRIMMING,
@@ -64,6 +65,9 @@ enum calibration_type {
* in the positive-TC generator block
* 0 <= reference_voltage <= 31
* @cal_type: calibration type 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.
*
* This structure is required for configuration of exynos4_tmu driver.
*/
@@ -79,5 +83,8 @@ struct exynos4_tmu_platform_data {
u8 reference_voltage;
enum calibration_type cal_type;
+
+ struct freq_clip_table freq_tab[4];
+ unsigned int freq_tab_count;
};
#endif /* _LINUX_EXYNOS4_TMU_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 6/6] ARM: exynos4: Add thermal sensor driver platform device support
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds necessary source definations needed for TMU driver and
the platform device support.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
arch/arm/mach-exynos/Kconfig | 11 +++++++
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 ++
arch/arm/mach-exynos/dev-tmu.c | 39 ++++++++++++++++++++++++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/thermal/exynos4_thermal.c | 47 +++++++++++++++++++++++++++++
9 files changed, 107 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5d602f6..03968a6 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -160,6 +160,16 @@ config EXYNOS4_SETUP_SPI
help
Common setup code for SPI GPIO configurations.
+config EXYNOS4_DEV_TMU
+ bool "Exynos4 tmu device support"
+ default n
+ depends on ARCH_EXYNOS4
+ ---help---
+ Compile in platform device definitions for TMU. This macro also
+ enables compilation hwmon base TMU driver and also allows compilation
+ of the platform device files. The platform data in this case is trip
+ temperature and some tmu h/w configurations related parameter.
+
# machine support
if ARCH_EXYNOS4
@@ -199,6 +209,7 @@ config MACH_SMDKV310
select SAMSUNG_DEV_PWM
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_DEV_TMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 5fc202c..9b62e69 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
+obj-$(CONFIG_EXYNOS4_DEV_TMU) += dev-tmu.o
obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 187287a..3b15397 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -560,6 +560,10 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 15),
}, {
+ .name = "tmu_apbif",
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
.name = "keypad",
.enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 16),
diff --git a/arch/arm/mach-exynos/dev-tmu.c b/arch/arm/mach-exynos/dev-tmu.c
new file mode 100644
index 0000000..e37f0f5
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-tmu.c
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos4/dev-tmu.c
+ *
+ * Copyright 2011 by SAMSUNG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/exynos4_tmu.h>
+#include <asm/irq.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+
+static struct resource exynos4_tmu_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_TMU,
+ .end = EXYNOS4_PA_TMU + 0xFFFF - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TMU_TRIG0,
+ .end = IRQ_TMU_TRIG0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos4_device_tmu = {
+ .name = "exynos4-tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos4_tmu_resource),
+ .resource = exynos4_tmu_resource,
+};
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index f77bce0..f98d2e4 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -128,6 +128,8 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
+#define IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4)
+#define IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4)
#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22..bc11f1f 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -66,6 +66,7 @@
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_TWD 0x10500600
#define EXYNOS4_PA_L2CC 0x10502000
+#define EXYNOS4_PA_TMU 0x100C0000
#define EXYNOS4_PA_MDMA 0x10810000
#define EXYNOS4_PA_PDMA0 0x12680000
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 0679b8a..5d56e53 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -630,6 +630,7 @@ static struct platform_device *origen_devices[] __initdata = {
&exynos4_device_pd[PD_MFC],
&origen_device_gpiokeys,
&origen_lcd_hv070wsa,
+ &exynos4_device_tmu,
};
/* LCD Backlight data */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0..0960405 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -130,6 +130,7 @@ extern struct platform_device exynos4_device_pcm2;
extern struct platform_device exynos4_device_pd[];
extern struct platform_device exynos4_device_spdif;
extern struct platform_device exynos4_device_sysmmu;
+extern struct platform_device exynos4_device_tmu;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device samsung_asoc_idma;
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index e5be944..7f8b867 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -573,12 +573,58 @@ static struct thermal_sensor_conf exynos4_sensor_conf = {
.read_temperature = (int (*)(void *))exynos4_tmu_read,
};
+#if defined(CONFIG_CPU_EXYNOS4210)
+static struct exynos4_tmu_platform_data exynos4_default_tmu_data = {
+ .threshold = 80,
+ .trigger_levels[0] = 2,
+ .trigger_levels[1] = 5,
+ .trigger_levels[2] = 20,
+ .trigger_levels[3] = 30,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 1,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ },
+ .freq_tab_count = 2,
+};
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)&exynos4_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+static struct platform_device_id exynos4_tmu_driver_ids[] = {
+ {
+ .name = "exynos4-tmu",
+ .driver_data = EXYNOS4210_TMU_DRV_DATA,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids);
+
+static inline struct exynos4_tmu_platform_data *exynos4_get_driver_data(
+ struct platform_device *pdev)
+{
+ return (struct exynos4_tmu_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
int ret, i;
+ if (!pdata)
+ pdata = exynos4_get_driver_data(pdev);
+
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV;
@@ -733,6 +779,7 @@ static struct platform_driver exynos4_tmu_driver = {
.remove = __devexit_p(exynos4_tmu_remove),
.suspend = exynos4_tmu_suspend,
.resume = exynos4_tmu_resume,
+ .id_table = exynos4_tmu_driver_ids,
};
module_platform_driver(exynos4_tmu_driver);
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH V2 6/6] ARM: exynos4: Add thermal sensor driver platform device support
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:17 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linux-kernel, mjg59, linux-acpi, lenb, linaro-dev, lm-sensors,
amit.kachhap, patches, eduardo.valentin, durgadoss.r
This patch adds necessary source definations needed for TMU driver and
the platform device support.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
arch/arm/mach-exynos/Kconfig | 11 +++++++
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 ++
arch/arm/mach-exynos/dev-tmu.c | 39 ++++++++++++++++++++++++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/thermal/exynos4_thermal.c | 47 +++++++++++++++++++++++++++++
9 files changed, 107 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5d602f6..03968a6 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -160,6 +160,16 @@ config EXYNOS4_SETUP_SPI
help
Common setup code for SPI GPIO configurations.
+config EXYNOS4_DEV_TMU
+ bool "Exynos4 tmu device support"
+ default n
+ depends on ARCH_EXYNOS4
+ ---help---
+ Compile in platform device definitions for TMU. This macro also
+ enables compilation hwmon base TMU driver and also allows compilation
+ of the platform device files. The platform data in this case is trip
+ temperature and some tmu h/w configurations related parameter.
+
# machine support
if ARCH_EXYNOS4
@@ -199,6 +209,7 @@ config MACH_SMDKV310
select SAMSUNG_DEV_PWM
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_DEV_TMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 5fc202c..9b62e69 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
+obj-$(CONFIG_EXYNOS4_DEV_TMU) += dev-tmu.o
obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 187287a..3b15397 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -560,6 +560,10 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 15),
}, {
+ .name = "tmu_apbif",
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
.name = "keypad",
.enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 16),
diff --git a/arch/arm/mach-exynos/dev-tmu.c b/arch/arm/mach-exynos/dev-tmu.c
new file mode 100644
index 0000000..e37f0f5
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-tmu.c
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos4/dev-tmu.c
+ *
+ * Copyright 2011 by SAMSUNG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/exynos4_tmu.h>
+#include <asm/irq.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+
+static struct resource exynos4_tmu_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_TMU,
+ .end = EXYNOS4_PA_TMU + 0xFFFF - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TMU_TRIG0,
+ .end = IRQ_TMU_TRIG0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos4_device_tmu = {
+ .name = "exynos4-tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos4_tmu_resource),
+ .resource = exynos4_tmu_resource,
+};
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index f77bce0..f98d2e4 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -128,6 +128,8 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
+#define IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4)
+#define IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4)
#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22..bc11f1f 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -66,6 +66,7 @@
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_TWD 0x10500600
#define EXYNOS4_PA_L2CC 0x10502000
+#define EXYNOS4_PA_TMU 0x100C0000
#define EXYNOS4_PA_MDMA 0x10810000
#define EXYNOS4_PA_PDMA0 0x12680000
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 0679b8a..5d56e53 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -630,6 +630,7 @@ static struct platform_device *origen_devices[] __initdata = {
&exynos4_device_pd[PD_MFC],
&origen_device_gpiokeys,
&origen_lcd_hv070wsa,
+ &exynos4_device_tmu,
};
/* LCD Backlight data */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0..0960405 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -130,6 +130,7 @@ extern struct platform_device exynos4_device_pcm2;
extern struct platform_device exynos4_device_pd[];
extern struct platform_device exynos4_device_spdif;
extern struct platform_device exynos4_device_sysmmu;
+extern struct platform_device exynos4_device_tmu;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device samsung_asoc_idma;
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index e5be944..7f8b867 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -573,12 +573,58 @@ static struct thermal_sensor_conf exynos4_sensor_conf = {
.read_temperature = (int (*)(void *))exynos4_tmu_read,
};
+#if defined(CONFIG_CPU_EXYNOS4210)
+static struct exynos4_tmu_platform_data exynos4_default_tmu_data = {
+ .threshold = 80,
+ .trigger_levels[0] = 2,
+ .trigger_levels[1] = 5,
+ .trigger_levels[2] = 20,
+ .trigger_levels[3] = 30,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 1,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ },
+ .freq_tab_count = 2,
+};
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)&exynos4_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+static struct platform_device_id exynos4_tmu_driver_ids[] = {
+ {
+ .name = "exynos4-tmu",
+ .driver_data = EXYNOS4210_TMU_DRV_DATA,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids);
+
+static inline struct exynos4_tmu_platform_data *exynos4_get_driver_data(
+ struct platform_device *pdev)
+{
+ return (struct exynos4_tmu_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
int ret, i;
+ if (!pdata)
+ pdata = exynos4_get_driver_data(pdev);
+
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV;
@@ -733,6 +779,7 @@ static struct platform_driver exynos4_tmu_driver = {
.remove = __devexit_p(exynos4_tmu_remove),
.suspend = exynos4_tmu_suspend,
.resume = exynos4_tmu_resume,
+ .id_table = exynos4_tmu_driver_ids,
};
module_platform_driver(exynos4_tmu_driver);
--
1.7.1
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
Changes since V1:
*Moved the sensor driver to driver/thermal folder from driver/hwmon folder
as suggested by Mark Brown and Guenter Roeck
*Added notifier support to notify the registered drivers of any cpu cooling
action. The driver can modify the default cooling behaviour(eg set different
max clip frequency).
*The percentage based frequency replaced with absolute clipped frequency.
*Some more conditional checks when setting max frequency.
*Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
THERMAL_TRIP_STATE_INSTANCE
*Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
eduardo.valentin@ti.com implemented.
*Removed cooling stats through debugfs patch
*The V1 based can be found here,
https://lkml.org/lkml/2012/2/22/123
http://lkml.org/lkml/2012/3/3/32
Changes since RFC:
*Changed the cpu cooling registration/unregistration API's to instance based
*Changed the STATE_ACTIVE trip type to pass correct instance id
*Adding support to restore back the policy->max_freq after doing frequency
clipping.
*Moved the trip cooling stats from sysfs node to debugfs node as suggested
by Greg KH greg@kroah.com
*Incorporated several review comments from eduardo.valentin@ti.com
*Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
*Some changes according to the changes in common cpu cooling APIs
*The RFC based patches can be found here,
https://lkml.org/lkml/2011/12/13/186
https://lkml.org/lkml/2011/12/21/169
Brief Description:
1) The generic cooling devices code is placed inside driver/thermal/* as
placing inside acpi folder will need un-necessary enabling of acpi code. This
codes is architecture independent.
2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
cooling device instance number and may be helpful for cpufreq cooling devices
to take the correct cooling action. This trip type avoids the temperature
comparision check again inside the cooling handler.
3) This patchset adds generic cpu cooling low level implementation through
frequency clipping and cpu hotplug. In future, other cpu related cooling
devices may be added here. An ACPI version of this already exists
(drivers/acpi/processor_thermal.c). But this will be useful for platforms
like ARM using the generic thermal interface along with the generic cpu
cooling devices. The cooling device registration API's return cooling device
pointers which can be easily binded with the thermal zone trip points.
The important APIs exposed are,
a)struct thermal_cooling_device *cpufreq_cooling_register(
struct freq_clip_table *tab_ptr, unsigned int tab_size,
const struct cpumask *mask_val)
b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
4) Samsung exynos platform thermal implementation is done using the generic
cpu cooling APIs and the new trip type. The temperature sensor driver present
in the hwmon folder(registered as hwmon driver) is moved to thermal folder
and registered as a thermal driver.
All this patchset is based on Kernel version 3.3-rc7
A simple data/control flow diagrams is shown below,
Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
| |
\|/ |
Cpufreq cooling device <---------------
Amit Daniel Kachhap (6):
thermal: Add a new trip type to use cooling device instance number
thermal: Add generic cpufreq cooling implementation
thermal: Add generic cpuhotplug cooling implementation
hwmon: exynos4: Move thermal sensor driver to driver/thermal
directory
thermal: exynos4: Register the tmu sensor with the kernel thermal
layer
ARM: exynos4: Add thermal sensor driver platform device support
Documentation/hwmon/exynos4_tmu | 81 ---
Documentation/thermal/cpu-cooling-api.txt | 76 +++
Documentation/thermal/exynos4_tmu | 52 ++
Documentation/thermal/sysfs-api.txt | 4 +-
arch/arm/mach-exynos/Kconfig | 11 +
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 +
arch/arm/mach-exynos/dev-tmu.c | 39 ++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------
drivers/thermal/Kconfig | 21 +
drivers/thermal/Makefile | 2 +
drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
drivers/thermal/thermal_sys.c | 45 ++-
include/linux/cpu_cooling.h | 78 +++
include/linux/platform_data/exynos4_tmu.h | 7 +
include/linux/thermal.h | 1 +
23 files changed, 1660 insertions(+), 611 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 Documentation/thermal/exynos4_tmu
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 drivers/thermal/exynos4_thermal.c
create mode 100644 include/linux/cpu_cooling.h
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 1/6] thermal: Add a new trip type to use cooling device instance number
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds a new trip type THERMAL_TRIP_STATE_INSTANCE. This
trip behaves same as THERMAL_TRIP_ACTIVE but also passes the cooling
device instance number. This helps the cooling device registered as
different instances to perform appropriate cooling action decision in
the set_cur_state call back function.
Also since the trip temperature's are in ascending order so some logic
is put in place to skip the un-necessary checks.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/sysfs-api.txt | 4 +-
drivers/thermal/thermal_sys.c | 45 ++++++++++++++++++++++++++++++++--
include/linux/thermal.h | 1 +
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 1733ab9..9a7c69c 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -184,8 +184,8 @@ trip_point_[0-*]_temp
trip_point_[0-*]_type
Strings which indicate the type of the trip point.
- E.g. it can be one of critical, hot, passive, active[0-*] for ACPI
- thermal zone.
+ E.g. it can be one of critical, hot, passive, active[0-1],
+ state-instance[0-*] for ACPI thermal zone.
RO, Optional
cdev[0-*]
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 220ce7e..9fc2150 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -192,6 +192,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_STATE_INSTANCE:
+ return sprintf(buf, "state-instance\n");
default:
return sprintf(buf, "unknown\n");
}
@@ -1034,10 +1036,10 @@ EXPORT_SYMBOL(thermal_cooling_device_unregister);
void thermal_zone_device_update(struct thermal_zone_device *tz)
{
- int count, ret = 0;
- long temp, trip_temp;
+ int count, ret = 0, inst_id;
+ long temp, trip_temp, max_state, last_trip_change = 0;
enum thermal_trip_type trip_type;
- struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device_instance *instance, *state_instance;
struct thermal_cooling_device *cdev;
mutex_lock(&tz->lock);
@@ -1086,6 +1088,43 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
cdev->ops->set_cur_state(cdev, 0);
}
break;
+ case THERMAL_TRIP_STATE_INSTANCE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ if (temp <= last_trip_change)
+ continue;
+
+ inst_id = 0;
+ /*
+ *For this instance how many instance of same
+ *cooling device occured before
+ */
+
+ list_for_each_entry(state_instance,
+ &tz->cooling_devices, node) {
+ if (instance->cdev =
+ state_instance->cdev)
+ inst_id++;
+ if (state_instance->trip = count)
+ break;
+ }
+
+ cdev = instance->cdev;
+ cdev->ops->get_max_state(cdev, &max_state);
+
+ if ((temp >= trip_temp) &&
+ (inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+ else if ((temp < trip_temp) &&
+ (--inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+
+ last_trip_change = trip_temp;
+ }
+ break;
case THERMAL_TRIP_PASSIVE:
if (temp >= trip_temp || tz->passive)
thermal_zone_device_passive(tz, temp,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 796f1ff..583fbda 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -42,6 +42,7 @@ enum thermal_trip_type {
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_STATE_INSTANCE,
};
struct thermal_zone_device_ops {
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 2/6] thermal: Add generic cpufreq cooling implementation
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds support for generic cpu thermal cooling low level
implementations using frequency scaling up/down based on the registration
parameters. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing clipping frequency . The drivers can also register to recieve
notification about any cooling action called. Even the driver can effect
the cooling action by modifying the default data such as freq_clip_max if
needed.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 60 +++++
drivers/thermal/Kconfig | 11 +
drivers/thermal/Makefile | 1 +
drivers/thermal/cpu_cooling.c | 359 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 61 +++++
5 files changed, 492 insertions(+), 0 deletions(-)
create mode 100644 Documentation/thermal/cpu-cooling-api.txt
create mode 100644 drivers/thermal/cpu_cooling.c
create mode 100644 include/linux/cpu_cooling.h
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
new file mode 100644
index 0000000..3720341
--- /dev/null
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -0,0 +1,60 @@
+CPU cooling APIs How To
+=================+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 9 March 2012
+
+Copyright (c) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+
+The generic cpu cooling(freq clipping, cpuhotplug) provides
+registration/unregistration APIs to the caller. The binding of the cooling
+devices to the trip point is left for the user. The registration APIs returns
+the cooling device pointer.
+
+1. cpu cooling APIs
+
+1.1 cpufreq registration/unregistration APIs
+1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpufreq cooling device with the name
+ "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+ cooling devices.
+
+ tab_ptr: The table containing the maximum value of frequency to be clipped
+ for each cooling state.
+ .freq_clip_max: Value of frequency to be clipped for each allowed
+ cpus.
+ tab_size: the total number of cpufreq cooling states.
+ mask_val: all the allowed cpu's where frequency clipping can happen.
+
+1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+ cdev: Cooling device pointer which has to be unregistered.
+
+
+2. CPU cooling action notifier interface
+
+2.1 int cputherm_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
+
+2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f7f71b2..df738f2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -18,3 +18,14 @@ config THERMAL_HWMON
depends on THERMAL
depends on HWMON=y || HWMON=THERMAL
default y
+
+config CPU_THERMAL
+ bool "generic cpu cooling support"
+ depends on THERMAL && CPU_FREQ
+ help
+ This implements the generic cpu cooling mechanism through frequency
+ reduction, cpu hotplug and any other ways of reducing temperature. An
+ ACPI version of this already exists(drivers/acpi/processor_thermal.c).
+ This will be useful for platforms using the generic thermal interface
+ and not the ACPI interface.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31108a0..655cbc4 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
+obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
new file mode 100644
index 0000000..ee2c96d
--- /dev/null
+++ b/drivers/thermal/cpu_cooling.c
@@ -0,0 +1,359 @@
+/*
+ * linux/drivers/thermal/cpu_cooling.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/cpu_cooling.h>
+
+struct cpufreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ struct freq_clip_table *tab_ptr;
+ unsigned int tab_size;
+ unsigned int cpufreq_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpufreq_list);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
+static DEFINE_IDR(cpufreq_idr);
+static DEFINE_PER_CPU(unsigned int, max_policy_freq);
+static struct freq_clip_table *notify_table;
+static int notify_state;
+static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+ int err;
+again:
+ if (unlikely(idr_pre_get(idr, GFP_KERNEL) = 0))
+ return -ENOMEM;
+
+ if (lock)
+ mutex_lock(lock);
+ err = idr_get_new(idr, NULL, id);
+ if (lock)
+ mutex_unlock(lock);
+ if (unlikely(err = -EAGAIN))
+ goto again;
+ else if (unlikely(err))
+ return err;
+
+ *id = *id & MAX_ID_MASK;
+ return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+ if (lock)
+ mutex_lock(lock);
+ idr_remove(idr, id);
+ if (lock)
+ mutex_unlock(lock);
+}
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_register(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_register_notifier);
+
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_unregister(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_unregister_notifier);
+
+/*Below codes defines functions to be used for cpufreq as cooling device*/
+static bool is_cpufreq_valid(int cpu)
+{
+ struct cpufreq_policy policy;
+ return !cpufreq_get_policy(&policy, cpu) ? true : false;
+}
+
+static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+ unsigned long cooling_state)
+{
+ unsigned int event, cpuid;
+ struct freq_clip_table *th_table;
+
+ if (cooling_state > cpufreq_device->tab_size)
+ return -EINVAL;
+
+ cpufreq_device->cpufreq_state = cooling_state;
+
+ /*cpufreq thermal notifier uses this cpufreq device pointer*/
+ notify_state = cooling_state;
+
+ if (notify_state > 0) {
+ th_table = &(cpufreq_device->tab_ptr[cooling_state - 1]);
+ memcpy(notify_table, th_table, sizeof(struct freq_clip_table));
+ event = CPUFREQ_COOLING_TYPE;
+ blocking_notifier_call_chain(&cputherm_state_notifier_list,
+ event, notify_table);
+ }
+
+ for_each_cpu(cpuid, cpufreq_device->allowed_cpus) {
+ if (is_cpufreq_valid(cpuid))
+ cpufreq_update_policy(cpuid);
+ }
+
+ notify_state = -1;
+
+ return 0;
+}
+
+static int cpufreq_thermal_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned long max_freq = 0;
+
+ if ((event != CPUFREQ_ADJUST) || (notify_state = -1))
+ return 0;
+
+ if (notify_state > 0) {
+ max_freq = notify_table->freq_clip_max;
+
+ if (per_cpu(max_policy_freq, policy->cpu) = 0)
+ per_cpu(max_policy_freq, policy->cpu) = policy->max;
+ } else {
+ if (per_cpu(max_policy_freq, policy->cpu) != 0) {
+ max_freq = per_cpu(max_policy_freq, policy->cpu);
+ per_cpu(max_policy_freq, policy->cpu) = 0;
+ } else {
+ max_freq = policy->max;
+ }
+ }
+
+ /* Never exceed user_policy.max*/
+ if (max_freq > policy->user_policy.max)
+ max_freq = policy->user_policy.max;
+
+ if (policy->max != max_freq)
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+
+ return 0;
+}
+
+/*
+ * cpufreq cooling device callback functions
+ */
+static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev = cdev) {
+ *state = cpufreq_device->tab_size;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev = cdev) {
+ *state = cpufreq_device->cpufreq_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+/*This cooling may be as PASSIVE/ACTIVE type*/
+static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev = cdev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ if (!ret)
+ ret = cpufreq_apply_cooling(cpufreq_device, state);
+
+ return ret;
+}
+
+/* bind cpufreq callbacks to cpufreq cooling device */
+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+ .get_max_state = cpufreq_get_max_state,
+ .get_cur_state = cpufreq_get_cur_state,
+ .set_cur_state = cpufreq_set_cur_state,
+};
+
+static struct notifier_block thermal_cpufreq_notifier_block = {
+ .notifier_call = cpufreq_thermal_notifier,
+};
+
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0, id = 0, i;
+
+ if (tab_ptr = NULL || tab_size = 0)
+ return ERR_PTR(-EINVAL);
+
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
+ cpufreq_dev_count++;
+
+ cpufreq_dev + kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL);
+
+ if (!cpufreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (cpufreq_dev_count = 0) {
+ notify_table = kzalloc(sizeof(struct freq_clip_table),
+ GFP_KERNEL);
+ if (!notify_table) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ cpufreq_dev->tab_ptr = tab_ptr;
+ cpufreq_dev->tab_size = tab_size;
+ cpufreq_dev->allowed_cpus = mask_val;
+
+ /* Initialize all the tab_ptr->mask_val to the passed mask_val */
+ for (i = 0; i < tab_size; i++)
+ ((struct freq_clip_table *)&tab_ptr[i])->mask_val = mask_val;
+
+ ret = get_idr(&cpufreq_idr, &cooling_cpufreq_lock, &cpufreq_dev->id);
+ if (ret) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
+ &cpufreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock,
+ cpufreq_dev->id);
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ cpufreq_dev->id = id;
+ cpufreq_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpufreq_lock);
+ list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Register the notifier for first cpufreq cooling device*/
+ if (cpufreq_dev_count = 0)
+ cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpufreq_cooling_register);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
+ if (cpufreq_dev && cpufreq_dev->cool_dev = cdev)
+ break;
+ cpufreq_dev_count++;
+ }
+
+ if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpufreq_lock);
+ return;
+ }
+
+ list_del(&cpufreq_dev->node);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Unregister the notifier for the last cpufreq cooling device*/
+ if (cpufreq_dev_count = 1) {
+ cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ kfree(notify_table);
+ }
+
+ thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock, cpufreq_dev->id);
+ kfree(cpufreq_dev);
+}
+EXPORT_SYMBOL(cpufreq_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
new file mode 100644
index 0000000..12efa01
--- /dev/null
+++ b/include/linux/cpu_cooling.h
@@ -0,0 +1,61 @@
+/*
+ * linux/include/linux/cpu_cooling.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * 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 __CPU_COOLING_H__
+#define __CPU_COOLING_H__
+
+#include <linux/thermal.h>
+
+#define CPUFREQ_COOLING_TYPE 0
+#define CPUHOTPLUG_COOLING_TYPE 1
+
+struct freq_clip_table {
+ unsigned int freq_clip_max;
+ unsigned int temp_level;
+ const struct cpumask *mask_val;
+};
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list);
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#ifdef CONFIG_CPU_FREQ
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_CPU_FREQ*/
+static inline struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpufreq_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_CPU_FREQ*/
+
+#endif /* __CPU_COOLING_H__ */
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds support for generic cpu thermal cooling low level
implementations using cpuhotplug based on the thermal level requested
from user. Different cpu related cooling devices can be registered by the
user and the binding of these cooling devices to the corresponding
trip points can be easily done as the registration APIs return the
cooling device pointer. The user of these APIs are responsible for
passing the cpumask.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
Documentation/thermal/cpu-cooling-api.txt | 16 +++
drivers/thermal/Kconfig | 2 +-
drivers/thermal/cpu_cooling.c | 170 +++++++++++++++++++++++++++++
include/linux/cpu_cooling.h | 17 +++
4 files changed, 204 insertions(+), 1 deletions(-)
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
index 3720341..6eb648e 100644
--- a/Documentation/thermal/cpu-cooling-api.txt
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -38,6 +38,22 @@ the cooling device pointer.
cdev: Cooling device pointer which has to be unregistered.
+1.2 cpuhotplug registration APIs
+1.2.1 struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpuhotplug cooling device with the name
+ "cpu-hotplug-%x". This api can support multiple instances of cpuhotplug
+ cooling devices.
+
+ mask_val: all the allowed cpu's which can be hotplugged out.
+
+1.1.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpuhotplug-%x" cooling
+ device.
+
+ cdev: Cooling device pointer which has to be unregistered.
2. CPU cooling action notifier interface
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index df738f2..24c43e3 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -21,7 +21,7 @@ config THERMAL_HWMON
config CPU_THERMAL
bool "generic cpu cooling support"
- depends on THERMAL && CPU_FREQ
+ depends on THERMAL && CPU_FREQ && HOTPLUG_CPU
help
This implements the generic cpu cooling mechanism through frequency
reduction, cpu hotplug and any other ways of reducing temperature. An
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index ee2c96d..1f3aa79 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -46,6 +46,19 @@ static DEFINE_IDR(cpufreq_idr);
static DEFINE_PER_CPU(unsigned int, max_policy_freq);
static struct freq_clip_table *notify_table;
static int notify_state;
+
+struct hotplug_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int hotplug_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpuhotplug_list);
+static DEFINE_MUTEX(cooling_cpuhotplug_lock);
+static DEFINE_IDR(cpuhotplug_idr);
+
static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
@@ -357,3 +370,160 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
kfree(cpufreq_dev);
}
EXPORT_SYMBOL(cpufreq_cooling_unregister);
+
+/*
+ * cpu hotplug cooling device callback functions
+ */
+static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev = cdev) {
+ *state = 1;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev = cdev) {
+ *state = hotplug_dev->hotplug_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+/*This cooling may be as ACTIVE type*/
+static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int cpuid, this_cpu = smp_processor_id();
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev = cdev)
+ break;
+
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
+ return -EINVAL;
+
+ if (hotplug_dev->hotplug_state = state)
+ return 0;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ if (state = 1) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_down(cpuid);
+ }
+ } else if (state = 0) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (!cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_up(cpuid);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ hotplug_dev->hotplug_state = state;
+
+ return 0;
+}
+/* bind hotplug callbacks to cpu hotplug cooling device */
+static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
+ .get_max_state = cpuhotplug_get_max_state,
+ .get_cur_state = cpuhotplug_get_cur_state,
+ .set_cur_state = cpuhotplug_set_cur_state,
+};
+
+struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct hotplug_cooling_device *hotplug_dev;
+ int ret = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+
+ hotplug_dev + kzalloc(sizeof(struct hotplug_cooling_device), GFP_KERNEL);
+
+ if (!hotplug_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ &hotplug_dev->id);
+ if (ret) {
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "cpu-hotplug-%u", hotplug_dev->id);
+
+ hotplug_dev->hotplug_state = 0;
+ hotplug_dev->allowed_cpus = mask_val;
+ cool_dev = thermal_cooling_device_register(dev_name, hotplug_dev,
+ &cpuhotplug_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ hotplug_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_add_tail(&hotplug_dev->node, &cooling_cpuhotplug_list);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_register);
+
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct hotplug_cooling_device *hotplug_dev = NULL;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev = cdev)
+ break;
+
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return;
+ }
+
+ list_del(&hotplug_dev->node);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ thermal_cooling_device_unregister(hotplug_dev->cool_dev);
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_unregister);
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 12efa01..5a3698c 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -57,5 +57,22 @@ static inline void cpufreq_cooling_unregister(
return;
}
#endif /*CONFIG_CPU_FREQ*/
+#ifdef CONFIG_HOTPLUG_CPU
+extern struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val);
+
+extern void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_HOTPLUG_CPU*/
+static inline struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpuhotplug_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_HOTPLUG_CPU*/
#endif /* __CPU_COOLING_H__ */
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 4/6] hwmon: exynos4: Move thermal sensor driver to driver/thermal directory
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This movement is needed because the hwmon entries and corresponding
sysfs interface is a duplicate of utilities already provided by
driver/thermal/thermal_sys.c. The goal is to place it in thermal folder
and add necessary functions to use the in-kernel thermal interfaces.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
---
Documentation/hwmon/exynos4_tmu | 81 ------
Documentation/thermal/exynos4_tmu | 52 ++++
drivers/hwmon/Kconfig | 10 -
drivers/hwmon/Makefile | 1 -
drivers/hwmon/exynos4_tmu.c | 514 -------------------------------------
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 1 +
drivers/thermal/exynos4_thermal.c | 409 +++++++++++++++++++++++++++++
8 files changed, 472 insertions(+), 606 deletions(-)
delete mode 100644 Documentation/hwmon/exynos4_tmu
create mode 100644 Documentation/thermal/exynos4_tmu
delete mode 100644 drivers/hwmon/exynos4_tmu.c
create mode 100644 drivers/thermal/exynos4_thermal.c
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu
deleted file mode 100644
index c3c6b41..0000000
--- a/Documentation/hwmon/exynos4_tmu
+++ /dev/null
@@ -1,81 +0,0 @@
-Kernel driver exynos4_tmu
-========-
-Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
- Prefix: 'exynos4-tmu'
- Datasheet: Not publicly available
-
-Authors: Donggeun Kim <dg77.kim@samsung.com>
-
-Description
------------
-
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
-
-The chip only exposes the measured 8-bit temperature code value
-through a register.
-Temperature can be taken from the temperature code.
-There are three equations converting from temperature to temperature code.
-
-The three equations are:
- 1. Two point trimming
- Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
-
- 2. One point trimming
- Tc = T + TI1 - 25
-
- 3. No trimming
- Tc = T + 50
-
- Tc: Temperature code, T: Temperature,
- TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
- Temperature code measured at 25 degree Celsius which is unchanged
- 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
-when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
-The threshold levels are defined as follows:
- Level_0: current temperature > trigger_level_0 + threshold
- Level_1: current temperature > trigger_level_1 + threshold
- Level_2: current temperature > trigger_level_2 + threshold
- Level_3: current temperature > trigger_level_3 + threshold
-
- The threshold and each trigger_level are set
- through the corresponding registers.
-
-When an interrupt occurs, this driver notify user space of
-one of four threshold levels for the interrupt
-through kobject_uevent_env and sysfs_notify functions.
-Although an interrupt condition for level_0 can be set,
-it is not notified to user space through sysfs_notify function.
-
-Sysfs Interface
----------------
-name name of the temperature sensor
- RO
-
-temp1_input temperature
- RO
-
-temp1_max temperature for level_1 interrupt
- RO
-
-temp1_crit temperature for level_2 interrupt
- RO
-
-temp1_emergency temperature for level_3 interrupt
- RO
-
-temp1_max_alarm alarm for level_1 interrupt
- RO
-
-temp1_crit_alarm
- alarm for level_2 interrupt
- RO
-
-temp1_emergency_alarm
- alarm for level_3 interrupt
- RO
diff --git a/Documentation/thermal/exynos4_tmu b/Documentation/thermal/exynos4_tmu
new file mode 100644
index 0000000..2b46f67
--- /dev/null
+++ b/Documentation/thermal/exynos4_tmu
@@ -0,0 +1,52 @@
+Kernel driver exynos4_tmu
+========+
+Supported chips:
+* ARM SAMSUNG EXYNOS4 series of SoC
+ Prefix: 'exynos4-tmu'
+ Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+
+Description
+-----------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+ 1. Two point trimming
+ Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+ 2. One point trimming
+ Tc = T + TI1 - 25
+
+ 3. No trimming
+ Tc = T + 50
+
+ Tc: Temperature code, T: Temperature,
+ TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+ Temperature code measured at 25 degree Celsius which is unchanged
+ 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
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is four.
+The threshold levels are defined as follows:
+ Level_0: current temperature > trigger_level_0 + threshold
+ Level_1: current temperature > trigger_level_1 + threshold
+ Level_2: current temperature > trigger_level_2 + threshold
+ Level_3: current temperature > trigger_level_3 + threshold
+
+ The threshold and each trigger_level are set
+ through the corresponding registers.
+
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos4_report_trigger.
+Although an interrupt condition for level_0 can be set,
+it can be used to synchronize the cooling action.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index dad895f..5a29885 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -313,16 +313,6 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
-config SENSORS_EXYNOS4_TMU
- tristate "Temperature sensor on Samsung EXYNOS4"
- depends on ARCH_EXYNOS4
- help
- If you say yes here you get support for TMU (Thermal Managment
- Unit) on SAMSUNG EXYNOS4 series of SoC.
-
- This driver can also be built as a module. If so, the module
- will be called exynos4-tmu.
-
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..228a4b7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
-obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c
deleted file mode 100644
index f2359a0..0000000
--- a/drivers/hwmon/exynos4_tmu.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
- *
- * Copyright (C) 2011 Samsung Electronics
- * Donggeun Kim <dg77.kim@samsung.com>
- *
- * 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/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/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
-#include <linux/platform_data/exynos4_tmu.h>
-
-#define EXYNOS4_TMU_REG_TRIMINFO 0x0
-#define EXYNOS4_TMU_REG_CONTROL 0x20
-#define EXYNOS4_TMU_REG_STATUS 0x28
-#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
-#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
-#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
-#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
-#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
-#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
-#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
-#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
-#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
-#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
-#define EXYNOS4_TMU_REG_INTEN 0x70
-#define EXYNOS4_TMU_REG_INTSTAT 0x74
-#define EXYNOS4_TMU_REG_INTCLEAR 0x78
-
-#define EXYNOS4_TMU_GAIN_SHIFT 8
-#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
-
-#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
-#define EXYNOS4_TMU_CORE_ON 3
-#define EXYNOS4_TMU_CORE_OFF 2
-#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
-#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
-#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
-#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
-#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
-#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
-
-struct exynos4_tmu_data {
- struct exynos4_tmu_platform_data *pdata;
- struct device *hwmon_dev;
- struct resource *mem;
- void __iomem *base;
- int irq;
- struct work_struct irq_work;
- struct mutex lock;
- struct clk *clk;
- u8 temp_error1, temp_error2;
-};
-
-/*
- * TMU treats temperature as a mapped temperature code.
- * The temperature is converted differently depending on the calibration type.
- */
-static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp_code;
-
- /* temp should range between 25 and 125 */
- if (temp < 25 || temp > 125) {
- temp_code = -EINVAL;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp_code = (temp - 25) *
- (data->temp_error2 - data->temp_error1) /
- (85 - 25) + data->temp_error1;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp_code = temp + data->temp_error1 - 25;
- break;
- default:
- temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp_code;
-}
-
-/*
- * Calculate a temperature value from a temperature code.
- * The unit of the temperature is degree Celsius.
- */
-static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
-{
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
-
- /* temp_code should range between 75 and 175 */
- if (temp_code < 75 || temp_code > 175) {
- temp = -ENODATA;
- goto out;
- }
-
- switch (pdata->cal_type) {
- case TYPE_TWO_POINT_TRIMMING:
- temp = (temp_code - data->temp_error1) * (85 - 25) /
- (data->temp_error2 - data->temp_error1) + 25;
- break;
- case TYPE_ONE_POINT_TRIMMING:
- temp = temp_code - data->temp_error1 + 25;
- break;
- default:
- temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
- break;
- }
-out:
- return temp;
-}
-
-static int exynos4_tmu_initialize(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int status, trim_info;
- int ret = 0, threshold_code;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
- if (!status) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Save trimming info in order to perform calibration */
- trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
- data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
- data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
-
- /* Write temperature code for threshold */
- threshold_code = temp_to_code(data, pdata->threshold);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
- }
- writeb(threshold_code,
- data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
-
- writeb(pdata->trigger_levels[0],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
- writeb(pdata->trigger_levels[1],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
- writeb(pdata->trigger_levels[2],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
- writeb(pdata->trigger_levels[3],
- data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL,
- data->base + EXYNOS4_TMU_REG_INTCLEAR);
-out:
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return ret;
-}
-
-static void exynos4_tmu_control(struct platform_device *pdev, bool on)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int con, interrupt_en;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
- pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
- if (on) {
- con |= EXYNOS4_TMU_CORE_ON;
- interrupt_en = pdata->trigger_level3_en << 12 |
- pdata->trigger_level2_en << 8 |
- pdata->trigger_level1_en << 4 |
- pdata->trigger_level0_en;
- } else {
- con |= EXYNOS4_TMU_CORE_OFF;
- interrupt_en = 0; /* Disable all interrupts */
- }
- writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
- writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static int exynos4_tmu_read(struct exynos4_tmu_data *data)
-{
- u8 temp_code;
- int temp;
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
- temp = code_to_temp(data, temp_code);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-
- return temp;
-}
-
-static void exynos4_tmu_work(struct work_struct *work)
-{
- struct exynos4_tmu_data *data = container_of(work,
- struct exynos4_tmu_data, irq_work);
-
- mutex_lock(&data->lock);
- clk_enable(data->clk);
-
- writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
-
- kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
-
- enable_irq(data->irq);
-
- clk_disable(data->clk);
- mutex_unlock(&data->lock);
-}
-
-static irqreturn_t exynos4_tmu_irq(int irq, void *id)
-{
- struct exynos4_tmu_data *data = id;
-
- disable_irq_nosync(irq);
- schedule_work(&data->irq_work);
-
- return IRQ_HANDLED;
-}
-
-static ssize_t exynos4_tmu_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "exynos4-tmu\n");
-}
-
-static ssize_t exynos4_tmu_show_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- int ret;
-
- ret = exynos4_tmu_read(data);
- if (ret < 0)
- return ret;
-
- /* convert from degree Celsius to millidegree Celsius */
- return sprintf(buf, "%d\n", ret * 1000);
-}
-
-static ssize_t exynos4_tmu_show_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
- unsigned int trigger_level;
-
- temp = exynos4_tmu_read(data);
- if (temp < 0)
- return temp;
-
- trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%d\n", !!(temp > trigger_level));
-}
-
-static ssize_t exynos4_tmu_show_level(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int temp = pdata->threshold +
- pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%u\n", temp * 1000);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
-
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
- exynos4_tmu_show_level, NULL, 3);
-
-static struct attribute *exynos4_tmu_attributes[] = {
- &dev_attr_name.attr,
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group exynos4_tmu_attr_group = {
- .attrs = exynos4_tmu_attributes,
-};
-
-static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data;
- struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform init data supplied.\n");
- return -ENODEV;
- }
-
- data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "Failed to allocate driver structure\n");
- return -ENOMEM;
- }
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0) {
- ret = data->irq;
- dev_err(&pdev->dev, "Failed to get platform irq\n");
- goto err_free;
- }
-
- INIT_WORK(&data->irq_work, exynos4_tmu_work);
-
- data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!data->mem) {
- ret = -ENOENT;
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- goto err_free;
- }
-
- data->mem = request_mem_region(data->mem->start,
- resource_size(data->mem), pdev->name);
- if (!data->mem) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to request memory region\n");
- goto err_free;
- }
-
- data->base = ioremap(data->mem->start, resource_size(data->mem));
- if (!data->base) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "Failed to ioremap memory\n");
- goto err_mem_region;
- }
-
- ret = request_irq(data->irq, exynos4_tmu_irq,
- IRQF_TRIGGER_RISING,
- "exynos4-tmu", data);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
- goto err_io_remap;
- }
-
- data->clk = clk_get(NULL, "tmu_apbif");
- if (IS_ERR(data->clk)) {
- ret = PTR_ERR(data->clk);
- dev_err(&pdev->dev, "Failed to get clock\n");
- goto err_irq;
- }
-
- data->pdata = pdata;
- platform_set_drvdata(pdev, data);
- mutex_init(&data->lock);
-
- ret = exynos4_tmu_initialize(pdev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to initialize TMU\n");
- goto err_clk;
- }
-
- ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create sysfs group\n");
- goto err_clk;
- }
-
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- dev_err(&pdev->dev, "Failed to register hwmon device\n");
- goto err_create_group;
- }
-
- exynos4_tmu_control(pdev, true);
-
- return 0;
-
-err_create_group:
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-err_clk:
- platform_set_drvdata(pdev, NULL);
- clk_put(data->clk);
-err_irq:
- free_irq(data->irq, data);
-err_io_remap:
- iounmap(data->base);
-err_mem_region:
- release_mem_region(data->mem->start, resource_size(data->mem));
-err_free:
- kfree(data);
-
- return ret;
-}
-
-static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
-{
- struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
-
- exynos4_tmu_control(pdev, false);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
-
- clk_put(data->clk);
-
- free_irq(data->irq, data);
-
- iounmap(data->base);
- release_mem_region(data->mem->start, resource_size(data->mem));
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(data);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
-{
- exynos4_tmu_control(pdev, false);
-
- return 0;
-}
-
-static int exynos4_tmu_resume(struct platform_device *pdev)
-{
- exynos4_tmu_initialize(pdev);
- exynos4_tmu_control(pdev, true);
-
- return 0;
-}
-#else
-#define exynos4_tmu_suspend NULL
-#define exynos4_tmu_resume NULL
-#endif
-
-static struct platform_driver exynos4_tmu_driver = {
- .driver = {
- .name = "exynos4-tmu",
- .owner = THIS_MODULE,
- },
- .probe = exynos4_tmu_probe,
- .remove = __devexit_p(exynos4_tmu_remove),
- .suspend = exynos4_tmu_suspend,
- .resume = exynos4_tmu_resume,
-};
-
-module_platform_driver(exynos4_tmu_driver);
-
-MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:exynos4-tmu");
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 24c43e3..5c5a43c 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -29,3 +29,13 @@ config CPU_THERMAL
This will be useful for platforms using the generic thermal interface
and not the ACPI interface.
If you want this support, you should say Y or M here.
+
+config SENSORS_EXYNOS4_TMU
+ tristate "Temperature sensor on Samsung EXYNOS4"
+ depends on ARCH_EXYNOS4 && THERMAL
+ help
+ If you say yes here you get support for TMU (Thermal Managment
+ Unit) on SAMSUNG EXYNOS4 series of SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called exynos4-tmu.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 655cbc4..d2d01e9 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_THERMAL) += thermal_sys.o
obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
+obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_thermal.o
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
new file mode 100644
index 0000000..ff708d5
--- /dev/null
+++ b/drivers/thermal/exynos4_thermal.c
@@ -0,0 +1,409 @@
+/*
+ * exynos4_thermal.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ * Amit Daniel Kachhap <amit.kachhap@linaro.org>
+ *
+ * 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/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/exynos4_tmu.h>
+
+#define EXYNOS4_TMU_REG_TRIMINFO 0x0
+#define EXYNOS4_TMU_REG_CONTROL 0x20
+#define EXYNOS4_TMU_REG_STATUS 0x28
+#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
+#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
+#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
+#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
+#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
+#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
+#define EXYNOS4_TMU_REG_INTEN 0x70
+#define EXYNOS4_TMU_REG_INTSTAT 0x74
+#define EXYNOS4_TMU_REG_INTCLEAR 0x78
+
+#define EXYNOS4_TMU_GAIN_SHIFT 8
+#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
+
+#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
+#define EXYNOS4_TMU_CORE_ON 3
+#define EXYNOS4_TMU_CORE_OFF 2
+#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
+#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
+#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
+#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
+#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+
+struct exynos4_tmu_data {
+ struct exynos4_tmu_platform_data *pdata;
+ struct resource *mem;
+ void __iomem *base;
+ int irq;
+ struct work_struct irq_work;
+ struct mutex lock;
+ struct clk *clk;
+ u8 temp_error1, temp_error2;
+};
+
+/*
+ * TMU treats temperature as a mapped temperature code.
+ * The temperature is converted differently depending on the calibration type.
+ */
+static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp_code;
+
+ /* temp should range between 25 and 125 */
+ if (temp < 25 || temp > 125) {
+ temp_code = -EINVAL;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp_code = (temp - 25) *
+ (data->temp_error2 - data->temp_error1) /
+ (85 - 25) + data->temp_error1;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp_code = temp + data->temp_error1 - 25;
+ break;
+ default:
+ temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp_code;
+}
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree Celsius.
+ */
+static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp;
+
+ /* temp_code should range between 75 and 175 */
+ if (temp_code < 75 || temp_code > 175) {
+ temp = -ENODATA;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp = (temp_code - data->temp_error1) * (85 - 25) /
+ (data->temp_error2 - data->temp_error1) + 25;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp = temp_code - data->temp_error1 + 25;
+ break;
+ default:
+ temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp;
+}
+
+static int exynos4_tmu_initialize(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int status, trim_info;
+ int ret = 0, threshold_code;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Save trimming info in order to perform calibration */
+ trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
+ data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
+ data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
+
+ /* Write temperature code for threshold */
+ threshold_code = temp_to_code(data, pdata->threshold);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ writeb(threshold_code,
+ data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
+
+ writeb(pdata->trigger_levels[0],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
+ writeb(pdata->trigger_levels[1],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
+ writeb(pdata->trigger_levels[2],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
+ writeb(pdata->trigger_levels[3],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL,
+ data->base + EXYNOS4_TMU_REG_INTCLEAR);
+out:
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static void exynos4_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int con, interrupt_en;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
+ pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
+ if (on) {
+ con |= EXYNOS4_TMU_CORE_ON;
+ interrupt_en = pdata->trigger_level3_en << 12 |
+ pdata->trigger_level2_en << 8 |
+ pdata->trigger_level1_en << 4 |
+ pdata->trigger_level0_en;
+ } else {
+ con |= EXYNOS4_TMU_CORE_OFF;
+ interrupt_en = 0; /* Disable all interrupts */
+ }
+ writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
+ writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static int exynos4_tmu_read(struct exynos4_tmu_data *data)
+{
+ u8 temp_code;
+ int temp;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
+ temp = code_to_temp(data, temp_code);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return temp;
+}
+
+static void exynos4_tmu_work(struct work_struct *work)
+{
+ struct exynos4_tmu_data *data = container_of(work,
+ struct exynos4_tmu_data, irq_work);
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
+
+ enable_irq(data->irq);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static irqreturn_t exynos4_tmu_irq(int irq, void *id)
+{
+ struct exynos4_tmu_data *data = id;
+
+ disable_irq_nosync(irq);
+ schedule_work(&data->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data;
+ struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform init data supplied.\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0) {
+ ret = data->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ goto err_free;
+ }
+
+ INIT_WORK(&data->irq_work, exynos4_tmu_work);
+
+ data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!data->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ goto err_free;
+ }
+
+ data->mem = request_mem_region(data->mem->start,
+ resource_size(data->mem), pdev->name);
+ if (!data->mem) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to request memory region\n");
+ goto err_free;
+ }
+
+ data->base = ioremap(data->mem->start, resource_size(data->mem));
+ if (!data->base) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ goto err_mem_region;
+ }
+
+ ret = request_irq(data->irq, exynos4_tmu_irq,
+ IRQF_TRIGGER_RISING,
+ "exynos4-tmu", data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
+ goto err_io_remap;
+ }
+
+ data->clk = clk_get(NULL, "tmu_apbif");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ goto err_irq;
+ }
+
+ data->pdata = pdata;
+ platform_set_drvdata(pdev, data);
+ mutex_init(&data->lock);
+
+ ret = exynos4_tmu_initialize(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize TMU\n");
+ goto err_clk;
+ }
+
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+err_clk:
+ platform_set_drvdata(pdev, NULL);
+ clk_put(data->clk);
+err_irq:
+ free_irq(data->irq, data);
+err_io_remap:
+ iounmap(data->base);
+err_mem_region:
+ release_mem_region(data->mem->start, resource_size(data->mem));
+err_free:
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+
+ exynos4_tmu_control(pdev, false);
+
+ clk_put(data->clk);
+
+ free_irq(data->irq, data);
+
+ iounmap(data->base);
+ release_mem_region(data->mem->start, resource_size(data->mem));
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ exynos4_tmu_control(pdev, false);
+
+ return 0;
+}
+
+static int exynos4_tmu_resume(struct platform_device *pdev)
+{
+ exynos4_tmu_initialize(pdev);
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+}
+#else
+#define exynos4_tmu_suspend NULL
+#define exynos4_tmu_resume NULL
+#endif
+
+static struct platform_driver exynos4_tmu_driver = {
+ .driver = {
+ .name = "exynos4-tmu",
+ .owner = THIS_MODULE,
+ },
+ .probe = exynos4_tmu_probe,
+ .remove = __devexit_p(exynos4_tmu_remove),
+ .suspend = exynos4_tmu_suspend,
+ .resume = exynos4_tmu_resume,
+};
+
+module_platform_driver(exynos4_tmu_driver);
+
+MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos4-tmu");
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 5/6] thermal: exynos4: Register the tmu sensor with the kernel thermal layer
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This code added creates a link between temperature sensors, linux thermal
framework and cooling devices for samsung exynos platform. This layer
monitors the temperature from the sensor and informs the generic thermal
layer to take the necessary cooling action.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
drivers/thermal/exynos4_thermal.c | 342 ++++++++++++++++++++++++++++-
include/linux/platform_data/exynos4_tmu.h | 7 +
2 files changed, 345 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index ff708d5..e5be944 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -33,8 +33,11 @@
#include <linux/kobject.h>
#include <linux/io.h>
#include <linux/mutex.h>
-
+#include <linux/err.h>
#include <linux/platform_data/exynos4_tmu.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
#define EXYNOS4_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_CONTROL 0x20
@@ -66,6 +69,22 @@
#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+#define SENSOR_NAME_LEN 16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+
+/* 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)
+
struct exynos4_tmu_data {
struct exynos4_tmu_platform_data *pdata;
struct resource *mem;
@@ -77,6 +96,296 @@ struct exynos4_tmu_data {
u8 temp_error1, temp_error2;
};
+struct thermal_trip_point_conf {
+ int trip_val[MAX_TRIP_COUNT];
+ int trip_count;
+};
+
+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);
+ struct thermal_trip_point_conf trip_data;
+ struct thermal_cooling_conf cooling_data;
+ void *private_data;
+};
+
+struct exynos4_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;
+};
+
+static struct exynos4_thermal_zone *th_zone;
+static void exynos4_unregister_thermal(void);
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf);
+
+/* Get mode callback functions for thermal zone */
+static int exynos4_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 exynos4_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->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;
+}
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+static void exynos4_report_trigger(void)
+{
+ unsigned int i;
+ char data[2];
+ char *envp[] = { data, NULL };
+
+ if (!th_zone || !th_zone->therm_dev)
+ return;
+
+ 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] * 1000)
+ break;
+ }
+
+ if (th_zone->mode = THERMAL_DEVICE_ENABLED) {
+ if (i > 0)
+ th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ }
+
+ sprintf(data, "%u", i);
+ kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Get trip type callback functions for thermal zone */
+static int exynos4_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_STATE_INSTANCE;
+ break;
+ case PANIC_ZONE:
+ *type = THERMAL_TRIP_CRITICAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos4_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ if (trip < 0 || trip > 2)
+ return -EINVAL;
+
+ *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+ /* convert the temperature into millicelsius */
+ *temp = *temp * 1000;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos4_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret = 0;
+ /* Panic zone */
+ ret = exynos4_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos4_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ /* if the cooling device is the one from exynos4 bind it */
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error binding cooling dev inst 0\n");
+ return -EINVAL;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error binding cooling dev inst 1\n");
+ ret = -EINVAL;
+ goto error_bind1;
+ }
+
+ return ret;
+error_bind1:
+ thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos4_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error unbinding cooling dev inst 0\n");
+ ret = -EINVAL;
+ }
+ if (thermal_zone_unbind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error unbinding cooling dev inst 1\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos4_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 * 1000;
+ return 0;
+}
+
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops exynos4_dev_ops = {
+ .bind = exynos4_bind,
+ .unbind = exynos4_unbind,
+ .get_temp = exynos4_get_temp,
+ .get_mode = exynos4_get_mode,
+ .set_mode = exynos4_set_mode,
+ .get_trip_type = exynos4_get_trip_type,
+ .get_trip_temp = exynos4_get_trip_temp,
+ .get_crit_temp = exynos4_get_crit_temp,
+};
+
+/* Register with the in-kernel thermal management */
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+ int ret, count, tab_size;
+ struct freq_clip_table *tab_ptr;
+
+ if (!sensor_conf || !sensor_conf->read_temperature) {
+ pr_err("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+
+ th_zone = kzalloc(sizeof(struct exynos4_thermal_zone), GFP_KERNEL);
+ if (!th_zone) {
+ ret = -ENOMEM;
+ goto err_unregister;
+ }
+
+ th_zone->sensor_conf = sensor_conf;
+
+ tab_ptr = (struct freq_clip_table *)sensor_conf->cooling_data.freq_data;
+ tab_size = sensor_conf->cooling_data.freq_clip_count;
+
+ /* Register the cpufreq cooling device */
+ th_zone->cool_dev_size = 1;
+ count = 0;
+ th_zone->cool_dev[count] = cpufreq_cooling_register(
+ (struct freq_clip_table *)&(tab_ptr[count]),
+ tab_size, cpumask_of(0));
+
+ if (IS_ERR(th_zone->cool_dev[count])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ th_zone->cool_dev_size = 0;
+ goto err_unregister;
+ }
+
+ th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
+ 3, NULL, &exynos4_dev_ops, 0, 0, 0, IDLE_INTERVAL);
+
+ if (IS_ERR(th_zone->therm_dev)) {
+ pr_err("Failed to register thermal zone device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->mode = THERMAL_DEVICE_ENABLED;
+
+ pr_info("Exynos: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ exynos4_unregister_thermal();
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+static void exynos4_unregister_thermal(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (th_zone && th_zone->cool_dev[i])
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+ }
+
+ if (th_zone && th_zone->therm_dev)
+ thermal_zone_device_unregister(th_zone->therm_dev);
+
+ 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.
@@ -243,10 +552,10 @@ static void exynos4_tmu_work(struct work_struct *work)
writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
- enable_irq(data->irq);
-
clk_disable(data->clk);
mutex_unlock(&data->lock);
+ exynos4_report_trigger();
+ enable_irq(data->irq);
}
static irqreturn_t exynos4_tmu_irq(int irq, void *id)
@@ -259,11 +568,16 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id)
return IRQ_HANDLED;
}
+static struct thermal_sensor_conf exynos4_sensor_conf = {
+ .name = "exynos4-therm",
+ .read_temperature = (int (*)(void *))exynos4_tmu_read,
+};
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
+ int ret, i;
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -334,6 +648,24 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
exynos4_tmu_control(pdev, true);
+ /*Register the sensor with thermal management interface*/
+ (&exynos4_sensor_conf)->private_data = data;
+ exynos4_sensor_conf.trip_data.trip_count = 3;
+ for (i = 0; i < exynos4_sensor_conf.trip_data.trip_count; i++)
+ exynos4_sensor_conf.trip_data.trip_val[i] + pdata->threshold + pdata->trigger_levels[i + 1];
+
+ exynos4_sensor_conf.cooling_data.freq_clip_count + pdata->freq_tab_count;
+ for (i = 0; i < pdata->freq_tab_count; i++)
+ exynos4_sensor_conf.cooling_data.freq_data[i].freq_clip_max + pdata->freq_tab[i].freq_clip_max;
+
+ ret = exynos4_register_thermal(&exynos4_sensor_conf);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register thermal interface\n");
+ goto err_clk;
+ }
return 0;
err_clk:
platform_set_drvdata(pdev, NULL);
@@ -356,6 +688,8 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
exynos4_tmu_control(pdev, false);
+ exynos4_unregister_thermal();
+
clk_put(data->clk);
free_irq(data->irq, data);
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h
index 39e038c..ae32f19 100644
--- a/include/linux/platform_data/exynos4_tmu.h
+++ b/include/linux/platform_data/exynos4_tmu.h
@@ -21,6 +21,7 @@
#ifndef _LINUX_EXYNOS4_TMU_H
#define _LINUX_EXYNOS4_TMU_H
+#include <linux/cpu_cooling.h>
enum calibration_type {
TYPE_ONE_POINT_TRIMMING,
@@ -64,6 +65,9 @@ enum calibration_type {
* in the positive-TC generator block
* 0 <= reference_voltage <= 31
* @cal_type: calibration type 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.
*
* This structure is required for configuration of exynos4_tmu driver.
*/
@@ -79,5 +83,8 @@ struct exynos4_tmu_platform_data {
u8 reference_voltage;
enum calibration_type cal_type;
+
+ struct freq_clip_table freq_tab[4];
+ unsigned int freq_tab_count;
};
#endif /* _LINUX_EXYNOS4_TMU_H */
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [lm-sensors] [PATCH V2 6/6] ARM: exynos4: Add thermal sensor driver platform device support
@ 2012-03-19 6:17 ` Amit Daniel Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Daniel Kachhap @ 2012-03-19 6:29 UTC (permalink / raw)
To: linux-pm, linux-samsung-soc
Cc: linaro-dev, patches, linux-kernel, lm-sensors, linux-acpi
This patch adds necessary source definations needed for TMU driver and
the platform device support.
Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
---
arch/arm/mach-exynos/Kconfig | 11 +++++++
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/mach-exynos/clock.c | 4 ++
arch/arm/mach-exynos/dev-tmu.c | 39 ++++++++++++++++++++++++
arch/arm/mach-exynos/include/mach/irqs.h | 2 +
arch/arm/mach-exynos/include/mach/map.h | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/plat-samsung/include/plat/devs.h | 1 +
drivers/thermal/exynos4_thermal.c | 47 +++++++++++++++++++++++++++++
9 files changed, 107 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-exynos/dev-tmu.c
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5d602f6..03968a6 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -160,6 +160,16 @@ config EXYNOS4_SETUP_SPI
help
Common setup code for SPI GPIO configurations.
+config EXYNOS4_DEV_TMU
+ bool "Exynos4 tmu device support"
+ default n
+ depends on ARCH_EXYNOS4
+ ---help---
+ Compile in platform device definitions for TMU. This macro also
+ enables compilation hwmon base TMU driver and also allows compilation
+ of the platform device files. The platform data in this case is trip
+ temperature and some tmu h/w configurations related parameter.
+
# machine support
if ARCH_EXYNOS4
@@ -199,6 +209,7 @@ config MACH_SMDKV310
select SAMSUNG_DEV_PWM
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_DEV_TMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 5fc202c..9b62e69 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
+obj-$(CONFIG_EXYNOS4_DEV_TMU) += dev-tmu.o
obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 187287a..3b15397 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -560,6 +560,10 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 15),
}, {
+ .name = "tmu_apbif",
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
.name = "keypad",
.enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 16),
diff --git a/arch/arm/mach-exynos/dev-tmu.c b/arch/arm/mach-exynos/dev-tmu.c
new file mode 100644
index 0000000..e37f0f5
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-tmu.c
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos4/dev-tmu.c
+ *
+ * Copyright 2011 by SAMSUNG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/exynos4_tmu.h>
+#include <asm/irq.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+
+static struct resource exynos4_tmu_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_TMU,
+ .end = EXYNOS4_PA_TMU + 0xFFFF - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TMU_TRIG0,
+ .end = IRQ_TMU_TRIG0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos4_device_tmu = {
+ .name = "exynos4-tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos4_tmu_resource),
+ .resource = exynos4_tmu_resource,
+};
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index f77bce0..f98d2e4 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -128,6 +128,8 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
+#define IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4)
+#define IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4)
#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22..bc11f1f 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -66,6 +66,7 @@
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_TWD 0x10500600
#define EXYNOS4_PA_L2CC 0x10502000
+#define EXYNOS4_PA_TMU 0x100C0000
#define EXYNOS4_PA_MDMA 0x10810000
#define EXYNOS4_PA_PDMA0 0x12680000
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 0679b8a..5d56e53 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -630,6 +630,7 @@ static struct platform_device *origen_devices[] __initdata = {
&exynos4_device_pd[PD_MFC],
&origen_device_gpiokeys,
&origen_lcd_hv070wsa,
+ &exynos4_device_tmu,
};
/* LCD Backlight data */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0..0960405 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -130,6 +130,7 @@ extern struct platform_device exynos4_device_pcm2;
extern struct platform_device exynos4_device_pd[];
extern struct platform_device exynos4_device_spdif;
extern struct platform_device exynos4_device_sysmmu;
+extern struct platform_device exynos4_device_tmu;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device samsung_asoc_idma;
diff --git a/drivers/thermal/exynos4_thermal.c b/drivers/thermal/exynos4_thermal.c
index e5be944..7f8b867 100644
--- a/drivers/thermal/exynos4_thermal.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -573,12 +573,58 @@ static struct thermal_sensor_conf exynos4_sensor_conf = {
.read_temperature = (int (*)(void *))exynos4_tmu_read,
};
+#if defined(CONFIG_CPU_EXYNOS4210)
+static struct exynos4_tmu_platform_data exynos4_default_tmu_data = {
+ .threshold = 80,
+ .trigger_levels[0] = 2,
+ .trigger_levels[1] = 5,
+ .trigger_levels[2] = 20,
+ .trigger_levels[3] = 30,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 1,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ },
+ .freq_tab_count = 2,
+};
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)&exynos4_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+static struct platform_device_id exynos4_tmu_driver_ids[] = {
+ {
+ .name = "exynos4-tmu",
+ .driver_data = EXYNOS4210_TMU_DRV_DATA,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids);
+
+static inline struct exynos4_tmu_platform_data *exynos4_get_driver_data(
+ struct platform_device *pdev)
+{
+ return (struct exynos4_tmu_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
int ret, i;
+ if (!pdata)
+ pdata = exynos4_get_driver_data(pdev);
+
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV;
@@ -733,6 +779,7 @@ static struct platform_driver exynos4_tmu_driver = {
.remove = __devexit_p(exynos4_tmu_remove),
.suspend = exynos4_tmu_suspend,
.resume = exynos4_tmu_resume,
+ .id_table = exynos4_tmu_driver_ids,
};
module_platform_driver(exynos4_tmu_driver);
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-03-19 11:45 ` Srivatsa S. Bhat
-1 siblings, 0 replies; 40+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-19 11:45 UTC (permalink / raw)
To: Amit Daniel Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm, Paul E. McKenney
On 03/19/2012 11:47 AM, Amit Daniel Kachhap wrote:
> This patch adds support for generic cpu thermal cooling low level
> implementations using cpuhotplug based on the thermal level requested
> from user. Different cpu related cooling devices can be registered by the
> user and the binding of these cooling devices to the corresponding
> trip points can be easily done as the registration APIs return the
> cooling device pointer. The user of these APIs are responsible for
> passing the cpumask.
>
I am really not aware of the cpu thermal cooling stuff, but since this patch
deals with CPU Hotplug (which I am interested in), I have some questions
below..
> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
> +
> +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + int ret = -EINVAL;
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
> + if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
> + *state = hotplug_dev->hotplug_state;
> + ret = 0;
> + break;
> + }
> + }
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + return ret;
> +}
> +
> +/*This cooling may be as ACTIVE type*/
> +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + int cpuid, this_cpu = smp_processor_id();
What prevents this task from being migrated to another CPU?
IOW, what ensures that 'this_cpu' remains valid throughout this function?
I see that you are acquiring mutex locks below.. So this is definitely not
a preempt disabled section.. so I guess my question above is valid..
Or is this code bound to a particular cpu?
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
> + if (hotplug_dev && hotplug_dev->cool_dev == cdev)
> + break;
> +
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
> + return -EINVAL;
> +
> + if (hotplug_dev->hotplug_state == state)
> + return 0;
> +
> + /*
> + * This cooling device may be of type ACTIVE, so state field can
> + * be 0 or 1
> + */
> + if (state == 1) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (cpu_online(cpuid) && (cpuid != this_cpu))
What prevents the cpu numbered cpuid from being taken down right at this moment?
Don't you need explicit synchronization with CPU Hotplug using something like
get_online_cpus()/put_online_cpus() here?
> + cpu_down(cpuid);
> + }
> + } else if (state == 0) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (!cpu_online(cpuid) && (cpuid != this_cpu))
Same here.
> + cpu_up(cpuid);
> + }
> + } else {
> + return -EINVAL;
> + }
> +
> + hotplug_dev->hotplug_state = state;
> +
> + return 0;
> +}
> +/* bind hotplug callbacks to cpu hotplug cooling device */
> +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
> + .get_max_state = cpuhotplug_get_max_state,
> + .get_cur_state = cpuhotplug_get_cur_state,
> + .set_cur_state = cpuhotplug_set_cur_state,
> +};
> +
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
@ 2012-03-19 11:45 ` Srivatsa S. Bhat
0 siblings, 0 replies; 40+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-19 11:45 UTC (permalink / raw)
To: Amit Daniel Kachhap
Cc: linux-pm, linux-samsung-soc, linux-kernel, mjg59, linux-acpi,
lenb, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r, Paul E. McKenney
On 03/19/2012 11:47 AM, Amit Daniel Kachhap wrote:
> This patch adds support for generic cpu thermal cooling low level
> implementations using cpuhotplug based on the thermal level requested
> from user. Different cpu related cooling devices can be registered by the
> user and the binding of these cooling devices to the corresponding
> trip points can be easily done as the registration APIs return the
> cooling device pointer. The user of these APIs are responsible for
> passing the cpumask.
>
I am really not aware of the cpu thermal cooling stuff, but since this patch
deals with CPU Hotplug (which I am interested in), I have some questions
below..
> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
> +
> +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + int ret = -EINVAL;
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
> + if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
> + *state = hotplug_dev->hotplug_state;
> + ret = 0;
> + break;
> + }
> + }
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + return ret;
> +}
> +
> +/*This cooling may be as ACTIVE type*/
> +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + int cpuid, this_cpu = smp_processor_id();
What prevents this task from being migrated to another CPU?
IOW, what ensures that 'this_cpu' remains valid throughout this function?
I see that you are acquiring mutex locks below.. So this is definitely not
a preempt disabled section.. so I guess my question above is valid..
Or is this code bound to a particular cpu?
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
> + if (hotplug_dev && hotplug_dev->cool_dev == cdev)
> + break;
> +
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
> + return -EINVAL;
> +
> + if (hotplug_dev->hotplug_state == state)
> + return 0;
> +
> + /*
> + * This cooling device may be of type ACTIVE, so state field can
> + * be 0 or 1
> + */
> + if (state == 1) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (cpu_online(cpuid) && (cpuid != this_cpu))
What prevents the cpu numbered cpuid from being taken down right at this moment?
Don't you need explicit synchronization with CPU Hotplug using something like
get_online_cpus()/put_online_cpus() here?
> + cpu_down(cpuid);
> + }
> + } else if (state == 0) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (!cpu_online(cpuid) && (cpuid != this_cpu))
Same here.
> + cpu_up(cpuid);
> + }
> + } else {
> + return -EINVAL;
> + }
> +
> + hotplug_dev->hotplug_state = state;
> +
> + return 0;
> +}
> +/* bind hotplug callbacks to cpu hotplug cooling device */
> +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
> + .get_max_state = cpuhotplug_get_max_state,
> + .get_cur_state = cpuhotplug_get_cur_state,
> + .set_cur_state = cpuhotplug_set_cur_state,
> +};
> +
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
@ 2012-03-19 11:45 ` Srivatsa S. Bhat
0 siblings, 0 replies; 40+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-19 11:57 UTC (permalink / raw)
To: Amit Daniel Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm, Paul E. McKenney
On 03/19/2012 11:47 AM, Amit Daniel Kachhap wrote:
> This patch adds support for generic cpu thermal cooling low level
> implementations using cpuhotplug based on the thermal level requested
> from user. Different cpu related cooling devices can be registered by the
> user and the binding of these cooling devices to the corresponding
> trip points can be easily done as the registration APIs return the
> cooling device pointer. The user of these APIs are responsible for
> passing the cpumask.
>
I am really not aware of the cpu thermal cooling stuff, but since this patch
deals with CPU Hotplug (which I am interested in), I have some questions
below..
> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
> +
> +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> +{
> + int ret = -EINVAL;
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
> + if (hotplug_dev && hotplug_dev->cool_dev = cdev) {
> + *state = hotplug_dev->hotplug_state;
> + ret = 0;
> + break;
> + }
> + }
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + return ret;
> +}
> +
> +/*This cooling may be as ACTIVE type*/
> +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> +{
> + int cpuid, this_cpu = smp_processor_id();
What prevents this task from being migrated to another CPU?
IOW, what ensures that 'this_cpu' remains valid throughout this function?
I see that you are acquiring mutex locks below.. So this is definitely not
a preempt disabled section.. so I guess my question above is valid..
Or is this code bound to a particular cpu?
> + struct hotplug_cooling_device *hotplug_dev;
> +
> + mutex_lock(&cooling_cpuhotplug_lock);
> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
> + if (hotplug_dev && hotplug_dev->cool_dev = cdev)
> + break;
> +
> + mutex_unlock(&cooling_cpuhotplug_lock);
> + if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
> + return -EINVAL;
> +
> + if (hotplug_dev->hotplug_state = state)
> + return 0;
> +
> + /*
> + * This cooling device may be of type ACTIVE, so state field can
> + * be 0 or 1
> + */
> + if (state = 1) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (cpu_online(cpuid) && (cpuid != this_cpu))
What prevents the cpu numbered cpuid from being taken down right at this moment?
Don't you need explicit synchronization with CPU Hotplug using something like
get_online_cpus()/put_online_cpus() here?
> + cpu_down(cpuid);
> + }
> + } else if (state = 0) {
> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
> + if (!cpu_online(cpuid) && (cpuid != this_cpu))
Same here.
> + cpu_up(cpuid);
> + }
> + } else {
> + return -EINVAL;
> + }
> +
> + hotplug_dev->hotplug_state = state;
> +
> + return 0;
> +}
> +/* bind hotplug callbacks to cpu hotplug cooling device */
> +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
> + .get_max_state = cpuhotplug_get_max_state,
> + .get_cur_state = cpuhotplug_get_cur_state,
> + .set_cur_state = cpuhotplug_set_cur_state,
> +};
> +
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
2012-03-19 11:45 ` Srivatsa S. Bhat
@ 2012-03-20 6:18 ` Amit Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-03-20 6:06 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: linux-pm, linux-samsung-soc, linux-kernel, mjg59, linux-acpi,
lenb, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r, Paul E. McKenney
On 19 March 2012 17:15, Srivatsa S. Bhat
<srivatsa.bhat@linux.vnet.ibm.com> wrote:
> On 03/19/2012 11:47 AM, Amit Daniel Kachhap wrote:
>
>> This patch adds support for generic cpu thermal cooling low level
>> implementations using cpuhotplug based on the thermal level requested
>> from user. Different cpu related cooling devices can be registered by the
>> user and the binding of these cooling devices to the corresponding
>> trip points can be easily done as the registration APIs return the
>> cooling device pointer. The user of these APIs are responsible for
>> passing the cpumask.
>>
>
>
> I am really not aware of the cpu thermal cooling stuff, but since this patch
> deals with CPU Hotplug (which I am interested in), I have some questions
> below..
>
>
>> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
>> +
>> +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + int ret = -EINVAL;
>> + struct hotplug_cooling_device *hotplug_dev;
>> +
>> + mutex_lock(&cooling_cpuhotplug_lock);
>> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
>> + if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
>> + *state = hotplug_dev->hotplug_state;
>> + ret = 0;
>> + break;
>> + }
>> + }
>> + mutex_unlock(&cooling_cpuhotplug_lock);
>> + return ret;
>> +}
>> +
>> +/*This cooling may be as ACTIVE type*/
>> +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long state)
>> +{
>> + int cpuid, this_cpu = smp_processor_id();
>
>
> What prevents this task from being migrated to another CPU?
> IOW, what ensures that 'this_cpu' remains valid throughout this function?
>
> I see that you are acquiring mutex locks below.. So this is definitely not
> a preempt disabled section.. so I guess my question above is valid..
>
> Or is this code bound to a particular cpu?
No this thread is not bound to a cpu. Your comment is valid and some
synchronization is needed for preemption. Thanks for pointing this
out.
>
>> + struct hotplug_cooling_device *hotplug_dev;
>> +
>> + mutex_lock(&cooling_cpuhotplug_lock);
>> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
>> + if (hotplug_dev && hotplug_dev->cool_dev == cdev)
>> + break;
>> +
>> + mutex_unlock(&cooling_cpuhotplug_lock);
>> + if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
>> + return -EINVAL;
>> +
>> + if (hotplug_dev->hotplug_state == state)
>> + return 0;
>> +
>> + /*
>> + * This cooling device may be of type ACTIVE, so state field can
>> + * be 0 or 1
>> + */
>> + if (state == 1) {
>> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
>> + if (cpu_online(cpuid) && (cpuid != this_cpu))
>
>
> What prevents the cpu numbered cpuid from being taken down right at this moment?
> Don't you need explicit synchronization with CPU Hotplug using something like
> get_online_cpus()/put_online_cpus() here?
>
>> + cpu_down(cpuid);
>> + }
>> + } else if (state == 0) {
>> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
>> + if (!cpu_online(cpuid) && (cpuid != this_cpu))
>
>
> Same here.
>
>> + cpu_up(cpuid);
>> + }
>> + } else {
>> + return -EINVAL;
>> + }
>> +
>> + hotplug_dev->hotplug_state = state;
>> +
>> + return 0;
>> +}
>> +/* bind hotplug callbacks to cpu hotplug cooling device */
>> +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
>> + .get_max_state = cpuhotplug_get_max_state,
>> + .get_cur_state = cpuhotplug_get_cur_state,
>> + .set_cur_state = cpuhotplug_set_cur_state,
>> +};
>> +
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 3/6] thermal: Add generic cpuhotplug cooling implementation
@ 2012-03-20 6:18 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-03-20 6:18 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: linux-pm, linux-samsung-soc, linux-kernel, mjg59, linux-acpi,
lenb, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r, Paul E. McKenney
On 19 March 2012 17:15, Srivatsa S. Bhat
<srivatsa.bhat@linux.vnet.ibm.com> wrote:
> On 03/19/2012 11:47 AM, Amit Daniel Kachhap wrote:
>
>> This patch adds support for generic cpu thermal cooling low level
>> implementations using cpuhotplug based on the thermal level requested
>> from user. Different cpu related cooling devices can be registered by the
>> user and the binding of these cooling devices to the corresponding
>> trip points can be easily done as the registration APIs return the
>> cooling device pointer. The user of these APIs are responsible for
>> passing the cpumask.
>>
>
>
> I am really not aware of the cpu thermal cooling stuff, but since this patch
> deals with CPU Hotplug (which I am interested in), I have some questions
> below..
>
>
>> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
>> +
>> +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long *state)
>> +{
>> + int ret = -EINVAL;
>> + struct hotplug_cooling_device *hotplug_dev;
>> +
>> + mutex_lock(&cooling_cpuhotplug_lock);
>> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
>> + if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
>> + *state = hotplug_dev->hotplug_state;
>> + ret = 0;
>> + break;
>> + }
>> + }
>> + mutex_unlock(&cooling_cpuhotplug_lock);
>> + return ret;
>> +}
>> +
>> +/*This cooling may be as ACTIVE type*/
>> +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
>> + unsigned long state)
>> +{
>> + int cpuid, this_cpu = smp_processor_id();
>
>
> What prevents this task from being migrated to another CPU?
> IOW, what ensures that 'this_cpu' remains valid throughout this function?
>
> I see that you are acquiring mutex locks below.. So this is definitely not
> a preempt disabled section.. so I guess my question above is valid..
>
> Or is this code bound to a particular cpu?
No this thread is not bound to a cpu. Your comment is valid and some
synchronization is needed for preemption. Thanks for pointing this
out.
>
>> + struct hotplug_cooling_device *hotplug_dev;
>> +
>> + mutex_lock(&cooling_cpuhotplug_lock);
>> + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
>> + if (hotplug_dev && hotplug_dev->cool_dev == cdev)
>> + break;
>> +
>> + mutex_unlock(&cooling_cpuhotplug_lock);
>> + if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
>> + return -EINVAL;
>> +
>> + if (hotplug_dev->hotplug_state == state)
>> + return 0;
>> +
>> + /*
>> + * This cooling device may be of type ACTIVE, so state field can
>> + * be 0 or 1
>> + */
>> + if (state == 1) {
>> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
>> + if (cpu_online(cpuid) && (cpuid != this_cpu))
>
>
> What prevents the cpu numbered cpuid from being taken down right at this moment?
> Don't you need explicit synchronization with CPU Hotplug using something like
> get_online_cpus()/put_online_cpus() here?
>
>> + cpu_down(cpuid);
>> + }
>> + } else if (state == 0) {
>> + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
>> + if (!cpu_online(cpuid) && (cpuid != this_cpu))
>
>
> Same here.
>
>> + cpu_up(cpuid);
>> + }
>> + } else {
>> + return -EINVAL;
>> + }
>> +
>> + hotplug_dev->hotplug_state = state;
>> +
>> + return 0;
>> +}
>> +/* bind hotplug callbacks to cpu hotplug cooling device */
>> +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
>> + .get_max_state = cpuhotplug_get_max_state,
>> + .get_cur_state = cpuhotplug_get_cur_state,
>> + .set_cur_state = cpuhotplug_set_cur_state,
>> +};
>> +
>
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
2012-03-19 6:17 ` Amit Daniel Kachhap
(?)
@ 2012-04-04 4:32 ` Amit Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-04 4:32 UTC (permalink / raw)
To: lenb, rui.zhang
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
Hi Len/Rui,
Any comment or feedback from your side about the status of this patch?
Is it merge-able or major re-work is needed? I have fixed most of the
comments in this patchset and currently working on some of the minor
comments received and will submit them shortly.
Regards,
Amit Daniel
On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> Changes since V1:
> *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> as suggested by Mark Brown and Guenter Roeck
> *Added notifier support to notify the registered drivers of any cpu cooling
> action. The driver can modify the default cooling behaviour(eg set different
> max clip frequency).
> *The percentage based frequency replaced with absolute clipped frequency.
> *Some more conditional checks when setting max frequency.
> *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> THERMAL_TRIP_STATE_INSTANCE
> *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> eduardo.valentin@ti.com implemented.
> *Removed cooling stats through debugfs patch
> *The V1 based can be found here,
> https://lkml.org/lkml/2012/2/22/123
> http://lkml.org/lkml/2012/3/3/32
>
> Changes since RFC:
> *Changed the cpu cooling registration/unregistration API's to instance based
> *Changed the STATE_ACTIVE trip type to pass correct instance id
> *Adding support to restore back the policy->max_freq after doing frequency
> clipping.
> *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> by Greg KH greg@kroah.com
> *Incorporated several review comments from eduardo.valentin@ti.com
> *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> *Some changes according to the changes in common cpu cooling APIs
> *The RFC based patches can be found here,
> https://lkml.org/lkml/2011/12/13/186
> https://lkml.org/lkml/2011/12/21/169
>
>
> Brief Description:
>
> 1) The generic cooling devices code is placed inside driver/thermal/* as
> placing inside acpi folder will need un-necessary enabling of acpi code. This
> codes is architecture independent.
>
> 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> cooling device instance number and may be helpful for cpufreq cooling devices
> to take the correct cooling action. This trip type avoids the temperature
> comparision check again inside the cooling handler.
>
> 3) This patchset adds generic cpu cooling low level implementation through
> frequency clipping and cpu hotplug. In future, other cpu related cooling
> devices may be added here. An ACPI version of this already exists
> (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> like ARM using the generic thermal interface along with the generic cpu
> cooling devices. The cooling device registration API's return cooling device
> pointers which can be easily binded with the thermal zone trip points.
> The important APIs exposed are,
> a)struct thermal_cooling_device *cpufreq_cooling_register(
> struct freq_clip_table *tab_ptr, unsigned int tab_size,
> const struct cpumask *mask_val)
> b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>
> 4) Samsung exynos platform thermal implementation is done using the generic
> cpu cooling APIs and the new trip type. The temperature sensor driver present
> in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> and registered as a thermal driver.
>
> All this patchset is based on Kernel version 3.3-rc7
>
> A simple data/control flow diagrams is shown below,
>
> Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> | |
> \|/ |
> Cpufreq cooling device <---------------
>
>
> Amit Daniel Kachhap (6):
> thermal: Add a new trip type to use cooling device instance number
> thermal: Add generic cpufreq cooling implementation
> thermal: Add generic cpuhotplug cooling implementation
> hwmon: exynos4: Move thermal sensor driver to driver/thermal
> directory
> thermal: exynos4: Register the tmu sensor with the kernel thermal
> layer
> ARM: exynos4: Add thermal sensor driver platform device support
>
> Documentation/hwmon/exynos4_tmu | 81 ---
> Documentation/thermal/cpu-cooling-api.txt | 76 +++
> Documentation/thermal/exynos4_tmu | 52 ++
> Documentation/thermal/sysfs-api.txt | 4 +-
> arch/arm/mach-exynos/Kconfig | 11 +
> arch/arm/mach-exynos/Makefile | 1 +
> arch/arm/mach-exynos/clock.c | 4 +
> arch/arm/mach-exynos/dev-tmu.c | 39 ++
> arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> arch/arm/mach-exynos/include/mach/map.h | 1 +
> arch/arm/mach-exynos/mach-origen.c | 1 +
> arch/arm/plat-samsung/include/plat/devs.h | 1 +
> drivers/hwmon/Kconfig | 10 -
> drivers/hwmon/Makefile | 1 -
> drivers/hwmon/exynos4_tmu.c | 514 -------------------
> drivers/thermal/Kconfig | 21 +
> drivers/thermal/Makefile | 2 +
> drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> drivers/thermal/thermal_sys.c | 45 ++-
> include/linux/cpu_cooling.h | 78 +++
> include/linux/platform_data/exynos4_tmu.h | 7 +
> include/linux/thermal.h | 1 +
> 23 files changed, 1660 insertions(+), 611 deletions(-)
> delete mode 100644 Documentation/hwmon/exynos4_tmu
> create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> create mode 100644 Documentation/thermal/exynos4_tmu
> create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> delete mode 100644 drivers/hwmon/exynos4_tmu.c
> create mode 100644 drivers/thermal/cpu_cooling.c
> create mode 100644 drivers/thermal/exynos4_thermal.c
> create mode 100644 include/linux/cpu_cooling.h
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-04 4:32 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-04 4:32 UTC (permalink / raw)
To: lenb, rui.zhang
Cc: linux-pm, linux-samsung-soc, linux-kernel, mjg59, linux-acpi,
linaro-dev, lm-sensors, amit.kachhap, patches, eduardo.valentin,
durgadoss.r
Hi Len/Rui,
Any comment or feedback from your side about the status of this patch?
Is it merge-able or major re-work is needed? I have fixed most of the
comments in this patchset and currently working on some of the minor
comments received and will submit them shortly.
Regards,
Amit Daniel
On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> Changes since V1:
> *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> as suggested by Mark Brown and Guenter Roeck
> *Added notifier support to notify the registered drivers of any cpu cooling
> action. The driver can modify the default cooling behaviour(eg set different
> max clip frequency).
> *The percentage based frequency replaced with absolute clipped frequency.
> *Some more conditional checks when setting max frequency.
> *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> THERMAL_TRIP_STATE_INSTANCE
> *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> eduardo.valentin@ti.com implemented.
> *Removed cooling stats through debugfs patch
> *The V1 based can be found here,
> https://lkml.org/lkml/2012/2/22/123
> http://lkml.org/lkml/2012/3/3/32
>
> Changes since RFC:
> *Changed the cpu cooling registration/unregistration API's to instance based
> *Changed the STATE_ACTIVE trip type to pass correct instance id
> *Adding support to restore back the policy->max_freq after doing frequency
> clipping.
> *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> by Greg KH greg@kroah.com
> *Incorporated several review comments from eduardo.valentin@ti.com
> *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> *Some changes according to the changes in common cpu cooling APIs
> *The RFC based patches can be found here,
> https://lkml.org/lkml/2011/12/13/186
> https://lkml.org/lkml/2011/12/21/169
>
>
> Brief Description:
>
> 1) The generic cooling devices code is placed inside driver/thermal/* as
> placing inside acpi folder will need un-necessary enabling of acpi code. This
> codes is architecture independent.
>
> 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> cooling device instance number and may be helpful for cpufreq cooling devices
> to take the correct cooling action. This trip type avoids the temperature
> comparision check again inside the cooling handler.
>
> 3) This patchset adds generic cpu cooling low level implementation through
> frequency clipping and cpu hotplug. In future, other cpu related cooling
> devices may be added here. An ACPI version of this already exists
> (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> like ARM using the generic thermal interface along with the generic cpu
> cooling devices. The cooling device registration API's return cooling device
> pointers which can be easily binded with the thermal zone trip points.
> The important APIs exposed are,
> a)struct thermal_cooling_device *cpufreq_cooling_register(
> struct freq_clip_table *tab_ptr, unsigned int tab_size,
> const struct cpumask *mask_val)
> b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>
> 4) Samsung exynos platform thermal implementation is done using the generic
> cpu cooling APIs and the new trip type. The temperature sensor driver present
> in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> and registered as a thermal driver.
>
> All this patchset is based on Kernel version 3.3-rc7
>
> A simple data/control flow diagrams is shown below,
>
> Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> | |
> \|/ |
> Cpufreq cooling device <---------------
>
>
> Amit Daniel Kachhap (6):
> thermal: Add a new trip type to use cooling device instance number
> thermal: Add generic cpufreq cooling implementation
> thermal: Add generic cpuhotplug cooling implementation
> hwmon: exynos4: Move thermal sensor driver to driver/thermal
> directory
> thermal: exynos4: Register the tmu sensor with the kernel thermal
> layer
> ARM: exynos4: Add thermal sensor driver platform device support
>
> Documentation/hwmon/exynos4_tmu | 81 ---
> Documentation/thermal/cpu-cooling-api.txt | 76 +++
> Documentation/thermal/exynos4_tmu | 52 ++
> Documentation/thermal/sysfs-api.txt | 4 +-
> arch/arm/mach-exynos/Kconfig | 11 +
> arch/arm/mach-exynos/Makefile | 1 +
> arch/arm/mach-exynos/clock.c | 4 +
> arch/arm/mach-exynos/dev-tmu.c | 39 ++
> arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> arch/arm/mach-exynos/include/mach/map.h | 1 +
> arch/arm/mach-exynos/mach-origen.c | 1 +
> arch/arm/plat-samsung/include/plat/devs.h | 1 +
> drivers/hwmon/Kconfig | 10 -
> drivers/hwmon/Makefile | 1 -
> drivers/hwmon/exynos4_tmu.c | 514 -------------------
> drivers/thermal/Kconfig | 21 +
> drivers/thermal/Makefile | 2 +
> drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> drivers/thermal/thermal_sys.c | 45 ++-
> include/linux/cpu_cooling.h | 78 +++
> include/linux/platform_data/exynos4_tmu.h | 7 +
> include/linux/thermal.h | 1 +
> 23 files changed, 1660 insertions(+), 611 deletions(-)
> delete mode 100644 Documentation/hwmon/exynos4_tmu
> create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> create mode 100644 Documentation/thermal/exynos4_tmu
> create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> delete mode 100644 drivers/hwmon/exynos4_tmu.c
> create mode 100644 drivers/thermal/cpu_cooling.c
> create mode 100644 drivers/thermal/exynos4_thermal.c
> create mode 100644 include/linux/cpu_cooling.h
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-04 4:32 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-04 4:44 UTC (permalink / raw)
To: lenb, rui.zhang
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
Hi Len/Rui,
Any comment or feedback from your side about the status of this patch?
Is it merge-able or major re-work is needed? I have fixed most of the
comments in this patchset and currently working on some of the minor
comments received and will submit them shortly.
Regards,
Amit Daniel
On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> Changes since V1:
> *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> as suggested by Mark Brown and Guenter Roeck
> *Added notifier support to notify the registered drivers of any cpu cooling
> action. The driver can modify the default cooling behaviour(eg set different
> max clip frequency).
> *The percentage based frequency replaced with absolute clipped frequency.
> *Some more conditional checks when setting max frequency.
> *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> THERMAL_TRIP_STATE_INSTANCE
> *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> eduardo.valentin@ti.com implemented.
> *Removed cooling stats through debugfs patch
> *The V1 based can be found here,
> https://lkml.org/lkml/2012/2/22/123
> http://lkml.org/lkml/2012/3/3/32
>
> Changes since RFC:
> *Changed the cpu cooling registration/unregistration API's to instance based
> *Changed the STATE_ACTIVE trip type to pass correct instance id
> *Adding support to restore back the policy->max_freq after doing frequency
> clipping.
> *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> by Greg KH greg@kroah.com
> *Incorporated several review comments from eduardo.valentin@ti.com
> *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> *Some changes according to the changes in common cpu cooling APIs
> *The RFC based patches can be found here,
> https://lkml.org/lkml/2011/12/13/186
> https://lkml.org/lkml/2011/12/21/169
>
>
> Brief Description:
>
> 1) The generic cooling devices code is placed inside driver/thermal/* as
> placing inside acpi folder will need un-necessary enabling of acpi code. This
> codes is architecture independent.
>
> 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> cooling device instance number and may be helpful for cpufreq cooling devices
> to take the correct cooling action. This trip type avoids the temperature
> comparision check again inside the cooling handler.
>
> 3) This patchset adds generic cpu cooling low level implementation through
> frequency clipping and cpu hotplug. In future, other cpu related cooling
> devices may be added here. An ACPI version of this already exists
> (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> like ARM using the generic thermal interface along with the generic cpu
> cooling devices. The cooling device registration API's return cooling device
> pointers which can be easily binded with the thermal zone trip points.
> The important APIs exposed are,
> a)struct thermal_cooling_device *cpufreq_cooling_register(
> struct freq_clip_table *tab_ptr, unsigned int tab_size,
> const struct cpumask *mask_val)
> b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>
> 4) Samsung exynos platform thermal implementation is done using the generic
> cpu cooling APIs and the new trip type. The temperature sensor driver present
> in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> and registered as a thermal driver.
>
> All this patchset is based on Kernel version 3.3-rc7
>
> A simple data/control flow diagrams is shown below,
>
> Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> | |
> \|/ |
> Cpufreq cooling device <---------------
>
>
> Amit Daniel Kachhap (6):
> thermal: Add a new trip type to use cooling device instance number
> thermal: Add generic cpufreq cooling implementation
> thermal: Add generic cpuhotplug cooling implementation
> hwmon: exynos4: Move thermal sensor driver to driver/thermal
> directory
> thermal: exynos4: Register the tmu sensor with the kernel thermal
> layer
> ARM: exynos4: Add thermal sensor driver platform device support
>
> Documentation/hwmon/exynos4_tmu | 81 ---
> Documentation/thermal/cpu-cooling-api.txt | 76 +++
> Documentation/thermal/exynos4_tmu | 52 ++
> Documentation/thermal/sysfs-api.txt | 4 +-
> arch/arm/mach-exynos/Kconfig | 11 +
> arch/arm/mach-exynos/Makefile | 1 +
> arch/arm/mach-exynos/clock.c | 4 +
> arch/arm/mach-exynos/dev-tmu.c | 39 ++
> arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> arch/arm/mach-exynos/include/mach/map.h | 1 +
> arch/arm/mach-exynos/mach-origen.c | 1 +
> arch/arm/plat-samsung/include/plat/devs.h | 1 +
> drivers/hwmon/Kconfig | 10 -
> drivers/hwmon/Makefile | 1 -
> drivers/hwmon/exynos4_tmu.c | 514 -------------------
> drivers/thermal/Kconfig | 21 +
> drivers/thermal/Makefile | 2 +
> drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> drivers/thermal/thermal_sys.c | 45 ++-
> include/linux/cpu_cooling.h | 78 +++
> include/linux/platform_data/exynos4_tmu.h | 7 +
> include/linux/thermal.h | 1 +
> 23 files changed, 1660 insertions(+), 611 deletions(-)
> delete mode 100644 Documentation/hwmon/exynos4_tmu
> create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> create mode 100644 Documentation/thermal/exynos4_tmu
> create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> delete mode 100644 drivers/hwmon/exynos4_tmu.c
> create mode 100644 drivers/thermal/cpu_cooling.c
> create mode 100644 drivers/thermal/exynos4_thermal.c
> create mode 100644 include/linux/cpu_cooling.h
>
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
2012-04-04 4:32 ` Amit Kachhap
(?)
@ 2012-04-10 0:58 ` Zhang Rui
-1 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-10 0:58 UTC (permalink / raw)
To: Amit Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
Hi, Amit,
On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
> Hi Len/Rui,
>
> Any comment or feedback from your side about the status of this patch?
> Is it merge-able or major re-work is needed? I have fixed most of the
> comments in this patchset and currently working on some of the minor
> comments received and will submit them shortly.
>
Sorry for the late response.
First of all, it makes sense to me to introduce the generic cpufrq
cooling implementation.
But I still have some questions.
I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
current passive handling in the generic thermal layer well, right?
e.g. there is no tc1/tc2 on exynos4.
If yes, is it possible that we can enhance the passive cooling to
support the generic processor cooling?
say, introduce another way to throttle the processor in
thermal_zone_device_passive when tc1 and tc2 are not available?
thanks,
rui
> Regards,
> Amit Daniel
>
> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> > Changes since V1:
> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> > as suggested by Mark Brown and Guenter Roeck
> > *Added notifier support to notify the registered drivers of any cpu cooling
> > action. The driver can modify the default cooling behaviour(eg set different
> > max clip frequency).
> > *The percentage based frequency replaced with absolute clipped frequency.
> > *Some more conditional checks when setting max frequency.
> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> > THERMAL_TRIP_STATE_INSTANCE
> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> > eduardo.valentin@ti.com implemented.
> > *Removed cooling stats through debugfs patch
> > *The V1 based can be found here,
> > https://lkml.org/lkml/2012/2/22/123
> > http://lkml.org/lkml/2012/3/3/32
> >
> > Changes since RFC:
> > *Changed the cpu cooling registration/unregistration API's to instance based
> > *Changed the STATE_ACTIVE trip type to pass correct instance id
> > *Adding support to restore back the policy->max_freq after doing frequency
> > clipping.
> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> > by Greg KH greg@kroah.com
> > *Incorporated several review comments from eduardo.valentin@ti.com
> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> > *Some changes according to the changes in common cpu cooling APIs
> > *The RFC based patches can be found here,
> > https://lkml.org/lkml/2011/12/13/186
> > https://lkml.org/lkml/2011/12/21/169
> >
> >
> > Brief Description:
> >
> > 1) The generic cooling devices code is placed inside driver/thermal/* as
> > placing inside acpi folder will need un-necessary enabling of acpi code. This
> > codes is architecture independent.
> >
> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> > cooling device instance number and may be helpful for cpufreq cooling devices
> > to take the correct cooling action. This trip type avoids the temperature
> > comparision check again inside the cooling handler.
> >
> > 3) This patchset adds generic cpu cooling low level implementation through
> > frequency clipping and cpu hotplug. In future, other cpu related cooling
> > devices may be added here. An ACPI version of this already exists
> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> > like ARM using the generic thermal interface along with the generic cpu
> > cooling devices. The cooling device registration API's return cooling device
> > pointers which can be easily binded with the thermal zone trip points.
> > The important APIs exposed are,
> > a)struct thermal_cooling_device *cpufreq_cooling_register(
> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
> > const struct cpumask *mask_val)
> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> >
> > 4) Samsung exynos platform thermal implementation is done using the generic
> > cpu cooling APIs and the new trip type. The temperature sensor driver present
> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> > and registered as a thermal driver.
> >
> > All this patchset is based on Kernel version 3.3-rc7
> >
> > A simple data/control flow diagrams is shown below,
> >
> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> > | |
> > \|/ |
> > Cpufreq cooling device <---------------
> >
> >
> > Amit Daniel Kachhap (6):
> > thermal: Add a new trip type to use cooling device instance number
> > thermal: Add generic cpufreq cooling implementation
> > thermal: Add generic cpuhotplug cooling implementation
> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
> > directory
> > thermal: exynos4: Register the tmu sensor with the kernel thermal
> > layer
> > ARM: exynos4: Add thermal sensor driver platform device support
> >
> > Documentation/hwmon/exynos4_tmu | 81 ---
> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
> > Documentation/thermal/exynos4_tmu | 52 ++
> > Documentation/thermal/sysfs-api.txt | 4 +-
> > arch/arm/mach-exynos/Kconfig | 11 +
> > arch/arm/mach-exynos/Makefile | 1 +
> > arch/arm/mach-exynos/clock.c | 4 +
> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> > arch/arm/mach-exynos/include/mach/map.h | 1 +
> > arch/arm/mach-exynos/mach-origen.c | 1 +
> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
> > drivers/hwmon/Kconfig | 10 -
> > drivers/hwmon/Makefile | 1 -
> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
> > drivers/thermal/Kconfig | 21 +
> > drivers/thermal/Makefile | 2 +
> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> > drivers/thermal/thermal_sys.c | 45 ++-
> > include/linux/cpu_cooling.h | 78 +++
> > include/linux/platform_data/exynos4_tmu.h | 7 +
> > include/linux/thermal.h | 1 +
> > 23 files changed, 1660 insertions(+), 611 deletions(-)
> > delete mode 100644 Documentation/hwmon/exynos4_tmu
> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> > create mode 100644 Documentation/thermal/exynos4_tmu
> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
> > create mode 100644 drivers/thermal/cpu_cooling.c
> > create mode 100644 drivers/thermal/exynos4_thermal.c
> > create mode 100644 include/linux/cpu_cooling.h
> >
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-pm
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-10 0:58 ` Zhang Rui
0 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-10 0:58 UTC (permalink / raw)
To: Amit Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
SGksIEFtaXQsCgpPbiDkuIksIDIwMTItMDQtMDQgYXQgMTA6MDIgKzA1MzAsIEFtaXQgS2FjaGhh
cCB3cm90ZToKPiBIaSBMZW4vUnVpLAo+IAo+IEFueSBjb21tZW50IG9yIGZlZWRiYWNrIGZyb20g
eW91ciBzaWRlIGFib3V0IHRoZSBzdGF0dXMgb2YgdGhpcyBwYXRjaD8KPiBJcyBpdCBtZXJnZS1h
YmxlIG9yIG1ham9yIHJlLXdvcmsgaXMgbmVlZGVkPyBJIGhhdmUgZml4ZWQgbW9zdCBvZiB0aGUK
PiBjb21tZW50cyBpbiB0aGlzIHBhdGNoc2V0IGFuZCBjdXJyZW50bHkgd29ya2luZyBvbiBzb21l
IG9mIHRoZSBtaW5vcgo+IGNvbW1lbnRzIHJlY2VpdmVkIGFuZCB3aWxsIHN1Ym1pdCB0aGVtIHNo
b3J0bHkuCj4gClNvcnJ5IGZvciB0aGUgbGF0ZSByZXNwb25zZS4KCkZpcnN0IG9mIGFsbCwgaXQg
bWFrZXMgc2Vuc2UgdG8gbWUgdG8gaW50cm9kdWNlIHRoZSBnZW5lcmljIGNwdWZycQpjb29saW5n
IGltcGxlbWVudGF0aW9uLgpCdXQgSSBzdGlsbCBoYXZlIHNvbWUgcXVlc3Rpb25zLgpJIHRoaW5r
IHRoZSBrZXkgcmVhc29uIHdoeSBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0UgaXMgaW50cm9k
dWNlZCBpcwp0aGF0IHRoZSBNT05JUk9SX1pPTkUgYW5kIFdBUk5fWk9ORSBvbiBleHlub3M0IGNh
biBub3QgZml0IGludG8gdGhlCmN1cnJlbnQgcGFzc2l2ZSBoYW5kbGluZyBpbiB0aGUgZ2VuZXJp
YyB0aGVybWFsIGxheWVyIHdlbGwsIHJpZ2h0PwplLmcuIHRoZXJlIGlzIG5vIHRjMS90YzIgb24g
ZXh5bm9zNC4KCklmIHllcywgaXMgaXQgcG9zc2libGUgdGhhdCB3ZSBjYW4gZW5oYW5jZSB0aGUg
cGFzc2l2ZSBjb29saW5nIHRvCnN1cHBvcnQgdGhlIGdlbmVyaWMgcHJvY2Vzc29yIGNvb2xpbmc/
CnNheSwgaW50cm9kdWNlIGFub3RoZXIgd2F5IHRvIHRocm90dGxlIHRoZSBwcm9jZXNzb3IgaW4K
dGhlcm1hbF96b25lX2RldmljZV9wYXNzaXZlIHdoZW4gdGMxIGFuZCB0YzIgYXJlIG5vdCBhdmFp
bGFibGU/Cgp0aGFua3MsCnJ1aQoKPiBSZWdhcmRzLAo+IEFtaXQgRGFuaWVsCj4gCj4gT24gMTkg
TWFyY2ggMjAxMiAxMTo0NywgQW1pdCBEYW5pZWwgS2FjaGhhcCA8YW1pdC5rYWNoaGFwQGxpbmFy
by5vcmc+IHdyb3RlOgo+ID4gQ2hhbmdlcyBzaW5jZSBWMToKPiA+ICpNb3ZlZCB0aGUgc2Vuc29y
IGRyaXZlciB0byBkcml2ZXIvdGhlcm1hbCBmb2xkZXIgZnJvbSBkcml2ZXIvaHdtb24gZm9sZGVy
Cj4gPiAgYXMgc3VnZ2VzdGVkIGJ5IE1hcmsgQnJvd24gYW5kIEd1ZW50ZXIgUm9lY2sKPiA+ICpB
ZGRlZCBub3RpZmllciBzdXBwb3J0IHRvIG5vdGlmeSB0aGUgcmVnaXN0ZXJlZCBkcml2ZXJzIG9m
IGFueSBjcHUgY29vbGluZwo+ID4gIGFjdGlvbi4gVGhlIGRyaXZlciBjYW4gbW9kaWZ5IHRoZSBk
ZWZhdWx0IGNvb2xpbmcgYmVoYXZpb3VyKGVnIHNldCBkaWZmZXJlbnQKPiA+ICBtYXggY2xpcCBm
cmVxdWVuY3kpLgo+ID4gKlRoZSBwZXJjZW50YWdlIGJhc2VkIGZyZXF1ZW5jeSByZXBsYWNlZCB3
aXRoIGFic29sdXRlIGNsaXBwZWQgZnJlcXVlbmN5Lgo+ID4gKlNvbWUgbW9yZSBjb25kaXRpb25h
bCBjaGVja3Mgd2hlbiBzZXR0aW5nIG1heCBmcmVxdWVuY3kuCj4gPiAqUmVuYW1lZCB0aGUgbmV3
IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfQUNUSVZFIHRvCj4gPiAgVEhFUk1BTF9UUklQ
X1NUQVRFX0lOU1RBTkNFCj4gPiAqTWFueSByZXZpZXcgY29tbWVudHMgZnJvbSBSLCBEdXJnYWRv
c3MgPGR1cmdhZG9zcy5yQGludGVsLmNvbT4gYW5kCj4gPiAgZWR1YXJkby52YWxlbnRpbkB0aS5j
b20gaW1wbGVtZW50ZWQuCj4gPiAqUmVtb3ZlZCBjb29saW5nIHN0YXRzIHRocm91Z2ggZGVidWdm
cyBwYXRjaAo+ID4gKlRoZSBWMSBiYXNlZCBjYW4gYmUgZm91bmQgaGVyZSwKPiA+ICBodHRwczov
L2xrbWwub3JnL2xrbWwvMjAxMi8yLzIyLzEyMwo+ID4gIGh0dHA6Ly9sa21sLm9yZy9sa21sLzIw
MTIvMy8zLzMyCj4gPgo+ID4gQ2hhbmdlcyBzaW5jZSBSRkM6Cj4gPiAqQ2hhbmdlZCB0aGUgY3B1
IGNvb2xpbmcgcmVnaXN0cmF0aW9uL3VucmVnaXN0cmF0aW9uIEFQSSdzIHRvIGluc3RhbmNlIGJh
c2VkCj4gPiAqQ2hhbmdlZCB0aGUgU1RBVEVfQUNUSVZFIHRyaXAgdHlwZSB0byBwYXNzIGNvcnJl
Y3QgaW5zdGFuY2UgaWQKPiA+ICpBZGRpbmcgc3VwcG9ydCB0byByZXN0b3JlIGJhY2sgdGhlIHBv
bGljeS0+bWF4X2ZyZXEgYWZ0ZXIgZG9pbmcgZnJlcXVlbmN5Cj4gPiAgY2xpcHBpbmcuCj4gPiAq
TW92ZWQgdGhlIHRyaXAgY29vbGluZyBzdGF0cyBmcm9tIHN5c2ZzIG5vZGUgdG8gZGVidWdmcyBu
b2RlIGFzIHN1Z2dlc3RlZAo+ID4gIGJ5IEdyZWcgS0ggZ3JlZ0Brcm9haC5jb20KPiA+ICpJbmNv
cnBvcmF0ZWQgc2V2ZXJhbCByZXZpZXcgY29tbWVudHMgZnJvbSBlZHVhcmRvLnZhbGVudGluQHRp
LmNvbQo+ID4gKk1vdmVkIHRoZSBUZW1wZXJhdHVyZSBzZW5zb3IgZHJpdmVyIGZyb20gZHJpdmVy
L2h3bW9uLyB0byBkcml2ZXIvbWZkCj4gPiAgYXMgZGlzY3Vzc2VkIHdpdGggR3VlbnRlciBSb2Vj
ayA8Z3VlbnRlci5yb2Vja0Blcmljc3Nvbi5jb20+IGFuZAo+ID4gIERvbmdnZXVuIEtpbSA8ZGc3
Ny5raW1Ac2Ftc3VuZy5jb20+IChodHRwczovL2xrbWwub3JnL2xrbWwvMjAxMi8xLzUvNykKPiA+
ICpTb21lIGNoYW5nZXMgYWNjb3JkaW5nIHRvIHRoZSBjaGFuZ2VzIGluIGNvbW1vbiBjcHUgY29v
bGluZyBBUElzCj4gPiAqVGhlIFJGQyBiYXNlZCBwYXRjaGVzIGNhbiBiZSBmb3VuZCBoZXJlLAo+
ID4gIGh0dHBzOi8vbGttbC5vcmcvbGttbC8yMDExLzEyLzEzLzE4Ngo+ID4gIGh0dHBzOi8vbGtt
bC5vcmcvbGttbC8yMDExLzEyLzIxLzE2OQo+ID4KPiA+Cj4gPiBCcmllZiBEZXNjcmlwdGlvbjoK
PiA+Cj4gPiAxKSBUaGUgZ2VuZXJpYyBjb29saW5nIGRldmljZXMgY29kZSBpcyBwbGFjZWQgaW5z
aWRlIGRyaXZlci90aGVybWFsLyogYXMKPiA+IHBsYWNpbmcgaW5zaWRlIGFjcGkgZm9sZGVyIHdp
bGwgbmVlZCB1bi1uZWNlc3NhcnkgZW5hYmxpbmcgb2YgYWNwaSBjb2RlLiBUaGlzCj4gPiBjb2Rl
cyBpcyBhcmNoaXRlY3R1cmUgaW5kZXBlbmRlbnQuCj4gPgo+ID4gMikgVGhpcyBwYXRjaHNldCBh
ZGRzIGEgbmV3IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0Ugd2hpY2ggcGFz
c2VzCj4gPiBjb29saW5nIGRldmljZSBpbnN0YW5jZSBudW1iZXIgYW5kIG1heSBiZSBoZWxwZnVs
IGZvciBjcHVmcmVxIGNvb2xpbmcgZGV2aWNlcwo+ID4gdG8gdGFrZSB0aGUgY29ycmVjdCBjb29s
aW5nIGFjdGlvbi4gVGhpcyB0cmlwIHR5cGUgYXZvaWRzIHRoZSB0ZW1wZXJhdHVyZQo+ID4gY29t
cGFyaXNpb24gY2hlY2sgYWdhaW4gaW5zaWRlIHRoZSBjb29saW5nIGhhbmRsZXIuCj4gPgo+ID4g
MykgVGhpcyBwYXRjaHNldCBhZGRzIGdlbmVyaWMgY3B1IGNvb2xpbmcgbG93IGxldmVsIGltcGxl
bWVudGF0aW9uIHRocm91Z2gKPiA+IGZyZXF1ZW5jeSBjbGlwcGluZyBhbmQgY3B1IGhvdHBsdWcu
IEluIGZ1dHVyZSwgb3RoZXIgY3B1IHJlbGF0ZWQgY29vbGluZwo+ID4gZGV2aWNlcyBtYXkgYmUg
YWRkZWQgaGVyZS4gQW4gQUNQSSB2ZXJzaW9uIG9mIHRoaXMgYWxyZWFkeSBleGlzdHMKPiA+IChk
cml2ZXJzL2FjcGkvcHJvY2Vzc29yX3RoZXJtYWwuYykuIEJ1dCB0aGlzIHdpbGwgYmUgdXNlZnVs
IGZvciBwbGF0Zm9ybXMKPiA+IGxpa2UgQVJNIHVzaW5nIHRoZSBnZW5lcmljIHRoZXJtYWwgaW50
ZXJmYWNlIGFsb25nIHdpdGggdGhlIGdlbmVyaWMgY3B1Cj4gPiBjb29saW5nIGRldmljZXMuIFRo
ZSBjb29saW5nIGRldmljZSByZWdpc3RyYXRpb24gQVBJJ3MgcmV0dXJuIGNvb2xpbmcgZGV2aWNl
Cj4gPiBwb2ludGVycyB3aGljaCBjYW4gYmUgZWFzaWx5IGJpbmRlZCB3aXRoIHRoZSB0aGVybWFs
IHpvbmUgdHJpcCBwb2ludHMuCj4gPiBUaGUgaW1wb3J0YW50IEFQSXMgZXhwb3NlZCBhcmUsCj4g
PiAgIGEpc3RydWN0IHRoZXJtYWxfY29vbGluZ19kZXZpY2UgKmNwdWZyZXFfY29vbGluZ19yZWdp
c3RlcigKPiA+ICAgICAgICBzdHJ1Y3QgZnJlcV9jbGlwX3RhYmxlICp0YWJfcHRyLCB1bnNpZ25l
ZCBpbnQgdGFiX3NpemUsCj4gPiAgICAgICAgY29uc3Qgc3RydWN0IGNwdW1hc2sgKm1hc2tfdmFs
KQo+ID4gICBiKXZvaWQgY3B1ZnJlcV9jb29saW5nX3VucmVnaXN0ZXIoc3RydWN0IHRoZXJtYWxf
Y29vbGluZ19kZXZpY2UgKmNkZXYpCj4gPgo+ID4gNCkgU2Ftc3VuZyBleHlub3MgcGxhdGZvcm0g
dGhlcm1hbCBpbXBsZW1lbnRhdGlvbiBpcyBkb25lIHVzaW5nIHRoZSBnZW5lcmljCj4gPiBjcHUg
Y29vbGluZyBBUElzIGFuZCB0aGUgbmV3IHRyaXAgdHlwZS4gVGhlIHRlbXBlcmF0dXJlIHNlbnNv
ciBkcml2ZXIgcHJlc2VudAo+ID4gaW4gdGhlIGh3bW9uIGZvbGRlcihyZWdpc3RlcmVkIGFzIGh3
bW9uIGRyaXZlcikgaXMgbW92ZWQgdG8gdGhlcm1hbCBmb2xkZXIKPiA+IGFuZCByZWdpc3RlcmVk
IGFzIGEgdGhlcm1hbCBkcml2ZXIuCj4gPgo+ID4gQWxsIHRoaXMgcGF0Y2hzZXQgaXMgYmFzZWQg
b24gS2VybmVsIHZlcnNpb24gMy4zLXJjNwo+ID4KPiA+IEEgc2ltcGxlIGRhdGEvY29udHJvbCBm
bG93IGRpYWdyYW1zIGlzIHNob3duIGJlbG93LAo+ID4KPiA+IENvcmUgTGludXggdGhlcm1hbCA8
LS0tLS0+ICBFeHlub3MgdGhlcm1hbCBpbnRlcmZhY2UgPC0tLS0tIFRlbXBlcmF0dXJlIFNlbnNv
cgo+ID4gICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAo+ID4gICAgICAg
ICBcfC8gICAgICAgICAgICAgICAgICAgICAgICAgICAgfAo+ID4gIENwdWZyZXEgY29vbGluZyBk
ZXZpY2UgPC0tLS0tLS0tLS0tLS0tLQo+ID4KPiA+Cj4gPiBBbWl0IERhbmllbCBLYWNoaGFwICg2
KToKPiA+ICB0aGVybWFsOiBBZGQgYSBuZXcgdHJpcCB0eXBlIHRvIHVzZSBjb29saW5nIGRldmlj
ZSBpbnN0YW5jZSBudW1iZXIKPiA+ICB0aGVybWFsOiBBZGQgZ2VuZXJpYyBjcHVmcmVxIGNvb2xp
bmcgaW1wbGVtZW50YXRpb24KPiA+ICB0aGVybWFsOiBBZGQgZ2VuZXJpYyBjcHVob3RwbHVnIGNv
b2xpbmcgaW1wbGVtZW50YXRpb24KPiA+ICBod21vbjogZXh5bm9zNDogTW92ZSB0aGVybWFsIHNl
bnNvciBkcml2ZXIgdG8gZHJpdmVyL3RoZXJtYWwKPiA+ICAgIGRpcmVjdG9yeQo+ID4gIHRoZXJt
YWw6IGV4eW5vczQ6IFJlZ2lzdGVyIHRoZSB0bXUgc2Vuc29yIHdpdGggdGhlIGtlcm5lbCB0aGVy
bWFsCj4gPiAgICBsYXllcgo+ID4gIEFSTTogZXh5bm9zNDogQWRkIHRoZXJtYWwgc2Vuc29yIGRy
aXZlciBwbGF0Zm9ybSBkZXZpY2Ugc3VwcG9ydAo+ID4KPiA+ICBEb2N1bWVudGF0aW9uL2h3bW9u
L2V4eW5vczRfdG11ICAgICAgICAgICB8ICAgODEgLS0tCj4gPiAgRG9jdW1lbnRhdGlvbi90aGVy
bWFsL2NwdS1jb29saW5nLWFwaS50eHQgfCAgIDc2ICsrKwo+ID4gIERvY3VtZW50YXRpb24vdGhl
cm1hbC9leHlub3M0X3RtdSAgICAgICAgIHwgICA1MiArKwo+ID4gIERvY3VtZW50YXRpb24vdGhl
cm1hbC9zeXNmcy1hcGkudHh0ICAgICAgIHwgICAgNCArLQo+ID4gIGFyY2gvYXJtL21hY2gtZXh5
bm9zL0tjb25maWcgICAgICAgICAgICAgIHwgICAxMSArCj4gPiAgYXJjaC9hcm0vbWFjaC1leHlu
b3MvTWFrZWZpbGUgICAgICAgICAgICAgfCAgICAxICsKPiA+ICBhcmNoL2FybS9tYWNoLWV4eW5v
cy9jbG9jay5jICAgICAgICAgICAgICB8ICAgIDQgKwo+ID4gIGFyY2gvYXJtL21hY2gtZXh5bm9z
L2Rldi10bXUuYyAgICAgICAgICAgIHwgICAzOSArKwo+ID4gIGFyY2gvYXJtL21hY2gtZXh5bm9z
L2luY2x1ZGUvbWFjaC9pcnFzLmggIHwgICAgMiArCj4gPiAgYXJjaC9hcm0vbWFjaC1leHlub3Mv
aW5jbHVkZS9tYWNoL21hcC5oICAgfCAgICAxICsKPiA+ICBhcmNoL2FybS9tYWNoLWV4eW5vcy9t
YWNoLW9yaWdlbi5jICAgICAgICB8ICAgIDEgKwo+ID4gIGFyY2gvYXJtL3BsYXQtc2Ftc3VuZy9p
bmNsdWRlL3BsYXQvZGV2cy5oIHwgICAgMSArCj4gPiAgZHJpdmVycy9od21vbi9LY29uZmlnICAg
ICAgICAgICAgICAgICAgICAgfCAgIDEwIC0KPiA+ICBkcml2ZXJzL2h3bW9uL01ha2VmaWxlICAg
ICAgICAgICAgICAgICAgICB8ICAgIDEgLQo+ID4gIGRyaXZlcnMvaHdtb24vZXh5bm9zNF90bXUu
YyAgICAgICAgICAgICAgIHwgIDUxNCAtLS0tLS0tLS0tLS0tLS0tLS0tCj4gPiAgZHJpdmVycy90
aGVybWFsL0tjb25maWcgICAgICAgICAgICAgICAgICAgfCAgIDIxICsKPiA+ICBkcml2ZXJzL3Ro
ZXJtYWwvTWFrZWZpbGUgICAgICAgICAgICAgICAgICB8ICAgIDIgKwo+ID4gIGRyaXZlcnMvdGhl
cm1hbC9jcHVfY29vbGluZy5jICAgICAgICAgICAgIHwgIDUyOSArKysrKysrKysrKysrKysrKysr
Cj4gPiAgZHJpdmVycy90aGVybWFsL2V4eW5vczRfdGhlcm1hbC5jICAgICAgICAgfCAgNzkwICsr
KysrKysrKysrKysrKysrKysrKysrKysrKysrCj4gPiAgZHJpdmVycy90aGVybWFsL3RoZXJtYWxf
c3lzLmMgICAgICAgICAgICAgfCAgIDQ1ICsrLQo+ID4gIGluY2x1ZGUvbGludXgvY3B1X2Nvb2xp
bmcuaCAgICAgICAgICAgICAgIHwgICA3OCArKysKPiA+ICBpbmNsdWRlL2xpbnV4L3BsYXRmb3Jt
X2RhdGEvZXh5bm9zNF90bXUuaCB8ICAgIDcgKwo+ID4gIGluY2x1ZGUvbGludXgvdGhlcm1hbC5o
ICAgICAgICAgICAgICAgICAgIHwgICAgMSArCj4gPiAgMjMgZmlsZXMgY2hhbmdlZCwgMTY2MCBp
bnNlcnRpb25zKCspLCA2MTEgZGVsZXRpb25zKC0pCj4gPiAgZGVsZXRlIG1vZGUgMTAwNjQ0IERv
Y3VtZW50YXRpb24vaHdtb24vZXh5bm9zNF90bXUKPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgRG9j
dW1lbnRhdGlvbi90aGVybWFsL2NwdS1jb29saW5nLWFwaS50eHQKPiA+ICBjcmVhdGUgbW9kZSAx
MDA2NDQgRG9jdW1lbnRhdGlvbi90aGVybWFsL2V4eW5vczRfdG11Cj4gPiAgY3JlYXRlIG1vZGUg
MTAwNjQ0IGFyY2gvYXJtL21hY2gtZXh5bm9zL2Rldi10bXUuYwo+ID4gIGRlbGV0ZSBtb2RlIDEw
MDY0NCBkcml2ZXJzL2h3bW9uL2V4eW5vczRfdG11LmMKPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQg
ZHJpdmVycy90aGVybWFsL2NwdV9jb29saW5nLmMKPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJp
dmVycy90aGVybWFsL2V4eW5vczRfdGhlcm1hbC5jCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGlu
Y2x1ZGUvbGludXgvY3B1X2Nvb2xpbmcuaAo+ID4KCgoKX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX18KbG0tc2Vuc29ycyBtYWlsaW5nIGxpc3QKbG0tc2Vuc29y
c0BsbS1zZW5zb3JzLm9yZwpodHRwOi8vbGlzdHMubG0tc2Vuc29ycy5vcmcvbWFpbG1hbi9saXN0
aW5mby9sbS1zZW5zb3Jz
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-10 0:58 ` Zhang Rui
0 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-10 0:58 UTC (permalink / raw)
To: Amit Kachhap
Cc: lenb, linux-pm, linux-samsung-soc, linux-kernel, mjg59,
linux-acpi, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r
Hi, Amit,
On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
> Hi Len/Rui,
>
> Any comment or feedback from your side about the status of this patch?
> Is it merge-able or major re-work is needed? I have fixed most of the
> comments in this patchset and currently working on some of the minor
> comments received and will submit them shortly.
>
Sorry for the late response.
First of all, it makes sense to me to introduce the generic cpufrq
cooling implementation.
But I still have some questions.
I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
current passive handling in the generic thermal layer well, right?
e.g. there is no tc1/tc2 on exynos4.
If yes, is it possible that we can enhance the passive cooling to
support the generic processor cooling?
say, introduce another way to throttle the processor in
thermal_zone_device_passive when tc1 and tc2 are not available?
thanks,
rui
> Regards,
> Amit Daniel
>
> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> > Changes since V1:
> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> > as suggested by Mark Brown and Guenter Roeck
> > *Added notifier support to notify the registered drivers of any cpu cooling
> > action. The driver can modify the default cooling behaviour(eg set different
> > max clip frequency).
> > *The percentage based frequency replaced with absolute clipped frequency.
> > *Some more conditional checks when setting max frequency.
> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> > THERMAL_TRIP_STATE_INSTANCE
> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> > eduardo.valentin@ti.com implemented.
> > *Removed cooling stats through debugfs patch
> > *The V1 based can be found here,
> > https://lkml.org/lkml/2012/2/22/123
> > http://lkml.org/lkml/2012/3/3/32
> >
> > Changes since RFC:
> > *Changed the cpu cooling registration/unregistration API's to instance based
> > *Changed the STATE_ACTIVE trip type to pass correct instance id
> > *Adding support to restore back the policy->max_freq after doing frequency
> > clipping.
> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> > by Greg KH greg@kroah.com
> > *Incorporated several review comments from eduardo.valentin@ti.com
> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> > *Some changes according to the changes in common cpu cooling APIs
> > *The RFC based patches can be found here,
> > https://lkml.org/lkml/2011/12/13/186
> > https://lkml.org/lkml/2011/12/21/169
> >
> >
> > Brief Description:
> >
> > 1) The generic cooling devices code is placed inside driver/thermal/* as
> > placing inside acpi folder will need un-necessary enabling of acpi code. This
> > codes is architecture independent.
> >
> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> > cooling device instance number and may be helpful for cpufreq cooling devices
> > to take the correct cooling action. This trip type avoids the temperature
> > comparision check again inside the cooling handler.
> >
> > 3) This patchset adds generic cpu cooling low level implementation through
> > frequency clipping and cpu hotplug. In future, other cpu related cooling
> > devices may be added here. An ACPI version of this already exists
> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> > like ARM using the generic thermal interface along with the generic cpu
> > cooling devices. The cooling device registration API's return cooling device
> > pointers which can be easily binded with the thermal zone trip points.
> > The important APIs exposed are,
> > a)struct thermal_cooling_device *cpufreq_cooling_register(
> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
> > const struct cpumask *mask_val)
> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> >
> > 4) Samsung exynos platform thermal implementation is done using the generic
> > cpu cooling APIs and the new trip type. The temperature sensor driver present
> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> > and registered as a thermal driver.
> >
> > All this patchset is based on Kernel version 3.3-rc7
> >
> > A simple data/control flow diagrams is shown below,
> >
> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> > | |
> > \|/ |
> > Cpufreq cooling device <---------------
> >
> >
> > Amit Daniel Kachhap (6):
> > thermal: Add a new trip type to use cooling device instance number
> > thermal: Add generic cpufreq cooling implementation
> > thermal: Add generic cpuhotplug cooling implementation
> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
> > directory
> > thermal: exynos4: Register the tmu sensor with the kernel thermal
> > layer
> > ARM: exynos4: Add thermal sensor driver platform device support
> >
> > Documentation/hwmon/exynos4_tmu | 81 ---
> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
> > Documentation/thermal/exynos4_tmu | 52 ++
> > Documentation/thermal/sysfs-api.txt | 4 +-
> > arch/arm/mach-exynos/Kconfig | 11 +
> > arch/arm/mach-exynos/Makefile | 1 +
> > arch/arm/mach-exynos/clock.c | 4 +
> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> > arch/arm/mach-exynos/include/mach/map.h | 1 +
> > arch/arm/mach-exynos/mach-origen.c | 1 +
> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
> > drivers/hwmon/Kconfig | 10 -
> > drivers/hwmon/Makefile | 1 -
> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
> > drivers/thermal/Kconfig | 21 +
> > drivers/thermal/Makefile | 2 +
> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> > drivers/thermal/thermal_sys.c | 45 ++-
> > include/linux/cpu_cooling.h | 78 +++
> > include/linux/platform_data/exynos4_tmu.h | 7 +
> > include/linux/thermal.h | 1 +
> > 23 files changed, 1660 insertions(+), 611 deletions(-)
> > delete mode 100644 Documentation/hwmon/exynos4_tmu
> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> > create mode 100644 Documentation/thermal/exynos4_tmu
> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
> > create mode 100644 drivers/thermal/cpu_cooling.c
> > create mode 100644 drivers/thermal/exynos4_thermal.c
> > create mode 100644 include/linux/cpu_cooling.h
> >
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
2012-04-10 0:58 ` [lm-sensors] " Zhang Rui
(?)
@ 2012-04-11 12:47 ` Amit Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-11 12:47 UTC (permalink / raw)
To: Zhang Rui
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
Hi Rui,
Thanks for looking into the patches.
On 10 April 2012 06:28, Zhang Rui <rui.zhang@intel.com> wrote:
> Hi, Amit,
>
> On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
>> Hi Len/Rui,
>>
>> Any comment or feedback from your side about the status of this patch?
>> Is it merge-able or major re-work is needed? I have fixed most of the
>> comments in this patchset and currently working on some of the minor
>> comments received and will submit them shortly.
>>
> Sorry for the late response.
>
> First of all, it makes sense to me to introduce the generic cpufrq
> cooling implementation.
ok thanks
> But I still have some questions.
> I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
> that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
> current passive handling in the generic thermal layer well, right?
> e.g. there is no tc1/tc2 on exynos4.
>
> If yes, is it possible that we can enhance the passive cooling to
> support the generic processor cooling?
> say, introduce another way to throttle the processor in
> thermal_zone_device_passive when tc1 and tc2 are not available?
I agree that this new trip type code can be moved into passive trip
type when tc1 and tc2 are 0. but this is special type of cooling
devices behaviour where only instances of the same cooling device is
binded to a trip point. The order of mapping is the only
differentiating criteria and there are some checks used to implement
this like
1) The trip points should be in ascending order.(This is missing in my
original patch, so I added below)
2) The set_cur_state has to be called for the exact temp range so
get_cur_state(&state) and set_cur_state(state ++/state--) logic is not
possible.
3) set_cur_state is called as set_cur_state(cdev_instance).
There is a chance that people might confuse that these checks are
applicable for passive trip types also which is not the case here.
@@ -1187,6 +1228,21 @@ struct thermal_zone_device
*thermal_zone_device_register(char *type,
tz->ops->get_trip_type(tz, count, &trip_type);
if (trip_type == THERMAL_TRIP_PASSIVE)
passive = 1;
+ /*
+ * For THERMAL_TRIP_STATE_INSTANCE trips, thermal zone should
+ * be in ascending order.
+ */
+ if (trip_type == THERMAL_TRIP_STATE_INSTANCE) {
+ tz->ops->get_trip_temp(tz, count, &trip_temp);
+ if (first_trip_temp == 0)
+ first_trip_temp = trip_temp;
+ else if (first_trip_temp < trip_temp)
+ first_trip_temp = trip_temp;
+ else if (first_trip_temp > trip_temp) {
+ pr_warn("Zone trip points should be in
ascending order\n");
+ goto unregister;
+ }
+ }
}
if (!passive)
Anyway there is other alternative where this new trip type is not
needed and I can just use the existing trip type THERMAL_TRIP_ACTIVE
and create 2 separate cooling devices for MONITOR_ZONE and WARN_ZONE.
I had thought to make this generic and just to manage with 1 cooling
device.
What is your view?
Thanks,
Amit Daniel
>
> thanks,
> rui
>
>> Regards,
>> Amit Daniel
>>
>> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
>> > Changes since V1:
>> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
>> > as suggested by Mark Brown and Guenter Roeck
>> > *Added notifier support to notify the registered drivers of any cpu cooling
>> > action. The driver can modify the default cooling behaviour(eg set different
>> > max clip frequency).
>> > *The percentage based frequency replaced with absolute clipped frequency.
>> > *Some more conditional checks when setting max frequency.
>> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
>> > THERMAL_TRIP_STATE_INSTANCE
>> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
>> > eduardo.valentin@ti.com implemented.
>> > *Removed cooling stats through debugfs patch
>> > *The V1 based can be found here,
>> > https://lkml.org/lkml/2012/2/22/123
>> > http://lkml.org/lkml/2012/3/3/32
>> >
>> > Changes since RFC:
>> > *Changed the cpu cooling registration/unregistration API's to instance based
>> > *Changed the STATE_ACTIVE trip type to pass correct instance id
>> > *Adding support to restore back the policy->max_freq after doing frequency
>> > clipping.
>> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
>> > by Greg KH greg@kroah.com
>> > *Incorporated several review comments from eduardo.valentin@ti.com
>> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
>> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
>> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
>> > *Some changes according to the changes in common cpu cooling APIs
>> > *The RFC based patches can be found here,
>> > https://lkml.org/lkml/2011/12/13/186
>> > https://lkml.org/lkml/2011/12/21/169
>> >
>> >
>> > Brief Description:
>> >
>> > 1) The generic cooling devices code is placed inside driver/thermal/* as
>> > placing inside acpi folder will need un-necessary enabling of acpi code. This
>> > codes is architecture independent.
>> >
>> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
>> > cooling device instance number and may be helpful for cpufreq cooling devices
>> > to take the correct cooling action. This trip type avoids the temperature
>> > comparision check again inside the cooling handler.
>> >
>> > 3) This patchset adds generic cpu cooling low level implementation through
>> > frequency clipping and cpu hotplug. In future, other cpu related cooling
>> > devices may be added here. An ACPI version of this already exists
>> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
>> > like ARM using the generic thermal interface along with the generic cpu
>> > cooling devices. The cooling device registration API's return cooling device
>> > pointers which can be easily binded with the thermal zone trip points.
>> > The important APIs exposed are,
>> > a)struct thermal_cooling_device *cpufreq_cooling_register(
>> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
>> > const struct cpumask *mask_val)
>> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>> >
>> > 4) Samsung exynos platform thermal implementation is done using the generic
>> > cpu cooling APIs and the new trip type. The temperature sensor driver present
>> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
>> > and registered as a thermal driver.
>> >
>> > All this patchset is based on Kernel version 3.3-rc7
>> >
>> > A simple data/control flow diagrams is shown below,
>> >
>> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
>> > | |
>> > \|/ |
>> > Cpufreq cooling device <---------------
>> >
>> >
>> > Amit Daniel Kachhap (6):
>> > thermal: Add a new trip type to use cooling device instance number
>> > thermal: Add generic cpufreq cooling implementation
>> > thermal: Add generic cpuhotplug cooling implementation
>> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
>> > directory
>> > thermal: exynos4: Register the tmu sensor with the kernel thermal
>> > layer
>> > ARM: exynos4: Add thermal sensor driver platform device support
>> >
>> > Documentation/hwmon/exynos4_tmu | 81 ---
>> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
>> > Documentation/thermal/exynos4_tmu | 52 ++
>> > Documentation/thermal/sysfs-api.txt | 4 +-
>> > arch/arm/mach-exynos/Kconfig | 11 +
>> > arch/arm/mach-exynos/Makefile | 1 +
>> > arch/arm/mach-exynos/clock.c | 4 +
>> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
>> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
>> > arch/arm/mach-exynos/include/mach/map.h | 1 +
>> > arch/arm/mach-exynos/mach-origen.c | 1 +
>> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
>> > drivers/hwmon/Kconfig | 10 -
>> > drivers/hwmon/Makefile | 1 -
>> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
>> > drivers/thermal/Kconfig | 21 +
>> > drivers/thermal/Makefile | 2 +
>> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
>> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
>> > drivers/thermal/thermal_sys.c | 45 ++-
>> > include/linux/cpu_cooling.h | 78 +++
>> > include/linux/platform_data/exynos4_tmu.h | 7 +
>> > include/linux/thermal.h | 1 +
>> > 23 files changed, 1660 insertions(+), 611 deletions(-)
>> > delete mode 100644 Documentation/hwmon/exynos4_tmu
>> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
>> > create mode 100644 Documentation/thermal/exynos4_tmu
>> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
>> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
>> > create mode 100644 drivers/thermal/cpu_cooling.c
>> > create mode 100644 drivers/thermal/exynos4_thermal.c
>> > create mode 100644 include/linux/cpu_cooling.h
>> >
>
>
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-pm
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-11 12:47 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-11 12:47 UTC (permalink / raw)
To: Zhang Rui
Cc: lenb, linux-pm, linux-samsung-soc, linux-kernel, mjg59,
linux-acpi, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r
Hi Rui,
Thanks for looking into the patches.
On 10 April 2012 06:28, Zhang Rui <rui.zhang@intel.com> wrote:
> Hi, Amit,
>
> On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
>> Hi Len/Rui,
>>
>> Any comment or feedback from your side about the status of this patch?
>> Is it merge-able or major re-work is needed? I have fixed most of the
>> comments in this patchset and currently working on some of the minor
>> comments received and will submit them shortly.
>>
> Sorry for the late response.
>
> First of all, it makes sense to me to introduce the generic cpufrq
> cooling implementation.
ok thanks
> But I still have some questions.
> I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
> that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
> current passive handling in the generic thermal layer well, right?
> e.g. there is no tc1/tc2 on exynos4.
>
> If yes, is it possible that we can enhance the passive cooling to
> support the generic processor cooling?
> say, introduce another way to throttle the processor in
> thermal_zone_device_passive when tc1 and tc2 are not available?
I agree that this new trip type code can be moved into passive trip
type when tc1 and tc2 are 0. but this is special type of cooling
devices behaviour where only instances of the same cooling device is
binded to a trip point. The order of mapping is the only
differentiating criteria and there are some checks used to implement
this like
1) The trip points should be in ascending order.(This is missing in my
original patch, so I added below)
2) The set_cur_state has to be called for the exact temp range so
get_cur_state(&state) and set_cur_state(state ++/state--) logic is not
possible.
3) set_cur_state is called as set_cur_state(cdev_instance).
There is a chance that people might confuse that these checks are
applicable for passive trip types also which is not the case here.
@@ -1187,6 +1228,21 @@ struct thermal_zone_device
*thermal_zone_device_register(char *type,
tz->ops->get_trip_type(tz, count, &trip_type);
if (trip_type == THERMAL_TRIP_PASSIVE)
passive = 1;
+ /*
+ * For THERMAL_TRIP_STATE_INSTANCE trips, thermal zone should
+ * be in ascending order.
+ */
+ if (trip_type == THERMAL_TRIP_STATE_INSTANCE) {
+ tz->ops->get_trip_temp(tz, count, &trip_temp);
+ if (first_trip_temp == 0)
+ first_trip_temp = trip_temp;
+ else if (first_trip_temp < trip_temp)
+ first_trip_temp = trip_temp;
+ else if (first_trip_temp > trip_temp) {
+ pr_warn("Zone trip points should be in
ascending order\n");
+ goto unregister;
+ }
+ }
}
if (!passive)
Anyway there is other alternative where this new trip type is not
needed and I can just use the existing trip type THERMAL_TRIP_ACTIVE
and create 2 separate cooling devices for MONITOR_ZONE and WARN_ZONE.
I had thought to make this generic and just to manage with 1 cooling
device.
What is your view?
Thanks,
Amit Daniel
>
> thanks,
> rui
>
>> Regards,
>> Amit Daniel
>>
>> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
>> > Changes since V1:
>> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
>> > as suggested by Mark Brown and Guenter Roeck
>> > *Added notifier support to notify the registered drivers of any cpu cooling
>> > action. The driver can modify the default cooling behaviour(eg set different
>> > max clip frequency).
>> > *The percentage based frequency replaced with absolute clipped frequency.
>> > *Some more conditional checks when setting max frequency.
>> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
>> > THERMAL_TRIP_STATE_INSTANCE
>> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
>> > eduardo.valentin@ti.com implemented.
>> > *Removed cooling stats through debugfs patch
>> > *The V1 based can be found here,
>> > https://lkml.org/lkml/2012/2/22/123
>> > http://lkml.org/lkml/2012/3/3/32
>> >
>> > Changes since RFC:
>> > *Changed the cpu cooling registration/unregistration API's to instance based
>> > *Changed the STATE_ACTIVE trip type to pass correct instance id
>> > *Adding support to restore back the policy->max_freq after doing frequency
>> > clipping.
>> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
>> > by Greg KH greg@kroah.com
>> > *Incorporated several review comments from eduardo.valentin@ti.com
>> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
>> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
>> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
>> > *Some changes according to the changes in common cpu cooling APIs
>> > *The RFC based patches can be found here,
>> > https://lkml.org/lkml/2011/12/13/186
>> > https://lkml.org/lkml/2011/12/21/169
>> >
>> >
>> > Brief Description:
>> >
>> > 1) The generic cooling devices code is placed inside driver/thermal/* as
>> > placing inside acpi folder will need un-necessary enabling of acpi code. This
>> > codes is architecture independent.
>> >
>> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
>> > cooling device instance number and may be helpful for cpufreq cooling devices
>> > to take the correct cooling action. This trip type avoids the temperature
>> > comparision check again inside the cooling handler.
>> >
>> > 3) This patchset adds generic cpu cooling low level implementation through
>> > frequency clipping and cpu hotplug. In future, other cpu related cooling
>> > devices may be added here. An ACPI version of this already exists
>> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
>> > like ARM using the generic thermal interface along with the generic cpu
>> > cooling devices. The cooling device registration API's return cooling device
>> > pointers which can be easily binded with the thermal zone trip points.
>> > The important APIs exposed are,
>> > a)struct thermal_cooling_device *cpufreq_cooling_register(
>> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
>> > const struct cpumask *mask_val)
>> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>> >
>> > 4) Samsung exynos platform thermal implementation is done using the generic
>> > cpu cooling APIs and the new trip type. The temperature sensor driver present
>> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
>> > and registered as a thermal driver.
>> >
>> > All this patchset is based on Kernel version 3.3-rc7
>> >
>> > A simple data/control flow diagrams is shown below,
>> >
>> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
>> > | |
>> > \|/ |
>> > Cpufreq cooling device <---------------
>> >
>> >
>> > Amit Daniel Kachhap (6):
>> > thermal: Add a new trip type to use cooling device instance number
>> > thermal: Add generic cpufreq cooling implementation
>> > thermal: Add generic cpuhotplug cooling implementation
>> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
>> > directory
>> > thermal: exynos4: Register the tmu sensor with the kernel thermal
>> > layer
>> > ARM: exynos4: Add thermal sensor driver platform device support
>> >
>> > Documentation/hwmon/exynos4_tmu | 81 ---
>> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
>> > Documentation/thermal/exynos4_tmu | 52 ++
>> > Documentation/thermal/sysfs-api.txt | 4 +-
>> > arch/arm/mach-exynos/Kconfig | 11 +
>> > arch/arm/mach-exynos/Makefile | 1 +
>> > arch/arm/mach-exynos/clock.c | 4 +
>> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
>> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
>> > arch/arm/mach-exynos/include/mach/map.h | 1 +
>> > arch/arm/mach-exynos/mach-origen.c | 1 +
>> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
>> > drivers/hwmon/Kconfig | 10 -
>> > drivers/hwmon/Makefile | 1 -
>> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
>> > drivers/thermal/Kconfig | 21 +
>> > drivers/thermal/Makefile | 2 +
>> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
>> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
>> > drivers/thermal/thermal_sys.c | 45 ++-
>> > include/linux/cpu_cooling.h | 78 +++
>> > include/linux/platform_data/exynos4_tmu.h | 7 +
>> > include/linux/thermal.h | 1 +
>> > 23 files changed, 1660 insertions(+), 611 deletions(-)
>> > delete mode 100644 Documentation/hwmon/exynos4_tmu
>> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
>> > create mode 100644 Documentation/thermal/exynos4_tmu
>> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
>> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
>> > create mode 100644 drivers/thermal/cpu_cooling.c
>> > create mode 100644 drivers/thermal/exynos4_thermal.c
>> > create mode 100644 include/linux/cpu_cooling.h
>> >
>
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-11 12:47 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-11 12:59 UTC (permalink / raw)
To: Zhang Rui
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
SGkgUnVpLAoKVGhhbmtzIGZvciBsb29raW5nIGludG8gdGhlIHBhdGNoZXMuCgpPbiAxMCBBcHJp
bCAyMDEyIDA2OjI4LCBaaGFuZyBSdWkgPHJ1aS56aGFuZ0BpbnRlbC5jb20+IHdyb3RlOgo+IEhp
LCBBbWl0LAo+Cj4gT24g5LiJLCAyMDEyLTA0LTA0IGF0IDEwOjAyICswNTMwLCBBbWl0IEthY2ho
YXAgd3JvdGU6Cj4+IEhpIExlbi9SdWksCj4+Cj4+IEFueSBjb21tZW50IG9yIGZlZWRiYWNrIGZy
b20geW91ciBzaWRlIGFib3V0IHRoZSBzdGF0dXMgb2YgdGhpcyBwYXRjaD8KPj4gSXMgaXQgbWVy
Z2UtYWJsZSBvciBtYWpvciByZS13b3JrIGlzIG5lZWRlZD8gSSBoYXZlIGZpeGVkIG1vc3Qgb2Yg
dGhlCj4+IGNvbW1lbnRzIGluIHRoaXMgcGF0Y2hzZXQgYW5kIGN1cnJlbnRseSB3b3JraW5nIG9u
IHNvbWUgb2YgdGhlIG1pbm9yCj4+IGNvbW1lbnRzIHJlY2VpdmVkIGFuZCB3aWxsIHN1Ym1pdCB0
aGVtIHNob3J0bHkuCj4+Cj4gU29ycnkgZm9yIHRoZSBsYXRlIHJlc3BvbnNlLgo+Cj4gRmlyc3Qg
b2YgYWxsLCBpdCBtYWtlcyBzZW5zZSB0byBtZSB0byBpbnRyb2R1Y2UgdGhlIGdlbmVyaWMgY3B1
ZnJxCj4gY29vbGluZyBpbXBsZW1lbnRhdGlvbi4Kb2sgdGhhbmtzCj4gQnV0IEkgc3RpbGwgaGF2
ZSBzb21lIHF1ZXN0aW9ucy4KPiBJIHRoaW5rIHRoZSBrZXkgcmVhc29uIHdoeSBUSEVSTUFMX1RS
SVBfU1RBVEVfSU5TVEFOQ0UgaXMgaW50cm9kdWNlZCBpcwo+IHRoYXQgdGhlIE1PTklST1JfWk9O
RSBhbmQgV0FSTl9aT05FIG9uIGV4eW5vczQgY2FuIG5vdCBmaXQgaW50byB0aGUKPiBjdXJyZW50
IHBhc3NpdmUgaGFuZGxpbmcgaW4gdGhlIGdlbmVyaWMgdGhlcm1hbCBsYXllciB3ZWxsLCByaWdo
dD8KPiBlLmcuIHRoZXJlIGlzIG5vIHRjMS90YzIgb24gZXh5bm9zNC4KPgo+IElmIHllcywgaXMg
aXQgcG9zc2libGUgdGhhdCB3ZSBjYW4gZW5oYW5jZSB0aGUgcGFzc2l2ZSBjb29saW5nIHRvCj4g
c3VwcG9ydCB0aGUgZ2VuZXJpYyBwcm9jZXNzb3IgY29vbGluZz8KPiBzYXksIGludHJvZHVjZSBh
bm90aGVyIHdheSB0byB0aHJvdHRsZSB0aGUgcHJvY2Vzc29yIGluCj4gdGhlcm1hbF96b25lX2Rl
dmljZV9wYXNzaXZlIHdoZW4gdGMxIGFuZCB0YzIgYXJlIG5vdCBhdmFpbGFibGU/CgpJIGFncmVl
IHRoYXQgdGhpcyBuZXcgdHJpcCB0eXBlIGNvZGUgY2FuIGJlIG1vdmVkIGludG8gcGFzc2l2ZSB0
cmlwCnR5cGUgd2hlbiB0YzEgYW5kIHRjMiBhcmUgMC4gYnV0IHRoaXMgaXMgc3BlY2lhbCB0eXBl
IG9mIGNvb2xpbmcKZGV2aWNlcyBiZWhhdmlvdXIgd2hlcmUgb25seSBpbnN0YW5jZXMgb2YgdGhl
IHNhbWUgY29vbGluZyBkZXZpY2UgaXMKYmluZGVkIHRvIGEgdHJpcCBwb2ludC4gVGhlIG9yZGVy
IG9mIG1hcHBpbmcgaXMgdGhlIG9ubHkKZGlmZmVyZW50aWF0aW5nIGNyaXRlcmlhIGFuZCB0aGVy
ZSBhcmUgc29tZSBjaGVja3MgdXNlZCB0byBpbXBsZW1lbnQKdGhpcyBsaWtlCjEpIFRoZSB0cmlw
IHBvaW50cyBzaG91bGQgYmUgaW4gYXNjZW5kaW5nIG9yZGVyLihUaGlzIGlzIG1pc3NpbmcgaW4g
bXkKb3JpZ2luYWwgcGF0Y2gsIHNvIEkgYWRkZWQgYmVsb3cpCjIpIFRoZSBzZXRfY3VyX3N0YXRl
IGhhcyB0byBiZSBjYWxsZWQgZm9yIHRoZSBleGFjdCB0ZW1wIHJhbmdlIHNvCmdldF9jdXJfc3Rh
dGUoJnN0YXRlKSBhbmQgc2V0X2N1cl9zdGF0ZShzdGF0ZSArKy9zdGF0ZS0tKSBsb2dpYyBpcyBu
b3QKcG9zc2libGUuCjMpIHNldF9jdXJfc3RhdGUgaXMgY2FsbGVkIGFzIHNldF9jdXJfc3RhdGUo
Y2Rldl9pbnN0YW5jZSkuClRoZXJlIGlzIGEgY2hhbmNlIHRoYXQgcGVvcGxlIG1pZ2h0IGNvbmZ1
c2UgdGhhdCB0aGVzZSBjaGVja3MgYXJlCmFwcGxpY2FibGUgZm9yIHBhc3NpdmUgdHJpcCB0eXBl
cyBhbHNvIHdoaWNoIGlzIG5vdCB0aGUgY2FzZSBoZXJlLgoKQEAgLTExODcsNiArMTIyOCwyMSBA
QCBzdHJ1Y3QgdGhlcm1hbF96b25lX2RldmljZQoqdGhlcm1hbF96b25lX2RldmljZV9yZWdpc3Rl
cihjaGFyICp0eXBlLAogICAgICAgICAgICAgICAgdHotPm9wcy0+Z2V0X3RyaXBfdHlwZSh0eiwg
Y291bnQsICZ0cmlwX3R5cGUpOwogICAgICAgICAgICAgICAgaWYgKHRyaXBfdHlwZSA9PSBUSEVS
TUFMX1RSSVBfUEFTU0lWRSkKICAgICAgICAgICAgICAgICAgICAgICAgcGFzc2l2ZSA9IDE7Cisg
ICAgICAgICAgICAgICAvKgorICAgICAgICAgICAgICAgICogRm9yIFRIRVJNQUxfVFJJUF9TVEFU
RV9JTlNUQU5DRSB0cmlwcywgdGhlcm1hbCB6b25lIHNob3VsZAorICAgICAgICAgICAgICAgICog
YmUgaW4gYXNjZW5kaW5nIG9yZGVyLgorICAgICAgICAgICAgICAgKi8KKyAgICAgICAgICAgICAg
IGlmICh0cmlwX3R5cGUgPT0gVEhFUk1BTF9UUklQX1NUQVRFX0lOU1RBTkNFKSB7CisgICAgICAg
ICAgICAgICAgICAgICAgIHR6LT5vcHMtPmdldF90cmlwX3RlbXAodHosIGNvdW50LCAmdHJpcF90
ZW1wKTsKKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZpcnN0X3RyaXBfdGVtcCA9PSAwKQor
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X3RyaXBfdGVtcCA9IHRyaXBfdGVt
cDsKKyAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZmlyc3RfdHJpcF90ZW1wIDwgdHJp
cF90ZW1wKQorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X3RyaXBfdGVtcCA9
IHRyaXBfdGVtcDsKKyAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZmlyc3RfdHJpcF90
ZW1wID4gdHJpcF90ZW1wKSB7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJfd2Fy
bigiWm9uZSB0cmlwIHBvaW50cyBzaG91bGQgYmUgaW4KYXNjZW5kaW5nIG9yZGVyXG4iKTsKKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb3RvIHVucmVnaXN0ZXI7CisgICAgICAgICAg
ICAgICAgICAgICAgIH0KKyAgICAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmICgh
cGFzc2l2ZSkKCkFueXdheSB0aGVyZSBpcyBvdGhlciBhbHRlcm5hdGl2ZSB3aGVyZSB0aGlzIG5l
dyB0cmlwIHR5cGUgaXMgbm90Cm5lZWRlZCBhbmQgSSBjYW4ganVzdCB1c2UgdGhlIGV4aXN0aW5n
IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfQUNUSVZFCmFuZCBjcmVhdGUgMiBzZXBhcmF0ZSBjb29s
aW5nIGRldmljZXMgZm9yIE1PTklUT1JfWk9ORSBhbmQgV0FSTl9aT05FLgpJIGhhZCB0aG91Z2h0
IHRvIG1ha2UgdGhpcyBnZW5lcmljIGFuZCBqdXN0IHRvIG1hbmFnZSB3aXRoIDEgY29vbGluZwpk
ZXZpY2UuCldoYXQgaXMgeW91ciB2aWV3PwoKVGhhbmtzLApBbWl0IERhbmllbAoKCj4KPiB0aGFu
a3MsCj4gcnVpCj4KPj4gUmVnYXJkcywKPj4gQW1pdCBEYW5pZWwKPj4KPj4gT24gMTkgTWFyY2gg
MjAxMiAxMTo0NywgQW1pdCBEYW5pZWwgS2FjaGhhcCA8YW1pdC5rYWNoaGFwQGxpbmFyby5vcmc+
IHdyb3RlOgo+PiA+IENoYW5nZXMgc2luY2UgVjE6Cj4+ID4gKk1vdmVkIHRoZSBzZW5zb3IgZHJp
dmVyIHRvIGRyaXZlci90aGVybWFsIGZvbGRlciBmcm9tIGRyaXZlci9od21vbiBmb2xkZXIKPj4g
PiDCoGFzIHN1Z2dlc3RlZCBieSBNYXJrIEJyb3duIGFuZCBHdWVudGVyIFJvZWNrCj4+ID4gKkFk
ZGVkIG5vdGlmaWVyIHN1cHBvcnQgdG8gbm90aWZ5IHRoZSByZWdpc3RlcmVkIGRyaXZlcnMgb2Yg
YW55IGNwdSBjb29saW5nCj4+ID4gwqBhY3Rpb24uIFRoZSBkcml2ZXIgY2FuIG1vZGlmeSB0aGUg
ZGVmYXVsdCBjb29saW5nIGJlaGF2aW91cihlZyBzZXQgZGlmZmVyZW50Cj4+ID4gwqBtYXggY2xp
cCBmcmVxdWVuY3kpLgo+PiA+ICpUaGUgcGVyY2VudGFnZSBiYXNlZCBmcmVxdWVuY3kgcmVwbGFj
ZWQgd2l0aCBhYnNvbHV0ZSBjbGlwcGVkIGZyZXF1ZW5jeS4KPj4gPiAqU29tZSBtb3JlIGNvbmRp
dGlvbmFsIGNoZWNrcyB3aGVuIHNldHRpbmcgbWF4IGZyZXF1ZW5jeS4KPj4gPiAqUmVuYW1lZCB0
aGUgbmV3IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfQUNUSVZFIHRvCj4+ID4gwqBUSEVS
TUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0UKPj4gPiAqTWFueSByZXZpZXcgY29tbWVudHMgZnJvbSBS
LCBEdXJnYWRvc3MgPGR1cmdhZG9zcy5yQGludGVsLmNvbT4gYW5kCj4+ID4gwqBlZHVhcmRvLnZh
bGVudGluQHRpLmNvbSBpbXBsZW1lbnRlZC4KPj4gPiAqUmVtb3ZlZCBjb29saW5nIHN0YXRzIHRo
cm91Z2ggZGVidWdmcyBwYXRjaAo+PiA+ICpUaGUgVjEgYmFzZWQgY2FuIGJlIGZvdW5kIGhlcmUs
Cj4+ID4gwqBodHRwczovL2xrbWwub3JnL2xrbWwvMjAxMi8yLzIyLzEyMwo+PiA+IMKgaHR0cDov
L2xrbWwub3JnL2xrbWwvMjAxMi8zLzMvMzIKPj4gPgo+PiA+IENoYW5nZXMgc2luY2UgUkZDOgo+
PiA+ICpDaGFuZ2VkIHRoZSBjcHUgY29vbGluZyByZWdpc3RyYXRpb24vdW5yZWdpc3RyYXRpb24g
QVBJJ3MgdG8gaW5zdGFuY2UgYmFzZWQKPj4gPiAqQ2hhbmdlZCB0aGUgU1RBVEVfQUNUSVZFIHRy
aXAgdHlwZSB0byBwYXNzIGNvcnJlY3QgaW5zdGFuY2UgaWQKPj4gPiAqQWRkaW5nIHN1cHBvcnQg
dG8gcmVzdG9yZSBiYWNrIHRoZSBwb2xpY3ktPm1heF9mcmVxIGFmdGVyIGRvaW5nIGZyZXF1ZW5j
eQo+PiA+IMKgY2xpcHBpbmcuCj4+ID4gKk1vdmVkIHRoZSB0cmlwIGNvb2xpbmcgc3RhdHMgZnJv
bSBzeXNmcyBub2RlIHRvIGRlYnVnZnMgbm9kZSBhcyBzdWdnZXN0ZWQKPj4gPiDCoGJ5IEdyZWcg
S0ggZ3JlZ0Brcm9haC5jb20KPj4gPiAqSW5jb3Jwb3JhdGVkIHNldmVyYWwgcmV2aWV3IGNvbW1l
bnRzIGZyb20gZWR1YXJkby52YWxlbnRpbkB0aS5jb20KPj4gPiAqTW92ZWQgdGhlIFRlbXBlcmF0
dXJlIHNlbnNvciBkcml2ZXIgZnJvbSBkcml2ZXIvaHdtb24vIHRvIGRyaXZlci9tZmQKPj4gPiDC
oGFzIGRpc2N1c3NlZCB3aXRoIEd1ZW50ZXIgUm9lY2sgPGd1ZW50ZXIucm9lY2tAZXJpY3Nzb24u
Y29tPiBhbmQKPj4gPiDCoERvbmdnZXVuIEtpbSA8ZGc3Ny5raW1Ac2Ftc3VuZy5jb20+IChodHRw
czovL2xrbWwub3JnL2xrbWwvMjAxMi8xLzUvNykKPj4gPiAqU29tZSBjaGFuZ2VzIGFjY29yZGlu
ZyB0byB0aGUgY2hhbmdlcyBpbiBjb21tb24gY3B1IGNvb2xpbmcgQVBJcwo+PiA+ICpUaGUgUkZD
IGJhc2VkIHBhdGNoZXMgY2FuIGJlIGZvdW5kIGhlcmUsCj4+ID4gwqBodHRwczovL2xrbWwub3Jn
L2xrbWwvMjAxMS8xMi8xMy8xODYKPj4gPiDCoGh0dHBzOi8vbGttbC5vcmcvbGttbC8yMDExLzEy
LzIxLzE2OQo+PiA+Cj4+ID4KPj4gPiBCcmllZiBEZXNjcmlwdGlvbjoKPj4gPgo+PiA+IDEpIFRo
ZSBnZW5lcmljIGNvb2xpbmcgZGV2aWNlcyBjb2RlIGlzIHBsYWNlZCBpbnNpZGUgZHJpdmVyL3Ro
ZXJtYWwvKiBhcwo+PiA+IHBsYWNpbmcgaW5zaWRlIGFjcGkgZm9sZGVyIHdpbGwgbmVlZCB1bi1u
ZWNlc3NhcnkgZW5hYmxpbmcgb2YgYWNwaSBjb2RlLiBUaGlzCj4+ID4gY29kZXMgaXMgYXJjaGl0
ZWN0dXJlIGluZGVwZW5kZW50Lgo+PiA+Cj4+ID4gMikgVGhpcyBwYXRjaHNldCBhZGRzIGEgbmV3
IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0Ugd2hpY2ggcGFzc2VzCj4+ID4g
Y29vbGluZyBkZXZpY2UgaW5zdGFuY2UgbnVtYmVyIGFuZCBtYXkgYmUgaGVscGZ1bCBmb3IgY3B1
ZnJlcSBjb29saW5nIGRldmljZXMKPj4gPiB0byB0YWtlIHRoZSBjb3JyZWN0IGNvb2xpbmcgYWN0
aW9uLiBUaGlzIHRyaXAgdHlwZSBhdm9pZHMgdGhlIHRlbXBlcmF0dXJlCj4+ID4gY29tcGFyaXNp
b24gY2hlY2sgYWdhaW4gaW5zaWRlIHRoZSBjb29saW5nIGhhbmRsZXIuCj4+ID4KPj4gPiAzKSBU
aGlzIHBhdGNoc2V0IGFkZHMgZ2VuZXJpYyBjcHUgY29vbGluZyBsb3cgbGV2ZWwgaW1wbGVtZW50
YXRpb24gdGhyb3VnaAo+PiA+IGZyZXF1ZW5jeSBjbGlwcGluZyBhbmQgY3B1IGhvdHBsdWcuIElu
IGZ1dHVyZSwgb3RoZXIgY3B1IHJlbGF0ZWQgY29vbGluZwo+PiA+IGRldmljZXMgbWF5IGJlIGFk
ZGVkIGhlcmUuIEFuIEFDUEkgdmVyc2lvbiBvZiB0aGlzIGFscmVhZHkgZXhpc3RzCj4+ID4gKGRy
aXZlcnMvYWNwaS9wcm9jZXNzb3JfdGhlcm1hbC5jKS4gQnV0IHRoaXMgd2lsbCBiZSB1c2VmdWwg
Zm9yIHBsYXRmb3Jtcwo+PiA+IGxpa2UgQVJNIHVzaW5nIHRoZSBnZW5lcmljIHRoZXJtYWwgaW50
ZXJmYWNlIGFsb25nIHdpdGggdGhlIGdlbmVyaWMgY3B1Cj4+ID4gY29vbGluZyBkZXZpY2VzLiBU
aGUgY29vbGluZyBkZXZpY2UgcmVnaXN0cmF0aW9uIEFQSSdzIHJldHVybiBjb29saW5nIGRldmlj
ZQo+PiA+IHBvaW50ZXJzIHdoaWNoIGNhbiBiZSBlYXNpbHkgYmluZGVkIHdpdGggdGhlIHRoZXJt
YWwgem9uZSB0cmlwIHBvaW50cy4KPj4gPiBUaGUgaW1wb3J0YW50IEFQSXMgZXhwb3NlZCBhcmUs
Cj4+ID4gwqAgYSlzdHJ1Y3QgdGhlcm1hbF9jb29saW5nX2RldmljZSAqY3B1ZnJlcV9jb29saW5n
X3JlZ2lzdGVyKAo+PiA+IMKgIMKgIMKgIMKgc3RydWN0IGZyZXFfY2xpcF90YWJsZSAqdGFiX3B0
ciwgdW5zaWduZWQgaW50IHRhYl9zaXplLAo+PiA+IMKgIMKgIMKgIMKgY29uc3Qgc3RydWN0IGNw
dW1hc2sgKm1hc2tfdmFsKQo+PiA+IMKgIGIpdm9pZCBjcHVmcmVxX2Nvb2xpbmdfdW5yZWdpc3Rl
cihzdHJ1Y3QgdGhlcm1hbF9jb29saW5nX2RldmljZSAqY2RldikKPj4gPgo+PiA+IDQpIFNhbXN1
bmcgZXh5bm9zIHBsYXRmb3JtIHRoZXJtYWwgaW1wbGVtZW50YXRpb24gaXMgZG9uZSB1c2luZyB0
aGUgZ2VuZXJpYwo+PiA+IGNwdSBjb29saW5nIEFQSXMgYW5kIHRoZSBuZXcgdHJpcCB0eXBlLiBU
aGUgdGVtcGVyYXR1cmUgc2Vuc29yIGRyaXZlciBwcmVzZW50Cj4+ID4gaW4gdGhlIGh3bW9uIGZv
bGRlcihyZWdpc3RlcmVkIGFzIGh3bW9uIGRyaXZlcikgaXMgbW92ZWQgdG8gdGhlcm1hbCBmb2xk
ZXIKPj4gPiBhbmQgcmVnaXN0ZXJlZCBhcyBhIHRoZXJtYWwgZHJpdmVyLgo+PiA+Cj4+ID4gQWxs
IHRoaXMgcGF0Y2hzZXQgaXMgYmFzZWQgb24gS2VybmVsIHZlcnNpb24gMy4zLXJjNwo+PiA+Cj4+
ID4gQSBzaW1wbGUgZGF0YS9jb250cm9sIGZsb3cgZGlhZ3JhbXMgaXMgc2hvd24gYmVsb3csCj4+
ID4KPj4gPiBDb3JlIExpbnV4IHRoZXJtYWwgPC0tLS0tPiDCoEV4eW5vcyB0aGVybWFsIGludGVy
ZmFjZSA8LS0tLS0gVGVtcGVyYXR1cmUgU2Vuc29yCj4+ID4gwqAgwqAgwqAgwqAgwqB8IMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHwKPj4gPiDCoCDCoCDCoCDCoCBc
fC8gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB8Cj4+ID4gwqBDcHVm
cmVxIGNvb2xpbmcgZGV2aWNlIDwtLS0tLS0tLS0tLS0tLS0KPj4gPgo+PiA+Cj4+ID4gQW1pdCBE
YW5pZWwgS2FjaGhhcCAoNik6Cj4+ID4gwqB0aGVybWFsOiBBZGQgYSBuZXcgdHJpcCB0eXBlIHRv
IHVzZSBjb29saW5nIGRldmljZSBpbnN0YW5jZSBudW1iZXIKPj4gPiDCoHRoZXJtYWw6IEFkZCBn
ZW5lcmljIGNwdWZyZXEgY29vbGluZyBpbXBsZW1lbnRhdGlvbgo+PiA+IMKgdGhlcm1hbDogQWRk
IGdlbmVyaWMgY3B1aG90cGx1ZyBjb29saW5nIGltcGxlbWVudGF0aW9uCj4+ID4gwqBod21vbjog
ZXh5bm9zNDogTW92ZSB0aGVybWFsIHNlbnNvciBkcml2ZXIgdG8gZHJpdmVyL3RoZXJtYWwKPj4g
PiDCoCDCoGRpcmVjdG9yeQo+PiA+IMKgdGhlcm1hbDogZXh5bm9zNDogUmVnaXN0ZXIgdGhlIHRt
dSBzZW5zb3Igd2l0aCB0aGUga2VybmVsIHRoZXJtYWwKPj4gPiDCoCDCoGxheWVyCj4+ID4gwqBB
Uk06IGV4eW5vczQ6IEFkZCB0aGVybWFsIHNlbnNvciBkcml2ZXIgcGxhdGZvcm0gZGV2aWNlIHN1
cHBvcnQKPj4gPgo+PiA+IMKgRG9jdW1lbnRhdGlvbi9od21vbi9leHlub3M0X3RtdSDCoCDCoCDC
oCDCoCDCoCB8IMKgIDgxIC0tLQo+PiA+IMKgRG9jdW1lbnRhdGlvbi90aGVybWFsL2NwdS1jb29s
aW5nLWFwaS50eHQgfCDCoCA3NiArKysKPj4gPiDCoERvY3VtZW50YXRpb24vdGhlcm1hbC9leHlu
b3M0X3RtdSDCoCDCoCDCoCDCoCB8IMKgIDUyICsrCj4+ID4gwqBEb2N1bWVudGF0aW9uL3RoZXJt
YWwvc3lzZnMtYXBpLnR4dCDCoCDCoCDCoCB8IMKgIMKgNCArLQo+PiA+IMKgYXJjaC9hcm0vbWFj
aC1leHlub3MvS2NvbmZpZyDCoCDCoCDCoCDCoCDCoCDCoCDCoHwgwqAgMTEgKwo+PiA+IMKgYXJj
aC9hcm0vbWFjaC1leHlub3MvTWFrZWZpbGUgwqAgwqAgwqAgwqAgwqAgwqAgfCDCoCDCoDEgKwo+
PiA+IMKgYXJjaC9hcm0vbWFjaC1leHlub3MvY2xvY2suYyDCoCDCoCDCoCDCoCDCoCDCoCDCoHwg
wqAgwqA0ICsKPj4gPiDCoGFyY2gvYXJtL21hY2gtZXh5bm9zL2Rldi10bXUuYyDCoCDCoCDCoCDC
oCDCoCDCoHwgwqAgMzkgKysKPj4gPiDCoGFyY2gvYXJtL21hY2gtZXh5bm9zL2luY2x1ZGUvbWFj
aC9pcnFzLmggwqB8IMKgIMKgMiArCj4+ID4gwqBhcmNoL2FybS9tYWNoLWV4eW5vcy9pbmNsdWRl
L21hY2gvbWFwLmggwqAgfCDCoCDCoDEgKwo+PiA+IMKgYXJjaC9hcm0vbWFjaC1leHlub3MvbWFj
aC1vcmlnZW4uYyDCoCDCoCDCoCDCoHwgwqAgwqAxICsKPj4gPiDCoGFyY2gvYXJtL3BsYXQtc2Ft
c3VuZy9pbmNsdWRlL3BsYXQvZGV2cy5oIHwgwqAgwqAxICsKPj4gPiDCoGRyaXZlcnMvaHdtb24v
S2NvbmZpZyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB8IMKgIDEwIC0KPj4gPiDCoGRy
aXZlcnMvaHdtb24vTWFrZWZpbGUgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB8IMKgIMKg
MSAtCj4+ID4gwqBkcml2ZXJzL2h3bW9uL2V4eW5vczRfdG11LmMgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgfCDCoDUxNCAtLS0tLS0tLS0tLS0tLS0tLS0tCj4+ID4gwqBkcml2ZXJzL3RoZXJtYWwvS2Nv
bmZpZyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB8IMKgIDIxICsKPj4gPiDCoGRyaXZlcnMv
dGhlcm1hbC9NYWtlZmlsZSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHwgwqAgwqAyICsKPj4g
PiDCoGRyaXZlcnMvdGhlcm1hbC9jcHVfY29vbGluZy5jIMKgIMKgIMKgIMKgIMKgIMKgIHwgwqA1
MjkgKysrKysrKysrKysrKysrKysrKwo+PiA+IMKgZHJpdmVycy90aGVybWFsL2V4eW5vczRfdGhl
cm1hbC5jIMKgIMKgIMKgIMKgIHwgwqA3OTAgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysK
Pj4gPiDCoGRyaXZlcnMvdGhlcm1hbC90aGVybWFsX3N5cy5jIMKgIMKgIMKgIMKgIMKgIMKgIHwg
wqAgNDUgKystCj4+ID4gwqBpbmNsdWRlL2xpbnV4L2NwdV9jb29saW5nLmggwqAgwqAgwqAgwqAg
wqAgwqAgwqAgfCDCoCA3OCArKysKPj4gPiDCoGluY2x1ZGUvbGludXgvcGxhdGZvcm1fZGF0YS9l
eHlub3M0X3RtdS5oIHwgwqAgwqA3ICsKPj4gPiDCoGluY2x1ZGUvbGludXgvdGhlcm1hbC5oIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHwgwqAgwqAxICsKPj4gPiDCoDIzIGZpbGVzIGNoYW5n
ZWQsIDE2NjAgaW5zZXJ0aW9ucygrKSwgNjExIGRlbGV0aW9ucygtKQo+PiA+IMKgZGVsZXRlIG1v
ZGUgMTAwNjQ0IERvY3VtZW50YXRpb24vaHdtb24vZXh5bm9zNF90bXUKPj4gPiDCoGNyZWF0ZSBt
b2RlIDEwMDY0NCBEb2N1bWVudGF0aW9uL3RoZXJtYWwvY3B1LWNvb2xpbmctYXBpLnR4dAo+PiA+
IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRpb24vdGhlcm1hbC9leHlub3M0X3RtdQo+
PiA+IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IGFyY2gvYXJtL21hY2gtZXh5bm9zL2Rldi10bXUuYwo+
PiA+IMKgZGVsZXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaHdtb24vZXh5bm9zNF90bXUuYwo+PiA+
IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdGhlcm1hbC9jcHVfY29vbGluZy5jCj4+ID4g
wqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90aGVybWFsL2V4eW5vczRfdGhlcm1hbC5jCj4+
ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS9saW51eC9jcHVfY29vbGluZy5oCj4+ID4K
Pgo+CgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpsbS1z
ZW5zb3JzIG1haWxpbmcgbGlzdApsbS1zZW5zb3JzQGxtLXNlbnNvcnMub3JnCmh0dHA6Ly9saXN0
cy5sbS1zZW5zb3JzLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xtLXNlbnNvcnM
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
2012-04-11 12:47 ` Amit Kachhap
(?)
@ 2012-04-16 2:07 ` Zhang Rui
-1 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-16 2:07 UTC (permalink / raw)
To: Amit Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
On 三, 2012-04-11 at 18:17 +0530, Amit Kachhap wrote:
> Hi Rui,
>
> Thanks for looking into the patches.
>
> On 10 April 2012 06:28, Zhang Rui <rui.zhang@intel.com> wrote:
> > Hi, Amit,
> >
> > On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
> >> Hi Len/Rui,
> >>
> >> Any comment or feedback from your side about the status of this patch?
> >> Is it merge-able or major re-work is needed? I have fixed most of the
> >> comments in this patchset and currently working on some of the minor
> >> comments received and will submit them shortly.
> >>
> > Sorry for the late response.
> >
> > First of all, it makes sense to me to introduce the generic cpufrq
> > cooling implementation.
> ok thanks
> > But I still have some questions.
> > I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
> > that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
> > current passive handling in the generic thermal layer well, right?
> > e.g. there is no tc1/tc2 on exynos4.
> >
> > If yes, is it possible that we can enhance the passive cooling to
> > support the generic processor cooling?
> > say, introduce another way to throttle the processor in
> > thermal_zone_device_passive when tc1 and tc2 are not available?
>
> I agree that this new trip type code can be moved into passive trip
> type when tc1 and tc2 are 0. but this is special type of cooling
> devices behaviour where only instances of the same cooling device is
> binded to a trip point. The order of mapping is the only
> differentiating criteria and there are some checks used to implement
> this like
> 1) The trip points should be in ascending order.(This is missing in my
> original patch, so I added below)
> 2) The set_cur_state has to be called for the exact temp range so
> get_cur_state(&state) and set_cur_state(state ++/state--) logic is not
> possible.
> 3) set_cur_state is called as set_cur_state(cdev_instance).
Do you really need two THERMAL_TRIP_STATE_INSTANCE trip points?
I'm not sure if my understanding is right, but IMO, we can have one
THERMAL_TRIP_STATE_INSTANCE only, for both MONIROR_ZONE and WARN_ZONE,
and the trip temperature equals MONIROR_ZONE.
The cpufreq cooling device will work in the same way, no?
thanks,
rui
> There is a chance that people might confuse that these checks are
> applicable for passive trip types also which is not the case here.
>
> @@ -1187,6 +1228,21 @@ struct thermal_zone_device
> *thermal_zone_device_register(char *type,
> tz->ops->get_trip_type(tz, count, &trip_type);
> if (trip_type == THERMAL_TRIP_PASSIVE)
> passive = 1;
> + /*
> + * For THERMAL_TRIP_STATE_INSTANCE trips, thermal zone should
> + * be in ascending order.
> + */
> + if (trip_type == THERMAL_TRIP_STATE_INSTANCE) {
> + tz->ops->get_trip_temp(tz, count, &trip_temp);
> + if (first_trip_temp == 0)
> + first_trip_temp = trip_temp;
> + else if (first_trip_temp < trip_temp)
> + first_trip_temp = trip_temp;
> + else if (first_trip_temp > trip_temp) {
> + pr_warn("Zone trip points should be in
> ascending order\n");
> + goto unregister;
> + }
> + }
> }
>
> if (!passive)
>
> Anyway there is other alternative where this new trip type is not
> needed and I can just use the existing trip type THERMAL_TRIP_ACTIVE
> and create 2 separate cooling devices for MONITOR_ZONE and WARN_ZONE.
> I had thought to make this generic and just to manage with 1 cooling
> device.
> What is your view?
>
> Thanks,
> Amit Daniel
>
>
> >
> > thanks,
> > rui
> >
> >> Regards,
> >> Amit Daniel
> >>
> >> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> >> > Changes since V1:
> >> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> >> > as suggested by Mark Brown and Guenter Roeck
> >> > *Added notifier support to notify the registered drivers of any cpu cooling
> >> > action. The driver can modify the default cooling behaviour(eg set different
> >> > max clip frequency).
> >> > *The percentage based frequency replaced with absolute clipped frequency.
> >> > *Some more conditional checks when setting max frequency.
> >> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> >> > THERMAL_TRIP_STATE_INSTANCE
> >> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> >> > eduardo.valentin@ti.com implemented.
> >> > *Removed cooling stats through debugfs patch
> >> > *The V1 based can be found here,
> >> > https://lkml.org/lkml/2012/2/22/123
> >> > http://lkml.org/lkml/2012/3/3/32
> >> >
> >> > Changes since RFC:
> >> > *Changed the cpu cooling registration/unregistration API's to instance based
> >> > *Changed the STATE_ACTIVE trip type to pass correct instance id
> >> > *Adding support to restore back the policy->max_freq after doing frequency
> >> > clipping.
> >> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> >> > by Greg KH greg@kroah.com
> >> > *Incorporated several review comments from eduardo.valentin@ti.com
> >> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> >> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> >> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> >> > *Some changes according to the changes in common cpu cooling APIs
> >> > *The RFC based patches can be found here,
> >> > https://lkml.org/lkml/2011/12/13/186
> >> > https://lkml.org/lkml/2011/12/21/169
> >> >
> >> >
> >> > Brief Description:
> >> >
> >> > 1) The generic cooling devices code is placed inside driver/thermal/* as
> >> > placing inside acpi folder will need un-necessary enabling of acpi code. This
> >> > codes is architecture independent.
> >> >
> >> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> >> > cooling device instance number and may be helpful for cpufreq cooling devices
> >> > to take the correct cooling action. This trip type avoids the temperature
> >> > comparision check again inside the cooling handler.
> >> >
> >> > 3) This patchset adds generic cpu cooling low level implementation through
> >> > frequency clipping and cpu hotplug. In future, other cpu related cooling
> >> > devices may be added here. An ACPI version of this already exists
> >> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> >> > like ARM using the generic thermal interface along with the generic cpu
> >> > cooling devices. The cooling device registration API's return cooling device
> >> > pointers which can be easily binded with the thermal zone trip points.
> >> > The important APIs exposed are,
> >> > a)struct thermal_cooling_device *cpufreq_cooling_register(
> >> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
> >> > const struct cpumask *mask_val)
> >> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> >> >
> >> > 4) Samsung exynos platform thermal implementation is done using the generic
> >> > cpu cooling APIs and the new trip type. The temperature sensor driver present
> >> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> >> > and registered as a thermal driver.
> >> >
> >> > All this patchset is based on Kernel version 3.3-rc7
> >> >
> >> > A simple data/control flow diagrams is shown below,
> >> >
> >> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> >> > | |
> >> > \|/ |
> >> > Cpufreq cooling device <---------------
> >> >
> >> >
> >> > Amit Daniel Kachhap (6):
> >> > thermal: Add a new trip type to use cooling device instance number
> >> > thermal: Add generic cpufreq cooling implementation
> >> > thermal: Add generic cpuhotplug cooling implementation
> >> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
> >> > directory
> >> > thermal: exynos4: Register the tmu sensor with the kernel thermal
> >> > layer
> >> > ARM: exynos4: Add thermal sensor driver platform device support
> >> >
> >> > Documentation/hwmon/exynos4_tmu | 81 ---
> >> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
> >> > Documentation/thermal/exynos4_tmu | 52 ++
> >> > Documentation/thermal/sysfs-api.txt | 4 +-
> >> > arch/arm/mach-exynos/Kconfig | 11 +
> >> > arch/arm/mach-exynos/Makefile | 1 +
> >> > arch/arm/mach-exynos/clock.c | 4 +
> >> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
> >> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> >> > arch/arm/mach-exynos/include/mach/map.h | 1 +
> >> > arch/arm/mach-exynos/mach-origen.c | 1 +
> >> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
> >> > drivers/hwmon/Kconfig | 10 -
> >> > drivers/hwmon/Makefile | 1 -
> >> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
> >> > drivers/thermal/Kconfig | 21 +
> >> > drivers/thermal/Makefile | 2 +
> >> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> >> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> >> > drivers/thermal/thermal_sys.c | 45 ++-
> >> > include/linux/cpu_cooling.h | 78 +++
> >> > include/linux/platform_data/exynos4_tmu.h | 7 +
> >> > include/linux/thermal.h | 1 +
> >> > 23 files changed, 1660 insertions(+), 611 deletions(-)
> >> > delete mode 100644 Documentation/hwmon/exynos4_tmu
> >> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> >> > create mode 100644 Documentation/thermal/exynos4_tmu
> >> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> >> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
> >> > create mode 100644 drivers/thermal/cpu_cooling.c
> >> > create mode 100644 drivers/thermal/exynos4_thermal.c
> >> > create mode 100644 include/linux/cpu_cooling.h
> >> >
> >
> >
_______________________________________________
linux-pm mailing list
linux-pm@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-pm
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-16 2:07 ` Zhang Rui
0 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-16 2:07 UTC (permalink / raw)
To: Amit Kachhap
Cc: linux-samsung-soc, linaro-dev, patches, linux-kernel, lm-sensors,
linux-acpi, linux-pm
T24g5LiJLCAyMDEyLTA0LTExIGF0IDE4OjE3ICswNTMwLCBBbWl0IEthY2hoYXAgd3JvdGU6Cj4g
SGkgUnVpLAo+IAo+IFRoYW5rcyBmb3IgbG9va2luZyBpbnRvIHRoZSBwYXRjaGVzLgo+IAo+IE9u
IDEwIEFwcmlsIDIwMTIgMDY6MjgsIFpoYW5nIFJ1aSA8cnVpLnpoYW5nQGludGVsLmNvbT4gd3Jv
dGU6Cj4gPiBIaSwgQW1pdCwKPiA+Cj4gPiBPbiDkuIksIDIwMTItMDQtMDQgYXQgMTA6MDIgKzA1
MzAsIEFtaXQgS2FjaGhhcCB3cm90ZToKPiA+PiBIaSBMZW4vUnVpLAo+ID4+Cj4gPj4gQW55IGNv
bW1lbnQgb3IgZmVlZGJhY2sgZnJvbSB5b3VyIHNpZGUgYWJvdXQgdGhlIHN0YXR1cyBvZiB0aGlz
IHBhdGNoPwo+ID4+IElzIGl0IG1lcmdlLWFibGUgb3IgbWFqb3IgcmUtd29yayBpcyBuZWVkZWQ/
IEkgaGF2ZSBmaXhlZCBtb3N0IG9mIHRoZQo+ID4+IGNvbW1lbnRzIGluIHRoaXMgcGF0Y2hzZXQg
YW5kIGN1cnJlbnRseSB3b3JraW5nIG9uIHNvbWUgb2YgdGhlIG1pbm9yCj4gPj4gY29tbWVudHMg
cmVjZWl2ZWQgYW5kIHdpbGwgc3VibWl0IHRoZW0gc2hvcnRseS4KPiA+Pgo+ID4gU29ycnkgZm9y
IHRoZSBsYXRlIHJlc3BvbnNlLgo+ID4KPiA+IEZpcnN0IG9mIGFsbCwgaXQgbWFrZXMgc2Vuc2Ug
dG8gbWUgdG8gaW50cm9kdWNlIHRoZSBnZW5lcmljIGNwdWZycQo+ID4gY29vbGluZyBpbXBsZW1l
bnRhdGlvbi4KPiBvayB0aGFua3MKPiA+IEJ1dCBJIHN0aWxsIGhhdmUgc29tZSBxdWVzdGlvbnMu
Cj4gPiBJIHRoaW5rIHRoZSBrZXkgcmVhc29uIHdoeSBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFO
Q0UgaXMgaW50cm9kdWNlZCBpcwo+ID4gdGhhdCB0aGUgTU9OSVJPUl9aT05FIGFuZCBXQVJOX1pP
TkUgb24gZXh5bm9zNCBjYW4gbm90IGZpdCBpbnRvIHRoZQo+ID4gY3VycmVudCBwYXNzaXZlIGhh
bmRsaW5nIGluIHRoZSBnZW5lcmljIHRoZXJtYWwgbGF5ZXIgd2VsbCwgcmlnaHQ/Cj4gPiBlLmcu
IHRoZXJlIGlzIG5vIHRjMS90YzIgb24gZXh5bm9zNC4KPiA+Cj4gPiBJZiB5ZXMsIGlzIGl0IHBv
c3NpYmxlIHRoYXQgd2UgY2FuIGVuaGFuY2UgdGhlIHBhc3NpdmUgY29vbGluZyB0bwo+ID4gc3Vw
cG9ydCB0aGUgZ2VuZXJpYyBwcm9jZXNzb3IgY29vbGluZz8KPiA+IHNheSwgaW50cm9kdWNlIGFu
b3RoZXIgd2F5IHRvIHRocm90dGxlIHRoZSBwcm9jZXNzb3IgaW4KPiA+IHRoZXJtYWxfem9uZV9k
ZXZpY2VfcGFzc2l2ZSB3aGVuIHRjMSBhbmQgdGMyIGFyZSBub3QgYXZhaWxhYmxlPwo+IAo+IEkg
YWdyZWUgdGhhdCB0aGlzIG5ldyB0cmlwIHR5cGUgY29kZSBjYW4gYmUgbW92ZWQgaW50byBwYXNz
aXZlIHRyaXAKPiB0eXBlIHdoZW4gdGMxIGFuZCB0YzIgYXJlIDAuIGJ1dCB0aGlzIGlzIHNwZWNp
YWwgdHlwZSBvZiBjb29saW5nCj4gZGV2aWNlcyBiZWhhdmlvdXIgd2hlcmUgb25seSBpbnN0YW5j
ZXMgb2YgdGhlIHNhbWUgY29vbGluZyBkZXZpY2UgaXMKPiBiaW5kZWQgdG8gYSB0cmlwIHBvaW50
LiBUaGUgb3JkZXIgb2YgbWFwcGluZyBpcyB0aGUgb25seQo+IGRpZmZlcmVudGlhdGluZyBjcml0
ZXJpYSBhbmQgdGhlcmUgYXJlIHNvbWUgY2hlY2tzIHVzZWQgdG8gaW1wbGVtZW50Cj4gdGhpcyBs
aWtlCj4gMSkgVGhlIHRyaXAgcG9pbnRzIHNob3VsZCBiZSBpbiBhc2NlbmRpbmcgb3JkZXIuKFRo
aXMgaXMgbWlzc2luZyBpbiBteQo+IG9yaWdpbmFsIHBhdGNoLCBzbyBJIGFkZGVkIGJlbG93KQo+
IDIpIFRoZSBzZXRfY3VyX3N0YXRlIGhhcyB0byBiZSBjYWxsZWQgZm9yIHRoZSBleGFjdCB0ZW1w
IHJhbmdlIHNvCj4gZ2V0X2N1cl9zdGF0ZSgmc3RhdGUpIGFuZCBzZXRfY3VyX3N0YXRlKHN0YXRl
ICsrL3N0YXRlLS0pIGxvZ2ljIGlzIG5vdAo+IHBvc3NpYmxlLgo+IDMpIHNldF9jdXJfc3RhdGUg
aXMgY2FsbGVkIGFzIHNldF9jdXJfc3RhdGUoY2Rldl9pbnN0YW5jZSkuCgpEbyB5b3UgcmVhbGx5
IG5lZWQgdHdvIFRIRVJNQUxfVFJJUF9TVEFURV9JTlNUQU5DRSB0cmlwIHBvaW50cz8KCkknbSBu
b3Qgc3VyZSBpZiBteSB1bmRlcnN0YW5kaW5nIGlzIHJpZ2h0LCBidXQgSU1PLCB3ZSBjYW4gaGF2
ZSBvbmUKVEhFUk1BTF9UUklQX1NUQVRFX0lOU1RBTkNFIG9ubHksIGZvciBib3RoIE1PTklST1Jf
Wk9ORSBhbmQgV0FSTl9aT05FLAphbmQgdGhlIHRyaXAgdGVtcGVyYXR1cmUgZXF1YWxzIE1PTklS
T1JfWk9ORS4KVGhlIGNwdWZyZXEgY29vbGluZyBkZXZpY2Ugd2lsbCB3b3JrIGluIHRoZSBzYW1l
IHdheSwgbm8/Cgp0aGFua3MsCnJ1aQoKPiBUaGVyZSBpcyBhIGNoYW5jZSB0aGF0IHBlb3BsZSBt
aWdodCBjb25mdXNlIHRoYXQgdGhlc2UgY2hlY2tzIGFyZQo+IGFwcGxpY2FibGUgZm9yIHBhc3Np
dmUgdHJpcCB0eXBlcyBhbHNvIHdoaWNoIGlzIG5vdCB0aGUgY2FzZSBoZXJlLgo+IAo+IEBAIC0x
MTg3LDYgKzEyMjgsMjEgQEAgc3RydWN0IHRoZXJtYWxfem9uZV9kZXZpY2UKPiAqdGhlcm1hbF96
b25lX2RldmljZV9yZWdpc3RlcihjaGFyICp0eXBlLAo+ICAgICAgICAgICAgICAgICB0ei0+b3Bz
LT5nZXRfdHJpcF90eXBlKHR6LCBjb3VudCwgJnRyaXBfdHlwZSk7Cj4gICAgICAgICAgICAgICAg
IGlmICh0cmlwX3R5cGUgPT0gVEhFUk1BTF9UUklQX1BBU1NJVkUpCj4gICAgICAgICAgICAgICAg
ICAgICAgICAgcGFzc2l2ZSA9IDE7Cj4gKyAgICAgICAgICAgICAgIC8qCj4gKyAgICAgICAgICAg
ICAgICAqIEZvciBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0UgdHJpcHMsIHRoZXJtYWwgem9u
ZSBzaG91bGQKPiArICAgICAgICAgICAgICAgICogYmUgaW4gYXNjZW5kaW5nIG9yZGVyLgo+ICsg
ICAgICAgICAgICAgICAqLwo+ICsgICAgICAgICAgICAgICBpZiAodHJpcF90eXBlID09IFRIRVJN
QUxfVFJJUF9TVEFURV9JTlNUQU5DRSkgewo+ICsgICAgICAgICAgICAgICAgICAgICAgIHR6LT5v
cHMtPmdldF90cmlwX3RlbXAodHosIGNvdW50LCAmdHJpcF90ZW1wKTsKPiArICAgICAgICAgICAg
ICAgICAgICAgICBpZiAoZmlyc3RfdHJpcF90ZW1wID09IDApCj4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBmaXJzdF90cmlwX3RlbXAgPSB0cmlwX3RlbXA7Cj4gKyAgICAgICAgICAg
ICAgICAgICAgICAgZWxzZSBpZiAoZmlyc3RfdHJpcF90ZW1wIDwgdHJpcF90ZW1wKQo+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfdHJpcF90ZW1wID0gdHJpcF90ZW1wOwo+
ICsgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGZpcnN0X3RyaXBfdGVtcCA+IHRyaXBf
dGVtcCkgewo+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJfd2FybigiWm9uZSB0
cmlwIHBvaW50cyBzaG91bGQgYmUgaW4KPiBhc2NlbmRpbmcgb3JkZXJcbiIpOwo+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgZ290byB1bnJlZ2lzdGVyOwo+ICsgICAgICAgICAgICAg
ICAgICAgICAgIH0KPiArICAgICAgICAgICAgICAgfQo+ICAgICAgICAgfQo+IAo+ICAgICAgICAg
aWYgKCFwYXNzaXZlKQo+IAo+IEFueXdheSB0aGVyZSBpcyBvdGhlciBhbHRlcm5hdGl2ZSB3aGVy
ZSB0aGlzIG5ldyB0cmlwIHR5cGUgaXMgbm90Cj4gbmVlZGVkIGFuZCBJIGNhbiBqdXN0IHVzZSB0
aGUgZXhpc3RpbmcgdHJpcCB0eXBlIFRIRVJNQUxfVFJJUF9BQ1RJVkUKPiBhbmQgY3JlYXRlIDIg
c2VwYXJhdGUgY29vbGluZyBkZXZpY2VzIGZvciBNT05JVE9SX1pPTkUgYW5kIFdBUk5fWk9ORS4K
PiBJIGhhZCB0aG91Z2h0IHRvIG1ha2UgdGhpcyBnZW5lcmljIGFuZCBqdXN0IHRvIG1hbmFnZSB3
aXRoIDEgY29vbGluZwo+IGRldmljZS4KPiBXaGF0IGlzIHlvdXIgdmlldz8KPiAKPiBUaGFua3Ms
Cj4gQW1pdCBEYW5pZWwKPiAKPiAKPiA+Cj4gPiB0aGFua3MsCj4gPiBydWkKPiA+Cj4gPj4gUmVn
YXJkcywKPiA+PiBBbWl0IERhbmllbAo+ID4+Cj4gPj4gT24gMTkgTWFyY2ggMjAxMiAxMTo0Nywg
QW1pdCBEYW5pZWwgS2FjaGhhcCA8YW1pdC5rYWNoaGFwQGxpbmFyby5vcmc+IHdyb3RlOgo+ID4+
ID4gQ2hhbmdlcyBzaW5jZSBWMToKPiA+PiA+ICpNb3ZlZCB0aGUgc2Vuc29yIGRyaXZlciB0byBk
cml2ZXIvdGhlcm1hbCBmb2xkZXIgZnJvbSBkcml2ZXIvaHdtb24gZm9sZGVyCj4gPj4gPiAgYXMg
c3VnZ2VzdGVkIGJ5IE1hcmsgQnJvd24gYW5kIEd1ZW50ZXIgUm9lY2sKPiA+PiA+ICpBZGRlZCBu
b3RpZmllciBzdXBwb3J0IHRvIG5vdGlmeSB0aGUgcmVnaXN0ZXJlZCBkcml2ZXJzIG9mIGFueSBj
cHUgY29vbGluZwo+ID4+ID4gIGFjdGlvbi4gVGhlIGRyaXZlciBjYW4gbW9kaWZ5IHRoZSBkZWZh
dWx0IGNvb2xpbmcgYmVoYXZpb3VyKGVnIHNldCBkaWZmZXJlbnQKPiA+PiA+ICBtYXggY2xpcCBm
cmVxdWVuY3kpLgo+ID4+ID4gKlRoZSBwZXJjZW50YWdlIGJhc2VkIGZyZXF1ZW5jeSByZXBsYWNl
ZCB3aXRoIGFic29sdXRlIGNsaXBwZWQgZnJlcXVlbmN5Lgo+ID4+ID4gKlNvbWUgbW9yZSBjb25k
aXRpb25hbCBjaGVja3Mgd2hlbiBzZXR0aW5nIG1heCBmcmVxdWVuY3kuCj4gPj4gPiAqUmVuYW1l
ZCB0aGUgbmV3IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfQUNUSVZFIHRvCj4gPj4gPiAg
VEhFUk1BTF9UUklQX1NUQVRFX0lOU1RBTkNFCj4gPj4gPiAqTWFueSByZXZpZXcgY29tbWVudHMg
ZnJvbSBSLCBEdXJnYWRvc3MgPGR1cmdhZG9zcy5yQGludGVsLmNvbT4gYW5kCj4gPj4gPiAgZWR1
YXJkby52YWxlbnRpbkB0aS5jb20gaW1wbGVtZW50ZWQuCj4gPj4gPiAqUmVtb3ZlZCBjb29saW5n
IHN0YXRzIHRocm91Z2ggZGVidWdmcyBwYXRjaAo+ID4+ID4gKlRoZSBWMSBiYXNlZCBjYW4gYmUg
Zm91bmQgaGVyZSwKPiA+PiA+ICBodHRwczovL2xrbWwub3JnL2xrbWwvMjAxMi8yLzIyLzEyMwo+
ID4+ID4gIGh0dHA6Ly9sa21sLm9yZy9sa21sLzIwMTIvMy8zLzMyCj4gPj4gPgo+ID4+ID4gQ2hh
bmdlcyBzaW5jZSBSRkM6Cj4gPj4gPiAqQ2hhbmdlZCB0aGUgY3B1IGNvb2xpbmcgcmVnaXN0cmF0
aW9uL3VucmVnaXN0cmF0aW9uIEFQSSdzIHRvIGluc3RhbmNlIGJhc2VkCj4gPj4gPiAqQ2hhbmdl
ZCB0aGUgU1RBVEVfQUNUSVZFIHRyaXAgdHlwZSB0byBwYXNzIGNvcnJlY3QgaW5zdGFuY2UgaWQK
PiA+PiA+ICpBZGRpbmcgc3VwcG9ydCB0byByZXN0b3JlIGJhY2sgdGhlIHBvbGljeS0+bWF4X2Zy
ZXEgYWZ0ZXIgZG9pbmcgZnJlcXVlbmN5Cj4gPj4gPiAgY2xpcHBpbmcuCj4gPj4gPiAqTW92ZWQg
dGhlIHRyaXAgY29vbGluZyBzdGF0cyBmcm9tIHN5c2ZzIG5vZGUgdG8gZGVidWdmcyBub2RlIGFz
IHN1Z2dlc3RlZAo+ID4+ID4gIGJ5IEdyZWcgS0ggZ3JlZ0Brcm9haC5jb20KPiA+PiA+ICpJbmNv
cnBvcmF0ZWQgc2V2ZXJhbCByZXZpZXcgY29tbWVudHMgZnJvbSBlZHVhcmRvLnZhbGVudGluQHRp
LmNvbQo+ID4+ID4gKk1vdmVkIHRoZSBUZW1wZXJhdHVyZSBzZW5zb3IgZHJpdmVyIGZyb20gZHJp
dmVyL2h3bW9uLyB0byBkcml2ZXIvbWZkCj4gPj4gPiAgYXMgZGlzY3Vzc2VkIHdpdGggR3VlbnRl
ciBSb2VjayA8Z3VlbnRlci5yb2Vja0Blcmljc3Nvbi5jb20+IGFuZAo+ID4+ID4gIERvbmdnZXVu
IEtpbSA8ZGc3Ny5raW1Ac2Ftc3VuZy5jb20+IChodHRwczovL2xrbWwub3JnL2xrbWwvMjAxMi8x
LzUvNykKPiA+PiA+ICpTb21lIGNoYW5nZXMgYWNjb3JkaW5nIHRvIHRoZSBjaGFuZ2VzIGluIGNv
bW1vbiBjcHUgY29vbGluZyBBUElzCj4gPj4gPiAqVGhlIFJGQyBiYXNlZCBwYXRjaGVzIGNhbiBi
ZSBmb3VuZCBoZXJlLAo+ID4+ID4gIGh0dHBzOi8vbGttbC5vcmcvbGttbC8yMDExLzEyLzEzLzE4
Ngo+ID4+ID4gIGh0dHBzOi8vbGttbC5vcmcvbGttbC8yMDExLzEyLzIxLzE2OQo+ID4+ID4KPiA+
PiA+Cj4gPj4gPiBCcmllZiBEZXNjcmlwdGlvbjoKPiA+PiA+Cj4gPj4gPiAxKSBUaGUgZ2VuZXJp
YyBjb29saW5nIGRldmljZXMgY29kZSBpcyBwbGFjZWQgaW5zaWRlIGRyaXZlci90aGVybWFsLyog
YXMKPiA+PiA+IHBsYWNpbmcgaW5zaWRlIGFjcGkgZm9sZGVyIHdpbGwgbmVlZCB1bi1uZWNlc3Nh
cnkgZW5hYmxpbmcgb2YgYWNwaSBjb2RlLiBUaGlzCj4gPj4gPiBjb2RlcyBpcyBhcmNoaXRlY3R1
cmUgaW5kZXBlbmRlbnQuCj4gPj4gPgo+ID4+ID4gMikgVGhpcyBwYXRjaHNldCBhZGRzIGEgbmV3
IHRyaXAgdHlwZSBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0Ugd2hpY2ggcGFzc2VzCj4gPj4g
PiBjb29saW5nIGRldmljZSBpbnN0YW5jZSBudW1iZXIgYW5kIG1heSBiZSBoZWxwZnVsIGZvciBj
cHVmcmVxIGNvb2xpbmcgZGV2aWNlcwo+ID4+ID4gdG8gdGFrZSB0aGUgY29ycmVjdCBjb29saW5n
IGFjdGlvbi4gVGhpcyB0cmlwIHR5cGUgYXZvaWRzIHRoZSB0ZW1wZXJhdHVyZQo+ID4+ID4gY29t
cGFyaXNpb24gY2hlY2sgYWdhaW4gaW5zaWRlIHRoZSBjb29saW5nIGhhbmRsZXIuCj4gPj4gPgo+
ID4+ID4gMykgVGhpcyBwYXRjaHNldCBhZGRzIGdlbmVyaWMgY3B1IGNvb2xpbmcgbG93IGxldmVs
IGltcGxlbWVudGF0aW9uIHRocm91Z2gKPiA+PiA+IGZyZXF1ZW5jeSBjbGlwcGluZyBhbmQgY3B1
IGhvdHBsdWcuIEluIGZ1dHVyZSwgb3RoZXIgY3B1IHJlbGF0ZWQgY29vbGluZwo+ID4+ID4gZGV2
aWNlcyBtYXkgYmUgYWRkZWQgaGVyZS4gQW4gQUNQSSB2ZXJzaW9uIG9mIHRoaXMgYWxyZWFkeSBl
eGlzdHMKPiA+PiA+IChkcml2ZXJzL2FjcGkvcHJvY2Vzc29yX3RoZXJtYWwuYykuIEJ1dCB0aGlz
IHdpbGwgYmUgdXNlZnVsIGZvciBwbGF0Zm9ybXMKPiA+PiA+IGxpa2UgQVJNIHVzaW5nIHRoZSBn
ZW5lcmljIHRoZXJtYWwgaW50ZXJmYWNlIGFsb25nIHdpdGggdGhlIGdlbmVyaWMgY3B1Cj4gPj4g
PiBjb29saW5nIGRldmljZXMuIFRoZSBjb29saW5nIGRldmljZSByZWdpc3RyYXRpb24gQVBJJ3Mg
cmV0dXJuIGNvb2xpbmcgZGV2aWNlCj4gPj4gPiBwb2ludGVycyB3aGljaCBjYW4gYmUgZWFzaWx5
IGJpbmRlZCB3aXRoIHRoZSB0aGVybWFsIHpvbmUgdHJpcCBwb2ludHMuCj4gPj4gPiBUaGUgaW1w
b3J0YW50IEFQSXMgZXhwb3NlZCBhcmUsCj4gPj4gPiAgIGEpc3RydWN0IHRoZXJtYWxfY29vbGlu
Z19kZXZpY2UgKmNwdWZyZXFfY29vbGluZ19yZWdpc3RlcigKPiA+PiA+ICAgICAgICBzdHJ1Y3Qg
ZnJlcV9jbGlwX3RhYmxlICp0YWJfcHRyLCB1bnNpZ25lZCBpbnQgdGFiX3NpemUsCj4gPj4gPiAg
ICAgICAgY29uc3Qgc3RydWN0IGNwdW1hc2sgKm1hc2tfdmFsKQo+ID4+ID4gICBiKXZvaWQgY3B1
ZnJlcV9jb29saW5nX3VucmVnaXN0ZXIoc3RydWN0IHRoZXJtYWxfY29vbGluZ19kZXZpY2UgKmNk
ZXYpCj4gPj4gPgo+ID4+ID4gNCkgU2Ftc3VuZyBleHlub3MgcGxhdGZvcm0gdGhlcm1hbCBpbXBs
ZW1lbnRhdGlvbiBpcyBkb25lIHVzaW5nIHRoZSBnZW5lcmljCj4gPj4gPiBjcHUgY29vbGluZyBB
UElzIGFuZCB0aGUgbmV3IHRyaXAgdHlwZS4gVGhlIHRlbXBlcmF0dXJlIHNlbnNvciBkcml2ZXIg
cHJlc2VudAo+ID4+ID4gaW4gdGhlIGh3bW9uIGZvbGRlcihyZWdpc3RlcmVkIGFzIGh3bW9uIGRy
aXZlcikgaXMgbW92ZWQgdG8gdGhlcm1hbCBmb2xkZXIKPiA+PiA+IGFuZCByZWdpc3RlcmVkIGFz
IGEgdGhlcm1hbCBkcml2ZXIuCj4gPj4gPgo+ID4+ID4gQWxsIHRoaXMgcGF0Y2hzZXQgaXMgYmFz
ZWQgb24gS2VybmVsIHZlcnNpb24gMy4zLXJjNwo+ID4+ID4KPiA+PiA+IEEgc2ltcGxlIGRhdGEv
Y29udHJvbCBmbG93IGRpYWdyYW1zIGlzIHNob3duIGJlbG93LAo+ID4+ID4KPiA+PiA+IENvcmUg
TGludXggdGhlcm1hbCA8LS0tLS0+ICBFeHlub3MgdGhlcm1hbCBpbnRlcmZhY2UgPC0tLS0tIFRl
bXBlcmF0dXJlIFNlbnNvcgo+ID4+ID4gICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgfAo+ID4+ID4gICAgICAgICBcfC8gICAgICAgICAgICAgICAgICAgICAgICAgICAgfAo+
ID4+ID4gIENwdWZyZXEgY29vbGluZyBkZXZpY2UgPC0tLS0tLS0tLS0tLS0tLQo+ID4+ID4KPiA+
PiA+Cj4gPj4gPiBBbWl0IERhbmllbCBLYWNoaGFwICg2KToKPiA+PiA+ICB0aGVybWFsOiBBZGQg
YSBuZXcgdHJpcCB0eXBlIHRvIHVzZSBjb29saW5nIGRldmljZSBpbnN0YW5jZSBudW1iZXIKPiA+
PiA+ICB0aGVybWFsOiBBZGQgZ2VuZXJpYyBjcHVmcmVxIGNvb2xpbmcgaW1wbGVtZW50YXRpb24K
PiA+PiA+ICB0aGVybWFsOiBBZGQgZ2VuZXJpYyBjcHVob3RwbHVnIGNvb2xpbmcgaW1wbGVtZW50
YXRpb24KPiA+PiA+ICBod21vbjogZXh5bm9zNDogTW92ZSB0aGVybWFsIHNlbnNvciBkcml2ZXIg
dG8gZHJpdmVyL3RoZXJtYWwKPiA+PiA+ICAgIGRpcmVjdG9yeQo+ID4+ID4gIHRoZXJtYWw6IGV4
eW5vczQ6IFJlZ2lzdGVyIHRoZSB0bXUgc2Vuc29yIHdpdGggdGhlIGtlcm5lbCB0aGVybWFsCj4g
Pj4gPiAgICBsYXllcgo+ID4+ID4gIEFSTTogZXh5bm9zNDogQWRkIHRoZXJtYWwgc2Vuc29yIGRy
aXZlciBwbGF0Zm9ybSBkZXZpY2Ugc3VwcG9ydAo+ID4+ID4KPiA+PiA+ICBEb2N1bWVudGF0aW9u
L2h3bW9uL2V4eW5vczRfdG11ICAgICAgICAgICB8ICAgODEgLS0tCj4gPj4gPiAgRG9jdW1lbnRh
dGlvbi90aGVybWFsL2NwdS1jb29saW5nLWFwaS50eHQgfCAgIDc2ICsrKwo+ID4+ID4gIERvY3Vt
ZW50YXRpb24vdGhlcm1hbC9leHlub3M0X3RtdSAgICAgICAgIHwgICA1MiArKwo+ID4+ID4gIERv
Y3VtZW50YXRpb24vdGhlcm1hbC9zeXNmcy1hcGkudHh0ICAgICAgIHwgICAgNCArLQo+ID4+ID4g
IGFyY2gvYXJtL21hY2gtZXh5bm9zL0tjb25maWcgICAgICAgICAgICAgIHwgICAxMSArCj4gPj4g
PiAgYXJjaC9hcm0vbWFjaC1leHlub3MvTWFrZWZpbGUgICAgICAgICAgICAgfCAgICAxICsKPiA+
PiA+ICBhcmNoL2FybS9tYWNoLWV4eW5vcy9jbG9jay5jICAgICAgICAgICAgICB8ICAgIDQgKwo+
ID4+ID4gIGFyY2gvYXJtL21hY2gtZXh5bm9zL2Rldi10bXUuYyAgICAgICAgICAgIHwgICAzOSAr
Kwo+ID4+ID4gIGFyY2gvYXJtL21hY2gtZXh5bm9zL2luY2x1ZGUvbWFjaC9pcnFzLmggIHwgICAg
MiArCj4gPj4gPiAgYXJjaC9hcm0vbWFjaC1leHlub3MvaW5jbHVkZS9tYWNoL21hcC5oICAgfCAg
ICAxICsKPiA+PiA+ICBhcmNoL2FybS9tYWNoLWV4eW5vcy9tYWNoLW9yaWdlbi5jICAgICAgICB8
ICAgIDEgKwo+ID4+ID4gIGFyY2gvYXJtL3BsYXQtc2Ftc3VuZy9pbmNsdWRlL3BsYXQvZGV2cy5o
IHwgICAgMSArCj4gPj4gPiAgZHJpdmVycy9od21vbi9LY29uZmlnICAgICAgICAgICAgICAgICAg
ICAgfCAgIDEwIC0KPiA+PiA+ICBkcml2ZXJzL2h3bW9uL01ha2VmaWxlICAgICAgICAgICAgICAg
ICAgICB8ICAgIDEgLQo+ID4+ID4gIGRyaXZlcnMvaHdtb24vZXh5bm9zNF90bXUuYyAgICAgICAg
ICAgICAgIHwgIDUxNCAtLS0tLS0tLS0tLS0tLS0tLS0tCj4gPj4gPiAgZHJpdmVycy90aGVybWFs
L0tjb25maWcgICAgICAgICAgICAgICAgICAgfCAgIDIxICsKPiA+PiA+ICBkcml2ZXJzL3RoZXJt
YWwvTWFrZWZpbGUgICAgICAgICAgICAgICAgICB8ICAgIDIgKwo+ID4+ID4gIGRyaXZlcnMvdGhl
cm1hbC9jcHVfY29vbGluZy5jICAgICAgICAgICAgIHwgIDUyOSArKysrKysrKysrKysrKysrKysr
Cj4gPj4gPiAgZHJpdmVycy90aGVybWFsL2V4eW5vczRfdGhlcm1hbC5jICAgICAgICAgfCAgNzkw
ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrCj4gPj4gPiAgZHJpdmVycy90aGVybWFsL3Ro
ZXJtYWxfc3lzLmMgICAgICAgICAgICAgfCAgIDQ1ICsrLQo+ID4+ID4gIGluY2x1ZGUvbGludXgv
Y3B1X2Nvb2xpbmcuaCAgICAgICAgICAgICAgIHwgICA3OCArKysKPiA+PiA+ICBpbmNsdWRlL2xp
bnV4L3BsYXRmb3JtX2RhdGEvZXh5bm9zNF90bXUuaCB8ICAgIDcgKwo+ID4+ID4gIGluY2x1ZGUv
bGludXgvdGhlcm1hbC5oICAgICAgICAgICAgICAgICAgIHwgICAgMSArCj4gPj4gPiAgMjMgZmls
ZXMgY2hhbmdlZCwgMTY2MCBpbnNlcnRpb25zKCspLCA2MTEgZGVsZXRpb25zKC0pCj4gPj4gPiAg
ZGVsZXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRpb24vaHdtb24vZXh5bm9zNF90bXUKPiA+PiA+
ICBjcmVhdGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi90aGVybWFsL2NwdS1jb29saW5nLWFw
aS50eHQKPiA+PiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi90aGVybWFsL2V4
eW5vczRfdG11Cj4gPj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGFyY2gvYXJtL21hY2gtZXh5bm9z
L2Rldi10bXUuYwo+ID4+ID4gIGRlbGV0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2h3bW9uL2V4eW5v
czRfdG11LmMKPiA+PiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90aGVybWFsL2NwdV9j
b29saW5nLmMKPiA+PiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90aGVybWFsL2V4eW5v
czRfdGhlcm1hbC5jCj4gPj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUvbGludXgvY3B1
X2Nvb2xpbmcuaAo+ID4+ID4KPiA+Cj4gPgoKCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fXwpsbS1zZW5zb3JzIG1haWxpbmcgbGlzdApsbS1zZW5zb3JzQGxt
LXNlbnNvcnMub3JnCmh0dHA6Ly9saXN0cy5sbS1zZW5zb3JzLm9yZy9tYWlsbWFuL2xpc3RpbmZv
L2xtLXNlbnNvcnM
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-16 2:07 ` Zhang Rui
0 siblings, 0 replies; 40+ messages in thread
From: Zhang Rui @ 2012-04-16 2:07 UTC (permalink / raw)
To: Amit Kachhap
Cc: lenb, linux-pm, linux-samsung-soc, linux-kernel, mjg59,
linux-acpi, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r
On 三, 2012-04-11 at 18:17 +0530, Amit Kachhap wrote:
> Hi Rui,
>
> Thanks for looking into the patches.
>
> On 10 April 2012 06:28, Zhang Rui <rui.zhang@intel.com> wrote:
> > Hi, Amit,
> >
> > On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
> >> Hi Len/Rui,
> >>
> >> Any comment or feedback from your side about the status of this patch?
> >> Is it merge-able or major re-work is needed? I have fixed most of the
> >> comments in this patchset and currently working on some of the minor
> >> comments received and will submit them shortly.
> >>
> > Sorry for the late response.
> >
> > First of all, it makes sense to me to introduce the generic cpufrq
> > cooling implementation.
> ok thanks
> > But I still have some questions.
> > I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
> > that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
> > current passive handling in the generic thermal layer well, right?
> > e.g. there is no tc1/tc2 on exynos4.
> >
> > If yes, is it possible that we can enhance the passive cooling to
> > support the generic processor cooling?
> > say, introduce another way to throttle the processor in
> > thermal_zone_device_passive when tc1 and tc2 are not available?
>
> I agree that this new trip type code can be moved into passive trip
> type when tc1 and tc2 are 0. but this is special type of cooling
> devices behaviour where only instances of the same cooling device is
> binded to a trip point. The order of mapping is the only
> differentiating criteria and there are some checks used to implement
> this like
> 1) The trip points should be in ascending order.(This is missing in my
> original patch, so I added below)
> 2) The set_cur_state has to be called for the exact temp range so
> get_cur_state(&state) and set_cur_state(state ++/state--) logic is not
> possible.
> 3) set_cur_state is called as set_cur_state(cdev_instance).
Do you really need two THERMAL_TRIP_STATE_INSTANCE trip points?
I'm not sure if my understanding is right, but IMO, we can have one
THERMAL_TRIP_STATE_INSTANCE only, for both MONIROR_ZONE and WARN_ZONE,
and the trip temperature equals MONIROR_ZONE.
The cpufreq cooling device will work in the same way, no?
thanks,
rui
> There is a chance that people might confuse that these checks are
> applicable for passive trip types also which is not the case here.
>
> @@ -1187,6 +1228,21 @@ struct thermal_zone_device
> *thermal_zone_device_register(char *type,
> tz->ops->get_trip_type(tz, count, &trip_type);
> if (trip_type == THERMAL_TRIP_PASSIVE)
> passive = 1;
> + /*
> + * For THERMAL_TRIP_STATE_INSTANCE trips, thermal zone should
> + * be in ascending order.
> + */
> + if (trip_type == THERMAL_TRIP_STATE_INSTANCE) {
> + tz->ops->get_trip_temp(tz, count, &trip_temp);
> + if (first_trip_temp == 0)
> + first_trip_temp = trip_temp;
> + else if (first_trip_temp < trip_temp)
> + first_trip_temp = trip_temp;
> + else if (first_trip_temp > trip_temp) {
> + pr_warn("Zone trip points should be in
> ascending order\n");
> + goto unregister;
> + }
> + }
> }
>
> if (!passive)
>
> Anyway there is other alternative where this new trip type is not
> needed and I can just use the existing trip type THERMAL_TRIP_ACTIVE
> and create 2 separate cooling devices for MONITOR_ZONE and WARN_ZONE.
> I had thought to make this generic and just to manage with 1 cooling
> device.
> What is your view?
>
> Thanks,
> Amit Daniel
>
>
> >
> > thanks,
> > rui
> >
> >> Regards,
> >> Amit Daniel
> >>
> >> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
> >> > Changes since V1:
> >> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
> >> > as suggested by Mark Brown and Guenter Roeck
> >> > *Added notifier support to notify the registered drivers of any cpu cooling
> >> > action. The driver can modify the default cooling behaviour(eg set different
> >> > max clip frequency).
> >> > *The percentage based frequency replaced with absolute clipped frequency.
> >> > *Some more conditional checks when setting max frequency.
> >> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
> >> > THERMAL_TRIP_STATE_INSTANCE
> >> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
> >> > eduardo.valentin@ti.com implemented.
> >> > *Removed cooling stats through debugfs patch
> >> > *The V1 based can be found here,
> >> > https://lkml.org/lkml/2012/2/22/123
> >> > http://lkml.org/lkml/2012/3/3/32
> >> >
> >> > Changes since RFC:
> >> > *Changed the cpu cooling registration/unregistration API's to instance based
> >> > *Changed the STATE_ACTIVE trip type to pass correct instance id
> >> > *Adding support to restore back the policy->max_freq after doing frequency
> >> > clipping.
> >> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
> >> > by Greg KH greg@kroah.com
> >> > *Incorporated several review comments from eduardo.valentin@ti.com
> >> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
> >> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
> >> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
> >> > *Some changes according to the changes in common cpu cooling APIs
> >> > *The RFC based patches can be found here,
> >> > https://lkml.org/lkml/2011/12/13/186
> >> > https://lkml.org/lkml/2011/12/21/169
> >> >
> >> >
> >> > Brief Description:
> >> >
> >> > 1) The generic cooling devices code is placed inside driver/thermal/* as
> >> > placing inside acpi folder will need un-necessary enabling of acpi code. This
> >> > codes is architecture independent.
> >> >
> >> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
> >> > cooling device instance number and may be helpful for cpufreq cooling devices
> >> > to take the correct cooling action. This trip type avoids the temperature
> >> > comparision check again inside the cooling handler.
> >> >
> >> > 3) This patchset adds generic cpu cooling low level implementation through
> >> > frequency clipping and cpu hotplug. In future, other cpu related cooling
> >> > devices may be added here. An ACPI version of this already exists
> >> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
> >> > like ARM using the generic thermal interface along with the generic cpu
> >> > cooling devices. The cooling device registration API's return cooling device
> >> > pointers which can be easily binded with the thermal zone trip points.
> >> > The important APIs exposed are,
> >> > a)struct thermal_cooling_device *cpufreq_cooling_register(
> >> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
> >> > const struct cpumask *mask_val)
> >> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
> >> >
> >> > 4) Samsung exynos platform thermal implementation is done using the generic
> >> > cpu cooling APIs and the new trip type. The temperature sensor driver present
> >> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
> >> > and registered as a thermal driver.
> >> >
> >> > All this patchset is based on Kernel version 3.3-rc7
> >> >
> >> > A simple data/control flow diagrams is shown below,
> >> >
> >> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
> >> > | |
> >> > \|/ |
> >> > Cpufreq cooling device <---------------
> >> >
> >> >
> >> > Amit Daniel Kachhap (6):
> >> > thermal: Add a new trip type to use cooling device instance number
> >> > thermal: Add generic cpufreq cooling implementation
> >> > thermal: Add generic cpuhotplug cooling implementation
> >> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
> >> > directory
> >> > thermal: exynos4: Register the tmu sensor with the kernel thermal
> >> > layer
> >> > ARM: exynos4: Add thermal sensor driver platform device support
> >> >
> >> > Documentation/hwmon/exynos4_tmu | 81 ---
> >> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
> >> > Documentation/thermal/exynos4_tmu | 52 ++
> >> > Documentation/thermal/sysfs-api.txt | 4 +-
> >> > arch/arm/mach-exynos/Kconfig | 11 +
> >> > arch/arm/mach-exynos/Makefile | 1 +
> >> > arch/arm/mach-exynos/clock.c | 4 +
> >> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
> >> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
> >> > arch/arm/mach-exynos/include/mach/map.h | 1 +
> >> > arch/arm/mach-exynos/mach-origen.c | 1 +
> >> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
> >> > drivers/hwmon/Kconfig | 10 -
> >> > drivers/hwmon/Makefile | 1 -
> >> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
> >> > drivers/thermal/Kconfig | 21 +
> >> > drivers/thermal/Makefile | 2 +
> >> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
> >> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
> >> > drivers/thermal/thermal_sys.c | 45 ++-
> >> > include/linux/cpu_cooling.h | 78 +++
> >> > include/linux/platform_data/exynos4_tmu.h | 7 +
> >> > include/linux/thermal.h | 1 +
> >> > 23 files changed, 1660 insertions(+), 611 deletions(-)
> >> > delete mode 100644 Documentation/hwmon/exynos4_tmu
> >> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
> >> > create mode 100644 Documentation/thermal/exynos4_tmu
> >> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
> >> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
> >> > create mode 100644 drivers/thermal/cpu_cooling.c
> >> > create mode 100644 drivers/thermal/exynos4_thermal.c
> >> > create mode 100644 include/linux/cpu_cooling.h
> >> >
> >
> >
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
2012-04-16 2:07 ` [lm-sensors] " Zhang Rui
@ 2012-04-24 13:36 ` Amit Kachhap
-1 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-24 13:24 UTC (permalink / raw)
To: Zhang Rui
Cc: lenb, linux-pm, linux-samsung-soc, linux-kernel, mjg59,
linux-acpi, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r
On 16 April 2012 07:37, Zhang Rui <rui.zhang@intel.com> wrote:
> On 三, 2012-04-11 at 18:17 +0530, Amit Kachhap wrote:
>> Hi Rui,
>>
>> Thanks for looking into the patches.
>>
>> On 10 April 2012 06:28, Zhang Rui <rui.zhang@intel.com> wrote:
>> > Hi, Amit,
>> >
>> > On 三, 2012-04-04 at 10:02 +0530, Amit Kachhap wrote:
>> >> Hi Len/Rui,
>> >>
>> >> Any comment or feedback from your side about the status of this patch?
>> >> Is it merge-able or major re-work is needed? I have fixed most of the
>> >> comments in this patchset and currently working on some of the minor
>> >> comments received and will submit them shortly.
>> >>
>> > Sorry for the late response.
>> >
>> > First of all, it makes sense to me to introduce the generic cpufrq
>> > cooling implementation.
>> ok thanks
>> > But I still have some questions.
>> > I think the key reason why THERMAL_TRIP_STATE_INSTANCE is introduced is
>> > that the MONIROR_ZONE and WARN_ZONE on exynos4 can not fit into the
>> > current passive handling in the generic thermal layer well, right?
>> > e.g. there is no tc1/tc2 on exynos4.
>> >
>> > If yes, is it possible that we can enhance the passive cooling to
>> > support the generic processor cooling?
>> > say, introduce another way to throttle the processor in
>> > thermal_zone_device_passive when tc1 and tc2 are not available?
>>
>> I agree that this new trip type code can be moved into passive trip
>> type when tc1 and tc2 are 0. but this is special type of cooling
>> devices behaviour where only instances of the same cooling device is
>> binded to a trip point. The order of mapping is the only
>> differentiating criteria and there are some checks used to implement
>> this like
>> 1) The trip points should be in ascending order.(This is missing in my
>> original patch, so I added below)
>> 2) The set_cur_state has to be called for the exact temp range so
>> get_cur_state(&state) and set_cur_state(state ++/state--) logic is not
>> possible.
>> 3) set_cur_state is called as set_cur_state(cdev_instance).
>
> Do you really need two THERMAL_TRIP_STATE_INSTANCE trip points?
Sorry for late reply as I was off for vacation.
Yes we need 2 trip points of type THERMAL_TRIP_STATE_INSTANCE as we
need different cooling for these 2 zones. Anyways Do you feel that
these whole/partial patch series(cpufreq cooling api's, new trip type
etc) is ack-able or some modification is needed?
>
> I'm not sure if my understanding is right, but IMO, we can have one
> THERMAL_TRIP_STATE_INSTANCE only, for both MONIROR_ZONE and WARN_ZONE,
> and the trip temperature equals MONIROR_ZONE.
> The cpufreq cooling device will work in the same way, no?
>
> thanks,
> rui
>
>> There is a chance that people might confuse that these checks are
>> applicable for passive trip types also which is not the case here.
>>
>> @@ -1187,6 +1228,21 @@ struct thermal_zone_device
>> *thermal_zone_device_register(char *type,
>> tz->ops->get_trip_type(tz, count, &trip_type);
>> if (trip_type == THERMAL_TRIP_PASSIVE)
>> passive = 1;
>> + /*
>> + * For THERMAL_TRIP_STATE_INSTANCE trips, thermal zone should
>> + * be in ascending order.
>> + */
>> + if (trip_type == THERMAL_TRIP_STATE_INSTANCE) {
>> + tz->ops->get_trip_temp(tz, count, &trip_temp);
>> + if (first_trip_temp == 0)
>> + first_trip_temp = trip_temp;
>> + else if (first_trip_temp < trip_temp)
>> + first_trip_temp = trip_temp;
>> + else if (first_trip_temp > trip_temp) {
>> + pr_warn("Zone trip points should be in
>> ascending order\n");
>> + goto unregister;
>> + }
>> + }
>> }
>>
>> if (!passive)
>>
>> Anyway there is other alternative where this new trip type is not
>> needed and I can just use the existing trip type THERMAL_TRIP_ACTIVE
>> and create 2 separate cooling devices for MONITOR_ZONE and WARN_ZONE.
>> I had thought to make this generic and just to manage with 1 cooling
>> device.
>> What is your view?
>>
>> Thanks,
>> Amit Daniel
>>
>>
>> >
>> > thanks,
>> > rui
>> >
>> >> Regards,
>> >> Amit Daniel
>> >>
>> >> On 19 March 2012 11:47, Amit Daniel Kachhap <amit.kachhap@linaro.org> wrote:
>> >> > Changes since V1:
>> >> > *Moved the sensor driver to driver/thermal folder from driver/hwmon folder
>> >> > as suggested by Mark Brown and Guenter Roeck
>> >> > *Added notifier support to notify the registered drivers of any cpu cooling
>> >> > action. The driver can modify the default cooling behaviour(eg set different
>> >> > max clip frequency).
>> >> > *The percentage based frequency replaced with absolute clipped frequency.
>> >> > *Some more conditional checks when setting max frequency.
>> >> > *Renamed the new trip type THERMAL_TRIP_STATE_ACTIVE to
>> >> > THERMAL_TRIP_STATE_INSTANCE
>> >> > *Many review comments from R, Durgadoss <durgadoss.r@intel.com> and
>> >> > eduardo.valentin@ti.com implemented.
>> >> > *Removed cooling stats through debugfs patch
>> >> > *The V1 based can be found here,
>> >> > https://lkml.org/lkml/2012/2/22/123
>> >> > http://lkml.org/lkml/2012/3/3/32
>> >> >
>> >> > Changes since RFC:
>> >> > *Changed the cpu cooling registration/unregistration API's to instance based
>> >> > *Changed the STATE_ACTIVE trip type to pass correct instance id
>> >> > *Adding support to restore back the policy->max_freq after doing frequency
>> >> > clipping.
>> >> > *Moved the trip cooling stats from sysfs node to debugfs node as suggested
>> >> > by Greg KH greg@kroah.com
>> >> > *Incorporated several review comments from eduardo.valentin@ti.com
>> >> > *Moved the Temperature sensor driver from driver/hwmon/ to driver/mfd
>> >> > as discussed with Guenter Roeck <guenter.roeck@ericsson.com> and
>> >> > Donggeun Kim <dg77.kim@samsung.com> (https://lkml.org/lkml/2012/1/5/7)
>> >> > *Some changes according to the changes in common cpu cooling APIs
>> >> > *The RFC based patches can be found here,
>> >> > https://lkml.org/lkml/2011/12/13/186
>> >> > https://lkml.org/lkml/2011/12/21/169
>> >> >
>> >> >
>> >> > Brief Description:
>> >> >
>> >> > 1) The generic cooling devices code is placed inside driver/thermal/* as
>> >> > placing inside acpi folder will need un-necessary enabling of acpi code. This
>> >> > codes is architecture independent.
>> >> >
>> >> > 2) This patchset adds a new trip type THERMAL_TRIP_STATE_INSTANCE which passes
>> >> > cooling device instance number and may be helpful for cpufreq cooling devices
>> >> > to take the correct cooling action. This trip type avoids the temperature
>> >> > comparision check again inside the cooling handler.
>> >> >
>> >> > 3) This patchset adds generic cpu cooling low level implementation through
>> >> > frequency clipping and cpu hotplug. In future, other cpu related cooling
>> >> > devices may be added here. An ACPI version of this already exists
>> >> > (drivers/acpi/processor_thermal.c). But this will be useful for platforms
>> >> > like ARM using the generic thermal interface along with the generic cpu
>> >> > cooling devices. The cooling device registration API's return cooling device
>> >> > pointers which can be easily binded with the thermal zone trip points.
>> >> > The important APIs exposed are,
>> >> > a)struct thermal_cooling_device *cpufreq_cooling_register(
>> >> > struct freq_clip_table *tab_ptr, unsigned int tab_size,
>> >> > const struct cpumask *mask_val)
>> >> > b)void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
>> >> >
>> >> > 4) Samsung exynos platform thermal implementation is done using the generic
>> >> > cpu cooling APIs and the new trip type. The temperature sensor driver present
>> >> > in the hwmon folder(registered as hwmon driver) is moved to thermal folder
>> >> > and registered as a thermal driver.
>> >> >
>> >> > All this patchset is based on Kernel version 3.3-rc7
>> >> >
>> >> > A simple data/control flow diagrams is shown below,
>> >> >
>> >> > Core Linux thermal <-----> Exynos thermal interface <----- Temperature Sensor
>> >> > | |
>> >> > \|/ |
>> >> > Cpufreq cooling device <---------------
>> >> >
>> >> >
>> >> > Amit Daniel Kachhap (6):
>> >> > thermal: Add a new trip type to use cooling device instance number
>> >> > thermal: Add generic cpufreq cooling implementation
>> >> > thermal: Add generic cpuhotplug cooling implementation
>> >> > hwmon: exynos4: Move thermal sensor driver to driver/thermal
>> >> > directory
>> >> > thermal: exynos4: Register the tmu sensor with the kernel thermal
>> >> > layer
>> >> > ARM: exynos4: Add thermal sensor driver platform device support
>> >> >
>> >> > Documentation/hwmon/exynos4_tmu | 81 ---
>> >> > Documentation/thermal/cpu-cooling-api.txt | 76 +++
>> >> > Documentation/thermal/exynos4_tmu | 52 ++
>> >> > Documentation/thermal/sysfs-api.txt | 4 +-
>> >> > arch/arm/mach-exynos/Kconfig | 11 +
>> >> > arch/arm/mach-exynos/Makefile | 1 +
>> >> > arch/arm/mach-exynos/clock.c | 4 +
>> >> > arch/arm/mach-exynos/dev-tmu.c | 39 ++
>> >> > arch/arm/mach-exynos/include/mach/irqs.h | 2 +
>> >> > arch/arm/mach-exynos/include/mach/map.h | 1 +
>> >> > arch/arm/mach-exynos/mach-origen.c | 1 +
>> >> > arch/arm/plat-samsung/include/plat/devs.h | 1 +
>> >> > drivers/hwmon/Kconfig | 10 -
>> >> > drivers/hwmon/Makefile | 1 -
>> >> > drivers/hwmon/exynos4_tmu.c | 514 -------------------
>> >> > drivers/thermal/Kconfig | 21 +
>> >> > drivers/thermal/Makefile | 2 +
>> >> > drivers/thermal/cpu_cooling.c | 529 +++++++++++++++++++
>> >> > drivers/thermal/exynos4_thermal.c | 790 +++++++++++++++++++++++++++++
>> >> > drivers/thermal/thermal_sys.c | 45 ++-
>> >> > include/linux/cpu_cooling.h | 78 +++
>> >> > include/linux/platform_data/exynos4_tmu.h | 7 +
>> >> > include/linux/thermal.h | 1 +
>> >> > 23 files changed, 1660 insertions(+), 611 deletions(-)
>> >> > delete mode 100644 Documentation/hwmon/exynos4_tmu
>> >> > create mode 100644 Documentation/thermal/cpu-cooling-api.txt
>> >> > create mode 100644 Documentation/thermal/exynos4_tmu
>> >> > create mode 100644 arch/arm/mach-exynos/dev-tmu.c
>> >> > delete mode 100644 drivers/hwmon/exynos4_tmu.c
>> >> > create mode 100644 drivers/thermal/cpu_cooling.c
>> >> > create mode 100644 drivers/thermal/exynos4_thermal.c
>> >> > create mode 100644 include/linux/cpu_cooling.h
>> >> >
>> >
>> >
>
>
^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [lm-sensors] [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform
@ 2012-04-24 13:36 ` Amit Kachhap
0 siblings, 0 replies; 40+ messages in thread
From: Amit Kachhap @ 2012-04-24 13:36 UTC (permalink / raw)
To: Zhang Rui
Cc: lenb, linux-pm, linux-samsung-soc, linux-kernel, mjg59,
linux-acpi, linaro-dev, lm-sensors, patches, eduardo.valentin,
durgadoss.r
T24gMTYgQXByaWwgMjAxMiAwNzozNywgWmhhbmcgUnVpIDxydWkuemhhbmdAaW50ZWwuY29tPiB3
cm90ZToKPiBPbiDkuIksIDIwMTItMDQtMTEgYXQgMTg6MTcgKzA1MzAsIEFtaXQgS2FjaGhhcCB3
cm90ZToKPj4gSGkgUnVpLAo+Pgo+PiBUaGFua3MgZm9yIGxvb2tpbmcgaW50byB0aGUgcGF0Y2hl
cy4KPj4KPj4gT24gMTAgQXByaWwgMjAxMiAwNjoyOCwgWmhhbmcgUnVpIDxydWkuemhhbmdAaW50
ZWwuY29tPiB3cm90ZToKPj4gPiBIaSwgQW1pdCwKPj4gPgo+PiA+IE9uIOS4iSwgMjAxMi0wNC0w
NCBhdCAxMDowMiArMDUzMCwgQW1pdCBLYWNoaGFwIHdyb3RlOgo+PiA+PiBIaSBMZW4vUnVpLAo+
PiA+Pgo+PiA+PiBBbnkgY29tbWVudCBvciBmZWVkYmFjayBmcm9tIHlvdXIgc2lkZSBhYm91dCB0
aGUgc3RhdHVzIG9mIHRoaXMgcGF0Y2g/Cj4+ID4+IElzIGl0IG1lcmdlLWFibGUgb3IgbWFqb3Ig
cmUtd29yayBpcyBuZWVkZWQ/IEkgaGF2ZSBmaXhlZCBtb3N0IG9mIHRoZQo+PiA+PiBjb21tZW50
cyBpbiB0aGlzIHBhdGNoc2V0IGFuZCBjdXJyZW50bHkgd29ya2luZyBvbiBzb21lIG9mIHRoZSBt
aW5vcgo+PiA+PiBjb21tZW50cyByZWNlaXZlZCBhbmQgd2lsbCBzdWJtaXQgdGhlbSBzaG9ydGx5
Lgo+PiA+Pgo+PiA+IFNvcnJ5IGZvciB0aGUgbGF0ZSByZXNwb25zZS4KPj4gPgo+PiA+IEZpcnN0
IG9mIGFsbCwgaXQgbWFrZXMgc2Vuc2UgdG8gbWUgdG8gaW50cm9kdWNlIHRoZSBnZW5lcmljIGNw
dWZycQo+PiA+IGNvb2xpbmcgaW1wbGVtZW50YXRpb24uCj4+IG9rIHRoYW5rcwo+PiA+IEJ1dCBJ
IHN0aWxsIGhhdmUgc29tZSBxdWVzdGlvbnMuCj4+ID4gSSB0aGluayB0aGUga2V5IHJlYXNvbiB3
aHkgVEhFUk1BTF9UUklQX1NUQVRFX0lOU1RBTkNFIGlzIGludHJvZHVjZWQgaXMKPj4gPiB0aGF0
IHRoZSBNT05JUk9SX1pPTkUgYW5kIFdBUk5fWk9ORSBvbiBleHlub3M0IGNhbiBub3QgZml0IGlu
dG8gdGhlCj4+ID4gY3VycmVudCBwYXNzaXZlIGhhbmRsaW5nIGluIHRoZSBnZW5lcmljIHRoZXJt
YWwgbGF5ZXIgd2VsbCwgcmlnaHQ/Cj4+ID4gZS5nLiB0aGVyZSBpcyBubyB0YzEvdGMyIG9uIGV4
eW5vczQuCj4+ID4KPj4gPiBJZiB5ZXMsIGlzIGl0IHBvc3NpYmxlIHRoYXQgd2UgY2FuIGVuaGFu
Y2UgdGhlIHBhc3NpdmUgY29vbGluZyB0bwo+PiA+IHN1cHBvcnQgdGhlIGdlbmVyaWMgcHJvY2Vz
c29yIGNvb2xpbmc/Cj4+ID4gc2F5LCBpbnRyb2R1Y2UgYW5vdGhlciB3YXkgdG8gdGhyb3R0bGUg
dGhlIHByb2Nlc3NvciBpbgo+PiA+IHRoZXJtYWxfem9uZV9kZXZpY2VfcGFzc2l2ZSB3aGVuIHRj
MSBhbmQgdGMyIGFyZSBub3QgYXZhaWxhYmxlPwo+Pgo+PiBJIGFncmVlIHRoYXQgdGhpcyBuZXcg
dHJpcCB0eXBlIGNvZGUgY2FuIGJlIG1vdmVkIGludG8gcGFzc2l2ZSB0cmlwCj4+IHR5cGUgd2hl
biB0YzEgYW5kIHRjMiBhcmUgMC4gYnV0IHRoaXMgaXMgc3BlY2lhbCB0eXBlIG9mIGNvb2xpbmcK
Pj4gZGV2aWNlcyBiZWhhdmlvdXIgd2hlcmUgb25seSBpbnN0YW5jZXMgb2YgdGhlIHNhbWUgY29v
bGluZyBkZXZpY2UgaXMKPj4gYmluZGVkIHRvIGEgdHJpcCBwb2ludC4gVGhlIG9yZGVyIG9mIG1h
cHBpbmcgaXMgdGhlIG9ubHkKPj4gZGlmZmVyZW50aWF0aW5nIGNyaXRlcmlhIGFuZCB0aGVyZSBh
cmUgc29tZSBjaGVja3MgdXNlZCB0byBpbXBsZW1lbnQKPj4gdGhpcyBsaWtlCj4+IDEpIFRoZSB0
cmlwIHBvaW50cyBzaG91bGQgYmUgaW4gYXNjZW5kaW5nIG9yZGVyLihUaGlzIGlzIG1pc3Npbmcg
aW4gbXkKPj4gb3JpZ2luYWwgcGF0Y2gsIHNvIEkgYWRkZWQgYmVsb3cpCj4+IDIpIFRoZSBzZXRf
Y3VyX3N0YXRlIGhhcyB0byBiZSBjYWxsZWQgZm9yIHRoZSBleGFjdCB0ZW1wIHJhbmdlIHNvCj4+
IGdldF9jdXJfc3RhdGUoJnN0YXRlKSBhbmQgc2V0X2N1cl9zdGF0ZShzdGF0ZSArKy9zdGF0ZS0t
KSBsb2dpYyBpcyBub3QKPj4gcG9zc2libGUuCj4+IDMpIHNldF9jdXJfc3RhdGUgaXMgY2FsbGVk
IGFzIHNldF9jdXJfc3RhdGUoY2Rldl9pbnN0YW5jZSkuCj4KPiBEbyB5b3UgcmVhbGx5IG5lZWQg
dHdvIFRIRVJNQUxfVFJJUF9TVEFURV9JTlNUQU5DRSB0cmlwIHBvaW50cz8KU29ycnkgZm9yIGxh
dGUgcmVwbHkgYXMgSSB3YXMgb2ZmIGZvciB2YWNhdGlvbi4KWWVzIHdlIG5lZWQgMiB0cmlwIHBv
aW50cyBvZiB0eXBlIFRIRVJNQUxfVFJJUF9TVEFURV9JTlNUQU5DRSBhcyB3ZQpuZWVkIGRpZmZl
cmVudCBjb29saW5nIGZvciB0aGVzZSAyIHpvbmVzLiBBbnl3YXlzIERvIHlvdSBmZWVsIHRoYXQK
dGhlc2Ugd2hvbGUvcGFydGlhbCBwYXRjaCBzZXJpZXMoY3B1ZnJlcSBjb29saW5nIGFwaSdzLCBu
ZXcgdHJpcCAgdHlwZQpldGMpIGlzIGFjay1hYmxlIG9yIHNvbWUgbW9kaWZpY2F0aW9uIGlzIG5l
ZWRlZD8KPgo+IEknbSBub3Qgc3VyZSBpZiBteSB1bmRlcnN0YW5kaW5nIGlzIHJpZ2h0LCBidXQg
SU1PLCB3ZSBjYW4gaGF2ZSBvbmUKPiBUSEVSTUFMX1RSSVBfU1RBVEVfSU5TVEFOQ0Ugb25seSwg
Zm9yIGJvdGggTU9OSVJPUl9aT05FIGFuZCBXQVJOX1pPTkUsCj4gYW5kIHRoZSB0cmlwIHRlbXBl
cmF0dXJlIGVxdWFscyBNT05JUk9SX1pPTkUuCj4gVGhlIGNwdWZyZXEgY29vbGluZyBkZXZpY2Ug
d2lsbCB3b3JrIGluIHRoZSBzYW1lIHdheSwgbm8/Cj4KPiB0aGFua3MsCj4gcnVpCj4KPj4gVGhl
cmUgaXMgYSBjaGFuY2UgdGhhdCBwZW9wbGUgbWlnaHQgY29uZnVzZSB0aGF0IHRoZXNlIGNoZWNr
cyBhcmUKPj4gYXBwbGljYWJsZSBmb3IgcGFzc2l2ZSB0cmlwIHR5cGVzIGFsc28gd2hpY2ggaXMg
bm90IHRoZSBjYXNlIGhlcmUuCj4+Cj4+IEBAIC0xMTg3LDYgKzEyMjgsMjEgQEAgc3RydWN0IHRo
ZXJtYWxfem9uZV9kZXZpY2UKPj4gKnRoZXJtYWxfem9uZV9kZXZpY2VfcmVnaXN0ZXIoY2hhciAq
dHlwZSwKPj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHotPm9wcy0+Z2V0X3RyaXBfdHlwZSh0
eiwgY291bnQsICZ0cmlwX3R5cGUpOwo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAodHJp
cF90eXBlID09IFRIRVJNQUxfVFJJUF9QQVNTSVZFKQo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBwYXNzaXZlID0gMTsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvKgo+
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKiBGb3IgVEhFUk1BTF9UUklQX1NUQVRFX0lOU1RB
TkNFIHRyaXBzLCB0aGVybWFsIHpvbmUgc2hvdWxkCj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAqIGJlIGluIGFzY2VuZGluZyBvcmRlci4KPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCAqLwo+
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmICh0cmlwX3R5cGUgPT0gVEhFUk1BTF9UUklQX1NU
QVRFX0lOU1RBTkNFKSB7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdHot
Pm9wcy0+Z2V0X3RyaXBfdGVtcCh0eiwgY291bnQsICZ0cmlwX3RlbXApOwo+PiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmIChmaXJzdF90cmlwX3RlbXAgPT0gMCkKPj4gKyDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBmaXJzdF90cmlwX3Rl
bXAgPSB0cmlwX3RlbXA7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZWxz
ZSBpZiAoZmlyc3RfdHJpcF90ZW1wIDwgdHJpcF90ZW1wKQo+PiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGZpcnN0X3RyaXBfdGVtcCA9IHRyaXBfdGVtcDsK
Pj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlbHNlIGlmIChmaXJzdF90cmlw
X3RlbXAgPiB0cmlwX3RlbXApIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBwcl93YXJuKCJab25lIHRyaXAgcG9pbnRzIHNob3VsZCBiZSBpbgo+PiBh
c2NlbmRpbmcgb3JkZXJcbiIpOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGdvdG8gdW5yZWdpc3RlcjsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCB9Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+PiDCoCDCoCDCoCDCoCB9
Cj4+Cj4+IMKgIMKgIMKgIMKgIGlmICghcGFzc2l2ZSkKPj4KPj4gQW55d2F5IHRoZXJlIGlzIG90
aGVyIGFsdGVybmF0aXZlIHdoZXJlIHRoaXMgbmV3IHRyaXAgdHlwZSBpcyBub3QKPj4gbmVlZGVk
IGFuZCBJIGNhbiBqdXN0IHVzZSB0aGUgZXhpc3RpbmcgdHJpcCB0eXBlIFRIRVJNQUxfVFJJUF9B
Q1RJVkUKPj4gYW5kIGNyZWF0ZSAyIHNlcGFyYXRlIGNvb2xpbmcgZGV2aWNlcyBmb3IgTU9OSVRP
Ul9aT05FIGFuZCBXQVJOX1pPTkUuCj4+IEkgaGFkIHRob3VnaHQgdG8gbWFrZSB0aGlzIGdlbmVy
aWMgYW5kIGp1c3QgdG8gbWFuYWdlIHdpdGggMSBjb29saW5nCj4+IGRldmljZS4KPj4gV2hhdCBp
cyB5b3VyIHZpZXc/Cj4+Cj4+IFRoYW5rcywKPj4gQW1pdCBEYW5pZWwKPj4KPj4KPj4gPgo+PiA+
IHRoYW5rcywKPj4gPiBydWkKPj4gPgo+PiA+PiBSZWdhcmRzLAo+PiA+PiBBbWl0IERhbmllbAo+
PiA+Pgo+PiA+PiBPbiAxOSBNYXJjaCAyMDEyIDExOjQ3LCBBbWl0IERhbmllbCBLYWNoaGFwIDxh
bWl0LmthY2hoYXBAbGluYXJvLm9yZz4gd3JvdGU6Cj4+ID4+ID4gQ2hhbmdlcyBzaW5jZSBWMToK
Pj4gPj4gPiAqTW92ZWQgdGhlIHNlbnNvciBkcml2ZXIgdG8gZHJpdmVyL3RoZXJtYWwgZm9sZGVy
IGZyb20gZHJpdmVyL2h3bW9uIGZvbGRlcgo+PiA+PiA+IMKgYXMgc3VnZ2VzdGVkIGJ5IE1hcmsg
QnJvd24gYW5kIEd1ZW50ZXIgUm9lY2sKPj4gPj4gPiAqQWRkZWQgbm90aWZpZXIgc3VwcG9ydCB0
byBub3RpZnkgdGhlIHJlZ2lzdGVyZWQgZHJpdmVycyBvZiBhbnkgY3B1IGNvb2xpbmcKPj4gPj4g
PiDCoGFjdGlvbi4gVGhlIGRyaXZlciBjYW4gbW9kaWZ5IHRoZSBkZWZhdWx0IGNvb2xpbmcgYmVo
YXZpb3VyKGVnIHNldCBkaWZmZXJlbnQKPj4gPj4gPiDCoG1heCBjbGlwIGZyZXF1ZW5jeSkuCj4+
ID4+ID4gKlRoZSBwZXJjZW50YWdlIGJhc2VkIGZyZXF1ZW5jeSByZXBsYWNlZCB3aXRoIGFic29s
dXRlIGNsaXBwZWQgZnJlcXVlbmN5Lgo+PiA+PiA+ICpTb21lIG1vcmUgY29uZGl0aW9uYWwgY2hl
Y2tzIHdoZW4gc2V0dGluZyBtYXggZnJlcXVlbmN5Lgo+PiA+PiA+ICpSZW5hbWVkIHRoZSBuZXcg
dHJpcCB0eXBlIFRIRVJNQUxfVFJJUF9TVEFURV9BQ1RJVkUgdG8KPj4gPj4gPiDCoFRIRVJNQUxf
VFJJUF9TVEFURV9JTlNUQU5DRQo+PiA+PiA+ICpNYW55IHJldmlldyBjb21tZW50cyBmcm9tIFIs
IER1cmdhZG9zcyA8ZHVyZ2Fkb3NzLnJAaW50ZWwuY29tPiBhbmQKPj4gPj4gPiDCoGVkdWFyZG8u
dmFsZW50aW5AdGkuY29tIGltcGxlbWVudGVkLgo+PiA+PiA+ICpSZW1vdmVkIGNvb2xpbmcgc3Rh
dHMgdGhyb3VnaCBkZWJ1Z2ZzIHBhdGNoCj4+ID4+ID4gKlRoZSBWMSBiYXNlZCBjYW4gYmUgZm91
bmQgaGVyZSwKPj4gPj4gPiDCoGh0dHBzOi8vbGttbC5vcmcvbGttbC8yMDEyLzIvMjIvMTIzCj4+
ID4+ID4gwqBodHRwOi8vbGttbC5vcmcvbGttbC8yMDEyLzMvMy8zMgo+PiA+PiA+Cj4+ID4+ID4g
Q2hhbmdlcyBzaW5jZSBSRkM6Cj4+ID4+ID4gKkNoYW5nZWQgdGhlIGNwdSBjb29saW5nIHJlZ2lz
dHJhdGlvbi91bnJlZ2lzdHJhdGlvbiBBUEkncyB0byBpbnN0YW5jZSBiYXNlZAo+PiA+PiA+ICpD
aGFuZ2VkIHRoZSBTVEFURV9BQ1RJVkUgdHJpcCB0eXBlIHRvIHBhc3MgY29ycmVjdCBpbnN0YW5j
ZSBpZAo+PiA+PiA+ICpBZGRpbmcgc3VwcG9ydCB0byByZXN0b3JlIGJhY2sgdGhlIHBvbGljeS0+
bWF4X2ZyZXEgYWZ0ZXIgZG9pbmcgZnJlcXVlbmN5Cj4+ID4+ID4gwqBjbGlwcGluZy4KPj4gPj4g
PiAqTW92ZWQgdGhlIHRyaXAgY29vbGluZyBzdGF0cyBmcm9tIHN5c2ZzIG5vZGUgdG8gZGVidWdm
cyBub2RlIGFzIHN1Z2dlc3RlZAo+PiA+PiA+IMKgYnkgR3JlZyBLSCBncmVnQGtyb2FoLmNvbQo+
PiA+PiA+ICpJbmNvcnBvcmF0ZWQgc2V2ZXJhbCByZXZpZXcgY29tbWVudHMgZnJvbSBlZHVhcmRv
LnZhbGVudGluQHRpLmNvbQo+PiA+PiA+ICpNb3ZlZCB0aGUgVGVtcGVyYXR1cmUgc2Vuc29yIGRy
aXZlciBmcm9tIGRyaXZlci9od21vbi8gdG8gZHJpdmVyL21mZAo+PiA+PiA+IMKgYXMgZGlzY3Vz
c2VkIHdpdGggR3VlbnRlciBSb2VjayA8Z3VlbnRlci5yb2Vja0Blcmljc3Nvbi5jb20+IGFuZAo+
PiA+PiA+IMKgRG9uZ2dldW4gS2ltIDxkZzc3LmtpbUBzYW1zdW5nLmNvbT4gKGh0dHBzOi8vbGtt
bC5vcmcvbGttbC8yMDEyLzEvNS83KQo+PiA+PiA+ICpTb21lIGNoYW5nZXMgYWNjb3JkaW5nIHRv
IHRoZSBjaGFuZ2VzIGluIGNvbW1vbiBjcHUgY29vbGluZyBBUElzCj4+ID4+ID4gKlRoZSBSRkMg
YmFzZWQgcGF0Y2hlcyBjYW4gYmUgZm91bmQgaGVyZSwKPj4gPj4gPiDCoGh0dHBzOi8vbGttbC5v
cmcvbGttbC8yMDExLzEyLzEzLzE4Ngo+PiA+PiA+IMKgaHR0cHM6Ly9sa21sLm9yZy9sa21sLzIw
MTEvMTIvMjEvMTY5Cj4+ID4+ID4KPj4gPj4gPgo+PiA+PiA+IEJyaWVmIERlc2NyaXB0aW9uOgo+
PiA+PiA+Cj4+ID4+ID4gMSkgVGhlIGdlbmVyaWMgY29vbGluZyBkZXZpY2VzIGNvZGUgaXMgcGxh
Y2VkIGluc2lkZSBkcml2ZXIvdGhlcm1hbC8qIGFzCj4+ID4+ID4gcGxhY2luZyBpbnNpZGUgYWNw
aSBmb2xkZXIgd2lsbCBuZWVkIHVuLW5lY2Vzc2FyeSBlbmFibGluZyBvZiBhY3BpIGNvZGUuIFRo
aXMKPj4gPj4gPiBjb2RlcyBpcyBhcmNoaXRlY3R1cmUgaW5kZXBlbmRlbnQuCj4+ID4+ID4KPj4g
Pj4gPiAyKSBUaGlzIHBhdGNoc2V0IGFkZHMgYSBuZXcgdHJpcCB0eXBlIFRIRVJNQUxfVFJJUF9T
VEFURV9JTlNUQU5DRSB3aGljaCBwYXNzZXMKPj4gPj4gPiBjb29saW5nIGRldmljZSBpbnN0YW5j
ZSBudW1iZXIgYW5kIG1heSBiZSBoZWxwZnVsIGZvciBjcHVmcmVxIGNvb2xpbmcgZGV2aWNlcwo+
PiA+PiA+IHRvIHRha2UgdGhlIGNvcnJlY3QgY29vbGluZyBhY3Rpb24uIFRoaXMgdHJpcCB0eXBl
IGF2b2lkcyB0aGUgdGVtcGVyYXR1cmUKPj4gPj4gPiBjb21wYXJpc2lvbiBjaGVjayBhZ2FpbiBp
bnNpZGUgdGhlIGNvb2xpbmcgaGFuZGxlci4KPj4gPj4gPgo+PiA+PiA+IDMpIFRoaXMgcGF0Y2hz
ZXQgYWRkcyBnZW5lcmljIGNwdSBjb29saW5nIGxvdyBsZXZlbCBpbXBsZW1lbnRhdGlvbiB0aHJv
dWdoCj4+ID4+ID4gZnJlcXVlbmN5IGNsaXBwaW5nIGFuZCBjcHUgaG90cGx1Zy4gSW4gZnV0dXJl
LCBvdGhlciBjcHUgcmVsYXRlZCBjb29saW5nCj4+ID4+ID4gZGV2aWNlcyBtYXkgYmUgYWRkZWQg
aGVyZS4gQW4gQUNQSSB2ZXJzaW9uIG9mIHRoaXMgYWxyZWFkeSBleGlzdHMKPj4gPj4gPiAoZHJp
dmVycy9hY3BpL3Byb2Nlc3Nvcl90aGVybWFsLmMpLiBCdXQgdGhpcyB3aWxsIGJlIHVzZWZ1bCBm
b3IgcGxhdGZvcm1zCj4+ID4+ID4gbGlrZSBBUk0gdXNpbmcgdGhlIGdlbmVyaWMgdGhlcm1hbCBp
bnRlcmZhY2UgYWxvbmcgd2l0aCB0aGUgZ2VuZXJpYyBjcHUKPj4gPj4gPiBjb29saW5nIGRldmlj
ZXMuIFRoZSBjb29saW5nIGRldmljZSByZWdpc3RyYXRpb24gQVBJJ3MgcmV0dXJuIGNvb2xpbmcg
ZGV2aWNlCj4+ID4+ID4gcG9pbnRlcnMgd2hpY2ggY2FuIGJlIGVhc2lseSBiaW5kZWQgd2l0aCB0
aGUgdGhlcm1hbCB6b25lIHRyaXAgcG9pbnRzLgo+PiA+PiA+IFRoZSBpbXBvcnRhbnQgQVBJcyBl
eHBvc2VkIGFyZSwKPj4gPj4gPiDCoCBhKXN0cnVjdCB0aGVybWFsX2Nvb2xpbmdfZGV2aWNlICpj
cHVmcmVxX2Nvb2xpbmdfcmVnaXN0ZXIoCj4+ID4+ID4gwqAgwqAgwqAgwqBzdHJ1Y3QgZnJlcV9j
bGlwX3RhYmxlICp0YWJfcHRyLCB1bnNpZ25lZCBpbnQgdGFiX3NpemUsCj4+ID4+ID4gwqAgwqAg
wqAgwqBjb25zdCBzdHJ1Y3QgY3B1bWFzayAqbWFza192YWwpCj4+ID4+ID4gwqAgYil2b2lkIGNw
dWZyZXFfY29vbGluZ191bnJlZ2lzdGVyKHN0cnVjdCB0aGVybWFsX2Nvb2xpbmdfZGV2aWNlICpj
ZGV2KQo+PiA+PiA+Cj4+ID4+ID4gNCkgU2Ftc3VuZyBleHlub3MgcGxhdGZvcm0gdGhlcm1hbCBp
bXBsZW1lbnRhdGlvbiBpcyBkb25lIHVzaW5nIHRoZSBnZW5lcmljCj4+ID4+ID4gY3B1IGNvb2xp
bmcgQVBJcyBhbmQgdGhlIG5ldyB0cmlwIHR5cGUuIFRoZSB0ZW1wZXJhdHVyZSBzZW5zb3IgZHJp
dmVyIHByZXNlbnQKPj4gPj4gPiBpbiB0aGUgaHdtb24gZm9sZGVyKHJlZ2lzdGVyZWQgYXMgaHdt
b24gZHJpdmVyKSBpcyBtb3ZlZCB0byB0aGVybWFsIGZvbGRlcgo+PiA+PiA+IGFuZCByZWdpc3Rl
cmVkIGFzIGEgdGhlcm1hbCBkcml2ZXIuCj4+ID4+ID4KPj4gPj4gPiBBbGwgdGhpcyBwYXRjaHNl
dCBpcyBiYXNlZCBvbiBLZXJuZWwgdmVyc2lvbiAzLjMtcmM3Cj4+ID4+ID4KPj4gPj4gPiBBIHNp
bXBsZSBkYXRhL2NvbnRyb2wgZmxvdyBkaWFncmFtcyBpcyBzaG93biBiZWxvdywKPj4gPj4gPgo+
PiA+PiA+IENvcmUgTGludXggdGhlcm1hbCA8LS0tLS0+IMKgRXh5bm9zIHRoZXJtYWwgaW50ZXJm
YWNlIDwtLS0tLSBUZW1wZXJhdHVyZSBTZW5zb3IKPj4gPj4gPiDCoCDCoCDCoCDCoCDCoHwgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfAo+PiA+PiA+IMKgIMKgIMKg
IMKgIFx8LyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHwKPj4gPj4g
PiDCoENwdWZyZXEgY29vbGluZyBkZXZpY2UgPC0tLS0tLS0tLS0tLS0tLQo+PiA+PiA+Cj4+ID4+
ID4KPj4gPj4gPiBBbWl0IERhbmllbCBLYWNoaGFwICg2KToKPj4gPj4gPiDCoHRoZXJtYWw6IEFk
ZCBhIG5ldyB0cmlwIHR5cGUgdG8gdXNlIGNvb2xpbmcgZGV2aWNlIGluc3RhbmNlIG51bWJlcgo+
PiA+PiA+IMKgdGhlcm1hbDogQWRkIGdlbmVyaWMgY3B1ZnJlcSBjb29saW5nIGltcGxlbWVudGF0
aW9uCj4+ID4+ID4gwqB0aGVybWFsOiBBZGQgZ2VuZXJpYyBjcHVob3RwbHVnIGNvb2xpbmcgaW1w
bGVtZW50YXRpb24KPj4gPj4gPiDCoGh3bW9uOiBleHlub3M0OiBNb3ZlIHRoZXJtYWwgc2Vuc29y
IGRyaXZlciB0byBkcml2ZXIvdGhlcm1hbAo+PiA+PiA+IMKgIMKgZGlyZWN0b3J5Cj4+ID4+ID4g
wqB0aGVybWFsOiBleHlub3M0OiBSZWdpc3RlciB0aGUgdG11IHNlbnNvciB3aXRoIHRoZSBrZXJu
ZWwgdGhlcm1hbAo+PiA+PiA+IMKgIMKgbGF5ZXIKPj4gPj4gPiDCoEFSTTogZXh5bm9zNDogQWRk
IHRoZXJtYWwgc2Vuc29yIGRyaXZlciBwbGF0Zm9ybSBkZXZpY2Ugc3VwcG9ydAo+PiA+PiA+Cj4+
ID4+ID4gwqBEb2N1bWVudGF0aW9uL2h3bW9uL2V4eW5vczRfdG11IMKgIMKgIMKgIMKgIMKgIHwg
wqAgODEgLS0tCj4+ID4+ID4gwqBEb2N1bWVudGF0aW9uL3RoZXJtYWwvY3B1LWNvb2xpbmctYXBp
LnR4dCB8IMKgIDc2ICsrKwo+PiA+PiA+IMKgRG9jdW1lbnRhdGlvbi90aGVybWFsL2V4eW5vczRf
dG11IMKgIMKgIMKgIMKgIHwgwqAgNTIgKysKPj4gPj4gPiDCoERvY3VtZW50YXRpb24vdGhlcm1h
bC9zeXNmcy1hcGkudHh0IMKgIMKgIMKgIHwgwqAgwqA0ICstCj4+ID4+ID4gwqBhcmNoL2FybS9t
YWNoLWV4eW5vcy9LY29uZmlnIMKgIMKgIMKgIMKgIMKgIMKgIMKgfCDCoCAxMSArCj4+ID4+ID4g
wqBhcmNoL2FybS9tYWNoLWV4eW5vcy9NYWtlZmlsZSDCoCDCoCDCoCDCoCDCoCDCoCB8IMKgIMKg
MSArCj4+ID4+ID4gwqBhcmNoL2FybS9tYWNoLWV4eW5vcy9jbG9jay5jIMKgIMKgIMKgIMKgIMKg
IMKgIMKgfCDCoCDCoDQgKwo+PiA+PiA+IMKgYXJjaC9hcm0vbWFjaC1leHlub3MvZGV2LXRtdS5j
IMKgIMKgIMKgIMKgIMKgIMKgfCDCoCAzOSArKwo+PiA+PiA+IMKgYXJjaC9hcm0vbWFjaC1leHlu
b3MvaW5jbHVkZS9tYWNoL2lycXMuaCDCoHwgwqAgwqAyICsKPj4gPj4gPiDCoGFyY2gvYXJtL21h
Y2gtZXh5bm9zL2luY2x1ZGUvbWFjaC9tYXAuaCDCoCB8IMKgIMKgMSArCj4+ID4+ID4gwqBhcmNo
L2FybS9tYWNoLWV4eW5vcy9tYWNoLW9yaWdlbi5jIMKgIMKgIMKgIMKgfCDCoCDCoDEgKwo+PiA+
PiA+IMKgYXJjaC9hcm0vcGxhdC1zYW1zdW5nL2luY2x1ZGUvcGxhdC9kZXZzLmggfCDCoCDCoDEg
Kwo+PiA+PiA+IMKgZHJpdmVycy9od21vbi9LY29uZmlnIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIHwgwqAgMTAgLQo+PiA+PiA+IMKgZHJpdmVycy9od21vbi9NYWtlZmlsZSDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoHwgwqAgwqAxIC0KPj4gPj4gPiDCoGRyaXZlcnMvaHdtb24v
ZXh5bm9zNF90bXUuYyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB8IMKgNTE0IC0tLS0tLS0tLS0tLS0t
LS0tLS0KPj4gPj4gPiDCoGRyaXZlcnMvdGhlcm1hbC9LY29uZmlnIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHwgwqAgMjEgKwo+PiA+PiA+IMKgZHJpdmVycy90aGVybWFsL01ha2VmaWxlIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfCDCoCDCoDIgKwo+PiA+PiA+IMKgZHJpdmVycy90aGVy
bWFsL2NwdV9jb29saW5nLmMgwqAgwqAgwqAgwqAgwqAgwqAgfCDCoDUyOSArKysrKysrKysrKysr
KysrKysrCj4+ID4+ID4gwqBkcml2ZXJzL3RoZXJtYWwvZXh5bm9zNF90aGVybWFsLmMgwqAgwqAg
wqAgwqAgfCDCoDc5MCArKysrKysrKysrKysrKysrKysrKysrKysrKysrKwo+PiA+PiA+IMKgZHJp
dmVycy90aGVybWFsL3RoZXJtYWxfc3lzLmMgwqAgwqAgwqAgwqAgwqAgwqAgfCDCoCA0NSArKy0K
Pj4gPj4gPiDCoGluY2x1ZGUvbGludXgvY3B1X2Nvb2xpbmcuaCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCB8IMKgIDc4ICsrKwo+PiA+PiA+IMKgaW5jbHVkZS9saW51eC9wbGF0Zm9ybV9kYXRhL2V4eW5v
czRfdG11LmggfCDCoCDCoDcgKwo+PiA+PiA+IMKgaW5jbHVkZS9saW51eC90aGVybWFsLmggwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfCDCoCDCoDEgKwo+PiA+PiA+IMKgMjMgZmlsZXMgY2hh
bmdlZCwgMTY2MCBpbnNlcnRpb25zKCspLCA2MTEgZGVsZXRpb25zKC0pCj4+ID4+ID4gwqBkZWxl
dGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi9od21vbi9leHlub3M0X3RtdQo+PiA+PiA+IMKg
Y3JlYXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRpb24vdGhlcm1hbC9jcHUtY29vbGluZy1hcGku
dHh0Cj4+ID4+ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgRG9jdW1lbnRhdGlvbi90aGVybWFsL2V4
eW5vczRfdG11Cj4+ID4+ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgYXJjaC9hcm0vbWFjaC1leHlu
b3MvZGV2LXRtdS5jCj4+ID4+ID4gwqBkZWxldGUgbW9kZSAxMDA2NDQgZHJpdmVycy9od21vbi9l
eHlub3M0X3RtdS5jCj4+ID4+ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90aGVybWFs
L2NwdV9jb29saW5nLmMKPj4gPj4gPiDCoGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3RoZXJt
YWwvZXh5bm9zNF90aGVybWFsLmMKPj4gPj4gPiDCoGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRl
L2xpbnV4L2NwdV9jb29saW5nLmgKPj4gPj4gPgo+PiA+Cj4+ID4KPgo+CgpfX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpsbS1zZW5zb3JzIG1haWxpbmcgbGlz
dApsbS1zZW5zb3JzQGxtLXNlbnNvcnMub3JnCmh0dHA6Ly9saXN0cy5sbS1zZW5zb3JzLm9yZy9t
YWlsbWFuL2xpc3RpbmZvL2xtLXNlbnNvcnM
^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2012-04-24 13:36 UTC | newest]
Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-19 6:17 [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 6:17 ` [PATCH V2 1/6] thermal: Add a new trip type to use cooling device instance number Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 6:17 ` [PATCH V2 2/6] thermal: Add generic cpufreq cooling implementation Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 6:17 ` [PATCH V2 3/6] thermal: Add generic cpuhotplug " Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 11:45 ` Srivatsa S. Bhat
2012-03-19 11:57 ` [lm-sensors] " Srivatsa S. Bhat
2012-03-19 11:45 ` Srivatsa S. Bhat
2012-03-20 6:06 ` Amit Kachhap
2012-03-20 6:18 ` [lm-sensors] " Amit Kachhap
2012-03-19 6:17 ` [PATCH V2 4/6] hwmon: exynos4: Move thermal sensor driver to driver/thermal directory Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 6:17 ` [PATCH V2 5/6] thermal: exynos4: Register the tmu sensor with the kernel thermal layer Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-03-19 6:17 ` [PATCH V2 6/6] ARM: exynos4: Add thermal sensor driver platform device support Amit Daniel Kachhap
2012-03-19 6:29 ` [lm-sensors] " Amit Daniel Kachhap
2012-03-19 6:17 ` Amit Daniel Kachhap
2012-04-04 4:32 ` [PATCH V2 0/6] thermal: exynos: Add kernel thermal support for exynos platform Amit Kachhap
2012-04-04 4:44 ` [lm-sensors] " Amit Kachhap
2012-04-04 4:32 ` Amit Kachhap
2012-04-10 0:58 ` Zhang Rui
2012-04-10 0:58 ` Zhang Rui
2012-04-10 0:58 ` [lm-sensors] " Zhang Rui
2012-04-11 12:47 ` Amit Kachhap
2012-04-11 12:59 ` [lm-sensors] " Amit Kachhap
2012-04-11 12:47 ` Amit Kachhap
2012-04-16 2:07 ` Zhang Rui
2012-04-16 2:07 ` Zhang Rui
2012-04-16 2:07 ` [lm-sensors] " Zhang Rui
2012-04-24 13:24 ` Amit Kachhap
2012-04-24 13:36 ` [lm-sensors] " Amit Kachhap
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.