]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/leds/leds-aaeon.c
mwifiex: Read a PCI register after writing the TX ring write pointer
[mirror_ubuntu-jammy-kernel.git] / drivers / leds / leds-aaeon.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AAEON LED driver
4 *
5 * Copyright (c) 2021, AAEON Ltd.
6 *
7 * Author: Kunyang Fan <kunyang_fan@aaeon.com.tw>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14 #include <linux/acpi.h>
15 #include <linux/bitops.h>
16 #include <linux/leds.h>
17 #include <linux/module.h>
18 #include <linux/platform_data/x86/asus-wmi.h>
19 #include <linux/platform_device.h>
20
21 #define DRVNAME "led_aaeon"
22 #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
23 #define AAEON_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
24
25 #define GET_LED_NUMBER_ID 0x00060000
26 #define GET_LED_METHOD_ID 0x00060001
27 #define SET_LED_METHOD_ID 0x00060002
28 #define GET_LED_NUMBER_METHOD_ID 0x10
29
30
31 struct aaeon_led_data {
32 int id;
33 struct led_classdev cdev;
34 };
35
36 static int aaeon_led_get_number(void)
37 {
38 int err, retval;
39
40 err = asus_wmi_evaluate_method(GET_LED_NUMBER_ID,
41 GET_LED_NUMBER_METHOD_ID,
42 0, &retval);
43 if (err)
44 return err;
45
46 return retval;
47 }
48
49 static enum led_brightness aaeon_led_brightness_get(struct led_classdev
50 *cdev)
51 {
52 int err, brightness;
53 struct aaeon_led_data *led =
54 container_of(cdev, struct aaeon_led_data, cdev);
55 u32 arg0;
56
57 arg0 = (u32)(led->id & 0xF);
58 err = asus_wmi_evaluate_method(GET_LED_METHOD_ID, arg0, 0, &brightness);
59 if (err)
60 return err;
61
62 return brightness;
63 };
64
65 static void aaeon_led_brightness_set(struct led_classdev *cdev,
66 enum led_brightness brightness)
67 {
68 int err, retval;
69 struct aaeon_led_data *led =
70 container_of(cdev, struct aaeon_led_data, cdev);
71 u32 arg0;
72
73 arg0 = (u32)(led->id & 0xF);
74 if (brightness != LED_OFF)
75 arg0 |= BIT(16);
76
77 err = asus_wmi_evaluate_method(SET_LED_METHOD_ID, arg0, 0, &retval);
78 };
79
80 static int __init aaeon_add_led_device(struct platform_device *pdev,
81 int id)
82 {
83 struct aaeon_led_data *led;
84
85 led = devm_kzalloc(&pdev->dev, sizeof(struct aaeon_led_data), GFP_KERNEL);
86 if (!led)
87 return -ENOMEM;
88
89 led->id = id;
90 led->cdev.brightness_get = aaeon_led_brightness_get;
91 led->cdev.brightness_set = aaeon_led_brightness_set;
92 led->cdev.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "led:%d:", id);
93
94 if (!led->cdev.name)
95 return -ENOMEM;
96
97 return devm_led_classdev_register(&pdev->dev, &led->cdev);
98 }
99
100 static int aaeon_led_probe(struct platform_device *pdev)
101 {
102 int err = -ENODEV, i;
103 int led_number = 0;
104
105 pr_debug("aaeon led device probe!\n");
106 /* Prevent other drivers adding this platfom device */
107 if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) {
108 pr_debug("AAEON Management GUID not found\n");
109 return -ENODEV;
110 }
111
112 /* Query the number of led devices board support */
113 led_number = aaeon_led_get_number();
114
115 /*
116 * If the number is 0 or can't get the number of leds,
117 * no need to register any led device node.
118 */
119 if (led_number <= 0)
120 return -ENODEV;
121
122 for (i = 0; i < led_number; i++) {
123 err = aaeon_add_led_device(pdev, i);
124 if (err)
125 break;
126 }
127
128 return err;
129 }
130
131 static struct platform_driver aaeon_led_driver = {
132 .driver = {
133 .name = "leds-aaeon",
134 },
135 };
136
137 module_platform_driver_probe(aaeon_led_driver, aaeon_led_probe);
138
139 MODULE_ALIAS("platform:leds-aaeon");
140 MODULE_DESCRIPTION("AAEON LED Driver");
141 MODULE_AUTHOR("Kunyang Fan <kunyang_fan@asus.com>");
142 MODULE_LICENSE("GPL v2");