1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * vimc-sensor.c Virtual Media Controller Driver
5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
8 #include <linux/v4l2-mediabus.h>
9 #include <linux/vmalloc.h>
10 #include <media/v4l2-ctrls.h>
11 #include <media/v4l2-event.h>
12 #include <media/v4l2-subdev.h>
13 #include <media/tpg/v4l2-tpg.h>
15 #include "vimc-common.h"
17 struct vimc_sen_device
{
18 struct vimc_ent_device ved
;
19 struct v4l2_subdev sd
;
22 /* The active format */
23 struct v4l2_mbus_framefmt mbus_format
;
24 struct v4l2_ctrl_handler hdl
;
28 static const struct v4l2_mbus_framefmt fmt_default
= {
31 .code
= MEDIA_BUS_FMT_RGB888_1X24
,
32 .field
= V4L2_FIELD_NONE
,
33 .colorspace
= V4L2_COLORSPACE_DEFAULT
,
36 static int vimc_sen_init_cfg(struct v4l2_subdev
*sd
,
37 struct v4l2_subdev_pad_config
*cfg
)
41 for (i
= 0; i
< sd
->entity
.num_pads
; i
++) {
42 struct v4l2_mbus_framefmt
*mf
;
44 mf
= v4l2_subdev_get_try_format(sd
, cfg
, i
);
51 static int vimc_sen_enum_mbus_code(struct v4l2_subdev
*sd
,
52 struct v4l2_subdev_pad_config
*cfg
,
53 struct v4l2_subdev_mbus_code_enum
*code
)
55 const struct vimc_pix_map
*vpix
= vimc_pix_map_by_index(code
->index
);
60 code
->code
= vpix
->code
;
65 static int vimc_sen_enum_frame_size(struct v4l2_subdev
*sd
,
66 struct v4l2_subdev_pad_config
*cfg
,
67 struct v4l2_subdev_frame_size_enum
*fse
)
69 const struct vimc_pix_map
*vpix
;
74 /* Only accept code in the pix map table */
75 vpix
= vimc_pix_map_by_code(fse
->code
);
79 fse
->min_width
= VIMC_FRAME_MIN_WIDTH
;
80 fse
->max_width
= VIMC_FRAME_MAX_WIDTH
;
81 fse
->min_height
= VIMC_FRAME_MIN_HEIGHT
;
82 fse
->max_height
= VIMC_FRAME_MAX_HEIGHT
;
87 static int vimc_sen_get_fmt(struct v4l2_subdev
*sd
,
88 struct v4l2_subdev_pad_config
*cfg
,
89 struct v4l2_subdev_format
*fmt
)
91 struct vimc_sen_device
*vsen
=
92 container_of(sd
, struct vimc_sen_device
, sd
);
94 fmt
->format
= fmt
->which
== V4L2_SUBDEV_FORMAT_TRY
?
95 *v4l2_subdev_get_try_format(sd
, cfg
, fmt
->pad
) :
101 static void vimc_sen_tpg_s_format(struct vimc_sen_device
*vsen
)
103 const struct vimc_pix_map
*vpix
=
104 vimc_pix_map_by_code(vsen
->mbus_format
.code
);
106 tpg_reset_source(&vsen
->tpg
, vsen
->mbus_format
.width
,
107 vsen
->mbus_format
.height
, vsen
->mbus_format
.field
);
108 tpg_s_bytesperline(&vsen
->tpg
, 0, vsen
->mbus_format
.width
* vpix
->bpp
);
109 tpg_s_buf_height(&vsen
->tpg
, vsen
->mbus_format
.height
);
110 tpg_s_fourcc(&vsen
->tpg
, vpix
->pixelformat
);
111 /* TODO: add support for V4L2_FIELD_ALTERNATE */
112 tpg_s_field(&vsen
->tpg
, vsen
->mbus_format
.field
, false);
113 tpg_s_colorspace(&vsen
->tpg
, vsen
->mbus_format
.colorspace
);
114 tpg_s_ycbcr_enc(&vsen
->tpg
, vsen
->mbus_format
.ycbcr_enc
);
115 tpg_s_quantization(&vsen
->tpg
, vsen
->mbus_format
.quantization
);
116 tpg_s_xfer_func(&vsen
->tpg
, vsen
->mbus_format
.xfer_func
);
119 static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt
*fmt
)
121 const struct vimc_pix_map
*vpix
;
123 /* Only accept code in the pix map table */
124 vpix
= vimc_pix_map_by_code(fmt
->code
);
126 fmt
->code
= fmt_default
.code
;
128 fmt
->width
= clamp_t(u32
, fmt
->width
, VIMC_FRAME_MIN_WIDTH
,
129 VIMC_FRAME_MAX_WIDTH
) & ~1;
130 fmt
->height
= clamp_t(u32
, fmt
->height
, VIMC_FRAME_MIN_HEIGHT
,
131 VIMC_FRAME_MAX_HEIGHT
) & ~1;
133 /* TODO: add support for V4L2_FIELD_ALTERNATE */
134 if (fmt
->field
== V4L2_FIELD_ANY
|| fmt
->field
== V4L2_FIELD_ALTERNATE
)
135 fmt
->field
= fmt_default
.field
;
137 vimc_colorimetry_clamp(fmt
);
140 static int vimc_sen_set_fmt(struct v4l2_subdev
*sd
,
141 struct v4l2_subdev_pad_config
*cfg
,
142 struct v4l2_subdev_format
*fmt
)
144 struct vimc_sen_device
*vsen
= v4l2_get_subdevdata(sd
);
145 struct v4l2_mbus_framefmt
*mf
;
147 if (fmt
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
) {
148 /* Do not change the format while stream is on */
152 mf
= &vsen
->mbus_format
;
154 mf
= v4l2_subdev_get_try_format(sd
, cfg
, fmt
->pad
);
157 /* Set the new format */
158 vimc_sen_adjust_fmt(&fmt
->format
);
160 dev_dbg(vsen
->ved
.dev
, "%s: format update: "
161 "old:%dx%d (0x%x, %d, %d, %d, %d) "
162 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen
->sd
.name
,
164 mf
->width
, mf
->height
, mf
->code
,
165 mf
->colorspace
, mf
->quantization
,
166 mf
->xfer_func
, mf
->ycbcr_enc
,
168 fmt
->format
.width
, fmt
->format
.height
, fmt
->format
.code
,
169 fmt
->format
.colorspace
, fmt
->format
.quantization
,
170 fmt
->format
.xfer_func
, fmt
->format
.ycbcr_enc
);
177 static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops
= {
178 .init_cfg
= vimc_sen_init_cfg
,
179 .enum_mbus_code
= vimc_sen_enum_mbus_code
,
180 .enum_frame_size
= vimc_sen_enum_frame_size
,
181 .get_fmt
= vimc_sen_get_fmt
,
182 .set_fmt
= vimc_sen_set_fmt
,
185 static void *vimc_sen_process_frame(struct vimc_ent_device
*ved
,
186 const void *sink_frame
)
188 struct vimc_sen_device
*vsen
= container_of(ved
, struct vimc_sen_device
,
191 tpg_fill_plane_buffer(&vsen
->tpg
, 0, 0, vsen
->frame
);
195 static int vimc_sen_s_stream(struct v4l2_subdev
*sd
, int enable
)
197 struct vimc_sen_device
*vsen
=
198 container_of(sd
, struct vimc_sen_device
, sd
);
201 const struct vimc_pix_map
*vpix
;
202 unsigned int frame_size
;
204 /* Calculate the frame size */
205 vpix
= vimc_pix_map_by_code(vsen
->mbus_format
.code
);
206 frame_size
= vsen
->mbus_format
.width
* vpix
->bpp
*
207 vsen
->mbus_format
.height
;
210 * Allocate the frame buffer. Use vmalloc to be able to
211 * allocate a large amount of memory
213 vsen
->frame
= vmalloc(frame_size
);
217 /* configure the test pattern generator */
218 vimc_sen_tpg_s_format(vsen
);
229 static const struct v4l2_subdev_core_ops vimc_sen_core_ops
= {
230 .log_status
= v4l2_ctrl_subdev_log_status
,
231 .subscribe_event
= v4l2_ctrl_subdev_subscribe_event
,
232 .unsubscribe_event
= v4l2_event_subdev_unsubscribe
,
235 static const struct v4l2_subdev_video_ops vimc_sen_video_ops
= {
236 .s_stream
= vimc_sen_s_stream
,
239 static const struct v4l2_subdev_ops vimc_sen_ops
= {
240 .core
= &vimc_sen_core_ops
,
241 .pad
= &vimc_sen_pad_ops
,
242 .video
= &vimc_sen_video_ops
,
245 static int vimc_sen_s_ctrl(struct v4l2_ctrl
*ctrl
)
247 struct vimc_sen_device
*vsen
=
248 container_of(ctrl
->handler
, struct vimc_sen_device
, hdl
);
251 case VIMC_CID_TEST_PATTERN
:
252 tpg_s_pattern(&vsen
->tpg
, ctrl
->val
);
255 tpg_s_hflip(&vsen
->tpg
, ctrl
->val
);
258 tpg_s_vflip(&vsen
->tpg
, ctrl
->val
);
260 case V4L2_CID_BRIGHTNESS
:
261 tpg_s_brightness(&vsen
->tpg
, ctrl
->val
);
263 case V4L2_CID_CONTRAST
:
264 tpg_s_contrast(&vsen
->tpg
, ctrl
->val
);
267 tpg_s_hue(&vsen
->tpg
, ctrl
->val
);
269 case V4L2_CID_SATURATION
:
270 tpg_s_saturation(&vsen
->tpg
, ctrl
->val
);
278 static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops
= {
279 .s_ctrl
= vimc_sen_s_ctrl
,
282 static void vimc_sen_release(struct v4l2_subdev
*sd
)
284 struct vimc_sen_device
*vsen
=
285 container_of(sd
, struct vimc_sen_device
, sd
);
287 v4l2_ctrl_handler_free(&vsen
->hdl
);
288 tpg_free(&vsen
->tpg
);
289 media_entity_cleanup(vsen
->ved
.ent
);
293 static const struct v4l2_subdev_internal_ops vimc_sen_int_ops
= {
294 .release
= vimc_sen_release
,
297 void vimc_sen_rm(struct vimc_device
*vimc
, struct vimc_ent_device
*ved
)
299 struct vimc_sen_device
*vsen
;
301 vsen
= container_of(ved
, struct vimc_sen_device
, ved
);
302 v4l2_device_unregister_subdev(&vsen
->sd
);
305 /* Image Processing Controls */
306 static const struct v4l2_ctrl_config vimc_sen_ctrl_class
= {
307 .flags
= V4L2_CTRL_FLAG_READ_ONLY
| V4L2_CTRL_FLAG_WRITE_ONLY
,
308 .id
= VIMC_CID_VIMC_CLASS
,
309 .name
= "VIMC Controls",
310 .type
= V4L2_CTRL_TYPE_CTRL_CLASS
,
313 static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern
= {
314 .ops
= &vimc_sen_ctrl_ops
,
315 .id
= VIMC_CID_TEST_PATTERN
,
316 .name
= "Test Pattern",
317 .type
= V4L2_CTRL_TYPE_MENU
,
318 .max
= TPG_PAT_NOISE
,
319 .qmenu
= tpg_pattern_strings
,
322 struct vimc_ent_device
*vimc_sen_add(struct vimc_device
*vimc
,
323 const char *vcfg_name
)
325 struct v4l2_device
*v4l2_dev
= &vimc
->v4l2_dev
;
326 struct vimc_sen_device
*vsen
;
329 /* Allocate the vsen struct */
330 vsen
= kzalloc(sizeof(*vsen
), GFP_KERNEL
);
334 v4l2_ctrl_handler_init(&vsen
->hdl
, 4);
336 v4l2_ctrl_new_custom(&vsen
->hdl
, &vimc_sen_ctrl_class
, NULL
);
337 v4l2_ctrl_new_custom(&vsen
->hdl
, &vimc_sen_ctrl_test_pattern
, NULL
);
338 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
339 V4L2_CID_VFLIP
, 0, 1, 1, 0);
340 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
341 V4L2_CID_HFLIP
, 0, 1, 1, 0);
342 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
343 V4L2_CID_BRIGHTNESS
, 0, 255, 1, 128);
344 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
345 V4L2_CID_CONTRAST
, 0, 255, 1, 128);
346 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
347 V4L2_CID_HUE
, -128, 127, 1, 0);
348 v4l2_ctrl_new_std(&vsen
->hdl
, &vimc_sen_ctrl_ops
,
349 V4L2_CID_SATURATION
, 0, 255, 1, 128);
350 vsen
->sd
.ctrl_handler
= &vsen
->hdl
;
351 if (vsen
->hdl
.error
) {
352 ret
= vsen
->hdl
.error
;
356 /* Initialize the test pattern generator */
357 tpg_init(&vsen
->tpg
, vsen
->mbus_format
.width
,
358 vsen
->mbus_format
.height
);
359 ret
= tpg_alloc(&vsen
->tpg
, VIMC_FRAME_MAX_WIDTH
);
363 /* Initialize ved and sd */
364 vsen
->pad
.flags
= MEDIA_PAD_FL_SOURCE
;
365 ret
= vimc_ent_sd_register(&vsen
->ved
, &vsen
->sd
, v4l2_dev
,
367 MEDIA_ENT_F_CAM_SENSOR
, 1, &vsen
->pad
,
368 &vimc_sen_int_ops
, &vimc_sen_ops
);
372 vsen
->ved
.process_frame
= vimc_sen_process_frame
;
373 vsen
->ved
.dev
= &vimc
->pdev
.dev
;
375 /* Initialize the frame format */
376 vsen
->mbus_format
= fmt_default
;
381 tpg_free(&vsen
->tpg
);
383 v4l2_ctrl_handler_free(&vsen
->hdl
);