aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vimc/vimc-sensor.c
diff options
context:
space:
mode:
authorHelen Fornazier <helen.koike@collabora.com>2017-06-19 13:00:16 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-06-23 08:07:15 -0400
commit88ad71aab1a7931ac3d35c3acaa431c3dc05afd9 (patch)
tree0a0d0be75d70ff503c63888fb1c78c6532373f9c /drivers/media/platform/vimc/vimc-sensor.c
parent441c0db6e5a2f07f91b72e31a22a19180d28ebf5 (diff)
[media] vimc: sen: Support several image formats
Allow user space to change the image format as the frame size, the media bus pixel format, colorspace, quantization, field YCbCr encoding and the transfer function Signed-off-by: Helen Koike <helen.koike@collabora.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vimc/vimc-sensor.c')
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c130
1 files changed, 101 insertions, 29 deletions
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 6386ac12856c..d4f97050b544 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -24,8 +24,6 @@
24 24
25#include "vimc-sensor.h" 25#include "vimc-sensor.h"
26 26
27#define VIMC_SEN_FRAME_MAX_WIDTH 4096
28
29struct vimc_sen_device { 27struct vimc_sen_device {
30 struct vimc_ent_device ved; 28 struct vimc_ent_device ved;
31 struct v4l2_subdev sd; 29 struct v4l2_subdev sd;
@@ -36,18 +34,39 @@ struct vimc_sen_device {
36 struct v4l2_mbus_framefmt mbus_format; 34 struct v4l2_mbus_framefmt mbus_format;
37}; 35};
38 36
37static const struct v4l2_mbus_framefmt fmt_default = {
38 .width = 640,
39 .height = 480,
40 .code = MEDIA_BUS_FMT_RGB888_1X24,
41 .field = V4L2_FIELD_NONE,
42 .colorspace = V4L2_COLORSPACE_DEFAULT,
43};
44
45static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
46 struct v4l2_subdev_pad_config *cfg)
47{
48 unsigned int i;
49
50 for (i = 0; i < sd->entity.num_pads; i++) {
51 struct v4l2_mbus_framefmt *mf;
52
53 mf = v4l2_subdev_get_try_format(sd, cfg, i);
54 *mf = fmt_default;
55 }
56
57 return 0;
58}
59
39static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, 60static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
40 struct v4l2_subdev_pad_config *cfg, 61 struct v4l2_subdev_pad_config *cfg,
41 struct v4l2_subdev_mbus_code_enum *code) 62 struct v4l2_subdev_mbus_code_enum *code)
42{ 63{
43 struct vimc_sen_device *vsen = 64 const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index);
44 container_of(sd, struct vimc_sen_device, sd);
45 65
46 /* TODO: Add support for other codes */ 66 if (!vpix)
47 if (code->index)
48 return -EINVAL; 67 return -EINVAL;
49 68
50 code->code = vsen->mbus_format.code; 69 code->code = vpix->code;
51 70
52 return 0; 71 return 0;
53} 72}
@@ -56,33 +75,34 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
56 struct v4l2_subdev_pad_config *cfg, 75 struct v4l2_subdev_pad_config *cfg,
57 struct v4l2_subdev_frame_size_enum *fse) 76 struct v4l2_subdev_frame_size_enum *fse)
58{ 77{
59 struct vimc_sen_device *vsen = 78 const struct vimc_pix_map *vpix;
60 container_of(sd, struct vimc_sen_device, sd);
61 79
62 /* TODO: Add support to other formats */
63 if (fse->index) 80 if (fse->index)
64 return -EINVAL; 81 return -EINVAL;
65 82
66 /* TODO: Add support for other codes */ 83 /* Only accept code in the pix map table */
67 if (fse->code != vsen->mbus_format.code) 84 vpix = vimc_pix_map_by_code(fse->code);
85 if (!vpix)
68 return -EINVAL; 86 return -EINVAL;
69 87
70 fse->min_width = vsen->mbus_format.width; 88 fse->min_width = VIMC_FRAME_MIN_WIDTH;
71 fse->max_width = vsen->mbus_format.width; 89 fse->max_width = VIMC_FRAME_MAX_WIDTH;
72 fse->min_height = vsen->mbus_format.height; 90 fse->min_height = VIMC_FRAME_MIN_HEIGHT;
73 fse->max_height = vsen->mbus_format.height; 91 fse->max_height = VIMC_FRAME_MAX_HEIGHT;
74 92
75 return 0; 93 return 0;
76} 94}
77 95
78static int vimc_sen_get_fmt(struct v4l2_subdev *sd, 96static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
79 struct v4l2_subdev_pad_config *cfg, 97 struct v4l2_subdev_pad_config *cfg,
80 struct v4l2_subdev_format *format) 98 struct v4l2_subdev_format *fmt)
81{ 99{
82 struct vimc_sen_device *vsen = 100 struct vimc_sen_device *vsen =
83 container_of(sd, struct vimc_sen_device, sd); 101 container_of(sd, struct vimc_sen_device, sd);
84 102
85 format->format = vsen->mbus_format; 103 fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
104 *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) :
105 vsen->mbus_format;
86 106
87 return 0; 107 return 0;
88} 108}
@@ -105,12 +125,70 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
105 tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); 125 tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func);
106} 126}
107 127
128static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
129{
130 const struct vimc_pix_map *vpix;
131
132 /* Only accept code in the pix map table */
133 vpix = vimc_pix_map_by_code(fmt->code);
134 if (!vpix)
135 fmt->code = fmt_default.code;
136
137 fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
138 VIMC_FRAME_MAX_WIDTH) & ~1;
139 fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
140 VIMC_FRAME_MAX_HEIGHT) & ~1;
141
142 /* TODO: add support for V4L2_FIELD_ALTERNATE */
143 if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
144 fmt->field = fmt_default.field;
145
146 vimc_colorimetry_clamp(fmt);
147}
148
149static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
150 struct v4l2_subdev_pad_config *cfg,
151 struct v4l2_subdev_format *fmt)
152{
153 struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
154 struct v4l2_mbus_framefmt *mf;
155
156 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
157 /* Do not change the format while stream is on */
158 if (vsen->frame)
159 return -EBUSY;
160
161 mf = &vsen->mbus_format;
162 } else {
163 mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
164 }
165
166 /* Set the new format */
167 vimc_sen_adjust_fmt(&fmt->format);
168
169 dev_dbg(vsen->sd.v4l2_dev->mdev->dev, "%s: format update: "
170 "old:%dx%d (0x%x, %d, %d, %d, %d) "
171 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name,
172 /* old */
173 mf->width, mf->height, mf->code,
174 mf->colorspace, mf->quantization,
175 mf->xfer_func, mf->ycbcr_enc,
176 /* new */
177 fmt->format.width, fmt->format.height, fmt->format.code,
178 fmt->format.colorspace, fmt->format.quantization,
179 fmt->format.xfer_func, fmt->format.ycbcr_enc);
180
181 *mf = fmt->format;
182
183 return 0;
184}
185
108static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { 186static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = {
187 .init_cfg = vimc_sen_init_cfg,
109 .enum_mbus_code = vimc_sen_enum_mbus_code, 188 .enum_mbus_code = vimc_sen_enum_mbus_code,
110 .enum_frame_size = vimc_sen_enum_frame_size, 189 .enum_frame_size = vimc_sen_enum_frame_size,
111 .get_fmt = vimc_sen_get_fmt, 190 .get_fmt = vimc_sen_get_fmt,
112 /* TODO: Add support to other formats */ 191 .set_fmt = vimc_sen_set_fmt,
113 .set_fmt = vimc_sen_get_fmt,
114}; 192};
115 193
116static int vimc_sen_tpg_thread(void *data) 194static int vimc_sen_tpg_thread(void *data)
@@ -247,19 +325,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,
247 if (ret) 325 if (ret)
248 goto err_free_vsen; 326 goto err_free_vsen;
249 327
250 /* Set the active frame format (this is hardcoded for now) */ 328 /* Initialize the frame format */
251 vsen->mbus_format.width = 640; 329 vsen->mbus_format = fmt_default;
252 vsen->mbus_format.height = 480;
253 vsen->mbus_format.code = MEDIA_BUS_FMT_RGB888_1X24;
254 vsen->mbus_format.field = V4L2_FIELD_NONE;
255 vsen->mbus_format.colorspace = V4L2_COLORSPACE_SRGB;
256 vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
257 vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB;
258 330
259 /* Initialize the test pattern generator */ 331 /* Initialize the test pattern generator */
260 tpg_init(&vsen->tpg, vsen->mbus_format.width, 332 tpg_init(&vsen->tpg, vsen->mbus_format.width,
261 vsen->mbus_format.height); 333 vsen->mbus_format.height);
262 ret = tpg_alloc(&vsen->tpg, VIMC_SEN_FRAME_MAX_WIDTH); 334 ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH);
263 if (ret) 335 if (ret)
264 goto err_unregister_ent_sd; 336 goto err_unregister_ent_sd;
265 337