From: Stephen Rothwell Date: Wed, 3 Oct 2012 02:12:15 +0000 (+1000) Subject: Merge remote-tracking branch 'thermal/next' X-Git-Tag: next-20121003~58 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=0bb326e5ad7e5c8a79d43f8767af5c40f8104362;p=karo-tx-linux.git Merge remote-tracking branch 'thermal/next' Conflicts: drivers/staging/omap-thermal/omap-thermal-common.c drivers/thermal/thermal_sys.c --- 0bb326e5ad7e5c8a79d43f8767af5c40f8104362 diff --cc drivers/hwmon/Kconfig index c74e73b2069a,84e02b416a4a..c4633de64465 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@@ -334,19 -324,9 +334,9 @@@ config SENSORS_DA9052_AD This driver can also be built as module. If so, the module will be called da9052-hwmon. - 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 Management - 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 + depends on PCI help If you say yes here you get support for FB-DIMM AMB temperature monitoring chips on systems with the Intel 5000 series chipset. diff --cc drivers/thermal/thermal_sys.c index 67789b8345d2,848553dd4bb7..3b87b1840db3 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@@ -91,6 -161,264 +161,261 @@@ static void release_idr(struct idr *idr mutex_unlock(lock); } + int get_tz_trend(struct thermal_zone_device *tz, int trip) + { + enum thermal_trend trend; + + if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) { + if (tz->temperature > tz->last_temperature) + trend = THERMAL_TREND_RAISING; + else if (tz->temperature < tz->last_temperature) + trend = THERMAL_TREND_DROPPING; + else + trend = THERMAL_TREND_STABLE; + } + + return trend; + } + EXPORT_SYMBOL(get_tz_trend); + + struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev, int trip) + { + struct thermal_instance *pos = NULL; + struct thermal_instance *target_instance = NULL; + + mutex_lock(&tz->lock); + mutex_lock(&cdev->lock); + + list_for_each_entry(pos, &tz->thermal_instances, tz_node) { + if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { + target_instance = pos; + break; + } + } + + mutex_unlock(&cdev->lock); + mutex_unlock(&tz->lock); + + return target_instance; + } + EXPORT_SYMBOL(get_thermal_instance); + + static void print_bind_err_msg(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev, int ret) + { + dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n", + tz->type, cdev->type, ret); + } + + static void __bind(struct thermal_zone_device *tz, int mask, + struct thermal_cooling_device *cdev) + { + int i, ret; + + for (i = 0; i < tz->trips; i++) { + if (mask & (1 << i)) { + ret = thermal_zone_bind_cooling_device(tz, i, cdev, + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); + if (ret) + print_bind_err_msg(tz, cdev, ret); + } + } + } + + static void __unbind(struct thermal_zone_device *tz, int mask, + struct thermal_cooling_device *cdev) + { + int i; + + for (i = 0; i < tz->trips; i++) + if (mask & (1 << i)) + thermal_zone_unbind_cooling_device(tz, i, cdev); + } + + static void bind_cdev(struct thermal_cooling_device *cdev) + { + int i, ret; + const struct thermal_zone_params *tzp; + struct thermal_zone_device *pos = NULL; + + mutex_lock(&thermal_list_lock); + + list_for_each_entry(pos, &thermal_tz_list, node) { + if (!pos->tzp && !pos->ops->bind) + continue; + + if (!pos->tzp && pos->ops->bind) { + ret = pos->ops->bind(pos, cdev); + if (ret) + print_bind_err_msg(pos, cdev, ret); + } + + tzp = pos->tzp; + if (!tzp || !tzp->tbp) + continue; + + for (i = 0; i < tzp->num_tbps; i++) { + if (tzp->tbp[i].cdev || !tzp->tbp[i].match) + continue; + if (tzp->tbp[i].match(pos, cdev)) + continue; + tzp->tbp[i].cdev = cdev; + __bind(pos, tzp->tbp[i].trip_mask, cdev); + } + } + + mutex_unlock(&thermal_list_lock); + } + + static void bind_tz(struct thermal_zone_device *tz) + { + int i, ret; + struct thermal_cooling_device *pos = NULL; + const struct thermal_zone_params *tzp = tz->tzp; + + if (!tzp && !tz->ops->bind) + return; + + mutex_lock(&thermal_list_lock); + + /* If there is no platform data, try to use ops->bind */ + if (!tzp && tz->ops->bind) { + list_for_each_entry(pos, &thermal_cdev_list, node) { + ret = tz->ops->bind(tz, pos); + if (ret) + print_bind_err_msg(tz, pos, ret); + } + goto exit; + } + + if (!tzp || !tzp->tbp) + goto exit; + + list_for_each_entry(pos, &thermal_cdev_list, node) { + for (i = 0; i < tzp->num_tbps; i++) { + if (tzp->tbp[i].cdev || !tzp->tbp[i].match) + continue; + if (tzp->tbp[i].match(tz, pos)) + continue; + tzp->tbp[i].cdev = pos; + __bind(tz, tzp->tbp[i].trip_mask, pos); + } + } + exit: + mutex_unlock(&thermal_list_lock); + } + + static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, + int delay) + { - cancel_delayed_work(&(tz->poll_queue)); - - if (!delay) - return; - + if (delay > 1000) - queue_delayed_work(system_freezable_wq, &(tz->poll_queue), - round_jiffies(msecs_to_jiffies(delay))); ++ mod_delayed_work(system_freezable_wq, &tz->poll_queue, ++ round_jiffies(msecs_to_jiffies(delay))); ++ else if (delay) ++ mod_delayed_work(system_freezable_wq, &tz->poll_queue, ++ msecs_to_jiffies(delay)); + else - queue_delayed_work(system_freezable_wq, &(tz->poll_queue), - msecs_to_jiffies(delay)); ++ cancel_delayed_work(&tz->poll_queue); + } + + static void monitor_thermal_zone(struct thermal_zone_device *tz) + { + mutex_lock(&tz->lock); + + if (tz->passive) + thermal_zone_device_set_polling(tz, tz->passive_delay); + else if (tz->polling_delay) + thermal_zone_device_set_polling(tz, tz->polling_delay); + else + thermal_zone_device_set_polling(tz, 0); + + mutex_unlock(&tz->lock); + } + + static void handle_non_critical_trips(struct thermal_zone_device *tz, + int trip, enum thermal_trip_type trip_type) + { + tz->governor->throttle(tz, trip); + } + + static void handle_critical_trips(struct thermal_zone_device *tz, + int trip, enum thermal_trip_type trip_type) + { + long trip_temp; + + tz->ops->get_trip_temp(tz, trip, &trip_temp); + + /* If we have not crossed the trip_temp, we do not care. */ + if (tz->temperature < trip_temp) + return; + + if (tz->ops->notify) + tz->ops->notify(tz, trip, trip_type); + + if (trip_type == THERMAL_TRIP_CRITICAL) { + pr_emerg("Critical temperature reached(%d C),shutting down\n", + tz->temperature / 1000); + orderly_poweroff(true); + } + } + + static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) + { + enum thermal_trip_type type; + + tz->ops->get_trip_type(tz, trip, &type); + + if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) + handle_critical_trips(tz, trip, type); + else + handle_non_critical_trips(tz, trip, type); + /* + * Alright, we handled this trip successfully. + * So, start monitoring again. + */ + monitor_thermal_zone(tz); + } + + static void update_temperature(struct thermal_zone_device *tz) + { + long temp; + int ret; + + mutex_lock(&tz->lock); + + ret = tz->ops->get_temp(tz, &temp); + if (ret) { + pr_warn("failed to read out thermal zone %d\n", tz->id); + goto exit; + } + + tz->last_temperature = tz->temperature; + tz->temperature = temp; + + exit: + mutex_unlock(&tz->lock); + } + + void thermal_zone_device_update(struct thermal_zone_device *tz) + { + int count; + + update_temperature(tz); + + for (count = 0; count < tz->trips; count++) + handle_thermal_trip(tz, count); + } + EXPORT_SYMBOL(thermal_zone_device_update); + + static void thermal_zone_device_check(struct work_struct *work) + { + struct thermal_zone_device *tz = container_of(work, struct + thermal_zone_device, + poll_queue.work); + thermal_zone_device_update(tz); + } + /* sys I/F for thermal zone */ #define to_thermal_zone(_dev) \