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,10 +1114,90 @@ 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 , enum video_endpoint_id ep ,
10421197 struct video_format * fmt )
10431198{
10441199 struct gc2145_data * drv_data = dev -> data ;
1200+ const struct gc2145_config * cfg = dev -> config ;
10451201 size_t res = ARRAY_SIZE (fmts );
10461202 int ret ;
10471203
@@ -1080,6 +1236,14 @@ static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
10801236 return ret ;
10811237 }
10821238
1239+ if (cfg -> bus_type == VIDEO_BUS_TYPE_CSI2_DPHY ) {
1240+ ret = gc2145_config_csi (dev , fmt -> pixelformat , fmt -> width , fmt -> height );
1241+ if (ret < 0 ) {
1242+ LOG_ERR ("Failed to configure MIPI-CSI" );
1243+ return ret ;
1244+ }
1245+ }
1246+
10831247 return 0 ;
10841248}
10851249
@@ -1093,14 +1257,44 @@ static int gc2145_get_fmt(const struct device *dev, enum video_endpoint_id ep,
10931257 return 0 ;
10941258}
10951259
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 )
10971261{
10981262 const struct gc2145_config * cfg = dev -> config ;
10991263
11001264 return enable ? gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x0f )
11011265 : gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x00 );
11021266}
11031267
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+
11041298static int gc2145_get_caps (const struct device * dev , enum video_endpoint_id ep ,
11051299 struct video_caps * caps )
11061300{
@@ -1142,8 +1336,15 @@ static int gc2145_init_controls(const struct device *dev)
11421336 return ret ;
11431337 }
11441338
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 ));
11471348}
11481349
11491350static int gc2145_init (const struct device * dev )
@@ -1205,6 +1406,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
12051406#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
12061407 .reset_gpio = GPIO_DT_SPEC_INST_GET (0 , reset_gpios ),
12071408#endif
1409+ .bus_type = DT_PROP_OR (DT_INST_ENDPOINT_BY_ID (0 , 0 , 0 ), bus_type ,
1410+ VIDEO_BUS_TYPE_PARALLEL ),
12081411};
12091412static struct gc2145_data gc2145_data_0 ;
12101413
0 commit comments