Skip to content

Commit a1814bb

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 dbefac0 commit a1814bb

File tree

2 files changed

+208
-4
lines changed

2 files changed

+208
-4
lines changed

drivers/video/gc2145.c

Lines changed: 204 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 pixelrate;
697773
};
698774

699775
struct gc2145_data {
@@ -1038,10 +1114,85 @@ static uint8_t gc2145_check_connection(const struct device *dev)
10381114
return 0;
10391115
}
10401116

1117+
#define GC2145_640_480_PIXEL_RATE 30000000
1118+
#define GC2145_1600_1200_PIXEL_RATE 60000000
1119+
static int gc2145_config_csi(const struct device *dev, uint32_t pixelformat,
1120+
uint32_t width, uint32_t height)
1121+
{
1122+
const struct gc2145_config *cfg = dev->config;
1123+
struct gc2145_data *drv_data = dev->data;
1124+
struct gc2145_ctrls *ctrls = &drv_data->ctrls;
1125+
uint16_t fifo_full_level = width == 1600 ? 0x0001 : 0x0190;
1126+
uint16_t lwc = width * 2;
1127+
uint8_t csi_dt;
1128+
int ret;
1129+
1130+
switch (pixelformat) {
1131+
case VIDEO_PIX_FMT_RGB565:
1132+
csi_dt = VIDEO_MIPI_CSI2_DT_RGB565;
1133+
break;
1134+
case VIDEO_PIX_FMT_YUYV:
1135+
csi_dt = VIDEO_MIPI_CSI2_DT_YUV422_8;
1136+
break;
1137+
default:
1138+
LOG_ERR("Unsupported pixelformat for CSI");
1139+
return -EINVAL;
1140+
}
1141+
1142+
/* Only VGA & UXGA work (currently) in CSI */
1143+
if (width == RESOLUTION_VGA_W && height == RESOLUTION_VGA_H) {
1144+
ctrls->pixelrate.val64 = GC2145_640_480_PIXEL_RATE;
1145+
} else if (width == RESOLUTION_UXGA_W && height == RESOLUTION_UXGA_H) {
1146+
ctrls->pixelrate.val64 = GC2145_1600_1200_PIXEL_RATE;
1147+
} else {
1148+
LOG_ERR("Unsupported resolution 320x240 for CSI");
1149+
return -EINVAL;
1150+
}
1151+
1152+
/* Apply fixed settings for MIPI-CSI. After that active page is 3 */
1153+
ret = gc2145_write_all(dev, default_mipi_csi_regs, ARRAY_SIZE(default_mipi_csi_regs));
1154+
if (ret < 0) {
1155+
return ret;
1156+
}
1157+
1158+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_LWC_LOW, lwc & 0xff);
1159+
if (ret < 0) {
1160+
return ret;
1161+
}
1162+
1163+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_LWC_HIGH, lwc >> 8);
1164+
if (ret < 0) {
1165+
return ret;
1166+
}
1167+
1168+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_FIFO_FULL_LVL_LOW, fifo_full_level & 0xff);
1169+
if (ret < 0) {
1170+
return ret;
1171+
}
1172+
1173+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_FIFO_FULL_LVL_HIGH, fifo_full_level >> 8);
1174+
if (ret < 0) {
1175+
return ret;
1176+
}
1177+
1178+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_FIFO_GATE_MODE, 0xf0);
1179+
if (ret < 0) {
1180+
return ret;
1181+
}
1182+
1183+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_MIPI_DT, csi_dt);
1184+
if (ret < 0) {
1185+
return ret;
1186+
}
1187+
1188+
return gc2145_write_reg(&cfg->i2c, 0xfe, 0x0);
1189+
}
1190+
10411191
static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
10421192
struct video_format *fmt)
10431193
{
10441194
struct gc2145_data *drv_data = dev->data;
1195+
const struct gc2145_config *cfg = dev->config;
10451196
size_t res = ARRAY_SIZE(fmts);
10461197
int ret;
10471198

@@ -1080,6 +1231,14 @@ static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
10801231
return ret;
10811232
}
10821233

1234+
if (cfg->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
1235+
ret = gc2145_config_csi(dev, fmt->pixelformat, fmt->width, fmt->height);
1236+
if (ret < 0) {
1237+
LOG_ERR("Failed to configure MIPI-CSI");
1238+
return ret;
1239+
}
1240+
}
1241+
10831242
return 0;
10841243
}
10851244

@@ -1093,14 +1252,44 @@ static int gc2145_get_fmt(const struct device *dev, enum video_endpoint_id ep,
10931252
return 0;
10941253
}
10951254

1096-
static int gc2145_set_stream(const struct device *dev, bool enable)
1255+
static int gc2145_set_stream_dvp(const struct device *dev, bool enable)
10971256
{
10981257
const struct gc2145_config *cfg = dev->config;
10991258

11001259
return enable ? gc2145_write_reg(&cfg->i2c, 0xf2, 0x0f)
11011260
: gc2145_write_reg(&cfg->i2c, 0xf2, 0x00);
11021261
}
11031262

1263+
static int gc2145_set_stream_csi(const struct device *dev, bool enable)
1264+
{
1265+
const struct gc2145_config *cfg = dev->config;
1266+
int ret;
1267+
1268+
ret = gc2145_write_reg(&cfg->i2c, 0xfe, 0x03);
1269+
if (ret < 0) {
1270+
return ret;
1271+
}
1272+
1273+
ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_BUF_CSI2_MODE,
1274+
enable ? GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
1275+
GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN
1276+
: 0);
1277+
if (ret < 0) {
1278+
return ret;
1279+
}
1280+
1281+
return gc2145_write_reg(&cfg->i2c, 0xfe, 0x0);
1282+
}
1283+
1284+
static int gc2145_set_stream(const struct device *dev, bool enable)
1285+
{
1286+
const struct gc2145_config *cfg = dev->config;
1287+
1288+
return cfg->bus_type == VIDEO_BUS_TYPE_PARALLEL ?
1289+
gc2145_set_stream_dvp(dev, enable) :
1290+
gc2145_set_stream_csi(dev, enable);
1291+
}
1292+
11041293
static int gc2145_get_caps(const struct device *dev, enum video_endpoint_id ep,
11051294
struct video_caps *caps)
11061295
{
@@ -1142,8 +1331,17 @@ static int gc2145_init_controls(const struct device *dev)
11421331
return ret;
11431332
}
11441333

1145-
return video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP,
1146-
(struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0});
1334+
ret = video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP,
1335+
(struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0});
1336+
if (ret < 0) {
1337+
return ret;
1338+
}
1339+
1340+
return video_init_ctrl(&ctrls->pixelrate, dev, VIDEO_CID_PIXEL_RATE,
1341+
(struct video_ctrl_range){.min64 = GC2145_640_480_PIXEL_RATE,
1342+
.max64 = GC2145_1600_1200_PIXEL_RATE,
1343+
.step64 = 1,
1344+
.def64 = GC2145_640_480_PIXEL_RATE});
11471345
}
11481346

11491347
static int gc2145_init(const struct device *dev)
@@ -1205,6 +1403,8 @@ static const struct gc2145_config gc2145_cfg_0 = {
12051403
#if DT_INST_NODE_HAS_PROP(0, reset_gpios)
12061404
.reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
12071405
#endif
1406+
.bus_type = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(0, 0, 0), bus_type,
1407+
VIDEO_BUS_TYPE_PARALLEL),
12081408
};
12091409
static struct gc2145_data gc2145_data_0;
12101410

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)