Skip to content

Commit 60ab641

Browse files
bemug-st6by9
authored andcommitted
media: i2c: vd55g1: Add support for vd65g4 RGB variant
Commit e138e7f upstream The vd65g4 is the bayer version of the vd55g1. As opposed to the vd55g1, the vd65g4 does not need any patch. Check the sensor id at probe and choose to patch or not on power_on() according to it. It's bayer matrix's order is RGGB. This commit handles hflip and vflip by switching the bayer pattern accordingly. Signed-off-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
1 parent c85fc00 commit 60ab641

1 file changed

Lines changed: 167 additions & 67 deletions

File tree

drivers/media/i2c/vd55g1.c

Lines changed: 167 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@
2929

3030
/* Register Map */
3131
#define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000)
32-
#define VD55G1_MODEL_ID 0x53354731
32+
#define VD55G1_MODEL_ID_VD55G1 0x53354731 /* Mono */
33+
#define VD55G1_MODEL_ID_VD65G4 0x53354733 /* RGB */
3334
#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004)
3435
#define VD55G1_REVISION_CCB 0x2020
36+
#define VD55G1_REVISION_BAYER 0x3030
3537
#define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012)
3638
#define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000)
3739
#define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c)
3840
#define VD55G1_SYSTEM_FSM_READY_TO_BOOT 0x01
3941
#define VD55G1_SYSTEM_FSM_SW_STBY 0x02
4042
#define VD55G1_SYSTEM_FSM_STREAMING 0x03
4143
#define VD55G1_REG_BOOT CCI_REG8(0x0200)
42-
#define VD55G1_BOOT_PATCH_SETUP 2
44+
#define VD55G1_BOOT_BOOT 1
45+
#define VD55G1_BOOT_PATCH_AND_BOOT 2
4346
#define VD55G1_REG_STBY CCI_REG8(0x0201)
4447
#define VD55G1_STBY_START_STREAM 1
4548
#define VD55G1_REG_STREAMING CCI_REG8(0x0202)
@@ -132,7 +135,10 @@
132135
#define VD55G1_MIPI_RATE_MIN (250 * MEGA)
133136
#define VD55G1_MIPI_RATE_MAX (1200 * MEGA)
134137

