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 pixelrate ;
697773};
698774
699775struct gc2145_data {
@@ -1038,10 +1114,77 @@ static uint8_t gc2145_check_connection(const struct device *dev)
10381114 return 0 ;
10391115}
10401116
1117+ static int gc2145_config_csi (const struct device * dev , uint32_t pixelformat ,
1118+ uint32_t width , uint32_t height )
1119+ {
1120+ const struct gc2145_config * cfg = dev -> config ;
1121+ uint16_t fifo_full_level = width == 1600 ? 0x0001 : 0x0190 ;
1122+ uint16_t lwc = width * 2 ;
1123+ uint8_t csi_dt ;
1124+ int ret ;
1125+
1126+ switch (pixelformat ) {
1127+ case VIDEO_PIX_FMT_RGB565 :
1128+ csi_dt = VIDEO_MIPI_CSI2_DT_RGB565 ;
1129+ break ;
1130+ case VIDEO_PIX_FMT_YUYV :
1131+ csi_dt = VIDEO_MIPI_CSI2_DT_YUV422_8 ;
1132+ break ;
1133+ default :
1134+ LOG_ERR ("Unsupported pixelformat for CSI" );
1135+ return - EINVAL ;
1136+ }
1137+
1138+ /* 320x240 resolution doesn't work (yet ?) in CSI */
1139+ if (width == 320 && height == 240 ) {
1140+ LOG_ERR ("Unsupported resolution 320x240 for CSI" );
1141+ return - EINVAL ;
1142+ }
1143+
1144+ /* Apply fixed settings for MIPI-CSI. After that active page is 3 */
1145+ ret = gc2145_write_all (dev , default_mipi_csi_regs , ARRAY_SIZE (default_mipi_csi_regs ));
1146+ if (ret ) {
1147+ return ret ;
1148+ }
1149+
1150+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_LWC_LOW , lwc & 0xff );
1151+ if (ret ) {
1152+ return ret ;
1153+ }
1154+
1155+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_LWC_HIGH , lwc >> 8 );
1156+ if (ret ) {
1157+ return ret ;
1158+ }
1159+
1160+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_FULL_LVL_LOW , fifo_full_level & 0xff );
1161+ if (ret ) {
1162+ return ret ;
1163+ }
1164+
1165+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_FULL_LVL_HIGH , fifo_full_level >> 8 );
1166+ if (ret ) {
1167+ return ret ;
1168+ }
1169+
1170+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_FIFO_GATE_MODE , 0xf0 );
1171+ if (ret ) {
1172+ return ret ;
1173+ }
1174+
1175+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_MIPI_DT , csi_dt );
1176+ if (ret ) {
1177+ return ret ;
1178+ }
1179+
1180+ return gc2145_write_reg (& cfg -> i2c , 0xfe , 0x0 );
1181+ }
1182+
10411183static int gc2145_set_fmt (const struct device * dev , enum video_endpoint_id ep ,
10421184 struct video_format * fmt )
10431185{
10441186 struct gc2145_data * drv_data = dev -> data ;
1187+ const struct gc2145_config * cfg = dev -> config ;
10451188 size_t res = ARRAY_SIZE (fmts );
10461189 int ret ;
10471190
@@ -1080,6 +1223,14 @@ static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
10801223 return ret ;
10811224 }
10821225
1226+ if (cfg -> bus_type == VIDEO_BUS_TYPE_CSI2_DPHY ) {
1227+ ret = gc2145_config_csi (dev , fmt -> pixelformat , fmt -> width , fmt -> height );
1228+ if (ret < 0 ) {
1229+ LOG_ERR ("Failed to configure MIPI-CSI" );
1230+ return ret ;
1231+ }
1232+ }
1233+
10831234 return 0 ;
10841235}
10851236
@@ -1093,14 +1244,44 @@ static int gc2145_get_fmt(const struct device *dev, enum video_endpoint_id ep,
10931244 return 0 ;
10941245}
10951246
1096- static int gc2145_set_stream (const struct device * dev , bool enable )
1247+ static int gc2145_set_stream_dvp (const struct device * dev , bool enable )
10971248{
10981249 const struct gc2145_config * cfg = dev -> config ;
10991250
11001251 return enable ? gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x0f )
11011252 : gc2145_write_reg (& cfg -> i2c , 0xf2 , 0x00 );
11021253}
11031254
1255+ static int gc2145_set_stream_csi (const struct device * dev , bool enable )
1256+ {
1257+ const struct gc2145_config * cfg = dev -> config ;
1258+ int ret ;
1259+
1260+ ret = gc2145_write_reg (& cfg -> i2c , 0xfe , 0x03 );
1261+ if (ret ) {
1262+ return ret ;
1263+ }
1264+
1265+ ret = gc2145_write_reg (& cfg -> i2c , GC2145_REG_BUF_CSI2_MODE ,
1266+ enable ? GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
1267+ GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN
1268+ : 0 );
1269+ if (ret ) {
1270+ return ret ;
1271+ }
1272+
1273+ return gc2145_write_reg (& cfg -> i2c , 0xfe , 0x0 );
1274+ }
1275+
1276+ static int gc2145_set_stream (const struct device * dev , bool enable )
1277+ {
1278+ const struct gc2145_config * cfg = dev -> config ;
1279+
1280+ return cfg -> bus_type == VIDEO_BUS_TYPE_PARALLEL ?
1281+ gc2145_set_stream_dvp (dev , enable ) :
1282+ gc2145_set_stream_csi (dev , enable );
1283+ }
1284+
11041285static int gc2145_get_caps (const struct device * dev , enum video_endpoint_id ep ,
11051286 struct video_caps * caps )
11061287{
@@ -1130,6 +1311,7 @@ static DEVICE_API(video, gc2145_driver_api) = {
11301311 .set_ctrl = gc2145_set_ctrl ,
11311312};
11321313
1314+ #define GC2145_PIXEL_RATE 120000000
11331315static int gc2145_init_controls (const struct device * dev )
11341316{
11351317 int ret ;
@@ -1142,8 +1324,18 @@ static int gc2145_init_controls(const struct device *dev)
11421324 return ret ;
11431325 }
11441326
1145- return video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1146- (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1327+ ret = video_init_ctrl (& ctrls -> vflip , dev , VIDEO_CID_VFLIP ,
1328+ (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
1329+ if (ret ) {
1330+ return ret ;
1331+ }
1332+
1333+
1334+ return video_init_ctrl (& ctrls -> pixelrate , dev , VIDEO_CID_PIXEL_RATE ,
1335+ (struct video_ctrl_range ){.min64 = GC2145_PIXEL_RATE ,
1336+ .max64 = GC2145_PIXEL_RATE ,
1337+ .step64 = 1 ,
1338+ .def64 = GC2145_PIXEL_RATE });
11471339}
11481340
11491341static int gc2145_init (const struct device * dev )
@@ -1205,6 +1397,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
12051397#if DT_INST_NODE_HAS_PROP (0 , reset_gpios )
12061398 .reset_gpio = GPIO_DT_SPEC_INST_GET (0 , reset_gpios ),
12071399#endif
1400+ .bus_type = DT_PROP_OR (DT_CHILD (DT_INST_CHILD (0 , port ), endpoint ), bus_type ,
1401+ VIDEO_BUS_TYPE_PARALLEL ),
12081402};
12091403static struct gc2145_data gc2145_data_0 ;
12101404
0 commit comments