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