135-
static const u8 patch_array[] = {
138+
#define VD55G1_MODEL_ID_NAME(id) \
139+
((id) == VD55G1_MODEL_ID_VD55G1 ? "vd55g1" : "vd65g4")
140+
141+
static const u8 vd55g1_patch_array[] = {
136142
0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00,
137143
0xf0, 0x01, 0x42, 0x00, 0xe6, 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
138144
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -466,22 +472,24 @@ struct vd55g1_mode {
466472
u32 height;
467473
};
468474

469-
struct vd55g1_fmt_desc {
470-
u32 code;
471-
u8 bpp;
472-
u8 data_type;
475+
static const u32 vd55g1_mbus_formats_mono[] = {
476+
MEDIA_BUS_FMT_Y8_1X8,
477+
MEDIA_BUS_FMT_Y10_1X10,
473478
};
474479

475-
static const struct vd55g1_fmt_desc vd55g1_mbus_codes[] = {
480+
/* Format order is : no flip, hflip, vflip, both */
481+
static const u32 vd55g1_mbus_formats_bayer[][4] = {
476482
{
477-
.code = MEDIA_BUS_FMT_Y8_1X8,
478-
.bpp = 8,
479-
.data_type = MIPI_CSI2_DT_RAW8,
483+
MEDIA_BUS_FMT_SRGGB8_1X8,
484+
MEDIA_BUS_FMT_SGRBG8_1X8,
485+
MEDIA_BUS_FMT_SGBRG8_1X8,
486+
MEDIA_BUS_FMT_SBGGR8_1X8,
480487
},
481488
{
482-
.code = MEDIA_BUS_FMT_Y10_1X10,
483-
.bpp = 10,
484-
.data_type = MIPI_CSI2_DT_RAW10,
489+
MEDIA_BUS_FMT_SRGGB10_1X10,
490+
MEDIA_BUS_FMT_SGRBG10_1X10,
491+
MEDIA_BUS_FMT_SGBRG10_1X10,
492+
MEDIA_BUS_FMT_SBGGR10_1X10,
485493
},
486494
};
487495

@@ -524,6 +532,7 @@ struct vd55g1_vblank_limits {
524532

525533
struct vd55g1 {
526534
struct device *dev;
535+
unsigned int id;
527536
struct v4l2_subdev sd;
528537
struct media_pad pad;
529538
struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)];
@@ -572,27 +581,78 @@ static inline struct vd55g1 *ctrl_to_vd55g1(struct v4l2_ctrl *ctrl)
572581
return to_vd55g1(sd);
573582
}
574583

575-
static const struct vd55g1_fmt_desc *vd55g1_get_fmt_desc(struct vd55g1 *sensor,
576-
u32 code)
584+
static unsigned int vd55g1_get_fmt_bpp(u32 code)
577585
{
578-
unsigned int i;
586+
switch (code) {
587+
case MEDIA_BUS_FMT_Y8_1X8:
588+
case MEDIA_BUS_FMT_SRGGB8_1X8:
589+
case MEDIA_BUS_FMT_SGRBG8_1X8:
590+
case MEDIA_BUS_FMT_SGBRG8_1X8:
591+
case MEDIA_BUS_FMT_SBGGR8_1X8:
592+
default:
593+
return 8;
594+
595+
case MEDIA_BUS_FMT_Y10_1X10:
596+
case MEDIA_BUS_FMT_SRGGB10_1X10:
597+
case MEDIA_BUS_FMT_SGRBG10_1X10:
598+
case MEDIA_BUS_FMT_SGBRG10_1X10:
599+
case MEDIA_BUS_FMT_SBGGR10_1X10:
600+
return 10;
601+
}
602+
}
603+
604+
static unsigned int vd55g1_get_fmt_data_type(u32 code)
605+
{
606+
switch (code) {
607+
case MEDIA_BUS_FMT_Y8_1X8:
608+
case MEDIA_BUS_FMT_SRGGB8_1X8:
609+
case MEDIA_BUS_FMT_SGRBG8_1X8:
610+
case MEDIA_BUS_FMT_SGBRG8_1X8:
611+
case MEDIA_BUS_FMT_SBGGR8_1X8:
612+
default:
613+
return MIPI_CSI2_DT_RAW8;
614+
615+
case MEDIA_BUS_FMT_Y10_1X10:
616+
case MEDIA_BUS_FMT_SRGGB10_1X10:
617+
case MEDIA_BUS_FMT_SGRBG10_1X10:
618+
case MEDIA_BUS_FMT_SGBRG10_1X10:
619+
case MEDIA_BUS_FMT_SBGGR10_1X10:
620+
return MIPI_CSI2_DT_RAW10;
621+
}
622+
}
623+
624+
static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code)
625+
{
626+
unsigned int i, j;
579627

580-
for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) {
581-
if (vd55g1_mbus_codes[i].code == code)
582-
return &vd55g1_mbus_codes[i];
628+
if (sensor->id == VD55G1_MODEL_ID_VD55G1)
629+
return code;
630+
631+
for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) {
632+
for (j = 0; j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); j++) {
633+
if (vd55g1_mbus_formats_bayer[i][j] == code)
634+
goto adapt_bayer_pattern;
635+
}
583636
}
637+
dev_warn(sensor->dev, "Unsupported mbus format\n");
584638

585-
/* Should never happen */
586-
dev_warn(sensor->dev, "Unsupported code %d. default to 8 bpp\n", code);
639+
return code;
640+
641+
adapt_bayer_pattern:
642+
j = 0;
643+
/* In first init_state() call, controls might not be initialized yet */
644+
if (sensor->hflip_ctrl && sensor->vflip_ctrl) {
645+
j = (sensor->hflip_ctrl->val ? 1 : 0) +
646+
(sensor->vflip_ctrl->val ? 2 : 0);
647+
}
587648

588-
return &vd55g1_mbus_codes[0];
649+
return vd55g1_mbus_formats_bayer[i][j];
589650
}
590651

591652
static s32 vd55g1_get_pixel_rate(struct vd55g1 *sensor,
592653
struct v4l2_mbus_framefmt *format)
593654
{
594-
return sensor->mipi_rate /
595-
vd55g1_get_fmt_desc(sensor, format->code)->bpp;
655+
return sensor->mipi_rate / vd55g1_get_fmt_bpp(format->code);
596656
}
597657

598658
static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor,
@@ -605,7 +665,7 @@ static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor,
605665

606666
/* MIPI required time */
607667
mipi_req_line_time = (crop->width *
608-
vd55g1_get_fmt_desc(sensor, format->code)->bpp +
668+
vd55g1_get_fmt_bpp(format->code) +
609669
VD55G1_MIPI_MARGIN) /
610670
(sensor->mipi_rate / MEGA);
611671
mipi_req_line_length = mipi_req_line_time * sensor->pixel_clock /
@@ -887,7 +947,7 @@ static void vd55g1_update_pad_fmt(struct vd55g1 *sensor,
887947
const struct vd55g1_mode *mode, u32 code,
888948
struct v4l2_mbus_framefmt *fmt)
889949
{
890-
fmt->code = code;
950+
fmt->code = vd55g1_get_fmt_code(sensor, code);
891951
fmt->width = mode->width;
892952
fmt->height = mode->height;
893953
fmt->colorspace = V4L2_COLORSPACE_RAW;
@@ -951,10 +1011,9 @@ static int vd55g1_set_framefmt(struct vd55g1 *sensor,
9511011
int ret = 0;
9521012

9531013
vd55g1_write(sensor, VD55G1_REG_FORMAT_CTRL,
954-
vd55g1_get_fmt_desc(sensor, format->code)->bpp, &ret);
1014+
vd55g1_get_fmt_bpp(format->code), &ret);
9551015
vd55g1_write(sensor, VD55G1_REG_OIF_IMG_CTRL,
956-
vd55g1_get_fmt_desc(sensor, format->code)->data_type,
957-
&ret);
1016+
vd55g1_get_fmt_data_type(format->code), &ret);
9581017

