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