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