blob: a764d2112a3cf1b548b15b4a0f138d759abade4a [file] [edit]
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
#include "core.h"
#include "debug.h"
static ssize_t ath12k_thermal_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ath12k *ar = dev_get_drvdata(dev);
unsigned long time_left;
int ret, temperature;
guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
if (ar->ah->state != ATH12K_HW_STATE_ON)
return -ENETDOWN;
reinit_completion(&ar->thermal.wmi_sync);
ret = ath12k_wmi_send_pdev_temperature_cmd(ar);
if (ret) {
ath12k_warn(ar->ab, "failed to read temperature %d\n", ret);
return ret;
}
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN;
time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
ATH12K_THERMAL_SYNC_TIMEOUT_HZ);
if (!time_left) {
ath12k_warn(ar->ab, "failed to synchronize thermal read\n");
return -ETIMEDOUT;
}
spin_lock_bh(&ar->data_lock);
temperature = ar->thermal.temperature;
spin_unlock_bh(&ar->data_lock);
/* display in millidegree celsius */
return sysfs_emit(buf, "%d\n", temperature * 1000);
}
void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature)
{
spin_lock_bh(&ar->data_lock);
ar->thermal.temperature = temperature;
spin_unlock_bh(&ar->data_lock);
complete_all(&ar->thermal.wmi_sync);
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, ath12k_thermal_temp, 0);
static struct attribute *ath12k_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(ath12k_hwmon);
int ath12k_thermal_register(struct ath12k_base *ab)
{
struct ath12k *ar;
int i, j, ret;
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
if (!ar)
continue;
ar->thermal.hwmon_dev =
hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev,
"ath12k_hwmon", ar,
ath12k_hwmon_groups);
if (IS_ERR(ar->thermal.hwmon_dev)) {
ret = PTR_ERR(ar->thermal.hwmon_dev);
ar->thermal.hwmon_dev = NULL;
ath12k_err(ar->ab, "failed to register hwmon device: %d\n",
ret);
for (j = i - 1; j >= 0; j--) {
ar = ab->pdevs[j].ar;
if (!ar)
continue;
hwmon_device_unregister(ar->thermal.hwmon_dev);
ar->thermal.hwmon_dev = NULL;
}
return ret;
}
}
return 0;
}
void ath12k_thermal_unregister(struct ath12k_base *ab)
{
struct ath12k *ar;
int i;
if (!IS_REACHABLE(CONFIG_HWMON))
return;
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
if (!ar)
continue;
if (ar->thermal.hwmon_dev) {
hwmon_device_unregister(ar->thermal.hwmon_dev);
ar->thermal.hwmon_dev = NULL;
}
}
}