1*151322bcSMaharaja Kennadyrajan // SPDX-License-Identifier: BSD-3-Clause-Clear 2*151322bcSMaharaja Kennadyrajan /* 3*151322bcSMaharaja Kennadyrajan * Copyright (c) 2020 The Linux Foundation. All rights reserved. 4*151322bcSMaharaja Kennadyrajan * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 5*151322bcSMaharaja Kennadyrajan */ 6*151322bcSMaharaja Kennadyrajan 7*151322bcSMaharaja Kennadyrajan #include <linux/device.h> 8*151322bcSMaharaja Kennadyrajan #include <linux/hwmon.h> 9*151322bcSMaharaja Kennadyrajan #include <linux/hwmon-sysfs.h> 10*151322bcSMaharaja Kennadyrajan #include <linux/sysfs.h> 11*151322bcSMaharaja Kennadyrajan #include <linux/thermal.h> 12*151322bcSMaharaja Kennadyrajan #include "core.h" 13*151322bcSMaharaja Kennadyrajan #include "debug.h" 14*151322bcSMaharaja Kennadyrajan 15*151322bcSMaharaja Kennadyrajan static ssize_t ath12k_thermal_temp_show(struct device *dev, 16*151322bcSMaharaja Kennadyrajan struct device_attribute *attr, 17*151322bcSMaharaja Kennadyrajan char *buf) 18*151322bcSMaharaja Kennadyrajan { 19*151322bcSMaharaja Kennadyrajan struct ath12k *ar = dev_get_drvdata(dev); 20*151322bcSMaharaja Kennadyrajan unsigned long time_left; 21*151322bcSMaharaja Kennadyrajan int ret, temperature; 22*151322bcSMaharaja Kennadyrajan 23*151322bcSMaharaja Kennadyrajan guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy); 24*151322bcSMaharaja Kennadyrajan 25*151322bcSMaharaja Kennadyrajan if (ar->ah->state != ATH12K_HW_STATE_ON) 26*151322bcSMaharaja Kennadyrajan return -ENETDOWN; 27*151322bcSMaharaja Kennadyrajan 28*151322bcSMaharaja Kennadyrajan reinit_completion(&ar->thermal.wmi_sync); 29*151322bcSMaharaja Kennadyrajan ret = ath12k_wmi_send_pdev_temperature_cmd(ar); 30*151322bcSMaharaja Kennadyrajan if (ret) { 31*151322bcSMaharaja Kennadyrajan ath12k_warn(ar->ab, "failed to read temperature %d\n", ret); 32*151322bcSMaharaja Kennadyrajan return ret; 33*151322bcSMaharaja Kennadyrajan } 34*151322bcSMaharaja Kennadyrajan 35*151322bcSMaharaja Kennadyrajan if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) 36*151322bcSMaharaja Kennadyrajan return -ESHUTDOWN; 37*151322bcSMaharaja Kennadyrajan 38*151322bcSMaharaja Kennadyrajan time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync, 39*151322bcSMaharaja Kennadyrajan ATH12K_THERMAL_SYNC_TIMEOUT_HZ); 40*151322bcSMaharaja Kennadyrajan if (!time_left) { 41*151322bcSMaharaja Kennadyrajan ath12k_warn(ar->ab, "failed to synchronize thermal read\n"); 42*151322bcSMaharaja Kennadyrajan return -ETIMEDOUT; 43*151322bcSMaharaja Kennadyrajan } 44*151322bcSMaharaja Kennadyrajan 45*151322bcSMaharaja Kennadyrajan spin_lock_bh(&ar->data_lock); 46*151322bcSMaharaja Kennadyrajan temperature = ar->thermal.temperature; 47*151322bcSMaharaja Kennadyrajan spin_unlock_bh(&ar->data_lock); 48*151322bcSMaharaja Kennadyrajan 49*151322bcSMaharaja Kennadyrajan /* display in millidegree celsius */ 50*151322bcSMaharaja Kennadyrajan return sysfs_emit(buf, "%d\n", temperature * 1000); 51*151322bcSMaharaja Kennadyrajan } 52*151322bcSMaharaja Kennadyrajan 53*151322bcSMaharaja Kennadyrajan void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature) 54*151322bcSMaharaja Kennadyrajan { 55*151322bcSMaharaja Kennadyrajan spin_lock_bh(&ar->data_lock); 56*151322bcSMaharaja Kennadyrajan ar->thermal.temperature = temperature; 57*151322bcSMaharaja Kennadyrajan spin_unlock_bh(&ar->data_lock); 58*151322bcSMaharaja Kennadyrajan complete_all(&ar->thermal.wmi_sync); 59*151322bcSMaharaja Kennadyrajan } 60*151322bcSMaharaja Kennadyrajan 61*151322bcSMaharaja Kennadyrajan static SENSOR_DEVICE_ATTR_RO(temp1_input, ath12k_thermal_temp, 0); 62*151322bcSMaharaja Kennadyrajan 63*151322bcSMaharaja Kennadyrajan static struct attribute *ath12k_hwmon_attrs[] = { 64*151322bcSMaharaja Kennadyrajan &sensor_dev_attr_temp1_input.dev_attr.attr, 65*151322bcSMaharaja Kennadyrajan NULL, 66*151322bcSMaharaja Kennadyrajan }; 67*151322bcSMaharaja Kennadyrajan ATTRIBUTE_GROUPS(ath12k_hwmon); 68*151322bcSMaharaja Kennadyrajan 69*151322bcSMaharaja Kennadyrajan int ath12k_thermal_register(struct ath12k_base *ab) 70*151322bcSMaharaja Kennadyrajan { 71*151322bcSMaharaja Kennadyrajan struct ath12k *ar; 72*151322bcSMaharaja Kennadyrajan int i, j, ret; 73*151322bcSMaharaja Kennadyrajan 74*151322bcSMaharaja Kennadyrajan if (!IS_REACHABLE(CONFIG_HWMON)) 75*151322bcSMaharaja Kennadyrajan return 0; 76*151322bcSMaharaja Kennadyrajan 77*151322bcSMaharaja Kennadyrajan for (i = 0; i < ab->num_radios; i++) { 78*151322bcSMaharaja Kennadyrajan ar = ab->pdevs[i].ar; 79*151322bcSMaharaja Kennadyrajan if (!ar) 80*151322bcSMaharaja Kennadyrajan continue; 81*151322bcSMaharaja Kennadyrajan 82*151322bcSMaharaja Kennadyrajan ar->thermal.hwmon_dev = 83*151322bcSMaharaja Kennadyrajan hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev, 84*151322bcSMaharaja Kennadyrajan "ath12k_hwmon", ar, 85*151322bcSMaharaja Kennadyrajan ath12k_hwmon_groups); 86*151322bcSMaharaja Kennadyrajan if (IS_ERR(ar->thermal.hwmon_dev)) { 87*151322bcSMaharaja Kennadyrajan ret = PTR_ERR(ar->thermal.hwmon_dev); 88*151322bcSMaharaja Kennadyrajan ar->thermal.hwmon_dev = NULL; 89*151322bcSMaharaja Kennadyrajan ath12k_err(ar->ab, "failed to register hwmon device: %d\n", 90*151322bcSMaharaja Kennadyrajan ret); 91*151322bcSMaharaja Kennadyrajan for (j = i - 1; j >= 0; j--) { 92*151322bcSMaharaja Kennadyrajan ar = ab->pdevs[j].ar; 93*151322bcSMaharaja Kennadyrajan if (!ar) 94*151322bcSMaharaja Kennadyrajan continue; 95*151322bcSMaharaja Kennadyrajan 96*151322bcSMaharaja Kennadyrajan hwmon_device_unregister(ar->thermal.hwmon_dev); 97*151322bcSMaharaja Kennadyrajan ar->thermal.hwmon_dev = NULL; 98*151322bcSMaharaja Kennadyrajan } 99*151322bcSMaharaja Kennadyrajan return ret; 100*151322bcSMaharaja Kennadyrajan } 101*151322bcSMaharaja Kennadyrajan } 102*151322bcSMaharaja Kennadyrajan 103*151322bcSMaharaja Kennadyrajan return 0; 104*151322bcSMaharaja Kennadyrajan } 105*151322bcSMaharaja Kennadyrajan 106*151322bcSMaharaja Kennadyrajan void ath12k_thermal_unregister(struct ath12k_base *ab) 107*151322bcSMaharaja Kennadyrajan { 108*151322bcSMaharaja Kennadyrajan struct ath12k *ar; 109*151322bcSMaharaja Kennadyrajan int i; 110*151322bcSMaharaja Kennadyrajan 111*151322bcSMaharaja Kennadyrajan if (!IS_REACHABLE(CONFIG_HWMON)) 112*151322bcSMaharaja Kennadyrajan return; 113*151322bcSMaharaja Kennadyrajan 114*151322bcSMaharaja Kennadyrajan for (i = 0; i < ab->num_radios; i++) { 115*151322bcSMaharaja Kennadyrajan ar = ab->pdevs[i].ar; 116*151322bcSMaharaja Kennadyrajan if (!ar) 117*151322bcSMaharaja Kennadyrajan continue; 118*151322bcSMaharaja Kennadyrajan 119*151322bcSMaharaja Kennadyrajan if (ar->thermal.hwmon_dev) { 120*151322bcSMaharaja Kennadyrajan hwmon_device_unregister(ar->thermal.hwmon_dev); 121*151322bcSMaharaja Kennadyrajan ar->thermal.hwmon_dev = NULL; 122*151322bcSMaharaja Kennadyrajan } 123*151322bcSMaharaja Kennadyrajan } 124*151322bcSMaharaja Kennadyrajan } 125