#include #include #include #include "hui_internal.h" #include "hui_generic.h" static DEFINE_MUTEX(led_ext_mutex); struct hui_generic_led_ext { struct hui_generic_led led; enum _led_groups group; int pin; u32 is_initialized : 1; }; #define MAX_EXT_GROUPS 7 static led_action_t external_actions[7]; static int led_out(struct hui_generic_led *_led, struct led_color color) { struct hui_generic_led_ext *led = container_of(_led, struct hui_generic_led_ext, led); led_action_t action; mutex_lock(&led_ext_mutex); action = external_actions[led->group]; if (!action) { mutex_unlock(&led_ext_mutex); return -ENODEV; } if (!led->is_initialized || true) { action(led->pin, led_ext_enable, NULL); led->is_initialized = 1; } if (color.brightness && color.c[0]) action(led->pin, led_ext_on, NULL); else action(led->pin, led_ext_off, NULL); mutex_unlock(&led_ext_mutex); // Always say -1 to always get called, there is some odd problem return -1; } static int led_probe(struct platform_device *pdev) { int err; const char *type, *group_str; struct hui_generic_led_ext *led; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; const char *name = node->name; led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led->led.dev = dev; led->led.name = name; led->led.code = BLINK_CODE(.type = blink_off); led->led.out = led_out; err = of_property_read_string(node, "led-type", &type); if (err == -EINVAL) type = name; else if (err) return err; err = of_property_read_string(node, "ext-group", &group_str); if (err) return err; if (strcmp(group_str, "wlan")) { dev_err(dev, "Invalid ext group %s\n", group_str); return -EINVAL; } led->group = led_wlan_leds; err = of_property_read_u32(node, "ext-pin", &led->pin); if (err) return err; dev_info(dev, "Using ext gpio <%s(%d), %d>\n", group_str, led->group, led->pin); led->led.handle = avm_hui_add_led(name, type, node, &hui_generic_ops, &led->led); // TODO add as res to free later if (IS_ERR(led->led.handle)) { return PTR_ERR(led->led.handle); } err = hui_generic_blink_add_led(&led->led); if (err) return err; return 0; } static const struct of_device_id hui_generic_ext_led_match[] = { { .compatible = "avm,hui-generic-led-ext" }, {}, }; MODULE_DEVICE_TABLE(of, hui_generic_ext_led_match); struct platform_driver hui_generic_led_ext = { .probe = led_probe, .driver = { .name = "avm,hui-generic-led-ext", .of_match_table = hui_generic_ext_led_match, }, }; int __led_register_external(enum _led_groups group_id, led_action_t action_func) { mutex_lock(&led_ext_mutex); external_actions[group_id] = action_func; mutex_unlock(&led_ext_mutex); return 0; } EXPORT_SYMBOL(__led_register_external); void __led_release_external(enum _led_groups group_id) { mutex_lock(&led_ext_mutex); external_actions[group_id] = NULL; mutex_unlock(&led_ext_mutex); } EXPORT_SYMBOL(__led_release_external);