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