Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Helen Fornazier and committed by
Mauro Carvalho Chehab
554946c3 ab924af9

+52 -13
+1
drivers/media/platform/vimc/Kconfig
··· 2 2 tristate "Virtual Media Controller Driver (VIMC)" 3 3 depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API 4 4 select VIDEOBUF2_VMALLOC 5 + select VIDEO_V4L2_TPG 5 6 default n 6 7 ---help--- 7 8 Skeleton driver for Virtual Media Controller
+51 -13
drivers/media/platform/vimc/vimc-sensor.c
··· 20 20 #include <linux/v4l2-mediabus.h> 21 21 #include <linux/vmalloc.h> 22 22 #include <media/v4l2-subdev.h> 23 + #include <media/v4l2-tpg.h> 23 24 24 25 #include "vimc-sensor.h" 26 + 27 + #define VIMC_SEN_FRAME_MAX_WIDTH 4096 25 28 26 29 struct vimc_sen_device { 27 30 struct vimc_ent_device ved; 28 31 struct v4l2_subdev sd; 32 + struct tpg_data tpg; 29 33 struct task_struct *kthread_sen; 30 34 u8 *frame; 31 35 /* The active format */ 32 36 struct v4l2_mbus_framefmt mbus_format; 33 - int frame_size; 34 37 }; 35 38 36 39 static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, ··· 87 84 return 0; 88 85 } 89 86 87 + static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) 88 + { 89 + const struct vimc_pix_map *vpix = 90 + vimc_pix_map_by_code(vsen->mbus_format.code); 91 + 92 + tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, 93 + vsen->mbus_format.height, vsen->mbus_format.field); 94 + tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); 95 + tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); 96 + tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); 97 + /* TODO: add support for V4L2_FIELD_ALTERNATE */ 98 + tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); 99 + tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); 100 + tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); 101 + tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); 102 + tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); 103 + } 104 + 90 105 static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { 91 106 .enum_mbus_code = vimc_sen_enum_mbus_code, 92 107 .enum_frame_size = vimc_sen_enum_frame_size, ··· 118 97 .link_validate = v4l2_subdev_link_validate, 119 98 }; 120 99 121 - static int vimc_thread_sen(void *data) 100 + static int vimc_sen_tpg_thread(void *data) 122 101 { 123 102 struct vimc_sen_device *vsen = data; 124 103 unsigned int i; ··· 131 110 if (kthread_should_stop()) 132 111 break; 133 112 134 - memset(vsen->frame, 100, vsen->frame_size); 113 + tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); 135 114 136 115 /* Send the frame to all source pads */ 137 116 for (i = 0; i < vsen->sd.entity.num_pads; i++) ··· 153 132 154 133 if (enable) { 155 134 const struct vimc_pix_map *vpix; 135 + unsigned int frame_size; 156 136 157 137 if (vsen->kthread_sen) 158 - return -EINVAL; 138 + /* tpg is already executing */ 139 + return 0; 159 140 160 141 /* Calculate the frame size */ 161 142 vpix = vimc_pix_map_by_code(vsen->mbus_format.code); 162 - vsen->frame_size = vsen->mbus_format.width * vpix->bpp * 163 - vsen->mbus_format.height; 143 + frame_size = vsen->mbus_format.width * vpix->bpp * 144 + vsen->mbus_format.height; 164 145 165 146 /* 166 147 * Allocate the frame buffer. Use vmalloc to be able to 167 148 * allocate a large amount of memory 168 149 */ 169 - vsen->frame = vmalloc(vsen->frame_size); 150 + vsen->frame = vmalloc(frame_size); 170 151 if (!vsen->frame) 171 152 return -ENOMEM; 172 153 154 + /* configure the test pattern generator */ 155 + vimc_sen_tpg_s_format(vsen); 156 + 173 157 /* Initialize the image generator thread */ 174 - vsen->kthread_sen = kthread_run(vimc_thread_sen, vsen, "%s-sen", 175 - vsen->sd.v4l2_dev->name); 158 + vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, 159 + "%s-sen", vsen->sd.v4l2_dev->name); 176 160 if (IS_ERR(vsen->kthread_sen)) { 177 161 dev_err(vsen->sd.v4l2_dev->dev, 178 162 "%s: kernel_thread() failed\n", vsen->sd.name); ··· 187 161 } 188 162 } else { 189 163 if (!vsen->kthread_sen) 190 - return -EINVAL; 164 + return 0; 191 165 192 166 /* Stop image generator */ 193 167 ret = kthread_stop(vsen->kthread_sen); 194 - vsen->kthread_sen = NULL; 168 + if (ret) 169 + return ret; 195 170 171 + vsen->kthread_sen = NULL; 196 172 vfree(vsen->frame); 197 173 vsen->frame = NULL; 198 - return ret; 174 + return 0; 199 175 } 200 176 201 177 return 0; ··· 217 189 struct vimc_sen_device *vsen = 218 190 container_of(ved, struct vimc_sen_device, ved); 219 191 192 + tpg_free(&vsen->tpg); 220 193 v4l2_device_unregister_subdev(&vsen->sd); 221 194 media_entity_cleanup(ved->ent); 222 195 kfree(vsen); ··· 283 254 vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE; 284 255 vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB; 285 256 257 + /* Initialize the test pattern generator */ 258 + tpg_init(&vsen->tpg, vsen->mbus_format.width, 259 + vsen->mbus_format.height); 260 + ret = tpg_alloc(&vsen->tpg, VIMC_SEN_FRAME_MAX_WIDTH); 261 + if (ret) 262 + goto err_clean_m_ent; 263 + 286 264 /* Register the subdev with the v4l2 and the media framework */ 287 265 ret = v4l2_device_register_subdev(v4l2_dev, &vsen->sd); 288 266 if (ret) { 289 267 dev_err(vsen->sd.v4l2_dev->dev, 290 268 "%s: subdev register failed (err=%d)\n", 291 269 vsen->sd.name, ret); 292 - goto err_clean_m_ent; 270 + goto err_free_tpg; 293 271 } 294 272 295 273 return &vsen->ved; 296 274 275 + err_free_tpg: 276 + tpg_free(&vsen->tpg); 297 277 err_clean_m_ent: 298 278 media_entity_cleanup(&vsen->sd.entity); 299 279 err_clean_pads: