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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
From a3359aca41e5942a74f803ce8837ef24456db2d5 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 11 Jun 2020 14:36:40 +0100
Subject: [PATCH] media: i2c: imx290: Convert HMAX setting into
V4L2_CID_HBLANK
Userspace needs to know HBLANK if it is to work out exposure times
and frame rates, therefore convert it to map onto V4L2_CID_HBLANK
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx290.c | 66 +++++++++++++++++++++++++-------------
1 file changed, 44 insertions(+), 22 deletions(-)
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -40,6 +40,9 @@ enum imx290_clk_index {
#define IMX290_GAIN 0x3014
#define IMX290_HMAX_LOW 0x301c
#define IMX290_HMAX_HIGH 0x301d
+#define IMX290_HMAX_MIN_2LANE 4400 /* Min of 4400 pixels = 30fps */
+#define IMX290_HMAX_MIN_4LANE 2200 /* Min of 2200 pixels = 60fps */
+#define IMX290_HMAX_MAX 0xffff
#define IMX290_PGCTRL 0x308c
#define IMX290_PHY_LANE_NUM 0x3407
#define IMX290_CSI_LANE_MODE 0x3443
@@ -82,6 +85,7 @@ struct imx290 {
struct regmap *regmap;
u8 nlanes;
u8 bpp;
+ u16 hmax_min;
struct v4l2_subdev sd;
struct media_pad pad;
@@ -94,6 +98,7 @@ struct imx290 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *hblank;
struct mutex lock;
};
@@ -518,6 +523,26 @@ static int imx290_set_gain(struct imx290
return ret;
}
+static int imx290_set_hmax(struct imx290 *imx290, u32 val)
+{
+ u32 hmax = val + imx290->current_mode->width;
+ int ret;
+
+ ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (hmax & 0xff));
+ if (ret) {
+ dev_err(imx290->dev, "Error setting HMAX register\n");
+ return ret;
+ }
+
+ ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((hmax >> 8) & 0xff));
+ if (ret) {
+ dev_err(imx290->dev, "Error setting HMAX register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
/* Stop streaming */
static int imx290_stop_streaming(struct imx290 *imx290)
{
@@ -546,6 +571,9 @@ static int imx290_set_ctrl(struct v4l2_c
case V4L2_CID_GAIN:
ret = imx290_set_gain(imx290, ctrl->val);
break;
+ case V4L2_CID_HBLANK:
+ ret = imx290_set_hmax(imx290, ctrl->val);
+ break;
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00);
@@ -702,6 +730,12 @@ static int imx290_set_fmt(struct v4l2_su
if (imx290->pixel_rate)
__v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
imx290_calc_pixel_rate(imx290));
+
+ if (imx290->hblank)
+ __v4l2_ctrl_modify_range(imx290->hblank,
+ imx290->hmax_min - mode->width,
+ IMX290_HMAX_MAX - mode->width,
+ 1, mode->hmax - mode->width);
}
*format = fmt->format;
@@ -756,25 +790,6 @@ static int imx290_write_current_format(s
return 0;
}
-static int imx290_set_hmax(struct imx290 *imx290, u32 val)
-{
- int ret;
-
- ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff));
- if (ret) {
- dev_err(imx290->dev, "Error setting HMAX register\n");
- return ret;
- }
-
- ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff));
- if (ret) {
- dev_err(imx290->dev, "Error setting HMAX register\n");
- return ret;
- }
-
- return 0;
-}
-
/* Start streaming */
static int imx290_start_streaming(struct imx290 *imx290)
{
@@ -813,9 +828,6 @@ static int imx290_start_streaming(struct
dev_err(imx290->dev, "Could not set current mode\n");
return ret;
}
- ret = imx290_set_hmax(imx290, imx290->current_mode->hmax);
- if (ret < 0)
- return ret;
/* Apply customized values from user */
ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
@@ -1014,6 +1026,7 @@ static int imx290_probe(struct i2c_clien
struct v4l2_fwnode_endpoint ep = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
+ const struct imx290_mode *mode;
struct imx290 *imx290;
s64 fq;
int ret;
@@ -1052,6 +1065,8 @@ static int imx290_probe(struct i2c_clien
ret = -EINVAL;
goto free_err;
}
+ imx290->hmax_min = (imx290->nlanes == 2) ? IMX290_HMAX_MIN_2LANE :
+ IMX290_HMAX_MIN_4LANE;
dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
@@ -1126,6 +1141,13 @@ static int imx290_probe(struct i2c_clien
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_GAIN, 0, 238, 1, 0);
+ mode = imx290->current_mode;
+ imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_HBLANK,
+ imx290->hmax_min - mode->width,
+ IMX290_HMAX_MAX - mode->width, 1,
+ mode->hmax - mode->width);
+
imx290->link_freq =
v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_LINK_FREQ,
|