1/* 2 * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 20#include <linux/init.h> 21#include <linux/module.h> 22#include <linux/slab.h> 23#include <linux/acpi.h> 24 25MODULE_LICENSE("GPL"); 26 27static ssize_t irst_show_wakeup_events(struct device *dev, 28 struct device_attribute *attr, 29 char *buf) 30{ 31 struct acpi_device *acpi; 32 unsigned long long value; 33 acpi_status status; 34 35 acpi = to_acpi_device(dev); 36 37 status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value); 38 if (ACPI_FAILURE(status)) 39 return -EINVAL; 40 41 return sprintf(buf, "%lld\n", value); 42} 43 44static ssize_t irst_store_wakeup_events(struct device *dev, 45 struct device_attribute *attr, 46 const char *buf, size_t count) 47{ 48 struct acpi_device *acpi; 49 acpi_status status; 50 unsigned long value; 51 int error; 52 53 acpi = to_acpi_device(dev); 54 55 error = kstrtoul(buf, 0, &value); 56 57 if (error) 58 return error; 59 60 status = acpi_execute_simple_method(acpi->handle, "SFFS", value); 61 62 if (ACPI_FAILURE(status)) 63 return -EINVAL; 64 65 return count; 66} 67 68static struct device_attribute irst_wakeup_attr = { 69 .attr = { .name = "wakeup_events", .mode = 0600 }, 70 .show = irst_show_wakeup_events, 71 .store = irst_store_wakeup_events 72}; 73 74static ssize_t irst_show_wakeup_time(struct device *dev, 75 struct device_attribute *attr, char *buf) 76{ 77 struct acpi_device *acpi; 78 unsigned long long value; 79 acpi_status status; 80 81 acpi = to_acpi_device(dev); 82 83 status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value); 84 if (ACPI_FAILURE(status)) 85 return -EINVAL; 86 87 return sprintf(buf, "%lld\n", value); 88} 89 90static ssize_t irst_store_wakeup_time(struct device *dev, 91 struct device_attribute *attr, 92 const char *buf, size_t count) 93{ 94 struct acpi_device *acpi; 95 acpi_status status; 96 unsigned long value; 97 int error; 98 99 acpi = to_acpi_device(dev); 100 101 error = kstrtoul(buf, 0, &value); 102 103 if (error) 104 return error; 105 106 status = acpi_execute_simple_method(acpi->handle, "SFTV", value); 107 108 if (ACPI_FAILURE(status)) 109 return -EINVAL; 110 111 return count; 112} 113 114static struct device_attribute irst_timeout_attr = { 115 .attr = { .name = "wakeup_time", .mode = 0600 }, 116 .show = irst_show_wakeup_time, 117 .store = irst_store_wakeup_time 118}; 119 120static int irst_add(struct acpi_device *acpi) 121{ 122 int error; 123 124 error = device_create_file(&acpi->dev, &irst_timeout_attr); 125 if (unlikely(error)) 126 return error; 127 128 error = device_create_file(&acpi->dev, &irst_wakeup_attr); 129 if (unlikely(error)) 130 device_remove_file(&acpi->dev, &irst_timeout_attr); 131 132 return error; 133} 134 135static int irst_remove(struct acpi_device *acpi) 136{ 137 device_remove_file(&acpi->dev, &irst_wakeup_attr); 138 device_remove_file(&acpi->dev, &irst_timeout_attr); 139 140 return 0; 141} 142 143static const struct acpi_device_id irst_ids[] = { 144 {"INT3392", 0}, 145 {"", 0} 146}; 147 148static struct acpi_driver irst_driver = { 149 .owner = THIS_MODULE, 150 .name = "intel_rapid_start", 151 .class = "intel_rapid_start", 152 .ids = irst_ids, 153 .ops = { 154 .add = irst_add, 155 .remove = irst_remove, 156 }, 157}; 158 159module_acpi_driver(irst_driver); 160 161MODULE_DEVICE_TABLE(acpi, irst_ids); 162