1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2015 Google, Inc 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <led.h> 11 #include <asm/gpio.h> 12 #include <dm/lists.h> 13 14 struct led_gpio_priv { 15 struct gpio_desc gpio; 16 }; 17 18 static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) 19 { 20 struct led_gpio_priv *priv = dev_get_priv(dev); 21 int ret; 22 23 if (!dm_gpio_is_valid(&priv->gpio)) 24 return -EREMOTEIO; 25 switch (state) { 26 case LEDST_OFF: 27 case LEDST_ON: 28 break; 29 case LEDST_TOGGLE: 30 ret = dm_gpio_get_value(&priv->gpio); 31 if (ret < 0) 32 return ret; 33 state = !ret; 34 break; 35 default: 36 return -ENOSYS; 37 } 38 39 return dm_gpio_set_value(&priv->gpio, state); 40 } 41 42 static enum led_state_t gpio_led_get_state(struct udevice *dev) 43 { 44 struct led_gpio_priv *priv = dev_get_priv(dev); 45 int ret; 46 47 if (!dm_gpio_is_valid(&priv->gpio)) 48 return -EREMOTEIO; 49 ret = dm_gpio_get_value(&priv->gpio); 50 if (ret < 0) 51 return ret; 52 53 return ret ? LEDST_ON : LEDST_OFF; 54 } 55 56 static int led_gpio_probe(struct udevice *dev) 57 { 58 struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); 59 struct led_gpio_priv *priv = dev_get_priv(dev); 60 61 /* Ignore the top-level LED node */ 62 if (!uc_plat->label) 63 return 0; 64 return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); 65 } 66 67 static int led_gpio_remove(struct udevice *dev) 68 { 69 /* 70 * The GPIO driver may have already been removed. We will need to 71 * address this more generally. 72 */ 73 #ifndef CONFIG_SANDBOX 74 struct led_gpio_priv *priv = dev_get_priv(dev); 75 76 if (dm_gpio_is_valid(&priv->gpio)) 77 dm_gpio_free(dev, &priv->gpio); 78 #endif 79 80 return 0; 81 } 82 83 static int led_gpio_bind(struct udevice *parent) 84 { 85 struct udevice *dev; 86 ofnode node; 87 int ret; 88 89 dev_for_each_subnode(node, parent) { 90 struct led_uc_plat *uc_plat; 91 const char *label; 92 93 label = ofnode_read_string(node, "label"); 94 if (!label) { 95 debug("%s: node %s has no label\n", __func__, 96 ofnode_get_name(node)); 97 return -EINVAL; 98 } 99 ret = device_bind_driver_to_node(parent, "gpio_led", 100 ofnode_get_name(node), 101 node, &dev); 102 if (ret) 103 return ret; 104 uc_plat = dev_get_uclass_platdata(dev); 105 uc_plat->label = label; 106 } 107 108 return 0; 109 } 110 111 static const struct led_ops gpio_led_ops = { 112 .set_state = gpio_led_set_state, 113 .get_state = gpio_led_get_state, 114 }; 115 116 static const struct udevice_id led_gpio_ids[] = { 117 { .compatible = "gpio-leds" }, 118 { } 119 }; 120 121 U_BOOT_DRIVER(led_gpio) = { 122 .name = "gpio_led", 123 .id = UCLASS_LED, 124 .of_match = led_gpio_ids, 125 .ops = &gpio_led_ops, 126 .priv_auto_alloc_size = sizeof(struct led_gpio_priv), 127 .bind = led_gpio_bind, 128 .probe = led_gpio_probe, 129 .remove = led_gpio_remove, 130 }; 131