cregit-Linux how code gets into the kernel

Release 4.17 drivers/acpi/acpi_tad.c

Directory: drivers/acpi
// SPDX-License-Identifier: GPL-2.0
/*
 * ACPI Time and Alarm (TAD) Device Driver
 *
 * Copyright (C) 2018 Intel Corporation
 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 *
 * This driver is based on Section 9.18 of the ACPI 6.2 specification revision.
 *
 * It only supports the system wakeup capabilities of the TAD.
 *
 * Provided are sysfs attributes, available under the TAD platform device,
 * allowing user space to manage the AC and DC wakeup timers of the TAD:
 * set and read their values, set and check their expire timer wake policies,
 * check and clear their status and check the capabilities of the TAD reported
 * by AML.  The DC timer attributes are only present if the TAD supports a
 * separate DC alarm timer.
 *
 * The wakeup events handling and power management of the TAD is expected to
 * be taken care of by the ACPI PM domain attached to its platform device.
 */

#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rafael J. Wysocki");

/* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */

#define ACPI_TAD_AC_WAKE	BIT(0)

#define ACPI_TAD_DC_WAKE	BIT(1)

#define ACPI_TAD_RT		BIT(2)

#define ACPI_TAD_RT_IN_MS	BIT(3)

#define ACPI_TAD_S4_S5__GWS	BIT(4)

#define ACPI_TAD_AC_S4_WAKE	BIT(5)

#define ACPI_TAD_AC_S5_WAKE	BIT(6)

#define ACPI_TAD_DC_S4_WAKE	BIT(7)

#define ACPI_TAD_DC_S5_WAKE	BIT(8)

/* ACPI TAD alarm timer selection */

#define ACPI_TAD_AC_TIMER	(u32)0

#define ACPI_TAD_DC_TIMER	(u32)1

/* Special value for disabled timer or expired timer wake policy. */

#define ACPI_TAD_WAKE_DISABLED	(~(u32)0)


struct acpi_tad_driver_data {
	
u32 capabilities;
};


