^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * A hwmon driver for ACPI 4.0 power meters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2009 IBM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Darrick J. Wong <darrick.wong@oracle.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/hwmon-sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kdev_t.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define ACPI_POWER_METER_NAME "power_meter"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define ACPI_POWER_METER_DEVICE_NAME "Power Meter"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define ACPI_POWER_METER_CLASS "pwr_meter_resource"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define NUM_SENSORS 17
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define POWER_METER_CAN_MEASURE (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define POWER_METER_CAN_TRIP (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define POWER_METER_CAN_CAP (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define POWER_METER_CAN_NOTIFY (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define POWER_METER_IS_BATTERY (1 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define UNKNOWN_HYSTERESIS 0xFFFFFFFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define METER_NOTIFY_CONFIG 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define METER_NOTIFY_TRIP 0x81
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define METER_NOTIFY_CAP 0x82
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define METER_NOTIFY_CAPPING 0x83
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define METER_NOTIFY_INTERVAL 0x84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define POWER_AVERAGE_NAME "power1_average"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define POWER_CAP_NAME "power1_cap"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define POWER_AVG_INTERVAL_NAME "power1_average_interval"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define POWER_ALARM_NAME "power1_alarm"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int cap_in_hardware;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static bool force_cap_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int can_cap_in_hardware(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return force_cap_on || cap_in_hardware;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static const struct acpi_device_id power_meter_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {"ACPI000D", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) MODULE_DEVICE_TABLE(acpi, power_meter_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct acpi_power_meter_capabilities {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u64 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u64 units;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u64 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u64 accuracy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u64 sampling_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u64 min_avg_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u64 max_avg_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u64 hysteresis;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u64 configurable_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u64 min_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u64 max_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct acpi_power_meter_resource {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct acpi_device *acpi_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) acpi_bus_id name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct device *hwmon_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct acpi_power_meter_capabilities caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) acpi_string model_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) acpi_string serial_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) acpi_string oem_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u64 power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u64 cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u64 avg_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int sensors_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long sensors_last_updated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct sensor_device_attribute sensors[NUM_SENSORS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int num_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) s64 trip[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int num_domain_devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct acpi_device **domain_devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct kobject *holders_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct sensor_template {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) char *label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ssize_t (*show)(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) char *buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ssize_t (*set)(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) const char *buf, size_t count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Averaging interval */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int update_avg_interval(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) NULL, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) resource->avg_interval = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static ssize_t show_avg_interval(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) update_avg_interval(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return sprintf(buf, "%llu\n", resource->avg_interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static ssize_t set_avg_interval(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) union acpi_object arg0 = { ACPI_TYPE_INTEGER };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct acpi_object_list args = { 1, &arg0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned long temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) res = kstrtoul(buf, 10, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (temp > resource->caps.max_avg_interval ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) temp < resource->caps.min_avg_interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) arg0.integer.value = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) &args, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) resource->avg_interval = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* _PAI returns 0 on success, nonzero otherwise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /* Cap functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int update_cap(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) NULL, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) resource->cap = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static ssize_t show_cap(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) update_cap(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return sprintf(buf, "%llu\n", resource->cap * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static ssize_t set_cap(struct device *dev, struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) union acpi_object arg0 = { ACPI_TYPE_INTEGER };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct acpi_object_list args = { 1, &arg0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) unsigned long temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) res = kstrtoul(buf, 10, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) temp = DIV_ROUND_CLOSEST(temp, 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (temp > resource->caps.max_cap || temp < resource->caps.min_cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) arg0.integer.value = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) &args, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) resource->cap = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* _SHL returns 0 on success, nonzero otherwise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* Power meter trip points */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int set_acpi_trip(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) union acpi_object arg_objs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {ACPI_TYPE_INTEGER},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {ACPI_TYPE_INTEGER}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct acpi_object_list args = { 2, arg_objs };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Both trip levels must be set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (resource->trip[0] < 0 || resource->trip[1] < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* This driver stores min, max; ACPI wants max, min. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) arg_objs[0].integer.value = resource->trip[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) arg_objs[1].integer.value = resource->trip[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) &args, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* _PTP returns 0 on success, nonzero otherwise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) unsigned long temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) res = kstrtoul(buf, 10, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) temp = DIV_ROUND_CLOSEST(temp, 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) resource->trip[attr->index - 7] = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) res = set_acpi_trip(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Power meter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static int update_meter(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) unsigned long long data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) unsigned long local_jiffies = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (time_before(local_jiffies, resource->sensors_last_updated +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) msecs_to_jiffies(resource->caps.sampling_time)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) resource->sensors_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) NULL, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) resource->power = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) resource->sensors_valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) resource->sensors_last_updated = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static ssize_t show_power(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) update_meter(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return sprintf(buf, "%llu\n", resource->power * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* Miscellaneous */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static ssize_t show_str(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) acpi_string val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) switch (attr->index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) val = resource->model_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) val = resource->serial_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) val = resource->oem_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) WARN(1, "Implementation error: unexpected attribute index %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) attr->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) val = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) ret = sprintf(buf, "%s\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) static ssize_t show_val(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) u64 val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) switch (attr->index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) val = resource->caps.min_avg_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) val = resource->caps.max_avg_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) val = resource->caps.min_cap * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) val = resource->caps.max_cap * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return sprintf(buf, "unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) val = resource->caps.hysteresis * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (resource->caps.flags & POWER_METER_IS_BATTERY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) val = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (resource->power > resource->cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) val = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) case 7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (resource->trip[attr->index - 7] < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return sprintf(buf, "unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) val = resource->trip[attr->index - 7] * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) WARN(1, "Implementation error: unexpected attribute index %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) attr->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return sprintf(buf, "%llu\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static ssize_t show_accuracy(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) struct acpi_device *acpi_dev = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) unsigned int acc = resource->caps.accuracy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static ssize_t show_name(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) #define RO_SENSOR_TEMPLATE(_label, _show, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) .label = _label, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) .show = _show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) .index = _index, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) #define RW_SENSOR_TEMPLATE(_label, _show, _set, _index) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) .label = _label, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .show = _show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) .set = _set, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) .index = _index, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) static struct sensor_template meter_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) set_avg_interval, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static struct sensor_template misc_cap_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static struct sensor_template ro_cap_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static struct sensor_template rw_cap_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static struct sensor_template trip_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static struct sensor_template misc_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) RO_SENSOR_TEMPLATE("name", show_name, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) #undef RO_SENSOR_TEMPLATE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) #undef RW_SENSOR_TEMPLATE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Read power domain data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static void remove_domain_devices(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (!resource->num_domain_devices)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) for (i = 0; i < resource->num_domain_devices; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct acpi_device *obj = resource->domain_devices[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) sysfs_remove_link(resource->holders_dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) kobject_name(&obj->dev.kobj));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) put_device(&obj->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) kfree(resource->domain_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) kobject_put(resource->holders_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) resource->num_domain_devices = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static int read_domain_devices(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) union acpi_object *pss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) pss = buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (!pss ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) pss->type != ACPI_TYPE_PACKAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) "Invalid _PMD data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) res = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (!pss->package.count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) resource->domain_devices = kcalloc(pss->package.count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) sizeof(struct acpi_device *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (!resource->domain_devices) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) res = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) resource->holders_dir = kobject_create_and_add("measures",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) &resource->acpi_dev->dev.kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (!resource->holders_dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) res = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) resource->num_domain_devices = pss->package.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) for (i = 0; i < pss->package.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct acpi_device *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) union acpi_object *element = &(pss->package.elements[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* Refuse non-references */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* Create a symlink to domain objects */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) resource->domain_devices[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (acpi_bus_get_device(element->reference.handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) &resource->domain_devices[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) obj = resource->domain_devices[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) get_device(&obj->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) kobject_name(&obj->dev.kobj));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) put_device(&obj->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) resource->domain_devices[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) exit_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) kfree(resource->domain_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) kfree(buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /* Registration and deregistration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) static int register_attrs(struct acpi_power_meter_resource *resource,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct sensor_template *attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) struct device *dev = &resource->acpi_dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) struct sensor_device_attribute *sensors =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) &resource->sensors[resource->num_sensors];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) while (attrs->label) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) sensors->dev_attr.attr.name = attrs->label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) sensors->dev_attr.attr.mode = 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) sensors->dev_attr.show = attrs->show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) sensors->index = attrs->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (attrs->set) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) sensors->dev_attr.attr.mode |= 0200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) sensors->dev_attr.store = attrs->set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) sysfs_attr_init(&sensors->dev_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) res = device_create_file(dev, &sensors->dev_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) sensors->dev_attr.attr.name = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) sensors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) resource->num_sensors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) attrs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) static void remove_attrs(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) for (i = 0; i < resource->num_sensors; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (!resource->sensors[i].dev_attr.attr.name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) device_remove_file(&resource->acpi_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) &resource->sensors[i].dev_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) remove_domain_devices(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) resource->num_sensors = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) static int setup_attrs(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) res = read_domain_devices(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) res = register_attrs(resource, meter_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if (resource->caps.flags & POWER_METER_CAN_CAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (!can_cap_in_hardware()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) dev_warn(&resource->acpi_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) "Ignoring unsafe software power cap!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) goto skip_unsafe_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (resource->caps.configurable_cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) res = register_attrs(resource, rw_cap_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) res = register_attrs(resource, ro_cap_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) res = register_attrs(resource, misc_cap_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) skip_unsafe_cap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (resource->caps.flags & POWER_METER_CAN_TRIP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) res = register_attrs(resource, trip_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) res = register_attrs(resource, misc_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) remove_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) static void free_capabilities(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) acpi_string *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) str = &resource->model_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) for (i = 0; i < 3; i++, str++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) kfree(*str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) static int read_capabilities(struct acpi_power_meter_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) struct acpi_buffer state = { 0, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) union acpi_object *pss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) acpi_string *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) pss = buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (!pss ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) pss->type != ACPI_TYPE_PACKAGE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) pss->package.count != 14) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) "Invalid _PMC data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) res = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) /* Grab all the integer data at once */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) state.length = sizeof(struct acpi_power_meter_capabilities);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) state.pointer = &resource->caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) status = acpi_extract_package(pss, &format, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) ACPI_EXCEPTION((AE_INFO, status, "Invalid data"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) res = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (resource->caps.units) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) "Unknown units %llu.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) resource->caps.units);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) res = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) /* Grab the string data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) str = &resource->model_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) for (i = 11; i < 14; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) union acpi_object *element = &(pss->package.elements[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) if (element->type != ACPI_TYPE_STRING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) res = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) *str = kcalloc(element->string.length + 1, sizeof(u8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (!*str) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) res = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) strncpy(*str, element->string.pointer, element->string.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) str = &resource->model_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) for (i = 0; i < 3; i++, str++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) kfree(*str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) kfree(buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) /* Handle ACPI event notifications */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) static void acpi_power_meter_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) struct acpi_power_meter_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (!device || !acpi_driver_data(device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) resource = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) case METER_NOTIFY_CONFIG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) mutex_lock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) free_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) res = read_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) mutex_unlock(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) remove_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) setup_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) case METER_NOTIFY_TRIP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) case METER_NOTIFY_CAP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) case METER_NOTIFY_INTERVAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) case METER_NOTIFY_CAPPING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) dev_info(&device->dev, "Capping in progress.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) WARN(1, "Unexpected event %d\n", event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) dev_name(&device->dev), event, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) static int acpi_power_meter_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct acpi_power_meter_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (!device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) resource = kzalloc(sizeof(struct acpi_power_meter_resource),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) if (!resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) resource->sensors_valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) resource->acpi_dev = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) mutex_init(&resource->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) device->driver_data = resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) free_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) res = read_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) resource->trip[0] = resource->trip[1] = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) res = setup_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) goto exit_free_capability;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) resource->hwmon_dev = hwmon_device_register(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (IS_ERR(resource->hwmon_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) res = PTR_ERR(resource->hwmon_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) goto exit_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) exit_remove:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) remove_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) exit_free_capability:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) free_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) exit_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) kfree(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) static int acpi_power_meter_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) struct acpi_power_meter_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) if (!device || !acpi_driver_data(device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) resource = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) hwmon_device_unregister(resource->hwmon_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) remove_attrs(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) free_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) kfree(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) static int acpi_power_meter_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) struct acpi_power_meter_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) resource = acpi_driver_data(to_acpi_device(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (!resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) free_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) read_capabilities(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static struct acpi_driver acpi_power_meter_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .name = "power_meter",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .class = ACPI_POWER_METER_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) .ids = power_meter_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) .add = acpi_power_meter_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) .remove = acpi_power_meter_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) .notify = acpi_power_meter_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) .drv.pm = &acpi_power_meter_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) /* Module init/exit routines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) static int __init enable_cap_knobs(const struct dmi_system_id *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) cap_in_hardware = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static const struct dmi_system_id pm_dmi_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) enable_cap_knobs, "IBM Active Energy Manager",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) DMI_MATCH(DMI_SYS_VENDOR, "IBM")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static int __init acpi_power_meter_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (acpi_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) dmi_check_system(pm_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) result = acpi_bus_register_driver(&acpi_power_meter_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) static void __exit acpi_power_meter_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) acpi_bus_unregister_driver(&acpi_power_meter_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) module_param(force_cap_on, bool, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) module_init(acpi_power_meter_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) module_exit(acpi_power_meter_exit);