Skip to content

Commit 4932c5b

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 2d2884a commit 4932c5b

File tree

2 files changed

+211
-4
lines changed

2 files changed

+211
-4
lines changed

drivers/video/gc2145.c

Lines changed: 207 additions & 4 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,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+
10411196
static 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+
11041298
static 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

11491350
static 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
};
12091412
static struct gc2145_data gc2145_data_0;
12101413

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)