Line data Source code
1 1 : /*
2 : * Copyright 2023 NXP
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : * @brief Public APIs for MIPI-DBI drivers
10 : *
11 : * MIPI-DBI defines the following 3 interfaces:
12 : * Type A: Motorola 6800 type parallel bus
13 : * Type B: Intel 8080 type parallel bus
14 : * Type C: SPI Type (1 bit bus) with 3 options:
15 : * 1. 9 write clocks per byte, final bit is command/data selection bit
16 : * 2. Same as above, but 16 write clocks per byte
17 : * 3. 8 write clocks per byte. Command/data selected via GPIO pin
18 : * The current driver interface does not support type C with 16 write clocks (option 2).
19 : */
20 :
21 : #ifndef ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_
22 : #define ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_
23 :
24 : /**
25 : * @brief MIPI-DBI driver APIs
26 : * @defgroup mipi_dbi_interface MIPI-DBI driver APIs
27 : * @since 3.6
28 : * @version 0.1.0
29 : * @ingroup io_interfaces
30 : * @{
31 : */
32 :
33 : #include <zephyr/device.h>
34 : #include <zephyr/drivers/display.h>
35 : #include <zephyr/display/mipi_display.h>
36 : #include <zephyr/drivers/spi.h>
37 : #include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>
38 :
39 : #ifdef __cplusplus
40 : extern "C" {
41 : #endif
42 :
43 : /**
44 : * @brief initialize a MIPI DBI SPI configuration struct from devicetree
45 : *
46 : * This helper allows drivers to initialize a MIPI DBI SPI configuration
47 : * structure using devicetree.
48 : * @param node_id Devicetree node identifier for the MIPI DBI device whose
49 : * struct spi_config to create an initializer for
50 : * @param operation_ the desired operation field in the struct spi_config
51 : * @param delay_ the desired delay field in the struct spi_config's
52 : * spi_cs_control, if there is one
53 : */
54 1 : #define MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_) \
55 : { \
56 : .frequency = DT_PROP(node_id, mipi_max_frequency), \
57 : .operation = (operation_) | \
58 : DT_PROP_OR(node_id, duplex, 0) | \
59 : COND_CODE_1(DT_PROP(node_id, mipi_cpol), SPI_MODE_CPOL, (0)) | \
60 : COND_CODE_1(DT_PROP(node_id, mipi_cpha), SPI_MODE_CPHA, (0)) | \
61 : COND_CODE_1(DT_PROP(node_id, mipi_hold_cs), SPI_HOLD_ON_CS, (0)), \
62 : .slave = DT_REG_ADDR(node_id), \
63 : .cs = { \
64 : .gpio = GPIO_DT_SPEC_GET_BY_IDX_OR(DT_PHANDLE(DT_PARENT(node_id), \
65 : spi_dev), cs_gpios, \
66 : DT_REG_ADDR_RAW(node_id), \
67 : {}), \
68 : .delay = (delay_), \
69 : }, \
70 : }
71 :
72 : /**
73 : * @brief Initialize a MIPI DBI SPI configuration from devicetree instance
74 : *
75 : * This helper initializes a MIPI DBI SPI configuration from a devicetree
76 : * instance. It is equivalent to MIPI_DBI_SPI_CONFIG_DT(DT_DRV_INST(inst))
77 : * @param inst Instance number to initialize configuration from
78 : * @param operation_ the desired operation field in the struct spi_config
79 : * @param delay_ the desired delay field in the struct spi_config's
80 : * spi_cs_control, if there is one
81 : */
82 1 : #define MIPI_DBI_SPI_CONFIG_DT_INST(inst, operation_, delay_) \
83 : MIPI_DBI_SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_)
84 :
85 : /**
86 : * @brief Initialize a MIPI DBI configuration from devicetree
87 : *
88 : * This helper allows drivers to initialize a MIPI DBI configuration
89 : * structure from devicetree. It sets the MIPI DBI mode, as well
90 : * as configuration fields in the SPI configuration structure
91 : * @param node_id Devicetree node identifier for the MIPI DBI device to
92 : * initialize
93 : * @param operation_ the desired operation field in the struct spi_config
94 : * @param delay_ the desired delay field in the struct spi_config's
95 : * spi_cs_control, if there is one
96 : */
97 1 : #define MIPI_DBI_CONFIG_DT(node_id, operation_, delay_) \
98 : { \
99 : .mode = DT_STRING_UPPER_TOKEN(node_id, mipi_mode), \
100 : .config = MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_), \
101 : }
102 :
103 : /**
104 : * @brief Initialize a MIPI DBI configuration from device instance
105 : *
106 : * Equivalent to MIPI_DBI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_)
107 : * @param inst Instance of the device to initialize a MIPI DBI configuration for
108 : * @param operation_ the desired operation field in the struct spi_config
109 : * @param delay_ the desired delay field in the struct spi_config's
110 : * spi_cs_control, if there is one
111 : */
112 1 : #define MIPI_DBI_CONFIG_DT_INST(inst, operation_, delay_) \
113 : MIPI_DBI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_)
114 :
115 : /**
116 : * @brief Get the MIPI DBI TE mode from devicetree
117 : *
118 : * Gets the MIPI DBI TE mode from a devicetree property.
119 : * @param node_id Devicetree node identifier for the MIPI DBI device with the
120 : * TE mode property
121 : * @param edge_prop Property name for the TE mode that should be read from
122 : * devicetree
123 : */
124 1 : #define MIPI_DBI_TE_MODE_DT(node_id, edge_prop) \
125 : DT_STRING_UPPER_TOKEN(node_id, edge_prop)
126 :
127 : /**
128 : * @brief Get the MIPI DBI TE mode for device instance
129 : *
130 : * Gets the MIPI DBI TE mode from a devicetree property. Equivalent to
131 : * MIPI_DBI_TE_MODE_DT(DT_DRV_INST(inst), edge_mode).
132 : * @param inst Instance of the device to get the TE mode for
133 : * @param edge_prop Property name for the TE mode that should be read from
134 : * devicetree
135 : */
136 1 : #define MIPI_DBI_TE_MODE_DT_INST(inst, edge_prop) \
137 : DT_STRING_UPPER_TOKEN(DT_DRV_INST(inst), edge_prop)
138 :
139 : /**
140 : * @brief MIPI DBI controller configuration
141 : *
142 : * Configuration for MIPI DBI controller write
143 : */
144 1 : struct mipi_dbi_config {
145 : /** MIPI DBI mode */
146 1 : uint8_t mode;
147 : /** SPI configuration */
148 1 : struct spi_config config;
149 : };
150 :
151 :
152 : /** MIPI-DBI host driver API */
153 1 : __subsystem struct mipi_dbi_driver_api {
154 0 : int (*command_write)(const struct device *dev,
155 : const struct mipi_dbi_config *config, uint8_t cmd,
156 : const uint8_t *data, size_t len);
157 0 : int (*command_read)(const struct device *dev,
158 : const struct mipi_dbi_config *config, uint8_t *cmds,
159 : size_t num_cmds, uint8_t *response, size_t len);
160 0 : int (*write_display)(const struct device *dev,
161 : const struct mipi_dbi_config *config,
162 : const uint8_t *framebuf,
163 : struct display_buffer_descriptor *desc,
164 : enum display_pixel_format pixfmt);
165 0 : int (*reset)(const struct device *dev, k_timeout_t delay);
166 0 : int (*release)(const struct device *dev,
167 : const struct mipi_dbi_config *config);
168 0 : int (*configure_te)(const struct device *dev,
169 : uint8_t edge,
170 : k_timeout_t delay);
171 : };
172 :
173 : /**
174 : * @brief Write a command to the display controller
175 : *
176 : * Writes a command, along with an optional data buffer to the display.
177 : * If data buffer and buffer length are NULL and 0 respectively, then
178 : * only a command will be sent. Note that if the SPI configuration passed
179 : * to this function locks the SPI bus, it is the caller's responsibility
180 : * to release it with mipi_dbi_release()
181 : *
182 : * @param dev mipi dbi controller
183 : * @param config MIPI DBI configuration
184 : * @param cmd command to write to display controller
185 : * @param data optional data buffer to write after command
186 : * @param len size of data buffer in bytes. Set to 0 to skip sending data.
187 : * @retval 0 command write succeeded
188 : * @retval -EIO I/O error
189 : * @retval -ETIMEDOUT transfer timed out
190 : * @retval -EBUSY controller is busy
191 : * @retval -ENOSYS not implemented
192 : */
193 1 : static inline int mipi_dbi_command_write(const struct device *dev,
194 : const struct mipi_dbi_config *config,
195 : uint8_t cmd, const uint8_t *data,
196 : size_t len)
197 : {
198 : const struct mipi_dbi_driver_api *api =
199 : (const struct mipi_dbi_driver_api *)dev->api;
200 :
201 : if (api->command_write == NULL) {
202 : return -ENOSYS;
203 : }
204 : return api->command_write(dev, config, cmd, data, len);
205 : }
206 :
207 : /**
208 : * @brief Read a command response from the display controller
209 : *
210 : * Reads a command response from the display controller.
211 : *
212 : * @param dev mipi dbi controller
213 : * @param config MIPI DBI configuration
214 : * @param cmds array of one byte commands to send to display controller
215 : * @param num_cmd number of commands to write to display controller
216 : * @param response response buffer, filled with display controller response
217 : * @param len size of response buffer in bytes.
218 : * @retval 0 command read succeeded
219 : * @retval -EIO I/O error
220 : * @retval -ETIMEDOUT transfer timed out
221 : * @retval -EBUSY controller is busy
222 : * @retval -ENOSYS not implemented
223 : */
224 1 : static inline int mipi_dbi_command_read(const struct device *dev,
225 : const struct mipi_dbi_config *config,
226 : uint8_t *cmds, size_t num_cmd,
227 : uint8_t *response, size_t len)
228 : {
229 : const struct mipi_dbi_driver_api *api =
230 : (const struct mipi_dbi_driver_api *)dev->api;
231 :
232 : if (api->command_read == NULL) {
233 : return -ENOSYS;
234 : }
235 : return api->command_read(dev, config, cmds, num_cmd, response, len);
236 : }
237 :
238 : /**
239 : * @brief Write a display buffer to the display controller.
240 : *
241 : * Writes a display buffer to the controller. If the controller requires
242 : * a "Write memory" command before writing display data, this should be
243 : * sent with @ref mipi_dbi_command_write
244 : * @param dev mipi dbi controller
245 : * @param config MIPI DBI configuration
246 : * @param framebuf: framebuffer to write to display
247 : * @param desc: descriptor of framebuffer to write. Note that the pitch must
248 : * be equal to width. "buf_size" field determines how many bytes will be
249 : * written.
250 : * @param pixfmt: pixel format of framebuffer data
251 : * @retval 0 buffer write succeeded.
252 : * @retval -EIO I/O error
253 : * @retval -ETIMEDOUT transfer timed out
254 : * @retval -EBUSY controller is busy
255 : * @retval -ENOSYS not implemented
256 : */
257 1 : static inline int mipi_dbi_write_display(const struct device *dev,
258 : const struct mipi_dbi_config *config,
259 : const uint8_t *framebuf,
260 : struct display_buffer_descriptor *desc,
261 : enum display_pixel_format pixfmt)
262 : {
263 : const struct mipi_dbi_driver_api *api =
264 : (const struct mipi_dbi_driver_api *)dev->api;
265 :
266 : if (api->write_display == NULL) {
267 : return -ENOSYS;
268 : }
269 : return api->write_display(dev, config, framebuf, desc, pixfmt);
270 : }
271 :
272 : /**
273 : * @brief Resets attached display controller
274 : *
275 : * Resets the attached display controller.
276 : * @param dev mipi dbi controller
277 : * @param delay_ms duration to set reset signal for, in milliseconds
278 : * @retval 0 reset succeeded
279 : * @retval -EIO I/O error
280 : * @retval -ENOSYS not implemented
281 : * @retval -ENOTSUP not supported
282 : */
283 1 : static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay_ms)
284 : {
285 : const struct mipi_dbi_driver_api *api =
286 : (const struct mipi_dbi_driver_api *)dev->api;
287 :
288 : if (api->reset == NULL) {
289 : return -ENOSYS;
290 : }
291 : return api->reset(dev, K_MSEC(delay_ms));
292 : }
293 :
294 : /**
295 : * @brief Releases a locked MIPI DBI device.
296 : *
297 : * Releases a lock on a MIPI DBI device and/or the device's CS line if and
298 : * only if the given config parameter was the last one to be used in any
299 : * of the above functions, and if it has the SPI_LOCK_ON bit set and/or
300 : * the SPI_HOLD_ON_CS bit set into its operation bits field.
301 : * This lock functions exactly like the SPI lock, and can be used if the caller
302 : * needs to keep CS asserted for multiple transactions, or the MIPI DBI device
303 : * locked.
304 : * @param dev mipi dbi controller
305 : * @param config MIPI DBI configuration
306 : * @retval 0 reset succeeded
307 : * @retval -EIO I/O error
308 : * @retval -ENOSYS not implemented
309 : * @retval -ENOTSUP not supported
310 : */
311 1 : static inline int mipi_dbi_release(const struct device *dev,
312 : const struct mipi_dbi_config *config)
313 : {
314 : const struct mipi_dbi_driver_api *api =
315 : (const struct mipi_dbi_driver_api *)dev->api;
316 :
317 : if (api->release == NULL) {
318 : return -ENOSYS;
319 : }
320 : return api->release(dev, config);
321 : }
322 :
323 : /**
324 : * @brief Configures MIPI DBI tearing effect signal
325 : *
326 : * Many displays provide a tearing effect signal, which can be configured
327 : * to pulse at each vsync interval or each hsync interval. This signal can be
328 : * used by the MCU to determine when to transmit a new frame so that the
329 : * read pointer of the display never overlaps with the write pointer from the
330 : * MCU. This function configures the MIPI DBI controller to delay transmitting
331 : * display frames until the selected tearing effect signal edge occurs.
332 : *
333 : * The delay will occur on the on each call to @ref mipi_dbi_write_display
334 : * where the ``frame_incomplete`` flag was set within the buffer descriptor
335 : * provided with the prior call, as this indicates the buffer being written
336 : * in this call is the first buffer of a new frame.
337 : *
338 : * Note that most display controllers will need to enable the TE signal
339 : * using vendor specific commands before the MIPI DBI controller can react
340 : * to it.
341 : *
342 : * @param dev mipi dbi controller
343 : * @param edge which edge of the TE signal to start transmitting on
344 : * @param delay_us how many microseconds after TE edge to start transmission
345 : * @retval -EIO I/O error
346 : * @retval -ENOSYS not implemented
347 : * @retval -ENOTSUP not supported
348 : */
349 1 : static inline int mipi_dbi_configure_te(const struct device *dev,
350 : uint8_t edge,
351 : uint32_t delay_us)
352 : {
353 : const struct mipi_dbi_driver_api *api =
354 : (const struct mipi_dbi_driver_api *)dev->api;
355 :
356 : if (api->configure_te == NULL) {
357 : return -ENOSYS;
358 : }
359 : return api->configure_te(dev, edge, K_USEC(delay_us));
360 : }
361 :
362 : #ifdef __cplusplus
363 : }
364 : #endif
365 :
366 : /**
367 : * @}
368 : */
369 :
370 : #endif /* ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ */
|