diff options
-rw-r--r-- | drivers/media/i2c/ov7670.c | 310 |
1 files changed, 112 insertions, 198 deletions
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 52c024a334df..93a051e8873f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/videodev2.h> | 18 | #include <linux/videodev2.h> |
19 | #include <media/v4l2-device.h> | 19 | #include <media/v4l2-device.h> |
20 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
21 | #include <media/v4l2-ctrls.h> | ||
21 | #include <media/v4l2-mediabus.h> | 22 | #include <media/v4l2-mediabus.h> |
22 | #include <media/ov7670.h> | 23 | #include <media/ov7670.h> |
23 | 24 | ||
@@ -222,9 +223,23 @@ struct ov7670_devtype { | |||
222 | struct ov7670_format_struct; /* coming later */ | 223 | struct ov7670_format_struct; /* coming later */ |
223 | struct ov7670_info { | 224 | struct ov7670_info { |
224 | struct v4l2_subdev sd; | 225 | struct v4l2_subdev sd; |
226 | struct v4l2_ctrl_handler hdl; | ||
227 | struct { | ||
228 | /* gain cluster */ | ||
229 | struct v4l2_ctrl *auto_gain; | ||
230 | struct v4l2_ctrl *gain; | ||
231 | }; | ||
232 | struct { | ||
233 | /* exposure cluster */ | ||
234 | struct v4l2_ctrl *auto_exposure; | ||
235 | struct v4l2_ctrl *exposure; | ||
236 | }; | ||
237 | struct { | ||
238 | /* saturation/hue cluster */ | ||
239 | struct v4l2_ctrl *saturation; | ||
240 | struct v4l2_ctrl *hue; | ||
241 | }; | ||
225 | struct ov7670_format_struct *fmt; /* Current format */ | 242 | struct ov7670_format_struct *fmt; /* Current format */ |
226 | unsigned char sat; /* Saturation value */ | ||
227 | int hue; /* Hue value */ | ||
228 | int min_width; /* Filter out smaller sizes */ | 243 | int min_width; /* Filter out smaller sizes */ |
229 | int min_height; /* Filter out smaller sizes */ | 244 | int min_height; /* Filter out smaller sizes */ |
230 | int clock_speed; /* External clock speed (MHz) */ | 245 | int clock_speed; /* External clock speed (MHz) */ |
@@ -240,6 +255,11 @@ static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) | |||
240 | return container_of(sd, struct ov7670_info, sd); | 255 | return container_of(sd, struct ov7670_info, sd); |
241 | } | 256 | } |
242 | 257 | ||
258 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
259 | { | ||
260 | return &container_of(ctrl->handler, struct ov7670_info, hdl)->sd; | ||
261 | } | ||
262 | |||
243 | 263 | ||
244 | 264 | ||
245 | /* | 265 | /* |
@@ -1195,23 +1215,23 @@ static int ov7670_cosine(int theta) | |||
1195 | 1215 | ||
1196 | 1216 | ||
1197 | static void ov7670_calc_cmatrix(struct ov7670_info *info, | 1217 | static void ov7670_calc_cmatrix(struct ov7670_info *info, |
1198 | int matrix[CMATRIX_LEN]) | 1218 | int matrix[CMATRIX_LEN], int sat, int hue) |
1199 | { | 1219 | { |
1200 | int i; | 1220 | int i; |
1201 | /* | 1221 | /* |
1202 | * Apply the current saturation setting first. | 1222 | * Apply the current saturation setting first. |
1203 | */ | 1223 | */ |
1204 | for (i = 0; i < CMATRIX_LEN; i++) | 1224 | for (i = 0; i < CMATRIX_LEN; i++) |
1205 | matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; | 1225 | matrix[i] = (info->fmt->cmatrix[i] * sat) >> 7; |
1206 | /* | 1226 | /* |
1207 | * Then, if need be, rotate the hue value. | 1227 | * Then, if need be, rotate the hue value. |
1208 | */ | 1228 | */ |
1209 | if (info->hue != 0) { | 1229 | if (hue != 0) { |
1210 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; | 1230 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; |
1211 | 1231 | ||
1212 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); | 1232 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); |
1213 | sinth = ov7670_sine(info->hue); | 1233 | sinth = ov7670_sine(hue); |
1214 | costh = ov7670_cosine(info->hue); | 1234 | costh = ov7670_cosine(hue); |
1215 | 1235 | ||
1216 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; | 1236 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; |
1217 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; | 1237 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; |
@@ -1224,60 +1244,21 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info, | |||
1224 | 1244 | ||
1225 | 1245 | ||
1226 | 1246 | ||
1227 | static int ov7670_s_sat(struct v4l2_subdev *sd, int value) | 1247 | static int ov7670_s_sat_hue(struct v4l2_subdev *sd, int sat, int hue) |
1228 | { | 1248 | { |
1229 | struct ov7670_info *info = to_state(sd); | 1249 | struct ov7670_info *info = to_state(sd); |
1230 | int matrix[CMATRIX_LEN]; | 1250 | int matrix[CMATRIX_LEN]; |
1231 | int ret; | 1251 | int ret; |
1232 | 1252 | ||
1233 | info->sat = value; | 1253 | ov7670_calc_cmatrix(info, matrix, sat, hue); |
1234 | ov7670_calc_cmatrix(info, matrix); | ||
1235 | ret = ov7670_store_cmatrix(sd, matrix); | 1254 | ret = ov7670_store_cmatrix(sd, matrix); |
1236 | return ret; | 1255 | return ret; |
1237 | } | 1256 | } |
1238 | 1257 | ||
1239 | static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value) | ||
1240 | { | ||
1241 | struct ov7670_info *info = to_state(sd); | ||
1242 | |||
1243 | *value = info->sat; | ||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | static int ov7670_s_hue(struct v4l2_subdev *sd, int value) | ||
1248 | { | ||
1249 | struct ov7670_info *info = to_state(sd); | ||
1250 | int matrix[CMATRIX_LEN]; | ||
1251 | int ret; | ||
1252 | |||
1253 | if (value < -180 || value > 180) | ||
1254 | return -EINVAL; | ||
1255 | info->hue = value; | ||
1256 | ov7670_calc_cmatrix(info, matrix); | ||
1257 | ret = ov7670_store_cmatrix(sd, matrix); | ||
1258 | return ret; | ||
1259 | } | ||
1260 | |||
1261 | |||
1262 | static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value) | ||
1263 | { | ||
1264 | struct ov7670_info *info = to_state(sd); | ||
1265 | |||
1266 | *value = info->hue; | ||
1267 | return 0; | ||
1268 | } | ||
1269 | |||
1270 | 1258 | ||
1271 | /* | 1259 | /* |
1272 | * Some weird registers seem to store values in a sign/magnitude format! | 1260 | * Some weird registers seem to store values in a sign/magnitude format! |
1273 | */ | 1261 | */ |
1274 | static unsigned char ov7670_sm_to_abs(unsigned char v) | ||
1275 | { | ||
1276 | if ((v & 0x80) == 0) | ||
1277 | return v + 128; | ||
1278 | return 128 - (v & 0x7f); | ||
1279 | } | ||
1280 | |||
1281 | 1262 | ||
1282 | static unsigned char ov7670_abs_to_sm(unsigned char v) | 1263 | static unsigned char ov7670_abs_to_sm(unsigned char v) |
1283 | { | 1264 | { |
@@ -1299,40 +1280,11 @@ static int ov7670_s_brightness(struct v4l2_subdev *sd, int value) | |||
1299 | return ret; | 1280 | return ret; |
1300 | } | 1281 | } |
1301 | 1282 | ||
1302 | static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value) | ||
1303 | { | ||
1304 | unsigned char v = 0; | ||
1305 | int ret = ov7670_read(sd, REG_BRIGHT, &v); | ||
1306 | |||
1307 | *value = ov7670_sm_to_abs(v); | ||
1308 | return ret; | ||
1309 | } | ||
1310 | |||
1311 | static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) | 1283 | static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) |
1312 | { | 1284 | { |
1313 | return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); | 1285 | return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); |
1314 | } | 1286 | } |
1315 | 1287 | ||
1316 | static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value) | ||
1317 | { | ||
1318 | unsigned char v = 0; | ||
1319 | int ret = ov7670_read(sd, REG_CONTRAS, &v); | ||
1320 | |||
1321 | *value = v; | ||
1322 | return ret; | ||
1323 | } | ||
1324 | |||
1325 | static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value) | ||
1326 | { | ||
1327 | int ret; | ||
1328 | unsigned char v = 0; | ||
1329 | |||
1330 | ret = ov7670_read(sd, REG_MVFP, &v); | ||
1331 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; | ||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
1335 | |||
1336 | static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) | 1288 | static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) |
1337 | { | 1289 | { |
1338 | unsigned char v = 0; | 1290 | unsigned char v = 0; |
@@ -1348,19 +1300,6 @@ static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) | |||
1348 | return ret; | 1300 | return ret; |
1349 | } | 1301 | } |
1350 | 1302 | ||
1351 | |||
1352 | |||
1353 | static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value) | ||
1354 | { | ||
1355 | int ret; | ||
1356 | unsigned char v = 0; | ||
1357 | |||
1358 | ret = ov7670_read(sd, REG_MVFP, &v); | ||
1359 | *value = (v & MVFP_FLIP) == MVFP_FLIP; | ||
1360 | return ret; | ||
1361 | } | ||
1362 | |||
1363 | |||
1364 | static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) | 1303 | static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) |
1365 | { | 1304 | { |
1366 | unsigned char v = 0; | 1305 | unsigned char v = 0; |
@@ -1409,16 +1348,6 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value) | |||
1409 | /* | 1348 | /* |
1410 | * Tweak autogain. | 1349 | * Tweak autogain. |
1411 | */ | 1350 | */ |
1412 | static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value) | ||
1413 | { | ||
1414 | int ret; | ||
1415 | unsigned char com8; | ||
1416 | |||
1417 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1418 | *value = (com8 & COM8_AGC) != 0; | ||
1419 | return ret; | ||
1420 | } | ||
1421 | |||
1422 | static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | 1351 | static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) |
1423 | { | 1352 | { |
1424 | int ret; | 1353 | int ret; |
@@ -1435,22 +1364,6 @@ static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | |||
1435 | return ret; | 1364 | return ret; |
1436 | } | 1365 | } |
1437 | 1366 | ||
1438 | /* | ||
1439 | * Exposure is spread all over the place: top 6 bits in AECHH, middle | ||
1440 | * 8 in AECH, and two stashed in COM1 just for the hell of it. | ||
1441 | */ | ||
1442 | static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value) | ||
1443 | { | ||
1444 | int ret; | ||
1445 | unsigned char com1, aech, aechh; | ||
1446 | |||
1447 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
1448 | ov7670_read(sd, REG_AECH, &aech) + | ||
1449 | ov7670_read(sd, REG_AECHH, &aechh); | ||
1450 | *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03); | ||
1451 | return ret; | ||
1452 | } | ||
1453 | |||
1454 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | 1367 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) |
1455 | { | 1368 | { |
1456 | int ret; | 1369 | int ret; |
@@ -1477,20 +1390,6 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | |||
1477 | /* | 1390 | /* |
1478 | * Tweak autoexposure. | 1391 | * Tweak autoexposure. |
1479 | */ | 1392 | */ |
1480 | static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value) | ||
1481 | { | ||
1482 | int ret; | ||
1483 | unsigned char com8; | ||
1484 | enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value; | ||
1485 | |||
1486 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1487 | if (com8 & COM8_AEC) | ||
1488 | *atype = V4L2_EXPOSURE_AUTO; | ||
1489 | else | ||
1490 | *atype = V4L2_EXPOSURE_MANUAL; | ||
1491 | return ret; | ||
1492 | } | ||
1493 | |||
1494 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, | 1393 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, |
1495 | enum v4l2_exposure_auto_type value) | 1394 | enum v4l2_exposure_auto_type value) |
1496 | { | 1395 | { |
@@ -1509,90 +1408,60 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd, | |||
1509 | } | 1408 | } |
1510 | 1409 | ||
1511 | 1410 | ||
1512 | 1411 | static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |
1513 | static int ov7670_queryctrl(struct v4l2_subdev *sd, | ||
1514 | struct v4l2_queryctrl *qc) | ||
1515 | { | 1412 | { |
1516 | /* Fill in min, max, step and default value for these controls. */ | 1413 | struct v4l2_subdev *sd = to_sd(ctrl); |
1517 | switch (qc->id) { | 1414 | struct ov7670_info *info = to_state(sd); |
1518 | case V4L2_CID_BRIGHTNESS: | ||
1519 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
1520 | case V4L2_CID_CONTRAST: | ||
1521 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); | ||
1522 | case V4L2_CID_VFLIP: | ||
1523 | case V4L2_CID_HFLIP: | ||
1524 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1525 | case V4L2_CID_SATURATION: | ||
1526 | return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); | ||
1527 | case V4L2_CID_HUE: | ||
1528 | return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); | ||
1529 | case V4L2_CID_GAIN: | ||
1530 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
1531 | case V4L2_CID_AUTOGAIN: | ||
1532 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
1533 | case V4L2_CID_EXPOSURE: | ||
1534 | return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500); | ||
1535 | case V4L2_CID_EXPOSURE_AUTO: | ||
1536 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1537 | } | ||
1538 | return -EINVAL; | ||
1539 | } | ||
1540 | 1415 | ||
1541 | static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
1542 | { | ||
1543 | switch (ctrl->id) { | 1416 | switch (ctrl->id) { |
1544 | case V4L2_CID_BRIGHTNESS: | ||
1545 | return ov7670_g_brightness(sd, &ctrl->value); | ||
1546 | case V4L2_CID_CONTRAST: | ||
1547 | return ov7670_g_contrast(sd, &ctrl->value); | ||
1548 | case V4L2_CID_SATURATION: | ||
1549 | return ov7670_g_sat(sd, &ctrl->value); | ||
1550 | case V4L2_CID_HUE: | ||
1551 | return ov7670_g_hue(sd, &ctrl->value); | ||
1552 | case V4L2_CID_VFLIP: | ||
1553 | return ov7670_g_vflip(sd, &ctrl->value); | ||
1554 | case V4L2_CID_HFLIP: | ||
1555 | return ov7670_g_hflip(sd, &ctrl->value); | ||
1556 | case V4L2_CID_GAIN: | ||
1557 | return ov7670_g_gain(sd, &ctrl->value); | ||
1558 | case V4L2_CID_AUTOGAIN: | 1417 | case V4L2_CID_AUTOGAIN: |
1559 | return ov7670_g_autogain(sd, &ctrl->value); | 1418 | return ov7670_g_gain(sd, &info->gain->val); |
1560 | case V4L2_CID_EXPOSURE: | ||
1561 | return ov7670_g_exp(sd, &ctrl->value); | ||
1562 | case V4L2_CID_EXPOSURE_AUTO: | ||
1563 | return ov7670_g_autoexp(sd, &ctrl->value); | ||
1564 | } | 1419 | } |
1565 | return -EINVAL; | 1420 | return -EINVAL; |
1566 | } | 1421 | } |
1567 | 1422 | ||
1568 | static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 1423 | static int ov7670_s_ctrl(struct v4l2_ctrl *ctrl) |
1569 | { | 1424 | { |
1425 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
1426 | struct ov7670_info *info = to_state(sd); | ||
1427 | |||
1570 | switch (ctrl->id) { | 1428 | switch (ctrl->id) { |
1571 | case V4L2_CID_BRIGHTNESS: | 1429 | case V4L2_CID_BRIGHTNESS: |
1572 | return ov7670_s_brightness(sd, ctrl->value); | 1430 | return ov7670_s_brightness(sd, ctrl->val); |
1573 | case V4L2_CID_CONTRAST: | 1431 | case V4L2_CID_CONTRAST: |
1574 | return ov7670_s_contrast(sd, ctrl->value); | 1432 | return ov7670_s_contrast(sd, ctrl->val); |
1575 | case V4L2_CID_SATURATION: | 1433 | case V4L2_CID_SATURATION: |
1576 | return ov7670_s_sat(sd, ctrl->value); | 1434 | return ov7670_s_sat_hue(sd, |
1577 | case V4L2_CID_HUE: | 1435 | info->saturation->val, info->hue->val); |
1578 | return ov7670_s_hue(sd, ctrl->value); | ||
1579 | case V4L2_CID_VFLIP: | 1436 | case V4L2_CID_VFLIP: |
1580 | return ov7670_s_vflip(sd, ctrl->value); | 1437 | return ov7670_s_vflip(sd, ctrl->val); |
1581 | case V4L2_CID_HFLIP: | 1438 | case V4L2_CID_HFLIP: |
1582 | return ov7670_s_hflip(sd, ctrl->value); | 1439 | return ov7670_s_hflip(sd, ctrl->val); |
1583 | case V4L2_CID_GAIN: | ||
1584 | return ov7670_s_gain(sd, ctrl->value); | ||
1585 | case V4L2_CID_AUTOGAIN: | 1440 | case V4L2_CID_AUTOGAIN: |
1586 | return ov7670_s_autogain(sd, ctrl->value); | 1441 | /* Only set manual gain if auto gain is not explicitly |
1587 | case V4L2_CID_EXPOSURE: | 1442 | turned on. */ |
1588 | return ov7670_s_exp(sd, ctrl->value); | 1443 | if (!ctrl->val) { |
1444 | /* ov7670_s_gain turns off auto gain */ | ||
1445 | return ov7670_s_gain(sd, info->gain->val); | ||
1446 | } | ||
1447 | return ov7670_s_autogain(sd, ctrl->val); | ||
1589 | case V4L2_CID_EXPOSURE_AUTO: | 1448 | case V4L2_CID_EXPOSURE_AUTO: |
1590 | return ov7670_s_autoexp(sd, | 1449 | /* Only set manual exposure if auto exposure is not explicitly |
1591 | (enum v4l2_exposure_auto_type) ctrl->value); | 1450 | turned on. */ |
1451 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
1452 | /* ov7670_s_exp turns off auto exposure */ | ||
1453 | return ov7670_s_exp(sd, info->exposure->val); | ||
1454 | } | ||
1455 | return ov7670_s_autoexp(sd, ctrl->val); | ||
1592 | } | 1456 | } |
1593 | return -EINVAL; | 1457 | return -EINVAL; |
1594 | } | 1458 | } |
1595 | 1459 | ||
1460 | static const struct v4l2_ctrl_ops ov7670_ctrl_ops = { | ||
1461 | .s_ctrl = ov7670_s_ctrl, | ||
1462 | .g_volatile_ctrl = ov7670_g_volatile_ctrl, | ||
1463 | }; | ||
1464 | |||
1596 | static int ov7670_g_chip_ident(struct v4l2_subdev *sd, | 1465 | static int ov7670_g_chip_ident(struct v4l2_subdev *sd, |
1597 | struct v4l2_dbg_chip_ident *chip) | 1466 | struct v4l2_dbg_chip_ident *chip) |
1598 | { | 1467 | { |
@@ -1635,9 +1504,13 @@ static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r | |||
1635 | 1504 | ||
1636 | static const struct v4l2_subdev_core_ops ov7670_core_ops = { | 1505 | static const struct v4l2_subdev_core_ops ov7670_core_ops = { |
1637 | .g_chip_ident = ov7670_g_chip_ident, | 1506 | .g_chip_ident = ov7670_g_chip_ident, |
1638 | .g_ctrl = ov7670_g_ctrl, | 1507 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
1639 | .s_ctrl = ov7670_s_ctrl, | 1508 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
1640 | .queryctrl = ov7670_queryctrl, | 1509 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
1510 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
1511 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
1512 | .queryctrl = v4l2_subdev_queryctrl, | ||
1513 | .querymenu = v4l2_subdev_querymenu, | ||
1641 | .reset = ov7670_reset, | 1514 | .reset = ov7670_reset, |
1642 | .init = ov7670_init, | 1515 | .init = ov7670_init, |
1643 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1516 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -1732,7 +1605,6 @@ static int ov7670_probe(struct i2c_client *client, | |||
1732 | 1605 | ||
1733 | info->devtype = &ov7670_devdata[id->driver_data]; | 1606 | info->devtype = &ov7670_devdata[id->driver_data]; |
1734 | info->fmt = &ov7670_formats[0]; | 1607 | info->fmt = &ov7670_formats[0]; |
1735 | info->sat = 128; /* Review this */ | ||
1736 | info->clkrc = 0; | 1608 | info->clkrc = 0; |
1737 | 1609 | ||
1738 | /* Set default frame rate to 30 fps */ | 1610 | /* Set default frame rate to 30 fps */ |
@@ -1743,6 +1615,46 @@ static int ov7670_probe(struct i2c_client *client, | |||
1743 | if (info->pclk_hb_disable) | 1615 | if (info->pclk_hb_disable) |
1744 | ov7670_write(sd, REG_COM10, COM10_PCLK_HB); | 1616 | ov7670_write(sd, REG_COM10, COM10_PCLK_HB); |
1745 | 1617 | ||
1618 | v4l2_ctrl_handler_init(&info->hdl, 10); | ||
1619 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1620 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
1621 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1622 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
1623 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1624 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1625 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1626 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1627 | info->saturation = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1628 | V4L2_CID_SATURATION, 0, 256, 1, 128); | ||
1629 | info->hue = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1630 | V4L2_CID_HUE, -180, 180, 5, 0); | ||
1631 | info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1632 | V4L2_CID_GAIN, 0, 255, 1, 128); | ||
1633 | info->auto_gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1634 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
1635 | info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1636 | V4L2_CID_EXPOSURE, 0, 65535, 1, 500); | ||
1637 | info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops, | ||
1638 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, | ||
1639 | V4L2_EXPOSURE_AUTO); | ||
1640 | sd->ctrl_handler = &info->hdl; | ||
1641 | if (info->hdl.error) { | ||
1642 | int err = info->hdl.error; | ||
1643 | |||
1644 | v4l2_ctrl_handler_free(&info->hdl); | ||
1645 | kfree(info); | ||
1646 | return err; | ||
1647 | } | ||
1648 | /* | ||
1649 | * We have checked empirically that hw allows to read back the gain | ||
1650 | * value chosen by auto gain but that's not the case for auto exposure. | ||
1651 | */ | ||
1652 | v4l2_ctrl_auto_cluster(2, &info->auto_gain, 0, true); | ||
1653 | v4l2_ctrl_auto_cluster(2, &info->auto_exposure, | ||
1654 | V4L2_EXPOSURE_MANUAL, false); | ||
1655 | v4l2_ctrl_cluster(2, &info->saturation); | ||
1656 | v4l2_ctrl_handler_setup(&info->hdl); | ||
1657 | |||
1746 | return 0; | 1658 | return 0; |
1747 | } | 1659 | } |
1748 | 1660 | ||
@@ -1750,9 +1662,11 @@ static int ov7670_probe(struct i2c_client *client, | |||
1750 | static int ov7670_remove(struct i2c_client *client) | 1662 | static int ov7670_remove(struct i2c_client *client) |
1751 | { | 1663 | { |
1752 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 1664 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1665 | struct ov7670_info *info = to_state(sd); | ||
1753 | 1666 | ||
1754 | v4l2_device_unregister_subdev(sd); | 1667 | v4l2_device_unregister_subdev(sd); |
1755 | kfree(to_state(sd)); | 1668 | v4l2_ctrl_handler_free(&info->hdl); |
1669 | kfree(info); | ||
1756 | return 0; | 1670 | return 0; |
1757 | } | 1671 | } |
1758 | 1672 | ||