From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350911; cv=none; d=zohomail.com; s=zohoarc; b=G9YaOkRD1fHnweq6mcuuFxs+wTHws7lJ43YKW0K1LFWVtiNB7K3sTvqzFiTzgF0Q/iPimi9ek/dNciOzfvj14kZoB5y/DDGpod6Mjc4enlgHB17gfipgiPfr6SOQmCS4dd9bBKcUo4G5r+Rv/kdnhcgv/SJFb9+o8FjhAOHbI+A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350911; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=TjR/1xx5bOl+takc0FONIiMwUFjjRDb8h/3I5ITMqHQ=; b=JVBQFXwBH7+9r4bbv7kBC6nX4e9kqcNKsxxs2y8MfJzDeZWCXjFr/pzh1RtL03kh/vshLGNuYDcOQptIT5xz0oX8qgOaCTnibL8d0A/m7eQXvT1A7vJLUjwAdYMclRaLe3PtGA+zbHUoP6lCZhQW1VIlqq6Gap3fEmPTd5Q77wg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350911926775.7146341993384; Tue, 18 May 2021 08:15:11 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350116AbhERPMX (ORCPT ); Tue, 18 May 2021 11:12:23 -0400 Received: from mail.kernel.org ([198.145.29.99]:49572 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344627AbhERPKb (ORCPT ); Tue, 18 May 2021 11:10:31 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 13838611CC; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LH-007HNy-V1; Tue, 18 May 2021 17:09:07 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=82XffmYo0cA66yCWYBV/J5xp5EBADo2oA0FQHMi2s38=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AJZkE1cMdTzTYatBd5+Lm3igisdnS4KHQbP66mU1UNcLylzmpkbjQrPD+AAmzuF64 gAB3gnSKXMekKC7+d79DdqSKC3MnUc2iMYM7R/1/qW01NNCvUTEHVwKg1cVX4GMIoX KROkULk0XziHoTDk11d5sFwtY6WKo19PcoZjVxn8wYIZEQH5FZp3+1HDr6kYL/JOxz 1zKfjjS/J+RZbayoh3h41geBOmZq+yAhyhrMGf+JEn1db0djdLHPyFI2OppFle8Mif S5KYDz33FXFpuP3EjEb8GQ0nc9dwNYhVNTb4klo67gXXqBTEvVEgzAXQmb/9dt8Uzo DNXd7Cal8YNww== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Dan Murphy , Greg Kroah-Hartman , Jacek Anaszewski , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 01/17] docs: describe the API used to set NUC LEDs Date: Tue, 18 May 2021 17:08:50 +0200 Message-Id: <176a87ffb738ec7fd650d85ec19ede882cd82772.1621349813.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Some NUC6 have LEDs that can be configurated dynamically from the operational system, via WMI. Describe how the API for such devices should work. Signed-off-by: Mauro Carvalho Chehab --- Documentation/leds/index.rst | 1 + Documentation/leds/leds-nuc.rst | 447 ++++++++++++++++++++++++++++++++ 2 files changed, 448 insertions(+) create mode 100644 Documentation/leds/leds-nuc.rst diff --git a/Documentation/leds/index.rst b/Documentation/leds/index.rst index e5d63b940045..4fdf9b60bb86 100644 --- a/Documentation/leds/index.rst +++ b/Documentation/leds/index.rst @@ -25,4 +25,5 @@ LEDs leds-lp5562 leds-lp55xx leds-mlxcpld + leds-nuc leds-sc27xx diff --git a/Documentation/leds/leds-nuc.rst b/Documentation/leds/leds-nuc.= rst new file mode 100644 index 000000000000..02e1c2602dd3 --- /dev/null +++ b/Documentation/leds/leds-nuc.rst @@ -0,0 +1,447 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Intel NUC WMI LEDs +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Some models of the Intel Next Unit of Computing (NUC) may have programmable +LEDs. Those can be partially programmed by opening the BIOS configuration. + +Among those models, some of them also allows the Operational System to +adjust the LED parameters via a firmware interface, called Windows Managem= ent +Interface - WMI. + +There are currently three different versions of WMI API for NUC, depending +on the NUC generation: + +For NUC 6 and 7, the WMI API is defined at: + + - https://www.intel.com/content/www/us/en/support/articles/000023426/in= tel-nuc/intel-nuc-kits.html + +For NUC 8 and 8, the WMI API is defined at: + + - https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/IN= TEL_WMI_LED_0.64.pdf + +For NUC 10 and newer generations, the WMI API is defined at: + - https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WM= I-Spec-Intel-NUC-NUC10ixFNx.pdf + +The nuc-wmi driver provides userspace support for changing the LED +configuration, and supports WMI API since NUC 6. Yet, the NUC6 WMI API +functionality is limited when compared with the newer NUC generations. + +Although there are some internal differences, the features supported for +NUC 10 WMI API are almost identical to the ones supported by NUC 8 WMI API. + +.. note:: + + Even when the firmware supports setting LEDs via WMI API, the + BIOS configuration has some parameters to either allow the Operational + System to also control them. Instructions about how to enable it can + be found at the manual of each specific NUC model. + +NUC 6 and NUC 7 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +When the driver detects NUC LEDs, up to two directories will be created +under sysfs. They're asocciated with the button(s) named "Power" and "Ring= ". + +Assuming that sysfs is mounted under ``/sys``, those are the +directories: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +LED name sysfs device directory +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Power ``/sys/class/leds/nuc::power`` +Ring ``/sys/class/leds/nuc::ring`` +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +For each of the above directory, some sysfs nodes will allow to control the +functionality for each button:: + + . + |-- blink_behavior + |-- blink_frequency + |-- brightness + |-- color + |-- device -> ../../../8C5DA44C-CDC3-46B3-8619-4E26D34390B7 + `-- max_brightness + +.. note:: + + 1. any user can read the LEDs parameter; + 2. changing a LED parameter is limited to the owner of the sysfs device + nodes (usually, the ``root`` user); + 3. changing a LED parameter is case-insensitive + +Brightness +---------- + +The ``brightness`` adjusts the LED brightness, and can be set from +0 to ``max_brightness``. + +So, for instance, in order to put the power LED with 50% of the bright:: + + $ cat /sys/class/leds/nuc::power/max_brightness + 100 + # echo 50 > /sys/class/leds/nuc::power/max_brightness + +Color +----- + +On NUC6 API, the power LED color can be be dual colored. Those are +the valid color values: + + +---------+ + | disable | + +---------+ + | blue | + +---------+ + | amber | + +---------+ + +And the ring LED color can be multi colored. Those are the valid color +values: + + +---------+ + | disable | + +---------+ + | cyan | + +---------+ + | pink | + +---------+ + | yellow | + +---------+ + | blue | + +---------+ + | red | + +---------+ + | green | + +---------+ + | white | + +---------+ + +Changing the ring color of the ring LED can be done with:: + + $ cat /sys/class/leds/nuc::ring/color + [disable] cyan pink yellow blue red green white + # echo "cyan" > /sys/class/leds/nuc::ring/color + +Blink behavior and frequency +---------------------------- + +The NUC6 API supports those blink behaviors: + + +-------+ + | Solid | + +-------+ + | Blink | + +-------+ + | Fade | + +-------+ + + +When in blink and/or fade mode, it supports the following frequencies: + + +---------+ + | 1 Hz | + +---------+ + | 0.5 Hz | + +---------+ + | 0.25 Hz | + +---------+ + +Changing the blink behavior of the power LED, for instance, can be done +with:: + + $ cat /sys/class/leds/nuc::power/blink_behavior + [solid] blink fade + $ cat /sys/class/leds/nuc::power/blink_frequency + [1] 0.5 0.25 + # echo "blink" > /sys/class/leds/nuc::power/blink_behavior + # echo 0.5 > /sys/class/leds/nuc::power/blink_frequency + +.. note:: + + The blink/fade behavior and frequencies can support only a subset of + the above values on old BIOS. + +NUC 8 and newer generations +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +When the driver detects NUC LEDs, up to seven directories will be +created under sysfs. Each one for each different LED. + +Assuming that sysfs is mounted under ``/sys``, those are the +directories: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +LED name sysfs device node +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Skull ``/sys/class/leds/nuc::skull`` +Skull eyes ``/sys/class/leds/nuc::eyes`` +Power ``/sys/class/leds/nuc::power`` +HDD ``/sys/class/leds/nuc::hdd`` +Front1 ``/sys/class/leds/nuc::front1`` +Front2 ``/sys/class/leds/nuc::front2`` +Front3 ``/sys/class/leds/nuc::front3`` +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +For each of the above directory, some sysfs nodes will allow to control the +functionality for each button:: + + /sys/class/leds/nuc::front1 + |-- blink_behavior + |-- blink_frequency + |-- brightness + |-- color + |-- ethernet_type + |-- hdd_default + |-- indicator + |-- max_brightness + |-- power_limit_scheme + |-- ready_mode_blink_behavior + |-- ready_mode_blink_frequency + |-- ready_mode_brightness + |-- s0_blink_behavior + |-- s0_blink_frequency + |-- s0_brightness + |-- s3_blink_behavior + |-- s3_blink_frequency + |-- s3_brightness + |-- s5_blink_behavior + |-- s5_blink_frequency + `-- s5_brightness + +The sessions below will explain the meaning of each aspect of the API. + +.. note:: + + 1. any user can read the LEDs parameter; + 2. changing a LED parameter is limited to the owner of the sysfs device + nodes (usually, the ``root`` user); + 3. changing a LED parameter is case-insensitive; + 4. The LED ``indicator`` parameter controls the function of the LED. + All other parameters can be enabled or disabled in runtime, depending + on it. When a certain parameter is disabled, an error code will be + returned; + 5. The hardware and its firmware actually controls the LED. The interfa= ce + provided by the driver just changes the LED settings in runtime. + Such changes can persist even after rebooting. + +LED indicator +------------- + +Despite the LED's name, the LED API may allow them to indicate different +hardware events. + +This is controlled via the ``indicator`` device node. Reading from it disp= lays +all the supported events for a giving LED, and the currently ative one:: + + $ cat /sys/class/leds/nuc::front1/indicator + Power State [HDD Activity] Ethernet WiFi Software Power Limit Di= sable + +Each LED may support the following indicator types: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Indicator type Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Power State Shows if the device is powered and what power level + it is (e. g. if the device is suspended or not, and + on which kind of suspended level). + HDD Activity Indicates if the LED is measuring the hard disk (or + SDD) activity. + Ethernet Indicates the activity Ethernet adapter(s) + WiFi Indicates if WiFi is enabled + Software Doesn't indicate any hardware level. Instead, the LED + status is controlled via software. + Power Limit Changes the LED color when the computer is throttling + its power limits. + Disable The LED was disabled. + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +In order to change the type of indicator, you should +just write a new value to the indicator type:: + + # echo "wifi" > /sys/class/leds/nuc::front1/indicator + + $ cat /sys/class/leds/nuc::front1/indicator + Power State HDD Activity Ethernet [WiFi] Software Power Limit Di= sable + + +Power State parameters +---------------------- + +When the LED indicator is measuring *Power State*, the following parameters +may be available: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Parameter Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + _brightness Brightness in percent (from 0 to 100) + _blink_behavior type of blink. + See :ref:`nuc_blink_behavior`. + _blink_frequency Blink frequency. + See :ref:`nuc_blink_behavior`. + _color LED color + See :ref:`nuc_color`. + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Where can be: + +On NUC8/9 API: + + +------------+ + | S0 | + +------------+ + | S3 | + +------------+ + | S5 | + +------------+ + | Ready mode | + +------------+ + +On NUC10 API: + + +------------+ + | S0 | + +------------+ + | S3 | + +------------+ + | Standby | + +------------+ + +HDD Activity parameters +----------------------- + +When the LED indicator is measuring *HDD Activity*, the following paramete= rs +may be available: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Parameter Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + brightness Brightness in percent (from 0 to 100) + color LED color. + See :ref:`nuc_color`. + hdd_default Default is LED turned ON or OFF. + When set toOFF, the LED will turn on + at disk activity. + When set to ON, the LED will be turned + on by default, turning off at disk + activity. + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Ethernet parameters +------------------- + +When the LED indicator is measuring *Ethernet*, the following parameters +may be available: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Parameter Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + brightness Brightness in percent (from 0 to 100) + color LED color. + See :ref:`nuc_color`. + ethernet_type What Ethernet interface is monitored. + Can be: + LAN1, LAN2 or LAN1+LAN2. + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Power limit parameters +---------------------- + +When the LED indicator is measuring *Power limit*, the following parameters +may be available: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Parameter Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + brightness Brightness in percent (from 0 to 100) + color LED color. + See :ref:`nuc_color`. + power_limit_scheme Indication scheme can be either: + - green to red + - single color + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +.. _nuc_color: + +NUC LED colors +-------------- + +The NUC LED API may support 3 types of LEDs: + +- Mono-colored LEDs; +- Dual-colored LEDs; +- multi-colored LEDs (only on NUC6/7); +- RGB LEDs. + +Also, when a let is set to be a *Power limit* indicator, despite the +physical device's LED color, the API may limit it to be a led that +can display only green and red, or just a single color. + +The ``color`` and ``_color`` parameter supports all those +different settings. + +The color parameter can be set to those values: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D + Color name Red Green Blue + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D + blue 0 0 255 + amber 255 191 0 + white 255 255 255 + red 255 0 0 + green 0 255 0 + yellow 255 255 0 + cyan 0 255 255 + magenta 255 0 255 + ,, + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D + +The color parameter will refuse to set a LED on a color that it is not +supported by the hardware or when the setting is incompatible with the +indicator type. So, when the indicator is set to *Power limit*, and +the ``power_limit_scheme`` is set to ``green to red``, it doesn't +let to set the LED's color. + +On the other hand, the behavior is identical if a color is written using +the color's name or its RGB value. + +So:: + + $ cat /sys/class/leds/nuc::front1/color + red + # echo "green" > /sys/class/leds/nuc::front1/color + $ cat /sys/class/leds/nuc::front1/color + green + # echo "255,0,0" > /sys/class/leds/nuc::front1/color + $ cat /sys/class/leds/nuc::front1/color + red + +.. _nuc_blink_behavior: + +NUC Blink behavior +------------------ + +The NUC LEDs hardware supports the following types of blink behavior: + + +------------+ + | Solid | + +------------+ + | Breathing | + +------------+ + | Pulsing | + +------------+ + | Strobing | + +------------+ + +Changing the blink behavior will change how the led will be turning +on and off when blinking. Setting it to ``Solid`` disables blinking. + +Please notice that not all types of indicator supports blinking. + +When blinking, the blink frequency can be changed via ``blink_frequency`` +or ``_blink_frequency``, depending on the indicator. + +Setting it allows to change the blink frequency in Hz, ranging from 0.1 Hz +to 1.0 Hz, in multiples of 0.1 Hz. --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350915; cv=none; d=zohomail.com; s=zohoarc; b=ePxbH5zDh9q/CTB8g/tO7i1UlvUXA+jr1+JO/xtX21vTtaCN99FkkRvvQJ60SeAm1KmWxqIxJfGnosJkEY0wY3dZxflvzyXPz6EFgVykcwKFlBHtKcQtX/p9FdgH3TGB5GFVBLAhXt0lTdHZqbDupu4/HaEp9kDLYwdQion81Qk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350915; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=504oRcWg//BFm2A93L98pjHoF2N7BIKL0foVw0LnfUU=; b=MVhAeNB0URSTO7bcFI2HZ9pkEoSE30QLMkFK48CHThr8N88x3jglbOlrfkxKzbagzXN1U9QqiJVjufFDkNXWyO0brlPucmAM5Bk1EkxnHf2MTq8JoOUGrtqCgvE9uacAs7o0Ab/BbTfF5RjfucTCJd8jN79EIe2Bk0h9JMK9jAY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350915683911.393649222727; Tue, 18 May 2021 08:15:15 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350064AbhERPMY (ORCPT ); Tue, 18 May 2021 11:12:24 -0400 Received: from mail.kernel.org ([198.145.29.99]:49582 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344884AbhERPKb (ORCPT ); Tue, 18 May 2021 11:10:31 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1F17E61353; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HO1-0V; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=OgCUxWUT+5/bhavISOf/ZnGzda+Vo5Mq0/2DW/bkllw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z71+8qSraqX5vMGaXYIbV2zNBrCAyMVq161Xhl+qlReDbhO6muB3NgUskVZeHRYgC gCNC0eWtDqQ6EmRApVX2Eoratv4ed1Z4sJbY6olL+1e9WeaxdQNCgQQZGpWIzNRwio CzD2o81ySsdYF1eynXGvDmuph+aqynyGRorjfOq0vcIoOkSr5VGB8g6FiBeZXdQbQh u0Mxi0eWrUfb6lsfLE5bU1uGU/JVd8O4h44m5F/RhrMGFD9+684m4HurAVTIt7YHED TndMRDJtDJrnf6/o3oETAMrn77Jo7X17KEcbqUKnR0L0ykll6cCb1Y3ECRp250sLVH iTb0cfOu5ZnXA== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 02/17] leds: add support for NUC WMI LEDs Date: Tue, 18 May 2021 17:08:51 +0200 Message-Id: <69b8623fe70f9bc636d5cd42d56c7f646f3bbf19.1621349813.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Some Intel Next Unit of Computing (NUC) machines have software-configured LEDs that can be used to display a variety of events: - Power State - HDD Activity - Ethernet - WiFi - Power Limit They can even be controlled directly via software, without any hardware-specific indicator connected into them. Some devices have mono-colored LEDs, but the more advanced ones have RGB leds that can show any color. Different color and 4 blink states can be programmed for thee system states: - powered on (S0); - S3; - Standby. The NUC BIOSes allow to partially set them for S0, but doesn't provide any control for the other states, nor does allow changing the blinking logic. They all use a WMI interface using GUID: 8C5DA44C-CDC3-46b3-8619-4E26D34390B7 But there are 3 different revisions of the spec, all using the same GUID, but two different APIs: - the original one, for NUC6 and to NUCi7: - https://www.intel.com/content/www/us/en/support/articles/000023426/intel= -nuc/intel-nuc-kits.html - a new one, starting with NUCi8, with two revisions: - https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/INTE= L_WMI_LED_0.64.pdf - https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-= Spec-Intel-NUC-NUC10ixFNx.pdf There are some OOT drivers for them, but they use procfs and use a messy interface to setup it. Also, there are different drivers with the same name, each with support for each NUC family. Let's start a new driver from scratch, using the x86 platform WMI core and the LED class. This initial version is compatible with NUCi8 and above, and it was tested with a Hades Canyon NUC (NUC8i7HNK). It provides just the more basic WMI support, allowing to change the LED hardware/firmware indicator for each LED in runtime. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 + drivers/leds/Kconfig | 8 + drivers/leds/Makefile | 1 + drivers/leds/leds-nuc.c | 481 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 497 insertions(+) create mode 100644 drivers/leds/leds-nuc.c diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..316f0e552ca6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13063,6 +13063,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/g= it/aia21/ntfs.git F: Documentation/filesystems/ntfs.rst F: fs/ntfs/ =20 +NUC LED DRIVER +M: Mauro Carvalho Chehab +L: linux-leds@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git +F: drivers/staging/nuc-led + NUBUS SUBSYSTEM M: Finn Thain L: linux-m68k@lists.linux-m68k.org diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 49d99cb084db..f5b7f7a02df5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -271,6 +271,14 @@ config LEDS_MT6323 This option enables support for on-chip LED drivers found on Mediatek MT6323 PMIC. =20 +config LEDS_NUC_WMI + tristate "LED Support for Intel NUC" + depends on LEDS_CLASS + depends on ACPI_WMI + help + This option enables support for the WMI interface for LEDs + present on certain Intel NUC models. + config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7e604d3028c8..11a4d29bf9a0 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_LEDS_MT6323) +=3D leds-mt6323.o obj-$(CONFIG_LEDS_NET48XX) +=3D leds-net48xx.o obj-$(CONFIG_LEDS_NETXBIG) +=3D leds-netxbig.o obj-$(CONFIG_LEDS_NIC78BX) +=3D leds-nic78bx.o +obj-$(CONFIG_LEDS_NUC_WMI) +=3D leds-nuc.o obj-$(CONFIG_LEDS_NS2) +=3D leds-ns2.o obj-$(CONFIG_LEDS_OT200) +=3D leds-ot200.o obj-$(CONFIG_LEDS_PCA9532) +=3D leds-pca9532.o diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c new file mode 100644 index 000000000000..69bab319122e --- /dev/null +++ b/drivers/leds/leds-nuc.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Intel NUC WMI Control WMI Driver + * + * Currently, it implements only the LED support + * + * Copyright(c) 2021 Mauro Carvalho Chehab + * + * Inspired on WMI from https://github.com/nomego/intel_nuc_led + * + * It follows this spec: + * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI= -Spec-Intel-NUC-NUC10ixFNx.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NUC_LED_WMI_GUID "8C5DA44C-CDC3-46B3-8619-4E26D34390B7" + +#define MAX_LEDS 7 +#define NUM_INPUT_ARGS 4 +#define NUM_OUTPUT_ARGS 3 + +enum led_cmds { + LED_QUERY =3D 0x03, + LED_NEW_GET_STATUS =3D 0x04, + LED_SET_INDICATOR =3D 0x05, + LED_SET_VALUE =3D 0x06, + LED_NOTIFICATION =3D 0x07, + LED_SWITCH_TYPE =3D 0x08, +}; + +enum led_query_subcmd { + LED_QUERY_LIST_ALL =3D 0x00, + LED_QUERY_COLOR_TYPE =3D 0x01, + LED_QUERY_INDICATOR_OPTIONS =3D 0x02, + LED_QUERY_CONTROL_ITEMS =3D 0x03, +}; + +enum led_new_get_subcmd { + LED_NEW_GET_CURRENT_INDICATOR =3D 0x00, + LED_NEW_GET_CONTROL_ITEM =3D 0x01, +}; + +/* LED color indicator */ +#define LED_BLUE_AMBER BIT(0) +#define LED_BLUE_WHITE BIT(1) +#define LED_RGB BIT(2) +#define LED_SINGLE_COLOR BIT(3) + +/* LED indicator options */ +#define LED_IND_POWER_STATE BIT(0) +#define LED_IND_HDD_ACTIVITY BIT(1) +#define LED_IND_ETHERNET BIT(2) +#define LED_IND_WIFI BIT(3) +#define LED_IND_SOFTWARE BIT(4) +#define LED_IND_POWER_LIMIT BIT(5) +#define LED_IND_DISABLE BIT(6) + +static const char * const led_names[] =3D { + "nuc::power", + "nuc::hdd", + "nuc::skull", + "nuc::eyes", + "nuc::front1", + "nuc::front2", + "nuc::front3", +}; + +struct nuc_nmi_led { + struct led_classdev cdev; + struct device *dev; + u8 id; + u8 indicator; + u32 color_type; + u32 avail_indicators; + u32 control_items; +}; + +struct nuc_wmi { + struct nuc_nmi_led led[MAX_LEDS * 3]; /* Worse case: RGB LEDs */ + int num_leds; + + /* Avoid concurrent access to WMI */ + struct mutex wmi_lock; +}; + +static int nuc_nmi_led_error(u8 error_code) +{ + switch (error_code) { + case 0: + return 0; + case 0xe1: /* Function not support */ + return -ENOENT; + case 0xe2: /* Undefined device */ + return -ENODEV; + case 0xe3: /* EC no respond */ + return -EIO; + case 0xe4: /* Invalid Parameter */ + return -EINVAL; + case 0xef: /* Unexpected error */ + return -EFAULT; + + /* Revision 1.0 Errors */ + case 0xe5: /* Node busy */ + return -EBUSY; + case 0xe6: /* Destination device is disabled or unavailable */ + return -EACCES; + case 0xe7: /* Invalid CEC Opcode */ + return -ENOENT; + case 0xe8: /* Data Buffer size is not enough */ + return -ENOSPC; + + default: /* Reserved */ + return -EPROTO; + } +} + +static int nuc_nmi_cmd(struct device *dev, + u8 cmd, + u8 input_args[NUM_INPUT_ARGS], + u8 output_args[NUM_OUTPUT_ARGS]) +{ + struct acpi_buffer output =3D { ACPI_ALLOCATE_BUFFER, NULL }; + struct nuc_wmi *priv =3D dev_get_drvdata(dev); + struct acpi_buffer input; + union acpi_object *obj; + acpi_status status; + int size, ret; + u8 *p; + + input.length =3D NUM_INPUT_ARGS; + input.pointer =3D input_args; + + mutex_lock(&priv->wmi_lock); + status =3D wmi_evaluate_method(NUC_LED_WMI_GUID, 0, cmd, + &input, &output); + mutex_unlock(&priv->wmi_lock); + if (ACPI_FAILURE(status)) { + dev_warn(dev, "cmd %02x (%*ph): ACPI failure: %d\n", + cmd, (int)input.length, input_args, ret); + return status; + } + + obj =3D output.pointer; + if (!obj) { + dev_warn(dev, "cmd %02x (%*ph): no output\n", + cmd, (int)input.length, input_args); + return -EINVAL; + } + + if (obj->type =3D=3D ACPI_TYPE_BUFFER) { + if (obj->buffer.length < NUM_OUTPUT_ARGS + 1) { + ret =3D -EINVAL; + goto err; + } + p =3D (u8 *)obj->buffer.pointer; + } else if (obj->type =3D=3D ACPI_TYPE_INTEGER) { + p =3D (u8 *)&obj->integer.value; + } else { + return -EINVAL; + } + + ret =3D nuc_nmi_led_error(p[0]); + if (ret) { + dev_warn(dev, "cmd %02x (%*ph): WMI error code: %02x\n", + cmd, (int)input.length, input_args, p[0]); + goto err; + } + + size =3D NUM_OUTPUT_ARGS + 1; + + if (output_args) { + memcpy(output_args, p + 1, NUM_OUTPUT_ARGS); + + dev_info(dev, "cmd %02x (%*ph), return: %*ph\n", + cmd, (int)input.length, input_args, NUM_OUTPUT_ARGS, output_args); + } else { + dev_info(dev, "cmd %02x (%*ph)\n", + cmd, (int)input.length, input_args); + } + +err: + kfree(obj); + return ret; +} + +static int nuc_wmi_query_leds(struct device *dev) +{ + struct nuc_wmi *priv =3D dev_get_drvdata(dev); + u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int i, id, ret; + u8 leds; + + /* + * List all LED types support in the platform + * + * Should work with both NUC8iXXX and NUC10iXXX + * + * FIXME: Should add a fallback code for it to work with older NUCs, + * as LED_QUERY returns an error on older devices like Skull Canyon. + */ + cmd =3D LED_QUERY; + input[0] =3D LED_QUERY_LIST_ALL; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d while listing all LEDs\n", ret); + return ret; + } + + leds =3D output[0]; + if (!leds) { + dev_warn(dev, "No LEDs found\n"); + return -ENODEV; + } + + for (id =3D 0; id < MAX_LEDS; id++) { + struct nuc_nmi_led *led =3D &priv->led[priv->num_leds]; + + if (!(leds & BIT(id))) + continue; + + led->id =3D id; + + cmd =3D LED_QUERY; + input[0] =3D LED_QUERY_COLOR_TYPE; + input[1] =3D id; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->color_type =3D output[0] | + output[1] << 8 | + output[2] << 16; + + cmd =3D LED_NEW_GET_STATUS; + input[0] =3D LED_NEW_GET_CURRENT_INDICATOR; + input[1] =3D i; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->indicator =3D output[0]; + + cmd =3D LED_QUERY; + input[0] =3D LED_QUERY_INDICATOR_OPTIONS; + input[1] =3D i; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->avail_indicators =3D output[0] | + output[1] << 8 | + output[2] << 16; + + cmd =3D LED_QUERY; + input[0] =3D LED_QUERY_CONTROL_ITEMS; + input[1] =3D i; + input[2] =3D led->indicator; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->control_items =3D output[0] | + output[1] << 8 | + output[2] << 16; + + dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %06x, control i= tems: %06x\n", + led_names[led->id], led->id, + led->color_type, led->indicator, led->control_items); + + priv->num_leds++; + } + + return 0; +} + +/* + * LED show/store routines + */ + +#define LED_ATTR_RW(_name) \ + DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) + +static const char * const led_indicators[] =3D { + "Power State", + "HDD Activity", + "Ethernet", + "WiFi", + "Software", + "Power Limit", + "Disable" +}; + +static ssize_t show_indicator(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int size =3D PAGE_SIZE; + char *p =3D buf; + int i, n; + + for (i =3D 0; i < fls(led->avail_indicators); i++) { + if (!(led->avail_indicators & BIT(i))) + continue; + if (i =3D=3D led->indicator) + n =3D scnprintf(p, size, "[%s] ", led_indicators[i]); + else + n =3D scnprintf(p, size, "%s ", led_indicators[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_indicator(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + const char *tmp; + int ret, i; + + tmp =3D strsep((char **)&buf, "\n"); + + for (i =3D 0; i < fls(led->avail_indicators); i++) { + if (!(led->avail_indicators & BIT(i))) + continue; + + if (!strcasecmp(tmp, led_indicators[i])) { + cmd =3D LED_SET_INDICATOR; + input[0] =3D led->id; + input[1] =3D i; + + dev_dbg(dev, "set led %s indicator to %s\n", + cdev->name, led_indicators[i]); + + ret =3D nuc_nmi_cmd(dev, cmd, input, NULL); + if (ret) + return ret; + + led->indicator =3D i; + + return len; + } + } + + return -EINVAL; +} + +static LED_ATTR_RW(indicator); + +/* + * Attributes for multicolor LEDs + */ + +static struct attribute *nuc_wmi_multicolor_led_attr[] =3D { + &dev_attr_indicator.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_attribute_group =3D { + .attrs =3D nuc_wmi_multicolor_led_attr, +}; + +static const struct attribute_group *nuc_wmi_led_attribute_groups[] =3D { + &nuc_wmi_led_attribute_group, + NULL +}; + +static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *le= d) +{ + led->cdev.name =3D led_names[led->id]; + + led->dev =3D dev; + led->cdev.groups =3D nuc_wmi_led_attribute_groups; + + /* + * It can't let the classdev to manage the brightness due to several + * reasons: + * + * 1) classdev has some internal logic to manage the brightness, + * at set_brightness_delayed(), which starts disabling the LEDs; + * While this makes sense on most cases, here, it would appear + * that the NUC was powered off, which is not what happens; + * 2) classdev unconditionally tries to set brightness for all + * leds, including the ones that were software-disabled or + * disabled disabled via BIOS menu; + * 3) There are 3 types of brightness values for each LED, depending + * on the CPU power state: S0, S3 and S5. + * + * So, the best seems to export everything via sysfs attributes + * directly. This would require some further changes at the + * LED class, though, or we would need to create our own LED + * class, which seems wrong. + */ + + return devm_led_classdev_register(dev, &led->cdev); +} + +static int nuc_wmi_leds_setup(struct device *dev) +{ + struct nuc_wmi *priv =3D dev_get_drvdata(dev); + int ret, i; + + ret =3D nuc_wmi_query_leds(dev); + if (ret) + return ret; + + for (i =3D 0; i < priv->num_leds; i++) { + ret =3D nuc_wmi_led_register(dev, &priv->led[i]); + if (ret) { + dev_err(dev, "Failed to register led %d: %s\n", + i, led_names[priv->led[i].id]); + while (--i >=3D 0) + devm_led_classdev_unregister(dev, &priv->led[i].cdev); + + return ret; + } + } + return 0; +} + +static int nuc_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct device *dev =3D &wdev->dev; + struct nuc_wmi *priv; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + mutex_init(&priv->wmi_lock); + + dev_set_drvdata(dev, priv); + + ret =3D nuc_wmi_leds_setup(dev); + if (ret) + return ret; + + dev_info(dev, "NUC WMI driver initialized.\n"); + return 0; +} + +static const struct wmi_device_id nuc_wmi_descriptor_id_table[] =3D { + { .guid_string =3D NUC_LED_WMI_GUID }, + { }, +}; + +static struct wmi_driver nuc_wmi_driver =3D { + .driver =3D { + .name =3D "nuc-wmi", + }, + .probe =3D nuc_wmi_probe, + .id_table =3D nuc_wmi_descriptor_id_table, +}; + +module_wmi_driver(nuc_wmi_driver); + +MODULE_DEVICE_TABLE(wmi, nuc_wmi_descriptor_id_table); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("Intel NUC WMI LED driver"); +MODULE_LICENSE("GPL"); --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350566; cv=none; d=zohomail.com; s=zohoarc; b=FHknf5bFQPaznFTfUy19uC7NXm79vMlomxvQbx/xMKtVvdQB1hPFtpBshVBlCo5FnqaJ3KIBbrswOWiKFDMBOxOtwRu4Ged77/m+WrlJ2uxWZ3uJFGaKDOWUeeMS5bZXDN5qEQmcEcwhK07u/Q0Sji1gXQooyou7RJ4t4dqwB0U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350566; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=DmB6H/dz8pDtBdS+AWX0UorzNSpyzvAZFiSqiNAO/Oc=; b=GlC/uo7eDczAXOQE3AhGMmm9fURuZynhkuz/BX6tidF3K4KrLZsHGtDnP65GfOgVzN7rtw0IZqUTM5pYC8mNLkFQYc1kRpn96rsO4lUpQIVWmkxhgBIns59YitGgTqJAISZmEEnwvOofCAnDqk6xn4UsIVGQSCmIwVFtPqicahI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350566723233.86527196470024; Tue, 18 May 2021 08:09:26 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345041AbhERPKh (ORCPT ); Tue, 18 May 2021 11:10:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:49412 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237974AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1C4AC61042; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HO6-2k; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=IPk6MBpB/XcYX8hxt1d+r0HxwF2eMb4v4R5nHNEAMoA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o9MbXM51OrGYylej2Azv0sWdy0oIXvObDT9T1v/FiizWiyNlbwE2kaQmcgJr0CW2d EUzyBl8A35i409JCm22FvwTjF0KkY34l3ScM3VzOERiTMMBUgm9PV/GQ+bcIRshywi DFixOHyA9y+PoJKBWE2IgI49Qggjm3opWocxYgJannksbgI5ElhYkaKE8xCNB0MLVs Jole2D+301QF8mp8GoIcPxxE3LRdFrtSsUmHkc2v73ESPUUnZI7ObWozbJRdN5+Bzm D7kAMlrU4tm3ta1M6bjHCZ3ln0MaKzvuN1ajkWAB4MY2v81NANduVXhRlfTPlWATjp g5l2sHDVFyfBQ== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 03/17] leds: leds-nuc: detect WMI API detection Date: Tue, 18 May 2021 17:08:52 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" There are currently 3 known API releases: - https://www.intel.com/content/www/us/en/support/articles/0000= 23426/intel-nuc/intel-nuc-kits.html - https://raw.githubusercontent.com/nomego/intel_nuc_led/master= /specs/INTEL_WMI_LED_0.64.pdf - https://www.intel.com/content/dam/support/us/en/documents/int= el-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf Add a logic to detect between them, preventing the driver to work with an unsupported version. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 69bab319122e..26bc4a4bb57c 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -26,6 +26,13 @@ #define NUM_INPUT_ARGS 4 #define NUM_OUTPUT_ARGS 3 =20 +enum led_api_rev { + LED_API_UNKNOWN, + LED_API_NUC6, + LED_API_REV_0_64, + LED_API_REV_1_0, +}; + enum led_cmds { LED_QUERY =3D 0x03, LED_NEW_GET_STATUS =3D 0x04, @@ -33,6 +40,7 @@ enum led_cmds { LED_SET_VALUE =3D 0x06, LED_NOTIFICATION =3D 0x07, LED_SWITCH_TYPE =3D 0x08, + LED_VERSION_CONTROL =3D 0x09, }; =20 enum led_query_subcmd { @@ -195,7 +203,7 @@ static int nuc_wmi_query_leds(struct device *dev) struct nuc_wmi *priv =3D dev_get_drvdata(dev); u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int i, id, ret; + int i, id, ret, ver =3D LED_API_UNKNOWN; u8 leds; =20 /* @@ -209,12 +217,31 @@ static int nuc_wmi_query_leds(struct device *dev) cmd =3D LED_QUERY; input[0] =3D LED_QUERY_LIST_ALL; ret =3D nuc_nmi_cmd(dev, cmd, input, output); - if (ret) { + if (ret =3D=3D -ENOENT) { + ver =3D LED_API_NUC6; + } else if (ret) { dev_warn(dev, "error %d while listing all LEDs\n", ret); return ret; + } else { + leds =3D output[0]; } =20 - leds =3D output[0]; + if (ver !=3D LED_API_NUC6) { + ret =3D nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); + if (ret) + return ret; + + ver =3D output[0] | output[1] << 16; + if (!ver) + ver =3D LED_API_REV_0_64; + else if (ver =3D=3D 0x0126) + ver =3D LED_API_REV_1_0; + } + + /* Currently, only API Revision 0.64 is supported */ + if (ver !=3D LED_API_REV_0_64) + return -ENODEV; + if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350595; cv=none; d=zohomail.com; s=zohoarc; b=LEdt/G6cASnes8XggAmK6YCMIgeMqfni9dNxAl++saNDUDVqtlL58H/Xpr6f4EZQDKCPaVRe79eO9ramHALSZ87CPNvM3TSnDPnBQfhSPzC1+pDUlZ8gfQt7vWmak1X2eNnmijMvmPstE1HM3uSaB1g1v7J00SLVpi5/YSs3zWk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350595; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=j2zZQ8fyBCWRGgLdETzNBkBgMa4nwdpqhZnWizPhPVg=; b=gWtGSsEJZuETyI0bqBDaRjxUeEzXNzQCM9Z19odFt1U0lkCAP5lRUHCHDbZga6F8AJ2bVIhWGiWRh+0eFIWrpvgkv1ynDt4C/4L9SUF7ClfDXT8m6XoIE2+zFSrAmpfT2JZRlQFWcovl2Ee7qtJPIq8gZ8qsBFETXHVf+pjE+gE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350595800321.32121017385634; Tue, 18 May 2021 08:09:55 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350022AbhERPLK (ORCPT ); Tue, 18 May 2021 11:11:10 -0400 Received: from mail.kernel.org ([198.145.29.99]:49434 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242078AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2CEF56135F; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOA-3x; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=zalE66nfGhQobchmfKxHkP0DtHaHCBxHlfx2X/n5+SI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=t9+aBhqb3vZJzssCN62R+RRU2EA8QxHzEqL1ecvAHVqmnlikdlrj4jtpXVx7ZUKPg of5X9EoeGL6/UZ/wsM4A1jtUKx1TC4Bitz4xgLUYnlKXXZqa+12dR8jnCiGdxBJFRF BfiYIlzvpXM/iXOe0F3rqveSMtoNlIoopdniGgjP/l1DO4l1fvewySEMvTK8PBIqxH VGid3j+pg4NjOLKF3spmTWhowrpVQn7jAaJRsX7ifOzt5kOb8SYhfhUMvwOm5Skztj +jn7znsE7DtBibjlbDD4WfFCenkIzyPL/wtb8fe3JYLCBkZ4cUZPnkHKnP9WGPp+91 kN+l/+CJGeq2Q== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 04/17] leds: leds-nuc: add support for changing S0 brightness Date: Tue, 18 May 2021 17:08:53 +0200 Message-Id: <443c059cc4ff153bf95cb36ed02a34d2d57e20c9.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Now that the core logic is in place, let's add support to adjust the S0 brightness level. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 26bc4a4bb57c..e12fa2e7a488 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -395,7 +395,85 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } =20 +/* Get S0 brightness */ +static ssize_t show_s0_brightness(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ret; + + cmd =3D LED_NEW_GET_STATUS; + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D 0; + + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) + return ret; + + /* Multicolor uses a scale from 0 to 100 */ + if (led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB)) + return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0]); + + /* single color uses 0, 50% and 100% */ + return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0] * 50); +} + +/* Change S0 brightness */ +static ssize_t store_s0_brightness(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + int ret; + u8 val; + + if (led->indicator =3D=3D LED_IND_DISABLE) { + dev_dbg(dev, "Led %s is disabled. ignoring it.\n", cdev->name); + return -EACCES; + } + + if (kstrtou8(buf, 0, &val) || val > 100) + return -EINVAL; + + /* + * For single-color LEDs, the value should be between 0 to 2, but, + * in order to have a consistent API, let's always handle it as if + * it is a percentage, for both multicolor and single color LEDs. + * So: + * value =3D=3D 0 will disable the LED + * value up to 74% will set it the brightness to 50% + * value equal or above 75% will use the maximum brightness. + */ + if (!(led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB))) { + if (val > 0 && val < 75) + val =3D 1; + if (val >=3D 75) + val =3D 2; + } + + cmd =3D LED_SET_VALUE; + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D 0; /* FIXME: replace by an enum */ + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, cmd, input, NULL); + if (ret) + return ret; + + return len; +} + static LED_ATTR_RW(indicator); +static LED_ATTR_RW(s0_brightness); =20 /* * Attributes for multicolor LEDs @@ -403,6 +481,7 @@ static LED_ATTR_RW(indicator); =20 static struct attribute *nuc_wmi_multicolor_led_attr[] =3D { &dev_attr_indicator.attr, + &dev_attr_s0_brightness.attr, NULL, }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350939; cv=none; d=zohomail.com; s=zohoarc; b=QSx0JJXCGEc7piJFeXxqRCuFiQv1a0RSVAjyail2oFysQg1RIrNu6bv0YMUvqDQ4Cx55ap7K1F2juAXRWNh95DmQT3g5hrwiX/H72iRWC1LpOlvBhewX5TkktF1BXrACwRxyf8wr/k8iI+Q+rUcPuYkNXvRqK8HdqtdYbDVGykI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350939; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=AHl59BlW75kXm/hBYNQC5HFuAalIqPIQvFR3oYu9D58=; b=fm2nJsaaE4faFA7jTpAiZW9RzY5j0n/3XQMP52vgb9iU8qmnospsEddjOlCjrqc9BJYNwndBNvIOccxIcm5HSUZYb4bcR4he36WynUMrPhalVO6rPyBZ70zkwq7Hp45ObatiPLK3UeNskvpf9CSxSmTdjJgBdrdUaEuWUeyrRCc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350939012291.5667132781257; Tue, 18 May 2021 08:15:39 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350161AbhERPMo (ORCPT ); Tue, 18 May 2021 11:12:44 -0400 Received: from mail.kernel.org ([198.145.29.99]:49660 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345056AbhERPKh (ORCPT ); Tue, 18 May 2021 11:10:37 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2A64561355; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOE-5B; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=gLdwdgyLLaR+xP/SNPgHYHTQ7ptcIkwGqK9Ot6um84c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Is0Csuf7ynpzMQrsLhZbi7o6qiZMtO/rOt+f8EysmnH2KLFTIj1tfcXsZ/aJNBKrR ya4+psHNNowXiqDJ9eYXQTiJbIXJusl9Xs1nxE6TIXU7fprNcgB1hTjkVkb9L1A7mo B/Ki5VrZ4Q788tAFASu7VPXubZjI0FOYOYaaWR3LP6imNaUXEOAQ2+1lpv4Fc8/AI+ 9kfoTCzSpPDtIJYZ6+d0IBCrmoKquO6D5RizmJPAHg4T2Jh33Vmm7/y+Ejv31v3a7K YYnurB0sbkBceG8YR9nS70/Y/rxDxTYj2oVjKfQzW492cP3lUoNtNv0RuQhfevUFVa Beuty5tMGZoFw== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 05/17] leds: leds-nuc: add all types of brightness Date: Tue, 18 May 2021 17:08:54 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Improve the logic in order to support not only S0 brightness, but also the brightness for other indicators and for all power states. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 369 +++++++++++++++++++++++++++------------- 1 file changed, 249 insertions(+), 120 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index e12fa2e7a488..df65bf17e0e6 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -55,21 +55,89 @@ enum led_new_get_subcmd { LED_NEW_GET_CONTROL_ITEM =3D 0x01, }; =20 +enum led_function { + LED_FUNC_BRIGHTNESS, + LED_FUNC_COLOR1, + LED_FUNC_COLOR_GREEN, + LED_FUNC_COLOR_BLUE, + + LED_FUNC_BLINK_BEHAVIOR, + LED_FUNC_BLINK_FREQ, + + LED_FUNC_HDD_BEHAVIOR, + LED_FUNC_ETH_TYPE, + LED_FUNC_POWER_LIMIT_SCHEME, + + MAX_LED_FUNC +}; + +enum led_indicators { + LED_IND_POWER_STATE, + LED_IND_HDD_ACTIVITY, + LED_IND_ETHERNET, + LED_IND_WIFI, + LED_IND_SOFTWARE, + LED_IND_POWER_LIMIT, + LED_IND_DISABLE, + + MAX_IND =3D LED_IND_DISABLE +}; + +/* + * control items ID for each of the valid indicators on spec Rev 0.64. + */ +static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] =3D { + [LED_IND_POWER_STATE] =3D { /* Offsets for each power state */ + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, + [LED_FUNC_BLINK_FREQ] =3D 0x02, + [LED_FUNC_COLOR1] =3D 0x03, + [LED_FUNC_COLOR_GREEN] =3D 0x04, + [LED_FUNC_COLOR_BLUE] =3D 0x05 + }, + [LED_IND_HDD_ACTIVITY] =3D { + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_COLOR1] =3D 0x01, + [LED_FUNC_COLOR_GREEN] =3D 0x02, + [LED_FUNC_COLOR_BLUE] =3D 0x03, + [LED_FUNC_HDD_BEHAVIOR] =3D 0x04 + }, + [LED_IND_ETHERNET] =3D { + [LED_FUNC_ETH_TYPE] =3D 0x00, + [LED_FUNC_BRIGHTNESS] =3D 0x01, + [LED_FUNC_COLOR1] =3D 0x02, + [LED_FUNC_COLOR_GREEN] =3D 0x03, + [LED_FUNC_COLOR_BLUE] =3D 0x04 + }, + [LED_IND_WIFI] =3D { + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_COLOR1] =3D 0x01, + [LED_FUNC_COLOR_GREEN] =3D 0x02, + [LED_FUNC_COLOR_BLUE] =3D 0x03 + }, + [LED_IND_SOFTWARE] =3D { + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, + [LED_FUNC_BLINK_FREQ] =3D 0x02, + [LED_FUNC_COLOR1] =3D 0x03, + [LED_FUNC_COLOR_GREEN] =3D 0x04, + [LED_FUNC_COLOR_BLUE] =3D 0x05 + }, + [LED_IND_POWER_LIMIT] =3D { + [LED_FUNC_POWER_LIMIT_SCHEME] =3D 0x00, + [LED_FUNC_BRIGHTNESS] =3D 0x01, + [LED_FUNC_COLOR1] =3D 0x02, + [LED_FUNC_COLOR_GREEN] =3D 0x03, + [LED_FUNC_COLOR_BLUE] =3D 0x04 + }, +}; + /* LED color indicator */ #define LED_BLUE_AMBER BIT(0) #define LED_BLUE_WHITE BIT(1) #define LED_RGB BIT(2) #define LED_SINGLE_COLOR BIT(3) =20 -/* LED indicator options */ -#define LED_IND_POWER_STATE BIT(0) -#define LED_IND_HDD_ACTIVITY BIT(1) -#define LED_IND_ETHERNET BIT(2) -#define LED_IND_WIFI BIT(3) -#define LED_IND_SOFTWARE BIT(4) -#define LED_IND_POWER_LIMIT BIT(5) -#define LED_IND_DISABLE BIT(6) - static const char * const led_names[] =3D { "nuc::power", "nuc::hdd", @@ -87,7 +155,6 @@ struct nuc_nmi_led { u8 indicator; u32 color_type; u32 avail_indicators; - u32 control_items; }; =20 struct nuc_wmi { @@ -201,9 +268,9 @@ static int nuc_nmi_cmd(struct device *dev, static int nuc_wmi_query_leds(struct device *dev) { struct nuc_wmi *priv =3D dev_get_drvdata(dev); - u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + u8 input[NUM_INPUT_ARGS] =3D { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int i, id, ret, ver =3D LED_API_UNKNOWN; + int id, ret, ver =3D LED_API_UNKNOWN; u8 leds; =20 /* @@ -214,9 +281,8 @@ static int nuc_wmi_query_leds(struct device *dev) * FIXME: Should add a fallback code for it to work with older NUCs, * as LED_QUERY returns an error on older devices like Skull Canyon. */ - cmd =3D LED_QUERY; input[0] =3D LED_QUERY_LIST_ALL; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + ret =3D nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret =3D=3D -ENOENT) { ver =3D LED_API_NUC6; } else if (ret) { @@ -255,12 +321,11 @@ static int nuc_wmi_query_leds(struct device *dev) =20 led->id =3D id; =20 - cmd =3D LED_QUERY; input[0] =3D LED_QUERY_COLOR_TYPE; input[1] =3D id; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + ret =3D nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } =20 @@ -268,23 +333,11 @@ static int nuc_wmi_query_leds(struct device *dev) output[1] << 8 | output[2] << 16; =20 - cmd =3D LED_NEW_GET_STATUS; - input[0] =3D LED_NEW_GET_CURRENT_INDICATOR; - input[1] =3D i; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); - if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); - return ret; - } - - led->indicator =3D output[0]; - - cmd =3D LED_QUERY; input[0] =3D LED_QUERY_INDICATOR_OPTIONS; - input[1] =3D i; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + input[1] =3D id; + ret =3D nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } =20 @@ -292,23 +345,18 @@ static int nuc_wmi_query_leds(struct device *dev) output[1] << 8 | output[2] << 16; =20 - cmd =3D LED_QUERY; - input[0] =3D LED_QUERY_CONTROL_ITEMS; - input[1] =3D i; - input[2] =3D led->indicator; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + input[0] =3D LED_NEW_GET_CURRENT_INDICATOR; + input[1] =3D id; + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } + led->indicator =3D output[0]; =20 - led->control_items =3D output[0] | - output[1] << 8 | - output[2] << 16; - - dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %06x, control i= tems: %06x\n", - led_names[led->id], led->id, - led->color_type, led->indicator, led->control_items); + dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %02x (avail %06= x)\n", + led_names[led->id], led->id, led->color_type, + led->indicator, led->avail_indicators); =20 priv->num_leds++; } @@ -316,6 +364,82 @@ static int nuc_wmi_query_leds(struct device *dev) return 0; } =20 +static bool nuc_wmi_test_control(struct device *dev, + struct nuc_nmi_led *led, u8 ctrl) +{ + int ret, avail_ctrls; + u8 output[NUM_OUTPUT_ARGS]; + u8 input[NUM_INPUT_ARGS] =3D { + LED_QUERY_CONTROL_ITEMS, + led->id, + led->indicator + }; + + ret =3D nuc_nmi_cmd(dev, LED_QUERY, input, output); + if (ret) + return false; + + avail_ctrls =3D output[0] | + output[1] << 8 | + output[2] << 16; + + return avail_ctrls & BIT(ctrl); +} + +static int nuc_wmi_get_brightness_offset(struct device *dev, + struct nuc_nmi_led *led, u8 offset) +{ + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + dev_dbg(dev, "%s: id: %02x, brightness: %02x\n", + led_names[led->id], led->id, output[0]); + + return output[0]; +} + +static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, + struct nuc_nmi_led *led, + u8 offset, + u8 val) +{ + u8 input[NUM_INPUT_ARGS]; + int ctrl; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + return nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); +} + /* * LED show/store routines */ @@ -323,6 +447,21 @@ static int nuc_wmi_query_leds(struct device *dev) #define LED_ATTR_RW(_name) \ DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) =20 +#define LED_ATTR_POWER_STATE_RW(_name, offset) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_brightness_offset(dev, attr, offset, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t len) \ + { \ + return store_brightness_offset(dev, attr, offset, buf, len); \ + } \ + static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) + static const char * const led_indicators[] =3D { "Power State", "HDD Activity", @@ -395,98 +534,93 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } =20 -/* Get S0 brightness */ -static ssize_t show_s0_brightness(struct device *dev, - struct device_attribute *attr, - char *buf) +/* Get brightness */ +static ssize_t show_brightness_offset(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) { struct led_classdev *cdev =3D dev_get_drvdata(dev); struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); - u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; - u8 output[NUM_OUTPUT_ARGS]; int ret; =20 - cmd =3D LED_NEW_GET_STATUS; - input[0] =3D LED_NEW_GET_CONTROL_ITEM; - input[1] =3D led->id; - input[2] =3D led->indicator; - input[3] =3D 0; + if (led->indicator !=3D LED_IND_POWER_STATE) + return -ENODEV; =20 - ret =3D nuc_nmi_cmd(dev, cmd, input, output); - if (ret) + ret =3D nuc_wmi_get_brightness_offset(dev, led, offset); + if (ret < 0) return ret; =20 - /* Multicolor uses a scale from 0 to 100 */ - if (led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB)) - return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0]); - - /* single color uses 0, 50% and 100% */ - return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0] * 50); + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } =20 -/* Change S0 brightness */ -static ssize_t store_s0_brightness(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +/* Change brightness */ +static ssize_t store_brightness_offset(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) { struct led_classdev *cdev =3D dev_get_drvdata(dev); struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); - u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; int ret; u8 val; =20 - if (led->indicator =3D=3D LED_IND_DISABLE) { - dev_dbg(dev, "Led %s is disabled. ignoring it.\n", cdev->name); - return -EACCES; - } + if (led->indicator !=3D LED_IND_POWER_STATE) + return -ENODEV; =20 if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; =20 - /* - * For single-color LEDs, the value should be between 0 to 2, but, - * in order to have a consistent API, let's always handle it as if - * it is a percentage, for both multicolor and single color LEDs. - * So: - * value =3D=3D 0 will disable the LED - * value up to 74% will set it the brightness to 50% - * value equal or above 75% will use the maximum brightness. - */ - if (!(led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB))) { - if (val > 0 && val < 75) - val =3D 1; - if (val >=3D 75) - val =3D 2; - } - - cmd =3D LED_SET_VALUE; - input[0] =3D led->id; - input[1] =3D led->indicator; - input[2] =3D 0; /* FIXME: replace by an enum */ - input[3] =3D val; - - ret =3D nuc_nmi_cmd(dev, cmd, input, NULL); + ret =3D nuc_wmi_set_brightness_offset(dev, led, offset, val); if (ret) return ret; =20 return len; } =20 +static enum led_brightness nuc_wmi_get_brightness(struct led_classdev *cde= v) +{ + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->indicator =3D=3D LED_IND_POWER_STATE) + return -ENODEV; + + return nuc_wmi_get_brightness_offset(cdev->dev, led, 0); +} + +static int nuc_wmi_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->indicator =3D=3D LED_IND_POWER_STATE) + return -ENODEV; + + return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); +} + static LED_ATTR_RW(indicator); -static LED_ATTR_RW(s0_brightness); + +LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); +LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); +LED_ATTR_POWER_STATE_RW(s5_brightness, 0x0c); +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); =20 /* - * Attributes for multicolor LEDs + * Attributes for LEDs */ =20 -static struct attribute *nuc_wmi_multicolor_led_attr[] =3D { +static struct attribute *nuc_wmi_led_attr[] =3D { &dev_attr_indicator.attr, &dev_attr_s0_brightness.attr, + &dev_attr_s3_brightness.attr, + &dev_attr_s5_brightness.attr, + &dev_attr_ready_mode_brightness.attr, NULL, }; =20 static const struct attribute_group nuc_wmi_led_attribute_group =3D { - .attrs =3D nuc_wmi_multicolor_led_attr, + .attrs =3D nuc_wmi_led_attr, }; =20 static const struct attribute_group *nuc_wmi_led_attribute_groups[] =3D { @@ -496,30 +630,25 @@ static const struct attribute_group *nuc_wmi_led_attr= ibute_groups[] =3D { =20 static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *le= d) { + int brightness =3D nuc_wmi_get_brightness_offset(dev, led, 0); + led->cdev.name =3D led_names[led->id]; - led->dev =3D dev; led->cdev.groups =3D nuc_wmi_led_attribute_groups; + led->cdev.brightness_get =3D nuc_wmi_get_brightness; + led->cdev.brightness_set_blocking =3D nuc_wmi_set_brightness; =20 - /* - * It can't let the classdev to manage the brightness due to several - * reasons: - * - * 1) classdev has some internal logic to manage the brightness, - * at set_brightness_delayed(), which starts disabling the LEDs; - * While this makes sense on most cases, here, it would appear - * that the NUC was powered off, which is not what happens; - * 2) classdev unconditionally tries to set brightness for all - * leds, including the ones that were software-disabled or - * disabled disabled via BIOS menu; - * 3) There are 3 types of brightness values for each LED, depending - * on the CPU power state: S0, S3 and S5. - * - * So, the best seems to export everything via sysfs attributes - * directly. This would require some further changes at the - * LED class, though, or we would need to create our own LED - * class, which seems wrong. - */ + if (led->color_type & LED_SINGLE_COLOR) + led->cdev.max_brightness =3D 2; + else + led->cdev.max_brightness =3D 100; + + /* Ensure that the current bright will be preserved */ + if (brightness >=3D 0) + led->cdev.delayed_set_value =3D brightness; + + /* Suppress warnings for the LED(s) indicating the power state */ + led->cdev.flags =3D LED_HW_PLUGGABLE | LED_UNREGISTERING; =20 return devm_led_classdev_register(dev, &led->cdev); } --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350899; cv=none; d=zohomail.com; s=zohoarc; b=d3McDQCKQPRGb1UIdCcNIzTqtUUtcpJkwPk3XRbB1xMbWfnZaLVgH6aWOSI4I/atXKLNyBAOB0kgrtQtAZyGGmoothIAYETdjJV3o4GJL6dz48na0WYJETDTitpjltKKSPacRBuKGVqO2ivxr4Rr3u6s7EQ8IX2emyVqBNLebOo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350899; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=eZis3uEDTdqidw0jifwVbf2/3b2PwRYfR2BjL4C8mZ0=; b=Wo9WswGokm9P3Pys1dhSychMGSYrOTS5FP3Q56LBsiC7hSZt1e9HtaYeQoJYlFFlgUw+i8InHvAo3D/V9+tlTLAcf5k0g7hM5XhYbZO1XJxFOZWOBcozr8zm92+lLFPWPGXMvWewrkNiTaZJ+NzLRvtDeMD1P+a4MlvL3k2DdLo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350899970583.1493992237662; Tue, 18 May 2021 08:14:59 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350094AbhERPML (ORCPT ); Tue, 18 May 2021 11:12:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:49524 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343506AbhERPK3 (ORCPT ); Tue, 18 May 2021 11:10:29 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 26C536135C; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOI-6d; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=0tES3bdt7Dfa21iZsJYbWnuV6/yUytq3HPpPGDOjRv4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hs46N4bQAY7ZbnQVgpgngh5EM1mhlWEFqutwHEtsW9UDx0nGkbmP5r830gV39wgUs 2B1VOEbazklk+VgHzys2eA/Aj7SDHaTzf6oxlMVCxmwHQ/ZM9boCHKCB1F9oPbDYFH 8DHFsvmkW58Ge/6JnZwU5c8pkdWV/NnYCiOoEmRZ7j1RMrOJV3grFS0P1IGdPaCBof msVhokcehbDeg1d05yCSpCz8BOXcvhAJobsKlHmZPEQMHbzBYPgAexD5vz4vzNqgvn HzyGWy+Rp4PV/fmLdGXDBgI2xaLCxmY9f2GFplYZ1EjKAMndxOsvqS4Uc/6s1RDBf1 vdUDt28s+kgiw== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 06/17] leds: leds-nuc: allow changing the LED colors Date: Tue, 18 May 2021 17:08:55 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Add routines to allow seeing and changing the LED colors. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 244 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 228 insertions(+), 16 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index df65bf17e0e6..415031d344c6 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -58,8 +58,6 @@ enum led_new_get_subcmd { enum led_function { LED_FUNC_BRIGHTNESS, LED_FUNC_COLOR1, - LED_FUNC_COLOR_GREEN, - LED_FUNC_COLOR_BLUE, =20 LED_FUNC_BLINK_BEHAVIOR, LED_FUNC_BLINK_FREQ, @@ -92,43 +90,31 @@ static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC= ] =3D { [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, [LED_FUNC_BLINK_FREQ] =3D 0x02, [LED_FUNC_COLOR1] =3D 0x03, - [LED_FUNC_COLOR_GREEN] =3D 0x04, - [LED_FUNC_COLOR_BLUE] =3D 0x05 }, [LED_IND_HDD_ACTIVITY] =3D { [LED_FUNC_BRIGHTNESS] =3D 0x00, [LED_FUNC_COLOR1] =3D 0x01, - [LED_FUNC_COLOR_GREEN] =3D 0x02, - [LED_FUNC_COLOR_BLUE] =3D 0x03, [LED_FUNC_HDD_BEHAVIOR] =3D 0x04 }, [LED_IND_ETHERNET] =3D { [LED_FUNC_ETH_TYPE] =3D 0x00, [LED_FUNC_BRIGHTNESS] =3D 0x01, [LED_FUNC_COLOR1] =3D 0x02, - [LED_FUNC_COLOR_GREEN] =3D 0x03, - [LED_FUNC_COLOR_BLUE] =3D 0x04 }, [LED_IND_WIFI] =3D { [LED_FUNC_BRIGHTNESS] =3D 0x00, [LED_FUNC_COLOR1] =3D 0x01, - [LED_FUNC_COLOR_GREEN] =3D 0x02, - [LED_FUNC_COLOR_BLUE] =3D 0x03 }, [LED_IND_SOFTWARE] =3D { [LED_FUNC_BRIGHTNESS] =3D 0x00, [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, [LED_FUNC_BLINK_FREQ] =3D 0x02, [LED_FUNC_COLOR1] =3D 0x03, - [LED_FUNC_COLOR_GREEN] =3D 0x04, - [LED_FUNC_COLOR_BLUE] =3D 0x05 }, [LED_IND_POWER_LIMIT] =3D { [LED_FUNC_POWER_LIMIT_SCHEME] =3D 0x00, [LED_FUNC_BRIGHTNESS] =3D 0x01, [LED_FUNC_COLOR1] =3D 0x02, - [LED_FUNC_COLOR_GREEN] =3D 0x03, - [LED_FUNC_COLOR_BLUE] =3D 0x04 }, }; =20 @@ -462,6 +448,8 @@ static ssize_t nuc_wmi_set_brightness_offset(struct dev= ice *dev, } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) =20 +/* Show/change the LED indicator */ + static const char * const led_indicators[] =3D { "Power State", "HDD Activity", @@ -534,7 +522,220 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } =20 -/* Get brightness */ +/* Show/change the LED color */ + +enum led_colors { + LED_COLOR_BLUE, + LED_COLOR_AMBER, + LED_COLOR_WHITE +}; + +struct led_color_name { + const char *name; + u8 r, g, b; +}; + +static const struct led_color_name led_colors[] =3D { + /* The first colors should match the dual-LED colorset */ + [LED_COLOR_BLUE] =3D { "blue", 0, 0, 0xff }, + [LED_COLOR_AMBER] =3D { "amber", 0xff, 0xbf, 0 }, + [LED_COLOR_WHITE] =3D { "white", 0xff, 0xff, 0xff }, + + /* Let's add a couple of common color names as well */ + { "red", 0xff, 0, 0 }, + { "green", 0, 0xff, 0 }, + { "yellow", 0xff, 0xff, 0 }, + { "cyan", 0, 0xff, 0xff }, + { "magenta", 0xff, 0, 0xff }, +}; + +static ssize_t show_color(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl; + int size =3D PAGE_SIZE; + char *p =3D buf; + int color, r, g, b; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + if (led->color_type & LED_RGB) { + r =3D output[0]; + + input[3]++; + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + g =3D output[0]; + + input[3]++; + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + b =3D output[0]; + + for (color =3D 0; color < ARRAY_SIZE(led_colors); color++) + if (led_colors[color].r =3D=3D r && + led_colors[color].g =3D=3D g && + led_colors[color].b =3D=3D b) + return scnprintf(p, size, "%s\n", + led_colors[color].name); + + return scnprintf(p, size, "%d,%d,%d\n", r, g, b); + } + + if (!output[0]) + return scnprintf(p, size, "%s\n", + led_colors[LED_COLOR_BLUE].name); + + if (led->color_type & LED_BLUE_AMBER) + return scnprintf(p, size, "%s\n", + led_colors[LED_COLOR_AMBER].name); + + return scnprintf(p, size, "%s\n", led_colors[LED_COLOR_WHITE].name); +} + +static ssize_t store_color(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ret, ctrl, color; + const char *tmp; + u8 r, g, b, val; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + tmp =3D strsep((char **)&buf, ",\n"); + + for (color =3D 0; color < ARRAY_SIZE(led_colors); color++) + if (!strcasecmp(tmp, led_colors[color].name)) + break; + + if (color < ARRAY_SIZE(led_colors)) { + r =3D led_colors[color].r; + g =3D led_colors[color].g; + b =3D led_colors[color].b; + } else { + if (kstrtou8(tmp, 0, &r) || r > 255) + return -EINVAL; + + tmp =3D strsep((char **)&buf, ",\n"); + if (kstrtou8(tmp, 0, &g) || g > 255) + return -EINVAL; + + tmp =3D strsep((char **)&buf, " \n"); + if (kstrtou8(tmp, 0, &b) || b > 255) + return -EINVAL; + + if (led->color_type & LED_SINGLE_COLOR) { + for (color =3D 0; color <=3D LED_COLOR_WHITE; color++) + if (led_colors[color].r =3D=3D r && + led_colors[color].g =3D=3D g && + led_colors[color].b =3D=3D b) + break; + } + } + + ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + + /* Dual color LEDs */ + if (!(led->color_type & LED_RGB)) { + if (color =3D=3D LED_COLOR_BLUE) + val =3D 0; + else { + if (led->color_type & LED_BLUE_AMBER && + color !=3D LED_COLOR_AMBER) + return -EINVAL; + else if (color !=3D LED_COLOR_WHITE) + return -EINVAL; + val =3D1; + } + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; + } + + /* RGB LEDs */ + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D r; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2]++; + input[3] =3D g; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2]++; + input[3] =3D b; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; + + return -EINVAL; +} + +static umode_t nuc_wmi_led_color_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev =3D kobj_to_dev(kobj); + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + umode_t mode =3D attr->mode; + + if (led->color_type & LED_SINGLE_COLOR) + return 0; + + return mode; +} + +/* Show/store brightness */ static ssize_t show_brightness_offset(struct device *dev, struct device_attribute *attr, u8 offset, @@ -554,7 +755,6 @@ static ssize_t show_brightness_offset(struct device *de= v, return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } =20 -/* Change brightness */ static ssize_t store_brightness_offset(struct device *dev, struct device_attribute *attr, u8 offset, @@ -600,6 +800,7 @@ static int nuc_wmi_set_brightness(struct led_classdev *= cdev, } =20 static LED_ATTR_RW(indicator); +static LED_ATTR_RW(color); =20 LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); @@ -623,8 +824,19 @@ static const struct attribute_group nuc_wmi_led_attrib= ute_group =3D { .attrs =3D nuc_wmi_led_attr, }; =20 +static struct attribute *nuc_wmi_led_color_attr[] =3D { + &dev_attr_color.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_color_attribute_group =3D { + .is_visible =3D nuc_wmi_led_color_is_visible, + .attrs =3D nuc_wmi_led_color_attr, +}; + static const struct attribute_group *nuc_wmi_led_attribute_groups[] =3D { &nuc_wmi_led_attribute_group, + &nuc_wmi_led_color_attribute_group, NULL }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350610; cv=none; d=zohomail.com; s=zohoarc; b=Bt4lC4kBiN5cB9fwnzxmACRufELlsc+n3xsWpxHNpJkun5MjGc0WYtxPrVQyhQ7ySU/+EN+mHIp+cvxtLUkD9/TxJs33H7Jq8HlgFFzjSYmU7Ne9pap9grxb6ZjN8wcYKxpvfa9wZLZv4MgSwG0UlLCOlFpZMSdsKPM89bJmeWI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350610; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=PTeFwV/cmr7dip9IUVVo8Dj4mGBdgaSe7ft+V5wAUC8=; b=QAlS1MLy/Gwt6PcYFoT4j304HSB9UhBTUtoblD+PDrgoI2DFHy+6j/1kBxmUNLR5+JeIyrhEziiKyGGrsupYhmrILndUvayhHANTc2IwnW+HUX/Dz6+uxX3/Bcj+cyEEzQU1RR/espLjDvuDWjVEVGRgl6Pf6dCp1DVPAUf81FU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350610559230.81261065725596; Tue, 18 May 2021 08:10:10 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350066AbhERPLW (ORCPT ); Tue, 18 May 2021 11:11:22 -0400 Received: from mail.kernel.org ([198.145.29.99]:49496 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244777AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 16A6761261; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOM-7o; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=pPHEVYhddjAKeLYMEumM836fer803bytTHNsI1Rz+eA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LVSVdD4AnBvIR4+63eAIMGjrG4Yx5e7Vif3NtwzbsrWlylDZXGzmKfPcuO07ZKCDb coZEMVjunhQVkdYk4exdX+ByCblai0YifMmn93l2MtpHGAuJosReUY/2lkWn2sU4qg XmTPYuNhXeuzMUNdDLg9ems3QjDXy8N+er98rJE6oibuOpQbi/9yTPaaBTYbL++faW gW3oZ+IlIKABl7v5ASMveZoiVnam4s+B7+DKwRrnKcnIt6ArMeNFRYHyFzqbJBuGpF dVBdbWbugiUAZ5NnKq6E1bAKPz+KMQPDWASlByPrmBkfIT7qDXnKnXX/v8D6HC90Ks 5sGoPSnqmkiGw== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 07/17] leds: leds-nuc: add support for WMI API version 1.0 Date: Tue, 18 May 2021 17:08:56 +0200 Message-Id: <234ebbff2cb1d15634b5f10aa98e58c11d24a65c.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The control indicators for WMI version 1.0 (used on NUCi10 and above) are on different locations. The main difference is on single color LEDs. Also, the Power State brightness names are defined on a different way, and there are 3 groups instead of 4. As the driver was written with some tables to map the control option values, it is easy to extend it to support the new definitions: all we need to do is to add the V1.0 tables and ensure that the right table will be used. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 119 +++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 20 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 415031d344c6..e0090626aeec 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -62,6 +62,7 @@ enum led_function { LED_FUNC_BLINK_BEHAVIOR, LED_FUNC_BLINK_FREQ, =20 + LED_FUNC_POWER_STATE_NUM_CTRLS, LED_FUNC_HDD_BEHAVIOR, LED_FUNC_ETH_TYPE, LED_FUNC_POWER_LIMIT_SCHEME, @@ -84,8 +85,11 @@ enum led_indicators { /* * control items ID for each of the valid indicators on spec Rev 0.64. */ -static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] =3D { - [LED_IND_POWER_STATE] =3D { /* Offsets for each power state */ +static const u8 led_func_multicolor[MAX_IND][MAX_LED_FUNC] =3D { + [LED_IND_POWER_STATE] =3D { + [LED_FUNC_POWER_STATE_NUM_CTRLS] =3D 0x06, + + /* Offsets for each power state */ [LED_FUNC_BRIGHTNESS] =3D 0x00, [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, [LED_FUNC_BLINK_FREQ] =3D 0x02, @@ -118,6 +122,24 @@ static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUN= C] =3D { }, }; =20 +static const u8 led_func_rev_1_0_singlecolor[MAX_IND][MAX_LED_FUNC] =3D { + [LED_IND_POWER_STATE] =3D { + [LED_FUNC_POWER_STATE_NUM_CTRLS] =3D 0x02, + + /* Offsets for each power state */ + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, + }, + [LED_IND_HDD_ACTIVITY] =3D { + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_HDD_BEHAVIOR] =3D 0x01 + }, + [LED_IND_SOFTWARE] =3D { + [LED_FUNC_BRIGHTNESS] =3D 0x00, + [LED_FUNC_BLINK_BEHAVIOR] =3D 0x01, + }, +}; + /* LED color indicator */ #define LED_BLUE_AMBER BIT(0) #define LED_BLUE_WHITE BIT(1) @@ -141,6 +163,9 @@ struct nuc_nmi_led { u8 indicator; u32 color_type; u32 avail_indicators; + enum led_api_rev api_rev; + + const u8 (*reg_table)[MAX_LED_FUNC]; }; =20 struct nuc_wmi { @@ -251,7 +276,7 @@ static int nuc_nmi_cmd(struct device *dev, return ret; } =20 -static int nuc_wmi_query_leds(struct device *dev) +static int nuc_wmi_query_leds(struct device *dev, enum led_api_rev *api_re= v) { struct nuc_wmi *priv =3D dev_get_drvdata(dev); u8 input[NUM_INPUT_ARGS] =3D { 0 }; @@ -291,9 +316,11 @@ static int nuc_wmi_query_leds(struct device *dev) } =20 /* Currently, only API Revision 0.64 is supported */ - if (ver !=3D LED_API_REV_0_64) + if (ver !=3D LED_API_REV_0_64 && ver !=3D LED_API_REV_1_0) return -ENODEV; =20 + *api_rev =3D ver; + if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; @@ -382,7 +409,7 @@ static int nuc_wmi_get_brightness_offset(struct device = *dev, if (led->indicator =3D=3D LED_IND_DISABLE) return -ENODEV; =20 - ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BRIGHTNESS] + offset; =20 if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -413,7 +440,7 @@ static ssize_t nuc_wmi_set_brightness_offset(struct dev= ice *dev, if (led->indicator =3D=3D LED_IND_DISABLE) return -ENODEV; =20 - ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BRIGHTNESS] + offset; =20 if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -564,7 +591,7 @@ static ssize_t show_color(struct device *dev, if (led->indicator =3D=3D LED_IND_DISABLE) return -ENODEV; =20 - ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_COLOR1]; =20 if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -661,7 +688,7 @@ static ssize_t store_color(struct device *dev, } } =20 - ctrl =3D led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_COLOR1]; =20 /* Dual color LEDs */ if (!(led->color_type & LED_RGB)) { @@ -748,6 +775,8 @@ static ssize_t show_brightness_offset(struct device *de= v, if (led->indicator !=3D LED_IND_POWER_STATE) return -ENODEV; =20 + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ret =3D nuc_wmi_get_brightness_offset(dev, led, offset); if (ret < 0) return ret; @@ -771,6 +800,8 @@ static ssize_t store_brightness_offset(struct device *d= ev, if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; =20 + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ret =3D nuc_wmi_set_brightness_offset(dev, led, offset, val); if (ret) return ret; @@ -799,13 +830,40 @@ static int nuc_wmi_set_brightness(struct led_classdev= *cdev, return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); } =20 +static umode_t nuc_wmi_led_power_state_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + struct device *dev =3D kobj_to_dev(kobj); + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + umode_t mode =3D attr->mode; + + if (!strcmp(attr->name, "s0_brightness") || + !strcmp(attr->name, "s3_brightness")) + return mode; + + if (led->api_rev =3D=3D LED_API_REV_0_64) { + if (!strcmp(attr->name, "s5_brightness") || + !strcmp(attr->name, "ready_mode_brightness")) + return mode; + } else { + if (!strcmp(attr->name, "standby_brightness")) + return mode; + } + + return 0; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); =20 -LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); -LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); -LED_ATTR_POWER_STATE_RW(s5_brightness, 0x0c); -LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); +LED_ATTR_POWER_STATE_RW(s0_brightness, 0); +LED_ATTR_POWER_STATE_RW(s3_brightness, 1); +LED_ATTR_POWER_STATE_RW(s5_brightness, 2); // Rev 0.64 +LED_ATTR_POWER_STATE_RW(standby_brightness, 2); // Rev 1.0 +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 3); // Rev 1.0 =20 /* * Attributes for LEDs @@ -813,15 +871,25 @@ LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); =20 static struct attribute *nuc_wmi_led_attr[] =3D { &dev_attr_indicator.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_attribute_group =3D { + .attrs =3D nuc_wmi_led_attr, +}; + +static struct attribute *nuc_wmi_led_power_state_attr[] =3D { &dev_attr_s0_brightness.attr, &dev_attr_s3_brightness.attr, + &dev_attr_standby_brightness.attr, &dev_attr_s5_brightness.attr, &dev_attr_ready_mode_brightness.attr, NULL, }; =20 -static const struct attribute_group nuc_wmi_led_attribute_group =3D { - .attrs =3D nuc_wmi_led_attr, +static const struct attribute_group nuc_wmi_led_power_state_group =3D { + .is_visible =3D nuc_wmi_led_power_state_is_visible, + .attrs =3D nuc_wmi_led_power_state_attr, }; =20 static struct attribute *nuc_wmi_led_color_attr[] =3D { @@ -836,26 +904,36 @@ static const struct attribute_group nuc_wmi_led_color= _attribute_group =3D { =20 static const struct attribute_group *nuc_wmi_led_attribute_groups[] =3D { &nuc_wmi_led_attribute_group, + &nuc_wmi_led_power_state_group, &nuc_wmi_led_color_attribute_group, NULL }; =20 -static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *le= d) +static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *le= d, + enum led_api_rev api_rev) { - int brightness =3D nuc_wmi_get_brightness_offset(dev, led, 0); + int brightness; =20 led->cdev.name =3D led_names[led->id]; led->dev =3D dev; led->cdev.groups =3D nuc_wmi_led_attribute_groups; led->cdev.brightness_get =3D nuc_wmi_get_brightness; led->cdev.brightness_set_blocking =3D nuc_wmi_set_brightness; + led->api_rev =3D api_rev; =20 - if (led->color_type & LED_SINGLE_COLOR) + if (led->color_type & LED_SINGLE_COLOR) { + if (led->api_rev =3D=3D LED_API_REV_1_0) + led->reg_table =3D led_func_rev_1_0_singlecolor; + else + led->reg_table =3D led_func_multicolor; led->cdev.max_brightness =3D 2; - else + } else { led->cdev.max_brightness =3D 100; + led->reg_table =3D led_func_multicolor; + } =20 /* Ensure that the current bright will be preserved */ + brightness =3D nuc_wmi_get_brightness_offset(dev, led, 0); if (brightness >=3D 0) led->cdev.delayed_set_value =3D brightness; =20 @@ -868,14 +946,15 @@ static int nuc_wmi_led_register(struct device *dev, s= truct nuc_nmi_led *led) static int nuc_wmi_leds_setup(struct device *dev) { struct nuc_wmi *priv =3D dev_get_drvdata(dev); + enum led_api_rev api_rev; int ret, i; =20 - ret =3D nuc_wmi_query_leds(dev); + ret =3D nuc_wmi_query_leds(dev, &api_rev); if (ret) return ret; =20 for (i =3D 0; i < priv->num_leds; i++) { - ret =3D nuc_wmi_led_register(dev, &priv->led[i]); + ret =3D nuc_wmi_led_register(dev, &priv->led[i], api_rev); if (ret) { dev_err(dev, "Failed to register led %d: %s\n", i, led_names[priv->led[i].id]); --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350606; cv=none; d=zohomail.com; s=zohoarc; b=PFI8EbAZZvyPJjyRZxnMyDWN6SrE8xFeaioaekCiNFc5PmNkP3PszOXmhEpOt8WnHApfudvYrTdgLHfwD8KYPYrsrVjd758maoqfevPhIVIEALE1n+K7p98I6zNfgfQQRvzH1nrgf5IK5HyU1/kYQLoUDfFEKhE8bgCQkxvccvc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350606; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=pjnv1CRkgT+cbCv6Xi0jcEEf9GsN/qQI+dkvngIt0UU=; b=N2DhpjRfq+25qNGjZ0dSlMxhAVtjEJR8N+MAp1Gz/Mh+sW3eeuGfZeGHkTLzQSpgwcbKgNryPDaprje0okFd5OZ6s0MKrs6hMQskZz7L+Nvfh356ds+MI2jZeiyHtzsAkycQFJFfGNqKTa+nFihc5Z/qLojJKGDmuXhmTu8c9us= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350606055997.2364766364999; Tue, 18 May 2021 08:10:06 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350051AbhERPLT (ORCPT ); Tue, 18 May 2021 11:11:19 -0400 Received: from mail.kernel.org ([198.145.29.99]:49446 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243998AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1984C61285; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOQ-8y; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=x3wrQxrzTGadyRwOA3LxdKBmzxjB74aMlEUAq2sqERQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sLVQFqaYcstlsnRpIgsAtVlPumAIAutpQKvXrWY3SSJsai8j2c6sbh/B/UQ0cSiEg OF9iYYzvRJ3td3MGkR2RWX2oiwUqkMg5gBbcnc4LJctAkcs9QKvcrdM/j/MjCjp6ja gvDp5qHO+5dfVPSRtoAOhaxg+bMAfabGiPfkSRIcLLYa2m0Z7BmFry6EVJQivhqlvH jz+sQyALmNOV8ReC/80t4TOw5BYXkp+YlDbGt4cO6mWIBPMhdei3Rly3KtFpdciwLf SZoF5MNHwkMZTd5Yt8iK6Vb/zep9SRoUkxEFR24AwZQ3AuhnESAmev5Qjt/PBrDTB+ WEgHk4lcrF+FA== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 08/17] leds: leds-nuc: add basic support for NUC6 WMI Date: Tue, 18 May 2021 17:08:57 +0200 Message-Id: <751ab7326957e0a05c568620b450a5690585d19b.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The NUC6 and NUCi7 supports an earlier version of the LEDs WMI, as specified at: https://www.intel.com/content/www/us/en/support/articles/000023426/intel-n= uc/intel-nuc-kits.html Implement the query part of the LED detection for those devices. Weird enough, at least with Skull Canyon (NUC6i7KYB) using the latest firmware release (KYSKLi70 0071), the WMI call return all zeros. It could well be due to a regression at the Intel's firmware, although this model was not announced as supporting this WMI. At the manufacturer's site, only NUC Kits NUC7i[x]BN and NUC6CAY are mentioned. Yet, it sounds to me that this is due to a firmware bug: $ sudo fwts wmi - ... Test 1 of 1: Windows Management Instrumentation test. ... \_SB_.WMTF._WDG (1 of 1) GUID: 86CCFD48-205E-4A77-9C48-2021CBEDE341 WMI Method: Flags : 0x02 (Method) Object ID : TF Instance : 0x01 Driver : intel-wmi-thunderbolt (Intel) FAILED [LOW] WMIMultipleMethod: Test 1, GUID 86CCFD48-205E-4A77-9C48-2021C= BEDE341 has multiple associated methods WMTF defined, this is a firmware bu= g that leads to ambiguous behaviour. ... \AMW0._WDG (1 of 2) GUID: 8C5DA44C-CDC3-46B3-8619-4E26D34390B7 WMI Method: Flags : 0x02 (Method) Object ID : AA Instance : 0x01 PASSED: Test 1, 8C5DA44C-CDC3-46B3-8619-4E26D34390B7 has associated method= \AMW0.WMAA ... Low failures: 1 wmi: GUID 86CCFD48-205E-4A77-9C48-2021CBEDE341 has multiple associated me= thods WMTF defined, this is a firmware bug that leads to ambiguous behaviou= r. Anyway, this was good enough to test that this patch will be producing exactly the WMI query as the NUC6 OOT driver at: https://github.com/milesp20/intel_nuc_led/ Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 142 +++++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 32 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index e0090626aeec..cd15ed824234 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -8,12 +8,15 @@ * * Inspired on WMI from https://github.com/nomego/intel_nuc_led * - * It follows this spec: - * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI= -Spec-Intel-NUC-NUC10ixFNx.pdf + * It follows those specs: + * https://www.intel.com/content/www/us/en/support/articles/000023426/in= tel-nuc/intel-nuc-kits.html + * https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/I= NTEL_WMI_LED_0.64.pdf + * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/W= MI-Spec-Intel-NUC-NUC10ixFNx.pdf */ =20 #include #include +#include #include #include #include @@ -34,12 +37,21 @@ enum led_api_rev { }; =20 enum led_cmds { + /* NUC6-specific cmds */ + LED_OLD_GET_STATUS =3D 0x01, + LED_OLD_SET_LED =3D 0x02, + + /* Rev 0.64 and 1.0 cmds */ + LED_QUERY =3D 0x03, LED_NEW_GET_STATUS =3D 0x04, LED_SET_INDICATOR =3D 0x05, LED_SET_VALUE =3D 0x06, LED_NOTIFICATION =3D 0x07, LED_SWITCH_TYPE =3D 0x08, + + /* Rev 1.0 cmds */ + LED_VERSION_CONTROL =3D 0x09, }; =20 @@ -55,6 +67,11 @@ enum led_new_get_subcmd { LED_NEW_GET_CONTROL_ITEM =3D 0x01, }; =20 +enum led_old_get_subcmd { + LED_OLD_GET_S0_POWER =3D 0x01, + LED_OLD_GET_S0_RING =3D 0x02, +}; + enum led_function { LED_FUNC_BRIGHTNESS, LED_FUNC_COLOR1, @@ -146,14 +163,19 @@ static const u8 led_func_rev_1_0_singlecolor[MAX_IND]= [MAX_LED_FUNC] =3D { #define LED_RGB BIT(2) #define LED_SINGLE_COLOR BIT(3) =20 +#define POWER_LED 0 +#define RING_LED (MAX_LEDS + 1) + static const char * const led_names[] =3D { - "nuc::power", + [POWER_LED] =3D "nuc::power", "nuc::hdd", "nuc::skull", "nuc::eyes", "nuc::front1", "nuc::front2", "nuc::front3", + + [RING_LED] =3D "nuc::ring", // NUC6 models }; =20 struct nuc_nmi_led { @@ -276,51 +298,101 @@ static int nuc_nmi_cmd(struct device *dev, return ret; } =20 +static int nuc_wmi_query_leds_nuc6(struct device *dev) +{ + // FIXME: add a check for the specific models that are known to work + struct nuc_wmi *priv =3D dev_get_drvdata(dev); + u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + struct nuc_nmi_led *led; + int ret; + + cmd =3D LED_OLD_GET_STATUS; + input[0] =3D LED_OLD_GET_S0_POWER; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "Get S0 Power: error %d\n", ret); + return ret; + } + + led =3D &priv->led[priv->num_leds]; + led->id =3D POWER_LED; + led->color_type =3D LED_BLUE_AMBER; + led->avail_indicators =3D LED_IND_POWER_STATE; + led->indicator =3D fls(led->avail_indicators); + priv->num_leds++; + + cmd =3D LED_OLD_GET_STATUS; + input[0] =3D LED_OLD_GET_S0_RING; + ret =3D nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "Get S0 Ring: error %d\n", ret); + return ret; + } + led =3D &priv->led[priv->num_leds]; + led->id =3D RING_LED; + led->color_type =3D LED_BLUE_AMBER; + led->avail_indicators =3D LED_IND_SOFTWARE; + led->indicator =3D fls(led->avail_indicators); + priv->num_leds++; + + return 0; +} + static int nuc_wmi_query_leds(struct device *dev, enum led_api_rev *api_re= v) { struct nuc_wmi *priv =3D dev_get_drvdata(dev); u8 input[NUM_INPUT_ARGS] =3D { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int id, ret, ver =3D LED_API_UNKNOWN; + int id, ret, ver =3D LED_API_UNKNOWN, nuc_ver =3D 0; u8 leds; + const char *dmi_name; + + dmi_name =3D dmi_get_system_info(DMI_PRODUCT_NAME); + if (!dmi_name || !*dmi_name) + dmi_name =3D dmi_get_system_info(DMI_BOARD_NAME); + + if (strncmp(dmi_name, "NUC", 3)) + return -ENODEV; + + dmi_name +=3D3; + while (*dmi_name) { + if (*dmi_name < '0' || *dmi_name > '9') + break; + nuc_ver =3D (*dmi_name - '0') + nuc_ver * 10; + dmi_name++; + } + + if (nuc_ver < 6) + return -ENODEV; + + if (nuc_ver < 8) { + *api_rev =3D LED_API_NUC6; + return nuc_wmi_query_leds_nuc6(dev); + } =20 - /* - * List all LED types support in the platform - * - * Should work with both NUC8iXXX and NUC10iXXX - * - * FIXME: Should add a fallback code for it to work with older NUCs, - * as LED_QUERY returns an error on older devices like Skull Canyon. - */ input[0] =3D LED_QUERY_LIST_ALL; ret =3D nuc_nmi_cmd(dev, LED_QUERY, input, output); - if (ret =3D=3D -ENOENT) { - ver =3D LED_API_NUC6; - } else if (ret) { + if (ret) { dev_warn(dev, "error %d while listing all LEDs\n", ret); return ret; - } else { - leds =3D output[0]; } =20 - if (ver !=3D LED_API_NUC6) { - ret =3D nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); - if (ret) - return ret; + leds =3D output[0]; =20 - ver =3D output[0] | output[1] << 16; - if (!ver) - ver =3D LED_API_REV_0_64; - else if (ver =3D=3D 0x0126) - ver =3D LED_API_REV_1_0; - } + ret =3D nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); + if (ret) + return ret; + + ver =3D output[0] | output[1] << 16; + if (!ver) + *api_rev =3D LED_API_REV_0_64; + else if (ver =3D=3D 0x0126) + *api_rev =3D LED_API_REV_1_0; =20 - /* Currently, only API Revision 0.64 is supported */ - if (ver !=3D LED_API_REV_0_64 && ver !=3D LED_API_REV_1_0) + if (*api_rev =3D=3D LED_API_UNKNOWN) return -ENODEV; =20 - *api_rev =3D ver; - if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; @@ -916,10 +988,16 @@ static int nuc_wmi_led_register(struct device *dev, s= truct nuc_nmi_led *led, =20 led->cdev.name =3D led_names[led->id]; led->dev =3D dev; + led->api_rev =3D api_rev; + + if (led->api_rev =3D=3D LED_API_NUC6) { + // FIXME: add NUC6-specific API bits here + return devm_led_classdev_register(dev, &led->cdev); + } + led->cdev.groups =3D nuc_wmi_led_attribute_groups; led->cdev.brightness_get =3D nuc_wmi_get_brightness; led->cdev.brightness_set_blocking =3D nuc_wmi_set_brightness; - led->api_rev =3D api_rev; =20 if (led->color_type & LED_SINGLE_COLOR) { if (led->api_rev =3D=3D LED_API_REV_1_0) --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350618; cv=none; d=zohomail.com; s=zohoarc; b=TruwbOvi6dPK9K9dqo7mqCxFtUkQV2DC8tCE5oUvG/kWvsF5fcjuqt4XmLSMmgX4T72hseUZNM+FjeoRqzDxRI3qcZ7QWAz1CNR43BVKzmRLJfzjUftShktbYLiHxBhMb52wzBMaSEbg7KkQuKCpIOm9aY+Bw8pdTX/nCPEPauo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350618; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=2IHcDo7tOCh6PCsPdKrqzAU/GkJWnZ0FM0GUMwemxOo=; b=UVZpN1Z/D8KdYvwqb7wfySSwQU1aweT7EPI/e4bRymWlf8EhEp1KLCFkTtGMpk6JmGTPEeL4rEx4nbk82nwQuC28mItKdnJU254HX13Kgy0Jx+HV8oWmHvs+VLQ9PPXzXPOEKDlMy/4JRF9UJHFytQolcRoxUtyTo2cNt1jEA4Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350618986141.25781356383027; Tue, 18 May 2021 08:10:18 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350068AbhERPL2 (ORCPT ); Tue, 18 May 2021 11:11:28 -0400 Received: from mail.kernel.org ([198.145.29.99]:49498 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245316AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 243DB6135B; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOU-Ae; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=OF31wuskOSGZ57gBcSDnyeKus3wSQ2N85viq/571JTI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=twerRVXPU/LJX87CKzUJMXURoFYahwyv/qetsHkE59uBky39byvpggqF9t6aWKlfv HGiFDJdh3favyPvXevyxMOlteRw68MN/Qi3XiGPoEXDdTSeO6Jz2OlgUZqSCNbOtTJ lmEOT46qes5BcvLHJ95bk+MtdztOF682UCtR0mdeuftFh4gNDYadsPf+UxkkZ9DgaP +kQ1pK1MdxAi2LjQXA+/h7FSn5uz6IgdYuBt9SMd0IuiDxHMjym8s/BeJkuVFysQFj 3TVbIp3WKhk1utPBdqv1Vet38XkmF1zecN1+YKBUo34O5O36/regF4PrBXgb/9y/JK iRAKzeddE8VZw== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 09/17] leds: leds-nuc: add brightness and color for NUC6 API Date: Tue, 18 May 2021 17:08:58 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The NUC6 WMI API is really simple: it has just 2 messages, that retrieves everything for a LED, and it has just 2 LEDs. Add support for retrieving and set brightness and color. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 198 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 7 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index cd15ed824234..03fa8bafc5de 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -302,14 +302,13 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) { // FIXME: add a check for the specific models that are known to work struct nuc_wmi *priv =3D dev_get_drvdata(dev); - u8 cmd, input[NUM_INPUT_ARGS] =3D { 0 }; + u8 input[NUM_INPUT_ARGS] =3D { 0 }; u8 output[NUM_OUTPUT_ARGS]; struct nuc_nmi_led *led; int ret; =20 - cmd =3D LED_OLD_GET_STATUS; input[0] =3D LED_OLD_GET_S0_POWER; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + ret =3D nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); if (ret) { dev_warn(dev, "Get S0 Power: error %d\n", ret); return ret; @@ -322,9 +321,8 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) led->indicator =3D fls(led->avail_indicators); priv->num_leds++; =20 - cmd =3D LED_OLD_GET_STATUS; input[0] =3D LED_OLD_GET_S0_RING; - ret =3D nuc_nmi_cmd(dev, cmd, input, output); + ret =3D nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); if (ret) { dev_warn(dev, "Get S0 Ring: error %d\n", ret); return ret; @@ -547,6 +545,167 @@ static ssize_t nuc_wmi_set_brightness_offset(struct d= evice *dev, } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) =20 +/* + * NUC6 specific logic + */ + +static int nuc_wmi_nuc6_led_get_set(struct device *dev, + struct nuc_nmi_led *led, int *brightness, + int *blink_fade, int *color_state) +{ + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ret; + + if (led->id =3D=3D POWER_LED) + input[0] =3D LED_OLD_GET_S0_POWER; + else + input[0] =3D LED_OLD_GET_S0_RING; + + ret =3D nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); + if (ret) { + dev_warn(dev, "Get %s: error %d\n", led_names[led->id], ret); + return ret; + } + + if (brightness && *brightness >=3D 0) + input[1] =3D *brightness; + else + input[1] =3D output[0]; + + if (blink_fade && *blink_fade >=3D 0) + input[2] =3D *blink_fade; + else + input[2] =3D output[1]; + + if (color_state && *color_state >=3D 0) + input[3] =3D *color_state; + else + input[3] =3D output[2]; + + ret =3D nuc_nmi_cmd(dev, LED_OLD_SET_LED, input, output); + if (ret) { + dev_warn(dev, "Get %s: error %d\n", led_names[led->id], ret); + return ret; + } + + if (brightness) + *brightness =3D output[0]; + if (blink_fade) + *blink_fade =3D output[1]; + if (color_state) + *color_state =3D output[2]; + + return 0; +} + +static enum led_brightness nuc_wmi_nuc6_get_brightness(struct led_classdev= *cdev) +{ + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int ret, brightness =3D -1; + + ret =3D nuc_wmi_nuc6_led_get_set(cdev->dev, led, &brightness, NULL, NULL); + if (ret) + return ret; + + return brightness; +} + +static int nuc_wmi_nuc6_set_brightness(struct led_classdev *cdev, + enum led_brightness bright) +{ + int brightness =3D bright; + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + return nuc_wmi_nuc6_led_get_set(cdev->dev, led, &brightness, + NULL, NULL); +} + +static const char * const nuc6_power_colors[] =3D { + "disable", + "blue", + "amber" +}; + +static const char * const nuc6_ring_colors[] =3D { + "disable", + "cyan", + "pink", + "yellow", + "blue", + "red", + "green", + "white" +}; + +static ssize_t nuc6_show_color(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int color =3D -1, ret, arr_size, i, n; + const char * const*color_names; + int size =3D PAGE_SIZE; + char *p =3D buf; + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, NULL, &color); + if (ret) + return ret; + + if (led->id =3D=3D POWER_LED) { + color_names =3D nuc6_power_colors; + arr_size =3D ARRAY_SIZE(nuc6_power_colors); + } else { + color_names =3D nuc6_ring_colors; + arr_size =3D ARRAY_SIZE(nuc6_ring_colors); + } + + for (i =3D 0; i < arr_size; i++) { + if (i =3D=3D color) + n =3D scnprintf(p, size, "[%s] ", color_names[i]); + else + n =3D scnprintf(p, size, "%s ", color_names[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; + +} + +static ssize_t nuc6_store_color(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + const char *tmp; + int ret, color; + + tmp =3D strsep((char **)&buf, ",\n"); + + if (led->id =3D=3D POWER_LED) { + for (color =3D ARRAY_SIZE(nuc6_power_colors)+1; color >=3D 0; color--) + if (!strcasecmp(tmp, nuc6_power_colors[color])) + break; + } else { + for (color =3D ARRAY_SIZE(nuc6_ring_colors)+1; color >=3D 0; color--) + if (!strcasecmp(tmp, nuc6_ring_colors[color])) + break; + } + + if (color < 0) + return -EINVAL; + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, NULL, &color); + if (ret) + return ret; + + return len; +} + /* Show/change the LED indicator */ =20 static const char * const led_indicators[] =3D { @@ -660,6 +819,9 @@ static ssize_t show_color(struct device *dev, char *p =3D buf; int color, r, g, b; =20 + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_show_color(dev, attr, buf); + if (led->indicator =3D=3D LED_IND_DISABLE) return -ENODEV; =20 @@ -726,6 +888,9 @@ static ssize_t store_color(struct device *dev, const char *tmp; u8 r, g, b, val; =20 + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_store_color(dev, attr, buf, len); + if (led->indicator =3D=3D LED_IND_DISABLE) return -ENODEV; =20 @@ -828,6 +993,9 @@ static umode_t nuc_wmi_led_color_is_visible(struct kobj= ect *kobj, struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); umode_t mode =3D attr->mode; =20 + if (led->api_rev =3D=3D LED_API_NUC6) + return mode; + if (led->color_type & LED_SINGLE_COLOR) return 0; =20 @@ -981,17 +1149,33 @@ static const struct attribute_group *nuc_wmi_led_att= ribute_groups[] =3D { NULL }; =20 +static const struct attribute_group *nuc_wmi_nuc6_led_attribute_groups[] = =3D { + &nuc_wmi_led_color_attribute_group, + NULL +}; + static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *le= d, enum led_api_rev api_rev) { - int brightness; + int ret, brightness; =20 led->cdev.name =3D led_names[led->id]; led->dev =3D dev; led->api_rev =3D api_rev; =20 if (led->api_rev =3D=3D LED_API_NUC6) { - // FIXME: add NUC6-specific API bits here + brightness =3D -1; + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, &brightness, + NULL, NULL); + if (ret) + return ret; + + led->cdev.groups =3D nuc_wmi_nuc6_led_attribute_groups; + led->cdev.delayed_set_value =3D brightness; + led->cdev.max_brightness =3D 100; + led->cdev.brightness_get =3D nuc_wmi_nuc6_get_brightness; + led->cdev.brightness_set_blocking =3D nuc_wmi_nuc6_set_brightness; + return devm_led_classdev_register(dev, &led->cdev); } =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350942; cv=none; d=zohomail.com; s=zohoarc; b=Z49UoEHAePvoqVEDmH9qPmrw6YeqasVN4+74U4Uwyc4cxJBfN7uQQsWarrevDQXwsf9cM05E2EH8o/d/Lke9oigOxR46DLJCpQn1ooSQfr7Z4pp2wm6dP33Uc1LSyvt6eVsGTMZCDD+oTN3xQ4GapmJFlSPaBJGkrhSVDZ5kMHs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350942; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=3EjOQtd1FIUlY1xhcPL2gqecRk1h44gepnYy2DzxRTw=; b=MID8wGY/AWPkli96yKCDVQzAvu6XvlD8j0isCacH5ECZavCqN1qPxL5rCnPQw3dBf+w6M3+jAGoQsCYb+6r4wm/FOMrV0cDNFrEwiWmy4ypojF3tLYiZsuym2P1rVCc9fme/bcchhah7+5S0iENs7OnCcmZoHPy7MaZQoQiMIb4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350942243880.5128166615268; Tue, 18 May 2021 08:15:42 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237974AbhERPMu (ORCPT ); Tue, 18 May 2021 11:12:50 -0400 Received: from mail.kernel.org ([198.145.29.99]:49498 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345115AbhERPKk (ORCPT ); Tue, 18 May 2021 11:10:40 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 3253E6135D; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOY-Bw; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=8ScJfoPrpnNH7Ei2h6t3H6qX9PFlvMLFJOxUxAyJWbo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MGpA9S7fryvwpywoR65U81eKP6hAtoGc6aMbEfHuEda4ggeClN9x95PlMaZmwzdg4 kLWy38h5Oh+xuH0sjkd98ffmR/5kJc31txtieHonumuc3SdcGdWOogQtQKtxc41Eqn I93tsyr0KsAYWu/ctEyRGpM7QoniqaKMgJV4+T4wOigjpLcbrhyWquQ91l3GvGR1oi 031LMAksauC0gTx7UmJhiSKYIyv72p/6OF1jtWR1h0mrgill9WjxR7fxLpOuceXWns cGKpzz7wH88kdI0qRyjBigAWXz4UAwEFpT3FiS9tDSn9Cxfue7ZnoT2+BzjDNCkJ7a +LztTjvPwTVLQ== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 10/17] leds: leds-nuc: Add support to blink behavior for NUC8/10 Date: Tue, 18 May 2021 17:08:59 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The hardware blink logic works for both Power State and Software controlled LEDs. Just like brightness, there is one different blink behavior per different power state. Due to that, the logic is somewhat more complex than what it would be expected otherwise. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 347 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 322 insertions(+), 25 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 03fa8bafc5de..a5eb625d7b51 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -530,18 +530,30 @@ static ssize_t nuc_wmi_set_brightness_offset(struct d= evice *dev, #define LED_ATTR_RW(_name) \ DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) =20 -#define LED_ATTR_POWER_STATE_RW(_name, offset) \ +#define LED_ATTR_POWER_STATE_RW(_name, _offname, _offset) \ static ssize_t show_##_name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return show_brightness_offset(dev, attr, offset, buf); \ + struct led_classdev *cdev =3D dev_get_drvdata(dev); \ + struct nuc_nmi_led *led; \ + \ + led =3D container_of(cdev, struct nuc_nmi_led, cdev); \ + if (led->indicator !=3D LED_IND_POWER_STATE) \ + return -ENODEV; \ + return offset_show_##_offname(dev, attr, _offset, buf); \ } \ static ssize_t store_##_name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ + struct device_attribute *attr, \ + const char *buf, size_t len) \ { \ - return store_brightness_offset(dev, attr, offset, buf, len); \ + struct led_classdev *cdev =3D dev_get_drvdata(dev); \ + struct nuc_nmi_led *led; \ + \ + led =3D container_of(cdev, struct nuc_nmi_led, cdev); \ + if (led->indicator !=3D LED_IND_POWER_STATE) \ + return -ENODEV; \ + return offset_store_##_offname(dev, attr, _offset, buf, len); \ } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) =20 @@ -684,7 +696,7 @@ static ssize_t nuc6_store_color(struct device *dev, const char *tmp; int ret, color; =20 - tmp =3D strsep((char **)&buf, ",\n"); + tmp =3D strsep((char **)&buf, "\n"); =20 if (led->id =3D=3D POWER_LED) { for (color =3D ARRAY_SIZE(nuc6_power_colors)+1; color >=3D 0; color--) @@ -1003,7 +1015,7 @@ static umode_t nuc_wmi_led_color_is_visible(struct ko= bject *kobj, } =20 /* Show/store brightness */ -static ssize_t show_brightness_offset(struct device *dev, +static ssize_t offset_show_brightness(struct device *dev, struct device_attribute *attr, u8 offset, char *buf) @@ -1012,9 +1024,6 @@ static ssize_t show_brightness_offset(struct device *= dev, struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); int ret; =20 - if (led->indicator !=3D LED_IND_POWER_STATE) - return -ENODEV; - offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; =20 ret =3D nuc_wmi_get_brightness_offset(dev, led, offset); @@ -1024,7 +1033,7 @@ static ssize_t show_brightness_offset(struct device *= dev, return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } =20 -static ssize_t store_brightness_offset(struct device *dev, +static ssize_t offset_store_brightness(struct device *dev, struct device_attribute *attr, u8 offset, const char *buf, size_t len) @@ -1034,9 +1043,6 @@ static ssize_t store_brightness_offset(struct device = *dev, int ret; u8 val; =20 - if (led->indicator !=3D LED_IND_POWER_STATE) - return -ENODEV; - if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; =20 @@ -1070,6 +1076,8 @@ static int nuc_wmi_set_brightness(struct led_classdev= *cdev, return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); } =20 +#define cmp_attr_prefix(a, b) strncmp(a, b, strlen(b)) + static umode_t nuc_wmi_led_power_state_is_visible(struct kobject *kobj, struct attribute *attr, int idx) @@ -1077,33 +1085,297 @@ static umode_t nuc_wmi_led_power_state_is_visible(= struct kobject *kobj, struct device *dev =3D kobj_to_dev(kobj); struct led_classdev *cdev =3D dev_get_drvdata(dev); struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); - umode_t mode =3D attr->mode; =20 - if (!strcmp(attr->name, "s0_brightness") || - !strcmp(attr->name, "s3_brightness")) + if (!cmp_attr_prefix(attr->name, "s0_") || + !cmp_attr_prefix(attr->name, "s3_")) return mode; =20 if (led->api_rev =3D=3D LED_API_REV_0_64) { - if (!strcmp(attr->name, "s5_brightness") || - !strcmp(attr->name, "ready_mode_brightness")) + if (!cmp_attr_prefix(attr->name, "s5_") || + !cmp_attr_prefix(attr->name, "ready_mode_")) return mode; } else { - if (!strcmp(attr->name, "standby_brightness")) + if (!cmp_attr_prefix(attr->name, "standby_")) return mode; } =20 return 0; } =20 +/* Blink */ +static const char * const led_blink_behaviors[] =3D { + "solid", + "breathing", + "pulsing", + "strobing" +}; + +static const char * const led_blink_frequencies[] =3D { + "0.1", + "0.2", + "0.3", + "0.4", + "0.5", + "0.6", + "0.7", + "0.8", + "0.9", + "1.0", +}; + +static ssize_t offset_show_blink_behavior(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl, val, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val =3D output[0]; + + for (i =3D 0; i < ARRAY_SIZE(led_blink_behaviors); i++) { + if (i =3D=3D val) + n =3D scnprintf(p, size, "[%s] ", led_blink_behaviors[i]); + else + n =3D scnprintf(p, size, "%s ", led_blink_behaviors[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t offset_store_blink_behavior(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + + if (led->id !=3D LED_IND_SOFTWARE && led->id !=3D LED_IND_POWER_STATE) + return -ENODEV; + + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp =3D strsep((char **)&buf, "\n"); + + for (val =3D 0; val < ARRAY_SIZE(led_blink_behaviors); val++) + if (!strcasecmp(tmp, led_blink_behaviors[val])) + break; + + if (val >=3D ARRAY_SIZE(led_blink_behaviors)) + return -EINVAL; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + +static ssize_t show_blink_behavior(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return offset_show_blink_behavior(dev, attr, 0, buf); +} + +static ssize_t store_blink_behavior(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return offset_store_blink_behavior(dev, attr, 0, buf, len); +} + +static ssize_t offset_show_blink_frequency(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl, val, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val =3D output[0]; + + for (i =3D 0; i < ARRAY_SIZE(led_blink_frequencies); i++) { + if (i =3D=3D val) + n =3D scnprintf(p, size, "[%s] ", led_blink_frequencies[i]); + else + n =3D scnprintf(p, size, "%s ", led_blink_frequencies[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t offset_store_blink_frequency(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator =3D=3D LED_IND_DISABLE) + return -ENODEV; + + + if (led->id !=3D LED_IND_SOFTWARE && led->id !=3D LED_IND_POWER_STATE) + return -ENODEV; + + offset *=3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS= ]; + ctrl =3D led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp =3D strsep((char **)&buf, "\n"); + + for (val =3D 0; val < ARRAY_SIZE(led_blink_frequencies); val++) + if (!strcasecmp(tmp, led_blink_frequencies[val])) + break; + + if (val >=3D ARRAY_SIZE(led_blink_frequencies)) + return -EINVAL; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val + 1; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + +static ssize_t show_blink_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return offset_show_blink_frequency(dev, attr, 0, buf); +} + +static ssize_t store_blink_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return offset_store_blink_frequency(dev, attr, 0, buf, len); +} + +static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev =3D kobj_to_dev(kobj); + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + umode_t mode =3D attr->mode; + + // TODO: implement for NUC6 API + if (led->api_rev =3D=3D LED_API_NUC6) + return 0; + + if (led->id =3D=3D LED_IND_SOFTWARE) + return mode; + + return 0; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); +static LED_ATTR_RW(blink_behavior); +static LED_ATTR_RW(blink_frequency); =20 -LED_ATTR_POWER_STATE_RW(s0_brightness, 0); -LED_ATTR_POWER_STATE_RW(s3_brightness, 1); -LED_ATTR_POWER_STATE_RW(s5_brightness, 2); // Rev 0.64 -LED_ATTR_POWER_STATE_RW(standby_brightness, 2); // Rev 1.0 -LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 3); // Rev 1.0 +LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); +LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); +LED_ATTR_POWER_STATE_RW(s0_blink_frequency, blink_frequency, 0); +LED_ATTR_POWER_STATE_RW(s3_brightness, brightness, 1); +LED_ATTR_POWER_STATE_RW(s3_blink_behavior, blink_behavior, 1); +LED_ATTR_POWER_STATE_RW(s3_blink_frequency, blink_frequency, 1); + +/* Rev 0.64 */ +LED_ATTR_POWER_STATE_RW(s5_brightness, brightness, 2); +LED_ATTR_POWER_STATE_RW(s5_blink_behavior, blink_behavior, 2); +LED_ATTR_POWER_STATE_RW(s5_blink_frequency, blink_frequency, 2); +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, brightness, 3); +LED_ATTR_POWER_STATE_RW(ready_mode_blink_behavior, blink_behavior, 3); +LED_ATTR_POWER_STATE_RW(ready_mode_blink_frequency, blink_frequency, 3); + +/* Rev 1.0 */ +LED_ATTR_POWER_STATE_RW(standby_brightness, brightness, 2); +LED_ATTR_POWER_STATE_RW(standby_blink_behavior, blink_behavior, 2); +LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blink_frequency, 2); =20 /* * Attributes for LEDs @@ -1124,6 +1396,19 @@ static struct attribute *nuc_wmi_led_power_state_att= r[] =3D { &dev_attr_standby_brightness.attr, &dev_attr_s5_brightness.attr, &dev_attr_ready_mode_brightness.attr, + + &dev_attr_s0_blink_behavior.attr, + &dev_attr_s3_blink_behavior.attr, + &dev_attr_standby_blink_behavior.attr, + &dev_attr_s5_blink_behavior.attr, + &dev_attr_ready_mode_blink_behavior.attr, + + &dev_attr_s0_blink_frequency.attr, + &dev_attr_s3_blink_frequency.attr, + &dev_attr_standby_blink_frequency.attr, + &dev_attr_s5_blink_frequency.attr, + &dev_attr_ready_mode_blink_frequency.attr, + NULL, }; =20 @@ -1142,10 +1427,22 @@ static const struct attribute_group nuc_wmi_led_col= or_attribute_group =3D { .attrs =3D nuc_wmi_led_color_attr, }; =20 +static struct attribute *nuc_wmi_led_blink_behavior_attr[] =3D { + &dev_attr_blink_behavior.attr, + &dev_attr_blink_frequency.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_blink_attribute_group =3D { + .is_visible =3D nuc_wmi_led_blink_is_visible, + .attrs =3D nuc_wmi_led_blink_behavior_attr, +}; + static const struct attribute_group *nuc_wmi_led_attribute_groups[] =3D { &nuc_wmi_led_attribute_group, &nuc_wmi_led_power_state_group, &nuc_wmi_led_color_attribute_group, + &nuc_wmi_led_blink_attribute_group, NULL }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350599; cv=none; d=zohomail.com; s=zohoarc; b=WZVCezbPsr2rEykRm0A2XLUvSk2vmeaGXfHjPEkV9NkTG+xHXXsUpotJHw7odF6CLsPbEEVKGcTd4okbkg5rgV/yXAqfQB5syO81lMJtSR2Nip7wM57iVYGCwWWShc1AtfAbSE8ZUUlCyGH73HS+wuhEQf1J/b/UYYtKgVkF4IA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350599; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=mMMBL04VPH9rfD8kBQfDQ04YclNJc04HeYvCzF2x7K0=; b=jaN5LSK/JA8SRRLImM0YpRmaDlulcef5WpVeBuSbWNMIEeCfiIzXAYvE0h4FiJv7Ojoc27yhhyTITkjdxdCEOz1Zkouvmm1y+XfUUnSumvKCygRZXQ63oyz1vvCspYsc5D8mZr3MKWUL6SwHllVL1oP4bpaz7zzwCy1RINOtkqY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350599809207.37461579627086; Tue, 18 May 2021 08:09:59 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345032AbhERPLN (ORCPT ); Tue, 18 May 2021 11:11:13 -0400 Received: from mail.kernel.org ([198.145.29.99]:49438 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243464AbhERPK2 (ORCPT ); Tue, 18 May 2021 11:10:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2F25B61360; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOc-FK; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=cG8d0SVSR9AemukQMBOciLYjz3JmBKqR6Q8YNsgQ+pU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Zvq7IFzz55ZAepPag+foeRSI7S5lyllxIhf8LpyXdETrQPhxigTqxrJBqSRxBdxZH 8yeDHst5qwEsgWkPSA6BrkwbrBL+RDI3k77senxvQatiiFjyUxlqA5mebVJFPP/l+r V/O+yy3b5SydNKoTA+n9MiWc3emFhaEBWNXNV6+hr7Tu4JufH85crllbgsv2DzflFX Fa77tXvxAuSS39E9ReBg6JzdqrgVxgWJHvKYJwptO9XLLt9A8g2xtHGdR6lCd7cfew hJ7dfz2G6PsL6uAy50fiBh2Wnf+Gkz47dJWw/EV/3QQe2C1LMiPitsHEvsc9a04fVZ ZNfRq8+SljN4g== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 11/17] leds: leds-nuc: get rid of an unused variable Date: Tue, 18 May 2021 17:09:00 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) drivers/staging/nuc-led/nuc-wmi.c: In function =E2=80=98nuc_nmi_cmd=E2=80= =99: drivers/staging/nuc-led/nuc-wmi.c:242:6: warning: variable =E2=80=98size= =E2=80=99 set but not used [-Wunused-but-set-variable] 242 | int size, ret; | ^~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index a5eb625d7b51..e2517e1a367f 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -239,7 +239,7 @@ static int nuc_nmi_cmd(struct device *dev, struct acpi_buffer input; union acpi_object *obj; acpi_status status; - int size, ret; + int ret; u8 *p; =20 input.length =3D NUM_INPUT_ARGS; @@ -281,8 +281,6 @@ static int nuc_nmi_cmd(struct device *dev, goto err; } =20 - size =3D NUM_OUTPUT_ARGS + 1; - if (output_args) { memcpy(output_args, p + 1, NUM_OUTPUT_ARGS); =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350908; cv=none; d=zohomail.com; s=zohoarc; b=lw9xHyon+7I0hd81DhrCYvy/5ynPaWK40o6tN6BjRHD2MZjgukrVbo3nDfAqpJmtwDQ2SQI32sI9u9nCKSCSlGih0l/FYWThDo6YM9G4adlb3n5DQO8HOvoOuKrFibFCL6PVRWGs0mV2tzehx0Cirs45hE6PtrHKlF8viZD4Wjg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350908; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=uENALAFq/kSdW0sjMhZSPQ8gwne8e0kD1C1qO+V9QqQ=; b=RtSHaIkTFGqh+ZSBdmJfX7fiE7O+C7Nqp269mznS+prapT3hgzaCXbx6K5eaopzsyg8QZ4xu2+7w1D9NLZ68MBFHFPdFCN+0YdgoXi9rTFIJLImBL/HmZ+0OznIyhcQfrNeZiIWDQP4DokSAulckRH/MyrkPdUsHBIyk/o84KXE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350908257328.9730413396113; Tue, 18 May 2021 08:15:08 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350107AbhERPMT (ORCPT ); Tue, 18 May 2021 11:12:19 -0400 Received: from mail.kernel.org ([198.145.29.99]:49542 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343962AbhERPKa (ORCPT ); Tue, 18 May 2021 11:10:30 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 3526261361; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOg-GV; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=WNd/FZyXWC3bVqUADHT/Lw1l4FiAmrVOx7fhoZ7HJ54=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X/HtJ/L9SRvPEHCBP4nvU8vDsRytz9haZXplygWzae07Kz3LSxuWanohuNuCV3kjj i6HjcvAFiWrkp2hdkO09yQ+DLkGyxJnFbqsrRupI+xRjn5ecTtVdh7hFDl/A7RFj8F hDc4G+znJuw8BHY1/ysC0djioG+1MoLOSuJB4YXEWP0Cn/WdOT4L0G9escO31kdPEj E7mJCXLnHlpGkSgKxZcf1+Bq8392WHeAYBm5ZrG+Iu1uw01TPqJAvvar5kmJI7LGkP /zschFVjiZ2X5bpKEYi4bd3v4H04/A9j48Rm45oFET7RUrivi3EJYNtJcVvz6h1mcw 1oyZbtBh24dYA== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 12/17] leds: leds-nuc: implement blink control for NUC6 Date: Tue, 18 May 2021 17:09:01 +0200 Message-Id: <059a46546066cba7e1a41ed9b2afc1d3bf2e5ed5.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The blink control logic for NUC6 API is somewhat messy, as it uses a single register for controlling both the blink type and the frequency, using a random order. Let's use the same API as defined for other versions, splitting this setting on two different properties. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 269 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index e2517e1a367f..6aa0bf16c8b7 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -716,6 +716,247 @@ static ssize_t nuc6_store_color(struct device *dev, return len; } =20 +enum nuc6_blink_mode_freq { + NUC6_BLINK_MODE_BLINK_1HZ =3D 0x01, + NUC6_BLINK_MODE_BLINK_0_25HZ =3D 0x02, + NUC6_BLINK_MODE_FADE_1HZ =3D 0x03, + NUC6_BLINK_MODE_DONT_BLINK =3D 0x04, + + /* BIOS equal or upper AY0038 or BN0043 */ + NUC6_BLINK_MODE_BLINK_0_5HZ =3D 0x05, + NUC6_BLINK_MODE_FADE_0_25HZ =3D 0x06, + NUC6_BLINK_MODE_FADE_0_5HZ =3D 0x07 +}; + +enum nuc6_blink_mode { + NUC6_BLINK_MODE_SOLID, + NUC6_BLINK_MODE_BLINK, + NUC6_BLINK_MODE_FADE +}; + +static const char * const nuc6_blink_behavior[] =3D { + "solid", + "blink", + "fade", +}; + +enum nuc6_blink_freq { + NUC6_BLINK_FREQ_1HZ, + NUC6_BLINK_FREQ_0_5HZ, + NUC6_BLINK_FREQ_0_25HZ, +}; + +static const char * const nuc6_blink_frequency[] =3D { + "1", + "0.5", + "0.25", +}; + +static int nuc_wmi_nuc6_set_blink(struct device *dev, + struct nuc_nmi_led *led, + int freq, enum nuc6_blink_mode mode) +{ + int val; + + switch(mode) { + case NUC6_BLINK_MODE_SOLID: + val =3D NUC6_BLINK_MODE_DONT_BLINK; + break; + case NUC6_BLINK_MODE_BLINK: + if (freq =3D=3D NUC6_BLINK_FREQ_0_25HZ) + val =3D NUC6_BLINK_MODE_BLINK_0_25HZ; + else if (freq =3D=3D NUC6_BLINK_FREQ_0_5HZ) + val =3D NUC6_BLINK_MODE_BLINK_0_5HZ; + else + val =3D NUC6_BLINK_MODE_BLINK_1HZ; + break; + case NUC6_BLINK_MODE_FADE: + if (freq =3D=3D NUC6_BLINK_FREQ_0_25HZ) + val =3D NUC6_BLINK_MODE_FADE_0_25HZ; + else if (freq =3D=3D NUC6_BLINK_FREQ_0_5HZ) + val =3D NUC6_BLINK_MODE_FADE_0_5HZ; + else + val =3D NUC6_BLINK_MODE_FADE_1HZ; + break; + default: + return -EINVAL; + } + + return nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); +} + +static ssize_t nuc6_show_blink_behavior(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int val =3D -1, mode =3D -1, ret, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + switch (val) { + case NUC6_BLINK_MODE_BLINK_1HZ: + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_BLINK_0_5HZ: + mode =3D NUC6_BLINK_MODE_BLINK; + break; + case NUC6_BLINK_MODE_FADE_1HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + mode =3D NUC6_BLINK_MODE_FADE; + break; + case NUC6_BLINK_MODE_DONT_BLINK: + mode =3D NUC6_BLINK_MODE_SOLID; + break; + } + + for (i =3D 0; i < ARRAY_SIZE(nuc6_blink_behavior); i++) { + if (i =3D=3D mode) + n =3D scnprintf(p, size, "[%s] ", nuc6_blink_behavior[i]); + else + n =3D scnprintf(p, size, "%s ", nuc6_blink_behavior[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; + +} + +static ssize_t nuc6_store_blink_behavior(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int ret, val =3D -1, freq; + const char *tmp; + + tmp =3D strsep((char **)&buf, "\n"); + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + /* Preserve the frequency */ + switch (val) { + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + freq =3D NUC6_BLINK_FREQ_0_25HZ; + break; + case NUC6_BLINK_MODE_BLINK_0_5HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + freq =3D NUC6_BLINK_FREQ_0_5HZ; + break; + default: + freq =3D NUC6_BLINK_FREQ_1HZ; + break; + } + + for (val =3D ARRAY_SIZE(nuc6_blink_behavior)+1; val >=3D 0; val--) + if (!strcasecmp(tmp, nuc6_blink_behavior[val])) + break; + if (val < 0) + return -EINVAL; + + ret =3D nuc_wmi_nuc6_set_blink(dev, led, val, freq); + if (ret) + return ret; + + return len; +} + +static ssize_t nuc6_show_blink_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + int val =3D -1, freq =3D -1, ret, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + switch (val) { + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + freq =3D NUC6_BLINK_FREQ_0_25HZ; + break; + case NUC6_BLINK_MODE_BLINK_0_5HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + freq =3D NUC6_BLINK_FREQ_0_5HZ; + break; + default: + freq =3D NUC6_BLINK_FREQ_1HZ; + } + + for (i =3D 0; i < ARRAY_SIZE(nuc6_blink_frequency); i++) { + if (i =3D=3D freq) + n =3D scnprintf(p, size, "[%s] ", nuc6_blink_frequency[i]); + else + n =3D scnprintf(p, size, "%s ", nuc6_blink_frequency[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t nuc6_store_blink_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + enum nuc6_blink_mode mode; + int ret, freq, val =3D -1; + const char *tmp; + + tmp =3D strsep((char **)&buf, "\n"); + + ret =3D nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + /* Preserve the blink mode */ + switch (val) { + case NUC6_BLINK_MODE_BLINK_1HZ: + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_BLINK_0_5HZ: + mode =3D NUC6_BLINK_MODE_BLINK; + break; + case NUC6_BLINK_MODE_FADE_1HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + mode =3D NUC6_BLINK_MODE_FADE; + break; + default: /* setting frequency NUC6_BLINK_MODE_SOLID won't make sense */ + return -EINVAL; + } + + for (freq =3D ARRAY_SIZE(nuc6_blink_frequency)+1; freq >=3D 0; freq--) + if (!strcasecmp(tmp, nuc6_blink_frequency[freq])) + break; + if (freq < 0) + return -EINVAL; + + ret =3D nuc_wmi_nuc6_set_blink(dev, led, mode, freq); + if (ret) + return ret; + + return len; +} + /* Show/change the LED indicator */ =20 static const char * const led_indicators[] =3D { @@ -1217,6 +1458,12 @@ static ssize_t show_blink_behavior(struct device *de= v, struct device_attribute *attr, char *buf) { + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_show_blink_behavior(dev, attr, buf); + return offset_show_blink_behavior(dev, attr, 0, buf); } =20 @@ -1224,6 +1471,12 @@ static ssize_t store_blink_behavior(struct device *d= ev, struct device_attribute *attr, const char *buf, size_t len) { + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_store_blink_behavior(dev, attr, buf, len); + return offset_store_blink_behavior(dev, attr, 0, buf, len); } =20 @@ -1322,6 +1575,12 @@ static ssize_t show_blink_frequency(struct device *d= ev, struct device_attribute *attr, char *buf) { + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_show_blink_frequency(dev, attr, buf); + return offset_show_blink_frequency(dev, attr, 0, buf); } =20 @@ -1329,6 +1588,12 @@ static ssize_t store_blink_frequency(struct device *= dev, struct device_attribute *attr, const char *buf, size_t len) { + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev =3D=3D LED_API_NUC6) + return nuc6_store_blink_frequency(dev, attr, buf, len); + return offset_store_blink_frequency(dev, attr, 0, buf, len); } =20 @@ -1340,9 +1605,8 @@ static umode_t nuc_wmi_led_blink_is_visible(struct ko= bject *kobj, struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); umode_t mode =3D attr->mode; =20 - // TODO: implement for NUC6 API if (led->api_rev =3D=3D LED_API_NUC6) - return 0; + return mode; =20 if (led->id =3D=3D LED_IND_SOFTWARE) return mode; @@ -1446,6 +1710,7 @@ static const struct attribute_group *nuc_wmi_led_attr= ibute_groups[] =3D { =20 static const struct attribute_group *nuc_wmi_nuc6_led_attribute_groups[] = =3D { &nuc_wmi_led_color_attribute_group, + &nuc_wmi_led_blink_attribute_group, NULL }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621351030; cv=none; d=zohomail.com; s=zohoarc; b=i6LuvF1jzdxLNcBChAS9z6E1T3rxgPVd+3Epg0dSl+NRe4qgEPe4n1g4LwKoSHtE+xcYneFl+c2iFkWxigvp/eG8gmczZZtTwDCEDIEq5Sv31Oei/orO+SY2HUSMAlQZpGbePtlL0r8hwaYkVEUXFmiO04wzjd4bsYhE9Mg5pHU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621351030; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=YrZ8H4QUu8dcH6gg0xRnHS/L011Y2pikVUtsr58lRy0=; b=IR8zH8OLkgpMYYzNvM/TYRSb9ax9gNJKpNxi6Jg634uAZMrEA7RS3u1OP6nVNUaiXRX90Q1BidZp1c9y2NvGdgx/DX9fx8PPLFYDlidqmj6i4S0oQOLlDXvRDtOJh4RM1BRuKJ0n9zT7F62Pf+PwYSVum88X3PC39FrsuoxAKNA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621351030659369.50876511383376; Tue, 18 May 2021 08:17:10 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239100AbhERPLu (ORCPT ); Tue, 18 May 2021 11:11:50 -0400 Received: from mail.kernel.org ([198.145.29.99]:49522 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245708AbhERPK3 (ORCPT ); Tue, 18 May 2021 11:10:29 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 43DA561376; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOk-Ho; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=irwt4RJFPgBRv9/8y13zzRL/edaGKx0UeKl9yigDS0M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=db1LhzBiRIIlRiB7UoFwrmSfyzqvvSI2W++A5Tnq/22PoSxQWTZKH7zhmvBSC1bKr KNkDRbDgoKNLKqZ8Pqdw1oTLmFE+Fkan3rkNd6ONzlNk+BfjtRERVn6qqxk0JOEh6R DExfTiz1iM69QqmjUo0kKsrbmm+Vale6QfYTPZBcbrfEec92tp+H4rQ0/eFr6UsVvL SbcW921TtUOcYr0a2QhdBEHEDbL0T6TmjwSQhSn1fRip3wvtUt7/OPscGfZuSLJFx4 R/4O1IGRIN4Fvo5ZzswS9KfQ5eDyUG19U+yfEDGVEmoyg9S2tH7/rOfNvT6BkmPqld pQ1uUwG+YxS8w== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 13/17] leds: leds-nuc: better detect NUC6/NUC7 devices Date: Tue, 18 May 2021 17:09:02 +0200 Message-Id: <29e9896e41eec83e8e775295d92fe3034735c792.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" There's no documented way to detect if the WMI API is valid, as, when it is not valid, it just returns 4 zeros. However, as having a value of 0x00 for the blinking state is not valid, we can check for it at detection time, in order to disable LEDs control on devices that won't support it. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 6aa0bf16c8b7..af57f54cfb05 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -312,6 +312,13 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) return ret; } =20 + /* + * Detect if NUC6/NUC7 supports the WMI API by checking the + * returned blink state, as valid values range from 0x01 to 0x07. + */ + if (output[1] =3D=3D 0x00) + return -ENODEV; + led =3D &priv->led[priv->num_leds]; led->id =3D POWER_LED; led->color_type =3D LED_BLUE_AMBER; @@ -325,6 +332,14 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) dev_warn(dev, "Get S0 Ring: error %d\n", ret); return ret; } + + /* + * Detect if NUC6/NUC7 supports the WMI API by checking the + * returned blink state, as valid values range from 0x01 to 0x07. + */ + if (output[1] =3D=3D 0x00) + return -ENODEV; + led =3D &priv->led[priv->num_leds]; led->id =3D RING_LED; led->color_type =3D LED_BLUE_AMBER; --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350904; cv=none; d=zohomail.com; s=zohoarc; b=W2CcoEDs+VJsNSe0xc2ikxL7E3OuWthMzbdQ+lLBhT13eB6QSUNKdhiz6FZqLioeZ0/E5m7bhKBa86ucUAz+DMvinsRPtmDFovzizAva3x0g4jftMzbLZcKrXN3OtjszjF+5Yzq0iki8JABsAGQA9H3UGZMcVXe6RbQYqAkGky0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350904; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=WbXxd2NgJ1x8XzQAyGr5HMCydlf4nrRXi3uTW8zRDbA=; b=dKidUgGCrjmAFh61Owzw6YEtMIw9vom/IpvhsMiOtkQzFnkCsPqwOeWrfyZQHEpsFQ5jscfFBWFOL5oOtH1HzYBLkF4u5TvtsVwQoIXAYDK9C05r7EjQGCRvzX5nux50DtVeWe9zaTn7F3n7FNIqDjPkBK/Nuzpfy8y1ESrlTqE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350904340884.0727962927486; Tue, 18 May 2021 08:15:04 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350056AbhERPMQ (ORCPT ); Tue, 18 May 2021 11:12:16 -0400 Received: from mail.kernel.org ([198.145.29.99]:49540 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343957AbhERPKa (ORCPT ); Tue, 18 May 2021 11:10:30 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5321961377; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOo-JV; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=n6zLHZrATy+wjzdZFOZuRrEPeNvHyrUErO937oDY13M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=j3V0PB8oVMkFDifntPLPtzAMRoexdcP+9UbESVhzL7vyg3xMjbHIoXURXCgvuDl4c yOsV7Gd/ffsmgOA6xHowdRXg+DYPIQGPT8+B5ATl7KcFdVwTcoc/4Rv5YS7B12iDji 8R+YrB/IpbQaVPg4y690M7KFo9gr7pjTqCe0fZxjrLHTCxLczmRRs+cE/2S5ms7dT+ aCGAyNWqb5+2VL/E0wN+qO0z4mWviSoqE4l0obEwXtpF5fQNFa3HBoLHJr5HNz8WOl ugSpeJFekzafFSGfUVdJXCYaI1SVHHOEiURalx/h8riSQ2tM221cPw6AOANqpfYkJ9 ODuhrJ/aLkjsA== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 14/17] leds: leds-nuc: add support for HDD activity default Date: Tue, 18 May 2021 17:09:03 +0200 Message-Id: <08d9c1d025e25a1a095089b9c38a780aef8fb797.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" There are two possible values for HDD activity behavior: - 0 Normally off, ON when active - 1 Normally on, OFF when active Implement a logic to set it. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 77 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index af57f54cfb05..719a57841c03 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -1629,10 +1629,86 @@ static umode_t nuc_wmi_led_blink_is_visible(struct = kobject *kobj, return 0; } =20 +/* HDD activity behavior */ +static ssize_t show_hdd_default(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val; + + if (led->indicator !=3D LED_IND_HDD_ACTIVITY) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_HDD_BEHAVIOR]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val =3D output[0]; + + if (val =3D=3D 0) + return scnprintf(buf, PAGE_SIZE, "off\n"); + + return scnprintf(buf, PAGE_SIZE, "on\n"); +} + +static ssize_t store_hdd_default(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator !=3D LED_IND_HDD_ACTIVITY) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_HDD_BEHAVIOR]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp =3D strsep((char **)&buf, "\n"); + if (!strcmp(tmp, "on")) + val =3D 1; + else if (!strcmp(tmp, "off")) + val =3D 0; + else + return -EINVAL; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); +static LED_ATTR_RW(hdd_default); =20 LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1660,6 +1736,7 @@ LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blin= k_frequency, 2); =20 static struct attribute *nuc_wmi_led_attr[] =3D { &dev_attr_indicator.attr, + &dev_attr_hdd_default.attr, NULL, }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350919; cv=none; d=zohomail.com; s=zohoarc; b=bIgf0/dNPg9Nh1J0SDlFdgtiRXvtb8zvuX6PjNs8FnJbP/zOTmPutQBICc1NM1Aq1rFvfNBdsn0VmKrRvwEkZ9bV4rpSbsO00tE06L+rI7EfqldN9JrE+SEZrPZgFtRHd/ksp6eX/n2Q14yB9bKNhkVb5103xvZuU9XZA3Rkdog= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350919; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=Ix827uKZ1gFJ4VhfNGNYtp939OBCJiNkcXboYtv4uMg=; b=E0TGThm9wtKyR++4OsGpHcRlTtB7j3Mz0L6CZ9g+mclGZnVOVWhndpPSRVUx5//mtbHrGKIk8wm8ofWZptSkRL/sxenHGX65/dKSoqLngcZ9dMq+FvYG+DecmUYzsNB+xJANYgjFwH0rx7HXy4rjJpk2+wC2vdz9uLK+OpF5MMg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350919780826.542625602222; Tue, 18 May 2021 08:15:19 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350134AbhERPM3 (ORCPT ); Tue, 18 May 2021 11:12:29 -0400 Received: from mail.kernel.org ([198.145.29.99]:49628 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344982AbhERPKe (ORCPT ); Tue, 18 May 2021 11:10:34 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 6ADCF613B4; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOs-Kf; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=8fwuaq8tsCOrCFnHrBrg5Jr8mMwviHOuxKo1IfHykBs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q7b9VfADkXACHt69AAPgCNc1IWGXY7tSSU89sIzY6b12t3jlbaL28p23dYoz2H773 F9FzP0clVvTDHchSQJYwlapeP0hx8l8XXv5kY7VkKb40kOxkZ/KrCkH8M60ENDJ14b +MFGD3JHLmN+L+87OyxNIoxfz+D4QipuvMhPISZvwn2hmWeTlz/kA5gjxOoce3Ftkm g2uWChrKkK0f1Va6TZuyel86dtlggojJOwiZHTAUQ6t2jtsjjeBj9U4/3k68TWsd98 bDC9g8IlSxNwod1vofcwayKg/jC954BF4ElTtf5GmXlOM3us+7cynBpCmUlqABWW4Q 0Jv8sqBp/LLNw== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 15/17] leds: leds-nuc: fix software blink behavior logic Date: Tue, 18 May 2021 17:09:04 +0200 Message-Id: <44aed20dc44c893c12ad26b109a8a0e49bc4dab0.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The is_visible logic for it is plain wrong: 1. it is used only during devnode creation; 2. it was using the wrong field (id, instead of indicator). Fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 719a57841c03..4d4ea6fbeff4 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -1479,6 +1479,9 @@ static ssize_t show_blink_behavior(struct device *dev, if (led->api_rev =3D=3D LED_API_NUC6) return nuc6_show_blink_behavior(dev, attr, buf); =20 + if (led->indicator !=3D LED_IND_SOFTWARE) + return -EINVAL; + return offset_show_blink_behavior(dev, attr, 0, buf); } =20 @@ -1492,6 +1495,9 @@ static ssize_t store_blink_behavior(struct device *de= v, if (led->api_rev =3D=3D LED_API_NUC6) return nuc6_store_blink_behavior(dev, attr, buf, len); =20 + if (led->indicator !=3D LED_IND_SOFTWARE) + return -EINVAL; + return offset_store_blink_behavior(dev, attr, 0, buf, len); } =20 @@ -1596,6 +1602,9 @@ static ssize_t show_blink_frequency(struct device *de= v, if (led->api_rev =3D=3D LED_API_NUC6) return nuc6_show_blink_frequency(dev, attr, buf); =20 + if (led->indicator !=3D LED_IND_SOFTWARE) + return -EINVAL; + return offset_show_blink_frequency(dev, attr, 0, buf); } =20 @@ -1609,26 +1618,12 @@ static ssize_t store_blink_frequency(struct device = *dev, if (led->api_rev =3D=3D LED_API_NUC6) return nuc6_store_blink_frequency(dev, attr, buf, len); =20 + if (led->indicator !=3D LED_IND_SOFTWARE) + return -EINVAL; + return offset_store_blink_frequency(dev, attr, 0, buf, len); } =20 -static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, - struct attribute *attr, int idx) -{ - struct device *dev =3D kobj_to_dev(kobj); - struct led_classdev *cdev =3D dev_get_drvdata(dev); - struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); - umode_t mode =3D attr->mode; - - if (led->api_rev =3D=3D LED_API_NUC6) - return mode; - - if (led->id =3D=3D LED_IND_SOFTWARE) - return mode; - - return 0; -} - /* HDD activity behavior */ static ssize_t show_hdd_default(struct device *dev, struct device_attribute *attr, @@ -1788,7 +1783,6 @@ static struct attribute *nuc_wmi_led_blink_behavior_a= ttr[] =3D { }; =20 static const struct attribute_group nuc_wmi_led_blink_attribute_group =3D { - .is_visible =3D nuc_wmi_led_blink_is_visible, .attrs =3D nuc_wmi_led_blink_behavior_attr, }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350925; cv=none; d=zohomail.com; s=zohoarc; b=nHvVNFdjuaoj0+P8rp7lrEgt9pKx88ujfnnD3fP3Y2PTyhirHhiqLIq4FGvXEe9iByBLv8vkxCK5p6VtcqLR8E5xgAY2BTy4UfBkaqUkLvYZh3lojqt8VE+eBcL4+87CO+f4n2AnJHs57HeLmems/NedpDpABL4JAYGfV1x7IKU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350925; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=dvM0Oqd/+J5FEvOLxy2PQ/S/PbxZLFgb947fjD4dRhA=; b=OS8nPbWjuxnMZqVB0tqba/O/jhDcY/vvq/PRTXOVV09S5oMYruXXI/tXPzPEAXTluDeVjBWfm8YX5or1SU+3ypP08krqrz4MbH94ZKqBEoTMCt9YTOjjaO2lJTDEYwF2gvMGbzG78Z6kVjGabLFVH9xkoJaXdWUZo/EP4GVULOk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350925193137.63976452533393; Tue, 18 May 2021 08:15:25 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242985AbhERPMf (ORCPT ); Tue, 18 May 2021 11:12:35 -0400 Received: from mail.kernel.org ([198.145.29.99]:49626 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344988AbhERPKe (ORCPT ); Tue, 18 May 2021 11:10:34 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 66FDF613AF; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HOw-MP; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=DLdEfx6xwQIJPGQdiBgHEYPiWWkAAU8NZ8TS0QVIJfo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SHXdEkXqJRbfyeImoZNRyK3cV+2OWJTIzLCRSpmvac0YB36l64vEcf3j8IMHwMzTr rdsUkP+i/e/mc97bjaPSUQ8CCMqzes0zhdPPmsv2lrL8ns1LRVUWSf3sbWwqaerr3V 36c9twPHni0prdQ6TqwkytqFHxa9NWMt2pHLKeFqtehyczzW7jBOXWx2zK7vPZdznG emAmqCnOd4VJIzw356tuwW+Sc5Xduo9yncKW/ks1Y5vlTCXogUSvVCYvLF8EEDJcaa /U2ltWkejDiQUgsao9DuagaHyWLCjYbN+zSldjWBeUdbaRgKS5C+CwV/RcduEle03H 3x6cTZSU5Cf4w== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 16/17] leds: leds-nuc: add support for changing the ethernet type indicator Date: Tue, 18 May 2021 17:09:05 +0200 Message-Id: <792598f4a1a3219b6517057c92559b0f0a95b419.1621349814.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The Ethernet type indicator can be configured to show the status of LAN1, LAN1 or both. Add support for it. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index 4d4ea6fbeff4..f84ec5662f5c 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -1698,12 +1698,100 @@ static ssize_t store_hdd_default(struct device *de= v, return len; } =20 +/* Ethernet type */ +static const char * const ethernet_type[] =3D { + "LAN1", + "LAN2", + "LAN1+LAN2" +}; + +static ssize_t show_ethernet_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + if (led->indicator !=3D LED_IND_ETHERNET) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_ETH_TYPE]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val =3D output[0]; + + for (i =3D 0; i < ARRAY_SIZE(ethernet_type); i++) { + if (i =3D=3D val) + n =3D scnprintf(p, size, "[%s] ", ethernet_type[i]); + else + n =3D scnprintf(p, size, "%s ", ethernet_type[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_ethernet_type(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator !=3D LED_IND_ETHERNET) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_ETH_TYPE]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + for (val =3D 0; val < ARRAY_SIZE(ethernet_type); val++) + if (!strcasecmp(tmp, ethernet_type[val])) + break; + + if (val >=3D ARRAY_SIZE(ethernet_type)) + return -EINVAL; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} =20 static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); static LED_ATTR_RW(hdd_default); +static LED_ATTR_RW(ethernet_type); =20 LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1732,6 +1820,7 @@ LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blin= k_frequency, 2); static struct attribute *nuc_wmi_led_attr[] =3D { &dev_attr_indicator.attr, &dev_attr_hdd_default.attr, + &dev_attr_ethernet_type.attr, NULL, }; =20 --=20 2.31.1 From nobody Thu May 9 23:47:33 2024 Delivered-To: importer2@patchew.org Received-SPF: pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; envelope-from=linux-kernel-owner@vger.kernel.org; helo=vger.kernel.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass(p=none dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1621350932; cv=none; d=zohomail.com; s=zohoarc; b=UR7NeC2N/ghzP8+ne+VrXRKEiZ0Ss4ZsHhhj8bbLq2BxcWYpNbhK7XmY3xvPe8dkXGZzf8iTDjNsIqm4iGC3M+EwXZycfITJJWMhwNJ0HOGFNKih9NxDLUs48NZuplUlap2PygGSuh84NDkMWKSZHRBILREtnccXrDKO1MlX87w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1621350932; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:MIME-Version:Message-ID:References:Sender:Subject:To; bh=MlDizexYHgFnPFTXyNS1ZESKtoQ3Qdzha35dkukb1fo=; b=e3Z/heMG+6cn1nQnFvwpze9AxmFM3COsCkn1io1Br+sR924YIyy+0zt8xtu9FOdvVDdof1zCcsv+6+KA5k13OWz2cXy7McIW2dAhajyg0n4x6mG8IAy20jlQGo0hxjbmGxFzHPpjkZA+STRKR9Qq+7XQF6Nca5XlWf4O5TBK8P4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mx.zohomail.com with SMTP id 1621350932799385.67793544180824; Tue, 18 May 2021 08:15:32 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350078AbhERPMh (ORCPT ); Tue, 18 May 2021 11:12:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:49496 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345055AbhERPKh (ORCPT ); Tue, 18 May 2021 11:10:37 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 6F6C1613B5; Tue, 18 May 2021 15:09:10 +0000 (UTC) Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1lj1LI-007HP0-Nd; Tue, 18 May 2021 17:09:08 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621350550; bh=3crpsUukJiwOrmYoQySDsb9Gg2iiXjFUvVuCwAECZfw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ND+HmJkIOBv/3v4uWcAy+U/+zYYO5wypLavi4OJxHUAZ2s3/xeTiO0JsKIT/UDA+U fB9hHWo0t6gHMSld1Ex4kGFCBUUgXPtltHpl/cl1S/Bn1STNIIzW+DVinoBh7Q/17e 0N+gXzuqNgMVQQ+2/zUmf7TUQCTFYWlTtDNu/fMQUYATNj/WYPxlFo5hrfxgfqOqtu yzbTWIPkA06V94opowwU1mHCKpvqBfWGzAW44Mbk4cd2gAPMneufvVvNP/o62ldynN JcHmWDwpotSWEBv2D0QNXVXZ2i9WKjREYlmC3szXREJoLgso5n5flv4biKCc+jX6zg 0m55NBCfZNG7Q== From: Mauro Carvalho Chehab Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , Pavel Machek , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v2 17/17] leds: leds-nuc: add support for changing the power limit scheme Date: Tue, 18 May 2021 17:09:06 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" The power limit indicator may have 2 behaviors: 1. Its color gradually changes from green to red; 2. It displays a single color Add support for it. Signed-off-by: Mauro Carvalho Chehab --- drivers/leds/leds-nuc.c | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c index f84ec5662f5c..c320a7e4c796 100644 --- a/drivers/leds/leds-nuc.c +++ b/drivers/leds/leds-nuc.c @@ -1767,6 +1767,8 @@ static ssize_t store_ethernet_type(struct device *dev, if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; =20 + tmp =3D strsep((char **)&buf, "\n"); + for (val =3D 0; val < ARRAY_SIZE(ethernet_type); val++) if (!strcasecmp(tmp, ethernet_type[val])) break; @@ -1786,12 +1788,102 @@ static ssize_t store_ethernet_type(struct device *= dev, return len; } =20 +/* Power Limit Indication scheme */ +static const char * const power_limit_scheme[] =3D { + "green to red", + "single color" +}; + +static ssize_t show_power_limit_scheme(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val, i, n; + int size =3D PAGE_SIZE; + char *p =3D buf; + + if (led->indicator !=3D LED_IND_POWER_LIMIT) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] =3D LED_NEW_GET_CONTROL_ITEM; + input[1] =3D led->id; + input[2] =3D led->indicator; + input[3] =3D ctrl; + + ret =3D nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val =3D output[0]; + + for (i =3D 0; i < ARRAY_SIZE(power_limit_scheme); i++) { + if (i =3D=3D val) + n =3D scnprintf(p, size, "[%s] ", power_limit_scheme[i]); + else + n =3D scnprintf(p, size, "%s ", power_limit_scheme[i]); + p +=3D n; + size -=3D n; + } + size -=3D scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_power_limit_scheme(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev =3D dev_get_drvdata(dev); + struct nuc_nmi_led *led =3D container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] =3D { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator !=3D LED_IND_POWER_LIMIT) + return -EINVAL; + + ctrl =3D led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp =3D strsep((char **)&buf, "\n"); + + for (val =3D 0; val < ARRAY_SIZE(power_limit_scheme); val++) + if (!strcasecmp(tmp, power_limit_scheme[val])) + break; + + if (val >=3D ARRAY_SIZE(power_limit_scheme)) + return -EINVAL; + + input[0] =3D led->id; + input[1] =3D led->indicator; + input[2] =3D ctrl; + input[3] =3D val; + + ret =3D nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); static LED_ATTR_RW(hdd_default); static LED_ATTR_RW(ethernet_type); +static LED_ATTR_RW(power_limit_scheme); =20 LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1821,6 +1913,7 @@ static struct attribute *nuc_wmi_led_attr[] =3D { &dev_attr_indicator.attr, &dev_attr_hdd_default.attr, &dev_attr_ethernet_type.attr, + &dev_attr_power_limit_scheme.attr, NULL, }; =20 --=20 2.31.1