Path: blob/main/sys/contrib/dev/athk/ath10k/thermal.c
48378 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2014-2015 Qualcomm Atheros, Inc.3*/45#include <linux/device.h>6#include <linux/sysfs.h>7#include <linux/thermal.h>8#include <linux/hwmon.h>9#include <linux/hwmon-sysfs.h>10#include "core.h"11#include "debug.h"12#include "wmi-ops.h"1314static int15ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,16unsigned long *state)17{18*state = ATH10K_THERMAL_THROTTLE_MAX;1920return 0;21}2223static int24ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,25unsigned long *state)26{27struct ath10k *ar = cdev->devdata;2829mutex_lock(&ar->conf_mutex);30*state = ar->thermal.throttle_state;31mutex_unlock(&ar->conf_mutex);3233return 0;34}3536static int37ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,38unsigned long throttle_state)39{40struct ath10k *ar = cdev->devdata;4142if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {43ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",44throttle_state, ATH10K_THERMAL_THROTTLE_MAX);45return -EINVAL;46}47mutex_lock(&ar->conf_mutex);48ar->thermal.throttle_state = throttle_state;49ath10k_thermal_set_throttling(ar);50mutex_unlock(&ar->conf_mutex);51return 0;52}5354static const struct thermal_cooling_device_ops ath10k_thermal_ops = {55.get_max_state = ath10k_thermal_get_max_throttle_state,56.get_cur_state = ath10k_thermal_get_cur_throttle_state,57.set_cur_state = ath10k_thermal_set_cur_throttle_state,58};5960static ssize_t ath10k_thermal_show_temp(struct device *dev,61struct device_attribute *attr,62char *buf)63{64struct ath10k *ar = dev_get_drvdata(dev);65int ret, temperature;66unsigned long time_left;6768mutex_lock(&ar->conf_mutex);6970/* Can't get temperature when the card is off */71if (ar->state != ATH10K_STATE_ON) {72ret = -ENETDOWN;73goto out;74}7576reinit_completion(&ar->thermal.wmi_sync);77ret = ath10k_wmi_pdev_get_temperature(ar);78if (ret) {79ath10k_warn(ar, "failed to read temperature %d\n", ret);80goto out;81}8283if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {84ret = -ESHUTDOWN;85goto out;86}8788time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,89ATH10K_THERMAL_SYNC_TIMEOUT_HZ);90if (!time_left) {91ath10k_warn(ar, "failed to synchronize thermal read\n");92ret = -ETIMEDOUT;93goto out;94}9596spin_lock_bh(&ar->data_lock);97temperature = ar->thermal.temperature;98spin_unlock_bh(&ar->data_lock);99100/* display in millidegree celsius */101ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);102out:103mutex_unlock(&ar->conf_mutex);104return ret;105}106107void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)108{109spin_lock_bh(&ar->data_lock);110ar->thermal.temperature = temperature;111spin_unlock_bh(&ar->data_lock);112complete(&ar->thermal.wmi_sync);113}114115static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp,116NULL, 0);117118static struct attribute *ath10k_hwmon_attrs[] = {119&sensor_dev_attr_temp1_input.dev_attr.attr,120NULL,121};122ATTRIBUTE_GROUPS(ath10k_hwmon);123124void ath10k_thermal_set_throttling(struct ath10k *ar)125{126u32 period, duration, enabled;127int ret;128129lockdep_assert_held(&ar->conf_mutex);130131if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))132return;133134if (!ar->wmi.ops->gen_pdev_set_quiet_mode)135return;136137if (ar->state != ATH10K_STATE_ON)138return;139140period = ar->thermal.quiet_period;141duration = (period * ar->thermal.throttle_state) / 100;142enabled = duration ? 1 : 0;143144ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,145ATH10K_QUIET_START_OFFSET,146enabled);147if (ret) {148ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",149period, duration, enabled, ret);150}151}152153int ath10k_thermal_register(struct ath10k *ar)154{155struct thermal_cooling_device *cdev;156struct device *hwmon_dev;157int ret;158159if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))160return 0;161162cdev = thermal_cooling_device_register("ath10k_thermal", ar,163&ath10k_thermal_ops);164165if (IS_ERR(cdev)) {166ath10k_err(ar, "failed to setup thermal device result: %ld\n",167PTR_ERR(cdev));168return -EINVAL;169}170171ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,172"cooling_device");173if (ret) {174ath10k_err(ar, "failed to create cooling device symlink\n");175goto err_cooling_destroy;176}177178ar->thermal.cdev = cdev;179ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;180181/* Do not register hwmon device when temperature reading is not182* supported by firmware183*/184if (!(ar->wmi.ops->gen_pdev_get_temperature))185return 0;186187/* Avoid linking error on devm_hwmon_device_register_with_groups, I188* guess linux/hwmon.h is missing proper stubs.189*/190if (!IS_REACHABLE(CONFIG_HWMON))191return 0;192193hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,194"ath10k_hwmon", ar,195ath10k_hwmon_groups);196if (IS_ERR(hwmon_dev)) {197ath10k_err(ar, "failed to register hwmon device: %ld\n",198PTR_ERR(hwmon_dev));199ret = -EINVAL;200goto err_remove_link;201}202return 0;203204err_remove_link:205sysfs_remove_link(&ar->dev->kobj, "cooling_device");206err_cooling_destroy:207thermal_cooling_device_unregister(cdev);208return ret;209}210211void ath10k_thermal_unregister(struct ath10k *ar)212{213if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))214return;215216sysfs_remove_link(&ar->dev->kobj, "cooling_device");217thermal_cooling_device_unregister(ar->thermal.cdev);218}219220221