138 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * fan_attr.c - Create extra attributes for ACPI Fan driver4 *5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>7 * Copyright (C) 2022 Intel Corporation. All rights reserved.8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/init.h>13#include <linux/acpi.h>14 15#include "fan.h"16 17MODULE_LICENSE("GPL");18 19static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)20{21 struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);22 int count;23 24 if (fps->control == 0xFFFFFFFF || fps->control > 100)25 count = scnprintf(buf, PAGE_SIZE, "not-defined:");26 else27 count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);28 29 if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)30 count += sysfs_emit_at(buf, count, "not-defined:");31 else32 count += sysfs_emit_at(buf, count, "%lld:", fps->trip_point);33 34 if (fps->speed == 0xFFFFFFFF)35 count += sysfs_emit_at(buf, count, "not-defined:");36 else37 count += sysfs_emit_at(buf, count, "%lld:", fps->speed);38 39 if (fps->noise_level == 0xFFFFFFFF)40 count += sysfs_emit_at(buf, count, "not-defined:");41 else42 count += sysfs_emit_at(buf, count, "%lld:", fps->noise_level * 100);43 44 if (fps->power == 0xFFFFFFFF)45 count += sysfs_emit_at(buf, count, "not-defined\n");46 else47 count += sysfs_emit_at(buf, count, "%lld\n", fps->power);48 49 return count;50}51 52static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)53{54 struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);55 struct acpi_fan_fst fst;56 int status;57 58 status = acpi_fan_get_fst(acpi_dev, &fst);59 if (status)60 return status;61 62 return sprintf(buf, "%lld\n", fst.speed);63}64 65static ssize_t show_fine_grain_control(struct device *dev, struct device_attribute *attr, char *buf)66{67 struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);68 struct acpi_fan *fan = acpi_driver_data(acpi_dev);69 70 return sprintf(buf, "%d\n", fan->fif.fine_grain_ctrl);71}72 73int acpi_fan_create_attributes(struct acpi_device *device)74{75 struct acpi_fan *fan = acpi_driver_data(device);76 int i, status;77 78 sysfs_attr_init(&fan->fine_grain_control.attr);79 fan->fine_grain_control.show = show_fine_grain_control;80 fan->fine_grain_control.store = NULL;81 fan->fine_grain_control.attr.name = "fine_grain_control";82 fan->fine_grain_control.attr.mode = 0444;83 status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);84 if (status)85 return status;86 87 /* _FST is present if we are here */88 sysfs_attr_init(&fan->fst_speed.attr);89 fan->fst_speed.show = show_fan_speed;90 fan->fst_speed.store = NULL;91 fan->fst_speed.attr.name = "fan_speed_rpm";92 fan->fst_speed.attr.mode = 0444;93 status = sysfs_create_file(&device->dev.kobj, &fan->fst_speed.attr);94 if (status)95 goto rem_fine_grain_attr;96 97 for (i = 0; i < fan->fps_count; ++i) {98 struct acpi_fan_fps *fps = &fan->fps[i];99 100 snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);101 sysfs_attr_init(&fps->dev_attr.attr);102 fps->dev_attr.show = show_state;103 fps->dev_attr.store = NULL;104 fps->dev_attr.attr.name = fps->name;105 fps->dev_attr.attr.mode = 0444;106 status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);107 if (status) {108 int j;109 110 for (j = 0; j < i; ++j)111 sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);112 goto rem_fst_attr;113 }114 }115 116 return 0;117 118rem_fst_attr:119 sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);120 121rem_fine_grain_attr:122 sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);123 124 return status;125}126 127void acpi_fan_delete_attributes(struct acpi_device *device)128{129 struct acpi_fan *fan = acpi_driver_data(device);130 int i;131 132 for (i = 0; i < fan->fps_count; ++i)133 sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);134 135 sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);136 sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);137}138