2 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/device.h>
18 #include <linux/sysfs.h>
19 #include <linux/thermal.h>
20 #include <linux/hwmon.h>
21 #include <linux/hwmon-sysfs.h>
27 ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device
*cdev
,
30 *state
= ATH10K_THERMAL_THROTTLE_MAX
;
36 ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device
*cdev
,
39 struct ath10k
*ar
= cdev
->devdata
;
41 mutex_lock(&ar
->conf_mutex
);
42 *state
= ar
->thermal
.throttle_state
;
43 mutex_unlock(&ar
->conf_mutex
);
49 ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device
*cdev
,
50 unsigned long throttle_state
)
52 struct ath10k
*ar
= cdev
->devdata
;
54 if (throttle_state
> ATH10K_THERMAL_THROTTLE_MAX
) {
55 ath10k_warn(ar
, "throttle state %ld is exceeding the limit %d\n",
56 throttle_state
, ATH10K_THERMAL_THROTTLE_MAX
);
59 mutex_lock(&ar
->conf_mutex
);
60 ar
->thermal
.throttle_state
= throttle_state
;
61 ath10k_thermal_set_throttling(ar
);
62 mutex_unlock(&ar
->conf_mutex
);
66 static const struct thermal_cooling_device_ops ath10k_thermal_ops
= {
67 .get_max_state
= ath10k_thermal_get_max_throttle_state
,
68 .get_cur_state
= ath10k_thermal_get_cur_throttle_state
,
69 .set_cur_state
= ath10k_thermal_set_cur_throttle_state
,
72 static ssize_t
ath10k_thermal_show_temp(struct device
*dev
,
73 struct device_attribute
*attr
,
76 struct ath10k
*ar
= dev_get_drvdata(dev
);
78 unsigned long time_left
;
80 mutex_lock(&ar
->conf_mutex
);
82 /* Can't get temperature when the card is off */
83 if (ar
->state
!= ATH10K_STATE_ON
) {
88 reinit_completion(&ar
->thermal
.wmi_sync
);
89 ret
= ath10k_wmi_pdev_get_temperature(ar
);
91 ath10k_warn(ar
, "failed to read temperature %d\n", ret
);
95 if (test_bit(ATH10K_FLAG_CRASH_FLUSH
, &ar
->dev_flags
)) {
100 time_left
= wait_for_completion_timeout(&ar
->thermal
.wmi_sync
,
101 ATH10K_THERMAL_SYNC_TIMEOUT_HZ
);
103 ath10k_warn(ar
, "failed to synchronize thermal read\n");
108 spin_lock_bh(&ar
->data_lock
);
109 temperature
= ar
->thermal
.temperature
;
110 spin_unlock_bh(&ar
->data_lock
);
112 /* display in millidegree celcius */
113 ret
= snprintf(buf
, PAGE_SIZE
, "%d\n", temperature
* 1000);
115 mutex_unlock(&ar
->conf_mutex
);
119 void ath10k_thermal_event_temperature(struct ath10k
*ar
, int temperature
)
121 spin_lock_bh(&ar
->data_lock
);
122 ar
->thermal
.temperature
= temperature
;
123 spin_unlock_bh(&ar
->data_lock
);
124 complete(&ar
->thermal
.wmi_sync
);
127 static SENSOR_DEVICE_ATTR(temp1_input
, 0444, ath10k_thermal_show_temp
,
130 static struct attribute
*ath10k_hwmon_attrs
[] = {
131 &sensor_dev_attr_temp1_input
.dev_attr
.attr
,
134 ATTRIBUTE_GROUPS(ath10k_hwmon
);
136 void ath10k_thermal_set_throttling(struct ath10k
*ar
)
138 u32 period
, duration
, enabled
;
141 lockdep_assert_held(&ar
->conf_mutex
);
143 if (!ar
->wmi
.ops
->gen_pdev_set_quiet_mode
)
146 if (ar
->state
!= ATH10K_STATE_ON
)
149 period
= ar
->thermal
.quiet_period
;
150 duration
= (period
* ar
->thermal
.throttle_state
) / 100;
151 enabled
= duration
? 1 : 0;
153 ret
= ath10k_wmi_pdev_set_quiet_mode(ar
, period
, duration
,
154 ATH10K_QUIET_START_OFFSET
,
157 ath10k_warn(ar
, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
158 period
, duration
, enabled
, ret
);
162 int ath10k_thermal_register(struct ath10k
*ar
)
164 struct thermal_cooling_device
*cdev
;
165 struct device
*hwmon_dev
;
168 cdev
= thermal_cooling_device_register("ath10k_thermal", ar
,
169 &ath10k_thermal_ops
);
172 ath10k_err(ar
, "failed to setup thermal device result: %ld\n",
177 ret
= sysfs_create_link(&ar
->dev
->kobj
, &cdev
->device
.kobj
,
180 ath10k_err(ar
, "failed to create cooling device symlink\n");
181 goto err_cooling_destroy
;
184 ar
->thermal
.cdev
= cdev
;
185 ar
->thermal
.quiet_period
= ATH10K_QUIET_PERIOD_DEFAULT
;
187 /* Do not register hwmon device when temperature reading is not
188 * supported by firmware
190 if (!(ar
->wmi
.ops
->gen_pdev_get_temperature
))
193 /* Avoid linking error on devm_hwmon_device_register_with_groups, I
194 * guess linux/hwmon.h is missing proper stubs.
196 if (!IS_REACHABLE(CONFIG_HWMON
))
199 hwmon_dev
= devm_hwmon_device_register_with_groups(ar
->dev
,
201 ath10k_hwmon_groups
);
202 if (IS_ERR(hwmon_dev
)) {
203 ath10k_err(ar
, "failed to register hwmon device: %ld\n",
206 goto err_remove_link
;
211 sysfs_remove_link(&ar
->dev
->kobj
, "cooling_device");
213 thermal_cooling_device_unregister(cdev
);
217 void ath10k_thermal_unregister(struct ath10k
*ar
)
219 sysfs_remove_link(&ar
->dev
->kobj
, "cooling_device");
220 thermal_cooling_device_unregister(ar
->thermal
.cdev
);