// 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 #include #include #include #include #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; } } }