aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/test-drivers/vimc/vimc-lens.c
blob: dfe824d3addbbea90058b0aa7ffcfe7c9e039a88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * vimc-lens.c Virtual Media Controller Driver
 * Copyright (C) 2022 Google, Inc
 * Author: [email protected] (Yunke Cao)
 */

#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-subdev.h>

#include "vimc-common.h"

#define VIMC_LEN_MAX_FOCUS_POS	1023
#define VIMC_LEN_MAX_FOCUS_STEP	1

struct vimc_len_device {
	struct vimc_ent_device ved;
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	u32 focus_absolute;
};

static const struct v4l2_subdev_core_ops vimc_len_core_ops = {
	.log_status = v4l2_ctrl_subdev_log_status,
	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};

static const struct v4l2_subdev_ops vimc_len_ops = {
	.core = &vimc_len_core_ops
};

static int vimc_len_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct vimc_len_device *vlen =
		container_of(ctrl->handler, struct vimc_len_device, hdl);
	if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
		vlen->focus_absolute = ctrl->val;
		return 0;
	}
	return -EINVAL;
}

static const struct v4l2_ctrl_ops vimc_len_ctrl_ops = {
	.s_ctrl = vimc_len_s_ctrl,
};

static struct vimc_ent_device *vimc_len_add(struct vimc_device *vimc,
					    const char *vcfg_name)
{
	struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
	struct vimc_len_device *vlen;
	int ret;

	/* Allocate the vlen struct */
	vlen = kzalloc(sizeof(*vlen), GFP_KERNEL);
	if (!vlen)
		return ERR_PTR(-ENOMEM);

	v4l2_ctrl_handler_init(&vlen->hdl, 1);

	v4l2_ctrl_new_std(&vlen->hdl, &vimc_len_ctrl_ops,
			  V4L2_CID_FOCUS_ABSOLUTE, 0,
			  VIMC_LEN_MAX_FOCUS_POS, VIMC_LEN_MAX_FOCUS_STEP, 0);
	vlen->sd.ctrl_handler = &vlen->hdl;
	if (vlen->hdl.error) {
		ret = vlen->hdl.error;
		goto err_free_vlen;
	}
	vlen->ved.dev = vimc->mdev.dev;

	ret = vimc_ent_sd_register(&vlen->ved, &vlen->sd, v4l2_dev,
				   vcfg_name, MEDIA_ENT_F_LENS, 0,
				   NULL, &vimc_len_ops);
	if (ret)
		goto err_free_hdl;

	return &vlen->ved;

err_free_hdl:
	v4l2_ctrl_handler_free(&vlen->hdl);
err_free_vlen:
	kfree(vlen);

	return ERR_PTR(ret);
}

static void vimc_len_release(struct vimc_ent_device *ved)
{
	struct vimc_len_device *vlen =
		container_of(ved, struct vimc_len_device, ved);

	v4l2_ctrl_handler_free(&vlen->hdl);
	media_entity_cleanup(vlen->ved.ent);
	kfree(vlen);
}

struct vimc_ent_type vimc_len_type = {
	.add = vimc_len_add,
	.release = vimc_len_release
};