diff options
author | Jonathan Corbet <corbet@lwn.net> | 2010-03-05 14:48:39 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:51:22 -0400 |
commit | 364e93372fb21ef5de18d0122c78789f065ddbf5 (patch) | |
tree | bfea3132d78b976ccae551f603f0d1c7845e5862 /drivers/media/video/ov7670.c | |
parent | 81898671247a6cfa6bfd6a32faee18b3999b6610 (diff) |
V4L/DVB: ov7670: wire up controls for exposure and autoexposure
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/ov7670.c')
-rw-r--r-- | drivers/media/video/ov7670.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index e7555d1f90e6..90c44598dd51 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -1190,6 +1190,79 @@ static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | |||
1190 | return ret; | 1190 | return ret; |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | /* | ||
1194 | * Exposure is spread all over the place: top 6 bits in AECHH, middle | ||
1195 | * 8 in AECH, and two stashed in COM1 just for the hell of it. | ||
1196 | */ | ||
1197 | static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value) | ||
1198 | { | ||
1199 | int ret; | ||
1200 | unsigned char com1, aech, aechh; | ||
1201 | |||
1202 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
1203 | ov7670_read(sd, REG_AECH, &aech) + | ||
1204 | ov7670_read(sd, REG_AECHH, &aechh); | ||
1205 | *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03); | ||
1206 | return ret; | ||
1207 | } | ||
1208 | |||
1209 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | ||
1210 | { | ||
1211 | int ret; | ||
1212 | unsigned char com1, com8, aech, aechh; | ||
1213 | |||
1214 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
1215 | ov7670_read(sd, REG_COM8, &com8); | ||
1216 | ov7670_read(sd, REG_AECHH, &aechh); | ||
1217 | if (ret) | ||
1218 | return ret; | ||
1219 | |||
1220 | com1 = (com1 & 0xfc) | (value & 0x03); | ||
1221 | aech = (value >> 2) & 0xff; | ||
1222 | aechh = (aechh & 0xc0) | ((value >> 10) & 0x3f); | ||
1223 | ret = ov7670_write(sd, REG_COM1, com1) + | ||
1224 | ov7670_write(sd, REG_AECH, aech) + | ||
1225 | ov7670_write(sd, REG_AECHH, aechh); | ||
1226 | /* Have to turn off AEC as well */ | ||
1227 | if (ret == 0) | ||
1228 | ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC); | ||
1229 | return ret; | ||
1230 | } | ||
1231 | |||
1232 | /* | ||
1233 | * Tweak autoexposure. | ||
1234 | */ | ||
1235 | static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value) | ||
1236 | { | ||
1237 | int ret; | ||
1238 | unsigned char com8; | ||
1239 | enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value; | ||
1240 | |||
1241 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1242 | if (com8 & COM8_AEC) | ||
1243 | *value = V4L2_EXPOSURE_AUTO; | ||
1244 | else | ||
1245 | *value = V4L2_EXPOSURE_MANUAL; | ||
1246 | return ret; | ||
1247 | } | ||
1248 | |||
1249 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, | ||
1250 | enum v4l2_exposure_auto_type value) | ||
1251 | { | ||
1252 | int ret; | ||
1253 | unsigned char com8; | ||
1254 | |||
1255 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1256 | if (ret == 0) { | ||
1257 | if (value == V4L2_EXPOSURE_AUTO) | ||
1258 | com8 |= COM8_AEC; | ||
1259 | else | ||
1260 | com8 &= ~COM8_AEC; | ||
1261 | ret = ov7670_write(sd, REG_COM8, com8); | ||
1262 | } | ||
1263 | return ret; | ||
1264 | } | ||
1265 | |||
1193 | 1266 | ||
1194 | 1267 | ||
1195 | static int ov7670_queryctrl(struct v4l2_subdev *sd, | 1268 | static int ov7670_queryctrl(struct v4l2_subdev *sd, |
@@ -1212,6 +1285,10 @@ static int ov7670_queryctrl(struct v4l2_subdev *sd, | |||
1212 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | 1285 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); |
1213 | case V4L2_CID_AUTOGAIN: | 1286 | case V4L2_CID_AUTOGAIN: |
1214 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | 1287 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); |
1288 | case V4L2_CID_EXPOSURE: | ||
1289 | return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500); | ||
1290 | case V4L2_CID_EXPOSURE_AUTO: | ||
1291 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1215 | } | 1292 | } |
1216 | return -EINVAL; | 1293 | return -EINVAL; |
1217 | } | 1294 | } |
@@ -1235,6 +1312,10 @@ static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
1235 | return ov7670_g_gain(sd, &ctrl->value); | 1312 | return ov7670_g_gain(sd, &ctrl->value); |
1236 | case V4L2_CID_AUTOGAIN: | 1313 | case V4L2_CID_AUTOGAIN: |
1237 | return ov7670_g_autogain(sd, &ctrl->value); | 1314 | return ov7670_g_autogain(sd, &ctrl->value); |
1315 | case V4L2_CID_EXPOSURE: | ||
1316 | return ov7670_g_exp(sd, &ctrl->value); | ||
1317 | case V4L2_CID_EXPOSURE_AUTO: | ||
1318 | return ov7670_g_autoexp(sd, &ctrl->value); | ||
1238 | } | 1319 | } |
1239 | return -EINVAL; | 1320 | return -EINVAL; |
1240 | } | 1321 | } |
@@ -1258,6 +1339,11 @@ static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
1258 | return ov7670_s_gain(sd, ctrl->value); | 1339 | return ov7670_s_gain(sd, ctrl->value); |
1259 | case V4L2_CID_AUTOGAIN: | 1340 | case V4L2_CID_AUTOGAIN: |
1260 | return ov7670_s_autogain(sd, ctrl->value); | 1341 | return ov7670_s_autogain(sd, ctrl->value); |
1342 | case V4L2_CID_EXPOSURE: | ||
1343 | return ov7670_s_exp(sd, ctrl->value); | ||
1344 | case V4L2_CID_EXPOSURE_AUTO: | ||
1345 | return ov7670_s_autoexp(sd, | ||
1346 | (enum v4l2_exposure_auto_type) ctrl->value); | ||
1261 | } | 1347 | } |
1262 | return -EINVAL; | 1348 | return -EINVAL; |
1263 | } | 1349 | } |