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/platform_device.h> 9 #include <linux/slab.h> 10 11 MODULE_DESCRIPTION("Intel Rapid Start Technology Driver"); 12 MODULE_LICENSE("GPL"); 13 14 static ssize_t irst_show_wakeup_events(struct device *dev, 15 struct device_attribute *attr, 16 char *buf) 17 { 18 struct acpi_device *acpi; 19 unsigned long long value; 20 acpi_status status; 21 22 acpi = to_acpi_device(dev); 23 24 status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value); 25 if (ACPI_FAILURE(status)) 26 return -EINVAL; 27 28 return sprintf(buf, "%lld\n", value); 29 } 30 31 static ssize_t irst_store_wakeup_events(struct device *dev, 32 struct device_attribute *attr, 33 const char *buf, size_t count) 34 { 35 struct acpi_device *acpi; 36 acpi_status status; 37 unsigned long value; 38 int error; 39 40 acpi = to_acpi_device(dev); 41 42 error = kstrtoul(buf, 0, &value); 43 if (error) 44 return error; 45 46 status = acpi_execute_simple_method(acpi->handle, "SFFS", value); 47 if (ACPI_FAILURE(status)) 48 return -EINVAL; 49 50 return count; 51 } 52 53 static struct device_attribute irst_wakeup_attr = { 54 .attr = { .name = "wakeup_events", .mode = 0600 }, 55 .show = irst_show_wakeup_events, 56 .store = irst_store_wakeup_events 57 }; 58 59 static ssize_t irst_show_wakeup_time(struct device *dev, 60 struct device_attribute *attr, char *buf) 61 { 62 struct acpi_device *acpi; 63 unsigned long long value; 64 acpi_status status; 65 66 acpi = to_acpi_device(dev); 67 68 status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value); 69 if (ACPI_FAILURE(status)) 70 return -EINVAL; 71 72 return sprintf(buf, "%lld\n", value); 73 } 74 75 static ssize_t irst_store_wakeup_time(struct device *dev, 76 struct device_attribute *attr, 77 const char *buf, size_t count) 78 { 79 struct acpi_device *acpi; 80 acpi_status status; 81 unsigned long value; 82 int error; 83 84 acpi = to_acpi_device(dev); 85 86 error = kstrtoul(buf, 0, &value); 87 if (error) 88 return error; 89 90 status = acpi_execute_simple_method(acpi->handle, "SFTV", value); 91 if (ACPI_FAILURE(status)) 92 return -EINVAL; 93 94 return count; 95 } 96 97 static struct device_attribute irst_timeout_attr = { 98 .attr = { .name = "wakeup_time", .mode = 0600 }, 99 .show = irst_show_wakeup_time, 100 .store = irst_store_wakeup_time 101 }; 102 103 static int irst_probe(struct platform_device *pdev) 104 { 105 struct acpi_device *acpi; 106 int error; 107 108 acpi = ACPI_COMPANION(&pdev->dev); 109 if (!acpi) 110 return -ENODEV; 111 112 error = device_create_file(&acpi->dev, &irst_timeout_attr); 113 if (unlikely(error)) 114 return error; 115 116 error = device_create_file(&acpi->dev, &irst_wakeup_attr); 117 if (unlikely(error)) 118 device_remove_file(&acpi->dev, &irst_timeout_attr); 119 120 return error; 121 } 122 123 static void irst_remove(struct platform_device *pdev) 124 { 125 struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev); 126 127 device_remove_file(&acpi->dev, &irst_wakeup_attr); 128 device_remove_file(&acpi->dev, &irst_timeout_attr); 129 } 130 131 static const struct acpi_device_id irst_ids[] = { 132 {"INT3392", 0}, 133 {"", 0} 134 }; 135 136 static struct platform_driver irst_driver = { 137 .probe = irst_probe, 138 .remove = irst_remove, 139 .driver = { 140 .name = "intel_rapid_start", 141 .acpi_match_table = irst_ids, 142 }, 143 }; 144 145 module_platform_driver(irst_driver); 146 147 MODULE_DEVICE_TABLE(acpi, irst_ids); 148