4
4
* SPDX-License-Identifier: Apache-2.0
5
5
*/
6
6
7
- #if defined(CONFIG_DT_HAS_SOLOMON_SSD1306FB_ENABLED )
8
- #define DT_DRV_COMPAT solomon_ssd1306fb
9
- #elif defined(CONFIG_DT_HAS_SINOWEALTH_SH1106_ENABLED )
10
- #define DT_DRV_COMPAT sinowealth_sh1106
11
- #endif
12
-
13
7
#include <zephyr/logging/log.h>
14
8
LOG_MODULE_REGISTER (ssd1306 , CONFIG_DISPLAY_LOG_LEVEL );
15
9
@@ -33,14 +27,23 @@ LOG_MODULE_REGISTER(ssd1306, CONFIG_DISPLAY_LOG_LEVEL);
33
27
#define SSD1306_ADDRESSING_MODE (SSD1306_SET_MEM_ADDRESSING_HORIZONTAL)
34
28
#endif
35
29
30
+ union ssd1306_bus {
31
+ struct i2c_dt_spec i2c ;
32
+ struct spi_dt_spec spi ;
33
+ };
34
+
35
+ typedef bool (* ssd1306_bus_ready_fn )(const struct device * dev );
36
+ typedef int (* ssd1306_write_bus_fn )(const struct device * dev , uint8_t * buf , size_t len ,
37
+ bool command );
38
+ typedef const char * (* ssd1306_bus_name_fn )(const struct device * dev );
39
+
36
40
struct ssd1306_config {
37
- #if DT_INST_ON_BUS (0 , i2c )
38
- struct i2c_dt_spec bus ;
39
- #elif DT_INST_ON_BUS (0 , spi )
40
- struct spi_dt_spec bus ;
41
+ union ssd1306_bus bus ;
41
42
struct gpio_dt_spec data_cmd ;
42
- #endif
43
43
struct gpio_dt_spec reset ;
44
+ ssd1306_bus_ready_fn bus_ready ;
45
+ ssd1306_write_bus_fn write_bus ;
46
+ ssd1306_bus_name_fn bus_name ;
44
47
uint16_t height ;
45
48
uint16_t width ;
46
49
uint8_t segment_offset ;
@@ -61,41 +64,47 @@ struct ssd1306_data {
61
64
uint8_t scan_mode ;
62
65
};
63
66
64
- #if DT_INST_ON_BUS ( 0 , i2c )
65
-
66
- static inline bool ssd1306_bus_ready (const struct device * dev )
67
+ #if ( DT_HAS_COMPAT_ON_BUS_STATUS_OKAY ( solomon_ssd1306fb , i2c ) || \
68
+ DT_HAS_COMPAT_ON_BUS_STATUS_OKAY ( sinowealth_sh1106 , i2c ))
69
+ static bool ssd1306_bus_ready_i2c (const struct device * dev )
67
70
{
68
71
const struct ssd1306_config * config = dev -> config ;
69
72
70
- return device_is_ready ( config -> bus .bus );
73
+ return i2c_is_ready_dt ( & config -> bus .i2c );
71
74
}
72
75
73
- static inline int ssd1306_write_bus (const struct device * dev ,
74
- uint8_t * buf , size_t len , bool command )
76
+ static int ssd1306_write_bus_i2c (const struct device * dev , uint8_t * buf , size_t len , bool command )
75
77
{
76
78
const struct ssd1306_config * config = dev -> config ;
77
79
78
- return i2c_burst_write_dt (& config -> bus ,
80
+ return i2c_burst_write_dt (& config -> bus . i2c ,
79
81
command ? SSD1306_CONTROL_ALL_BYTES_CMD :
80
82
SSD1306_CONTROL_ALL_BYTES_DATA ,
81
83
buf , len );
82
84
}
83
85
84
- #elif DT_INST_ON_BUS (0 , spi )
86
+ static const char * ssd1306_bus_name_i2c (const struct device * dev )
87
+ {
88
+ const struct ssd1306_config * config = dev -> config ;
85
89
86
- static inline bool ssd1306_bus_ready (const struct device * dev )
90
+ return config -> bus .i2c .bus -> name ;
91
+ }
92
+ #endif
93
+
94
+ #if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY (solomon_ssd1306fb , spi ) || \
95
+ DT_HAS_COMPAT_ON_BUS_STATUS_OKAY (sinowealth_sh1106 , spi ))
96
+ static bool ssd1306_bus_ready_spi (const struct device * dev )
87
97
{
88
98
const struct ssd1306_config * config = dev -> config ;
89
99
90
100
if (gpio_pin_configure_dt (& config -> data_cmd , GPIO_OUTPUT_INACTIVE ) < 0 ) {
91
101
return false;
92
102
}
93
103
94
- return spi_is_ready_dt (& config -> bus );
104
+ return spi_is_ready_dt (& config -> bus . spi );
95
105
}
96
106
97
- static inline int ssd1306_write_bus (const struct device * dev ,
98
- uint8_t * buf , size_t len , bool command )
107
+ static int ssd1306_write_bus_spi (const struct device * dev , uint8_t * buf , size_t len , bool command )
99
108
{
100
109
const struct ssd1306_config * config = dev -> config ;
101
110
int errno ;
@@ -111,12 +120,34 @@ static inline int ssd1306_write_bus(const struct device *dev,
111
120
.count = 1
112
121
};
113
122
114
- errno = spi_write_dt (& config -> bus , & tx_bufs );
123
+ errno = spi_write_dt (& config -> bus . spi , & tx_bufs );
115
124
116
125
return errno ;
117
126
}
127
+
128
+ static const char * ssd1306_bus_name_spi (const struct device * dev )
129
+ {
130
+ const struct ssd1306_config * config = dev -> config ;
131
+
132
+ return config -> bus .spi .bus -> name ;
133
+ }
118
134
#endif
119
135
136
+ static inline bool ssd1306_bus_ready (const struct device * dev )
137
+ {
138
+ const struct ssd1306_config * config = dev -> config ;
139
+
140
+ return config -> bus_ready (dev );
141
+ }
142
+
143
+ static inline int ssd1306_write_bus (const struct device * dev , uint8_t * buf , size_t len ,
144
+ bool command )
145
+ {
146
+ const struct ssd1306_config * config = dev -> config ;
147
+
148
+ return config -> write_bus (dev , buf , len , command );
149
+ }
150
+
120
151
static inline int ssd1306_set_panel_orientation (const struct device * dev )
121
152
{
122
153
const struct ssd1306_config * config = dev -> config ;
@@ -410,7 +441,7 @@ static int ssd1306_init(const struct device *dev)
410
441
k_sleep (K_TIMEOUT_ABS_MS (config -> ready_time_ms ));
411
442
412
443
if (!ssd1306_bus_ready (dev )) {
413
- LOG_ERR ("Bus device %s not ready!" , config -> bus . bus -> name );
444
+ LOG_ERR ("Bus device %s not ready!" , config -> bus_name ( dev ) );
414
445
return - EINVAL ;
415
446
}
416
447
@@ -432,32 +463,6 @@ static int ssd1306_init(const struct device *dev)
432
463
return 0 ;
433
464
}
434
465
435
- static const struct ssd1306_config ssd1306_config = {
436
- #if DT_INST_ON_BUS (0 , i2c )
437
- .bus = I2C_DT_SPEC_INST_GET (0 ),
438
- #elif DT_INST_ON_BUS (0 , spi )
439
- .bus = SPI_DT_SPEC_INST_GET (
440
- 0 , SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET (8 ), 0 ),
441
- .data_cmd = GPIO_DT_SPEC_INST_GET (0 , data_cmd_gpios ),
442
- #endif
443
- .reset = GPIO_DT_SPEC_INST_GET_OR (0 , reset_gpios , { 0 }),
444
- .height = DT_INST_PROP (0 , height ),
445
- .width = DT_INST_PROP (0 , width ),
446
- .segment_offset = DT_INST_PROP (0 , segment_offset ),
447
- .page_offset = DT_INST_PROP (0 , page_offset ),
448
- .display_offset = DT_INST_PROP (0 , display_offset ),
449
- .multiplex_ratio = DT_INST_PROP (0 , multiplex_ratio ),
450
- .segment_remap = DT_INST_PROP (0 , segment_remap ),
451
- .com_invdir = DT_INST_PROP (0 , com_invdir ),
452
- .com_sequential = DT_INST_PROP (0 , com_sequential ),
453
- .prechargep = DT_INST_PROP (0 , prechargep ),
454
- .color_inversion = DT_INST_PROP (0 , inversion_on ),
455
- .sh1106_compatible = DT_NODE_HAS_COMPAT (0 , sinowealth_sh1106 ),
456
- .ready_time_ms = DT_INST_PROP (0 , ready_time_ms ),
457
- };
458
-
459
- static struct ssd1306_data ssd1306_driver ;
460
-
461
466
static struct display_driver_api ssd1306_driver_api = {
462
467
.blanking_on = ssd1306_suspend ,
463
468
.blanking_off = ssd1306_resume ,
@@ -471,7 +476,44 @@ static struct display_driver_api ssd1306_driver_api = {
471
476
.set_orientation = ssd1306_set_orientation ,
472
477
};
473
478
474
- DEVICE_DT_INST_DEFINE (0 , ssd1306_init , NULL ,
475
- & ssd1306_driver , & ssd1306_config ,
476
- POST_KERNEL , CONFIG_DISPLAY_INIT_PRIORITY ,
477
- & ssd1306_driver_api );
479
+ #define SSD1306_CONFIG_SPI (node_id ) \
480
+ .bus = {.spi = SPI_DT_SPEC_GET( \
481
+ node_id, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0)}, \
482
+ .bus_ready = ssd1306_bus_ready_spi, \
483
+ .write_bus = ssd1306_write_bus_spi, \
484
+ .bus_name = ssd1306_bus_name_spi, \
485
+ .data_cmd = GPIO_DT_SPEC_GET(node_id, data_cmd_gpios),
486
+
487
+ #define SSD1306_CONFIG_I2C (node_id ) \
488
+ .bus = {.i2c = I2C_DT_SPEC_GET(node_id)}, \
489
+ .bus_ready = ssd1306_bus_ready_i2c, \
490
+ .write_bus = ssd1306_write_bus_i2c, \
491
+ .bus_name = ssd1306_bus_name_i2c, \
492
+ .data_cmd = {0},
493
+
494
+ #define SSD1306_DEFINE (node_id ) \
495
+ static struct ssd1306_data data##node_id; \
496
+ static const struct ssd1306_config config##node_id = { \
497
+ .reset = GPIO_DT_SPEC_GET_OR(node_id, reset_gpios, {0}), \
498
+ .height = DT_PROP(node_id, height), \
499
+ .width = DT_PROP(node_id, width), \
500
+ .segment_offset = DT_PROP(node_id, segment_offset), \
501
+ .page_offset = DT_PROP(node_id, page_offset), \
502
+ .display_offset = DT_PROP(node_id, display_offset), \
503
+ .multiplex_ratio = DT_PROP(node_id, multiplex_ratio), \
504
+ .segment_remap = DT_PROP(node_id, segment_remap), \
505
+ .com_invdir = DT_PROP(node_id, com_invdir), \
506
+ .com_sequential = DT_PROP(node_id, com_sequential), \
507
+ .prechargep = DT_PROP(node_id, prechargep), \
508
+ .color_inversion = DT_PROP(node_id, inversion_on), \
509
+ .sh1106_compatible = DT_NODE_HAS_COMPAT(node_id, sinowealth_sh1106), \
510
+ .ready_time_ms = DT_PROP(node_id, ready_time_ms), \
511
+ COND_CODE_1(DT_ON_BUS(node_id, spi), (SSD1306_CONFIG_SPI(node_id)), \
512
+ (SSD1306_CONFIG_I2C(node_id))) \
513
+ }; \
514
+ \
515
+ DEVICE_DT_DEFINE(node_id, ssd1306_init, NULL, &data##node_id, &config##node_id, \
516
+ POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &ssd1306_driver_api);
517
+
518
+ DT_FOREACH_STATUS_OKAY (solomon_ssd1306fb , SSD1306_DEFINE )
519
+ DT_FOREACH_STATUS_OKAY (sinowealth_sh1106 , SSD1306_DEFINE )
0 commit comments