xref: /openbmc/u-boot/drivers/led/led_gpio.c (revision 699e831e158a5846778d8bd6af054d4276277cb6)
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