1212#include <zephyr/drivers/video-controls.h>
1313#include <zephyr/drivers/i2c.h>
1414#include <zephyr/drivers/gpio.h>
15-
15+ #include <zephyr/dt-bindings/video/video-interfaces.h>
1616#include <zephyr/logging/log.h>
1717
1818#include "video_ctrls.h"
@@ -42,6 +42,54 @@ LOG_MODULE_REGISTER(video_gc2145, CONFIG_VIDEO_LOG_LEVEL);
4242#define GC2145_REG_SUBSAMPLE_MODE 0x9A
4343#define GC2145_SUBSAMPLE_MODE_SMOOTH 0x0E
4444
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+
4593#define UXGA_HSIZE 1600
4694#define UXGA_VSIZE 1200
4795
@@ -681,6 +729,32 @@ static const struct gc2145_reg default_regs[] = {
681729 {0x00 , 0x00 },
682730};
683731
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+
684758struct gc2145_config {
685759 struct i2c_dt_spec i2c ;
686760#if DT_INST_NODE_HAS_PROP (0 , pwdn_gpios )
@@ -689,11 +763,13 @@ struct gc2145_config {
689763#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
690764 struct gpio_dt_spec reset_gpio ;
691765#endif
766+ int bus_type ;
692767};
693768
694769struct gc2145_ctrls {
695770 struct video_ctrl hflip ;
696771 struct video_ctrl vflip ;
772+ struct video_ctrl linkfreq ;
697773};
698774
699775struct gc2145_data {
@@ -1038,9 +1114,89 @@ static uint8_t gc2145_check_connection(const struct device *dev)
10381114 return 0 ;
10391115}
10401116
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+
10411196static int gc2145_set_fmt (const struct device * dev , struct video_format * fmt )
10421197{
10431198 struct gc2145_data * drv_data = dev -> data ;
1199+ const struct gc2145_config * cfg = dev -> config ;
10441200 size_t res = ARRAY_SIZE (fmts );
10451201 int ret ;
10461202
@@ -1062,8 +1218,6 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10621218 return - ENOTSUP ;
10631219 }
10641220
1065- drv_data -> fmt = * fmt ;
1066-
10671221 /* Set output format */
10681222 ret = gc2145_set_output_format (dev , fmt -> pixelformat );
10691223 if (ret < 0 ) {
@@ -1079,6 +1233,16 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
10791233 return ret ;
10801234 }
10811235
1236+ if (cfg -> bus_type == VIDEO_BUS_TYPE_CSI2_DPHY ) {
1237+ ret = gc2145_config_csi (dev , fmt -> pixelformat , fmt -> width , fmt -> height );
1238+ if (ret < 0 ) {
1239+ LOG_ERR ("Failed to configure MIPI-CSI" );
1240+ return ret ;
1241+ }
1242+ }
1243+
1244+ drv_data -> fmt = * fmt ;
1245+
10821246 return 0 ;
10831247}
10841248
@@ -1091,14 +1255,44 @@ static int gc2145_get_fmt(const struct device *dev, struct video_format *fmt)
10911255 return 0 ;
10921256}
10931257
1094- static int gc2145_set_stream (const struct device * dev , bool enable , enum video_buf_type type )
1258+ static int gc2145_set_stream_dvp (const struct device * dev , bool enable )
10951259{
10961260 const struct gc2145_config * cfg = dev -> config ;
10971261
10981262 return enable ? gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x0f )
10991263 : gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x00 );
11001264}
11011265
1266+ static int gc2145_set_stream_csi (const struct device * dev , bool enable )
1267+ {
1268+ const struct gc2145_config * cfg = dev -> config ;
1269+ int ret ;
1270+
1271+ ret = gc2145_write_reg (& cfg -> i2c , 0xfe , 0x03 );
1272+ if (ret < 0 ) {
1273+ return ret ;
1274+ }
1275+
1276+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_BUF_CSI2_MODE ,
1277+ enable ? GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
1278+ GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN
1279+ : 0 );
1280+ if (ret < 0 ) {
1281+ return ret ;
1282+ }
1283+
1284+ return gc2145_write_reg (& cfg -> i2c , 0xfe , 0x0 );
1285+ }
1286+
1287+ static int gc2145_set_stream (const struct device * dev , bool enable , enum video_buf_type type )
1288+ {
1289+ const struct gc2145_config * cfg = dev -> config ;
1290+
1291+ return cfg -> bus_type == VIDEO_BUS_TYPE_PARALLEL ?
1292+ gc2145_set_stream_dvp (dev , enable ) :
1293+ gc2145_set_stream_csi (dev , enable );
1294+ }
1295+
11021296static int gc2145_get_caps (const struct device * dev , struct video_caps * caps )
11031297{
11041298 caps -> format_caps = fmts ;
@@ -1139,8 +1333,15 @@ static int gc2145_init_controls(const struct device *dev)
11391333 return ret ;
11401334 }
11411335
1142- return video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1143- (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1336+ ret = video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1337+ (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1338+ if (ret < 0 ) {
1339+ return ret ;
1340+ }
1341+
1342+ return video_init_int_menu_ctrl (& ctrls -> linkfreq , dev , VIDEO_CID_LINK_FREQUENCY ,
1343+ GC2145_640_480_LINK_FREQ_ID , gc2145_link_frequency ,
1344+ ARRAY_SIZE (gc2145_link_frequency ));
11441345}
11451346
11461347static int gc2145_init (const struct device * dev )
@@ -1201,6 +1402,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
12011402#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
12021403 .reset_gpio = GPIO_DT_SPEC_INST_GET (0 , reset_gpios ),
12031404#endif
1405+ .bus_type = DT_PROP_OR (DT_INST_ENDPOINT_BY_ID (0 , 0 , 0 ), bus_type ,
1406+ VIDEO_BUS_TYPE_PARALLEL ),
12041407};
12051408static struct gc2145_data gc2145_data_0 ;
12061409
0 commit comments