aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2013-01-29 05:31:17 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-08 11:37:02 -0500
commit492959c77f66c2238298115f4fabf1bb9ca997eb (patch)
tree6b3a35b47bda99e2ba891d622e0a22defed887e9
parentee95258ed3926f3aa2cf8d62e62cd51be466fe26 (diff)
[media] ov7670: use the control framework
Cc: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/i2c/ov7670.c310
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 {
222struct ov7670_format_struct; /* coming later */ 223struct ov7670_format_struct; /* coming later */
223struct ov7670_info { 224struct 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
258static 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
1197static void ov7670_calc_cmatrix(struct ov7670_info *info, 1217static 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
1227static int ov7670_s_sat(struct v4l2_subdev *sd, int value) 1247static 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
1239static 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
1247static 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
1262static 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 */
1274static 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
1282static unsigned char ov7670_abs_to_sm(unsigned char v) 1263static 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
1302static 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
1311static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) 1283static 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
1316static 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
1325static 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
1336static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) 1288static 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
1353static 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
1364static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) 1303static 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 */
1412static 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
1422static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) 1351static 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 */
1442static 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
1454static int ov7670_s_exp(struct v4l2_subdev *sd, int value) 1367static 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 */
1480static 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
1494static int ov7670_s_autoexp(struct v4l2_subdev *sd, 1393static 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 1411static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
1513static 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
1541static 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
1568static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 1423static 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
1460static const struct v4l2_ctrl_ops ov7670_ctrl_ops = {
1461 .s_ctrl = ov7670_s_ctrl,
1462 .g_volatile_ctrl = ov7670_g_volatile_ctrl,
1463};
1464
1596static int ov7670_g_chip_ident(struct v4l2_subdev *sd, 1465static 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
1636static const struct v4l2_subdev_core_ops ov7670_core_ops = { 1505static 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,
1750static int ov7670_remove(struct i2c_client *client) 1662static 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