diff options
Diffstat (limited to 'drivers/media/video/ov7670.c')
| -rw-r--r-- | drivers/media/video/ov7670.c | 286 |
1 files changed, 251 insertions, 35 deletions
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index aaa50f9b8e78..91c886ab15c6 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
| @@ -198,6 +198,7 @@ struct ov7670_info { | |||
| 198 | struct ov7670_format_struct *fmt; /* Current format */ | 198 | struct ov7670_format_struct *fmt; /* Current format */ |
| 199 | unsigned char sat; /* Saturation value */ | 199 | unsigned char sat; /* Saturation value */ |
| 200 | int hue; /* Hue value */ | 200 | int hue; /* Hue value */ |
| 201 | u8 clkrc; /* Clock divider value */ | ||
| 201 | }; | 202 | }; |
| 202 | 203 | ||
| 203 | static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) | 204 | static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) |
| @@ -351,7 +352,7 @@ static struct regval_list ov7670_default_regs[] = { | |||
| 351 | static struct regval_list ov7670_fmt_yuv422[] = { | 352 | static struct regval_list ov7670_fmt_yuv422[] = { |
| 352 | { REG_COM7, 0x0 }, /* Selects YUV mode */ | 353 | { REG_COM7, 0x0 }, /* Selects YUV mode */ |
| 353 | { REG_RGB444, 0 }, /* No RGB444 please */ | 354 | { REG_RGB444, 0 }, /* No RGB444 please */ |
| 354 | { REG_COM1, 0 }, | 355 | { REG_COM1, 0 }, /* CCIR601 */ |
| 355 | { REG_COM15, COM15_R00FF }, | 356 | { REG_COM15, COM15_R00FF }, |
| 356 | { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ | 357 | { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ |
| 357 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ | 358 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ |
| @@ -367,7 +368,7 @@ static struct regval_list ov7670_fmt_yuv422[] = { | |||
| 367 | static struct regval_list ov7670_fmt_rgb565[] = { | 368 | static struct regval_list ov7670_fmt_rgb565[] = { |
| 368 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ | 369 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ |
| 369 | { REG_RGB444, 0 }, /* No RGB444 please */ | 370 | { REG_RGB444, 0 }, /* No RGB444 please */ |
| 370 | { REG_COM1, 0x0 }, | 371 | { REG_COM1, 0x0 }, /* CCIR601 */ |
| 371 | { REG_COM15, COM15_RGB565 }, | 372 | { REG_COM15, COM15_RGB565 }, |
| 372 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ | 373 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ |
| 373 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ | 374 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ |
| @@ -383,7 +384,7 @@ static struct regval_list ov7670_fmt_rgb565[] = { | |||
| 383 | static struct regval_list ov7670_fmt_rgb444[] = { | 384 | static struct regval_list ov7670_fmt_rgb444[] = { |
| 384 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ | 385 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ |
| 385 | { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ | 386 | { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ |
| 386 | { REG_COM1, 0x40 }, /* Magic reserved bit */ | 387 | { REG_COM1, 0x0 }, /* CCIR601 */ |
| 387 | { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ | 388 | { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ |
| 388 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ | 389 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ |
| 389 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ | 390 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ |
| @@ -408,8 +409,13 @@ static struct regval_list ov7670_fmt_raw[] = { | |||
| 408 | 409 | ||
| 409 | /* | 410 | /* |
| 410 | * Low-level register I/O. | 411 | * Low-level register I/O. |
| 412 | * | ||
| 413 | * Note that there are two versions of these. On the XO 1, the | ||
| 414 | * i2c controller only does SMBUS, so that's what we use. The | ||
| 415 | * ov7670 is not really an SMBUS device, though, so the communication | ||
| 416 | * is not always entirely reliable. | ||
| 411 | */ | 417 | */ |
| 412 | 418 | #ifdef CONFIG_OLPC_XO_1 | |
| 413 | static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, | 419 | static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, |
| 414 | unsigned char *value) | 420 | unsigned char *value) |
| 415 | { | 421 | { |
| @@ -432,9 +438,67 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, | |||
| 432 | int ret = i2c_smbus_write_byte_data(client, reg, value); | 438 | int ret = i2c_smbus_write_byte_data(client, reg, value); |
| 433 | 439 | ||
| 434 | if (reg == REG_COM7 && (value & COM7_RESET)) | 440 | if (reg == REG_COM7 && (value & COM7_RESET)) |
| 435 | msleep(2); /* Wait for reset to run */ | 441 | msleep(5); /* Wait for reset to run */ |
| 442 | return ret; | ||
| 443 | } | ||
| 444 | |||
| 445 | #else /* ! CONFIG_OLPC_XO_1 */ | ||
| 446 | /* | ||
| 447 | * On most platforms, we'd rather do straight i2c I/O. | ||
| 448 | */ | ||
| 449 | static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, | ||
| 450 | unsigned char *value) | ||
| 451 | { | ||
| 452 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 453 | u8 data = reg; | ||
| 454 | struct i2c_msg msg; | ||
| 455 | int ret; | ||
| 456 | |||
| 457 | /* | ||
| 458 | * Send out the register address... | ||
| 459 | */ | ||
| 460 | msg.addr = client->addr; | ||
| 461 | msg.flags = 0; | ||
| 462 | msg.len = 1; | ||
| 463 | msg.buf = &data; | ||
| 464 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
| 465 | if (ret < 0) { | ||
| 466 | printk(KERN_ERR "Error %d on register write\n", ret); | ||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | /* | ||
| 470 | * ...then read back the result. | ||
| 471 | */ | ||
| 472 | msg.flags = I2C_M_RD; | ||
| 473 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
| 474 | if (ret >= 0) { | ||
| 475 | *value = data; | ||
| 476 | ret = 0; | ||
| 477 | } | ||
| 478 | return ret; | ||
| 479 | } | ||
| 480 | |||
| 481 | |||
| 482 | static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, | ||
| 483 | unsigned char value) | ||
| 484 | { | ||
| 485 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 486 | struct i2c_msg msg; | ||
| 487 | unsigned char data[2] = { reg, value }; | ||
| 488 | int ret; | ||
| 489 | |||
| 490 | msg.addr = client->addr; | ||
| 491 | msg.flags = 0; | ||
| 492 | msg.len = 2; | ||
| 493 | msg.buf = data; | ||
| 494 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
| 495 | if (ret > 0) | ||
| 496 | ret = 0; | ||
| 497 | if (reg == REG_COM7 && (value & COM7_RESET)) | ||
| 498 | msleep(5); /* Wait for reset to run */ | ||
| 436 | return ret; | 499 | return ret; |
| 437 | } | 500 | } |
| 501 | #endif /* CONFIG_OLPC_XO_1 */ | ||
| 438 | 502 | ||
| 439 | 503 | ||
| 440 | /* | 504 | /* |
| @@ -744,22 +808,12 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | |||
| 744 | struct ov7670_format_struct *ovfmt; | 808 | struct ov7670_format_struct *ovfmt; |
| 745 | struct ov7670_win_size *wsize; | 809 | struct ov7670_win_size *wsize; |
| 746 | struct ov7670_info *info = to_state(sd); | 810 | struct ov7670_info *info = to_state(sd); |
| 747 | unsigned char com7, clkrc = 0; | 811 | unsigned char com7; |
| 748 | 812 | ||
| 749 | ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); | 813 | ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); |
| 750 | if (ret) | 814 | if (ret) |
| 751 | return ret; | 815 | return ret; |
| 752 | /* | 816 | /* |
| 753 | * HACK: if we're running rgb565 we need to grab then rewrite | ||
| 754 | * CLKRC. If we're *not*, however, then rewriting clkrc hoses | ||
| 755 | * the colors. | ||
| 756 | */ | ||
| 757 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { | ||
| 758 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); | ||
| 759 | if (ret) | ||
| 760 | return ret; | ||
| 761 | } | ||
| 762 | /* | ||
| 763 | * COM7 is a pain in the ass, it doesn't like to be read then | 817 | * COM7 is a pain in the ass, it doesn't like to be read then |
| 764 | * quickly written afterward. But we have everything we need | 818 | * quickly written afterward. But we have everything we need |
| 765 | * to set it absolutely here, as long as the format-specific | 819 | * to set it absolutely here, as long as the format-specific |
| @@ -779,8 +833,18 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | |||
| 779 | ret = ov7670_write_array(sd, wsize->regs); | 833 | ret = ov7670_write_array(sd, wsize->regs); |
| 780 | info->fmt = ovfmt; | 834 | info->fmt = ovfmt; |
| 781 | 835 | ||
| 782 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) | 836 | /* |
| 783 | ret = ov7670_write(sd, REG_CLKRC, clkrc); | 837 | * If we're running RGB565, we must rewrite clkrc after setting |
| 838 | * the other parameters or the image looks poor. If we're *not* | ||
| 839 | * doing RGB565, we must not rewrite clkrc or the image looks | ||
| 840 | * *really* poor. | ||
| 841 | * | ||
| 842 | * (Update) Now that we retain clkrc state, we should be able | ||
| 843 | * to write it unconditionally, and that will make the frame | ||
| 844 | * rate persistent too. | ||
| 845 | */ | ||
| 846 | if (ret == 0) | ||
| 847 | ret = ov7670_write(sd, REG_CLKRC, info->clkrc); | ||
| 784 | return ret; | 848 | return ret; |
| 785 | } | 849 | } |
| 786 | 850 | ||
| @@ -791,20 +855,17 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | |||
| 791 | static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | 855 | static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) |
| 792 | { | 856 | { |
| 793 | struct v4l2_captureparm *cp = &parms->parm.capture; | 857 | struct v4l2_captureparm *cp = &parms->parm.capture; |
| 794 | unsigned char clkrc; | 858 | struct ov7670_info *info = to_state(sd); |
| 795 | int ret; | ||
| 796 | 859 | ||
| 797 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 860 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| 798 | return -EINVAL; | 861 | return -EINVAL; |
| 799 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); | 862 | |
| 800 | if (ret < 0) | ||
| 801 | return ret; | ||
| 802 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | 863 | memset(cp, 0, sizeof(struct v4l2_captureparm)); |
| 803 | cp->capability = V4L2_CAP_TIMEPERFRAME; | 864 | cp->capability = V4L2_CAP_TIMEPERFRAME; |
| 804 | cp->timeperframe.numerator = 1; | 865 | cp->timeperframe.numerator = 1; |
| 805 | cp->timeperframe.denominator = OV7670_FRAME_RATE; | 866 | cp->timeperframe.denominator = OV7670_FRAME_RATE; |
| 806 | if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1) | 867 | if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1) |
| 807 | cp->timeperframe.denominator /= (clkrc & CLK_SCALE); | 868 | cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE); |
| 808 | return 0; | 869 | return 0; |
| 809 | } | 870 | } |
| 810 | 871 | ||
| @@ -812,19 +873,14 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
| 812 | { | 873 | { |
| 813 | struct v4l2_captureparm *cp = &parms->parm.capture; | 874 | struct v4l2_captureparm *cp = &parms->parm.capture; |
| 814 | struct v4l2_fract *tpf = &cp->timeperframe; | 875 | struct v4l2_fract *tpf = &cp->timeperframe; |
| 815 | unsigned char clkrc; | 876 | struct ov7670_info *info = to_state(sd); |
| 816 | int ret, div; | 877 | int div; |
| 817 | 878 | ||
| 818 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 879 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| 819 | return -EINVAL; | 880 | return -EINVAL; |
| 820 | if (cp->extendedmode != 0) | 881 | if (cp->extendedmode != 0) |
| 821 | return -EINVAL; | 882 | return -EINVAL; |
| 822 | /* | 883 | |
| 823 | * CLKRC has a reserved bit, so let's preserve it. | ||
| 824 | */ | ||
| 825 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); | ||
| 826 | if (ret < 0) | ||
| 827 | return ret; | ||
| 828 | if (tpf->numerator == 0 || tpf->denominator == 0) | 884 | if (tpf->numerator == 0 || tpf->denominator == 0) |
| 829 | div = 1; /* Reset to full rate */ | 885 | div = 1; /* Reset to full rate */ |
| 830 | else | 886 | else |
| @@ -833,10 +889,10 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
| 833 | div = 1; | 889 | div = 1; |
| 834 | else if (div > CLK_SCALE) | 890 | else if (div > CLK_SCALE) |
| 835 | div = CLK_SCALE; | 891 | div = CLK_SCALE; |
| 836 | clkrc = (clkrc & 0x80) | div; | 892 | info->clkrc = (info->clkrc & 0x80) | div; |
| 837 | tpf->numerator = 1; | 893 | tpf->numerator = 1; |
| 838 | tpf->denominator = OV7670_FRAME_RATE/div; | 894 | tpf->denominator = OV7670_FRAME_RATE/div; |
| 839 | return ov7670_write(sd, REG_CLKRC, clkrc); | 895 | return ov7670_write(sd, REG_CLKRC, info->clkrc); |
| 840 | } | 896 | } |
| 841 | 897 | ||
| 842 | 898 | ||
| @@ -1115,6 +1171,140 @@ static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) | |||
| 1115 | return ret; | 1171 | return ret; |
| 1116 | } | 1172 | } |
| 1117 | 1173 | ||
| 1174 | /* | ||
| 1175 | * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes | ||
| 1176 | * the data sheet, the VREF parts should be the most significant, but | ||
| 1177 | * experience shows otherwise. There seems to be little value in | ||
| 1178 | * messing with the VREF bits, so we leave them alone. | ||
| 1179 | */ | ||
| 1180 | static int ov7670_g_gain(struct v4l2_subdev *sd, __s32 *value) | ||
| 1181 | { | ||
| 1182 | int ret; | ||
| 1183 | unsigned char gain; | ||
| 1184 | |||
| 1185 | ret = ov7670_read(sd, REG_GAIN, &gain); | ||
| 1186 | *value = gain; | ||
| 1187 | return ret; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | static int ov7670_s_gain(struct v4l2_subdev *sd, int value) | ||
| 1191 | { | ||
| 1192 | int ret; | ||
| 1193 | unsigned char com8; | ||
| 1194 | |||
| 1195 | ret = ov7670_write(sd, REG_GAIN, value & 0xff); | ||
| 1196 | /* Have to turn off AGC as well */ | ||
| 1197 | if (ret == 0) { | ||
| 1198 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
| 1199 | ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC); | ||
| 1200 | } | ||
| 1201 | return ret; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | /* | ||
| 1205 | * Tweak autogain. | ||
| 1206 | */ | ||
| 1207 | static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value) | ||
| 1208 | { | ||
| 1209 | int ret; | ||
| 1210 | unsigned char com8; | ||
| 1211 | |||
| 1212 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
| 1213 | *value = (com8 & COM8_AGC) != 0; | ||
| 1214 | return ret; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | ||
| 1218 | { | ||
| 1219 | int ret; | ||
| 1220 | unsigned char com8; | ||
| 1221 | |||
| 1222 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
| 1223 | if (ret == 0) { | ||
| 1224 | if (value) | ||
| 1225 | com8 |= COM8_AGC; | ||
| 1226 | else | ||
| 1227 | com8 &= ~COM8_AGC; | ||
| 1228 | ret = ov7670_write(sd, REG_COM8, com8); | ||
| 1229 | } | ||
| 1230 | return ret; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | /* | ||
| 1234 | * Exposure is spread all over the place: top 6 bits in AECHH, middle | ||
| 1235 | * 8 in AECH, and two stashed in COM1 just for the hell of it. | ||
| 1236 | */ | ||
| 1237 | static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value) | ||
| 1238 | { | ||
| 1239 | int ret; | ||
| 1240 | unsigned char com1, aech, aechh; | ||
| 1241 | |||
| 1242 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
| 1243 | ov7670_read(sd, REG_AECH, &aech) + | ||
| 1244 | ov7670_read(sd, REG_AECHH, &aechh); | ||
| 1245 | *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03); | ||
| 1246 | return ret; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | ||
| 1250 | { | ||
| 1251 | int ret; | ||
| 1252 | unsigned char com1, com8, aech, aechh; | ||
| 1253 | |||
| 1254 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
| 1255 | ov7670_read(sd, REG_COM8, &com8); | ||
| 1256 | ov7670_read(sd, REG_AECHH, &aechh); | ||
| 1257 | if (ret) | ||
| 1258 | return ret; | ||
| 1259 | |||
| 1260 | com1 = (com1 & 0xfc) | (value & 0x03); | ||
| 1261 | aech = (value >> 2) & 0xff; | ||
| 1262 | aechh = (aechh & 0xc0) | ((value >> 10) & 0x3f); | ||
| 1263 | ret = ov7670_write(sd, REG_COM1, com1) + | ||
| 1264 | ov7670_write(sd, REG_AECH, aech) + | ||
| 1265 | ov7670_write(sd, REG_AECHH, aechh); | ||
| 1266 | /* Have to turn off AEC as well */ | ||
| 1267 | if (ret == 0) | ||
| 1268 | ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC); | ||
| 1269 | return ret; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | /* | ||
| 1273 | * Tweak autoexposure. | ||
| 1274 | */ | ||
| 1275 | static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value) | ||
| 1276 | { | ||
| 1277 | int ret; | ||
| 1278 | unsigned char com8; | ||
| 1279 | enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value; | ||
| 1280 | |||
| 1281 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
| 1282 | if (com8 & COM8_AEC) | ||
| 1283 | *atype = V4L2_EXPOSURE_AUTO; | ||
| 1284 | else | ||
| 1285 | *atype = V4L2_EXPOSURE_MANUAL; | ||
| 1286 | return ret; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, | ||
| 1290 | enum v4l2_exposure_auto_type value) | ||
| 1291 | { | ||
| 1292 | int ret; | ||
| 1293 | unsigned char com8; | ||
| 1294 | |||
| 1295 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
| 1296 | if (ret == 0) { | ||
| 1297 | if (value == V4L2_EXPOSURE_AUTO) | ||
| 1298 | com8 |= COM8_AEC; | ||
| 1299 | else | ||
| 1300 | com8 &= ~COM8_AEC; | ||
| 1301 | ret = ov7670_write(sd, REG_COM8, com8); | ||
| 1302 | } | ||
| 1303 | return ret; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | |||
| 1307 | |||
| 1118 | static int ov7670_queryctrl(struct v4l2_subdev *sd, | 1308 | static int ov7670_queryctrl(struct v4l2_subdev *sd, |
| 1119 | struct v4l2_queryctrl *qc) | 1309 | struct v4l2_queryctrl *qc) |
| 1120 | { | 1310 | { |
| @@ -1131,6 +1321,14 @@ static int ov7670_queryctrl(struct v4l2_subdev *sd, | |||
| 1131 | return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); | 1321 | return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); |
| 1132 | case V4L2_CID_HUE: | 1322 | case V4L2_CID_HUE: |
| 1133 | return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); | 1323 | return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); |
| 1324 | case V4L2_CID_GAIN: | ||
| 1325 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
| 1326 | case V4L2_CID_AUTOGAIN: | ||
| 1327 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
| 1328 | case V4L2_CID_EXPOSURE: | ||
| 1329 | return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500); | ||
| 1330 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 1331 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
| 1134 | } | 1332 | } |
| 1135 | return -EINVAL; | 1333 | return -EINVAL; |
| 1136 | } | 1334 | } |
| @@ -1150,6 +1348,14 @@ static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 1150 | return ov7670_g_vflip(sd, &ctrl->value); | 1348 | return ov7670_g_vflip(sd, &ctrl->value); |
| 1151 | case V4L2_CID_HFLIP: | 1349 | case V4L2_CID_HFLIP: |
| 1152 | return ov7670_g_hflip(sd, &ctrl->value); | 1350 | return ov7670_g_hflip(sd, &ctrl->value); |
| 1351 | case V4L2_CID_GAIN: | ||
| 1352 | return ov7670_g_gain(sd, &ctrl->value); | ||
| 1353 | case V4L2_CID_AUTOGAIN: | ||
| 1354 | return ov7670_g_autogain(sd, &ctrl->value); | ||
| 1355 | case V4L2_CID_EXPOSURE: | ||
| 1356 | return ov7670_g_exp(sd, &ctrl->value); | ||
| 1357 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 1358 | return ov7670_g_autoexp(sd, &ctrl->value); | ||
| 1153 | } | 1359 | } |
| 1154 | return -EINVAL; | 1360 | return -EINVAL; |
| 1155 | } | 1361 | } |
| @@ -1169,6 +1375,15 @@ static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 1169 | return ov7670_s_vflip(sd, ctrl->value); | 1375 | return ov7670_s_vflip(sd, ctrl->value); |
| 1170 | case V4L2_CID_HFLIP: | 1376 | case V4L2_CID_HFLIP: |
| 1171 | return ov7670_s_hflip(sd, ctrl->value); | 1377 | return ov7670_s_hflip(sd, ctrl->value); |
| 1378 | case V4L2_CID_GAIN: | ||
| 1379 | return ov7670_s_gain(sd, ctrl->value); | ||
| 1380 | case V4L2_CID_AUTOGAIN: | ||
| 1381 | return ov7670_s_autogain(sd, ctrl->value); | ||
| 1382 | case V4L2_CID_EXPOSURE: | ||
| 1383 | return ov7670_s_exp(sd, ctrl->value); | ||
| 1384 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 1385 | return ov7670_s_autoexp(sd, | ||
| 1386 | (enum v4l2_exposure_auto_type) ctrl->value); | ||
| 1172 | } | 1387 | } |
| 1173 | return -EINVAL; | 1388 | return -EINVAL; |
| 1174 | } | 1389 | } |
| @@ -1268,6 +1483,7 @@ static int ov7670_probe(struct i2c_client *client, | |||
| 1268 | 1483 | ||
| 1269 | info->fmt = &ov7670_formats[0]; | 1484 | info->fmt = &ov7670_formats[0]; |
| 1270 | info->sat = 128; /* Review this */ | 1485 | info->sat = 128; /* Review this */ |
| 1486 | info->clkrc = 1; /* 30fps */ | ||
| 1271 | 1487 | ||
| 1272 | return 0; | 1488 | return 0; |
| 1273 | } | 1489 | } |
