11/*
22 * Copyright 2023 NXP
3+ * Copyright 2024 TiaC Systems
34 *
45 * SPDX-License-Identifier: Apache-2.0
56 */
910#include <zephyr/drivers/mipi_dbi.h>
1011#include <zephyr/drivers/spi.h>
1112#include <zephyr/drivers/gpio.h>
13+ #include <zephyr/sys/byteorder.h>
1214
1315#include <zephyr/logging/log.h>
1416LOG_MODULE_REGISTER (mipi_dbi_spi , CONFIG_MIPI_DBI_LOG_LEVEL );
@@ -20,6 +22,8 @@ struct mipi_dbi_spi_config {
2022 const struct gpio_dt_spec cmd_data ;
2123 /* Reset GPIO */
2224 const struct gpio_dt_spec reset ;
25+ /* Minimum transfer bits */
26+ const uint8_t xfr_min_bits ;
2327};
2428
2529struct mipi_dbi_spi_data {
@@ -38,6 +42,18 @@ struct mipi_dbi_spi_data {
3842#define MIPI_DBI_SPI_READ_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_WRITE_ONLY_ABSENT) 0
3943uint32_t var = MIPI_DBI_SPI_READ_REQUIRED ;
4044
45+ /* Expands to 1 if the node does reflect the enum in `xfr-min-bits` property */
46+ #define _XFR_8BITS (n ) (DT_INST_PROP(n, xfr_min_bits) == MIPI_DBI_SPI_XFR_8BIT) |
47+ #define _XFR_16BITS (n ) (DT_INST_PROP(n, xfr_min_bits) == MIPI_DBI_SPI_XFR_16BIT) |
48+
49+ /* This macros will evaluate to 1 if any of the nodes with zephyr,mipi-dbi-spi
50+ * have the `xfr-min-bits` property to corresponding enum value. The intention
51+ * here is to allow the write helper functions to be optimized out when not all
52+ * minimum transfer bits will be needed.
53+ */
54+ #define MIPI_DBI_SPI_WRITE_8BIT_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_XFR_8BITS) 0
55+ #define MIPI_DBI_SPI_WRITE_16BIT_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_XFR_16BITS) 0
56+
4157/* In Type C mode 1 MIPI BIT communication, the 9th bit of the word
4258 * (first bit sent in each word) indicates if the word is a command or
4359 * data. Typically 0 indicates a command and 1 indicates data, but some
@@ -93,11 +109,13 @@ mipi_dbi_spi_write_helper_3wire(const struct device *dev,
93109 return ret ;
94110}
95111
112+ #if MIPI_DBI_SPI_WRITE_8BIT_REQUIRED
113+
96114static inline int
97- mipi_dbi_spi_write_helper_4wire (const struct device * dev ,
98- const struct mipi_dbi_config * dbi_config ,
99- bool cmd_present , uint8_t cmd ,
100- const uint8_t * data_buf , size_t len )
115+ mipi_dbi_spi_write_helper_4wire_8bit (const struct device * dev ,
116+ const struct mipi_dbi_config * dbi_config ,
117+ bool cmd_present , uint8_t cmd ,
118+ const uint8_t * data_buf , size_t len )
101119{
102120 const struct mipi_dbi_spi_config * config = dev -> config ;
103121 struct spi_buf buffer ;
@@ -140,11 +158,104 @@ mipi_dbi_spi_write_helper_4wire(const struct device *dev,
140158 return ret ;
141159}
142160
161+ #endif /* MIPI_DBI_SPI_WRITE_8BIT_REQUIRED */
162+
163+ #if MIPI_DBI_SPI_WRITE_16BIT_REQUIRED
164+
165+ static inline int
166+ mipi_dbi_spi_write_helper_4wire_16bit (const struct device * dev ,
167+ const struct mipi_dbi_config * dbi_config ,
168+ bool cmd_present , uint8_t cmd ,
169+ const uint8_t * data_buf , size_t len )
170+ {
171+ const struct mipi_dbi_spi_config * config = dev -> config ;
172+ struct spi_buf buffer ;
173+ struct spi_buf_set buf_set = {
174+ .buffers = & buffer ,
175+ .count = 1 ,
176+ };
177+ uint16_t data16 ;
178+ int ret = 0 ;
179+
180+ /*
181+ * 4 wire mode with toggle the command/data GPIO
182+ * to indicate if we are sending a command or data
183+ * but send 16-bit blocks (with bit stuffing).
184+ */
185+
186+ if (cmd_present ) {
187+ data16 = sys_cpu_to_be16 (cmd );
188+ buffer .buf = & data16 ;
189+ buffer .len = sizeof (data16 );
190+
191+ /* Set CD pin low for command */
192+ gpio_pin_set_dt (& config -> cmd_data , 0 );
193+ ret = spi_write (config -> spi_dev , & dbi_config -> config ,
194+ & buf_set );
195+ if (ret < 0 ) {
196+ goto out ;
197+ }
198+
199+ /* Set CD pin high for data, if there are any */
200+ if (len > 0 ) {
201+ gpio_pin_set_dt (& config -> cmd_data , 1 );
202+ }
203+
204+ /* iterate command data */
205+ for (int i = 0 ; i < len ; i ++ ) {
206+ data16 = sys_cpu_to_be16 (data_buf [i ]);
207+
208+ ret = spi_write (config -> spi_dev , & dbi_config -> config ,
209+ & buf_set );
210+ if (ret < 0 ) {
211+ goto out ;
212+ }
213+ }
214+ } else {
215+ int stuffing = len % sizeof (data16 );
216+
217+ /* Set CD pin high for data, if there are any */
218+ if (len > 0 ) {
219+ gpio_pin_set_dt (& config -> cmd_data , 1 );
220+ }
221+
222+ /* pass through generic device data */
223+ if (len - stuffing > 0 ) {
224+ buffer .buf = (void * )data_buf ;
225+ buffer .len = len - stuffing ;
226+
227+ ret = spi_write (config -> spi_dev , & dbi_config -> config ,
228+ & buf_set );
229+ if (ret < 0 ) {
230+ goto out ;
231+ }
232+ }
233+
234+ /* iterate remaining data with stuffing */
235+ for (int i = len - stuffing ; i < len ; i ++ ) {
236+ data16 = sys_cpu_to_be16 (data_buf [i ]);
237+ buffer .buf = & data16 ;
238+ buffer .len = sizeof (data16 );
239+
240+ ret = spi_write (config -> spi_dev , & dbi_config -> config ,
241+ & buf_set );
242+ if (ret < 0 ) {
243+ goto out ;
244+ }
245+ }
246+ }
247+ out :
248+ return ret ;
249+ }
250+
251+ #endif /* MIPI_DBI_SPI_WRITE_16BIT_REQUIRED */
252+
143253static int mipi_dbi_spi_write_helper (const struct device * dev ,
144254 const struct mipi_dbi_config * dbi_config ,
145255 bool cmd_present , uint8_t cmd ,
146256 const uint8_t * data_buf , size_t len )
147257{
258+ const struct mipi_dbi_spi_config * config = dev -> config ;
148259 struct mipi_dbi_spi_data * data = dev -> data ;
149260 int ret = 0 ;
150261
@@ -158,20 +269,36 @@ static int mipi_dbi_spi_write_helper(const struct device *dev,
158269 ret = mipi_dbi_spi_write_helper_3wire (dev , dbi_config ,
159270 cmd_present , cmd ,
160271 data_buf , len );
161- if (ret < 0 ) {
272+ goto out ;
273+ }
274+
275+ if (dbi_config -> mode == MIPI_DBI_MODE_SPI_4WIRE ) {
276+
277+ #if MIPI_DBI_SPI_WRITE_8BIT_REQUIRED
278+ if (config -> xfr_min_bits == MIPI_DBI_SPI_XFR_8BIT ) {
279+ ret = mipi_dbi_spi_write_helper_4wire_8bit (
280+ dev , dbi_config ,
281+ cmd_present , cmd ,
282+ data_buf , len );
162283 goto out ;
163284 }
164- } else if (dbi_config -> mode == MIPI_DBI_MODE_SPI_4WIRE ) {
165- ret = mipi_dbi_spi_write_helper_4wire (dev , dbi_config ,
166- cmd_present , cmd ,
167- data_buf , len );
168- if (ret < 0 ) {
285+ #endif
286+
287+ #if MIPI_DBI_SPI_WRITE_16BIT_REQUIRED
288+ if (config -> xfr_min_bits == MIPI_DBI_SPI_XFR_16BIT ) {
289+ ret = mipi_dbi_spi_write_helper_4wire_16bit (
290+ dev , dbi_config ,
291+ cmd_present , cmd ,
292+ data_buf , len );
169293 goto out ;
170294 }
171- } else {
172- /* Otherwise, unsupported mode */
173- ret = - ENOTSUP ;
295+ #endif
296+
174297 }
298+
299+ /* Otherwise, unsupported mode */
300+ ret = - ENOTSUP ;
301+
175302out :
176303 k_mutex_unlock (& data -> lock );
177304 return ret ;
@@ -433,6 +560,7 @@ static DEVICE_API(mipi_dbi, mipi_dbi_spi_driver_api) = {
433560 DT_INST_PHANDLE(n, spi_dev)), \
434561 .cmd_data = GPIO_DT_SPEC_INST_GET_OR(n, dc_gpios, {}), \
435562 .reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \
563+ .xfr_min_bits = DT_INST_PROP(n, xfr_min_bits) \
436564 }; \
437565 static struct mipi_dbi_spi_data mipi_dbi_spi_data_##n; \
438566 \
0 commit comments