1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org> 4 */ 5 6 #include <linux/acpi.h> 7 #include <linux/module.h> 8 #include <linux/slab.h> 9 10 MODULE_LICENSE("GPL"); 11 12 static ssize_t irst_show_wakeup_events(struct device *dev, 13 struct device_attribute *attr, 14 char *buf) 15 { 16 struct acpi_device *acpi; 17 unsigned long long value; 18 acpi_status status; 19 20 acpi = to_acpi_device(dev); 21 22 status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value); 23 if (ACPI_FAILURE(status)) 24 return -EINVAL; 25 26 return sprintf(buf, "%lld\n", value); 27 } 28 29 static ssize_t irst_store_wakeup_events(struct device *dev, 30 struct device_attribute *attr, 31 const char *buf, size_t count) 32 { 33 struct acpi_device *acpi; 34 acpi_status status; 35 unsigned long value; 36 int error; 37 38 acpi = to_acpi_device(dev); 39 40 error = kstrtoul(buf, 0, &value); 41 if (error) 42 return error; 43 44 status = acpi_execute_simple_method(acpi->handle, "SFFS", value); 45 if (ACPI_FAILURE(status)) 46 return -EINVAL; 47 48 return count; 49 } 50 51 static struct device_attribute irst_wakeup_attr = { 52 .attr = { .name = "wakeup_events", .mode = 0600 }, 53 .show = irst_show_wakeup_events, 54 .store = irst_store_wakeup_events 55 }; 56 57 static ssize_t irst_show_wakeup_time(struct device *dev, 58 struct device_attribute *attr, char *buf) 59 { 60 struct acpi_device *acpi; 61 unsigned long long value; 62 acpi_status status; 63 64 acpi = to_acpi_device(dev); 65 66 status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value); 67 if (ACPI_FAILURE(status)) 68 return -EINVAL; 69 70 return sprintf(buf, "%lld\n", value); 71 } 72 73 static ssize_t irst_store_wakeup_time(struct device *dev, 74 struct device_attribute *attr, 75 const char *buf, size_t count) 76 { 77 struct acpi_device *acpi; 78 acpi_status status; 79 unsigned long value; 80 int error; 81 82 acpi = to_acpi_device(dev); 83 84 error = kstrtoul(buf, 0, &value); 85 if (error) 86 return error; 87 88 status = acpi_execute_simple_method(acpi->handle, "SFTV", value); 89 if (ACPI_FAILURE(status)) 90 return -EINVAL; 91 92 return count; 93 } 94 95 static struct device_attribute irst_timeout_attr = { 96 .attr = { .name = "wakeup_time", .mode = 0600 }, 97 .show = irst_show_wakeup_time, 98 .store = irst_store_wakeup_time 99 }; 100 101 static int irst_add(struct acpi_device *acpi) 102 { 103 int error; 104 105 error = device_create_file(&acpi->dev, &irst_timeout_attr); 106 if (unlikely(error)) 107 return error; 108 109 error = device_create_file(&acpi->dev, &irst_wakeup_attr); 110 if (unlikely(error)) 111 device_remove_file(&acpi->dev, &irst_timeout_attr); 112 113 return error; 114 } 115 116 static void irst_remove(struct acpi_device *acpi) 117 { 118 device_remove_file(&acpi->dev, &irst_wakeup_attr); 119 device_remove_file(&acpi->dev, &irst_timeout_attr); 120 } 121 122 static const struct acpi_device_id irst_ids[] = { 123 {"INT3392", 0}, 124 {"", 0} 125 }; 126 127 static struct acpi_driver irst_driver = { 128 .name = "intel_rapid_start", 129 .class = "intel_rapid_start", 130 .ids = irst_ids, 131 .ops = { 132 .add = irst_add, 133 .remove = irst_remove, 134 }, 135 }; 136 137 module_acpi_driver(irst_driver); 138 139 MODULE_DEVICE_TABLE(acpi, irst_ids); 140