From patchwork Wed Dec 16 01:40:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 11976149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F3050C4361B for ; Wed, 16 Dec 2020 01:41:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C56FE22D75 for ; Wed, 16 Dec 2020 01:41:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725833AbgLPBlg (ORCPT ); Tue, 15 Dec 2020 20:41:36 -0500 Received: from mail-40134.protonmail.ch ([185.70.40.134]:45094 "EHLO mail-40134.protonmail.ch" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725817AbgLPBlg (ORCPT ); Tue, 15 Dec 2020 20:41:36 -0500 Date: Wed, 16 Dec 2020 01:40:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail; t=1608082843; bh=SNNA/jJUHx5LZShaJGbm+Lh0h+qnbxD1WMNynpqX81w=; h=Date:To:From:Reply-To:Subject:From; b=JuAsOi2rYN6N3WR64nzQD0z6hy6dW++71u5UhLkOJpPMk3NQcCqFXbGBnZ5ZIqYFP MO77j8F/Q6WsaVyi/bWAyII6G9QV9wdnO6m6/K6nRAbS+rdVPTofQ9awLzHgUx/BDb txVOwVH2KrvVCoxlIXwzcKP/M9vFIsJ5lFz98WJk= To: platform-driver-x86@vger.kernel.org, Hans de Goede , Mark Gross , Ike Panhc From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= Reply-To: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= Subject: [PATCH 21/24] platform/x86: ideapad-laptop: add keyboard backlight control support Message-ID: <20201216013857.360987-22-pobrn@protonmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org On certain models it is possible to control/query the keyboard backlight via the SALS/HALS ACPI methods. Add support for that, and register an LED class device to expose this functionality. Tested on: Lenovo YOGA 520-14IKB 80X8 Signed-off-by: Barnabás Pőcze diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 075056075b2d..a43574e65f61 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -56,12 +58,16 @@ enum { }; enum { + HALS_KBD_BL_SUPPORT_BIT = 4, + HALS_KBD_BL_STATE_BIT = 5, HALS_FNLOCK_SUPPORT_BIT = 9, HALS_FNLOCK_STATE_BIT = 10, HALS_HOTKEYS_PRIMARY_BIT = 11, }; enum { + SALS_KBD_BL_ON = 0x8, + SALS_KBD_BL_OFF = 0x9, SALS_FNLOCK_ON = 0xe, SALS_FNLOCK_OFF = 0xf, }; @@ -114,6 +120,11 @@ struct ideapad_private { fn_lock : 1, hw_rfkill_switch : 1; } features; + struct { + bool initialized; + struct led_classdev led; + unsigned int last_brightness; + } kbd_bl; }; static bool no_bt_rfkill; @@ -934,6 +945,110 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); } +/* + * keyboard backlight + */ +static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv) +{ + unsigned long hals; + int err; + + err = eval_hals(priv->adev->handle, &hals); + if (err) + return err; + + return test_bit(HALS_KBD_BL_STATE_BIT, &hals); +} + +static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct led_classdev *led_cdev) +{ + struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led); + + return ideapad_kbd_bl_brightness_get(priv); +} + +static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, unsigned int brightness) +{ + int err; + + err = eval_sals(priv->adev->handle, + brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF); + if (err) + return err; + + priv->kbd_bl.last_brightness = brightness; + + return 0; +} + +static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led); + + return ideapad_kbd_bl_brightness_set(priv, brightness); +} + +static void ideapad_kbd_bl_notify(struct ideapad_private *priv) +{ + int brightness; + + if (!priv->kbd_bl.initialized) + return; + + brightness = ideapad_kbd_bl_brightness_get(priv); + if (brightness < 0) + return; + + if (brightness == priv->kbd_bl.last_brightness) + return; + + priv->kbd_bl.last_brightness = brightness; + + led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness); +} + +static int ideapad_kbd_bl_init(struct ideapad_private *priv) +{ + unsigned long hals; + int err; + + err = eval_hals(priv->adev->handle, &hals); + if (err) + return err; + + if (!test_bit(HALS_KBD_BL_SUPPORT_BIT, &hals)) + return -ENODEV; + + err = ideapad_kbd_bl_brightness_get(priv); + if (err < 0) + return err; + + priv->kbd_bl.last_brightness = err; + + priv->kbd_bl.led.name = "platform::" LED_FUNCTION_KBD_BACKLIGHT; + priv->kbd_bl.led.max_brightness = 1; + priv->kbd_bl.led.brightness_get = ideapad_kbd_bl_led_cdev_brightness_get; + priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set; + priv->kbd_bl.led.flags = LED_BRIGHT_HW_CHANGED; + + err = led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.led); + if (err) + return err; + + priv->kbd_bl.initialized = true; + + return 0; +} + +static void ideapad_kbd_bl_exit(struct ideapad_private *priv) +{ + if (!priv->kbd_bl.initialized) + return; + + led_classdev_unregister(&priv->kbd_bl.led); +} + /* * module init/exit */ @@ -1000,8 +1115,9 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) * Some IdeaPads report event 1 every ~20 * seconds while on battery power; some * report this when changing to/from tablet - * mode. Squelch this event. + * mode. */ + ideapad_kbd_bl_notify(priv); break; default: dev_warn(&priv->platform_device->dev, @@ -1101,6 +1217,11 @@ static int ideapad_acpi_add(struct platform_device *pdev) if (err) goto input_failed; + err = ideapad_kbd_bl_init(priv); + if (err && err != -ENODEV) + dev_warn(&pdev->dev, + "Could not register keyboard backlight led: %d\n", err); + /* * On some models without a hw-switch (the yoga 2 13 at least) * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. @@ -1161,6 +1282,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) ideapad_unregister_rfkill(priv, i); + ideapad_kbd_bl_exit(priv); ideapad_input_exit(priv); input_failed: @@ -1188,6 +1310,7 @@ static int ideapad_acpi_remove(struct platform_device *pdev) for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) ideapad_unregister_rfkill(priv, i); + ideapad_kbd_bl_exit(priv); ideapad_input_exit(priv); ideapad_debugfs_exit(priv); ideapad_sysfs_exit(priv);