Skip to content

Commit e0ccd1e

Browse files
author
Alain Volmat
committed
video: gc2145: add CSI mode of the GC2145 sensor
Add possibility to use the gc2145 sensor in CSI mode by adding the bus-type property in the device-tree. Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
1 parent 7e35a3f commit e0ccd1e

File tree

2 files changed

+220
-6
lines changed

2 files changed

+220
-6
lines changed

drivers/video/gc2145.c

Lines changed: 216 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
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+
684758
struct 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

694769
struct gc2145_ctrls {
695770
struct video_ctrl hflip;
696771
struct video_ctrl vflip;
772+
struct video_ctrl linkfreq;
697773
};
698774

699775
struct 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+
10411196
static 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+
11021296
static int gc2145_get_caps(const struct device *dev, struct video_caps *caps)
11031297
{
11041298
caps->format_caps = fmts;
@@ -1139,8 +1333,22 @@ 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+
ret = video_init_int_menu_ctrl(&ctrls->linkfreq, dev, VIDEO_CID_LINK_FREQ,
1343+
GC2145_640_480_LINK_FREQ_ID, gc2145_link_frequency,
1344+
ARRAY_SIZE(gc2145_link_frequency));
1345+
if (ret < 0) {
1346+
return ret;
1347+
}
1348+
1349+
ctrls->linkfreq.flags |= VIDEO_CTRL_FLAG_READ_ONLY;
1350+
1351+
return 0;
11441352
}
11451353

11461354
static int gc2145_init(const struct device *dev)
@@ -1201,6 +1409,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
12011409
#if DT_INST_NODE_HAS_PROP(0, reset_gpios)
12021410
.reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
12031411
#endif
1412+
.bus_type = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(0, 0, 0), bus_type,
1413+
VIDEO_BUS_TYPE_PARALLEL),
12041414
};
12051415
static struct gc2145_data gc2145_data_0;
12061416

dts/bindings/video/galaxycore,gc2145.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ properties:
1818
description: |
1919
The PWDN pin is asserted to power down the sensor. The sensor
2020
receives this as an active high signal
21+
22+
child-binding:
23+
child-binding:
24+
include: video-interfaces.yaml

0 commit comments

Comments
 (0)