9591018
switch (crop->width / format->width) {
9601019
case 1:
@@ -1114,26 +1173,45 @@ static int vd55g1_patch(struct vd55g1 *sensor)
11141173
u64 patch;
11151174
int ret = 0;
11161175

1117-
vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR,
1118-
sizeof(patch_array), patch_array, &ret);
1119-
vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_PATCH_SETUP, &ret);
1120-
vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret);
1121-
if (ret) {
1122-
dev_err(sensor->dev, "Failed to apply patch\n");
1123-
return ret;
1124-
}
1176+
/* vd55g1 needs a patch while vd65g4 does not */
1177+
if (sensor->id == VD55G1_MODEL_ID_VD55G1) {
1178+
vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR,
1179+
sizeof(vd55g1_patch_array),
1180+
vd55g1_patch_array, &ret);
1181+
vd55g1_write(sensor, VD55G1_REG_BOOT,
1182+
VD55G1_BOOT_PATCH_AND_BOOT, &ret);
1183+
vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret);
1184+
if (ret) {
1185+
dev_err(sensor->dev, "Failed to apply patch\n");
1186+
return ret;
1187+
}
11251188

1126-
vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret);
1127-
if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) +
1128-
VD55G1_FWPATCH_REVISION_MINOR) {
1129-
dev_err(sensor->dev, "Bad patch version expected %d.%d got %d.%d\n",
1130-
VD55G1_FWPATCH_REVISION_MAJOR,
1131-
VD55G1_FWPATCH_REVISION_MINOR,
1189+
vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret);
1190+
if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) +
1191+
VD55G1_FWPATCH_REVISION_MINOR) {
1192+
dev_err(sensor->dev, "Bad patch version expected %d.%d got %d.%d\n",
1193+
VD55G1_FWPATCH_REVISION_MAJOR,
1194+
VD55G1_FWPATCH_REVISION_MINOR,
1195+
(u8)(patch >> 8), (u8)(patch & 0xff));
1196+
return -ENODEV;
1197+
}
1198+
dev_dbg(sensor->dev, "patch %d.%d applied\n",
11321199
(u8)(patch >> 8), (u8)(patch & 0xff));
1133-
return -ENODEV;
1200+
1201+
} else {
1202+
vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_BOOT, &ret);
1203+
vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret);
1204+
if (ret) {
1205+
dev_err(sensor->dev, "Failed to boot\n");
1206+
return ret;
1207+
}
1208+
}
1209+
1210+
ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL);
1211+
if (ret) {
1212+
dev_err(sensor->dev, "Sensor waiting after boot failed\n");
1213+
return ret;
11341214
}
1135-
dev_dbg(sensor->dev, "patch %d.%d applied\n",
1136-
(u8)(patch >> 8), (u8)(patch & 0xff));
11371215

11381216
return 0;
11391217
}
@@ -1165,10 +1243,19 @@ static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd,
11651243
struct v4l2_subdev_state *sd_state,
11661244
struct v4l2_subdev_mbus_code_enum *code)
11671245
{
1168-
if (code->index >= ARRAY_SIZE(vd55g1_mbus_codes))
1169-
return -EINVAL;
1246+
struct vd55g1 *sensor = to_vd55g1(sd);
1247+
u32 base_code;
11701248

1171-
code->code = vd55g1_mbus_codes[code->index].code;
1249+
if (sensor->id == VD55G1_MODEL_ID_VD55G1) {
1250+
if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_mono))
1251+
return -EINVAL;
1252+
base_code = vd55g1_mbus_formats_mono[code->index];
1253+
} else {
1254+
if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_bayer))
1255+
return -EINVAL;
1256+
base_code = vd55g1_mbus_formats_bayer[code->index][0];
1257+
}
1258+
code->code = vd55g1_get_fmt_code(sensor, base_code);
11721259

11731260
return 0;
11741261
}
@@ -1275,7 +1362,7 @@ static int vd55g1_init_state(struct v4l2_subdev *sd,
12751362
return ret;
12761363

12771364
vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF],
1278-
vd55g1_mbus_codes[VD55G1_MBUS_CODE_DEF].code,
1365+
vd55g1_get_fmt_code(sensor, VD55G1_MBUS_CODE_DEF),
12791366
&fmt.format);
12801367

