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 only supports type C modes 1 and 3
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(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_PROP(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 MIPI DBI controller configuration
117  *
118  * Configuration for MIPI DBI controller write
119  */
120 struct mipi_dbi_config {
121 	/** MIPI DBI mode (SPI 3 wire or 4 wire) */
122 	uint8_t mode;
123 	/** SPI configuration */
124 	struct spi_config config;
125 };
126 
127 
128 /** MIPI-DBI host driver API */
129 __subsystem struct mipi_dbi_driver_api {
130 	int (*command_write)(const struct device *dev,
131 			     const struct mipi_dbi_config *config, uint8_t cmd,
132 			     const uint8_t *data, size_t len);
133 	int (*command_read)(const struct device *dev,
134 			    const struct mipi_dbi_config *config, uint8_t *cmds,
135 			    size_t num_cmds, uint8_t *response, size_t len);
136 	int (*write_display)(const struct device *dev,
137 			     const struct mipi_dbi_config *config,
138 			     const uint8_t *framebuf,
139 			     struct display_buffer_descriptor *desc,
140 			     enum display_pixel_format pixfmt);
141 	int (*reset)(const struct device *dev, uint32_t delay);
142 	int (*release)(const struct device *dev,
143 		       const struct mipi_dbi_config *config);
144 };
145 
146 /**
147  * @brief Write a command to the display controller
148  *
149  * Writes a command, along with an optional data buffer to the display.
150  * If data buffer and buffer length are NULL and 0 respectively, then
151  * only a command will be sent. Note that if the SPI configuration passed
152  * to this function locks the SPI bus, it is the caller's responsibility
153  * to release it with mipi_dbi_release()
154  *
155  * @param dev mipi dbi controller
156  * @param config MIPI DBI configuration
157  * @param cmd command to write to display controller
158  * @param data optional data buffer to write after command
159  * @param len size of data buffer in bytes. Set to 0 to skip sending data.
160  * @retval 0 command write succeeded
161  * @retval -EIO I/O error
162  * @retval -ETIMEDOUT transfer timed out
163  * @retval -EBUSY controller is busy
164  * @retval -ENOSYS not implemented
165  */
mipi_dbi_command_write(const struct device * dev,const struct mipi_dbi_config * config,uint8_t cmd,const uint8_t * data,size_t len)166 static inline int mipi_dbi_command_write(const struct device *dev,
167 					 const struct mipi_dbi_config *config,
168 					 uint8_t cmd, const uint8_t *data,
169 					 size_t len)
170 {
171 	const struct mipi_dbi_driver_api *api =
172 		(const struct mipi_dbi_driver_api *)dev->api;
173 
174 	if (api->command_write == NULL) {
175 		return -ENOSYS;
176 	}
177 	return api->command_write(dev, config, cmd, data, len);
178 }
179 
180 /**
181  * @brief Read a command response from the display controller
182  *
183  * Reads a command response from the display controller.
184  *
185  * @param dev mipi dbi controller
186  * @param config MIPI DBI configuration
187  * @param cmds array of one byte commands to send to display controller
188  * @param num_cmd number of commands to write to display controller
189  * @param response response buffer, filled with display controller response
190  * @param len size of response buffer in bytes.
191  * @retval 0 command read succeeded
192  * @retval -EIO I/O error
193  * @retval -ETIMEDOUT transfer timed out
194  * @retval -EBUSY controller is busy
195  * @retval -ENOSYS not implemented
196  */
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)197 static inline int mipi_dbi_command_read(const struct device *dev,
198 					const struct mipi_dbi_config *config,
199 					uint8_t *cmds, size_t num_cmd,
200 					uint8_t *response, size_t len)
201 {
202 	const struct mipi_dbi_driver_api *api =
203 		(const struct mipi_dbi_driver_api *)dev->api;
204 
205 	if (api->command_read == NULL) {
206 		return -ENOSYS;
207 	}
208 	return api->command_read(dev, config, cmds, num_cmd, response, len);
209 }
210 
211 /**
212  * @brief Write a display buffer to the display controller.
213  *
214  * Writes a display buffer to the controller. If the controller requires
215  * a "Write memory" command before writing display data, this should be
216  * sent with @ref mipi_dbi_command_write
217  * @param dev mipi dbi controller
218  * @param config MIPI DBI configuration
219  * @param framebuf: framebuffer to write to display
220  * @param desc: descriptor of framebuffer to write. Note that the pitch must
221  *   be equal to width. "buf_size" field determines how many bytes will be
222  *   written.
223  * @param pixfmt: pixel format of framebuffer data
224  * @retval 0 buffer write succeeded.
225  * @retval -EIO I/O error
226  * @retval -ETIMEDOUT transfer timed out
227  * @retval -EBUSY controller is busy
228  * @retval -ENOSYS not implemented
229  */
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)230 static inline int mipi_dbi_write_display(const struct device *dev,
231 					 const struct mipi_dbi_config *config,
232 					 const uint8_t *framebuf,
233 					 struct display_buffer_descriptor *desc,
234 					 enum display_pixel_format pixfmt)
235 {
236 	const struct mipi_dbi_driver_api *api =
237 		(const struct mipi_dbi_driver_api *)dev->api;
238 
239 	if (api->write_display == NULL) {
240 		return -ENOSYS;
241 	}
242 	return api->write_display(dev, config, framebuf, desc, pixfmt);
243 }
244 
245 /**
246  * @brief Resets attached display controller
247  *
248  * Resets the attached display controller.
249  * @param dev mipi dbi controller
250  * @param delay duration to set reset signal for, in milliseconds
251  * @retval 0 reset succeeded
252  * @retval -EIO I/O error
253  * @retval -ENOSYS not implemented
254  * @retval -ENOTSUP not supported
255  */
mipi_dbi_reset(const struct device * dev,uint32_t delay)256 static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay)
257 {
258 	const struct mipi_dbi_driver_api *api =
259 		(const struct mipi_dbi_driver_api *)dev->api;
260 
261 	if (api->reset == NULL) {
262 		return -ENOSYS;
263 	}
264 	return api->reset(dev, delay);
265 }
266 
267 /**
268  * @brief Releases a locked MIPI DBI device.
269  *
270  * Releases a lock on a MIPI DBI device and/or the device's CS line if and
271  * only if the given config parameter was the last one to be used in any
272  * of the above functions, and if it has the SPI_LOCK_ON bit set and/or
273  * the SPI_HOLD_ON_CS bit set into its operation bits field.
274  * This lock functions exactly like the SPI lock, and can be used if the caller
275  * needs to keep CS asserted for multiple transactions, or the MIPI DBI device
276  * locked.
277  * @param dev mipi dbi controller
278  * @param config MIPI DBI configuration
279  * @retval 0 reset succeeded
280  * @retval -EIO I/O error
281  * @retval -ENOSYS not implemented
282  * @retval -ENOTSUP not supported
283  */
mipi_dbi_release(const struct device * dev,const struct mipi_dbi_config * config)284 static inline int mipi_dbi_release(const struct device *dev,
285 				   const struct mipi_dbi_config *config)
286 {
287 	const struct mipi_dbi_driver_api *api =
288 		(const struct mipi_dbi_driver_api *)dev->api;
289 
290 	if (api->release == NULL) {
291 		return -ENOSYS;
292 	}
293 	return api->release(dev, config);
294 }
295 
296 #ifdef __cplusplus
297 }
298 #endif
299 
300 /**
301  * @}
302  */
303 
304 #endif /* ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ */
305