1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * fan_attr.c - Create extra attributes for ACPI Fan driver
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.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/acpi.h>
17 MODULE_LICENSE("GPL");
19 static ssize_t
show_state(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
21 struct acpi_fan_fps
*fps
= container_of(attr
, struct acpi_fan_fps
, dev_attr
);
24 if (fps
->control
== 0xFFFFFFFF || fps
->control
> 100)
25 count
= scnprintf(buf
, PAGE_SIZE
, "not-defined:");
27 count
= scnprintf(buf
, PAGE_SIZE
, "%lld:", fps
->control
);
29 if (fps
->trip_point
== 0xFFFFFFFF || fps
->trip_point
> 9)
30 count
+= sysfs_emit_at(buf
, count
, "not-defined:");
32 count
+= sysfs_emit_at(buf
, count
, "%lld:", fps
->trip_point
);
34 if (fps
->speed
== 0xFFFFFFFF)
35 count
+= sysfs_emit_at(buf
, count
, "not-defined:");
37 count
+= sysfs_emit_at(buf
, count
, "%lld:", fps
->speed
);
39 if (fps
->noise_level
== 0xFFFFFFFF)
40 count
+= sysfs_emit_at(buf
, count
, "not-defined:");
42 count
+= sysfs_emit_at(buf
, count
, "%lld:", fps
->noise_level
* 100);
44 if (fps
->power
== 0xFFFFFFFF)
45 count
+= sysfs_emit_at(buf
, count
, "not-defined\n");
47 count
+= sysfs_emit_at(buf
, count
, "%lld\n", fps
->power
);
52 static ssize_t
show_fan_speed(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
54 struct acpi_device
*acpi_dev
= container_of(dev
, struct acpi_device
, dev
);
55 struct acpi_fan_fst fst
;
58 status
= acpi_fan_get_fst(acpi_dev
, &fst
);
62 return sprintf(buf
, "%lld\n", fst
.speed
);
65 static ssize_t
show_fine_grain_control(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
67 struct acpi_device
*acpi_dev
= container_of(dev
, struct acpi_device
, dev
);
68 struct acpi_fan
*fan
= acpi_driver_data(acpi_dev
);
70 return sprintf(buf
, "%d\n", fan
->fif
.fine_grain_ctrl
);
73 int acpi_fan_create_attributes(struct acpi_device
*device
)
75 struct acpi_fan
*fan
= acpi_driver_data(device
);
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
);
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
);
95 goto rem_fine_grain_attr
;
97 for (i
= 0; i
< fan
->fps_count
; ++i
) {
98 struct acpi_fan_fps
*fps
= &fan
->fps
[i
];
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
);
110 for (j
= 0; j
< i
; ++j
)
111 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fps
[j
].dev_attr
.attr
);
119 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fst_speed
.attr
);
122 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fine_grain_control
.attr
);
127 void acpi_fan_delete_attributes(struct acpi_device
*device
)
129 struct acpi_fan
*fan
= acpi_driver_data(device
);
132 for (i
= 0; i
< fan
->fps_count
; ++i
)
133 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fps
[i
].dev_attr
.attr
);
135 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fst_speed
.attr
);
136 sysfs_remove_file(&device
->dev
.kobj
, &fan
->fine_grain_control
.attr
);