12
12
#include <zephyr/drivers/video-controls.h>
13
13
#include <zephyr/drivers/i2c.h>
14
14
#include <zephyr/drivers/gpio.h>
15
-
15
+ #include <zephyr/dt-bindings/video/video-interfaces.h>
16
16
#include <zephyr/logging/log.h>
17
17
18
18
#include "video_ctrls.h"
@@ -42,6 +42,54 @@ LOG_MODULE_REGISTER(video_gc2145, CONFIG_VIDEO_LOG_LEVEL);
42
42
#define GC2145_REG_SUBSAMPLE_MODE 0x9A
43
43
#define GC2145_SUBSAMPLE_MODE_SMOOTH 0x0E
44
44
45
+ /* MIPI-CSI registers - on page 3 */
46
+ #define GC2145_REG_DPHY_MODE1 0x01
47
+ #define GC2145_DPHY_MODE1_CLK_EN BIT(0)
48
+ #define GC2145_DPHY_MODE1_LANE0_EN BIT(1)
49
+ #define GC2145_DPHY_MODE1_LANE1_EN BIT(2)
50
+ #define GC2145_DPHY_MODE1_CLK_LANE_P2S_SEL BIT(7)
51
+
52
+ #define GC2145_REG_DPHY_MODE2 0x02
53
+ #define GC2145_DPHY_MODE2_CLK_DIFF (a ) ((a) & 0x07)
54
+ #define GC2145_DPHY_MODE2_LANE0_DIFF (a ) (((a) & 0x07) << 4)
55
+
56
+ #define GC2145_REG_DPHY_MODE3 0x03
57
+ #define GC2145_DPHY_MODE3_LANE1_DIFF (a ) ((a) & 0x07)
58
+ #define GC2145_DPHY_MODE3_CLK_DELAY BIT(4)
59
+ #define GC2145_DPHY_MODE3_LANE0_DELAY BIT(5)
60
+ #define GC2145_DPHY_MODE3_LANE1_DELAY BIT(6)
61
+
62
+ #define GC2145_REG_FIFO_FULL_LVL_LOW 0x04
63
+ #define GC2145_REG_FIFO_FULL_LVL_HIGH 0x05
64
+ #define GC2145_REG_FIFO_MODE 0x06
65
+ #define GC2145_FIFO_MODE_READ_GATE BIT(3)
66
+ #define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7)
67
+
68
+ #define GC2145_REG_BUF_CSI2_MODE 0x10
69
+ #define GC2145_CSI2_MODE_DOUBLE BIT(0)
70
+ #define GC2145_CSI2_MODE_RAW8 BIT(2)
71
+ #define GC2145_CSI2_MODE_MIPI_EN BIT(4)
72
+ #define GC2145_CSI2_MODE_EN BIT(7)
73
+
74
+ #define GC2145_REG_MIPI_DT 0x11
75
+ #define GC2145_REG_LWC_LOW 0x12
76
+ #define GC2145_REG_LWC_HIGH 0x13
77
+ #define GC2145_REG_DPHY_MODE 0x15
78
+ #define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4)
79
+
80
+ #define GC2145_REG_FIFO_GATE_MODE 0x17
81
+ #define GC2145_REG_T_LPX 0x21
82
+ #define GC2145_REG_T_CLK_HS_PREPARE 0x22
83
+ #define GC2145_REG_T_CLK_ZERO 0x23
84
+ #define GC2145_REG_T_CLK_PRE 0x24
85
+ #define GC2145_REG_T_CLK_POST 0x25
86
+ #define GC2145_REG_T_CLK_TRAIL 0x26
87
+ #define GC2145_REG_T_HS_EXIT 0x27
88
+ #define GC2145_REG_T_WAKEUP 0x28
89
+ #define GC2145_REG_T_HS_PREPARE 0x29
90
+ #define GC2145_REG_T_HS_ZERO 0x2a
91
+ #define GC2145_REG_T_HS_TRAIL 0x2b
92
+
45
93
#define UXGA_HSIZE 1600
46
94
#define UXGA_VSIZE 1200
47
95
@@ -681,6 +729,32 @@ static const struct gc2145_reg default_regs[] = {
681
729
{0x00 , 0x00 },
682
730
};
683
731
732
+ static const struct gc2145_reg default_mipi_csi_regs [] = {
733
+ /* Switch to page 3 */
734
+ {0xfe , 0x03 },
735
+ {GC2145_REG_DPHY_MODE1 , GC2145_DPHY_MODE1_CLK_EN |
736
+ GC2145_DPHY_MODE1_LANE0_EN | GC2145_DPHY_MODE1_LANE1_EN |
737
+ GC2145_DPHY_MODE1_CLK_LANE_P2S_SEL },
738
+ {GC2145_REG_DPHY_MODE2 , GC2145_DPHY_MODE2_CLK_DIFF (2 ) |
739
+ GC2145_DPHY_MODE2_LANE0_DIFF (2 )},
740
+ {GC2145_REG_DPHY_MODE3 , GC2145_DPHY_MODE3_LANE1_DIFF (0 ) |
741
+ GC2145_DPHY_MODE3_CLK_DELAY },
742
+ {GC2145_REG_FIFO_MODE , GC2145_FIFO_MODE_READ_GATE |
743
+ GC2145_FIFO_MODE_MIPI_CLK_MODULE },
744
+ {GC2145_REG_DPHY_MODE , GC2145_DPHY_MODE_TRIGGER_PROG },
745
+
746
+ /* Clock & Data lanes timing */
747
+ {GC2145_REG_T_LPX , 0x10 },
748
+ {GC2145_REG_T_CLK_HS_PREPARE , 0x04 },
749
+ {GC2145_REG_T_CLK_ZERO , 0x10 },
750
+ {GC2145_REG_T_CLK_PRE , 0x10 },
751
+ {GC2145_REG_T_CLK_POST , 0x10 },
752
+ {GC2145_REG_T_CLK_TRAIL , 0x05 },
753
+ {GC2145_REG_T_HS_PREPARE , 0x03 },
754
+ {GC2145_REG_T_HS_ZERO , 0x0a },
755
+ {GC2145_REG_T_HS_TRAIL , 0x06 },
756
+ };
757
+
684
758
struct gc2145_config {
685
759
struct i2c_dt_spec i2c ;
686
760
#if DT_INST_NODE_HAS_PROP (0 , pwdn_gpios )
@@ -689,11 +763,13 @@ struct gc2145_config {
689
763
#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
690
764
struct gpio_dt_spec reset_gpio ;
691
765
#endif
766
+ int bus_type ;
692
767
};
693
768
694
769
struct gc2145_ctrls {
695
770
struct video_ctrl hflip ;
696
771
struct video_ctrl vflip ;
772
+ struct video_ctrl linkfreq ;
697
773
};
698
774
699
775
struct gc2145_data {
@@ -1038,10 +1114,90 @@ static uint8_t gc2145_check_connection(const struct device *dev)
1038
1114
return 0 ;
1039
1115
}
1040
1116
1117
+ #define GC2145_640_480_LINK_FREQ 120000000
1118
+ #define GC2145_640_480_LINK_FREQ_ID 0
1119
+ #define GC2145_1600_1200_LINK_FREQ 240000000
1120
+ #define GC2145_1600_1200_LINK_FREQ_ID 1
1121
+ const int64_t gc2145_link_frequency [] = {
1122
+ GC2145_640_480_LINK_FREQ , GC2145_1600_1200_LINK_FREQ ,
1123
+ };
1124
+ static int gc2145_config_csi (const struct device * dev , uint32_t pixelformat ,
1125
+ uint32_t width , uint32_t height )
1126
+ {
1127
+ const struct gc2145_config * cfg = dev -> config ;
1128
+ struct gc2145_data * drv_data = dev -> data ;
1129
+ struct gc2145_ctrls * ctrls = & drv_data -> ctrls ;
1130
+ uint16_t fifo_full_level = width == 1600 ? 0x0001 : 0x0190 ;
1131
+ uint16_t lwc = width * video_bits_per_pixel (pixelformat ) / BITS_PER_BYTE ;
1132
+ uint8_t csi_dt ;
1133
+ int ret ;
1134
+
1135
+ switch (pixelformat ) {
1136
+ case VIDEO_PIX_FMT_RGB565 :
1137
+ csi_dt = VIDEO_MIPI_CSI2_DT_RGB565 ;
1138
+ break ;
1139
+ case VIDEO_PIX_FMT_YUYV :
1140
+ csi_dt = VIDEO_MIPI_CSI2_DT_YUV422_8 ;
1141
+ break ;
1142
+ default :
1143
+ LOG_ERR ("Unsupported pixelformat for CSI" );
1144
+ return - EINVAL ;
1145
+ }
1146
+
1147
+ /* Only VGA & UXGA work (currently) in CSI */
1148
+ if (width == RESOLUTION_VGA_W && height == RESOLUTION_VGA_H ) {
1149
+ ctrls -> linkfreq .val = GC2145_640_480_LINK_FREQ_ID ;
1150
+ } else if (width == RESOLUTION_UXGA_W && height == RESOLUTION_UXGA_H ) {
1151
+ ctrls -> linkfreq .val = GC2145_1600_1200_LINK_FREQ_ID ;
1152
+ } else {
1153
+ LOG_ERR ("Unsupported resolution 320x240 for CSI" );
1154
+ return - EINVAL ;
1155
+ }
1156
+
1157
+ /* Apply fixed settings for MIPI-CSI. After that active page is 3 */
1158
+ ret = gc2145_write_all (dev , default_mipi_csi_regs , ARRAY_SIZE (default_mipi_csi_regs ));
1159
+ if (ret < 0 ) {
1160
+ return ret ;
1161
+ }
1162
+
1163
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_LWC_LOW , lwc & 0xff );
1164
+ if (ret < 0 ) {
1165
+ return ret ;
1166
+ }
1167
+
1168
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_LWC_HIGH , lwc >> 8 );
1169
+ if (ret < 0 ) {
1170
+ return ret ;
1171
+ }
1172
+
1173
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_FULL_LVL_LOW , fifo_full_level & 0xff );
1174
+ if (ret < 0 ) {
1175
+ return ret ;
1176
+ }
1177
+
1178
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_FULL_LVL_HIGH , fifo_full_level >> 8 );
1179
+ if (ret < 0 ) {
1180
+ return ret ;
1181
+ }
1182
+
1183
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_GATE_MODE , 0xf0 );
1184
+ if (ret < 0 ) {
1185
+ return ret ;
1186
+ }
1187
+
1188
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_MIPI_DT , csi_dt );
1189
+ if (ret < 0 ) {
1190
+ return ret ;
1191
+ }
1192
+
1193
+ return gc2145_write_reg (& cfg -> i2c , 0xfe , 0x0 );
1194
+ }
1195
+
1041
1196
static int gc2145_set_fmt (const struct device * dev , enum video_endpoint_id ep ,
1042
1197
struct video_format * fmt )
1043
1198
{
1044
1199
struct gc2145_data * drv_data = dev -> data ;
1200
+ const struct gc2145_config * cfg = dev -> config ;
1045
1201
size_t res = ARRAY_SIZE (fmts );
1046
1202
int ret ;
1047
1203
@@ -1063,8 +1219,6 @@ static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
1063
1219
return - ENOTSUP ;
1064
1220
}
1065
1221
1066
- drv_data -> fmt = * fmt ;
1067
-
1068
1222
/* Set output format */
1069
1223
ret = gc2145_set_output_format (dev , fmt -> pixelformat );
1070
1224
if (ret < 0 ) {
@@ -1080,6 +1234,16 @@ static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
1080
1234
return ret ;
1081
1235
}
1082
1236
1237
+ if (cfg -> bus_type == VIDEO_BUS_TYPE_CSI2_DPHY ) {
1238
+ ret = gc2145_config_csi (dev , fmt -> pixelformat , fmt -> width , fmt -> height );
1239
+ if (ret < 0 ) {
1240
+ LOG_ERR ("Failed to configure MIPI-CSI" );
1241
+ return ret ;
1242
+ }
1243
+ }
1244
+
1245
+ drv_data -> fmt = * fmt ;
1246
+
1083
1247
return 0 ;
1084
1248
}
1085
1249
@@ -1093,14 +1257,44 @@ static int gc2145_get_fmt(const struct device *dev, enum video_endpoint_id ep,
1093
1257
return 0 ;
1094
1258
}
1095
1259
1096
- static int gc2145_set_stream (const struct device * dev , bool enable )
1260
+ static int gc2145_set_stream_dvp (const struct device * dev , bool enable )
1097
1261
{
1098
1262
const struct gc2145_config * cfg = dev -> config ;
1099
1263
1100
1264
return enable ? gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x0f )
1101
1265
: gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x00 );
1102
1266
}
1103
1267
1268
+ static int gc2145_set_stream_csi (const struct device * dev , bool enable )
1269
+ {
1270
+ const struct gc2145_config * cfg = dev -> config ;
1271
+ int ret ;
1272
+
1273
+ ret = gc2145_write_reg (& cfg -> i2c , 0xfe , 0x03 );
1274
+ if (ret < 0 ) {
1275
+ return ret ;
1276
+ }
1277
+
1278
+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_BUF_CSI2_MODE ,
1279
+ enable ? GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
1280
+ GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN
1281
+ : 0 );
1282
+ if (ret < 0 ) {
1283
+ return ret ;
1284
+ }
1285
+
1286
+ return gc2145_write_reg (& cfg -> i2c , 0xfe , 0x0 );
1287
+ }
1288
+
1289
+ static int gc2145_set_stream (const struct device * dev , bool enable )
1290
+ {
1291
+ const struct gc2145_config * cfg = dev -> config ;
1292
+
1293
+ return cfg -> bus_type == VIDEO_BUS_TYPE_PARALLEL ?
1294
+ gc2145_set_stream_dvp (dev , enable ) :
1295
+ gc2145_set_stream_csi (dev , enable );
1296
+ }
1297
+
1104
1298
static int gc2145_get_caps (const struct device * dev , enum video_endpoint_id ep ,
1105
1299
struct video_caps * caps )
1106
1300
{
@@ -1142,8 +1336,15 @@ static int gc2145_init_controls(const struct device *dev)
1142
1336
return ret ;
1143
1337
}
1144
1338
1145
- return video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1146
- (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1339
+ ret = video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1340
+ (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1341
+ if (ret < 0 ) {
1342
+ return ret ;
1343
+ }
1344
+
1345
+ return video_init_int_menu_ctrl (& ctrls -> linkfreq , dev , VIDEO_CID_LINK_FREQUENCY ,
1346
+ GC2145_640_480_LINK_FREQ_ID , gc2145_link_frequency ,
1347
+ ARRAY_SIZE (gc2145_link_frequency ));
1147
1348
}
1148
1349
1149
1350
static int gc2145_init (const struct device * dev )
@@ -1205,6 +1406,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
1205
1406
#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
1206
1407
.reset_gpio = GPIO_DT_SPEC_INST_GET (0 , reset_gpios ),
1207
1408
#endif
1409
+ .bus_type = DT_PROP_OR (DT_INST_ENDPOINT_BY_ID (0 , 0 , 0 ), bus_type ,
1410
+ VIDEO_BUS_TYPE_PARALLEL ),
1208
1411
};
1209
1412
static struct gc2145_data gc2145_data_0 ;
1210
1413
0 commit comments