1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2024 Jamie McCrae
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @file
10  * @brief Public API for controlling linear strips of LEDs.
11  *
12  * This library abstracts the chipset drivers for individually
13  * addressable strips of LEDs.
14  */
15 
16 #ifndef ZEPHYR_INCLUDE_DRIVERS_LED_STRIP_H_
17 #define ZEPHYR_INCLUDE_DRIVERS_LED_STRIP_H_
18 
19 /**
20  * @brief LED Strip Interface
21  * @defgroup led_strip_interface LED Strip Interface
22  * @ingroup io_interfaces
23  * @{
24  */
25 
26 #include <errno.h>
27 #include <zephyr/types.h>
28 #include <zephyr/device.h>
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /**
35  * @brief Color value for a single RGB LED.
36  *
37  * Individual strip drivers may ignore lower-order bits if their
38  * resolution in any channel is less than a full byte.
39  */
40 struct led_rgb {
41 #ifdef CONFIG_LED_STRIP_RGB_SCRATCH
42 	/*
43 	 * Pad/scratch space needed by some drivers. Users should
44 	 * ignore.
45 	 */
46 	uint8_t scratch;
47 #endif
48 	/** Red channel */
49 	uint8_t r;
50 	/** Green channel */
51 	uint8_t g;
52 	/** Blue channel */
53 	uint8_t b;
54 };
55 
56 /**
57  * @typedef led_api_update_rgb
58  * @brief Callback API for updating an RGB LED strip
59  *
60  * @see led_strip_update_rgb() for argument descriptions.
61  */
62 typedef int (*led_api_update_rgb)(const struct device *dev,
63 				  struct led_rgb *pixels,
64 				  size_t num_pixels);
65 
66 /**
67  * @typedef led_api_update_channels
68  * @brief Callback API for updating channels without an RGB interpretation.
69  *
70  * @see led_strip_update_channels() for argument descriptions.
71  */
72 typedef int (*led_api_update_channels)(const struct device *dev,
73 				       uint8_t *channels,
74 				       size_t num_channels);
75 
76 /**
77  * @typedef led_api_length
78  * @brief Callback API for getting length of an LED strip.
79  *
80  * @see led_strip_length() for argument descriptions.
81  */
82 typedef size_t (*led_api_length)(const struct device *dev);
83 
84 /**
85  * @brief LED strip driver API
86  *
87  * This is the mandatory API any LED strip driver needs to expose.
88  */
89 __subsystem struct led_strip_driver_api {
90 	led_api_update_rgb update_rgb;
91 	led_api_update_channels update_channels;
92 	led_api_length length;
93 };
94 
95 /**
96  * @brief		Mandatory function to update an LED strip with the given RGB array.
97  *
98  * @param dev		LED strip device.
99  * @param pixels	Array of pixel data.
100  * @param num_pixels	Length of pixels array.
101  *
102  * @retval		0 on success.
103  * @retval		-errno negative errno code on failure.
104  *
105  * @warning		This routine may overwrite @a pixels.
106  */
led_strip_update_rgb(const struct device * dev,struct led_rgb * pixels,size_t num_pixels)107 static inline int led_strip_update_rgb(const struct device *dev,
108 				       struct led_rgb *pixels,
109 				       size_t num_pixels)
110 {
111 	const struct led_strip_driver_api *api =
112 		(const struct led_strip_driver_api *)dev->api;
113 
114 	/* Allow for out-of-tree drivers that do not have this function for 2 Zephyr releases
115 	 * until making it mandatory, function added after Zephyr 3.6
116 	 */
117 	if (api->length != NULL) {
118 		/* Ensure supplied pixel size is valid for this device */
119 		if (api->length(dev) < num_pixels) {
120 			return -ERANGE;
121 		}
122 	}
123 
124 	return api->update_rgb(dev, pixels, num_pixels);
125 }
126 
127 /**
128  * @brief		Optional function to update an LED strip with the given channel array
129  *			(each channel byte corresponding to an individually addressable color
130  *			channel or LED. Channels are updated linearly in strip order.
131  *
132  * @param dev		LED strip device.
133  * @param channels	Array of per-channel data.
134  * @param num_channels	Length of channels array.
135  *
136  * @retval		0 on success.
137  * @retval		-ENOSYS if not implemented.
138  * @retval		-errno negative errno code on other failure.
139  *
140  * @warning		This routine may overwrite @a channels.
141  */
led_strip_update_channels(const struct device * dev,uint8_t * channels,size_t num_channels)142 static inline int led_strip_update_channels(const struct device *dev,
143 					    uint8_t *channels,
144 					    size_t num_channels)
145 {
146 	const struct led_strip_driver_api *api =
147 		(const struct led_strip_driver_api *)dev->api;
148 
149 	if (api->update_channels == NULL) {
150 		return -ENOSYS;
151 	}
152 
153 	return api->update_channels(dev, channels, num_channels);
154 }
155 
156 /**
157  * @brief	Mandatory function to get chain length (in pixels) of an LED strip device.
158  *
159  * @param dev	LED strip device.
160  *
161  * @retval	Length of LED strip device.
162  */
led_strip_length(const struct device * dev)163 static inline size_t led_strip_length(const struct device *dev)
164 {
165 	const struct led_strip_driver_api *api =
166 		(const struct led_strip_driver_api *)dev->api;
167 
168 	return api->length(dev);
169 }
170 
171 #ifdef __cplusplus
172 }
173 #endif
174 
175 /**
176  * @}
177  */
178 
179 #endif	/* ZEPHYR_INCLUDE_DRIVERS_LED_STRIP_H_ */
180