1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. 4 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 */ 6 7 #include <linux/device.h> 8 #include <linux/sysfs.h> 9 #include <linux/thermal.h> 10 #include <linux/hwmon.h> 11 #include <linux/hwmon-sysfs.h> 12 #include "core.h" 13 #include "debug.h" 14 #include "wmi-ops.h" 15 16 static int 17 ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, 18 unsigned long *state) 19 { 20 *state = ATH10K_THERMAL_THROTTLE_MAX; 21 22 return 0; 23 } 24 25 static int 26 ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, 27 unsigned long *state) 28 { 29 struct ath10k *ar = cdev->devdata; 30 31 mutex_lock(&ar->conf_mutex); 32 *state = ar->thermal.throttle_state; 33 mutex_unlock(&ar->conf_mutex); 34 35 return 0; 36 } 37 38 static int 39 ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, 40 unsigned long throttle_state) 41 { 42 struct ath10k *ar = cdev->devdata; 43 44 if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) { 45 ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n", 46 throttle_state, ATH10K_THERMAL_THROTTLE_MAX); 47 return -EINVAL; 48 } 49 mutex_lock(&ar->conf_mutex); 50 ar->thermal.throttle_state = throttle_state; 51 ath10k_thermal_set_throttling(ar); 52 mutex_unlock(&ar->conf_mutex); 53 return 0; 54 } 55 56 static const struct thermal_cooling_device_ops ath10k_thermal_ops = { 57 .get_max_state = ath10k_thermal_get_max_throttle_state, 58 .get_cur_state = ath10k_thermal_get_cur_throttle_state, 59 .set_cur_state = ath10k_thermal_set_cur_throttle_state, 60 }; 61 62 static ssize_t ath10k_thermal_show_temp(struct device *dev, 63 struct device_attribute *attr, 64 char *buf) 65 { 66 struct ath10k *ar = dev_get_drvdata(dev); 67 int ret, temperature; 68 unsigned long time_left; 69 70 mutex_lock(&ar->conf_mutex); 71 72 /* Can't get temperature when the card is off */ 73 if (ar->state != ATH10K_STATE_ON) { 74 ret = -ENETDOWN; 75 goto out; 76 } 77 78 reinit_completion(&ar->thermal.wmi_sync); 79 ret = ath10k_wmi_pdev_get_temperature(ar); 80 if (ret) { 81 ath10k_warn(ar, "failed to read temperature %d\n", ret); 82 goto out; 83 } 84 85 if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { 86 ret = -ESHUTDOWN; 87 goto out; 88 } 89 90 time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync, 91 ATH10K_THERMAL_SYNC_TIMEOUT_HZ); 92 if (!time_left) { 93 ath10k_warn(ar, "failed to synchronize thermal read\n"); 94 ret = -ETIMEDOUT; 95 goto out; 96 } 97 98 spin_lock_bh(&ar->data_lock); 99 temperature = ar->thermal.temperature; 100 spin_unlock_bh(&ar->data_lock); 101 102 /* display in millidegree celsius */ 103 ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); 104 out: 105 mutex_unlock(&ar->conf_mutex); 106 return ret; 107 } 108 109 void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature) 110 { 111 spin_lock_bh(&ar->data_lock); 112 ar->thermal.temperature = temperature; 113 spin_unlock_bh(&ar->data_lock); 114 complete(&ar->thermal.wmi_sync); 115 } 116 117 static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp, 118 NULL, 0); 119 120 static struct attribute *ath10k_hwmon_attrs[] = { 121 &sensor_dev_attr_temp1_input.dev_attr.attr, 122 NULL, 123 }; 124 ATTRIBUTE_GROUPS(ath10k_hwmon); 125 126 void ath10k_thermal_set_throttling(struct ath10k *ar) 127 { 128 u32 period, duration, enabled; 129 int ret; 130 131 lockdep_assert_held(&ar->conf_mutex); 132 133 if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) 134 return; 135 136 if (!ar->wmi.ops->gen_pdev_set_quiet_mode) 137 return; 138 139 if (ar->state != ATH10K_STATE_ON) 140 return; 141 142 period = ar->thermal.quiet_period; 143 duration = (period * ar->thermal.throttle_state) / 100; 144 enabled = duration ? 1 : 0; 145 146 ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration, 147 ATH10K_QUIET_START_OFFSET, 148 enabled); 149 if (ret) { 150 ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n", 151 period, duration, enabled, ret); 152 } 153 } 154 155 int ath10k_thermal_register(struct ath10k *ar) 156 { 157 struct thermal_cooling_device *cdev; 158 struct device *hwmon_dev; 159 int ret; 160 161 if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) 162 return 0; 163 164 cdev = thermal_cooling_device_register("ath10k_thermal", ar, 165 &ath10k_thermal_ops); 166 167 if (IS_ERR(cdev)) { 168 ath10k_err(ar, "failed to setup thermal device result: %ld\n", 169 PTR_ERR(cdev)); 170 return -EINVAL; 171 } 172 173 ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj, 174 "cooling_device"); 175 if (ret) { 176 ath10k_err(ar, "failed to create cooling device symlink\n"); 177 goto err_cooling_destroy; 178 } 179 180 ar->thermal.cdev = cdev; 181 ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT; 182 183 /* Do not register hwmon device when temperature reading is not 184 * supported by firmware 185 */ 186 if (!(ar->wmi.ops->gen_pdev_get_temperature)) 187 return 0; 188 189 /* Avoid linking error on devm_hwmon_device_register_with_groups, I 190 * guess linux/hwmon.h is missing proper stubs. 191 */ 192 if (!IS_REACHABLE(CONFIG_HWMON)) 193 return 0; 194 195 hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, 196 "ath10k_hwmon", ar, 197 ath10k_hwmon_groups); 198 if (IS_ERR(hwmon_dev)) { 199 ath10k_err(ar, "failed to register hwmon device: %ld\n", 200 PTR_ERR(hwmon_dev)); 201 ret = -EINVAL; 202 goto err_remove_link; 203 } 204 return 0; 205 206 err_remove_link: 207 sysfs_remove_link(&ar->dev->kobj, "cooling_device"); 208 err_cooling_destroy: 209 thermal_cooling_device_unregister(cdev); 210 return ret; 211 } 212 213 void ath10k_thermal_unregister(struct ath10k *ar) 214 { 215 if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) 216 return; 217 218 sysfs_remove_link(&ar->dev->kobj, "cooling_device"); 219 thermal_cooling_device_unregister(ar->thermal.cdev); 220 } 221