907bab5cfd4a34773b7e882017e6abee4dbfb6d0
[openwrt/staging/svanheule.git] /
1 From d9d333b717f220439868edd533994f2709b3a95f Mon Sep 17 00:00:00 2001
2 From: David Plowman <david.plowman@raspberrypi.com>
3 Date: Wed, 29 Jan 2020 15:31:23 +0000
4 Subject: [PATCH] media: ov5647: Add V4L2 controls for analogue gain,
5 exposure and AWB
6
7 Added basic v4l2_ctrl_handler infrastructure (there was none
8 previously).
9
10 Added controls to let AWB/AEC/AGC run in the sensor's auto mode or
11 manually. Also controls to set exposure (in lines) and analogue gain
12 (as a register code) from user code.
13
14 Also delete registers (just the one) from the VGA mode register set
15 that are now controlled by the new V4L2 controls.
16
17 Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
18 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
19 ---
20 drivers/media/i2c/ov5647.c | 175 ++++++++++++++++++++++++++++++++++++-
21 1 file changed, 174 insertions(+), 1 deletion(-)
22
23 --- a/drivers/media/i2c/ov5647.c
24 +++ b/drivers/media/i2c/ov5647.c
25 @@ -29,11 +29,13 @@
26 #include <linux/of_graph.h>
27 #include <linux/slab.h>
28 #include <linux/videodev2.h>
29 +#include <media/v4l2-ctrls.h>
30 #include <media/v4l2-device.h>
31 #include <media/v4l2-fwnode.h>
32 #include <media/v4l2-image-sizes.h>
33 #include <media/v4l2-mediabus.h>
34
35 +
36 #define SENSOR_NAME "ov5647"
37
38 /*
39 @@ -53,9 +55,16 @@
40 #define OV5647_REG_CHIPID_H 0x300A
41 #define OV5647_REG_CHIPID_L 0x300B
42 #define OV5640_REG_PAD_OUT 0x300D
43 +#define OV5647_REG_EXP_HI 0x3500
44 +#define OV5647_REG_EXP_MID 0x3501
45 +#define OV5647_REG_EXP_LO 0x3502
46 +#define OV5647_REG_AEC_AGC 0x3503
47 +#define OV5647_REG_GAIN_HI 0x350A
48 +#define OV5647_REG_GAIN_LO 0x350B
49 #define OV5647_REG_FRAME_OFF_NUMBER 0x4202
50 #define OV5647_REG_MIPI_CTRL00 0x4800
51 #define OV5647_REG_MIPI_CTRL14 0x4814
52 +#define OV5647_REG_AWB 0x5001
53
54 #define REG_TERM 0xfffe
55 #define VAL_TERM 0xfe
56 @@ -101,6 +110,7 @@ struct ov5647 {
57 struct clk *xclk;
58 struct gpio_desc *pwdn;
59 unsigned int flags;
60 + struct v4l2_ctrl_handler ctrls;
61 };
62
63 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
64 @@ -135,7 +145,6 @@ static struct regval_list ov5647_640x480
65 {0x3612, 0x59},
66 {0x3618, 0x00},
67 {0x5000, 0x06},
68 - {0x5001, 0x01},
69 {0x5002, 0x41},
70 {0x5003, 0x08},
71 {0x5a00, 0x08},
72 @@ -372,6 +381,11 @@ static int ov5647_stream_on(struct v4l2_
73 return ret;
74 }
75
76 + /* Apply customized values from user when stream starts */
77 + ret = __v4l2_ctrl_handler_setup(sd->ctrl_handler);
78 + if (ret)
79 + return ret;
80 +
81 if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
82 val |= MIPI_CTRL00_CLOCK_LANE_GATE |
83 MIPI_CTRL00_LINE_SYNC_ENABLE;
84 @@ -753,6 +767,120 @@ static int ov5647_parse_dt(struct device
85 return ret;
86 }
87
88 +static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)
89 +{
90 + /* non-zero turns on AWB */
91 + return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);
92 +}
93 +
94 +static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)
95 +{
96 + int ret;
97 + u8 reg;
98 +
99 + /* non-zero turns on AGC by clearing bit 1 */
100 + ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
101 + if (ret == 0)
102 + ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
103 + val ? reg & ~2 : reg | 2);
104 +
105 + return ret;
106 +}
107 +
108 +static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)
109 +{
110 + int ret;
111 + u8 reg;
112 +
113 + /* Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
114 + * clearing bit 0
115 + */
116 + ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
117 + if (ret == 0)
118 + ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
119 + val == V4L2_EXPOSURE_MANUAL ?
120 + reg | 1 : reg & ~1);
121 +
122 + return ret;
123 +}
124 +
125 +static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)
126 +{
127 + int ret;
128 +
129 + /* 10 bits of gain, 2 in the high register */
130 + ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);
131 + if (ret == 0)
132 + ret = ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);
133 +
134 + return ret;
135 +}
136 +
137 +static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)
138 +{
139 + int ret;
140 +
141 + /* Sensor has 20 bits, but the bottom 4 bits are fractions of a line
142 + * which we leave as zero (and don't receive in "val").
143 + */
144 + ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);
145 + if (ret == 0)
146 + ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);
147 + if (ret == 0)
148 + ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);
149 +
150 + return ret;
151 +}
152 +
153 +static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
154 +{
155 + struct ov5647 *state = container_of(ctrl->handler,
156 + struct ov5647, ctrls);
157 + struct v4l2_subdev *sd = &state->sd;
158 + struct i2c_client *client = v4l2_get_subdevdata(sd);
159 + int ret = 0;
160 +
161 + /* v4l2_ctrl_lock() locks our own mutex */
162 +
163 + /*
164 + * If the device is not powered up by the host driver do
165 + * not apply any controls to H/W at this time. Instead
166 + * the controls will be restored right after power-up.
167 + */
168 + if (state->power_count == 0)
169 + return 0;
170 +
171 + switch (ctrl->id) {
172 + case V4L2_CID_AUTO_WHITE_BALANCE:
173 + ret = ov5647_s_auto_white_balance(sd, ctrl->val);
174 + break;
175 + case V4L2_CID_AUTOGAIN:
176 + ret = ov5647_s_autogain(sd, ctrl->val);
177 + break;
178 + case V4L2_CID_EXPOSURE_AUTO:
179 + ret = ov5647_s_exposure_auto(sd, ctrl->val);
180 + break;
181 + case V4L2_CID_ANALOGUE_GAIN:
182 + ret = ov5647_s_analogue_gain(sd, ctrl->val);
183 + break;
184 + case V4L2_CID_EXPOSURE:
185 + ret = ov5647_s_exposure(sd, ctrl->val);
186 + break;
187 + default:
188 + dev_info(&client->dev,
189 + "ctrl(id:0x%x,val:0x%x) is not handled\n",
190 + ctrl->id, ctrl->val);
191 + ret = -EINVAL;
192 + break;
193 + }
194 +
195 + return ret;
196 +}
197 +
198 +static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
199 + .s_ctrl = ov5647_s_ctrl,
200 +};
201 +
202 static int ov5647_probe(struct i2c_client *client)
203 {
204 struct device *dev = &client->dev;
205 @@ -761,6 +889,7 @@ static int ov5647_probe(struct i2c_clien
206 struct v4l2_subdev *sd;
207 struct device_node *np = client->dev.of_node;
208 u32 xclk_freq;
209 + struct v4l2_ctrl *ctrl;
210
211 sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
212 if (!sensor)
213 @@ -793,6 +922,48 @@ static int ov5647_probe(struct i2c_clien
214
215 mutex_init(&sensor->lock);
216
217 + /* Initialise controls. */
218 + v4l2_ctrl_handler_init(&sensor->ctrls, 3);
219 + v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
220 + V4L2_CID_AUTOGAIN,
221 + 0, /* min */
222 + 1, /* max */
223 + 1, /* step */
224 + 1); /* default */
225 + v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
226 + V4L2_CID_AUTO_WHITE_BALANCE,
227 + 0, /* min */
228 + 1, /* max */
229 + 1, /* step */
230 + 1); /* default */
231 + v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
232 + V4L2_CID_EXPOSURE_AUTO,
233 + V4L2_EXPOSURE_MANUAL, /* max */
234 + 0, /* skip_mask */
235 + V4L2_EXPOSURE_AUTO); /* default */
236 + ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
237 + V4L2_CID_EXPOSURE,
238 + 4, /* min lines */
239 + 65535, /* max lines (4+8+4 bits)*/
240 + 1, /* step */
241 + 1000); /* default number of lines */
242 + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
243 + ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
244 + V4L2_CID_ANALOGUE_GAIN,
245 + 16, /* min, 16 = 1.0x */
246 + 1023, /* max (10 bits) */
247 + 1, /* step */
248 + 32); /* default, 32 = 2.0x */
249 + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
250 +
251 + if (sensor->ctrls.error) {
252 + ret = sensor->ctrls.error;
253 + dev_err(&client->dev, "%s control init failed (%d)\n",
254 + __func__, ret);
255 + goto error;
256 + }
257 + sensor->sd.ctrl_handler = &sensor->ctrls;
258 +
259 /* Set the default mode before we init the subdev */
260 sensor->mode = OV5647_DEFAULT_MODE;
261
262 @@ -828,6 +999,7 @@ static int ov5647_probe(struct i2c_clien
263 error:
264 media_entity_cleanup(&sd->entity);
265 mutex_remove:
266 + v4l2_ctrl_handler_free(&sensor->ctrls);
267 mutex_destroy(&sensor->lock);
268 return ret;
269 }
270 @@ -839,6 +1011,7 @@ static int ov5647_remove(struct i2c_clie
271
272 v4l2_async_unregister_subdev(&ov5647->sd);
273 media_entity_cleanup(&ov5647->sd.entity);
274 + v4l2_ctrl_handler_free(&ov5647->ctrls);
275 v4l2_device_unregister_subdev(sd);
276 mutex_destroy(&ov5647->lock);
277