Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
0004  */
0005 
0006 #include <linux/device.h>
0007 #include <linux/sysfs.h>
0008 #include <linux/thermal.h>
0009 #include <linux/hwmon.h>
0010 #include <linux/hwmon-sysfs.h>
0011 #include "core.h"
0012 #include "debug.h"
0013 #include "wmi-ops.h"
0014 
0015 static int
0016 ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
0017                       unsigned long *state)
0018 {
0019     *state = ATH10K_THERMAL_THROTTLE_MAX;
0020 
0021     return 0;
0022 }
0023 
0024 static int
0025 ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
0026                       unsigned long *state)
0027 {
0028     struct ath10k *ar = cdev->devdata;
0029 
0030     mutex_lock(&ar->conf_mutex);
0031     *state = ar->thermal.throttle_state;
0032     mutex_unlock(&ar->conf_mutex);
0033 
0034     return 0;
0035 }
0036 
0037 static int
0038 ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
0039                       unsigned long throttle_state)
0040 {
0041     struct ath10k *ar = cdev->devdata;
0042 
0043     if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
0044         ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
0045                 throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
0046         return -EINVAL;
0047     }
0048     mutex_lock(&ar->conf_mutex);
0049     ar->thermal.throttle_state = throttle_state;
0050     ath10k_thermal_set_throttling(ar);
0051     mutex_unlock(&ar->conf_mutex);
0052     return 0;
0053 }
0054 
0055 static const struct thermal_cooling_device_ops ath10k_thermal_ops = {
0056     .get_max_state = ath10k_thermal_get_max_throttle_state,
0057     .get_cur_state = ath10k_thermal_get_cur_throttle_state,
0058     .set_cur_state = ath10k_thermal_set_cur_throttle_state,
0059 };
0060 
0061 static ssize_t ath10k_thermal_show_temp(struct device *dev,
0062                     struct device_attribute *attr,
0063                     char *buf)
0064 {
0065     struct ath10k *ar = dev_get_drvdata(dev);
0066     int ret, temperature;
0067     unsigned long time_left;
0068 
0069     mutex_lock(&ar->conf_mutex);
0070 
0071     /* Can't get temperature when the card is off */
0072     if (ar->state != ATH10K_STATE_ON) {
0073         ret = -ENETDOWN;
0074         goto out;
0075     }
0076 
0077     reinit_completion(&ar->thermal.wmi_sync);
0078     ret = ath10k_wmi_pdev_get_temperature(ar);
0079     if (ret) {
0080         ath10k_warn(ar, "failed to read temperature %d\n", ret);
0081         goto out;
0082     }
0083 
0084     if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
0085         ret = -ESHUTDOWN;
0086         goto out;
0087     }
0088 
0089     time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
0090                         ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
0091     if (!time_left) {
0092         ath10k_warn(ar, "failed to synchronize thermal read\n");
0093         ret = -ETIMEDOUT;
0094         goto out;
0095     }
0096 
0097     spin_lock_bh(&ar->data_lock);
0098     temperature = ar->thermal.temperature;
0099     spin_unlock_bh(&ar->data_lock);
0100 
0101     /* display in millidegree celcius */
0102     ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
0103 out:
0104     mutex_unlock(&ar->conf_mutex);
0105     return ret;
0106 }
0107 
0108 void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
0109 {
0110     spin_lock_bh(&ar->data_lock);
0111     ar->thermal.temperature = temperature;
0112     spin_unlock_bh(&ar->data_lock);
0113     complete(&ar->thermal.wmi_sync);
0114 }
0115 
0116 static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp,
0117               NULL, 0);
0118 
0119 static struct attribute *ath10k_hwmon_attrs[] = {
0120     &sensor_dev_attr_temp1_input.dev_attr.attr,
0121     NULL,
0122 };
0123 ATTRIBUTE_GROUPS(ath10k_hwmon);
0124 
0125 void ath10k_thermal_set_throttling(struct ath10k *ar)
0126 {
0127     u32 period, duration, enabled;
0128     int ret;
0129 
0130     lockdep_assert_held(&ar->conf_mutex);
0131 
0132     if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
0133         return;
0134 
0135     if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
0136         return;
0137 
0138     if (ar->state != ATH10K_STATE_ON)
0139         return;
0140 
0141     period = ar->thermal.quiet_period;
0142     duration = (period * ar->thermal.throttle_state) / 100;
0143     enabled = duration ? 1 : 0;
0144 
0145     ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
0146                          ATH10K_QUIET_START_OFFSET,
0147                          enabled);
0148     if (ret) {
0149         ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
0150                 period, duration, enabled, ret);
0151     }
0152 }
0153 
0154 int ath10k_thermal_register(struct ath10k *ar)
0155 {
0156     struct thermal_cooling_device *cdev;
0157     struct device *hwmon_dev;
0158     int ret;
0159 
0160     if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
0161         return 0;
0162 
0163     cdev = thermal_cooling_device_register("ath10k_thermal", ar,
0164                            &ath10k_thermal_ops);
0165 
0166     if (IS_ERR(cdev)) {
0167         ath10k_err(ar, "failed to setup thermal device result: %ld\n",
0168                PTR_ERR(cdev));
0169         return -EINVAL;
0170     }
0171 
0172     ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
0173                 "cooling_device");
0174     if (ret) {
0175         ath10k_err(ar, "failed to create cooling device symlink\n");
0176         goto err_cooling_destroy;
0177     }
0178 
0179     ar->thermal.cdev = cdev;
0180     ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
0181 
0182     /* Do not register hwmon device when temperature reading is not
0183      * supported by firmware
0184      */
0185     if (!(ar->wmi.ops->gen_pdev_get_temperature))
0186         return 0;
0187 
0188     /* Avoid linking error on devm_hwmon_device_register_with_groups, I
0189      * guess linux/hwmon.h is missing proper stubs.
0190      */
0191     if (!IS_REACHABLE(CONFIG_HWMON))
0192         return 0;
0193 
0194     hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
0195                                "ath10k_hwmon", ar,
0196                                ath10k_hwmon_groups);
0197     if (IS_ERR(hwmon_dev)) {
0198         ath10k_err(ar, "failed to register hwmon device: %ld\n",
0199                PTR_ERR(hwmon_dev));
0200         ret = -EINVAL;
0201         goto err_remove_link;
0202     }
0203     return 0;
0204 
0205 err_remove_link:
0206     sysfs_remove_link(&ar->dev->kobj, "cooling_device");
0207 err_cooling_destroy:
0208     thermal_cooling_device_unregister(cdev);
0209     return ret;
0210 }
0211 
0212 void ath10k_thermal_unregister(struct ath10k *ar)
0213 {
0214     if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
0215         return;
0216 
0217     sysfs_remove_link(&ar->dev->kobj, "cooling_device");
0218     thermal_cooling_device_unregister(ar->thermal.cdev);
0219 }