#include #include #include #include "asm/mach_avm.h" #include #include "hui_internal.h" #include "hui_generic.h" struct hui_generic_led_avm { struct hui_generic_led led; int pins[3]; u32 is_compound : 1; }; static int avm_led_out_separated(struct hui_generic_led_avm *led, struct led_color color) { int j; color = led_color_premultiply(color); for (j = 0; j < 3; j++) { int pin = led->pins[j]; u32 c = color.c[j]; if (pin == -1) continue; dev_dbg(led->led.dev, "p=%d c=%08x\n", pin, c); avm_gpio_out_bit(pin, c); } return 0; } static int avm_led_out_compound(struct hui_generic_led_avm *led, struct led_color color) { int pin = led->pins[0]; u32 c = 0; color = led_color_premultiply(color); c |= ((u32)color.red << 16); c |= ((u32)color.green << 8); c |= ((u32)color.blue << 0); dev_dbg(led->led.dev, "p=%d c=%08x\n", pin, c); avm_gpio_out_bit(pin, c); return 0; } static int avm_led_out(struct hui_generic_led *_led, struct led_color color) { struct hui_generic_led_avm *led = container_of(_led, struct hui_generic_led_avm, led); if (led->is_compound) return avm_led_out_compound(led, color); else return avm_led_out_separated(led, color); } static int led_probe(struct platform_device *pdev) { int count, i, err; struct device *dev = &pdev->dev; struct of_phandle_args args; struct hui_generic_led_avm *led; struct device_node *node = dev->of_node; const char *name = node->name; const char *type; 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 = avm_led_out; err = of_property_read_string(node, "led-type", &type); if (err == -EINVAL) type = name; else if (err) return err; count = of_count_phandle_with_args(node, "avm-gpios", NULL); if (count < 0) return count; if (count > 3) { dev_err(dev, "Ignoring led: more than 3 gpios\n"); return -EINVAL; } for (i = 0; i < 3; i++) { led->pins[0] = -1; } for (i = 0; i < count; i++) { enum _avm_hw_param param; err = of_parse_phandle_with_args(node, "avm-gpios", NULL, i, &args); if (err) return err; err = avm_get_hw_config(AVM_HW_CONFIG_VERSION, args.np->name, led->pins + i, ¶m); if (err) { dev_err(dev, "Could not get avm_gpio %s: %d\n", args.np->name, err); return err; } avm_gpio_ctrl(led->pins[i], GPIO_PIN, GPIO_OUTPUT_PIN); if (param == avm_hw_param_gpio_out_rgb || param == avm_hw_param_gpio_out_rgb_active_low) { led->is_compound = 1; if (count != 1) { dev_err(dev, "Compound rgb should only have on pin\n"); return -EINVAL; } } } dev_info(dev, "Using avm-gpios <%d, %d, %d>\n", led->pins[0], led->pins[1], led->pins[2]); 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_avm_led_match[] = { { .compatible = "avm,hui-generic-led-avm" }, {}, }; MODULE_DEVICE_TABLE(of, hui_generic_avm_led_match); struct platform_driver hui_generic_led_avm = { .probe = led_probe, .driver = { .name = "avm,hui-generic-led-avm", .of_match_table = hui_generic_avm_led_match, }, }; struct hui_generic_button_avm { struct hui_generic_button button; int pin; }; static int avm_button_in(struct hui_generic_button *_button) { struct hui_generic_button_avm *button = container_of(_button, struct hui_generic_button_avm, button); return avm_gpio_in_bit(button->pin); } static int button_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; const char *name = node->name; struct hui_generic_button_avm *button; int count, err; struct of_phandle_args args; button = devm_kzalloc(dev, sizeof(*button), GFP_KERNEL); if (!button) return -ENOMEM; button->button.dev = dev; button->button.name = name; button->button.in = avm_button_in; count = of_count_phandle_with_args(node, "avm-gpios", NULL); if (count < 0) return count; if (count > 1) { dev_err(dev, "Ignoring button more than 1 gpios\n"); return -EINVAL; } err = of_parse_phandle_with_args(node, "avm-gpios", NULL, 0, &args); if (err) return err; err = of_property_read_u32(args.np, "value", &button->pin); if (err) return err; avm_gpio_ctrl(button->pin, GPIO_PIN, GPIO_INPUT_PIN); dev_info(button->button.dev, "Using avm-gpios <%d>\n", button->pin); button->button.handle = avm_hui_add_button(name, name); // TODO add as res to free later if (IS_ERR(button->button.handle)) { return PTR_ERR(button->button.handle); } err = hui_generic_blink_add_button(&button->button); if (err) return err; return 0; } static const struct of_device_id hui_generic_avm_button_match[] = { { .compatible = "avm,hui-generic-button-avm" }, {}, }; MODULE_DEVICE_TABLE(of, hui_generic_avm_button_match); struct platform_driver hui_generic_button_avm = { .probe = button_probe, .driver = { .name = "avm,hui-generic-button-avm", .of_match_table = hui_generic_avm_button_match, }, };