12811368
return vd55g1_set_pad_fmt(sd, sd_state, &fmt);
@@ -1285,9 +1372,16 @@ static int vd55g1_enum_frame_size(struct v4l2_subdev *sd,
12851372
struct v4l2_subdev_state *sd_state,
12861373
struct v4l2_subdev_frame_size_enum *fse)
12871374
{
1375+
struct vd55g1 *sensor = to_vd55g1(sd);
1376+
u32 code;
1377+
12881378
if (fse->index >= ARRAY_SIZE(vd55g1_supported_modes))
12891379
return -EINVAL;
12901380

1381+
code = vd55g1_get_fmt_code(sensor, fse->code);
1382+
if (fse->code != code)
1383+
return -EINVAL;
1384+
12911385
fse->min_width = vd55g1_supported_modes[fse->index].width;
12921386
fse->max_width = fse->min_width;
12931387
fse->min_height = vd55g1_supported_modes[fse->index].height;
@@ -1463,8 +1557,12 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor)
14631557
/* Flip cluster */
14641558
sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
14651559
0, 1, 1, 0);
1560+
if (sensor->hflip_ctrl)
1561+
sensor->hflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
14661562
sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
14671563
0, 1, 1, 0);
1564+
if (sensor->vflip_ctrl)
1565+
sensor->vflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
14681566
v4l2_ctrl_cluster(2, &sensor->hflip_ctrl);
14691567

14701568
/* Exposition cluster */
@@ -1548,26 +1646,34 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor)
15481646

15491647
static int vd55g1_detect(struct vd55g1 *sensor)
15501648
{
1551-
u64 device_rev;
1552-
u64 id;
1649+
unsigned int dt_id = (uintptr_t)device_get_match_data(sensor->dev);
1650+
u64 rev, id;
15531651
int ret;
15541652

15551653
ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL);
15561654
if (ret)
15571655
return ret;
15581656

1559-
if (id != VD55G1_MODEL_ID) {
1560-
dev_warn(sensor->dev, "Unsupported sensor id %x\n", (u32)id);
1657+
if (id != VD55G1_MODEL_ID_VD55G1 && id != VD55G1_MODEL_ID_VD65G4) {
1658+
dev_warn(sensor->dev, "Unsupported sensor id 0x%x\n",
1659+
(u32)id);
1660+
return -ENODEV;
1661+
}
1662+
if (id != dt_id) {
1663+
dev_err(sensor->dev, "Probed sensor %s and device tree definition (%s) mismatch",
1664+
VD55G1_MODEL_ID_NAME(id), VD55G1_MODEL_ID_NAME(dt_id));
15611665
return -ENODEV;
15621666
}
1667+
sensor->id = id;
15631668

1564-
ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &device_rev, NULL);
1669+
ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &rev, NULL);
15651670
if (ret)
15661671
return ret;
15671672

1568-
if (device_rev != VD55G1_REVISION_CCB) {
1569-
dev_err(sensor->dev, "Unsupported sensor revision (0x%x)\n",
1570-
(u16)device_rev);
1673+
if ((id == VD55G1_MODEL_ID_VD55G1 && rev != VD55G1_REVISION_CCB) &&
1674+
(id == VD55G1_MODEL_ID_VD65G4 && rev != VD55G1_REVISION_BAYER)) {
1675+
dev_err(sensor->dev, "Unsupported sensor revision 0x%x for sensor %s\n",
1676+
(u16)rev, VD55G1_MODEL_ID_NAME(id));
15711677
return -ENODEV;
15721678
}
15731679

@@ -1616,13 +1722,6 @@ static int vd55g1_power_on(struct device *dev)
16161722
goto disable_clock;
16171723
}
16181724

1619-
ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL);
1620-
if (ret) {
1621-
dev_err(dev, "Sensor waiting after patch failed %d\n",
1622-
ret);
1623-
goto disable_clock;
1624-
}
1625-
16261725
return 0;
16271726

16281727
disable_clock:
@@ -1934,7 +2033,8 @@ static void vd55g1_remove(struct i2c_client *client)
19342033
}
19352034

19362035
static const struct of_device_id vd55g1_dt_ids[] = {
1937-
{ .compatible = "st,vd55g1" },
2036+
{ .compatible = "st,vd55g1", .data = (void *)VD55G1_MODEL_ID_VD55G1 },
2037+
{ .compatible = "st,vd65g4", .data = (void *)VD55G1_MODEL_ID_VD65G4 },
19382038
{ /* sentinel */ }
19392039
};
19402040
MODULE_DEVICE_TABLE(of, vd55g1_dt_ids);

0 commit comments

Comments
 (0)