aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vimc/vimc-sensor.c
diff options
context:
space:
mode:
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