diff options
author | Helen Fornazier <helen.koike@collabora.com> | 2017-06-19 13:00:10 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-06-23 07:30:31 -0400 |
commit | 554946c3665793e8fb03fef3401adbd99e271cf6 (patch) | |
tree | c16d3aa57fb09ab1257544ee321057bc8a3fe12e /drivers/media/platform/vimc/vimc-sensor.c | |
parent | ab924af9acde26a5840b905c599dd4f3e10eaa00 (diff) |
[media] vimc: sen: Integrate the tpg on the sensor
Initialize the test pattern generator on the sensor
Generate a colored bar image instead of a grey one
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.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 591f6a4f8bd3..2e834878da0d 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c | |||
@@ -20,17 +20,20 @@ | |||
20 | #include <linux/v4l2-mediabus.h> | 20 | #include <linux/v4l2-mediabus.h> |
21 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
22 | #include <media/v4l2-subdev.h> | 22 | #include <media/v4l2-subdev.h> |
23 | #include <media/v4l2-tpg.h> | ||
23 | 24 | ||
24 | #include "vimc-sensor.h" | 25 | #include "vimc-sensor.h" |
25 | 26 | ||
27 | #define VIMC_SEN_FRAME_MAX_WIDTH 4096 | ||
28 | |||
26 | struct vimc_sen_device { | 29 | struct vimc_sen_device { |
27 | struct vimc_ent_device ved; | 30 | struct vimc_ent_device ved; |
28 | struct v4l2_subdev sd; | 31 | struct v4l2_subdev sd; |
32 | struct tpg_data tpg; | ||
29 | struct task_struct *kthread_sen; | 33 | struct task_struct *kthread_sen; |
30 | u8 *frame; | 34 | u8 *frame; |
31 | /* The active format */ | 35 | /* The active format */ |
32 | struct v4l2_mbus_framefmt mbus_format; | 36 | struct v4l2_mbus_framefmt mbus_format; |
33 | int frame_size; | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, | 39 | static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, |
@@ -84,6 +87,24 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd, | |||
84 | return 0; | 87 | return 0; |
85 | } | 88 | } |
86 | 89 | ||
90 | static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) | ||
91 | { | ||
92 | const struct vimc_pix_map *vpix = | ||
93 | vimc_pix_map_by_code(vsen->mbus_format.code); | ||
94 | |||
95 | tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, | ||
96 | vsen->mbus_format.height, vsen->mbus_format.field); | ||
97 | tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); | ||
98 | tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); | ||
99 | tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); | ||
100 | /* TODO: add support for V4L2_FIELD_ALTERNATE */ | ||
101 | tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); | ||
102 | tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); | ||
103 | tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); | ||
104 | tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); | ||
105 | tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); | ||
106 | } | ||
107 | |||
87 | static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { | 108 | static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { |
88 | .enum_mbus_code = vimc_sen_enum_mbus_code, | 109 | .enum_mbus_code = vimc_sen_enum_mbus_code, |
89 | .enum_frame_size = vimc_sen_enum_frame_size, | 110 | .enum_frame_size = vimc_sen_enum_frame_size, |
@@ -97,7 +118,7 @@ static const struct media_entity_operations vimc_sen_mops = { | |||
97 | .link_validate = v4l2_subdev_link_validate, | 118 | .link_validate = v4l2_subdev_link_validate, |
98 | }; | 119 | }; |
99 | 120 | ||
100 | static int vimc_thread_sen(void *data) | 121 | static int vimc_sen_tpg_thread(void *data) |
101 | { | 122 | { |
102 | struct vimc_sen_device *vsen = data; | 123 | struct vimc_sen_device *vsen = data; |
103 | unsigned int i; | 124 | unsigned int i; |
@@ -110,7 +131,7 @@ static int vimc_thread_sen(void *data) | |||
110 | if (kthread_should_stop()) | 131 | if (kthread_should_stop()) |
111 | break; | 132 | break; |
112 | 133 | ||
113 | memset(vsen->frame, 100, vsen->frame_size); | 134 | tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); |
114 | 135 | ||
115 | /* Send the frame to all source pads */ | 136 | /* Send the frame to all source pads */ |
116 | for (i = 0; i < vsen->sd.entity.num_pads; i++) | 137 | for (i = 0; i < vsen->sd.entity.num_pads; i++) |
@@ -132,26 +153,31 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) | |||
132 | 153 | ||
133 | if (enable) { | 154 | if (enable) { |
134 | const struct vimc_pix_map *vpix; | 155 | const struct vimc_pix_map *vpix; |
156 | unsigned int frame_size; | ||
135 | 157 | ||
136 | if (vsen->kthread_sen) | 158 | if (vsen->kthread_sen) |
137 | return -EINVAL; | 159 | /* tpg is already executing */ |
160 | return 0; | ||
138 | 161 | ||
139 | /* Calculate the frame size */ | 162 | /* Calculate the frame size */ |
140 | vpix = vimc_pix_map_by_code(vsen->mbus_format.code); | 163 | vpix = vimc_pix_map_by_code(vsen->mbus_format.code); |
141 | vsen->frame_size = vsen->mbus_format.width * vpix->bpp * | 164 | frame_size = vsen->mbus_format.width * vpix->bpp * |
142 | vsen->mbus_format.height; | 165 | vsen->mbus_format.height; |
143 | 166 | ||
144 | /* | 167 | /* |
145 | * Allocate the frame buffer. Use vmalloc to be able to | 168 | * Allocate the frame buffer. Use vmalloc to be able to |
146 | * allocate a large amount of memory | 169 | * allocate a large amount of memory |
147 | */ | 170 | */ |
148 | vsen->frame = vmalloc(vsen->frame_size); | 171 | vsen->frame = vmalloc(frame_size); |
149 | if (!vsen->frame) | 172 | if (!vsen->frame) |
150 | return -ENOMEM; | 173 | return -ENOMEM; |
151 | 174 | ||
175 | /* configure the test pattern generator */ | ||
176 | vimc_sen_tpg_s_format(vsen); | ||
177 | |||
152 | /* Initialize the image generator thread */ | 178 | /* Initialize the image generator thread */ |
153 | vsen->kthread_sen = kthread_run(vimc_thread_sen, vsen, "%s-sen", | 179 | vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, |
154 | vsen->sd.v4l2_dev->name); | 180 | "%s-sen", vsen->sd.v4l2_dev->name); |
155 | if (IS_ERR(vsen->kthread_sen)) { | 181 | if (IS_ERR(vsen->kthread_sen)) { |
156 | dev_err(vsen->sd.v4l2_dev->dev, | 182 | dev_err(vsen->sd.v4l2_dev->dev, |
157 | "%s: kernel_thread() failed\n", vsen->sd.name); | 183 | "%s: kernel_thread() failed\n", vsen->sd.name); |
@@ -161,15 +187,17 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) | |||
161 | } | 187 | } |
162 | } else { | 188 | } else { |
163 | if (!vsen->kthread_sen) | 189 | if (!vsen->kthread_sen) |
164 | return -EINVAL; | 190 | return 0; |
165 | 191 | ||
166 | /* Stop image generator */ | 192 | /* Stop image generator */ |
167 | ret = kthread_stop(vsen->kthread_sen); | 193 | ret = kthread_stop(vsen->kthread_sen); |
168 | vsen->kthread_sen = NULL; | 194 | if (ret) |
195 | return ret; | ||
169 | 196 | ||
197 | vsen->kthread_sen = NULL; | ||
170 | vfree(vsen->frame); | 198 | vfree(vsen->frame); |
171 | vsen->frame = NULL; | 199 | vsen->frame = NULL; |
172 | return ret; | 200 | return 0; |
173 | } | 201 | } |
174 | 202 | ||
175 | return 0; | 203 | return 0; |
@@ -189,6 +217,7 @@ static void vimc_sen_destroy(struct vimc_ent_device *ved) | |||
189 | struct vimc_sen_device *vsen = | 217 | struct vimc_sen_device *vsen = |
190 | container_of(ved, struct vimc_sen_device, ved); | 218 | container_of(ved, struct vimc_sen_device, ved); |
191 | 219 | ||
220 | tpg_free(&vsen->tpg); | ||
192 | v4l2_device_unregister_subdev(&vsen->sd); | 221 | v4l2_device_unregister_subdev(&vsen->sd); |
193 | media_entity_cleanup(ved->ent); | 222 | media_entity_cleanup(ved->ent); |
194 | kfree(vsen); | 223 | kfree(vsen); |
@@ -254,17 +283,26 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | |||
254 | vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE; | 283 | vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE; |
255 | vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB; | 284 | vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB; |
256 | 285 | ||
286 | /* Initialize the test pattern generator */ | ||
287 | tpg_init(&vsen->tpg, vsen->mbus_format.width, | ||
288 | vsen->mbus_format.height); | ||
289 | ret = tpg_alloc(&vsen->tpg, VIMC_SEN_FRAME_MAX_WIDTH); | ||
290 | if (ret) | ||
291 | goto err_clean_m_ent; | ||
292 | |||
257 | /* Register the subdev with the v4l2 and the media framework */ | 293 | /* Register the subdev with the v4l2 and the media framework */ |
258 | ret = v4l2_device_register_subdev(v4l2_dev, &vsen->sd); | 294 | ret = v4l2_device_register_subdev(v4l2_dev, &vsen->sd); |
259 | if (ret) { | 295 | if (ret) { |
260 | dev_err(vsen->sd.v4l2_dev->dev, | 296 | dev_err(vsen->sd.v4l2_dev->dev, |
261 | "%s: subdev register failed (err=%d)\n", | 297 | "%s: subdev register failed (err=%d)\n", |
262 | vsen->sd.name, ret); | 298 | vsen->sd.name, ret); |
263 | goto err_clean_m_ent; | 299 | goto err_free_tpg; |
264 | } | 300 | } |
265 | 301 | ||
266 | return &vsen->ved; | 302 | return &vsen->ved; |
267 | 303 | ||
304 | err_free_tpg: | ||
305 | tpg_free(&vsen->tpg); | ||
268 | err_clean_m_ent: | 306 | err_clean_m_ent: |
269 | media_entity_cleanup(&vsen->sd.entity); | 307 | media_entity_cleanup(&vsen->sd.entity); |
270 | err_clean_pads: | 308 | err_clean_pads: |