#define pr_fmt(fmt) "[hui][stm32] " fmt #include #include #include #include #include #define ID_STM32 0 #include "spi.h" struct led { struct stm32 *stm32; u8 index; void *handle; }; static int stm32_get_version(struct stm32 *stm32) { int err, version; err = stm32_read(stm32, CMD_VERSION, (char *)&version, sizeof(version)); if (err) return err; return be32_to_cpu(version); } static inline void led_handler(struct blink_code code, void *ctx) { struct led *led = ctx; struct led_cmd { u8 count; u8 led_index; u8 code; u8 params[2]; u8 color[3]; }; struct led_cmd cmd = { .count = 1, .led_index = led->index, .code = code.type, .params = { code.params[0], code.params[1] }, .color = { code.color.c[0], code.color.c[1], code.color.c[2] }, }; stm32_write(led->stm32, CMD_SET_COLOR_LED, &cmd, sizeof(struct led_cmd)); } static const struct avm_hui_led_ops ops = { .out = led_handler, }; static inline int add_led(struct stm32 *stm32, struct device_node *node) { const char *name = node->name + 4; const char *type = NULL; int index, err; struct led *led; err = of_property_read_string(node, "led-type", &type); if (err == -EINVAL) type = name; else if (err) return err; err = of_property_read_u32(node, "index", &index); if (err) return err; led = kzalloc(sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led->index = index; led->stm32 = stm32; led->handle = avm_hui_add_led(name, type, node, &ops, led); pr_info("Add led <%s> with index %d\n", name, led->index); return 0; } static const struct of_device_id avm_hui_stm32_of_ids[] = { { .compatible = "avm,hui_stm32", .data = (void *)ID_STM32, }, {}, }; static int avm_hui_stm32_probe(struct spi_device *spi) { const struct of_device_id *match; int version, err; struct stm32 *stm32; struct device_node *def; match = of_match_device(avm_hui_stm32_of_ids, &spi->dev); if (!match) { pr_err("Did not match DT!\n"); return -ENODEV; } stm32 = kzalloc(sizeof(struct stm32), GFP_KERNEL); if (!stm32) return -ENOMEM; stm32->dev = spi; stm32->cs_gpio = gpiod_get(&spi->dev, "frame", GPIOD_OUT_LOW); if (IS_ERR(stm32->cs_gpio)) { err = PTR_ERR(stm32->cs_gpio); pr_err("Could not find gpio 'frame'.\n"); goto out_err; } version = stm32_get_version(stm32); if (version < 0) { pr_err("Could not get version: %d\n", version); err = version; goto out_err; } pr_info("Firmware version: %d\n", version); // TODO: check spi-mode for_each_child_of_node (spi->dev.of_node, def) { if (strncmp(def->name, "led-", 4) == 0) { add_led(stm32, def); } else if (strncmp(def->name, "button-", 7) == 0) { pr_err("Buttons are not implemented yet!\n"); // add_button(def); } else { pr_err("Unhandled node %s\n", def->name); } } return 0; out_err: if (!IS_ERR(stm32->cs_gpio)) gpiod_put(stm32->cs_gpio); kfree(stm32); return err; } static const struct spi_device_id avm_hui_stm32_ids[] = { { "avm_hui_stm32", ID_STM32 }, {}, }; MODULE_DEVICE_TABLE(spi, avm_hui_stm32_ids); static struct spi_driver driver = { .driver = { .name = "avm_hui_stm32", .of_match_table = of_match_ptr(avm_hui_stm32_of_ids), }, .id_table = avm_hui_stm32_ids, .probe = avm_hui_stm32_probe, }; int stm32_init(void) { return spi_register_driver(&driver); } void stm32_exit(void) { spi_unregister_driver(&driver); }