diff --git a/Kconfig b/Kconfig index 305ab99027..340838fc9a 100644 --- a/Kconfig +++ b/Kconfig @@ -1936,6 +1936,37 @@ config DEBUG_SPI_INFO endif # DEBUG_SPI +config DEBUG_THERMAL + bool "Thermal Debug Features" + default n + ---help--- + Enable thermal debug features. + +if DEBUG_THERMAL + +config DEBUG_THERMAL_ERROR + bool "Thermal Error Output" + default n + depends on DEBUG_ERROR + ---help--- + Enable thermal error output to SYSLOG. + +config DEBUG_THERMAL_WARN + bool "Thermal Warnings Output" + default n + depends on DEBUG_WARN + ---help--- + Enable thermal warning output to SYSLOG. + +config DEBUG_THERMAL_INFO + bool "Thermal Informational Output" + default n + depends on DEBUG_INFO + ---help--- + Enable thermal informational output to SYSLOG. + +endif # DEBUG_THERMAL + config DEBUG_TIMER bool "Timer Debug Features" default n diff --git a/drivers/Kconfig b/drivers/Kconfig index d5e9f18608..751b07052a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,7 @@ source "drivers/rpmsg/Kconfig" source "drivers/rptun/Kconfig" source "drivers/sensors/Kconfig" source "drivers/serial/Kconfig" +source "drivers/thermal/Kconfig" source "drivers/usbdev/Kconfig" source "drivers/usbhost/Kconfig" source "drivers/usbmisc/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 6dbc5563f0..87992a1d62 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -63,6 +63,7 @@ include sensors/Make.defs include serial/Make.defs include spi/Make.defs include syslog/Make.defs +include thermal/Make.defs include timers/Make.defs include usbdev/Make.defs include usbhost/Make.defs diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index 0be8a0519e..8431d0c6c5 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -271,5 +272,9 @@ void drivers_initialize(void) optee_register(); #endif +#ifdef CONFIG_THERMAL + thermal_init(); +#endif + drivers_trace_end(); } diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig new file mode 100644 index 0000000000..568c762edd --- /dev/null +++ b/drivers/thermal/Kconfig @@ -0,0 +1,20 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig THERMAL + bool "Thermal framework" + default n + ---help--- + Enable thermal framework. + +if THERMAL + +config THERMAL_DEFAULT_GOVERNOR + string "Thermal default governor name" + default "step_wise" + ---help--- + Default governor name. + +endif # THERMAL diff --git a/drivers/thermal/Make.defs b/drivers/thermal/Make.defs new file mode 100644 index 0000000000..20c8c4f054 --- /dev/null +++ b/drivers/thermal/Make.defs @@ -0,0 +1,30 @@ +############################################################################ +# drivers/thermal/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +# Include thermal sources + +ifeq ($(CONFIG_THERMAL),y) + +CSRCS += thermal_core.c + +DEPPATH += --dep-path thermal +VPATH += thermal + +endif diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c new file mode 100644 index 0000000000..a7de5fc86c --- /dev/null +++ b/drivers/thermal/thermal_core.c @@ -0,0 +1,843 @@ +/**************************************************************************** + * drivers/thermal/thermal_core.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "thermal_core.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int zone_bind_cooling (FAR struct thermal_zone_device_s *zdev, + int trip, + FAR struct thermal_cooling_device_s *cdev, + unsigned int upper, unsigned int lower, + unsigned int weight); +static void zone_unbind_cooling(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR struct thermal_cooling_device_s *cdev); + +static FAR struct thermal_governor_s * +find_governor_by_name (FAR const char *name); +static int zone_set_governor (FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_governor_s *gov); + +static void device_bind (FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_cooling_device_s *cdev); +static void device_unbind (FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_cooling_device_s *cdev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct list_node +g_cooling_dev_list = LIST_INITIAL_VALUE(g_cooling_dev_list); + +static struct list_node +g_governor_list = LIST_INITIAL_VALUE(g_governor_list); + +static struct list_node +g_zone_dev_list = LIST_INITIAL_VALUE(g_zone_dev_list); + +static mutex_t g_thermal_lock = NXMUTEX_INITIALIZER; + +static FAR struct thermal_governor_s *g_def_governor = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int zone_set_governor(FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_governor_s *gov) +{ + int ret = OK; + + /* The caller must use `g_thermal_lock` to protect zones and governors */ + + if (zdev->governor && zdev->governor->unbind_from_tz) + { + zdev->governor->unbind_from_tz(zdev); + } + + if (gov && gov->bind_to_tz) + { + ret = gov->bind_to_tz(zdev); + if (ret < 0) + { + if (zdev->governor->bind_to_tz(zdev) < 0) + { + zdev->governor = NULL; + } + + return ret; + } + } + + zdev->governor = gov; + return ret; +} + +static int zone_bind_cooling(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR struct thermal_cooling_device_s *cdev, + unsigned int upper, unsigned int lower, + unsigned int weight) +{ + FAR struct thermal_instance_s *ins; + FAR struct thermal_instance_s *pos; + unsigned int max_state; + int ret; + + ret = cdev->ops->get_max_state(cdev, &max_state); + if (ret < 0) + { + therr("Get max state failed!\n"); + return ret; + } + + list_for_every_entry(&zdev->instance_list, pos, + struct thermal_instance_s, zdev_node) + { + if (zdev == pos->zdev && cdev == pos->cdev && trip == pos->trip) + { + thwarn("Instance %s %s %d already exist!", + zdev->name, cdev->name, trip); + return -EEXIST; + } + } + + ins = kmm_malloc(sizeof(struct thermal_instance_s)); + if (!ins) + { + return -ENOMEM; + } + + ins->zdev = zdev; + ins->cdev = cdev; + ins->trip = trip; + ins->target = THERMAL_NO_TARGET; + + if (lower == THERMAL_NO_LIMIT) + { + ins->lower = 0; + } + else + { + ins->lower = lower; + } + + if (upper == THERMAL_NO_LIMIT) + { + ins->upper = max_state; + } + else + { + ins->upper = upper; + } + + ins->weight = weight; + + thinfo("Adding instance zdev:%-4s cdev:%-4s h:%2u l:%2u t:%d\n", + zdev->name, cdev->name, ins->upper, ins->lower, ins->trip); + + list_add_tail(&zdev->instance_list, &ins->zdev_node); + list_add_tail(&cdev->instance_list, &ins->cdev_node); + return OK; +} + +static void zone_unbind_cooling(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR struct thermal_cooling_device_s *cdev) +{ + FAR struct thermal_instance_s *ins; + + list_for_every_entry(&zdev->instance_list, ins, + struct thermal_instance_s, zdev_node) + { + if (zdev == ins->zdev && cdev == ins->cdev && trip == ins->trip) + { + list_delete(&ins->zdev_node); + list_delete(&ins->cdev_node); + + kmm_free(ins); + break; + } + } +} + +static void device_bind(FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_cooling_device_s *cdev) +{ + FAR const struct thermal_zone_map_s *map; + FAR const struct thermal_zone_trip_s *trip; + int ret; + int i; + int j; + + for (i = 0; i < zdev->params->num_maps; i++) + { + map = &zdev->params->maps[i]; + + if (strcmp(map->cdev_name, cdev->name)) + { + continue; + } + + for (j = 0; j < zdev->params->num_trips; j++) + { + trip = &zdev->params->trips[j]; + if (strcmp(map->trip_name, trip->name)) + { + continue; + } + + ret = zone_bind_cooling(zdev, j, cdev, map->high, map->low, + map->weight); + if (ret < 0) + { + therr("Failed to bind %s and %s, trip %d\n", + zdev->name, cdev->name, j); + } + } + } +} + +static void device_unbind(FAR struct thermal_zone_device_s *zdev, + FAR struct thermal_cooling_device_s *cdev) +{ + int i; + + for (i = 0; i < zdev->params->num_trips; i++) + { + zone_unbind_cooling(zdev, i, cdev); + } +} + +static FAR struct thermal_governor_s * +find_governor_by_name(FAR const char *name) +{ + FAR struct thermal_governor_s *gov; + + if (!name) + { + return NULL; + } + + /* The caller must use `g_thermal_lock` to protect governors */ + + list_for_every_entry(&g_governor_list, gov, struct thermal_governor_s, + node) + { + if (!strcmp(gov->name, name)) + { + return gov; + } + } + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int thermal_zone_enable(FAR struct thermal_zone_device_s *zdev, + bool enabled) +{ + nxmutex_lock(&g_thermal_lock); + + if (enabled == zdev->enabled) + { + nxmutex_unlock(&g_thermal_lock); + return OK; + } + + zdev->enabled = enabled; + work_cancel_sync(LPWORK, &zdev->monitor); + + nxmutex_unlock(&g_thermal_lock); + + thermal_zone_device_update(zdev); + return OK; +} + +int thermal_zone_get_trend(FAR struct thermal_zone_device_s *zdev) +{ + enum thermal_trend_e trend; + + if (zdev->ops->get_trend) + { + if (!zdev->ops->get_trend(zdev, &trend)) + { + return trend; + } + } + + if (zdev->last_temperature == THERMAL_INVALID_TEMP || + zdev->temperature == THERMAL_INVALID_TEMP) + { + trend = THERMAL_TREND_STABLE; + } + else if (zdev->last_temperature > zdev->temperature) + { + trend = THERMAL_TREND_DROPPING; + } + else if (zdev->last_temperature < zdev->temperature) + { + trend = THERMAL_TREND_RAISING; + } + else + { + trend = THERMAL_TREND_STABLE; + } + + return trend; +} + +int thermal_zone_get_trip_temp(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR int *temp) +{ + if (!temp || trip >= zdev->params->num_trips) + { + return -EINVAL; + } + + *temp = zdev->params->trips[trip].temp; + return OK; +} + +int thermal_zone_get_trip_type(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR enum thermal_trip_type_e *type) +{ + if (!type || trip >= zdev->params->num_trips) + { + return -EINVAL; + } + + *type = zdev->params->trips[trip].type; + return OK; +} + +int thermal_zone_get_trip_hyst(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR int *hyst) +{ + if (!hyst || trip >= zdev->params->num_trips) + { + return -EINVAL; + } + + *hyst = zdev->params->trips[trip].hyst; + return OK; +} + +/**************************************************************************** + * Name: thermal_register_governor + * + * Description: + * Register governor + * + * Input Parameters: + * gov - the struct thermal_governor_s addr + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + ****************************************************************************/ + +int thermal_register_governor(FAR struct thermal_governor_s *gov) +{ + FAR struct thermal_governor_s *pos; + + if (!gov || !gov->throttle) + { + therr("Invalid governor!\n"); + return -EINVAL; + } + + nxmutex_lock(&g_thermal_lock); + + list_for_every_entry(&g_governor_list, pos, + struct thermal_governor_s, node) + { + if (!strcmp(gov->name, pos->name)) + { + thwarn("Governor (%s) already exists!", gov->name); + nxmutex_unlock(&g_thermal_lock); + return -EEXIST; + } + } + + list_add_tail(&g_governor_list, &gov->node); + + thinfo("Register governor %s\n", gov->name); + + /* Default governor */ + + if (!strcmp(gov->name, CONFIG_THERMAL_DEFAULT_GOVERNOR)) + { + g_def_governor = gov; + thinfo("Default governor %s registered!\n", g_def_governor->name); + } + + nxmutex_unlock(&g_thermal_lock); + return OK; +} + +/**************************************************************************** + * Name: thermal_unregister_governor + * + * Description: + * Unregister governor + * + * Input Parameters: + * gov - the struct thermal_governor_s addr + * + * Returned Value: + * None + ****************************************************************************/ + +void thermal_unregister_governor(FAR struct thermal_governor_s *gov) +{ + FAR struct thermal_zone_device_s *zdev; + + if (!gov) + { + return; + } + + nxmutex_lock(&g_thermal_lock); + + list_for_every_entry(&g_zone_dev_list, zdev, + struct thermal_zone_device_s, node) + { + if (zdev->governor == gov) + { + zone_set_governor(zdev, NULL); + } + } + + list_delete(&gov->node); + nxmutex_unlock(&g_thermal_lock); +} + +/**************************************************************************** + * Name: thermal_cooling_device_register + * + * Description: + * Register thermal cooling device. + * + * Input Parameters: + * name - Name of cooling device + * devdata - Device driver data + * ops - Operations + * + * Returned Value: + * Addr of created cooling device entry. + ****************************************************************************/ + +FAR struct thermal_cooling_device_s * +thermal_cooling_device_register(FAR const char *name, void *devdata, + FAR const struct thermal_cooling_device_ops_s *ops) +{ + FAR struct thermal_zone_device_s *zdev; + FAR struct thermal_cooling_device_s *cdev; + + nxmutex_lock(&g_thermal_lock); + + list_for_every_entry(&g_cooling_dev_list, cdev, + struct thermal_cooling_device_s, node) + { + if (!strcmp(cdev->name, name)) + { + thwarn("Cooling device (%s) already exists!", name); + nxmutex_unlock(&g_thermal_lock); + return NULL; + } + } + + cdev = kmm_zalloc(sizeof(*cdev)); + if (!cdev) + { + therr("Cannot allocate memory for cooling device registering!\n"); + nxmutex_unlock(&g_thermal_lock); + return NULL; + } + + strlcpy(cdev->name, name, THERMAL_NAME_LEN); + cdev->ops = ops; + cdev->devdata = devdata; + + list_initialize(&cdev->instance_list); + list_add_tail(&g_cooling_dev_list, &cdev->node); + + list_for_every_entry(&g_zone_dev_list, zdev, + struct thermal_zone_device_s, node) + { + device_bind(zdev, cdev); + } + + thinfo("Registered cooling device %s\n", cdev->name); + nxmutex_unlock(&g_thermal_lock); + + return cdev; +} + +/**************************************************************************** + * Name: thermal_cooling_device_unregister + * + * Description: + * Unregister thermal cooling device. + * + * Input Parameters: + * cdev - Cooling Device + * + * Returned Value: + * None + ****************************************************************************/ + +void +thermal_cooling_device_unregister(FAR struct thermal_cooling_device_s *cdev) +{ + FAR struct thermal_zone_device_s *zdev; + + /* Unbind */ + + nxmutex_lock(&g_thermal_lock); + + list_delete(&cdev->node); + + list_for_every_entry(&g_zone_dev_list, zdev, + struct thermal_zone_device_s, node) + { + device_unbind(zdev, cdev); + } + + kmm_free(cdev); + nxmutex_unlock(&g_thermal_lock); +} + +/**************************************************************************** + * Name: thermal_cooling_device_update + * + * Description: + * Update thermal cooling device. + * + * Input Parameters: + * cdev - Cooling Device. + * + * Returned Value: + * None + ****************************************************************************/ + +void thermal_cooling_device_update(FAR struct thermal_cooling_device_s *cdev) +{ + FAR struct thermal_instance_s *instance; + unsigned int target = THERMAL_NO_TARGET; + unsigned int current = THERMAL_NO_TARGET; + int ret; + + ret = cdev->ops->get_state(cdev, ¤t); + if (ret < 0) + { + thwarn("Thermal get cooling state failed!\n"); + return; + } + + list_for_every_entry(&cdev->instance_list, instance, + struct thermal_instance_s, cdev_node) + { + if ((instance->target != THERMAL_NO_TARGET) && + (instance->target > target || + target == THERMAL_NO_TARGET)) + { + target = instance->target; + } + } + + if (target != THERMAL_NO_TARGET && target != current) + { + ret = cdev->ops->set_state(cdev, target); + if (ret < 0) + { + thwarn("Thermal set cooling state of %s failed!\n", cdev->name); + } + } +} + +/**************************************************************************** + * Name: thermal_zone_device_register + * + * Description: + * Register thermal zone device. + * + * Input Parameters: + * name - Name of zone. + * devdata - Device driver data. + * ops - Operations of zone deivce. + * params - Parameter of zone device. + * + * Returned Value: + * Addr of created zone device entry. + ****************************************************************************/ + +struct thermal_zone_device_s * +thermal_zone_device_register(FAR const char *name, + FAR void *devdata, + FAR const struct thermal_zone_device_ops_s *ops, + FAR const struct thermal_zone_params_s *params) +{ + FAR struct thermal_cooling_device_s *cdev; + FAR struct thermal_governor_s *gov; + FAR struct thermal_zone_device_s *pos; + FAR struct thermal_zone_device_s *zdev; + + if (!ops || !ops->get_temp) + { + therr("Invalid zone operations!\n"); + return NULL; + } + + nxmutex_lock(&g_thermal_lock); + + list_for_every_entry(&g_zone_dev_list, pos, + struct thermal_zone_device_s, node) + { + if (!strcmp(name, pos->name)) + { + thwarn("Zone device (%s) already exists!", name); + nxmutex_unlock(&g_thermal_lock); + return NULL; + } + } + + zdev = kmm_zalloc(sizeof(struct thermal_zone_device_s)); + if (!zdev) + { + nxmutex_unlock(&g_thermal_lock); + return NULL; + } + + zdev->ops = ops; + zdev->devdata = devdata; + zdev->enabled = true; + + strlcpy(zdev->name, name, THERMAL_NAME_LEN); + + zdev->params = params; + zdev->temperature = THERMAL_INVALID_TEMP; + + list_initialize(&zdev->instance_list); + + /* Set governor */ + + gov = find_governor_by_name(zdev->params->gov_name); + zone_set_governor(zdev, gov ? gov : g_def_governor); + + thinfo("Set governor of zone %s to %s.\n", zdev->name, + zdev->governor ? zdev->governor->name : ""); + + list_add_tail(&g_zone_dev_list, &zdev->node); + + list_for_every_entry(&g_cooling_dev_list, cdev, + struct thermal_cooling_device_s, node) + { + device_bind(zdev, cdev); + } + + nxmutex_unlock(&g_thermal_lock); + + thinfo("Registered zone device %s\n", zdev->name); + thermal_zone_device_update(zdev); + return zdev; +} + +/**************************************************************************** + * Name: thermal_zone_device_unregister + * + * Description: + * Unregister thermal zone device. + * + * Input Parameters: + * zdev - Zone Device + * + * Returned Value: + * None + ****************************************************************************/ + +void thermal_zone_device_unregister(FAR struct thermal_zone_device_s *zdev) +{ + FAR struct thermal_cooling_device_s *cdev; + + /* Disable Zone */ + + thermal_zone_enable(zdev, false); + + /* Unbind */ + + nxmutex_lock(&g_thermal_lock); + + list_for_every_entry(&g_cooling_dev_list, cdev, + struct thermal_cooling_device_s, node) + { + device_unbind(zdev, cdev); + } + + list_delete(&zdev->node); + zone_set_governor(zdev, NULL); + kmm_free(zdev); + nxmutex_unlock(&g_thermal_lock); +} + +/**************************************************************************** + * Name: thermal_zone_device_update + * + * Description: + * Update thermal zone device. + * Get temperature from sensor and throttle if necessary. + * + * Input Parameters: + * zdev - Zone Device + * + * Returned Value: + * None + ****************************************************************************/ + +void thermal_zone_device_update(FAR struct thermal_zone_device_s *zdev) +{ + int trip_high = INT_MAX; + int trip_low = INT_MIN; + int trip; + int temp; + int ret; + + nxmutex_lock(&g_thermal_lock); + + /* Update termerature */ + + if (!zdev->enabled) + { + goto unlock; + } + + ret = zdev->ops->get_temp(zdev, &temp); + if (ret < 0) + { + therr("Failed to get temperature from zone %s \n", zdev->name); + goto unlock; + } + + zdev->last_temperature = zdev->temperature; + zdev->temperature = temp; + + for (trip = 0; trip < zdev->params->num_trips; trip++) + { + enum thermal_trip_type_e type; + int temp_low; + int hyst; + + thermal_zone_get_trip_temp(zdev, trip, &temp); + thermal_zone_get_trip_hyst(zdev, trip, &hyst); + thermal_zone_get_trip_type(zdev, trip, &type); + + if (zdev->temperature < temp && trip_high > temp) + { + trip_high = temp; + } + + temp_low = temp - hyst; + + if (zdev->temperature > temp_low && trip_low < temp_low) + { + trip_low = temp_low; + } + + /* Critical */ + + if (type == THERMAL_CRITICAL && zdev->temperature >= temp) + { + therr("Thermal critical (%d), resetting...\n", zdev->temperature); +#ifdef CONFIG_BOARDCTL_RESET + boardctl(BOARDIOC_RESET, BOARDIOC_SOFTRESETCAUSE_THERMAL); +#endif + } + else if (zdev->governor) + { + zdev->governor->throttle(zdev, trip); + } + else if(g_def_governor) + { + g_def_governor->throttle(zdev, trip); + } + else + { + therr("No valid governor!\n"); + } + } + + if (zdev->ops->set_trips) + { + ret = zdev->ops->set_trips(zdev, trip_low, trip_high); + if (ret < 0) + { + thwarn("Set trip points (l:%d, h:%d) for %s failed\n", + trip_low, trip_high, zdev->name); + } + } + + work_queue(LPWORK, &zdev->monitor, (worker_t)thermal_zone_device_update, + zdev, zdev->params->polling_delay); + +unlock: + nxmutex_unlock(&g_thermal_lock); +} + +/**************************************************************************** + * Name: thermal_init + * + * Description: + * Init thermal framework + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + ****************************************************************************/ + +int thermal_init(void) +{ + int ret = OK; + + return ret; +} diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h new file mode 100644 index 0000000000..3ea97df9db --- /dev/null +++ b/drivers/thermal/thermal_core.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * drivers/thermal/thermal_core.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_THERMAL_THERMAL_CORE_H +#define __DRIVERS_THERMAL_THERMAL_CORE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + + #include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct thermal_instance_s +{ + FAR struct thermal_cooling_device_s *cdev; + FAR struct thermal_zone_device_s *zdev; + + int trip; + + /* Cooling State */ + + unsigned int target; /* Expected Cooling State */ + unsigned int upper; /* The Maximum cooling state for this trip point */ + unsigned int lower; /* Minimum cooling state */ + unsigned int weight; + + struct list_node cdev_node; + struct list_node zdev_node; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Cooling Device */ + +void +thermal_cooling_device_update (FAR struct thermal_cooling_device_s *cdev); + +/* Zone Device */ + +int thermal_zone_enable (FAR struct thermal_zone_device_s *zdev, + bool enabled); +int thermal_zone_get_trend (FAR struct thermal_zone_device_s *zdev); +int thermal_zone_get_trip_temp(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR int *temp); +int thermal_zone_get_trip_type(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR enum thermal_trip_type_e *type); +int thermal_zone_get_trip_hyst(FAR struct thermal_zone_device_s *zdev, + int trip, + FAR int *hyst); + +#endif /* __DRIVERS_THERMAL_THERMAL_CORE_H */ diff --git a/include/debug.h b/include/debug.h index 418ecc6fb6..bfe42a199e 100644 --- a/include/debug.h +++ b/include/debug.h @@ -758,6 +758,24 @@ # define spiinfo _none #endif +#ifdef CONFIG_DEBUG_THERMAL_ERROR +# define therr _err +#else +# define therr _none +#endif + +#ifdef CONFIG_DEBUG_THERMAL_WARN +# define thwarn _warn +#else +# define thwarn _none +#endif + +#ifdef CONFIG_DEBUG_THERMAL_INFO +# define thinfo _info +#else +# define thinfo _none +#endif + #ifdef CONFIG_DEBUG_TIMER_ERROR # define tmrerr _err #else diff --git a/include/nuttx/thermal.h b/include/nuttx/thermal.h new file mode 100644 index 0000000000..53a7c668a2 --- /dev/null +++ b/include/nuttx/thermal.h @@ -0,0 +1,205 @@ +/**************************************************************************** + * include/nuttx/thermal.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_THERMAL_H +#define __INCLUDE_NUTTX_THERMAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Generic */ + +#define THERMAL_NAME_LEN 32 + +/* Trips */ + +#define THERMAL_NO_LIMIT 0 + +/* Temperature */ + +#define THERMAL_INVALID_TEMP INT_MIN + +/* Cooling State */ + +#define THERMAL_TARGET_MIN 0 +#define THERMAL_TARGET_MAX (UINT_MAX - 1) +#define THERMAL_NO_TARGET UINT_MAX + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct thermal_cooling_device_ops_s; +struct thermal_zone_device_ops_s; +struct thermal_zone_device_s; +struct thermal_zone_params_s; + +enum thermal_trend_e +{ + THERMAL_TREND_RAISING, + THERMAL_TREND_DROPPING, + THERMAL_TREND_STABLE, +}; + +enum thermal_trip_type_e +{ + THERMAL_COLD, + THERMAL_NORMAL, + THERMAL_HOT, + THERMAL_CRITICAL, +}; + +struct thermal_governor_s +{ + struct list_node node; + + FAR const char *name; + + CODE int (*bind_to_tz) (FAR struct thermal_zone_device_s *zdev); + CODE int (*throttle) (FAR struct thermal_zone_device_s *zdev, + int trip); + CODE void (*unbind_from_tz)(FAR struct thermal_zone_device_s *zdev); +}; + +struct thermal_cooling_device_s +{ + struct list_node node; + + char name[THERMAL_NAME_LEN]; + FAR void *devdata; + FAR const struct thermal_cooling_device_ops_s *ops; + + struct list_node instance_list; +}; + +struct thermal_zone_device_s +{ + struct list_node node; + + char name[THERMAL_NAME_LEN]; + bool enabled; + + FAR void *devdata; + + int last_temperature; + int temperature; + + FAR const struct thermal_zone_device_ops_s *ops; + FAR struct thermal_governor_s *governor; + + FAR const struct thermal_zone_params_s *params; + struct work_s monitor; + + struct list_node instance_list; +}; + +struct thermal_cooling_device_ops_s +{ + CODE int (*set_state) (FAR struct thermal_cooling_device_s *cdev, + unsigned int state); + CODE int (*get_state) (FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state); + CODE int (*get_max_state)(FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state); +}; + +struct thermal_zone_device_ops_s +{ + CODE int (*get_temp) (FAR struct thermal_zone_device_s *zdev, + FAR int *temp); + CODE int (*get_trend) (FAR struct thermal_zone_device_s *zdev, + FAR enum thermal_trend_e *trend); + CODE int (*set_trips) (FAR struct thermal_zone_device_s *zdev, + int low, int high); +}; + +struct thermal_zone_map_s +{ + FAR const char *trip_name; + + FAR const char *cdev_name; + unsigned int low; + unsigned int high; + + unsigned int weight; +}; + +struct thermal_zone_trip_s +{ + FAR const char *name; + unsigned int temp; + unsigned int hyst; + enum thermal_trip_type_e type; +}; + +struct thermal_zone_params_s +{ + FAR const char *gov_name; + int polling_delay; + FAR const struct thermal_zone_trip_s *trips; + int num_trips; + FAR const struct thermal_zone_map_s *maps; + int num_maps; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Governor */ + +int thermal_register_governor (FAR struct thermal_governor_s *gov); +void thermal_unregister_governor(FAR struct thermal_governor_s *gov); + +/* Cooling Device */ + +FAR struct thermal_cooling_device_s * +thermal_cooling_device_register(FAR const char *name, void *devdata, + FAR const struct thermal_cooling_device_ops_s *ops); +void +thermal_cooling_device_unregister( + FAR struct thermal_cooling_device_s *cdev); + +/* Zone Device */ + +FAR struct thermal_zone_device_s * +thermal_zone_device_register(FAR const char *name, FAR void *devdata, + FAR const struct thermal_zone_device_ops_s *ops, + FAR const struct thermal_zone_params_s *params); +void +thermal_zone_device_unregister( + FAR struct thermal_zone_device_s *zdev); +void +thermal_zone_device_update (FAR struct thermal_zone_device_s *zdev); + +/* Thermal Framework initialization */ + +int thermal_init(void); + +#endif /* __INCLUDE_NUTTX_THERMAL_H */