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 #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 #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 #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 #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 #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 #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 struct mipi_dbi_config {
145 /** MIPI DBI mode */
146 uint8_t mode;
147 /** SPI configuration */
148 struct spi_config config;
149 };
150
151
152 /** MIPI-DBI host driver API */
153 __subsystem struct mipi_dbi_driver_api {
154 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 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 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 int (*reset)(const struct device *dev, k_timeout_t delay);
166 int (*release)(const struct device *dev,
167 const struct mipi_dbi_config *config);
168 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 */
mipi_dbi_command_write(const struct device * dev,const struct mipi_dbi_config * config,uint8_t cmd,const uint8_t * data,size_t len)193 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 */
mipi_dbi_command_read(const struct device * dev,const struct mipi_dbi_config * config,uint8_t * cmds,size_t num_cmd,uint8_t * response,size_t len)224 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 */
mipi_dbi_write_display(const struct device * dev,const struct mipi_dbi_config * config,const uint8_t * framebuf,struct display_buffer_descriptor * desc,enum display_pixel_format pixfmt)257 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 */
mipi_dbi_reset(const struct device * dev,uint32_t delay_ms)283 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 */
mipi_dbi_release(const struct device * dev,const struct mipi_dbi_config * config)311 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 */
mipi_dbi_configure_te(const struct device * dev,uint8_t edge,uint32_t delay_us)349 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_ */
371