]> git.proxmox.com Git - mirror_ubuntu-impish-kernel.git/commitdiff
UBUNTU: ODM: leds: add driver for AAEON devices
authorKunyang_Fan <kunyang_fan@asus.com>
Wed, 16 Jun 2021 05:57:02 +0000 (13:57 +0800)
committerAndrea Righi <andrea.righi@canonical.com>
Mon, 28 Jun 2021 06:04:07 +0000 (08:04 +0200)
BugLink: https://bugs.launchpad.net/bugs/1929504
This patch adds support for the led devices which can
be controlled from sysfs through ASUS WMI interface.

Signed-off-by: Kunyang_Fan <kunyang_fan@asus.com>
Review-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Review-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-aaeon.c [new file with mode: 0644]

index bd29f800ff67c9c6e3776b6bf19d35779726a096..d6b69f8ccc12daf125d16ec454148b2e1ecc84b7 100644 (file)
@@ -59,6 +59,18 @@ config LEDS_88PM860X
          This option enables support for on-chip LED drivers found on Marvell
          Semiconductor 88PM8606 PMIC.
 
+config LEDS_AAEON
+       tristate "AAEON LED driver"
+       depends on X86
+       depends on UBUNTU_ODM_DRIVERS
+       select MFD_AAEON
+       help
+         This led driver adds support for LED brightness control on Single
+         Board Computers produced by AAEON.
+
+         This driver leverages the ASUS WMI interface to access device
+         resources.
+
 config LEDS_AAT1290
        tristate "LED support for the AAT1290"
        depends on LEDS_CLASS_FLASH
index 7e604d3028c80ac9e4998582b473ef227213b2e1..0acaa46185f5f2c4234bccd4b8472ecbe55c2bfd 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_LEDS_TRIGGERS)             += led-triggers.o
 
 # LED Platform Drivers (keep this sorted, M-| sort)
 obj-$(CONFIG_LEDS_88PM860X)            += leds-88pm860x.o
+obj-$(CONFIG_LEDS_AAEON)               += leds-aaeon.o
 obj-$(CONFIG_LEDS_AAT1290)             += leds-aat1290.o
 obj-$(CONFIG_LEDS_ACER_A500)           += leds-acer-a500.o
 obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
diff --git a/drivers/leds/leds-aaeon.c b/drivers/leds/leds-aaeon.c
new file mode 100644 (file)
index 0000000..10090a4
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AAEON LED driver
+ *
+ * Copyright (c) 2021, AAEON Ltd.
+ *
+ * Author: Kunyang Fan <kunyang_fan@aaeon.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/platform_device.h>
+
+#define DRVNAME "led_aaeon"
+#define ASUS_NB_WMI_EVENT_GUID   "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+#define AAEON_WMI_MGMT_GUID      "97845ED0-4E6D-11DE-8A39-0800200C9A66"
+
+#define GET_LED_NUMBER_ID        0x00060000
+#define GET_LED_METHOD_ID        0x00060001
+#define SET_LED_METHOD_ID        0x00060002
+#define GET_LED_NUMBER_METHOD_ID 0x10
+
+
+struct aaeon_led_data {
+       int id;
+       struct led_classdev cdev;
+};
+
+static int aaeon_led_get_number(void)
+{
+       int err, retval;
+
+       err = asus_wmi_evaluate_method(GET_LED_NUMBER_ID,
+                                      GET_LED_NUMBER_METHOD_ID,
+                                      0, &retval);
+       if (err)
+               return err;
+
+       return retval;
+}
+
+static enum led_brightness aaeon_led_brightness_get(struct led_classdev
+                                                     *cdev)
+{
+       int err, brightness;
+       struct aaeon_led_data *led =
+                       container_of(cdev, struct aaeon_led_data, cdev);
+       u32 arg0;
+
+       arg0 = (u32)(led->id & 0xF);
+       err = asus_wmi_evaluate_method(GET_LED_METHOD_ID, arg0, 0, &brightness);
+       if (err)
+               return err;
+
+       return brightness;
+};
+
+static void aaeon_led_brightness_set(struct led_classdev *cdev,
+                                      enum led_brightness brightness)
+{
+       int err, retval;
+       struct aaeon_led_data *led =
+                       container_of(cdev, struct aaeon_led_data, cdev);
+       u32 arg0;
+
+       arg0 = (u32)(led->id & 0xF);
+       if (brightness != LED_OFF)
+               arg0 |= BIT(16);
+
+       err = asus_wmi_evaluate_method(SET_LED_METHOD_ID, arg0, 0, &retval);
+};
+
+static int __init aaeon_add_led_device(struct platform_device *pdev,
+                                          int id)
+{
+       struct aaeon_led_data *led;
+
+       led = devm_kzalloc(&pdev->dev, sizeof(struct aaeon_led_data), GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       led->id = id;
+       led->cdev.brightness_get = aaeon_led_brightness_get;
+       led->cdev.brightness_set = aaeon_led_brightness_set;
+       led->cdev.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "led:%d:", id);
+
+       if (!led->cdev.name)
+               return -ENOMEM;
+
+       return devm_led_classdev_register(&pdev->dev, &led->cdev);
+}
+
+static int aaeon_led_probe(struct platform_device *pdev)
+{
+       int err = -ENODEV, i;
+       int led_number = 0;
+
+       pr_debug("aaeon led device probe!\n");
+       /* Prevent other drivers adding this platfom device */
+       if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) {
+               pr_debug("AAEON Management GUID not found\n");
+               return -ENODEV;
+       }
+
+       /* Query the number of led devices board support */
+       led_number = aaeon_led_get_number();
+
+       /*
+        * If the number is 0 or can't get the number of leds,
+        * no need to register any led device node.
+        */
+       if (led_number <= 0)
+               return -ENODEV;
+
+       for (i = 0; i < led_number; i++) {
+               err = aaeon_add_led_device(pdev, i);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+static struct platform_driver aaeon_led_driver = {
+       .driver = {
+               .name = "leds-aaeon",
+       },
+};
+
+module_platform_driver_probe(aaeon_led_driver, aaeon_led_probe);
+
+MODULE_ALIAS("platform:leds-aaeon");
+MODULE_DESCRIPTION("AAEON LED Driver");
+MODULE_AUTHOR("Kunyang Fan <kunyang_fan@asus.com>");
+MODULE_LICENSE("GPL v2");