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