diff options
Diffstat (limited to 'drivers/media/platform/vimc/vimc-sensor.c')
-rw-r--r-- | drivers/media/platform/vimc/vimc-sensor.c | 130 |
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 | |||
29 | struct vimc_sen_device { | 27 | struct 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 | ||
37 | static 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 | |||
45 | static 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 | |||
39 | static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, | 60 | static 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 | ||
78 | static int vimc_sen_get_fmt(struct v4l2_subdev *sd, | 96 | static 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 | ||
128 | static 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 | |||
149 | static 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 | |||
108 | static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { | 186 | static 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 | ||
116 | static int vimc_sen_tpg_thread(void *data) | 194 | static 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 | ||