Line data Source code
1 1 : /*
2 : * Copyright (c) 2018 Linaro Limited
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : * @brief Public LED driver APIs
10 : */
11 :
12 : #ifndef ZEPHYR_INCLUDE_DRIVERS_LED_H_
13 : #define ZEPHYR_INCLUDE_DRIVERS_LED_H_
14 :
15 : /**
16 : * @brief LED Interface
17 : * @defgroup led_interface LED Interface
18 : * @since 1.12
19 : * @version 1.0.0
20 : * @ingroup io_interfaces
21 : * @{
22 : */
23 :
24 : #include <errno.h>
25 :
26 : #include <zephyr/types.h>
27 : #include <zephyr/device.h>
28 :
29 : #ifdef __cplusplus
30 : extern "C" {
31 : #endif
32 :
33 : /**
34 : * @brief Maximum brightness level, range is 0 to 100.
35 : */
36 1 : #define LED_BRIGHTNESS_MAX 100u
37 :
38 : /**
39 : * @brief LED information structure
40 : *
41 : * This structure gathers useful information about LED controller.
42 : */
43 1 : struct led_info {
44 : /** LED label */
45 1 : const char *label;
46 : /** Index of the LED on the controller */
47 1 : uint32_t index;
48 : /** Number of colors per LED */
49 1 : uint8_t num_colors;
50 : /** Mapping of the LED colors */
51 1 : const uint8_t *color_mapping;
52 : };
53 :
54 : /**
55 : * @typedef led_api_blink()
56 : * @brief Callback API for blinking an LED
57 : *
58 : * @see led_blink() for argument descriptions.
59 : */
60 1 : typedef int (*led_api_blink)(const struct device *dev, uint32_t led,
61 : uint32_t delay_on, uint32_t delay_off);
62 :
63 : /**
64 : * @typedef led_api_get_info()
65 : * @brief Optional API callback to get LED information
66 : *
67 : * @see led_get_info() for argument descriptions.
68 : */
69 1 : typedef int (*led_api_get_info)(const struct device *dev, uint32_t led,
70 : const struct led_info **info);
71 :
72 : /**
73 : * @typedef led_api_set_brightness()
74 : * @brief Callback API for setting brightness of an LED
75 : *
76 : * @see led_set_brightness() for argument descriptions.
77 : */
78 1 : typedef int (*led_api_set_brightness)(const struct device *dev, uint32_t led,
79 : uint8_t value);
80 : /**
81 : * @typedef led_api_set_color()
82 : * @brief Optional API callback to set the colors of a LED.
83 : *
84 : * @see led_set_color() for argument descriptions.
85 : */
86 1 : typedef int (*led_api_set_color)(const struct device *dev, uint32_t led,
87 : uint8_t num_colors, const uint8_t *color);
88 :
89 : /**
90 : * @typedef led_api_on()
91 : * @brief Callback API for turning on an LED
92 : *
93 : * @see led_on() for argument descriptions.
94 : */
95 1 : typedef int (*led_api_on)(const struct device *dev, uint32_t led);
96 :
97 : /**
98 : * @typedef led_api_off()
99 : * @brief Callback API for turning off an LED
100 : *
101 : * @see led_off() for argument descriptions.
102 : */
103 1 : typedef int (*led_api_off)(const struct device *dev, uint32_t led);
104 :
105 : /**
106 : * @typedef led_api_write_channels()
107 : * @brief Callback API for writing a strip of LED channels
108 : *
109 : * @see led_api_write_channels() for arguments descriptions.
110 : */
111 1 : typedef int (*led_api_write_channels)(const struct device *dev,
112 : uint32_t start_channel,
113 : uint32_t num_channels,
114 : const uint8_t *buf);
115 :
116 : /**
117 : * @brief LED driver API
118 : */
119 1 : __subsystem struct led_driver_api {
120 : /* Mandatory callbacks, either on/off or set_brightness. */
121 0 : led_api_on on;
122 0 : led_api_off off;
123 0 : led_api_set_brightness set_brightness;
124 : /* Optional callbacks. */
125 0 : led_api_blink blink;
126 0 : led_api_get_info get_info;
127 0 : led_api_set_color set_color;
128 0 : led_api_write_channels write_channels;
129 : };
130 :
131 : /**
132 : * @brief Blink an LED
133 : *
134 : * This optional routine starts blinking a LED forever with the given time
135 : * period.
136 : *
137 : * @param dev LED device
138 : * @param led LED number
139 : * @param delay_on Time period (in milliseconds) an LED should be ON
140 : * @param delay_off Time period (in milliseconds) an LED should be OFF
141 : * @return 0 on success, negative on error
142 : */
143 1 : __syscall int led_blink(const struct device *dev, uint32_t led,
144 : uint32_t delay_on, uint32_t delay_off);
145 :
146 : static inline int z_impl_led_blink(const struct device *dev, uint32_t led,
147 : uint32_t delay_on, uint32_t delay_off)
148 : {
149 : const struct led_driver_api *api =
150 : (const struct led_driver_api *)dev->api;
151 :
152 : if (api->blink == NULL) {
153 : return -ENOSYS;
154 : }
155 : return api->blink(dev, led, delay_on, delay_off);
156 : }
157 :
158 : /**
159 : * @brief Get LED information
160 : *
161 : * This optional routine provides information about a LED.
162 : *
163 : * @param dev LED device
164 : * @param led LED number
165 : * @param info Pointer to a pointer filled with LED information
166 : * @return 0 on success, negative on error
167 : */
168 1 : __syscall int led_get_info(const struct device *dev, uint32_t led,
169 : const struct led_info **info);
170 :
171 : static inline int z_impl_led_get_info(const struct device *dev, uint32_t led,
172 : const struct led_info **info)
173 : {
174 : const struct led_driver_api *api =
175 : (const struct led_driver_api *)dev->api;
176 :
177 : if (api->get_info == NULL) {
178 : *info = NULL;
179 : return -ENOSYS;
180 : }
181 : return api->get_info(dev, led, info);
182 : }
183 :
184 : /**
185 : * @brief Set LED brightness
186 : *
187 : * This optional routine sets the brightness of a LED to the given value.
188 : * Calling this function after led_blink() won't affect blinking.
189 : *
190 : * LEDs which can only be turned on or off do not need to provide this
191 : * function.
192 : * These should simply turn the LED on if @p value is nonzero, and off
193 : * if @p value is zero using the on/off APIs automatically.
194 : *
195 : * @param dev LED device
196 : * @param led LED number
197 : * @param value Brightness value to set in percent
198 : * @return 0 on success, negative on error
199 : */
200 1 : __syscall int led_set_brightness(const struct device *dev, uint32_t led,
201 : uint8_t value);
202 :
203 : static inline int z_impl_led_set_brightness(const struct device *dev,
204 : uint32_t led,
205 : uint8_t value)
206 : {
207 : const struct led_driver_api *api =
208 : (const struct led_driver_api *)dev->api;
209 :
210 : if (api->set_brightness == NULL) {
211 : if (api->on == NULL || api->off == NULL) {
212 : return -ENOSYS;
213 : }
214 : }
215 :
216 : if (value > LED_BRIGHTNESS_MAX) {
217 : return -EINVAL;
218 : }
219 :
220 : if (api->set_brightness == NULL) {
221 : if (value) {
222 : return api->on(dev, led);
223 : } else {
224 : return api->off(dev, led);
225 : }
226 : }
227 :
228 : return api->set_brightness(dev, led, value);
229 : }
230 :
231 : /**
232 : * @brief Write/update a strip of LED channels
233 : *
234 : * This optional routine writes a strip of LED channels to the given array of
235 : * levels. Therefore it can be used to configure several LEDs at the same time.
236 : *
237 : * Calling this function after led_blink() won't affect blinking.
238 : *
239 : * @param dev LED device
240 : * @param start_channel Absolute number (i.e. not relative to a LED) of the
241 : * first channel to update.
242 : * @param num_channels The number of channels to write/update.
243 : * @param buf array of values to configure the channels with. num_channels
244 : * entries must be provided.
245 : * @return 0 on success, negative on error
246 : */
247 1 : __syscall int led_write_channels(const struct device *dev,
248 : uint32_t start_channel,
249 : uint32_t num_channels, const uint8_t *buf);
250 :
251 : static inline int
252 : z_impl_led_write_channels(const struct device *dev, uint32_t start_channel,
253 : uint32_t num_channels, const uint8_t *buf)
254 : {
255 : const struct led_driver_api *api =
256 : (const struct led_driver_api *)dev->api;
257 :
258 : if (api->write_channels == NULL) {
259 : return -ENOSYS;
260 : }
261 : return api->write_channels(dev, start_channel, num_channels, buf);
262 : }
263 :
264 : /**
265 : * @brief Set a single LED channel
266 : *
267 : * This optional routine sets a single LED channel to the given value.
268 : *
269 : * Calling this function after led_blink() won't affect blinking.
270 : *
271 : * @param dev LED device
272 : * @param channel Absolute channel number (i.e. not relative to a LED)
273 : * @param value Value to configure the channel with
274 : * @return 0 on success, negative on error
275 : */
276 1 : __syscall int led_set_channel(const struct device *dev,
277 : uint32_t channel, uint8_t value);
278 :
279 : static inline int z_impl_led_set_channel(const struct device *dev,
280 : uint32_t channel, uint8_t value)
281 : {
282 : return z_impl_led_write_channels(dev, channel, 1, &value);
283 : }
284 :
285 : /**
286 : * @brief Set LED color
287 : *
288 : * This routine configures all the color channels of a LED with the given
289 : * color array.
290 : *
291 : * Calling this function after led_blink() won't affect blinking.
292 : *
293 : * @param dev LED device
294 : * @param led LED number
295 : * @param num_colors Number of colors in the array.
296 : * @param color Array of colors. It must be ordered following the color
297 : * mapping of the LED controller. See the color_mapping member
298 : * in struct led_info.
299 : * @return 0 on success, negative on error
300 : */
301 1 : __syscall int led_set_color(const struct device *dev, uint32_t led,
302 : uint8_t num_colors, const uint8_t *color);
303 :
304 : static inline int z_impl_led_set_color(const struct device *dev, uint32_t led,
305 : uint8_t num_colors, const uint8_t *color)
306 : {
307 : const struct led_driver_api *api =
308 : (const struct led_driver_api *)dev->api;
309 :
310 : if (api->set_color == NULL) {
311 : return -ENOSYS;
312 : }
313 : return api->set_color(dev, led, num_colors, color);
314 : }
315 :
316 : /**
317 : * @brief Turn on an LED
318 : *
319 : * This routine turns on an LED
320 : *
321 : * LEDs which implements brightness control do not need to implement this, the
322 : * set_brightness API is used automatically.
323 : *
324 : * @param dev LED device
325 : * @param led LED number
326 : * @return 0 on success, negative on error
327 : */
328 1 : __syscall int led_on(const struct device *dev, uint32_t led);
329 :
330 : static inline int z_impl_led_on(const struct device *dev, uint32_t led)
331 : {
332 : const struct led_driver_api *api =
333 : (const struct led_driver_api *)dev->api;
334 :
335 : if (api->set_brightness == NULL && api->on == NULL) {
336 : return -ENOSYS;
337 : }
338 :
339 : if (api->on == NULL) {
340 : return api->set_brightness(dev, led, LED_BRIGHTNESS_MAX);
341 : }
342 :
343 : return api->on(dev, led);
344 : }
345 :
346 : /**
347 : * @brief Turn off an LED
348 : *
349 : * This routine turns off an LED
350 : *
351 : * LEDs which implements brightness control do not need to implement this, the
352 : * set_brightness API is used automatically.
353 : *
354 : * @param dev LED device
355 : * @param led LED number
356 : * @return 0 on success, negative on error
357 : */
358 1 : __syscall int led_off(const struct device *dev, uint32_t led);
359 :
360 : static inline int z_impl_led_off(const struct device *dev, uint32_t led)
361 : {
362 : const struct led_driver_api *api =
363 : (const struct led_driver_api *)dev->api;
364 :
365 : if (api->set_brightness == NULL && api->off == NULL) {
366 : return -ENOSYS;
367 : }
368 :
369 : if (api->off == NULL) {
370 : return api->set_brightness(dev, led, 0);
371 : }
372 :
373 : return api->off(dev, led);
374 : }
375 :
376 : /*
377 : * LED DT helpers.
378 : */
379 :
380 : /**
381 : * @brief Container for an LED information specified in devicetree.
382 : *
383 : * This type contains a pointer to and LED device and an LED index.
384 : *
385 : * @see LED_DT_SPEC_GET
386 : * @see LED_DT_SPEC_GET_OR
387 : */
388 1 : struct led_dt_spec {
389 : /** LED device instance. */
390 1 : const struct device *dev;
391 : /** Index of the LED on the controller. */
392 1 : uint32_t index;
393 : };
394 :
395 : /**
396 : * @brief Set LED brightness from a led_dt_spec.
397 : *
398 : * @param spec LED device specification from devicetree.
399 : * @param value Brightness value to set in percent.
400 : * @return 0 on success, negative on error.
401 : *
402 : * @see led_set_brightness()
403 : */
404 1 : static inline int led_set_brightness_dt(const struct led_dt_spec *spec,
405 : uint8_t value)
406 : {
407 : return led_set_brightness(spec->dev, spec->index, value);
408 : }
409 :
410 : /**
411 : * @brief Turn on an LED from a struct led_dt_spec.
412 : *
413 : * @param spec LED device specification from devicetree.
414 : * @return 0 on success, negative on error.
415 : *
416 : * @see led_on()
417 : */
418 1 : static inline int led_on_dt(const struct led_dt_spec *spec)
419 : {
420 : return led_on(spec->dev, spec->index);
421 : }
422 :
423 : /**
424 : * @brief Turn off an LED from a struct led_dt_spec.
425 : *
426 : * @param spec LED device specification from devicetree.
427 : * @return 0 on success, negative on error.
428 : *
429 : * @see led_off()
430 : */
431 1 : static inline int led_off_dt(const struct led_dt_spec *spec)
432 : {
433 : return led_off(spec->dev, spec->index);
434 : }
435 :
436 : /**
437 : * @brief Validate that the LED device is ready.
438 : *
439 : * @param spec LED specification from devicetree.
440 : *
441 : * @retval true If the LED device is ready for use.
442 : * @retval false If the LED device is not ready for use.
443 : */
444 1 : static inline bool led_is_ready_dt(const struct led_dt_spec *spec)
445 : {
446 : return device_is_ready(spec->dev);
447 : }
448 :
449 : /**
450 : * @brief Static initializer for a struct led_dt_spec
451 : *
452 : * This returns a static initializer for a struct led_dt_spec given a devicetree
453 : * node identifier.
454 : *
455 : * Example devicetree fragment:
456 : *
457 : * @code{.dts}
458 : * leds {
459 : * compatible = "gpio-leds";
460 : * led0: led_0 {
461 : * ...
462 : * };
463 : * };
464 : * @endcode
465 : *
466 : * Example usage:
467 : *
468 : * @code{.c}
469 : * const struct led_dt_spec spec = LED_DT_SPEC_GET(DT_NODELABEL(led0));
470 : *
471 : * // Initializes 'spec' to:
472 : * // {
473 : * // .dev = DEVICE_DT_GET(DT_PARENT(led0)),
474 : * // .index = 0,
475 : * // }
476 : * @endcode
477 : *
478 : * The device (dev) must still be checked for readiness, e.g. using
479 : * device_is_ready().
480 : *
481 : * @param node_id Devicetree node identifier.
482 : *
483 : * @return Static initializer for a struct led_dt_spec for the property.
484 : */
485 1 : #define LED_DT_SPEC_GET(node_id) \
486 : { \
487 : .dev = DEVICE_DT_GET(DT_PARENT(node_id)), \
488 : .index = DT_NODE_CHILD_IDX(node_id), \
489 : }
490 :
491 : /**
492 : * @brief Like LED_DT_SPEC_GET(), with a fallback value if the node does not exist.
493 : *
494 : * @param node_id Devicetree node identifier.
495 : *
496 : * @return Static initializer for a struct led_dt_spec for the property.
497 : *
498 : * @see LED_DT_SPEC_GET
499 : */
500 1 : #define LED_DT_SPEC_GET_OR(node_id, default_value) \
501 : COND_CODE_1(DT_NODE_EXISTS(node_id), \
502 : (LED_DT_SPEC_GET(node_id)), \
503 : (default_value))
504 :
505 : /**
506 : * @}
507 : */
508 :
509 : #ifdef __cplusplus
510 : }
511 : #endif
512 :
513 : #include <zephyr/syscalls/led.h>
514 :
515 : #endif /* ZEPHYR_INCLUDE_DRIVERS_LED_H_ */
|