static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, u32 value) { acpi_handle handle = ACPI_HANDLE(dev); union acpi_object args[] = { { .type = ACPI_TYPE_INTEGER, }, { .type = ACPI_TYPE_INTEGER, }, }; struct acpi_object_list arg_list = { .pointer = args, .count = ARRAY_SIZE(args), }; unsigned long long retval; acpi_status status; args[0].integer.value = timer_id; args[1].integer.value = value; pm_runtime_get_sync(dev); status = acpi_evaluate_integer(handle, method, &arg_list, &retval); pm_runtime_put_sync(dev); if (ACPI_FAILURE(status) || retval) return -EIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki140100.00%1100.00%
Total140100.00%1100.00%


static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method, u32 timer_id, const char *specval) { u32 value; if (sysfs_streq(buf, specval)) { value = ACPI_TAD_WAKE_DISABLED; } else { int ret = kstrtou32(buf, 0, &value); if (ret) return ret; if (value == ACPI_TAD_WAKE_DISABLED) return -EINVAL; } return acpi_tad_wake_set(dev, method, timer_id, value); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki91100.00%1100.00%
Total91100.00%1100.00%


static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method, u32 timer_id, const char *specval) { acpi_handle handle = ACPI_HANDLE(dev); union acpi_object args[] = { { .type = ACPI_TYPE_INTEGER, }, }; struct acpi_object_list arg_list = { .pointer = args, .count = ARRAY_SIZE(args), }; unsigned long long retval; acpi_status status; args[0].integer.value = timer_id; pm_runtime_get_sync(dev); status = acpi_evaluate_integer(handle, method, &arg_list, &retval); pm_runtime_put_sync(dev); if (ACPI_FAILURE(status)) return -EIO; if ((u32)retval == ACPI_TAD_WAKE_DISABLED) return sprintf(buf, "%s\n", specval); return sprintf(buf, "%u\n", (u32)retval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki155100.00%1100.00%
Total155100.00%1100.00%

static const char *alarm_specval = "disabled";
static int acpi_tad_alarm_write(struct device *dev, const char *buf, u32 timer_id) { return acpi_tad_wake_write(dev, buf, "_STV", timer_id, alarm_specval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki33100.00%1100.00%
Total33100.00%1100.00%


static ssize_t acpi_tad_alarm_read(struct device *dev, char *buf, u32 timer_id) { return acpi_tad_wake_read(dev, buf, "_TIV", timer_id, alarm_specval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki32100.00%1100.00%
Total32100.00%1100.00%

static const char *policy_specval = "never";
static int acpi_tad_policy_write(struct device *dev, const char *buf, u32 timer_id) { return acpi_tad_wake_write(dev, buf, "_STP", timer_id, policy_specval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki33100.00%1100.00%
Total33100.00%1100.00%


static ssize_t acpi_tad_policy_read(struct device *dev, char *buf, u32 timer_id) { return acpi_tad_wake_read(dev, buf, "_TIP", timer_id, policy_specval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki32100.00%1100.00%
Total32100.00%1100.00%


static int acpi_tad_clear_status(struct device *dev, u32 timer_id) { acpi_handle handle = ACPI_HANDLE(dev); union acpi_object args[] = { { .type = ACPI_TYPE_INTEGER, }, }; struct acpi_object_list arg_list = { .pointer = args, .count = ARRAY_SIZE(args), }; unsigned long long retval; acpi_status status; args[0].integer.value = timer_id; pm_runtime_get_sync(dev); status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval); pm_runtime_put_sync(dev); if (ACPI_FAILURE(status) || retval) return -EIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki115100.00%1100.00%
Total115100.00%1100.00%


static int acpi_tad_status_write(struct device *dev, const char *buf, u32 timer_id) { int ret, value; ret = kstrtoint(buf, 0, &value); if (ret) return ret; if (value) return -EINVAL; return acpi_tad_clear_status(dev, timer_id); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki59100.00%1100.00%
Total59100.00%1100.00%


static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id) { acpi_handle handle = ACPI_HANDLE(dev); union acpi_object args[] = { { .type = ACPI_TYPE_INTEGER, }, }; struct acpi_object_list arg_list = { .pointer = args, .count = ARRAY_SIZE(args), }; unsigned long long retval; acpi_status status; args[0].integer.value = timer_id; pm_runtime_get_sync(dev); status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval); pm_runtime_put_sync(dev); if (ACPI_FAILURE(status)) return -EIO; return sprintf(buf, "0x%02X\n", (u32)retval); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki127100.00%1100.00%
Total127100.00%1100.00%


static ssize_t caps_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); return sprintf(buf, "0x%02X\n", dd->capabilities); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki42100.00%1100.00%
Total42100.00%1100.00%

static DEVICE_ATTR_RO(caps);
static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_AC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t ac_alarm_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_alarm_read(dev, buf, ACPI_TAD_AC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(ac_alarm, S_IRUSR | S_IWUSR, ac_alarm_show, ac_alarm_store);
static ssize_t ac_policy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_AC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t ac_policy_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_policy_read(dev, buf, ACPI_TAD_AC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(ac_policy, S_IRUSR | S_IWUSR, ac_policy_show, ac_policy_store);
static ssize_t ac_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_AC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_status_read(dev, buf, ACPI_TAD_AC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(ac_status, S_IRUSR | S_IWUSR, ac_status_show, ac_status_store); static struct attribute *acpi_tad_attrs[] = { &dev_attr_caps.attr, &dev_attr_ac_alarm.attr, &dev_attr_ac_policy.attr, &dev_attr_ac_status.attr, NULL, }; static const struct attribute_group acpi_tad_attr_group = { .attrs = acpi_tad_attrs, };
static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_alarm_write(dev, buf, ACPI_TAD_DC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t dc_alarm_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_alarm_read(dev, buf, ACPI_TAD_DC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(dc_alarm, S_IRUSR | S_IWUSR, dc_alarm_show, dc_alarm_store);
static ssize_t dc_policy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_policy_write(dev, buf, ACPI_TAD_DC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t dc_policy_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_policy_read(dev, buf, ACPI_TAD_DC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(dc_policy, S_IRUSR | S_IWUSR, dc_policy_show, dc_policy_store);
static ssize_t dc_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = acpi_tad_status_write(dev, buf, ACPI_TAD_DC_TIMER); return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki43100.00%1100.00%
Total43100.00%1100.00%


static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr, char *buf) { return acpi_tad_status_read(dev, buf, ACPI_TAD_DC_TIMER); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

static DEVICE_ATTR(dc_status, S_IRUSR | S_IWUSR, dc_status_show, dc_status_store); static struct attribute *acpi_tad_dc_attrs[] = { &dev_attr_dc_alarm.attr, &dev_attr_dc_policy.attr, &dev_attr_dc_status.attr, NULL, }; static const struct attribute_group acpi_tad_dc_attr_group = { .attrs = acpi_tad_dc_attrs, };
static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) { return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki26100.00%1100.00%
Total26100.00%1100.00%


static int acpi_tad_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); device_init_wakeup(dev, false); pm_runtime_get_sync(dev); if (dd->capabilities & ACPI_TAD_DC_WAKE) sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); if (dd->capabilities & ACPI_TAD_DC_WAKE) { acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); } pm_runtime_put_sync(dev); pm_runtime_disable(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki124100.00%1100.00%
Total124100.00%1100.00%


static int acpi_tad_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; acpi_handle handle = ACPI_HANDLE(dev); struct acpi_tad_driver_data *dd; acpi_status status; unsigned long long caps; int ret; /* * Initialization failure messages are mostly about firmware issues, so * print them at the "info" level. */ status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps); if (ACPI_FAILURE(status)) { dev_info(dev, "Unable to get capabilities\n"); return -ENODEV; } if (!(caps & ACPI_TAD_AC_WAKE)) { dev_info(dev, "Unsupported capabilities\n"); return -ENODEV; } if (!acpi_has_method(handle, "_PRW")) { dev_info(dev, "Missing _PRW\n"); return -ENODEV; } dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); if (!dd) return -ENOMEM; dd->capabilities = caps; dev_set_drvdata(dev, dd); /* * Assume that the ACPI PM domain has been attached to the device and * simply enable system wakeup and runtime PM and put the device into * runtime suspend. Everything else should be taken care of by the ACPI * PM domain callbacks. */ device_init_wakeup(dev, true); dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | DPM_FLAG_LEAVE_SUSPENDED); /* * The platform bus type layer tells the ACPI PM domain powers up the * device, so set the runtime PM status of it to "active". */ pm_runtime_set_active(dev); pm_runtime_enable(dev); pm_runtime_suspend(dev); ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group); if (ret) goto fail; if (caps & ACPI_TAD_DC_WAKE) { ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) goto fail; } return 0; fail: acpi_tad_remove(pdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki256100.00%1100.00%
Total256100.00%1100.00%

static const struct acpi_device_id acpi_tad_ids[] = { {"ACPI000E", 0}, {} }; static struct platform_driver acpi_tad_driver = { .driver = { .name = "acpi-tad", .acpi_match_table = acpi_tad_ids, }, .probe = acpi_tad_probe, .remove = acpi_tad_remove, }; MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); module_platform_driver(acpi_tad_driver);

Overall Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki2042100.00%1100.00%
Total2042100.00%1100.00%
Directory: drivers/acpi
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.