15ac76badSSimon Glass /* 25ac76badSSimon Glass * Copyright (c) 2015 Google, Inc 35ac76badSSimon Glass * Written by Simon Glass <sjg@chromium.org> 45ac76badSSimon Glass * 55ac76badSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 65ac76badSSimon Glass */ 75ac76badSSimon Glass 85ac76badSSimon Glass #include <common.h> 95ac76badSSimon Glass #include <dm.h> 105ac76badSSimon Glass #include <errno.h> 115ac76badSSimon Glass #include <led.h> 125ac76badSSimon Glass #include <asm/gpio.h> 135ac76badSSimon Glass #include <dm/lists.h> 145ac76badSSimon Glass 155ac76badSSimon Glass DECLARE_GLOBAL_DATA_PTR; 165ac76badSSimon Glass 175ac76badSSimon Glass struct led_gpio_priv { 185ac76badSSimon Glass struct gpio_desc gpio; 195ac76badSSimon Glass }; 205ac76badSSimon Glass 21*ddae9fcdSSimon Glass static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) 225ac76badSSimon Glass { 235ac76badSSimon Glass struct led_gpio_priv *priv = dev_get_priv(dev); 245ac76badSSimon Glass 255ac76badSSimon Glass if (!dm_gpio_is_valid(&priv->gpio)) 265ac76badSSimon Glass return -EREMOTEIO; 275ac76badSSimon Glass 28*ddae9fcdSSimon Glass return dm_gpio_set_value(&priv->gpio, state); 295ac76badSSimon Glass } 305ac76badSSimon Glass 315ac76badSSimon Glass static int led_gpio_probe(struct udevice *dev) 325ac76badSSimon Glass { 3356e19871SSimon Glass struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); 345ac76badSSimon Glass struct led_gpio_priv *priv = dev_get_priv(dev); 355ac76badSSimon Glass 365ac76badSSimon Glass /* Ignore the top-level LED node */ 375ac76badSSimon Glass if (!uc_plat->label) 385ac76badSSimon Glass return 0; 395ac76badSSimon Glass return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); 405ac76badSSimon Glass } 415ac76badSSimon Glass 425ac76badSSimon Glass static int led_gpio_remove(struct udevice *dev) 435ac76badSSimon Glass { 443c43fba3SSimon Glass /* 453c43fba3SSimon Glass * The GPIO driver may have already been removed. We will need to 463c43fba3SSimon Glass * address this more generally. 473c43fba3SSimon Glass */ 483c43fba3SSimon Glass #ifndef CONFIG_SANDBOX 495ac76badSSimon Glass struct led_gpio_priv *priv = dev_get_priv(dev); 505ac76badSSimon Glass 515ac76badSSimon Glass if (dm_gpio_is_valid(&priv->gpio)) 525ac76badSSimon Glass dm_gpio_free(dev, &priv->gpio); 533c43fba3SSimon Glass #endif 545ac76badSSimon Glass 555ac76badSSimon Glass return 0; 565ac76badSSimon Glass } 575ac76badSSimon Glass 585ac76badSSimon Glass static int led_gpio_bind(struct udevice *parent) 595ac76badSSimon Glass { 605ac76badSSimon Glass const void *blob = gd->fdt_blob; 615ac76badSSimon Glass struct udevice *dev; 625ac76badSSimon Glass int node; 635ac76badSSimon Glass int ret; 645ac76badSSimon Glass 65e160f7d4SSimon Glass for (node = fdt_first_subnode(blob, dev_of_offset(parent)); 665ac76badSSimon Glass node > 0; 675ac76badSSimon Glass node = fdt_next_subnode(blob, node)) { 6856e19871SSimon Glass struct led_uc_plat *uc_plat; 695ac76badSSimon Glass const char *label; 705ac76badSSimon Glass 715ac76badSSimon Glass label = fdt_getprop(blob, node, "label", NULL); 725ac76badSSimon Glass if (!label) { 735ac76badSSimon Glass debug("%s: node %s has no label\n", __func__, 745ac76badSSimon Glass fdt_get_name(blob, node, NULL)); 755ac76badSSimon Glass return -EINVAL; 765ac76badSSimon Glass } 775ac76badSSimon Glass ret = device_bind_driver_to_node(parent, "gpio_led", 785ac76badSSimon Glass fdt_get_name(blob, node, NULL), 795ac76badSSimon Glass node, &dev); 805ac76badSSimon Glass if (ret) 815ac76badSSimon Glass return ret; 825ac76badSSimon Glass uc_plat = dev_get_uclass_platdata(dev); 835ac76badSSimon Glass uc_plat->label = label; 845ac76badSSimon Glass } 855ac76badSSimon Glass 865ac76badSSimon Glass return 0; 875ac76badSSimon Glass } 885ac76badSSimon Glass 895ac76badSSimon Glass static const struct led_ops gpio_led_ops = { 90*ddae9fcdSSimon Glass .set_state = gpio_led_set_state, 915ac76badSSimon Glass }; 925ac76badSSimon Glass 935ac76badSSimon Glass static const struct udevice_id led_gpio_ids[] = { 945ac76badSSimon Glass { .compatible = "gpio-leds" }, 955ac76badSSimon Glass { } 965ac76badSSimon Glass }; 975ac76badSSimon Glass 985ac76badSSimon Glass U_BOOT_DRIVER(led_gpio) = { 995ac76badSSimon Glass .name = "gpio_led", 1005ac76badSSimon Glass .id = UCLASS_LED, 1015ac76badSSimon Glass .of_match = led_gpio_ids, 1025ac76badSSimon Glass .ops = &gpio_led_ops, 1035ac76badSSimon Glass .priv_auto_alloc_size = sizeof(struct led_gpio_priv), 1045ac76badSSimon Glass .bind = led_gpio_bind, 1055ac76badSSimon Glass .probe = led_gpio_probe, 1065ac76badSSimon Glass .remove = led_gpio_remove, 1075ac76badSSimon Glass }; 108