1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
6 #include <linux/device.h>
7 #include <linux/sysfs.h>
8 #include <linux/thermal.h>
9 #include <linux/hwmon.h>
10 #include <linux/hwmon-sysfs.h>
16 ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device
*cdev
,
19 *state
= ATH10K_THERMAL_THROTTLE_MAX
;
25 ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device
*cdev
,
28 struct ath10k
*ar
= cdev
->devdata
;
30 mutex_lock(&ar
->conf_mutex
);
31 *state
= ar
->thermal
.throttle_state
;
32 mutex_unlock(&ar
->conf_mutex
);
38 ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device
*cdev
,
39 unsigned long throttle_state
)
41 struct ath10k
*ar
= cdev
->devdata
;
43 if (throttle_state
> ATH10K_THERMAL_THROTTLE_MAX
) {
44 ath10k_warn(ar
, "throttle state %ld is exceeding the limit %d\n",
45 throttle_state
, ATH10K_THERMAL_THROTTLE_MAX
);
48 mutex_lock(&ar
->conf_mutex
);
49 ar
->thermal
.throttle_state
= throttle_state
;
50 ath10k_thermal_set_throttling(ar
);
51 mutex_unlock(&ar
->conf_mutex
);
55 static const struct thermal_cooling_device_ops ath10k_thermal_ops
= {
56 .get_max_state
= ath10k_thermal_get_max_throttle_state
,
57 .get_cur_state
= ath10k_thermal_get_cur_throttle_state
,
58 .set_cur_state
= ath10k_thermal_set_cur_throttle_state
,
61 static ssize_t
ath10k_thermal_show_temp(struct device
*dev
,
62 struct device_attribute
*attr
,
65 struct ath10k
*ar
= dev_get_drvdata(dev
);
67 unsigned long time_left
;
69 mutex_lock(&ar
->conf_mutex
);
71 /* Can't get temperature when the card is off */
72 if (ar
->state
!= ATH10K_STATE_ON
) {
77 reinit_completion(&ar
->thermal
.wmi_sync
);
78 ret
= ath10k_wmi_pdev_get_temperature(ar
);
80 ath10k_warn(ar
, "failed to read temperature %d\n", ret
);
84 if (test_bit(ATH10K_FLAG_CRASH_FLUSH
, &ar
->dev_flags
)) {
89 time_left
= wait_for_completion_timeout(&ar
->thermal
.wmi_sync
,
90 ATH10K_THERMAL_SYNC_TIMEOUT_HZ
);
92 ath10k_warn(ar
, "failed to synchronize thermal read\n");
97 spin_lock_bh(&ar
->data_lock
);
98 temperature
= ar
->thermal
.temperature
;
99 spin_unlock_bh(&ar
->data_lock
);
101 /* display in millidegree celcius */
102 ret
= snprintf(buf
, PAGE_SIZE
, "%d\n", temperature
* 1000);
104 mutex_unlock(&ar
->conf_mutex
);
108 void ath10k_thermal_event_temperature(struct ath10k
*ar
, int temperature
)
110 spin_lock_bh(&ar
->data_lock
);
111 ar
->thermal
.temperature
= temperature
;
112 spin_unlock_bh(&ar
->data_lock
);
113 complete(&ar
->thermal
.wmi_sync
);
116 static SENSOR_DEVICE_ATTR(temp1_input
, 0444, ath10k_thermal_show_temp
,
119 static struct attribute
*ath10k_hwmon_attrs
[] = {
120 &sensor_dev_attr_temp1_input
.dev_attr
.attr
,
123 ATTRIBUTE_GROUPS(ath10k_hwmon
);
125 void ath10k_thermal_set_throttling(struct ath10k
*ar
)
127 u32 period
, duration
, enabled
;
130 lockdep_assert_held(&ar
->conf_mutex
);
132 if (!test_bit(WMI_SERVICE_THERM_THROT
, ar
->wmi
.svc_map
))
135 if (!ar
->wmi
.ops
->gen_pdev_set_quiet_mode
)
138 if (ar
->state
!= ATH10K_STATE_ON
)
141 period
= ar
->thermal
.quiet_period
;
142 duration
= (period
* ar
->thermal
.throttle_state
) / 100;
143 enabled
= duration
? 1 : 0;
145 ret
= ath10k_wmi_pdev_set_quiet_mode(ar
, period
, duration
,
146 ATH10K_QUIET_START_OFFSET
,
149 ath10k_warn(ar
, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
150 period
, duration
, enabled
, ret
);
154 int ath10k_thermal_register(struct ath10k
*ar
)
156 struct thermal_cooling_device
*cdev
;
157 struct device
*hwmon_dev
;
160 if (!test_bit(WMI_SERVICE_THERM_THROT
, ar
->wmi
.svc_map
))
163 cdev
= thermal_cooling_device_register("ath10k_thermal", ar
,
164 &ath10k_thermal_ops
);
167 ath10k_err(ar
, "failed to setup thermal device result: %ld\n",
172 ret
= sysfs_create_link(&ar
->dev
->kobj
, &cdev
->device
.kobj
,
175 ath10k_err(ar
, "failed to create cooling device symlink\n");
176 goto err_cooling_destroy
;
179 ar
->thermal
.cdev
= cdev
;
180 ar
->thermal
.quiet_period
= ATH10K_QUIET_PERIOD_DEFAULT
;
182 /* Do not register hwmon device when temperature reading is not
183 * supported by firmware
185 if (!(ar
->wmi
.ops
->gen_pdev_get_temperature
))
188 /* Avoid linking error on devm_hwmon_device_register_with_groups, I
189 * guess linux/hwmon.h is missing proper stubs.
191 if (!IS_REACHABLE(CONFIG_HWMON
))
194 hwmon_dev
= devm_hwmon_device_register_with_groups(ar
->dev
,
196 ath10k_hwmon_groups
);
197 if (IS_ERR(hwmon_dev
)) {
198 ath10k_err(ar
, "failed to register hwmon device: %ld\n",
201 goto err_remove_link
;
206 sysfs_remove_link(&ar
->dev
->kobj
, "cooling_device");
208 thermal_cooling_device_unregister(cdev
);
212 void ath10k_thermal_unregister(struct ath10k
*ar
)
214 if (!test_bit(WMI_SERVICE_THERM_THROT
, ar
->wmi
.svc_map
))
217 sysfs_remove_link(&ar
->dev
->kobj
, "cooling_device");
218 thermal_cooling_device_unregister(ar
->thermal
.cdev
);