From 66b616677d8f76c88920eda02a38403581b8e867 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Fri, 10 Feb 2023 14:22:10 +0100 Subject: [PATCH 01/11] fbd-dev-led-multicolor: Use separate log domain Debugging driver probing is much easier when each driver has its own log domain. --- src/fbd-dev-led-multicolor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index d48ddc0..425ee4f 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -6,7 +6,7 @@ * See Documentation/ABI/testing/sysfs-class-led-trigger-pattern */ -#define G_LOG_DOMAIN "fbd-dev-led" +#define G_LOG_DOMAIN "fbd-dev-led-multicolor" #include "fbd-dev-led-priv.h" #include "fbd-dev-led-multicolor.h" From 7f69813e84973ca41ebb2890f8b91055bbf69ff3 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sun, 19 May 2024 18:46:08 +0200 Subject: [PATCH 02/11] fbd-dev-led-multicolor: Fix typo in error message multicololo -> multicolor LED --- src/fbd-dev-led-multicolor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index 425ee4f..30a89ef 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -53,7 +53,7 @@ fbd_dev_led_probe_multicolor (FbdDevLed *led, GError **error) if (index == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - "%s is no multicololor LED", name); + "%s is no multicolor LED", name); return FALSE; } From 94afe719a9fc2084fe32fc958ef0a85a6a3358f1 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sun, 19 May 2024 18:21:40 +0200 Subject: [PATCH 03/11] fbd-dev-led: Scan for RGB color as well Multicolor LEDs have the color 'rgb', we should also scan it as they are also a FbdDevLed. --- src/fbd-dev-led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c index 8c48e67..f577229 100644 --- a/src/fbd-dev-led.c +++ b/src/fbd-dev-led.c @@ -63,7 +63,7 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) /* We don't know anything about diffusors that can combine different color LEDSs so go with fixed colors until the kernel gives us enough information */ - for (int i = 0; i < FBD_FEEDBACK_LED_COLOR_RGB; i++) { + for (int i = 0; i <= FBD_FEEDBACK_LED_COLOR_LAST; i++) { g_autofree char *color = NULL; g_autofree char *enum_name = NULL; gchar *c; From bcd37b0aa574c1505f905679d315dad4f8acfec1 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Fri, 10 Feb 2023 18:01:53 +0100 Subject: [PATCH 04/11] fbd-dev-led-*: Adjust to method convention fbd_dev_led_ is the convention for methods, adjust them all. --- src/fbd-dev-led-multicolor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index 30a89ef..5d1d692 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -37,7 +37,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (FbdDevLedMulticolor, fbd_dev_led_multicolor, FBD_TYP static gboolean -fbd_dev_led_probe_multicolor (FbdDevLed *led, GError **error) +fbd_dev_led_multicolor_probe (FbdDevLed *led, GError **error) { FbdDevLedMulticolor *self = FBD_DEV_LED_MULTICOLOR (led); FbdDevLedMulticolorPrivate *priv = fbd_dev_led_multicolor_get_instance_private (self); @@ -90,7 +90,7 @@ fbd_dev_led_probe_multicolor (FbdDevLed *led, GError **error) static gboolean -fbd_dev_led_start_periodic_multicolor (FbdDevLed *led, +fbd_dev_led_multicolor_start_periodic (FbdDevLed *led, FbdFeedbackLedColor color, guint max_brightness_percentage, guint freq) @@ -160,8 +160,8 @@ fbd_dev_led_multicolor_class_init (FbdDevLedMulticolorClass *klass) { FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); - fbd_dev_led_class->probe = fbd_dev_led_probe_multicolor; - fbd_dev_led_class->start_periodic = fbd_dev_led_start_periodic_multicolor; + fbd_dev_led_class->probe = fbd_dev_led_multicolor_probe; + fbd_dev_led_class->start_periodic = fbd_dev_led_multicolor_start_periodic; fbd_dev_led_class->has_color = fbd_dev_led_has_color_multicolor; } From e43126b0072e8af742beeb1048995a3c32205351 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sat, 11 Feb 2023 12:45:00 +0100 Subject: [PATCH 05/11] fbd-dev-led: Rework color API Drop has_color API since supported colors are set during probing and can be handled completely separately from the classes for each type of hardware. Rename set_color to set_supported_color because the usage of this API is to check if the color is supported, but not setting it. Setting the color is also separated from start_periodic API to re-use multicolor across multiple LED types with a set_color API. Multicolor LEDs are actually the same as regular LEDs but they require a few additional sysfs entries to actually set the color. Single color LEDs only have a single color so the set_color method just returns TRUE for these LEDs. Supported colors are advertised through the supports_color API now. This way, each LED driver define which colors are supported through supports_color API. RGB multicolor LEDs will report only fixed colors like red, blue, green and white until the kernel can expose if a diffusor is present to mix these colors. --- src/fbd-dev-led-multicolor.c | 22 +++--------- src/fbd-dev-led-priv.h | 2 +- src/fbd-dev-led.c | 70 ++++++++++++++++++++++-------------- src/fbd-dev-led.h | 13 +++---- src/fbd-dev-leds.c | 6 ++-- tests/test-fbd-dev-led.c | 8 ++--- 6 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index 5d1d692..bcb5d17 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -65,7 +65,7 @@ fbd_dev_led_multicolor_probe (FbdDevLed *led, GError **error) return FALSE; } fbd_dev_led_set_max_brightness (led, max_brightness); - fbd_dev_led_set_color (led, FBD_FEEDBACK_LED_COLOR_RGB); + fbd_dev_led_set_supported_color (led, FBD_FEEDBACK_LED_COLOR_RGB); for (int i = 0; index[i] != NULL; i++) { g_debug ("Index: %s", index[i]); @@ -90,10 +90,8 @@ fbd_dev_led_multicolor_probe (FbdDevLed *led, GError **error) static gboolean -fbd_dev_led_multicolor_start_periodic (FbdDevLed *led, - FbdFeedbackLedColor color, - guint max_brightness_percentage, - guint freq) +fbd_dev_led_multicolor_set_color (FbdDevLed *led, + FbdFeedbackLedColor color) { FbdDevLedMulticolor *self = FBD_DEV_LED_MULTICOLOR (led); FbdDevLedMulticolorPrivate *priv = fbd_dev_led_multicolor_get_instance_private (self); @@ -142,16 +140,7 @@ fbd_dev_led_multicolor_start_periodic (FbdDevLed *led, return FALSE; } - /* Chain up to parent class to set the pattern */ - return FBD_DEV_LED_CLASS (fbd_dev_led_multicolor_parent_class)->start_periodic ( - led, color, max_brightness_percentage, freq); -} - - -static gboolean -fbd_dev_led_has_color_multicolor (FbdDevLed *led, FbdFeedbackLedColor color) -{ - return color == FBD_FEEDBACK_LED_COLOR_RGB; + return TRUE; } @@ -161,8 +150,7 @@ fbd_dev_led_multicolor_class_init (FbdDevLedMulticolorClass *klass) FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); fbd_dev_led_class->probe = fbd_dev_led_multicolor_probe; - fbd_dev_led_class->start_periodic = fbd_dev_led_multicolor_start_periodic; - fbd_dev_led_class->has_color = fbd_dev_led_has_color_multicolor; + fbd_dev_led_class->set_color = fbd_dev_led_multicolor_set_color; } diff --git a/src/fbd-dev-led-priv.h b/src/fbd-dev-led-priv.h index 32b34e1..b2300b2 100644 --- a/src/fbd-dev-led-priv.h +++ b/src/fbd-dev-led-priv.h @@ -17,6 +17,6 @@ G_BEGIN_DECLS GUdevDevice *fbd_dev_led_get_device (FbdDevLed *led); void fbd_dev_led_set_max_brightness (FbdDevLed *led, guint max_brightness); -void fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color); +void fbd_dev_led_set_supported_color (FbdDevLed *led, FbdFeedbackLedColor color); G_END_DECLS diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c index f577229..cf6b9ed 100644 --- a/src/fbd-dev-led.c +++ b/src/fbd-dev-led.c @@ -16,11 +16,6 @@ #include #define LED_BRIGHTNESS_ATTR "brightness" -#define LED_MULTI_INDEX_ATTR "multi_index" -#define LED_MULTI_INDEX_RED "red" -#define LED_MULTI_INDEX_GREEN "green" -#define LED_MULTI_INDEX_BLUE "blue" -#define LED_MULTI_INTENSITY_ATTR "multi_intensity" #define LED_PATTERN_ATTR "pattern" enum { @@ -98,10 +93,31 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) static gboolean -fbd_dev_led_start_periodic_default (FbdDevLed *led, - FbdFeedbackLedColor color, - guint max_brightness_percentage, - guint freq) +fbd_dev_led_set_color_default (FbdDevLed *led, + FbdFeedbackLedColor color) +{ + /* Ignore setting color as we have a single color only */ + return TRUE; +} + + +static gboolean +fbd_dev_led_supports_color_default (FbdDevLed *led, + FbdFeedbackLedColor color) +{ + FbdDevLedPrivate *priv; + + g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + priv = fbd_dev_led_get_instance_private (led); + + return priv->color == color; +} + + +static gboolean +fbd_dev_led_start_periodic_default (FbdDevLed *led, + guint max_brightness_percentage, + guint freq) { FbdDevLedPrivate *priv; g_autoptr (GError) err = NULL; @@ -127,18 +143,6 @@ fbd_dev_led_start_periodic_default (FbdDevLed *led, } -static gboolean -fbd_dev_led_has_color_default (FbdDevLed *led, FbdFeedbackLedColor color) -{ - FbdDevLedPrivate *priv; - - g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); - priv = fbd_dev_led_get_instance_private (led); - - return priv->color == color; -} - - static void fbd_dev_led_set_property (GObject *object, guint property_id, @@ -221,7 +225,8 @@ fbd_dev_led_class_init (FbdDevLedClass *klass) fbd_dev_led_class->probe = fbd_dev_led_probe_default; fbd_dev_led_class->start_periodic = fbd_dev_led_start_periodic_default; - fbd_dev_led_class->has_color = fbd_dev_led_has_color_default; + fbd_dev_led_class->set_color = fbd_dev_led_set_color_default; + fbd_dev_led_class->supports_color = fbd_dev_led_supports_color_default; props[PROP_DEV] = g_param_spec_object ("dev", "", "", @@ -265,7 +270,6 @@ fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness) gboolean fbd_dev_led_start_periodic (FbdDevLed *led, - FbdFeedbackLedColor color, guint max_brightness_percentage, guint freq) { @@ -273,18 +277,30 @@ fbd_dev_led_start_periodic (FbdDevLed *led, g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); - return fbd_dev_led_class->start_periodic (led, color, max_brightness_percentage, freq); + return fbd_dev_led_class->start_periodic (led, max_brightness_percentage, freq); } gboolean -fbd_dev_led_has_color (FbdDevLed *led, FbdFeedbackLedColor color) +fbd_dev_led_set_color (FbdDevLed *led, + FbdFeedbackLedColor color) { FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_GET_CLASS (led); g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); - return fbd_dev_led_class->has_color (led, color); + return fbd_dev_led_class->set_color (led, color); +} + + +gboolean +fbd_dev_led_supports_color (FbdDevLed *led, FbdFeedbackLedColor color) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_GET_CLASS (led); + + g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + + return fbd_dev_led_class->supports_color (led, color); } @@ -314,7 +330,7 @@ fbd_dev_led_get_device (FbdDevLed *led) void -fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color) +fbd_dev_led_set_supported_color (FbdDevLed *led, FbdFeedbackLedColor color) { FbdDevLedPrivate *priv; diff --git a/src/fbd-dev-led.h b/src/fbd-dev-led.h index 139deec..0aba548 100644 --- a/src/fbd-dev-led.h +++ b/src/fbd-dev-led.h @@ -20,22 +20,23 @@ G_DECLARE_DERIVABLE_TYPE (FbdDevLed, fbd_dev_led, FBD, DEV_LED, GObject) FbdDevLed *fbd_dev_led_new (GUdevDevice *dev, GError **err); gboolean fbd_dev_led_set_brightness (FbdDevLed *led, guint brightness); guint fbd_dev_led_get_max_brightness (FbdDevLed *led); +gboolean fbd_dev_led_set_color (FbdDevLed *led, FbdFeedbackLedColor color); gboolean fbd_dev_led_start_periodic (FbdDevLed *led, - FbdFeedbackLedColor color, guint max_brightness_percentage, guint freq); -gboolean fbd_dev_led_has_color (FbdDevLed *led, FbdFeedbackLedColor color); +gboolean fbd_dev_led_supports_color (FbdDevLed *led, FbdFeedbackLedColor color); struct _FbdDevLedClass { GObjectClass parent_class; - gboolean (*probe) (FbdDevLed *led, GError **error); + gboolean (*probe) (FbdDevLed *led, GError **error); gboolean (*start_periodic) (FbdDevLed *led, - FbdFeedbackLedColor color, guint max_brightness_percentage, guint freq); - gboolean (*has_color) (FbdDevLed *led, - FbdFeedbackLedColor color); + gboolean (*set_color) (FbdDevLed *led, + FbdFeedbackLedColor color); + gboolean (*supports_color) (FbdDevLed *led, + FbdFeedbackLedColor color); }; G_END_DECLS diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index 34b4314..a1e77c0 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -47,7 +47,7 @@ find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) for (GSList *l = self->leds; l != NULL; l = l->next) { FbdDevLed *led = l->data; - if (fbd_dev_led_has_color (led, color)) + if (fbd_dev_led_supports_color (led, color)) return led; } @@ -165,7 +165,9 @@ fbd_dev_leds_start_periodic (FbdDevLeds *self, FbdFeedbackLedColor color, led = find_led_by_color (self, color); g_return_val_if_fail (led, FALSE); - return fbd_dev_led_start_periodic (led, color, max_brightness_percentage, freq); + fbd_dev_led_set_color (led, color); + + return fbd_dev_led_start_periodic (led, max_brightness_percentage, freq); } gboolean diff --git a/tests/test-fbd-dev-led.c b/tests/test-fbd-dev-led.c index c541218..9b5fe8d 100644 --- a/tests/test-fbd-dev-led.c +++ b/tests/test-fbd-dev-led.c @@ -33,8 +33,8 @@ test_fbd_dev_led_simple (FbdUmockdevFixture *fixture, gconstpointer unused) led = fbd_dev_led_new (dev, &err); g_assert_no_error (err); g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 255); - g_assert_true (fbd_dev_led_has_color (led, FBD_FEEDBACK_LED_COLOR_BLUE)); - g_assert_true (fbd_dev_led_start_periodic (led, FBD_FEEDBACK_LED_COLOR_BLUE, 50, 50)); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_BLUE)); + g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); g_assert_finalize_object (led); } @@ -60,8 +60,8 @@ test_fbd_dev_led_multicolor (FbdUmockdevFixture *fixture, gconstpointer unused) led = fbd_dev_led_multicolor_new (dev, &err); g_assert_no_error (err); g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 248); - g_assert_true (fbd_dev_led_has_color (led, FBD_FEEDBACK_LED_COLOR_RGB)); - g_assert_true (fbd_dev_led_start_periodic (led, FBD_FEEDBACK_LED_COLOR_BLUE, 50, 50)); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_RGB)); + g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); g_assert_finalize_object (led); } From 63b564494b236e3289343664d273d879dba56c7a Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sat, 31 Dec 2022 15:10:21 +0100 Subject: [PATCH 06/11] fbd-ledctrl: Set permissions for hw_pattern Allow access to hw_pattern sysfs node for feedbackd, similar to other nodes. --- src/fbd-ledctrl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fbd-ledctrl.c b/src/fbd-ledctrl.c index fd6612b..d49b14d 100644 --- a/src/fbd-ledctrl.c +++ b/src/fbd-ledctrl.c @@ -16,12 +16,13 @@ #include #include -#define LED_BRIGHTNESS_ATTR "brightness" +#define LED_BRIGHTNESS_ATTR "brightness" #define LED_MULTI_INTENSITY_ATTR "multi_intensity" -#define LED_PATTERN_ATTR "pattern" -#define LED_REPEAT_ATTR "repeat" -#define LED_TRIGGER_ATTR "trigger" -#define LED_TRIGGER_PATTERN "pattern" +#define LED_PATTERN_ATTR "pattern" +#define LED_REPEAT_ATTR "repeat" +#define LED_TRIGGER_ATTR "trigger" +#define LED_TRIGGER_PATTERN "pattern" +#define LED_TRIGGER_HW_PATTERN "hw_pattern" enum { FBD_LEDCTRL_ERR_CMDLINE = 1, @@ -127,7 +128,7 @@ set_perms (const char *sysfs_path, const char *trigger, const char *gname) if (!set_sysfs_attr_perm (sysfs_path, LED_BRIGHTNESS_ATTR, group->gr_gid)) return FALSE; - // Attribute is optional + /* Attribute is optional */ set_sysfs_attr_perm (sysfs_path, LED_MULTI_INTENSITY_ATTR, group->gr_gid); if (!g_strcmp0 (trigger, LED_TRIGGER_PATTERN)) { @@ -135,6 +136,9 @@ set_perms (const char *sysfs_path, const char *trigger, const char *gname) success = FALSE; if (!set_sysfs_attr_perm (sysfs_path, LED_REPEAT_ATTR, group->gr_gid)) success = FALSE; + + /* Attribute is optional */ + set_sysfs_attr_perm (sysfs_path, LED_TRIGGER_HW_PATTERN, group->gr_gid); } /* specific setup for other triggers goes here */ From 60ce9ecb3caae30b73488bfed1c8ecab61529bd8 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 9 Feb 2023 21:15:53 +0100 Subject: [PATCH 07/11] fbd-dev-led: Check max_brightness_percentage range Percentages are always between 0.0 and 100.0. Also fix a typo along the way. --- src/fbd-dev-led.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c index cf6b9ed..f3b942f 100644 --- a/src/fbd-dev-led.c +++ b/src/fbd-dev-led.c @@ -85,7 +85,7 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) if (!success) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - "%s not usable as RBG LED", name); + "%s not usable as RGB LED", name); } return success; @@ -127,6 +127,7 @@ fbd_dev_led_start_periodic_default (FbdDevLed *led, gdouble t; g_return_val_if_fail (FBD_IS_DEV_LED (led), FALSE); + g_return_val_if_fail (max_brightness_percentage <= 100, FALSE); priv = fbd_dev_led_get_instance_private (led); max = priv->max_brightness * (max_brightness_percentage / 100.0); From 22e4c33606bb57e2b966ae11539be6ab232e3d72 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sat, 11 Feb 2023 12:46:27 +0100 Subject: [PATCH 08/11] fbd-dev-led-multicolor: Support red, green, blue and white LED colors Provide our own supports_color method to specify which colors are actually implemented by the driver. RGB LEDs could provide different colors as well such as orange, purple, etc. but those are not supported yet. --- src/fbd-dev-led-multicolor.c | 21 +++++++++++++++++++++ tests/test-fbd-dev-led.c | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/fbd-dev-led-multicolor.c b/src/fbd-dev-led-multicolor.c index bcb5d17..23fcf54 100644 --- a/src/fbd-dev-led-multicolor.c +++ b/src/fbd-dev-led-multicolor.c @@ -144,6 +144,26 @@ fbd_dev_led_multicolor_set_color (FbdDevLed *led, } +static gboolean +fbd_dev_led_multicolor_supports_color (FbdDevLed *led, + FbdFeedbackLedColor color) +{ + switch(color) { + case FBD_FEEDBACK_LED_COLOR_WHITE: + return TRUE; + case FBD_FEEDBACK_LED_COLOR_RED: + return TRUE; + case FBD_FEEDBACK_LED_COLOR_GREEN: + return TRUE; + case FBD_FEEDBACK_LED_COLOR_BLUE: + return TRUE; + default: + g_warning ("Color unsupported: %d", color); + return FALSE; + } +} + + static void fbd_dev_led_multicolor_class_init (FbdDevLedMulticolorClass *klass) { @@ -151,6 +171,7 @@ fbd_dev_led_multicolor_class_init (FbdDevLedMulticolorClass *klass) fbd_dev_led_class->probe = fbd_dev_led_multicolor_probe; fbd_dev_led_class->set_color = fbd_dev_led_multicolor_set_color; + fbd_dev_led_class->supports_color = fbd_dev_led_multicolor_supports_color; } diff --git a/tests/test-fbd-dev-led.c b/tests/test-fbd-dev-led.c index 9b5fe8d..533accd 100644 --- a/tests/test-fbd-dev-led.c +++ b/tests/test-fbd-dev-led.c @@ -60,7 +60,7 @@ test_fbd_dev_led_multicolor (FbdUmockdevFixture *fixture, gconstpointer unused) led = fbd_dev_led_multicolor_new (dev, &err); g_assert_no_error (err); g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 248); - g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_RGB)); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_BLUE)); g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); g_assert_finalize_object (led); From 10e6d3cba84ff06a30af991c60bc76b429c25422 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 9 Feb 2023 21:20:54 +0100 Subject: [PATCH 09/11] fbd-dev-led-qcom: Support QCOM LPG LED single color QCOM LPG LEDs expose a hw_pattern sysfs entry which accepts a limited set of patterns but allows to use dedicated hardware for blinking the LED. This way, battery life can be improved and the LED still blinks, even if the device is suspended. --- src/fbd-dev-led-qcom-priv.h | 16 +++ src/fbd-dev-led-qcom.c | 118 +++++++++++++++++++ src/fbd-dev-led-qcom.h | 18 +++ src/meson.build | 1 + tests/data/umockdev/led-qcom-simple.umockdev | 118 +++++++++++++++++++ tests/test-fbd-dev-led.c | 31 +++++ 6 files changed, 302 insertions(+) create mode 100644 src/fbd-dev-led-qcom-priv.h create mode 100644 src/fbd-dev-led-qcom.c create mode 100644 src/fbd-dev-led-qcom.h create mode 100644 tests/data/umockdev/led-qcom-simple.umockdev diff --git a/src/fbd-dev-led-qcom-priv.h b/src/fbd-dev-led-qcom-priv.h new file mode 100644 index 0000000..1ff3a9a --- /dev/null +++ b/src/fbd-dev-led-qcom-priv.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Dylan Van Assche + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led-qcom.h" + +#include + +G_BEGIN_DECLS + +gboolean fbd_dev_led_probe_qcom (FbdDevLed *led, GError **error); + +G_END_DECLS diff --git a/src/fbd-dev-led-qcom.c b/src/fbd-dev-led-qcom.c new file mode 100644 index 0000000..5115f8d --- /dev/null +++ b/src/fbd-dev-led-qcom.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2023 Dylan Van Assche + * + * SPDX-License-Identifier: GPL-3.0+ + */ + +#define G_LOG_DOMAIN "fbd-dev-led-qcom" + +#include "fbd-dev-led-priv.h" +#include "fbd-dev-led-qcom.h" +#include "fbd-dev-led-qcom-priv.h" +#include "fbd-enums.h" +#include "fbd-udev.h" + +#include + +#define LED_HW_PATTERN_ATTR "hw_pattern" +#define LED_REPEAT_ATTR "repeat" +#define LED_REPEAT_INFINITY "-1" +#define QCOM_LPG_MAX_PAUSE_MS 511 + +typedef struct _FbdDevLedQcom { + FbdDevLed parent; +} FbdDevLedQcom; + + +G_DEFINE_TYPE (FbdDevLedQcom, fbd_dev_led_qcom, FBD_TYPE_DEV_LED) + + +static gboolean +fbd_dev_led_qcom_probe (FbdDevLed *led, GError **error) +{ + GUdevDevice *dev = fbd_dev_led_get_device (led); + const gchar *name; + const gchar * const *index; + + name = g_udev_device_get_name (dev); + + index = g_udev_device_get_sysfs_attr_as_strv (dev, LED_HW_PATTERN_ATTR); + if (index == NULL) { + g_set_error (error, + G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s is no QCOM LED with HW support", name); + return FALSE; + } + + return FBD_DEV_LED_CLASS (fbd_dev_led_qcom_parent_class)->probe(led, error); +} + + +static gboolean +fbd_dev_led_qcom_start_periodic (FbdDevLed *led, + guint max_brightness_percentage, + guint freq) +{ + GUdevDevice *dev = fbd_dev_led_get_device (led); + gdouble max; + gdouble t; + g_autofree gchar *str = NULL; + g_autoptr (GError) err = NULL; + gboolean success; + + g_return_val_if_fail (max_brightness_percentage <= 100.0, FALSE); + max = fbd_dev_led_get_max_brightness (led) * (max_brightness_percentage / 100.0); + + g_debug ("Using hw_pattern interface for QCOM LPG LED"); + + /* QCOM LPG LEDs can only pause up to 511ms */ + /* ms mHz T/2 */ + t = 1000.0 * 1000.0 / freq / 2.0; + if (t > QCOM_LPG_MAX_PAUSE_MS) + t = QCOM_LPG_MAX_PAUSE_MS; + + str = g_strdup_printf ("0 %d 0 0 %d %d %d 0\n", (gint)t, (gint)max, (gint)t, (gint)max); + + success = fbd_udev_set_sysfs_path_attr_as_string (dev, LED_REPEAT_ATTR, LED_REPEAT_INFINITY, &err); + if (!success) { + g_warning ("Failed to set LED repeat: %s", err->message); + goto failure; + } + + success = fbd_udev_set_sysfs_path_attr_as_string (dev, LED_HW_PATTERN_ATTR, str, &err); + if (!success) { + g_warning ("Failed to set LED hw_pattern: %s", err->message); + goto failure; + } + + g_debug ("Freq %d mHz, Brightness: %d%%, Blink pattern: %s, HW: yes", freq, max_brightness_percentage, str); + return TRUE; + +failure: + g_warning("Falling back to software pattern"); + return FBD_DEV_LED_CLASS (fbd_dev_led_qcom_parent_class)->start_periodic ( + led, max_brightness_percentage, freq); +} + + +static void +fbd_dev_led_qcom_class_init (FbdDevLedQcomClass *klass) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); + + fbd_dev_led_class->probe = fbd_dev_led_qcom_probe; + fbd_dev_led_class->start_periodic = fbd_dev_led_qcom_start_periodic; +} + + +static void +fbd_dev_led_qcom_init (FbdDevLedQcom *self) +{ +} + + +FbdDevLed * +fbd_dev_led_qcom_new (GUdevDevice *dev, GError **err) +{ + return g_initable_new (FBD_TYPE_DEV_LED_QCOM, NULL, err, "dev", dev, NULL); +} diff --git a/src/fbd-dev-led-qcom.h b/src/fbd-dev-led-qcom.h new file mode 100644 index 0000000..ad77c9f --- /dev/null +++ b/src/fbd-dev-led-qcom.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Dylan Van Assche + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led.h" + +G_BEGIN_DECLS + +#define FBD_TYPE_DEV_LED_QCOM fbd_dev_led_qcom_get_type() + +G_DECLARE_FINAL_TYPE (FbdDevLedQcom, fbd_dev_led_qcom, FBD, DEV_LED_QCOM, FbdDevLed) + +FbdDevLed *fbd_dev_led_qcom_new (GUdevDevice *dev, GError **err); + +G_END_DECLS diff --git a/src/meson.build b/src/meson.build index 8d2dcdb..fdbc07e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,6 +17,7 @@ sources = [ 'fbd-dev-sound.c', 'fbd-dev-led.c', 'fbd-dev-led-multicolor.c', + 'fbd-dev-led-qcom.c', 'fbd-dev-leds.c', 'fbd-event.c', 'fbd-feedback-base.c', diff --git a/tests/data/umockdev/led-qcom-simple.umockdev b/tests/data/umockdev/led-qcom-simple.umockdev new file mode 100644 index 0000000..0883590 --- /dev/null +++ b/tests/data/umockdev/led-qcom-simple.umockdev @@ -0,0 +1,118 @@ +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:pwm/leds/white:status +E: FEEDBACKD_TYPE=led +E: ID_FOR_SEAT=leds-platform-c440000_spmi-platform-c440000_spmi_pmic_3_pwm +E: ID_PATH=platform-c440000.spmi-platform-c440000.spmi:pmic@3:pwm +E: ID_PATH_TAG=platform-c440000_spmi-platform-c440000_spmi_pmic_3_pwm +E: OF_COMPATIBLE_N=0 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/pwm/led@5 +E: OF_NAME=led +E: SUBSYSTEM=leds +E: TAGS=:seat: +A: brightness=0\n +L: device=../../../c440000.spmi:pmic@3:pwm +A: hw_pattern= +A: max_brightness=511\n +A: pattern= +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n +A: repeat=-1\n +A: trigger=none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer oneshot heartbeat backlight cpu cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 cpu6 cpu7 activity default-on panic [pattern] mmc0 rfkill-any rfkill-none bluetooth-power hci0-power rfkill0 pmi8998-charger-online qcom-battery-charging-or-full qcom-battery-charging qcom-battery-full qcom-battery-charging-blink-full-solid phy0rx phy0tx phy0assoc phy0radio rfkill1\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:pwm +E: DRIVER=qcom-spmi-lpg +E: MODALIAS=of:NpwmT(null)Cqcom,pmi8998-lpg +E: OF_COMPATIBLE_0=qcom,pmi8998-lpg +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/pwm +E: OF_NAME=pwm +E: SUBSYSTEM=platform +L: driver=../../../../../../../bus/platform/drivers/qcom-spmi-lpg +A: driver_override=(null)\n +A: modalias=of:NpwmT(null)Cqcom,pmi8998-lpg\n +L: of_node=../../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3/pwm +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03 +E: DRIVER=pmic-spmi +E: MODALIAS=of:NpmicT(null)Cqcom,pmi8998Cqcom,spmi-pmic +E: OF_COMPATIBLE_0=qcom,pmi8998 +E: OF_COMPATIBLE_1=qcom,spmi-pmic +E: OF_COMPATIBLE_N=2 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3 +E: OF_NAME=pmic +E: SUBSYSTEM=spmi +L: driver=../../../../../../bus/spmi/drivers/pmic-spmi +L: of_node=../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3 +A: power/control=auto\n +A: power/runtime_active_time=124723680\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0 +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=spmi +L: of_node=../../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi +E: DRIVER=spmi_pmic_arb +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=platform +L: consumer:platform:c440000.spmi:pmic@0:adc@3100=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:adc@3100 +L: consumer:platform:c440000.spmi:pmic@0:pon@800:pwrkey=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:pon@800:pwrkey +L: consumer:platform:c440000.spmi:pmic@0:pon@800:resin=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:pon@800:resin +L: consumer:platform:c440000.spmi:pmic@0:rtc@6000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:rtc@6000 +L: consumer:platform:c440000.spmi:pmic@0:temp-alarm@2400=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:temp-alarm@2400 +L: consumer:platform:c440000.spmi:pmic@2:charger@1000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@2:charger@1000 +L: consumer:platform:c440000.spmi:pmic@2:fuel-gauge@4000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@2:fuel-gauge@4000 +L: consumer:platform:c440000.spmi:pmic@3:haptics@c000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@3:haptics@c000 +L: consumer:platform:c440000.spmi:pmic@3:leds@d800=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@3:leds@d800 +L: driver=../../../../bus/platform/drivers/spmi_pmic_arb +A: driver_override=(null)\n +A: modalias=of:NspmiT(null)Cqcom,spmi-pmic-arb\n +L: of_node=../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0 +E: DRIVER=simple-pm-bus +E: MODALIAS=of:NsocT(null)Csimple-bus +E: OF_COMPATIBLE_0=simple-bus +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0 +E: OF_NAME=soc +E: SUBSYSTEM=platform +L: consumer:platform:17c90000.timer=../../virtual/devlink/platform:soc@0--platform:17c90000.timer +L: consumer:platform:894000.i2c=../../virtual/devlink/platform:soc@0--platform:894000.i2c +L: consumer:platform:898000.serial=../../virtual/devlink/platform:soc@0--platform:898000.serial +L: consumer:platform:a600000.usb=../../virtual/devlink/platform:soc@0--platform:a600000.usb +L: consumer:platform:a84000.serial=../../virtual/devlink/platform:soc@0--platform:a84000.serial +L: consumer:platform:a98000.i2c=../../virtual/devlink/platform:soc@0--platform:a98000.i2c +L: driver=../../../bus/platform/drivers/simple-pm-bus +A: driver_override=(null)\n +A: modalias=of:NsocT(null)Csimple-bus\n +L: of_node=../../../firmware/devicetree/base/soc@0 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + + diff --git a/tests/test-fbd-dev-led.c b/tests/test-fbd-dev-led.c index 533accd..6ccc08d 100644 --- a/tests/test-fbd-dev-led.c +++ b/tests/test-fbd-dev-led.c @@ -8,6 +8,7 @@ #include "fbd-feedback-led.h" #include "fbd-dev-led.h" #include "fbd-dev-led-multicolor.h" +#include "fbd-dev-led-qcom.h" #include "testlib.h" @@ -67,6 +68,33 @@ test_fbd_dev_led_multicolor (FbdUmockdevFixture *fixture, gconstpointer unused) } +static void +test_fbd_dev_led_qcom_simple (FbdUmockdevFixture *fixture, gconstpointer unused) +{ + GUdevClient *client; + g_autolist (GUdevDevice) leds = NULL; + FbdDevLed *led; + g_autoptr (GError) err = NULL; + GUdevDevice *dev; + + client = g_udev_client_new ((const char *const []){ "leds", NULL}); + leds = g_udev_client_query_by_subsystem (client, "leds"); + + /* There should be a single device only */ + g_assert_cmpint (g_list_length (leds), ==, 1); + dev = G_UDEV_DEVICE (leds->data); + + g_assert_cmpstr (g_udev_device_get_property (dev, "FEEDBACKD_TYPE"), ==, "led"); + + led = fbd_dev_led_qcom_new (dev, &err); + g_assert_no_error (err); + g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 511); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_WHITE)); + g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); + g_assert_finalize_object (led); +} + + gint main (gint argc, gchar *argv[]) { @@ -78,6 +106,9 @@ main (gint argc, gchar *argv[]) FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/multicolor", test_fbd_dev_led_multicolor, "led-multicolor"); + FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/qcom/simple", + test_fbd_dev_led_qcom_simple, + "led-qcom-simple"); return g_test_run(); } From 2b53725fcb46b918d661f8f66a3f35fba10ee870 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 9 Feb 2023 21:22:38 +0100 Subject: [PATCH 10/11] fbd-dev-led-qcom-multicolor: Support QCOM LPG LED multicolor QCOM LPG LEDs can also operate in a multicolor fashion. Re-use the probing sequence of multicolor LEDs and the hw_pattern configuration of single color QCOM LPG LEDs. --- src/fbd-dev-led-qcom-multicolor.c | 74 +++++++++++ src/fbd-dev-led-qcom-multicolor.h | 18 +++ src/meson.build | 1 + .../umockdev/led-qcom-multicolor.umockdev | 118 ++++++++++++++++++ tests/test-fbd-dev-led.c | 32 +++++ 5 files changed, 243 insertions(+) create mode 100644 src/fbd-dev-led-qcom-multicolor.c create mode 100644 src/fbd-dev-led-qcom-multicolor.h create mode 100644 tests/data/umockdev/led-qcom-multicolor.umockdev diff --git a/src/fbd-dev-led-qcom-multicolor.c b/src/fbd-dev-led-qcom-multicolor.c new file mode 100644 index 0000000..26e7f28 --- /dev/null +++ b/src/fbd-dev-led-qcom-multicolor.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 Dylan Van Assche + * SPDX-License-Identifier: GPL-3.0+ + */ + +#define G_LOG_DOMAIN "fbd-dev-led-qcom-multicolor" + +#include "fbd-dev-led-priv.h" +#include "fbd-dev-led.h" +#include "fbd-dev-led-qcom.h" +#include "fbd-dev-led-qcom-priv.h" +#include "fbd-dev-led-qcom-multicolor.h" +#include "fbd-enums.h" +#include "fbd-udev.h" + +#include + +#define LED_HW_PATTERN_ATTR "hw_pattern" +#define LED_REPEAT_ATTR "repeat" + +typedef struct _FbdDevLedQcomMulticolor { + FbdDevLedMulticolor parent; + + FbdDevLedQcom *qcom_led; +} FbdDevLedQcomMulticolor; + + +G_DEFINE_TYPE (FbdDevLedQcomMulticolor, fbd_dev_led_qcom_multicolor, FBD_TYPE_DEV_LED_MULTICOLOR) + + +static gboolean +fbd_dev_led_qcom_multicolor_probe (FbdDevLed *led, GError **error) +{ + FbdDevLedQcomMulticolor *self = FBD_DEV_LED_QCOM_MULTICOLOR (led); + GUdevDevice *dev = fbd_dev_led_get_device (FBD_DEV_LED (led)); + + self->qcom_led = FBD_DEV_LED_QCOM (fbd_dev_led_qcom_new (dev, error)); + if (!self->qcom_led) + return FALSE; + + return FBD_DEV_LED_CLASS (fbd_dev_led_qcom_multicolor_parent_class)->probe(led, error); +} + +static gboolean +fbd_dev_led_qcom_multicolor_start_periodic (FbdDevLed *led, + guint max_brightness_percentage, + guint freq) +{ + FbdDevLedQcomMulticolor *self = FBD_DEV_LED_QCOM_MULTICOLOR (led); + + return fbd_dev_led_start_periodic (FBD_DEV_LED (self->qcom_led), max_brightness_percentage, freq); +} + +static void +fbd_dev_led_qcom_multicolor_class_init (FbdDevLedQcomMulticolorClass *klass) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); + + fbd_dev_led_class->probe = fbd_dev_led_qcom_multicolor_probe; + fbd_dev_led_class->start_periodic = fbd_dev_led_qcom_multicolor_start_periodic; +} + + +static void +fbd_dev_led_qcom_multicolor_init (FbdDevLedQcomMulticolor *self) +{ +} + + +FbdDevLed * +fbd_dev_led_qcom_multicolor_new (GUdevDevice *dev, GError **err) +{ + return g_initable_new (FBD_TYPE_DEV_LED_QCOM_MULTICOLOR, NULL, err, "dev", dev, NULL); +} diff --git a/src/fbd-dev-led-qcom-multicolor.h b/src/fbd-dev-led-qcom-multicolor.h new file mode 100644 index 0000000..bf264eb --- /dev/null +++ b/src/fbd-dev-led-qcom-multicolor.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Dylan Van Assche + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led-multicolor.h" + +G_BEGIN_DECLS + +#define FBD_TYPE_DEV_LED_QCOM_MULTICOLOR fbd_dev_led_qcom_multicolor_get_type() + +G_DECLARE_FINAL_TYPE (FbdDevLedQcomMulticolor, fbd_dev_led_qcom_multicolor, FBD, DEV_LED_QCOM_MULTICOLOR, FbdDevLedMulticolor) + +FbdDevLed *fbd_dev_led_qcom_multicolor_new (GUdevDevice *dev, GError **err); + +G_END_DECLS diff --git a/src/meson.build b/src/meson.build index fdbc07e..2ae7691 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,7 @@ sources = [ 'fbd-dev-led.c', 'fbd-dev-led-multicolor.c', 'fbd-dev-led-qcom.c', + 'fbd-dev-led-qcom-multicolor.c', 'fbd-dev-leds.c', 'fbd-event.c', 'fbd-feedback-base.c', diff --git a/tests/data/umockdev/led-qcom-multicolor.umockdev b/tests/data/umockdev/led-qcom-multicolor.umockdev new file mode 100644 index 0000000..814f3a5 --- /dev/null +++ b/tests/data/umockdev/led-qcom-multicolor.umockdev @@ -0,0 +1,118 @@ +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:pwm/leds/rgb:status +E: FEEDBACKD_TYPE=led +E: ID_FOR_SEAT=leds-platform-c440000_spmi-platform-c440000_spmi_pmic_3_pwm +E: ID_PATH=platform-c440000.spmi-platform-c440000.spmi:pmic@3:pwm +E: ID_PATH_TAG=platform-c440000_spmi-platform-c440000_spmi_pmic_3_pwm +E: OF_COMPATIBLE_N=0 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/pwm/multi-led +E: OF_NAME=multi-led +E: SUBSYSTEM=leds +E: TAGS=:seat: +A: brightness=0\n +L: device=../../../c440000.spmi:pmic@3:pwm +A: hw_pattern= +A: max_brightness=511\n +A: multi_index=blue green red\n +A: multi_intensity=0 0 0\n +A: pattern= +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n +A: repeat=-1\n +A: trigger=none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer oneshot heartbeat backlight cpu cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 cpu6 cpu7 activity default-on panic [pattern] mmc0 rfkill-any rfkill-none bluetooth-power hci0-power rfkill0 pmi8998-charger-online qcom-battery-charging-or-full qcom-battery-charging qcom-battery-full qcom-battery-charging-blink-full-solid\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:pwm +E: DRIVER=qcom-spmi-lpg +E: MODALIAS=of:NpwmT(null)Cqcom,pmi8998-lpg +E: OF_COMPATIBLE_0=qcom,pmi8998-lpg +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/pwm +E: OF_NAME=pwm +E: SUBSYSTEM=platform +L: driver=../../../../../../../bus/platform/drivers/qcom-spmi-lpg +A: driver_override=(null)\n +A: modalias=of:NpwmT(null)Cqcom,pmi8998-lpg\n +L: of_node=../../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3/pwm +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03 +E: DRIVER=pmic-spmi +E: MODALIAS=of:NpmicT(null)Cqcom,pmi8998Cqcom,spmi-pmic +E: OF_COMPATIBLE_0=qcom,pmi8998 +E: OF_COMPATIBLE_1=qcom,spmi-pmic +E: OF_COMPATIBLE_N=2 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3 +E: OF_NAME=pmic +E: SUBSYSTEM=spmi +L: driver=../../../../../../bus/spmi/drivers/pmic-spmi +L: of_node=../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3 +A: power/control=auto\n +A: power/runtime_active_time=7149472\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0 +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=spmi +L: of_node=../../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi +E: DRIVER=spmi_pmic_arb +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=platform +L: consumer:platform:c440000.spmi:pmic@0:adc@3100=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:adc@3100 +L: consumer:platform:c440000.spmi:pmic@0:pon@800:pwrkey=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:pon@800:pwrkey +L: consumer:platform:c440000.spmi:pmic@0:pon@800:resin=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:pon@800:resin +L: consumer:platform:c440000.spmi:pmic@0:rtc@6000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:rtc@6000 +L: consumer:platform:c440000.spmi:pmic@0:temp-alarm@2400=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:temp-alarm@2400 +L: consumer:platform:c440000.spmi:pmic@2:charger@1000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@2:charger@1000 +L: consumer:platform:c440000.spmi:pmic@2:fuel-gauge@4000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@2:fuel-gauge@4000 +L: consumer:platform:c440000.spmi:pmic@3:haptics@c000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@3:haptics@c000 +L: driver=../../../../bus/platform/drivers/spmi_pmic_arb +A: driver_override=(null)\n +A: modalias=of:NspmiT(null)Cqcom,spmi-pmic-arb\n +L: of_node=../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0 +E: DRIVER=simple-pm-bus +E: MODALIAS=of:NsocT(null)Csimple-bus +E: OF_COMPATIBLE_0=simple-bus +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0 +E: OF_NAME=soc +E: SUBSYSTEM=platform +L: consumer:platform:17c90000.timer=../../virtual/devlink/platform:soc@0--platform:17c90000.timer +L: consumer:platform:894000.i2c=../../virtual/devlink/platform:soc@0--platform:894000.i2c +L: consumer:platform:898000.serial=../../virtual/devlink/platform:soc@0--platform:898000.serial +L: consumer:platform:a600000.usb=../../virtual/devlink/platform:soc@0--platform:a600000.usb +L: consumer:platform:a84000.serial=../../virtual/devlink/platform:soc@0--platform:a84000.serial +L: consumer:platform:a8c000.i2c=../../virtual/devlink/platform:soc@0--platform:a8c000.i2c +L: driver=../../../bus/platform/drivers/simple-pm-bus +A: driver_override=(null)\n +A: modalias=of:NsocT(null)Csimple-bus\n +L: of_node=../../../firmware/devicetree/base/soc@0 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + diff --git a/tests/test-fbd-dev-led.c b/tests/test-fbd-dev-led.c index 6ccc08d..93f64a9 100644 --- a/tests/test-fbd-dev-led.c +++ b/tests/test-fbd-dev-led.c @@ -9,6 +9,7 @@ #include "fbd-dev-led.h" #include "fbd-dev-led-multicolor.h" #include "fbd-dev-led-qcom.h" +#include "fbd-dev-led-qcom-multicolor.h" #include "testlib.h" @@ -95,6 +96,34 @@ test_fbd_dev_led_qcom_simple (FbdUmockdevFixture *fixture, gconstpointer unused) } +static void +test_fbd_dev_led_qcom_multicolor (FbdUmockdevFixture *fixture, gconstpointer unused) +{ + GUdevClient *client; + g_autolist (GUdevDevice) leds = NULL; + FbdDevLed *led; + g_autoptr (GError) err = NULL; + GUdevDevice *dev; + + client = g_udev_client_new ((const char *const []){ "leds", NULL}); + leds = g_udev_client_query_by_subsystem (client, "leds"); + + /* There should be a single device only */ + g_assert_cmpint (g_list_length (leds), ==, 1); + dev = G_UDEV_DEVICE (leds->data); + + g_assert_cmpstr (g_udev_device_get_property (dev, "FEEDBACKD_TYPE"), ==, "led"); + + led = fbd_dev_led_qcom_multicolor_new (dev, &err); + g_assert_no_error (err); + g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 511); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_BLUE)); + g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); + + g_assert_finalize_object (led); +} + + gint main (gint argc, gchar *argv[]) { @@ -109,6 +138,9 @@ main (gint argc, gchar *argv[]) FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/qcom/simple", test_fbd_dev_led_qcom_simple, "led-qcom-simple"); + FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/qcom/multicolor", + test_fbd_dev_led_qcom_multicolor, + "led-qcom-multicolor"); return g_test_run(); } From 6b1eb92b7ac993d884c5779ff1d857128e221dff Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Fri, 10 Feb 2023 09:22:28 +0100 Subject: [PATCH 11/11] fbd-dev-leds: Probe QCOM HW LED types Try first the QCOM hardware LED types which require the most features of LED drivers. Try until we have a single color GPIO LED which is the minimal LED driver support we require. If the LED does not meet that expectation either, we ignore the LED. --- src/fbd-dev-leds.c | 48 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index a1e77c0..418cf44 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -12,6 +12,8 @@ #include "fbd-enums.h" #include "fbd-dev-led.h" #include "fbd-dev-led-multicolor.h" +#include "fbd-dev-led-qcom.h" +#include "fbd-dev-led-qcom-multicolor.h" #include "fbd-dev-leds.h" #include "fbd-feedback-led.h" #include "fbd-udev.h" @@ -55,6 +57,43 @@ find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) return self->leds->data; } + +static FbdDevLed* +probe_led (GUdevDevice *dev, GError **error) { + FbdDevLed *led = NULL; + + led = fbd_dev_led_qcom_multicolor_new (dev, error); + if (led != NULL) { + g_debug ("Discovered QCOM multicolor LED"); + return led; + } + g_clear_error (error); + + led = fbd_dev_led_qcom_new (dev, error); + if (led != NULL) { + g_debug ("Discovered QCOM single color LED"); + return led; + } + g_clear_error (error); + + led = fbd_dev_led_multicolor_new (dev, error); + if (led != NULL) { + g_debug ("Discovered multicolor LED"); + return led; + } + g_clear_error (error); + + led = fbd_dev_led_new (dev, error); + if (led != NULL) { + g_debug ("Discovered single color LED"); + return led; + } + + g_debug ("Unable to determine LED driver"); + return NULL; +} + + static gboolean initable_init (GInitable *initable, GCancellable *cancellable, @@ -79,14 +118,7 @@ initable_init (GInitable *initable, continue; } - /* Try multicolor first, fall back to single color */ - led = fbd_dev_led_multicolor_new (dev, &err); - if (led == NULL) { - g_debug ("Led not usable as multicolor: '%s'", err->message); - led = fbd_dev_led_new (dev, &err); - if (led == NULL) - g_debug ("Led not usable as single color: '%s'", err->message); - } + led = probe_led (dev, &err); if (led) { self->leds = g_slist_append (self->leds, led);