From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/thermal/thermal_core.c | 559 +++++++++++++++++++++++++++++-------------------------- 1 files changed, 293 insertions(+), 266 deletions(-) diff --git a/kernel/drivers/thermal/thermal_core.c b/kernel/drivers/thermal/thermal_core.c index 07e4862..48a993d 100644 --- a/kernel/drivers/thermal/thermal_core.c +++ b/kernel/drivers/thermal/thermal_core.c @@ -9,9 +9,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/module.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/kdev_t.h> #include <linux/idr.h> @@ -19,22 +19,15 @@ #include <linux/reboot.h> #include <linux/string.h> #include <linux/of.h> -#include <net/netlink.h> -#include <net/genetlink.h> #include <linux/suspend.h> -#ifdef CONFIG_ARCH_ROCKCHIP -#include <soc/rockchip/rockchip_system_monitor.h> -#endif #define CREATE_TRACE_POINTS #include <trace/events/thermal.h> +#undef CREATE_TRACE_POINTS +#include <trace/hooks/thermal.h> #include "thermal_core.h" #include "thermal_hwmon.h" - -MODULE_AUTHOR("Zhang Rui"); -MODULE_DESCRIPTION("Generic thermal management sysfs support"); -MODULE_LICENSE("GPL v2"); static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); @@ -224,6 +217,8 @@ mutex_unlock(&tz->lock); mutex_unlock(&thermal_governor_lock); + thermal_notify_tz_gov_change(tz->id, policy); + return ret; } @@ -245,36 +240,42 @@ return count; } -static int __init thermal_register_governors(void) +static void __init thermal_unregister_governors(void) { - int result; + struct thermal_governor **governor; - result = thermal_gov_step_wise_register(); - if (result) - return result; - - result = thermal_gov_fair_share_register(); - if (result) - return result; - - result = thermal_gov_bang_bang_register(); - if (result) - return result; - - result = thermal_gov_user_space_register(); - if (result) - return result; - - return thermal_gov_power_allocator_register(); + for_each_governor_table(governor) + thermal_unregister_governor(*governor); } -static void thermal_unregister_governors(void) +static int __init thermal_register_governors(void) { - thermal_gov_step_wise_unregister(); - thermal_gov_fair_share_unregister(); - thermal_gov_bang_bang_unregister(); - thermal_gov_user_space_unregister(); - thermal_gov_power_allocator_unregister(); + int ret = 0; + struct thermal_governor **governor; + + for_each_governor_table(governor) { + ret = thermal_register_governor(*governor); + if (ret) { + pr_err("Failed to register governor: '%s'", + (*governor)->name); + break; + } + + pr_info("Registered thermal governor '%s'", + (*governor)->name); + } + + if (ret) { + struct thermal_governor **gov; + + for_each_governor_table(gov) { + if (gov == governor) + break; + thermal_unregister_governor(*gov); + } + } + + return ret; } /* @@ -292,22 +293,33 @@ int delay) { if (delay > 1000) - mod_delayed_work(system_freezable_wq, &tz->poll_queue, + mod_delayed_work(system_freezable_power_efficient_wq, + &tz->poll_queue, round_jiffies(msecs_to_jiffies(delay))); else if (delay) - mod_delayed_work(system_freezable_wq, &tz->poll_queue, + mod_delayed_work(system_freezable_power_efficient_wq, + &tz->poll_queue, msecs_to_jiffies(delay)); else cancel_delayed_work(&tz->poll_queue); } +static inline bool should_stop_polling(struct thermal_zone_device *tz) +{ + return !thermal_zone_device_is_enabled(tz); +} + static void monitor_thermal_zone(struct thermal_zone_device *tz) { + bool stop; + + stop = should_stop_polling(tz); + mutex_lock(&tz->lock); - if (tz->passive) + if (!stop && tz->passive) thermal_zone_device_set_polling(tz, tz->passive_delay); - else if (tz->polling_delay) + else if (!stop && tz->polling_delay) thermal_zone_device_set_polling(tz, tz->polling_delay); else thermal_zone_device_set_polling(tz, 0); @@ -315,9 +327,7 @@ mutex_unlock(&tz->lock); } -static void handle_non_critical_trips(struct thermal_zone_device *tz, - int trip, - enum thermal_trip_type trip_type) +static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip) { tz->governor ? tz->governor->throttle(tz, trip) : def_governor->throttle(tz, trip); @@ -408,39 +418,35 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) { enum thermal_trip_type type; + int trip_temp, hyst = 0; /* Ignore disabled trip points */ if (test_bit(trip, &tz->trips_disabled)) return; + tz->ops->get_trip_temp(tz, trip, &trip_temp); tz->ops->get_trip_type(tz, trip, &type); + if (tz->ops->get_trip_hyst) + tz->ops->get_trip_hyst(tz, trip, &hyst); + + if (tz->last_temperature != THERMAL_TEMP_INVALID) { + if (tz->last_temperature < trip_temp && + tz->temperature >= trip_temp) + thermal_notify_tz_trip_up(tz->id, trip); + if (tz->last_temperature >= trip_temp && + tz->temperature < (trip_temp - hyst)) + thermal_notify_tz_trip_down(tz->id, trip); + } if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) handle_critical_trips(tz, trip, type); else - handle_non_critical_trips(tz, trip, type); + handle_non_critical_trips(tz, trip); /* * Alright, we handled this trip successfully. * So, start monitoring again. */ monitor_thermal_zone(tz); -} - -static void store_temperature(struct thermal_zone_device *tz, int temp) -{ - mutex_lock(&tz->lock); - tz->last_temperature = tz->temperature; - tz->temperature = temp; - mutex_unlock(&tz->lock); - - trace_thermal_temperature(tz); - if (tz->last_temperature == THERMAL_TEMP_INVALID || - tz->last_temperature == THERMAL_TEMP_INVALID_LOW) - dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", - tz->temperature); - else - dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", - tz->last_temperature, tz->temperature); } static void update_temperature(struct thermal_zone_device *tz) @@ -455,7 +461,15 @@ ret); return; } - store_temperature(tz, temp); + + mutex_lock(&tz->lock); + tz->last_temperature = tz->temperature; + tz->temperature = temp; + mutex_unlock(&tz->lock); + + trace_thermal_temperature(tz); + + thermal_genl_sampling_temp(tz->id, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) @@ -474,38 +488,73 @@ thermal_zone_device_init(tz); } -void thermal_zone_device_update_temp(struct thermal_zone_device *tz, - enum thermal_notify_event event, int temp) +static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, + enum thermal_device_mode mode) { - int count; + int ret = 0; - if (!tz || !tz->ops) - return; + mutex_lock(&tz->lock); - if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable || - !(tz->ops->is_wakeable(tz)))) - return; + /* do nothing if mode isn't changing */ + if (mode == tz->mode) { + mutex_unlock(&tz->lock); - store_temperature(tz, temp); + return ret; + } - thermal_zone_set_trips(tz); + if (tz->ops->change_mode) + ret = tz->ops->change_mode(tz, mode); - tz->notify_event = event; + if (!ret) + tz->mode = mode; - for (count = 0; count < tz->trips; count++) - handle_thermal_trip(tz, count); + mutex_unlock(&tz->lock); + + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + if (mode == THERMAL_DEVICE_ENABLED) + thermal_notify_tz_enable(tz->id); + else + thermal_notify_tz_disable(tz->id); + + return ret; } + +int thermal_zone_device_enable(struct thermal_zone_device *tz) +{ + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED); +} +EXPORT_SYMBOL_GPL(thermal_zone_device_enable); + +int thermal_zone_device_disable(struct thermal_zone_device *tz) +{ + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED); +} +EXPORT_SYMBOL_GPL(thermal_zone_device_disable); + +int thermal_zone_device_is_enabled(struct thermal_zone_device *tz) +{ + enum thermal_device_mode mode; + + mutex_lock(&tz->lock); + + mode = tz->mode; + + mutex_unlock(&tz->lock); + + return mode == THERMAL_DEVICE_ENABLED; +} +EXPORT_SYMBOL_GPL(thermal_zone_device_is_enabled); void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { int count; - if (!tz || !tz->ops) + if (should_stop_polling(tz)) return; - if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable || - !(tz->ops->is_wakeable(tz)))) + if (atomic_read(&in_suspend)) return; if (!tz->ops->get_temp) @@ -558,7 +607,6 @@ /** * power_actor_get_max_power() - get the maximum power that a cdev can consume * @cdev: pointer to &thermal_cooling_device - * @tz: a valid thermal zone device pointer * @max_power: pointer in which to store the maximum power * * Calculate the maximum power consumption in milliwats that the @@ -568,18 +616,17 @@ * power_actor API or -E* on other error. */ int power_actor_get_max_power(struct thermal_cooling_device *cdev, - struct thermal_zone_device *tz, u32 *max_power) + u32 *max_power) { if (!cdev_is_power_actor(cdev)) return -EINVAL; - return cdev->ops->state2power(cdev, tz, 0, max_power); + return cdev->ops->state2power(cdev, 0, max_power); } /** * power_actor_get_min_power() - get the mainimum power that a cdev can consume * @cdev: pointer to &thermal_cooling_device - * @tz: a valid thermal zone device pointer * @min_power: pointer in which to store the minimum power * * Calculate the minimum power consumption in milliwatts that the @@ -589,7 +636,7 @@ * power_actor API or -E* on other error. */ int power_actor_get_min_power(struct thermal_cooling_device *cdev, - struct thermal_zone_device *tz, u32 *min_power) + u32 *min_power) { unsigned long max_state; int ret; @@ -601,7 +648,7 @@ if (ret) return ret; - return cdev->ops->state2power(cdev, tz, max_state, min_power); + return cdev->ops->state2power(cdev, max_state, min_power); } /** @@ -625,16 +672,7 @@ if (!cdev_is_power_actor(cdev)) return -EINVAL; - ret = cdev->ops->power2state(cdev, instance->tz, power, &state); -#ifdef CONFIG_ARCH_ROCKCHIP - if (ret) - state = THERMAL_CSTATE_INVALID; - rockchip_system_monitor_adjust_cdev_state(cdev, - instance->tz->temperature, - &state); - if (state == THERMAL_CSTATE_INVALID) - ret = -EINVAL; -#endif + ret = cdev->ops->power2state(cdev, power, &state); if (ret) return ret; @@ -665,6 +703,73 @@ THERMAL_WEIGHT_DEFAULT); } mutex_unlock(&thermal_list_lock); +} + +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), + void *data) +{ + struct thermal_governor *gov; + int ret = 0; + + mutex_lock(&thermal_governor_lock); + list_for_each_entry(gov, &thermal_governor_list, governor_list) { + ret = cb(gov, data); + if (ret) + break; + } + mutex_unlock(&thermal_governor_lock); + + return ret; +} + +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, + void *), void *data) +{ + struct thermal_cooling_device *cdev; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(cdev, &thermal_cdev_list, node) { + ret = cb(cdev, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), + void *data) +{ + struct thermal_zone_device *tz; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + ret = cb(tz, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + +struct thermal_zone_device *thermal_zone_get_by_id(int id) +{ + struct thermal_zone_device *tz, *match = NULL; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + if (tz->id == id) { + match = tz; + break; + } + } + mutex_unlock(&thermal_list_lock); + + return match; } void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, @@ -780,9 +885,8 @@ sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); sysfs_attr_init(&dev->attr.attr); dev->attr.attr.name = dev->attr_name; - dev->attr.attr.mode = 0644; + dev->attr.attr.mode = 0444; dev->attr.show = trip_point_show; - dev->attr.store = trip_point_store; result = device_create_file(&tz->device, &dev->attr); if (result) goto remove_symbol_link; @@ -1024,7 +1128,7 @@ result = device_register(&cdev->device); if (result) { ida_simple_remove(&thermal_cdev_ida, cdev->id); - kfree(cdev); + put_device(&cdev->device); return ERR_PTR(result); } @@ -1090,6 +1194,55 @@ return __thermal_cooling_device_register(np, type, devdata, ops); } EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register); + +static void thermal_cooling_device_release(struct device *dev, void *res) +{ + thermal_cooling_device_unregister( + *(struct thermal_cooling_device **)res); +} + +/** + * devm_thermal_of_cooling_device_register() - register an OF thermal cooling + * device + * @dev: a valid struct device pointer of a sensor device. + * @np: a pointer to a device tree node. + * @type: the thermal cooling device type. + * @devdata: device private data. + * @ops: standard thermal cooling devices callbacks. + * + * This function will register a cooling device with device tree node reference. + * This interface function adds a new thermal cooling device (fan/processor/...) + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself + * to all the thermal zone devices registered at the same time. + * + * Return: a pointer to the created struct thermal_cooling_device or an + * ERR_PTR. Caller must check return value with IS_ERR*() helpers. + */ +struct thermal_cooling_device * +devm_thermal_of_cooling_device_register(struct device *dev, + struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + struct thermal_cooling_device **ptr, *tcd; + + ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + tcd = __thermal_cooling_device_register(np, type, devdata, ops); + if (IS_ERR(tcd)) { + devres_free(ptr); + return tcd; + } + + *ptr = tcd; + devres_add(dev, ptr); + + return tcd; +} +EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register); static void __unbind(struct thermal_zone_device *tz, int mask, struct thermal_cooling_device *cdev) @@ -1230,21 +1383,31 @@ struct thermal_zone_device *tz; enum thermal_trip_type trip_type; int trip_temp; + int id; int result; int count; struct thermal_governor *governor; - if (!type || strlen(type) == 0) + if (!type || strlen(type) == 0) { + pr_err("Error: No thermal zone type defined\n"); return ERR_PTR(-EINVAL); + } - if (type && strlen(type) >= THERMAL_NAME_LENGTH) + if (type && strlen(type) >= THERMAL_NAME_LENGTH) { + pr_err("Error: Thermal zone name (%s) too long, should be under %d chars\n", + type, THERMAL_NAME_LENGTH); return ERR_PTR(-EINVAL); + } - if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) + if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) { + pr_err("Error: Incorrect number of thermal trips\n"); return ERR_PTR(-EINVAL); + } - if (!ops) + if (!ops) { + pr_err("Error: Thermal zone device ops not defined\n"); return ERR_PTR(-EINVAL); + } if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp)) return ERR_PTR(-EINVAL); @@ -1256,11 +1419,13 @@ INIT_LIST_HEAD(&tz->thermal_instances); ida_init(&tz->ida); mutex_init(&tz->lock); - result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL); - if (result < 0) + id = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL); + if (id < 0) { + result = id; goto free_tz; + } - tz->id = result; + tz->id = id; strlcpy(tz->type, type, sizeof(tz->type)); tz->ops = ops; tz->tzp = tzp; @@ -1282,7 +1447,7 @@ dev_set_name(&tz->device, "thermal_zone%d", tz->id); result = device_register(&tz->device); if (result) - goto remove_device_groups; + goto release_device; for (count = 0; count < trips; count++) { if (tz->ops->get_trip_type(tz, count, &trip_type)) @@ -1330,17 +1495,17 @@ if (atomic_cmpxchg(&tz->need_update, 1, 0)) thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_notify_tz_create(tz->id, tz->type); + return tz; unregister: - ida_simple_remove(&thermal_tz_ida, tz->id); - device_unregister(&tz->device); - return ERR_PTR(result); - -remove_device_groups: - thermal_zone_destroy_device_groups(tz); + device_del(&tz->device); +release_device: + put_device(&tz->device); + tz = NULL; remove_id: - ida_simple_remove(&thermal_tz_ida, tz->id); + ida_simple_remove(&thermal_tz_ida, id); free_tz: kfree(tz); return ERR_PTR(result); @@ -1353,7 +1518,7 @@ */ void thermal_zone_device_unregister(struct thermal_zone_device *tz) { - int i; + int i, tz_id; const struct thermal_zone_params *tzp; struct thermal_cooling_device *cdev; struct thermal_zone_device *pos = NULL; @@ -1362,6 +1527,7 @@ return; tzp = tz->tzp; + tz_id = tz->id; mutex_lock(&thermal_list_lock); list_for_each_entry(pos, &thermal_tz_list, node) @@ -1403,6 +1569,8 @@ ida_destroy(&tz->ida); mutex_destroy(&tz->lock); device_unregister(&tz->device); + + thermal_notify_tz_delete(tz_id); } EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); @@ -1444,138 +1612,11 @@ } EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); -/** - * thermal_zone_get_cdev_by_name() - search for a cooling device and returns - * its ref. - * @name: thermal cdev name to fetch the temperature - * - * When only one cdev is found with the passed name, returns a reference to it. - * - * Return: On success returns a reference to an unique thermal cooling device - * with matching name equals to @name, an ERR_PTR otherwise (-EINVAL for - * invalid paramenters, -ENODEV for not found and -EEXIST for multiple matches). - */ -struct thermal_cooling_device *thermal_zone_get_cdev_by_name(const char *name) -{ - struct thermal_cooling_device *pos = NULL, *ref = ERR_PTR(-EINVAL); - unsigned int found = 0; - - if (!name) - return ref; - - mutex_lock(&thermal_list_lock); - list_for_each_entry(pos, &thermal_cdev_list, node) - if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) { - found++; - ref = pos; - } - mutex_unlock(&thermal_list_lock); - - /* nothing has been found, thus an error code for it */ - if (found == 0) - return ERR_PTR(-ENODEV); - if (found > 1) - return ERR_PTR(-EEXIST); - return ref; - -} -EXPORT_SYMBOL_GPL(thermal_zone_get_cdev_by_name); - -#ifdef CONFIG_NET -static const struct genl_multicast_group thermal_event_mcgrps[] = { - { .name = THERMAL_GENL_MCAST_GROUP_NAME, }, -}; - -static struct genl_family thermal_event_genl_family __ro_after_init = { - .module = THIS_MODULE, - .name = THERMAL_GENL_FAMILY_NAME, - .version = THERMAL_GENL_VERSION, - .maxattr = THERMAL_GENL_ATTR_MAX, - .mcgrps = thermal_event_mcgrps, - .n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps), -}; - -int thermal_generate_netlink_event(struct thermal_zone_device *tz, - enum events event) -{ - struct sk_buff *skb; - struct nlattr *attr; - struct thermal_genl_event *thermal_event; - void *msg_header; - int size; - int result; - static unsigned int thermal_event_seqnum; - - if (!tz) - return -EINVAL; - - /* allocate memory */ - size = nla_total_size(sizeof(struct thermal_genl_event)) + - nla_total_size(0); - - skb = genlmsg_new(size, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - /* add the genetlink message header */ - msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++, - &thermal_event_genl_family, 0, - THERMAL_GENL_CMD_EVENT); - if (!msg_header) { - nlmsg_free(skb); - return -ENOMEM; - } - - /* fill the data */ - attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, - sizeof(struct thermal_genl_event)); - - if (!attr) { - nlmsg_free(skb); - return -EINVAL; - } - - thermal_event = nla_data(attr); - if (!thermal_event) { - nlmsg_free(skb); - return -EINVAL; - } - - memset(thermal_event, 0, sizeof(struct thermal_genl_event)); - - thermal_event->orig = tz->id; - thermal_event->event = event; - - /* send multicast genetlink message */ - genlmsg_end(skb, msg_header); - - result = genlmsg_multicast(&thermal_event_genl_family, skb, 0, - 0, GFP_ATOMIC); - if (result) - dev_err(&tz->device, "Failed to send netlink event:%d", result); - - return result; -} -EXPORT_SYMBOL_GPL(thermal_generate_netlink_event); - -static int __init genetlink_init(void) -{ - return genl_register_family(&thermal_event_genl_family); -} - -static void genetlink_exit(void) -{ - genl_unregister_family(&thermal_event_genl_family); -} -#else /* !CONFIG_NET */ -static inline int genetlink_init(void) { return 0; } -static inline void genetlink_exit(void) {} -#endif /* !CONFIG_NET */ - static int thermal_pm_notify(struct notifier_block *nb, unsigned long mode, void *_unused) { struct thermal_zone_device *tz; + int irq_wakeable = 0; switch (mode) { case PM_HIBERNATION_PREPARE: @@ -1588,9 +1629,13 @@ case PM_POST_SUSPEND: atomic_set(&in_suspend, 0); list_for_each_entry(tz, &thermal_tz_list, node) { - if (tz->ops && tz->ops->is_wakeable && - tz->ops->is_wakeable(tz)) + if (!thermal_zone_device_is_enabled(tz)) continue; + + trace_android_vh_thermal_pm_notify_suspend(tz, &irq_wakeable); + if (irq_wakeable) + continue; + thermal_zone_device_init(tz); thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); @@ -1610,7 +1655,10 @@ { int result; - mutex_init(&poweroff_lock); + result = thermal_netlink_init(); + if (result) + goto error; + result = thermal_register_governors(); if (result) goto error; @@ -1619,13 +1667,9 @@ if (result) goto unregister_governors; - result = genetlink_init(); - if (result) - goto unregister_class; - result = of_parse_thermal_zones(); if (result) - goto exit_netlink; + goto unregister_class; result = register_pm_notifier(&thermal_pm_nb); if (result) @@ -1634,8 +1678,6 @@ return 0; -exit_netlink: - genetlink_exit(); unregister_class: class_unregister(&thermal_class); unregister_governors: @@ -1648,19 +1690,4 @@ mutex_destroy(&poweroff_lock); return result; } - -static void __exit thermal_exit(void) -{ - unregister_pm_notifier(&thermal_pm_nb); - of_thermal_destroy_zones(); - genetlink_exit(); - class_unregister(&thermal_class); - thermal_unregister_governors(); - ida_destroy(&thermal_tz_ida); - ida_destroy(&thermal_cdev_ida); - mutex_destroy(&thermal_list_lock); - mutex_destroy(&thermal_governor_lock); -} - -fs_initcall(thermal_init); -module_exit(thermal_exit); +postcore_initcall(thermal_init); -- Gitblit v1.6.2