Skip to content

Commit e3376fb

Browse files
naushirpopcornmix
authored andcommitted
media: imx219: Advertise embedded data node on media pad 1
This commit updates the imx219 driver to adverise support for embedded data streams. This can then be used by the bcm2835-unicam driver, which has recently been updated to expose the embedded data stream to userland. The imx219 sensor subdevice overloads the media pad to differentiate between image stream (pad 0) and embedded data stream (pad 1) when performing the v4l2_subdev_pad_ops functions. Signed-off-by: Naushir Patuck <[email protected]> Signed-off-by: Dave Stevenson <[email protected]>
1 parent 7032a77 commit e3376fb

File tree

1 file changed

+161
-82
lines changed

1 file changed

+161
-82
lines changed

drivers/media/i2c/imx219.c

Lines changed: 161 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@
126126
#define IMX219_PIXEL_ARRAY_WIDTH 3280U
127127
#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
128128

129+
/* Embedded metadata stream structure */
130+
#define IMX219_EMBEDDED_LINE_WIDTH 16384
131+
#define IMX219_NUM_EMBEDDED_LINES 1
132+
133+
enum pad_types {
134+
IMAGE_PAD,
135+
METADATA_PAD,
136+
NUM_PADS
137+
};
138+
129139
struct imx219_reg {
130140
u16 address;
131141
u8 val;
@@ -448,7 +458,7 @@ static const struct imx219_mode supported_modes[] = {
448458

449459
struct imx219 {
450460
struct v4l2_subdev sd;
451-
struct media_pad pad;
461+
struct media_pad pad[NUM_PADS];
452462

453463
struct v4l2_mbus_framefmt fmt;
454464

@@ -598,18 +608,26 @@ static void imx219_set_default_format(struct imx219 *imx219)
598608
static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
599609
{
600610
struct imx219 *imx219 = to_imx219(sd);
601-
struct v4l2_mbus_framefmt *try_fmt =
602-
v4l2_subdev_get_try_format(sd, fh->state, 0);
611+
struct v4l2_mbus_framefmt *try_fmt_img =
612+
v4l2_subdev_get_try_format(sd, fh->state, IMAGE_PAD);
613+
struct v4l2_mbus_framefmt *try_fmt_meta =
614+
v4l2_subdev_get_try_format(sd, fh->state, METADATA_PAD);
603615
struct v4l2_rect *try_crop;
604616

605617
mutex_lock(&imx219->mutex);
606618

607619
/* Initialize try_fmt */
608-
try_fmt->width = supported_modes[0].width;
609-
try_fmt->height = supported_modes[0].height;
610-
try_fmt->code = imx219_get_format_code(imx219,
611-
MEDIA_BUS_FMT_SRGGB10_1X10);
612-
try_fmt->field = V4L2_FIELD_NONE;
620+
try_fmt_img->width = supported_modes[0].width;
621+
try_fmt_img->height = supported_modes[0].height;
622+
try_fmt_img->code = imx219_get_format_code(imx219,
623+
MEDIA_BUS_FMT_SRGGB10_1X10);
624+
try_fmt_img->field = V4L2_FIELD_NONE;
625+
626+
/* Initialize try_fmt for the embedded metadata pad */
627+
try_fmt_meta->width = IMX219_EMBEDDED_LINE_WIDTH;
628+
try_fmt_meta->height = IMX219_NUM_EMBEDDED_LINES;
629+
try_fmt_meta->code = MEDIA_BUS_FMT_SENSOR_DATA;
630+
try_fmt_meta->field = V4L2_FIELD_NONE;
613631

614632
/* Initialize try_crop rectangle. */
615633
try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
@@ -723,12 +741,22 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
723741
{
724742
struct imx219 *imx219 = to_imx219(sd);
725743

726-
if (code->index >= (ARRAY_SIZE(codes) / 4))
744+
if (code->pad >= NUM_PADS)
727745
return -EINVAL;
728746

729-
mutex_lock(&imx219->mutex);
730-
code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
731-
mutex_unlock(&imx219->mutex);
747+
if (code->pad == IMAGE_PAD) {
748+
if (code->index >= (ARRAY_SIZE(codes) / 4))
749+
return -EINVAL;
750+
751+
mutex_lock(&imx219->mutex);
752+
code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
753+
mutex_unlock(&imx219->mutex);
754+
} else {
755+
if (code->index > 0)
756+
return -EINVAL;
757+
758+
code->code = MEDIA_BUS_FMT_SENSOR_DATA;
759+
}
732760

733761
return 0;
734762
}
@@ -740,19 +768,32 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
740768
struct imx219 *imx219 = to_imx219(sd);
741769
u32 code;
742770

743-
if (fse->index >= ARRAY_SIZE(supported_modes))
771+
if (fse->pad >= NUM_PADS)
744772
return -EINVAL;
745773

746-
mutex_lock(&imx219->mutex);
747-
code = imx219_get_format_code(imx219, fse->code);
748-
mutex_unlock(&imx219->mutex);
749-
if (fse->code != code)
750-
return -EINVAL;
774+
if (fse->pad == IMAGE_PAD) {
775+
if (fse->index >= ARRAY_SIZE(supported_modes))
776+
return -EINVAL;
777+
778+
mutex_lock(&imx219->mutex);
779+
code = imx219_get_format_code(imx219, fse->code);
780+
mutex_unlock(&imx219->mutex);
781+
if (fse->code != code)
782+
return -EINVAL;
783+
784+
fse->min_width = supported_modes[fse->index].width;
785+
fse->max_width = fse->min_width;
786+
fse->min_height = supported_modes[fse->index].height;
787+
fse->max_height = fse->min_height;
788+
} else {
789+
if (fse->code != MEDIA_BUS_FMT_SENSOR_DATA || fse->index > 0)
790+
return -EINVAL;
751791

752-
fse->min_width = supported_modes[fse->index].width;
753-
fse->max_width = fse->min_width;
754-
fse->min_height = supported_modes[fse->index].height;
755-
fse->max_height = fse->min_height;
792+
fse->min_width = IMX219_EMBEDDED_LINE_WIDTH;
793+
fse->max_width = fse->min_width;
794+
fse->min_height = IMX219_NUM_EMBEDDED_LINES;
795+
fse->max_height = fse->min_height;
796+
}
756797

757798
return 0;
758799
}
@@ -767,31 +808,49 @@ static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
767808
fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
768809
}
769810

770-
static void imx219_update_pad_format(struct imx219 *imx219,
771-
const struct imx219_mode *mode,
772-
struct v4l2_subdev_format *fmt)
811+
static void imx219_update_image_pad_format(struct imx219 *imx219,
812+
const struct imx219_mode *mode,
813+
struct v4l2_subdev_format *fmt)
773814
{
774815
fmt->format.width = mode->width;
775816
fmt->format.height = mode->height;
776817
fmt->format.field = V4L2_FIELD_NONE;
777818
imx219_reset_colorspace(&fmt->format);
778819
}
779820

821+
static void imx219_update_metadata_pad_format(struct v4l2_subdev_format *fmt)
822+
{
823+
fmt->format.width = IMX219_EMBEDDED_LINE_WIDTH;
824+
fmt->format.height = IMX219_NUM_EMBEDDED_LINES;
825+
fmt->format.code = MEDIA_BUS_FMT_SENSOR_DATA;
826+
fmt->format.field = V4L2_FIELD_NONE;
827+
}
828+
780829
static int __imx219_get_pad_format(struct imx219 *imx219,
781830
struct v4l2_subdev_state *sd_state,
782831
struct v4l2_subdev_format *fmt)
783832
{
833+
if (fmt->pad >= NUM_PADS)
834+
return -EINVAL;
835+
784836
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
785837
struct v4l2_mbus_framefmt *try_fmt =
786838
v4l2_subdev_get_try_format(&imx219->sd, sd_state,
787839
fmt->pad);
788840
/* update the code which could change due to vflip or hflip: */
789-
try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
841+
try_fmt->code = fmt->pad == IMAGE_PAD ?
842+
imx219_get_format_code(imx219, try_fmt->code) :
843+
MEDIA_BUS_FMT_SENSOR_DATA;
790844
fmt->format = *try_fmt;
791845
} else {
792-
imx219_update_pad_format(imx219, imx219->mode, fmt);
793-
fmt->format.code = imx219_get_format_code(imx219,
794-
imx219->fmt.code);
846+
if (fmt->pad == IMAGE_PAD) {
847+
imx219_update_image_pad_format(imx219, imx219->mode,
848+
fmt);
849+
fmt->format.code = imx219_get_format_code(imx219,
850+
imx219->fmt.code);
851+
} else {
852+
imx219_update_metadata_pad_format(fmt);
853+
}
795854
}
796855

797856
return 0;
@@ -821,59 +880,78 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
821880
int exposure_max, exposure_def, hblank;
822881
unsigned int i;
823882

824-
mutex_lock(&imx219->mutex);
825-
826-
for (i = 0; i < ARRAY_SIZE(codes); i++)
827-
if (codes[i] == fmt->format.code)
828-
break;
829-
if (i >= ARRAY_SIZE(codes))
830-
i = 0;
883+
if (fmt->pad >= NUM_PADS)
884+
return -EINVAL;
831885

832-
/* Bayer order varies with flips */
833-
fmt->format.code = imx219_get_format_code(imx219, codes[i]);
886+
mutex_lock(&imx219->mutex);
834887

835-
mode = v4l2_find_nearest_size(supported_modes,
836-
ARRAY_SIZE(supported_modes),
837-
width, height,
838-
fmt->format.width, fmt->format.height);
839-
imx219_update_pad_format(imx219, mode, fmt);
840-
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
841-
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
842-
*framefmt = fmt->format;
843-
} else if (imx219->mode != mode ||
844-
imx219->fmt.code != fmt->format.code) {
845-
u32 prev_hts = imx219->mode->width + imx219->hblank->val;
846-
847-
imx219->fmt = fmt->format;
848-
imx219->mode = mode;
849-
/* Update limits and set FPS to default */
850-
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
851-
IMX219_VTS_MAX - mode->height, 1,
852-
mode->vts_def - mode->height);
853-
__v4l2_ctrl_s_ctrl(imx219->vblank,
854-
mode->vts_def - mode->height);
855-
/* Update max exposure while meeting expected vblanking */
856-
exposure_max = mode->vts_def - 4;
857-
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
858-
exposure_max : IMX219_EXPOSURE_DEFAULT;
859-
__v4l2_ctrl_modify_range(imx219->exposure,
860-
imx219->exposure->minimum,
861-
exposure_max, imx219->exposure->step,
862-
exposure_def);
863-
/*
864-
* Retain PPL setting from previous mode so that the
865-
* line time does not change on a mode change.
866-
* Limits have to be recomputed as the controls define
867-
* the blanking only, so PPL values need to have the
868-
* mode width subtracted.
869-
*/
870-
hblank = prev_hts - mode->width;
871-
__v4l2_ctrl_modify_range(imx219->hblank,
872-
IMX219_PPL_MIN - mode->width,
873-
IMX219_PPL_MAX - mode->width,
874-
1,
875-
IMX219_PPL_MIN - mode->width);
876-
__v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
888+
if (fmt->pad == IMAGE_PAD) {
889+
for (i = 0; i < ARRAY_SIZE(codes); i++)
890+
if (codes[i] == fmt->format.code)
891+
break;
892+
if (i >= ARRAY_SIZE(codes))
893+
i = 0;
894+
895+
/* Bayer order varies with flips */
896+
fmt->format.code = imx219_get_format_code(imx219, codes[i]);
897+
898+
mode = v4l2_find_nearest_size(supported_modes,
899+
ARRAY_SIZE(supported_modes),
900+
width, height,
901+
fmt->format.width,
902+
fmt->format.height);
903+
imx219_update_image_pad_format(imx219, mode, fmt);
904+
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
905+
framefmt = v4l2_subdev_get_try_format(sd, sd_state,
906+
fmt->pad);
907+
*framefmt = fmt->format;
908+
} else if (imx219->mode != mode ||
909+
imx219->fmt.code != fmt->format.code) {
910+
u32 prev_hts = imx219->mode->width + imx219->hblank->val;
911+
912+
imx219->fmt = fmt->format;
913+
imx219->mode = mode;
914+
/* Update limits and set FPS to default */
915+
__v4l2_ctrl_modify_range(imx219->vblank,
916+
IMX219_VBLANK_MIN,
917+
IMX219_VTS_MAX - mode->height,
918+
1,
919+
mode->vts_def - mode->height);
920+
__v4l2_ctrl_s_ctrl(imx219->vblank,
921+
mode->vts_def - mode->height);
922+
/* Update max exposure while meeting expected vblanking */
923+
exposure_max = mode->vts_def - 4;
924+
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
925+
exposure_max : IMX219_EXPOSURE_DEFAULT;
926+
__v4l2_ctrl_modify_range(imx219->exposure,
927+
imx219->exposure->minimum,
928+
exposure_max,
929+
imx219->exposure->step,
930+
exposure_def);
931+
/*
932+
* Retain PPL setting from previous mode so that the
933+
* line time does not change on a mode change.
934+
* Limits have to be recomputed as the controls define
935+
* the blanking only, so PPL values need to have the
936+
* mode width subtracted.
937+
*/
938+
hblank = prev_hts - mode->width;
939+
__v4l2_ctrl_modify_range(imx219->hblank,
940+
IMX219_PPL_MIN - mode->width,
941+
IMX219_PPL_MAX - mode->width,
942+
1,
943+
IMX219_PPL_MIN - mode->width);
944+
__v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
945+
}
946+
} else {
947+
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
948+
framefmt = v4l2_subdev_get_try_format(sd, sd_state,
949+
fmt->pad);
950+
*framefmt = fmt->format;
951+
} else {
952+
/* Only one embedded data mode is supported */
953+
imx219_update_metadata_pad_format(fmt);
954+
}
877955
}
878956

879957
mutex_unlock(&imx219->mutex);
@@ -1490,12 +1568,13 @@ static int imx219_probe(struct i2c_client *client)
14901568
imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
14911569

14921570
/* Initialize source pad */
1493-
imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
1571+
imx219->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE;
1572+
imx219->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE;
14941573

14951574
/* Initialize default format */
14961575
imx219_set_default_format(imx219);
14971576

1498-
ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
1577+
ret = media_entity_pads_init(&imx219->sd.entity, NUM_PADS, imx219->pad);
14991578
if (ret) {
15001579
dev_err(dev, "failed to init entity pads: %d\n", ret);
15011580
goto error_handler_free;

0 commit comments

Comments
 (0)