From patchwork Tue Jun 2 22:56:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Pearson X-Patchwork-Id: 11584641 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C8CE260D for ; Tue, 2 Jun 2020 22:56:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BB2002072F for ; Tue, 2 Jun 2020 22:56:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728980AbgFBW4z (ORCPT ); Tue, 2 Jun 2020 18:56:55 -0400 Received: from mail1.bemta24.messagelabs.com ([67.219.250.113]:8439 "EHLO mail1.bemta24.messagelabs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728344AbgFBW4y (ORCPT ); Tue, 2 Jun 2020 18:56:54 -0400 Received: from [100.112.132.93] (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256 bits)) by server-2.bemta.az-b.us-west-2.aws.symcld.net id C2/19-18598-439D6DE5; Tue, 02 Jun 2020 22:56:52 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrBIsWRWlGSWpSXmKPExsWSLveKTdfk5rU 4g8NbeC1mH7axmPNsLaPF6j0vmB2YPX4fYPTYveAzk8fnTXIBzFGsmXlJ+RUJrBkXT5gX7FWu mP9wIUsD43q5LkYuDiGB/4wSHVdmsEE4zxkl9nXOZ+9i5ORgE9CW2LLlF1CCg0NEQEbiw1pPk BpmgY2MEnv/fmIFqREW8JZYsH8TG4jNIqAicbX1DVgvr4CVxIlX78HiEgLyEu3Lt4PZnAKqEm e6HrOA2EJA9fcfLGGDqBeUODnzCVicGai+eetsZghbQuLgixfMEHMUJFad7maFsBMklr28wzy BUWAWkvZZSNpnIWlfwMi8itEiqSgzPaMkNzEzR9fQwEDX0NBI19DYRNfQxFgvsUo3Sa+0WLc8 tbhE10gvsbxYr7gyNzknRS8vtWQTIzDAUwra+ncwrn/zQe8QoyQHk5Ior/vea3FCfEn5KZUZi cUZ8UWlOanFhxhlODiUJHj9rgPlBItS01Mr0jJzgNEGk5bg4FES4d0FkuYtLkjMLc5Mh0idYl SUEufdApIQAElklObBtcEi/BKjrJQwLyMDA4MQT0FqUW5mCar8K0ZxDkYlYV5+kCk8mXklcNN fAS1mAlps3we2uCQRISXVwNStnGD16ULhrmKt+OW7Z64TeXbQOlnz8SM/0+f/vxzk2dq4Mfuy eKPXbg9jbh9vBZu7TGIH5CXjJYN0MhIXC6Uc0NZk3GJ3zti7ovXIhPB8/5bMsOhM5Q7Ba9bhA V3PNmvMeOTnnLT9egjT7D72gOX7y68s2ex2nVX47YcPyevj3xmyxX4LOcC71+jaWbHtXU/033 5J2nw2uLCUc09yg8P+H//Mn6T3ZO/4yp5ib3Y27fO2CXNNY+ffYnGe73v9emi56v2q8xFiKuZ /mNk37b17+LZlrezh8ucBX2tCmOsO59c+2RAybfHO25+3LVyUHOK0PvqU+79NQX3thk9UGc7F XJM4b7VV4kDBp00Bq5RYijMSDbWYi4oTATKgj+trAwAA X-Env-Sender: markpearson@lenovo.com X-Msg-Ref: server-19.tower-355.messagelabs.com!1591138609!22923!1 X-Originating-IP: [103.30.234.6] X-SYMC-ESS-Client-Auth: outbound-route-from=pass X-StarScan-Received: X-StarScan-Version: 9.50.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 26495 invoked from network); 2 Jun 2020 22:56:51 -0000 Received: from unknown (HELO lenovo.com) (103.30.234.6) by server-19.tower-355.messagelabs.com with ECDHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 2 Jun 2020 22:56:51 -0000 Received: from reswpmail04.lenovo.com (unknown [10.62.32.23]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by Forcepoint Email with ESMTPS id D773747A47B2C5552B08; Wed, 3 Jun 2020 06:56:47 +0800 (CST) Received: from localhost.localdomain (10.64.88.167) by reswpmail04.lenovo.com (10.62.32.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.1913.5; Tue, 2 Jun 2020 15:56:43 -0700 From: Mark Pearson To: CC: , , , Nitin Joshi , Sugumaran Subject: [PATCH v2] platform/x86: thinkpad_acpi: lap or desk mode interface Date: Tue, 2 Jun 2020 18:56:15 -0400 Message-ID: <20200602225615.8336-1-markpearson@lenovo.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [10.64.88.167] X-ClientProxiedBy: reswpmail04.lenovo.com (10.62.32.23) To reswpmail04.lenovo.com (10.62.32.23) Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Newer Lenovo Thinkpad platforms have support to identify whether the system is on-lap or not using an ACPI DYTC event from the firmware. This patch provides the ability to retrieve the current mode via sysfs entrypoints and will be used by userspace for thermal mode and WWAN functionality Co-developed-by: Nitin Joshi Signed-off-by: Nitin Joshi Reviewed-by: Sugumaran Signed-off-by: Mark Pearson --- Changes in v2: - cleaned up initialisation sequence to be cleaner and avoid spamming platforms that don't have DYTC with warning message. Tested on P52 - Adding platform-driver-x86 mailing list for review as requested drivers/platform/x86/thinkpad_acpi.c | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 0f704484ae1d..8f51bbba21cd 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4049,6 +4049,7 @@ static bool hotkey_notify_6xxx(const u32 hkey, pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n"); /* recommended action: do nothing, we don't have * Lenovo ATM information */ + tpacpi_driver_event(hkey); return true; case TP_HKEY_EV_THM_TRANSFM_CHANGED: pr_debug("EC reports: Thermal Transformation changed (GMTS)\n"); @@ -9811,6 +9812,110 @@ static struct ibm_struct lcdshadow_driver_data = { .write = lcdshadow_write, }; +/************************************************************************* + * DYTC subdriver, for the Lenovo performace mode feature + */ + +#define DYTC_CMD_GET 2 /*To get current IC function and mode*/ + +#define DYTC_GET_ENABLE_MASK 0x1 /*0 = disabled, 1 = enabled*/ +#define DYTC_GET_LAPMODE_SHIFT 17 + +static int dytc_lapmode; +static void dytc_lapmode_notify_change(void) +{ + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "dytc_lapmode"); +} + +static int dytc_command(int command) +{ + acpi_handle dytc_handle; + int output; + + if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DYTC", &dytc_handle))) { + /*Platform doesn't support DYTC*/ + return -ENODEV; + } + if (!acpi_evalf(dytc_handle, &output, NULL, "dd", command)) + return -EIO; + return output; +} + +static int dytc_lapmode_get(void) +{ + int output; + + output = dytc_command(DYTC_CMD_GET); + if ((output == -ENODEV) || (output == -EIO)) + return output; + + return ((output >> DYTC_GET_LAPMODE_SHIFT) & + DYTC_GET_ENABLE_MASK); +} + +static void dytc_lapmode_refresh(void) +{ + int new_state; + + new_state = dytc_lapmode_get(); + if ((new_state == -ENODEV) || (new_state == -EIO)) + return; + + if (dytc_lapmode != new_state) { + dytc_lapmode = new_state; + dytc_lapmode_notify_change(); + } +} + +/* sysfs lapmode entry */ +static ssize_t dytc_lapmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + if (dytc_lapmode < 0) + return dytc_lapmode; + + return snprintf(buf, PAGE_SIZE, "%d\n", dytc_lapmode); +} + +static DEVICE_ATTR_RO(dytc_lapmode); + +static struct attribute *dytc_attributes[] = { + &dev_attr_dytc_lapmode.attr, + NULL +}; + +static const struct attribute_group dytc_attr_group = { + .attrs = dytc_attributes, +}; + +static int tpacpi_dytc_init(struct ibm_init_struct *iibm) +{ + int res; + + dytc_lapmode = dytc_lapmode_get(); + + if (dytc_lapmode < 0 && dytc_lapmode != -ENODEV) + return dytc_lapmode; + + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &dytc_attr_group); + + return res; +} + +static void dytc_exit(void) +{ + sysfs_remove_group(&tpacpi_pdev->dev.kobj, + &dytc_attr_group); +} + +static struct ibm_struct dytc_driver_data = { + .name = "dytc", + .exit = dytc_exit +}; + /**************************************************************************** **************************************************************************** * @@ -9858,6 +9963,10 @@ static void tpacpi_driver_event(const unsigned int hkey_event) mutex_unlock(&kbdlight_mutex); } + + if (hkey_event == TP_HKEY_EV_THM_CSM_COMPLETED) + dytc_lapmode_refresh(); + } static void hotkey_driver_event(const unsigned int scancode) @@ -10296,6 +10405,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = tpacpi_lcdshadow_init, .data = &lcdshadow_driver_data, }, + { + .init = tpacpi_dytc_init, + .data = &dytc_driver_data, + }, }; static int __init set_ibm_param(const char *val, const struct kernel_param *kp) From patchwork Wed Dec 2 17:11:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Pearson X-Patchwork-Id: 11946443 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C4752C64E7C for ; Wed, 2 Dec 2020 17:16:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 59669217A0 for ; Wed, 2 Dec 2020 17:16:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728782AbgLBRQh (ORCPT ); Wed, 2 Dec 2020 12:16:37 -0500 Received: from mail1.bemta24.messagelabs.com ([67.219.250.116]:47942 "EHLO mail1.bemta24.messagelabs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726221AbgLBRQg (ORCPT ); Wed, 2 Dec 2020 12:16:36 -0500 Received: from [100.112.133.223] (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256 bits)) by server-5.bemta.az-b.us-west-2.aws.symcld.net id 29/62-25369-9DAC7CF5; Wed, 02 Dec 2020 17:11:53 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprDKsWRWlGSWpSXmKPExsWSLveKXffKqeP xBr3/BS32X5ew6FpoYLHw/ilWi6/fbrNbvDk+ncli+b5+RoumziY2i88dk1ksVu95wWyx9ss8 Noszpy+xOnB7TJo5g9lj56y77B6/tq1h8di8Qstj3slAj562TUwe7/ddZfPYcrWdxePzJrkAz ijWzLyk/IoE1oxrP1ayFJzxr9i7eD1rA+NEly5GLg4hgf+MEvNnf2SEcB4wSlx6uR/I4eRgE9 CW2LLlF1sXIweHiICMxIe1niA1zALzmSSuTbjKDlIjLOAj0bC0lw3EZhFQkdh8sQOsl1fAWmL 3pRvMILaEgLzE097lzCBzOAVsJGZvzwcJCwmESrxa9YcVolxQ4uTMJywgNjNQefPW2cwQtoTE wRcvoMYoSMz7uogFwk6QWPbyDvMERoFZSNpnIWmfhaR9ASPzKkaLpKLM9IyS3MTMHF1DAwNdQ 0MjXUNjE11DMxO9xCrdJL3SYt3y1OISXSO9xPJiveLK3OScFL281JJNjMBISyloW7KDcdebD3 qHGCU5mJREeVfNPx4vxJeUn1KZkVicEV9UmpNafIhRhoNDSYJX/yRQTrAoNT21Ii0zBxj1MGk JDh4lEV5JkDRvcUFibnFmOkTqFKOilDhvEUhCACSRUZoH1wZLNJcYZaWEeRkZGBiEeApSi3Iz S1DlXzGKczAqCfNeOQE0hSczrwRu+iugxUxAi10+HwZZXJKIkJJqYFIpUmqaeyj6ztfUPrkCe 9urxsvKWyVDz/Xd2nhN6qK87hT/zfas054dMbk9Q4mbb+2yM0cECndzSi6onuHhqpbT/K7kaP D1IyveL0lNjmYR9zpyof34AanOl0Jv8gxmfHlsEy36Rnsaz4Nn08//P+tkK/x3P9O1D9mTIlo vxOV9ThLn2iRW8DTdJ0fiO+fTY/VP2G8e3R76+EfcFLm7L0QjtV2vvTKwapxQuFKiN2Ovj6j8 pqsNJ9Yp7X1zJVT78W2Hy8E7WAJTP+2uKNP/snuvQ4ml3lwWKbNIz9Ta3tVbX55pbP8kzHIz8 eoTP2E5q1l7o4oUHl+eUb196cuys8JsidzqUVNXckV26hysllFiKc5INNRiLipOBACcLjiFrw MAAA== X-Env-Sender: markpearson@lenovo.com X-Msg-Ref: server-37.tower-355.messagelabs.com!1606929106!7440!1 X-Originating-IP: [103.30.234.7] X-SYMC-ESS-Client-Auth: outbound-route-from=pass X-StarScan-Received: X-StarScan-Version: 9.60.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 4321 invoked from network); 2 Dec 2020 17:11:47 -0000 Received: from unknown (HELO lenovo.com) (103.30.234.7) by server-37.tower-355.messagelabs.com with ECDHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 2 Dec 2020 17:11:47 -0000 Received: from reswpmail04.lenovo.com (unknown [10.62.32.23]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by Forcepoint Email with ESMTPS id 44EACC56D39F85ECCF7B; Thu, 3 Dec 2020 01:11:43 +0800 (CST) Received: from localhost.home (10.64.84.211) by reswpmail04.lenovo.com (10.62.32.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2044.4; Wed, 2 Dec 2020 09:11:38 -0800 From: Mark Pearson To: CC: , , , , , , , , , , Subject: [PATCH v5 2/3] ACPI: platform-profile: Add platform profile support Date: Wed, 2 Dec 2020 12:11:19 -0500 Message-ID: <20201202171120.65269-2-markpearson@lenovo.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201202171120.65269-1-markpearson@lenovo.com> References: <20201202171120.65269-1-markpearson@lenovo.com> MIME-Version: 1.0 X-Originating-IP: [10.64.84.211] X-ClientProxiedBy: reswpmail04.lenovo.com (10.62.32.23) To reswpmail04.lenovo.com (10.62.32.23) Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org This is the initial implementation of the platform-profile feature. It provides the details discussed and outlined in the sysfs-platform_profile document. Many modern systems have the ability to modify the operating profile to control aspects like fan speed, temperature and power levels. This module provides a common sysfs interface that platform modules can register against to control their individual profile options. Signed-off-by: Mark Pearson --- Changes in v2: Address (hopefully) all recommendations from review including: - reorder includes list alphabetically - make globals statics and use const as required - change profile name scanning to use full string - clean up profile name lists to remove unwanted additions - use sysfs_emit and sysfs_emit_at appropriately (much nicer!) - improve error handling. Return errors to user in all cases and use better error codes where appropriate (ENOOPSUPP) - clean up sysfs output for better readability - formatting fixes where needed - improve structure and enum names to be clearer - remove cur_profile field from structure. It is now local to the actual platform driver file (patch 3 in series) - improve checking so if future profile options are added profile_names will be updated as well. - move CONFIG option next to ACPI_THERMAL as it seemed slightly related - removed MAINTAINERS update as not appropriate (note warning message is seen when running checkpatch) Changes in v3: - Add missed platform_profile.h file Changes in v4: - Clean up duplicate entry in Kconfig file - Add linux/bits.h to include list - Remove unnecessary items from include list - Make cur_profile const - Clean up comments - formatting clean-ups - add checking of profile return value to show function - add checking to store to see if it's a supported profile - revert ENOTSUPP change in store function - improved error checking in profile registration - improved profile naming (now platform_profile_*) Changes in v5: - correct 'balance' to 'balanced' to be consistent with documentation - add WARN_ON when checking profile index in show function - switch mutex_lock_interruptible back to mutex_lock where appropriate - add 'platform_profile_last' as final entry in profile entry. Update implementation to use this appropriately - Use BITS_TO_LONG and appropriate access functions for choices field - Correct error handling as recommended - Sanity check profile fields on registration - Remove unnecessary init and exit functions drivers/acpi/Kconfig | 14 +++ drivers/acpi/Makefile | 1 + drivers/acpi/platform_profile.c | 181 +++++++++++++++++++++++++++++++ include/linux/platform_profile.h | 39 +++++++ 4 files changed, 235 insertions(+) create mode 100644 drivers/acpi/platform_profile.c create mode 100644 include/linux/platform_profile.h diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index edf1558c1105..c1ca6255ff85 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -326,6 +326,20 @@ config ACPI_THERMAL To compile this driver as a module, choose M here: the module will be called thermal. +config ACPI_PLATFORM_PROFILE + tristate "ACPI Platform Profile Driver" + default y + help + This driver adds support for platform-profiles on platforms that + support it. + Platform-profiles can be used to control the platform behaviour. For + example whether to operate in a lower power mode, in a higher + power performance mode or between the two. + This driver provides the sysfs interface and is used as the registration + point for platform specific drivers. + Which profiles are supported is determined on a per-platform basis and + should be obtained from the platform specific driver. + config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" default "" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 44e412506317..c64a8af106c0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI) += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o +obj-$(CONFIG_ACPI_PLATFORM_PROFILE) += platform_profile.o obj-$(CONFIG_ACPI_NFIT) += nfit/ obj-$(CONFIG_ACPI_NUMA) += numa/ obj-$(CONFIG_ACPI) += acpi_memhotplug.o diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c new file mode 100644 index 000000000000..1bc092359e35 --- /dev/null +++ b/drivers/acpi/platform_profile.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* Platform profile sysfs interface */ + +#include +#include +#include +#include +#include +#include + +static const struct platform_profile_handler *cur_profile; +static DEFINE_MUTEX(profile_lock); + +static const char * const profile_names[] = { + [platform_profile_low] = "low-power", + [platform_profile_cool] = "cool", + [platform_profile_quiet] = "quiet", + [platform_profile_balanced] = "balanced", + [platform_profile_perform] = "performance", +}; +static_assert(ARRAY_SIZE(profile_names) == platform_profile_last); + +static ssize_t platform_profile_choices_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int len = 0; + int err, i; + + err = mutex_lock_interruptible(&profile_lock); + if (err) + return err; + + if (!cur_profile) { + mutex_unlock(&profile_lock); + return -ENODEV; + } + + for_each_set_bit(i, cur_profile->choices, platform_profile_last) { + if (len == 0) + len += sysfs_emit_at(buf, len, "%s", profile_names[i]); + else + len += sysfs_emit_at(buf, len, " %s", profile_names[i]); + } + len += sysfs_emit_at(buf, len, "\n"); + mutex_unlock(&profile_lock); + return len; +} + +static ssize_t platform_profile_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + enum platform_profile_option profile = platform_profile_balanced; + int err; + + err = mutex_lock_interruptible(&profile_lock); + if (err) + return err; + + if (!cur_profile) { + mutex_unlock(&profile_lock); + return -ENODEV; + } + + err = cur_profile->profile_get(&profile); + mutex_unlock(&profile_lock); + if (err) + return err; + + /* Check that profile is valid index */ + if (WARN_ON((profile < 0) || (profile >= ARRAY_SIZE(profile_names)))) + return -EIO; + + return sysfs_emit(buf, "%s\n", profile_names[profile]); +} + +static ssize_t platform_profile_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err, i; + + err = mutex_lock_interruptible(&profile_lock); + if (err) + return err; + + if (!cur_profile) { + mutex_unlock(&profile_lock); + return -ENODEV; + } + + /* Scan for a matching profile */ + i = sysfs_match_string(profile_names, buf); + if (i < 0) { + mutex_unlock(&profile_lock); + return -EINVAL; + } + + /* Check that platform supports this profile choice */ + if (!test_bit(i, cur_profile->choices)) { + mutex_unlock(&profile_lock); + return -EOPNOTSUPP; + } + + err = cur_profile->profile_set(i); + mutex_unlock(&profile_lock); + if (err) + return err; + return count; +} + +static DEVICE_ATTR_RO(platform_profile_choices); +static DEVICE_ATTR_RW(platform_profile); + +static struct attribute *platform_profile_attrs[] = { + &dev_attr_platform_profile_choices.attr, + &dev_attr_platform_profile.attr, + NULL +}; + +static const struct attribute_group platform_profile_group = { + .attrs = platform_profile_attrs +}; + +void platform_profile_notify(void) +{ + if (!cur_profile) + return; + sysfs_notify(acpi_kobj, NULL, "platform_profile"); +} +EXPORT_SYMBOL_GPL(platform_profile_notify); + +int platform_profile_register(const struct platform_profile_handler *pprof) +{ + int err; + + mutex_lock(&profile_lock); + /* We can only have one active profile */ + if (cur_profile) { + mutex_unlock(&profile_lock); + return -EEXIST; + } + + /* Sanity check the profile handler field are set */ + if (!pprof || !pprof->choices || !pprof->profile_set || + !pprof->profile_get) { + mutex_unlock(&profile_lock); + return -EINVAL; + } + + err = sysfs_create_group(acpi_kobj, &platform_profile_group); + if (err) { + mutex_unlock(&profile_lock); + return err; + } + + cur_profile = pprof; + mutex_unlock(&profile_lock); + return 0; +} +EXPORT_SYMBOL_GPL(platform_profile_register); + +int platform_profile_unregister(void) +{ + mutex_lock(&profile_lock); + if (!cur_profile) { + mutex_unlock(&profile_lock); + return -ENODEV; + } + + sysfs_remove_group(acpi_kobj, &platform_profile_group); + cur_profile = NULL; + mutex_unlock(&profile_lock); + return 0; +} +EXPORT_SYMBOL_GPL(platform_profile_unregister); + +MODULE_AUTHOR("Mark Pearson "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_profile.h b/include/linux/platform_profile.h new file mode 100644 index 000000000000..f2e1b1c90482 --- /dev/null +++ b/include/linux/platform_profile.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Platform profile sysfs interface + * + * See Documentation/ABI/testing/sysfs-platform_profile.rst for more + * information. + */ + +#ifndef _PLATFORM_PROFILE_H_ +#define _PLATFORM_PROFILE_H_ + +#include + +/* + * If more options are added please update profile_names + * array in platform-profile.c and sysfs-platform-profile.rst + * documentation. + */ + +enum platform_profile_option { + platform_profile_low, + platform_profile_cool, + platform_profile_quiet, + platform_profile_balanced, + platform_profile_perform, + platform_profile_last, /*must always be last */ +}; + +struct platform_profile_handler { + unsigned long choices[BITS_TO_LONGS(platform_profile_last)]; + int (*profile_get)(enum platform_profile_option *profile); + int (*profile_set)(enum platform_profile_option profile); +}; + +int platform_profile_register(const struct platform_profile_handler *pprof); +int platform_profile_unregister(void); +void platform_profile_notify(void); + +#endif /*_PLATFORM_PROFILE_H_*/