1 /* 2 * Copyright (c) 2015 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <led.h> 12 #include <asm/gpio.h> 13 #include <dm/lists.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 struct led_gpio_priv { 18 struct gpio_desc gpio; 19 }; 20 21 static int gpio_led_set_on(struct udevice *dev, int on) 22 { 23 struct led_gpio_priv *priv = dev_get_priv(dev); 24 25 if (!dm_gpio_is_valid(&priv->gpio)) 26 return -EREMOTEIO; 27 28 return dm_gpio_set_value(&priv->gpio, on); 29 } 30 31 static int led_gpio_probe(struct udevice *dev) 32 { 33 struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); 34 struct led_gpio_priv *priv = dev_get_priv(dev); 35 36 /* Ignore the top-level LED node */ 37 if (!uc_plat->label) 38 return 0; 39 return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); 40 } 41 42 static int led_gpio_remove(struct udevice *dev) 43 { 44 /* 45 * The GPIO driver may have already been removed. We will need to 46 * address this more generally. 47 */ 48 #ifndef CONFIG_SANDBOX 49 struct led_gpio_priv *priv = dev_get_priv(dev); 50 51 if (dm_gpio_is_valid(&priv->gpio)) 52 dm_gpio_free(dev, &priv->gpio); 53 #endif 54 55 return 0; 56 } 57 58 static int led_gpio_bind(struct udevice *parent) 59 { 60 const void *blob = gd->fdt_blob; 61 struct udevice *dev; 62 int node; 63 int ret; 64 65 for (node = fdt_first_subnode(blob, dev_of_offset(parent)); 66 node > 0; 67 node = fdt_next_subnode(blob, node)) { 68 struct led_uclass_plat *uc_plat; 69 const char *label; 70 71 label = fdt_getprop(blob, node, "label", NULL); 72 if (!label) { 73 debug("%s: node %s has no label\n", __func__, 74 fdt_get_name(blob, node, NULL)); 75 return -EINVAL; 76 } 77 ret = device_bind_driver_to_node(parent, "gpio_led", 78 fdt_get_name(blob, node, NULL), 79 node, &dev); 80 if (ret) 81 return ret; 82 uc_plat = dev_get_uclass_platdata(dev); 83 uc_plat->label = label; 84 } 85 86 return 0; 87 } 88 89 static const struct led_ops gpio_led_ops = { 90 .set_on = gpio_led_set_on, 91 }; 92 93 static const struct udevice_id led_gpio_ids[] = { 94 { .compatible = "gpio-leds" }, 95 { } 96 }; 97 98 U_BOOT_DRIVER(led_gpio) = { 99 .name = "gpio_led", 100 .id = UCLASS_LED, 101 .of_match = led_gpio_ids, 102 .ops = &gpio_led_ops, 103 .priv_auto_alloc_size = sizeof(struct led_gpio_priv), 104 .bind = led_gpio_bind, 105 .probe = led_gpio_probe, 106 .remove = led_gpio_remove, 107 }; 108