14763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén/*
24763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Driver for the ov7660 sensor
34763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén *
44763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2009 Erik Andrén
54763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
64763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
74763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén *
84763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Portions of code to USB interface and ALi driver software,
94763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (c) 2006 Willem Duinker
104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * v4l2 interface modeled after the V4L2 driver
114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * for SN9C10x PC Camera Controllers
124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén *
134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * This program is free software; you can redistribute it and/or
144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * modify it under the terms of the GNU General Public License as
154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * published by the Free Software Foundation, version 2.
164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén *
174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén */
184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
19bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches
214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén#include "m5602_ov7660.h"
224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
23c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
26f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 *val);
27f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
28f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 val);
29456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
30456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
317c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrénstatic int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
327c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrénstatic int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
33a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
34a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
35a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
36a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
37c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
38f0ecba96e76295792a0b1ee2e03b505562e7b9f3Tobias Klauserstatic const struct ctrl ov7660_ctrls[] = {
39c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén#define GAIN_IDX 1
40c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	{
41c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		{
42c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.id		= V4L2_CID_GAIN,
43c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.type		= V4L2_CTRL_TYPE_INTEGER,
44c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.name		= "gain",
45c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.minimum	= 0x00,
46c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.maximum	= 0xff,
47c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.step		= 0x1,
4872b79747a88f1ffcb6689cedacc01235bb545cd6Erik Andrén			.default_value	= OV7660_DEFAULT_GAIN,
49c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.flags		= V4L2_CTRL_FLAG_SLIDER
50c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		},
51c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		.set = ov7660_set_gain,
52c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		.get = ov7660_get_gain
53c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	},
54cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén#define BLUE_BALANCE_IDX 2
5568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén#define RED_BALANCE_IDX 3
56f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén#define AUTO_WHITE_BALANCE_IDX 4
57f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	{
58f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		{
59780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.id		= V4L2_CID_AUTO_WHITE_BALANCE,
60780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.type		= V4L2_CTRL_TYPE_BOOLEAN,
61780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.name		= "auto white balance",
62780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.minimum	= 0,
63780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.maximum	= 1,
64780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.step		= 1,
65780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.default_value	= 1
66f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		},
67f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		.set = ov7660_set_auto_white_balance,
68f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		.get = ov7660_get_auto_white_balance
69f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	},
70456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén#define AUTO_GAIN_CTRL_IDX 5
71456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	{
72456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		{
73780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.id		= V4L2_CID_AUTOGAIN,
74780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.type		= V4L2_CTRL_TYPE_BOOLEAN,
75780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.name		= "auto gain control",
76780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.minimum	= 0,
77780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.maximum	= 1,
78780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.step		= 1,
79780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.default_value	= 1
80456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		},
81456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		.set = ov7660_set_auto_gain,
82456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		.get = ov7660_get_auto_gain
83456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	},
847c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén#define AUTO_EXPOSURE_IDX 6
857c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	{
867c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		{
87780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.id		= V4L2_CID_EXPOSURE_AUTO,
88780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.type		= V4L2_CTRL_TYPE_BOOLEAN,
89780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.name		= "auto exposure",
90780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.minimum	= 0,
91780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.maximum	= 1,
92780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.step		= 1,
93780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.default_value	= 1
947c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		},
957c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		.set = ov7660_set_auto_exposure,
967c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		.get = ov7660_get_auto_exposure
97a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	},
98a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén#define HFLIP_IDX 7
99a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	{
100a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		{
101780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.id		= V4L2_CID_HFLIP,
102780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.type		= V4L2_CTRL_TYPE_BOOLEAN,
103780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.name		= "horizontal flip",
104780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.minimum	= 0,
105780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.maximum	= 1,
106780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.step		= 1,
107780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.default_value	= 0
108a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		},
109a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		.set = ov7660_set_hflip,
110a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		.get = ov7660_get_hflip
111a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	},
112a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén#define VFLIP_IDX 8
113a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	{
114a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		{
115780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.id		= V4L2_CID_VFLIP,
116780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.type		= V4L2_CTRL_TYPE_BOOLEAN,
117780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.name		= "vertical flip",
118780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.minimum	= 0,
119780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.maximum	= 1,
120780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.step		= 1,
121780e312175f688ab5ab6124c91d46fa2b9afe2d2Jean-François Moine			.default_value	= 0
122a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		},
123a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		.set = ov7660_set_vflip,
124a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		.get = ov7660_get_vflip
125a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	},
126a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
127c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén};
1284763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1294763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic struct v4l2_pix_format ov7660_modes[] = {
1304763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	{
1314763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		640,
1324763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		480,
1334763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		V4L2_PIX_FMT_SBGGR8,
1344763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		V4L2_FIELD_NONE,
1354763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.sizeimage =
1364763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén			640 * 480,
1374763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.bytesperline = 640,
1384763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.colorspace = V4L2_COLORSPACE_SRGB,
1394763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.priv = 0
1404763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
1414763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén};
1424763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1434763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd);
1444763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1454763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_probe(struct sd *sd)
1464763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
147ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	int err = 0, i;
148ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	u8 prod_id = 0, ver_id = 0;
149ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
150ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	s32 *sensor_settings;
151ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
152ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (force_sensor) {
153ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		if (force_sensor == OV7660_SENSOR) {
154bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches			pr_info("Forcing an %s sensor\n", ov7660.name);
155ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			goto sensor_found;
156ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		}
157ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		/* If we want to force another sensor,
158ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		don't try to probe this one */
159ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
160ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
161ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
162ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	/* Do the preinit */
163ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
164ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		u8 data[2];
165ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
166ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		if (preinit_ov7660[i][0] == BRIDGE) {
167ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			err = m5602_write_bridge(sd,
168ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][1],
169ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][2]);
170ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		} else {
171ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			data[0] = preinit_ov7660[i][2];
172ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			err = m5602_write_sensor(sd,
173ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][1], data, 1);
174ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		}
175ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
176ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (err < 0)
177ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return err;
178ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
179ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
180ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
181ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
182ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
183ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
184ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
185bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches	pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id);
186ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
187ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if ((prod_id == 0x76) && (ver_id == 0x60)) {
188bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches		pr_info("Detected a ov7660 sensor\n");
189ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		goto sensor_found;
190ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
1914763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return -ENODEV;
192ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
193ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrénsensor_found:
194c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sensor_settings = kmalloc(
195c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
196c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	if (!sensor_settings)
197c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		return -ENOMEM;
198c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
199ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->gspca_dev.cam.cam_mode = ov7660_modes;
200ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
201ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->desc->ctrls = ov7660_ctrls;
202ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
203ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
204ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
205ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
206ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->sensor_priv = sensor_settings;
207ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
208ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	return 0;
2094763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
2114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_init(struct sd *sd)
2124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
2130364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	int i, err = 0;
214c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
2150364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
2160364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	/* Init the sensor */
217eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén	for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
2180364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		u8 data[2];
2190364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
220eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén		if (init_ov7660[i][0] == BRIDGE) {
2210364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén			err = m5602_write_bridge(sd,
222eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén				init_ov7660[i][1],
223eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén				init_ov7660[i][2]);
2240364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		} else {
225eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén			data[0] = init_ov7660[i][2];
2260364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén			err = m5602_write_sensor(sd,
227eb3678fbe5d5be8315628885b7c93228c97a433dErik Andrén				init_ov7660[i][1], data, 1);
2280364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		}
2290364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	}
2300364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
2310364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	if (dump_sensor)
2320364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		ov7660_dump_registers(sd);
2330364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
234c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
235c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	if (err < 0)
236c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		return err;
237c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
238f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = ov7660_set_auto_white_balance(&sd->gspca_dev,
239f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		sensor_settings[AUTO_WHITE_BALANCE_IDX]);
24036e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén	if (err < 0)
24136e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén		return err;
24236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén
243456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	err = ov7660_set_auto_gain(&sd->gspca_dev,
244456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		sensor_settings[AUTO_GAIN_CTRL_IDX]);
245456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	if (err < 0)
246456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		return err;
247456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
2487c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	err = ov7660_set_auto_exposure(&sd->gspca_dev,
2497c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		sensor_settings[AUTO_EXPOSURE_IDX]);
2507c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	if (err < 0)
2517c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		return err;
252a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	err = ov7660_set_hflip(&sd->gspca_dev,
253a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		sensor_settings[HFLIP_IDX]);
254a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	if (err < 0)
255a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		return err;
256a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
257a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	err = ov7660_set_vflip(&sd->gspca_dev,
258a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		sensor_settings[VFLIP_IDX]);
259f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
2600364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	return err;
2614763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2624763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
2634763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_start(struct sd *sd)
2644763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
2654763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return 0;
2664763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2674763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
2684763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_stop(struct sd *sd)
2694763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
2704763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return 0;
2714763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2724763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
273c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénvoid ov7660_disconnect(struct sd *sd)
274c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
275c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	ov7660_stop(sd);
276c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
277c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sd->sensor = NULL;
278c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	kfree(sd->sensor_priv);
279c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
280c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
281c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
282c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
283c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
284c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
285c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
286c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	*val = sensor_settings[GAIN_IDX];
287c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	PDEBUG(D_V4L2, "Read gain %d", *val);
288c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	return 0;
289c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
290c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
291c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
292c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
293c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	int err;
294c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	u8 i2c_data;
295c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
296c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
297c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
298c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	PDEBUG(D_V4L2, "Setting gain to %d", val);
299c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
300c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sensor_settings[GAIN_IDX] = val;
301c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
302c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
303c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	return err;
304c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
3054763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
30668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
307f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
308f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 *val)
309f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{
310f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
311f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
312f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
313f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
314f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	return 0;
315f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén}
316f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
317f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
318f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 val)
319f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{
320f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	int err;
321f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	u8 i2c_data;
322f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
323f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
324f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
325f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	PDEBUG(D_V4L2, "Set auto white balance to %d", val);
326f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
327f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
328f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
329f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	if (err < 0)
330f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		return err;
331f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
332f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
333f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
334f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
335f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	return err;
336f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén}
337f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
338456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
339456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{
340456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
341456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	s32 *sensor_settings = sd->sensor_priv;
342456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
343456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
344456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	PDEBUG(D_V4L2, "Read auto gain control %d", *val);
345456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	return 0;
346456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén}
347456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
348456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
349456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{
350456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	int err;
351456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	u8 i2c_data;
352456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
353456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	s32 *sensor_settings = sd->sensor_priv;
354456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
355456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	PDEBUG(D_V4L2, "Set auto gain control to %d", val);
356456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
357456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
358456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
359456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	if (err < 0)
360456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		return err;
361456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
362456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
363456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
364456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
365456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén}
366456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
3677c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrénstatic int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
3687c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén{
3697c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
3707c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	s32 *sensor_settings = sd->sensor_priv;
3717c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3727c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	*val = sensor_settings[AUTO_EXPOSURE_IDX];
3737c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
3747c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	return 0;
3757c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén}
3767c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3777c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrénstatic int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
3787c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén				    __s32 val)
3797c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén{
3807c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	int err;
3817c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	u8 i2c_data;
3827c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
3837c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	s32 *sensor_settings = sd->sensor_priv;
3847c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3857c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
3867c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3877c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	sensor_settings[AUTO_EXPOSURE_IDX] = val;
3887c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
3897c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	if (err < 0)
3907c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén		return err;
3917c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3927c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
3937c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
3947c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén	return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
3957c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén}
3967c7ddf1638a45923ab053d1f7818c6d123148b4bErik Andrén
397a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
398a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén{
399a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
400a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
401a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
402a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	*val = sensor_settings[HFLIP_IDX];
403a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
404a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	return 0;
405a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén}
406a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
407a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
408a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén{
409a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	int err;
410a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	u8 i2c_data;
411a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
412a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
413a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
414a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
415a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
416a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	sensor_settings[HFLIP_IDX] = val;
417a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
418a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	i2c_data = ((val & 0x01) << 5) |
419a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		(sensor_settings[VFLIP_IDX] << 4);
420a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
421a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
422a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
423a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	return err;
424a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén}
425a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
426a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
427a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén{
428a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
429a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
430a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
431a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	*val = sensor_settings[VFLIP_IDX];
432a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	PDEBUG(D_V4L2, "Read vertical flip %d", *val);
433a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
434a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	return 0;
435a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén}
436a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
437a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrénstatic int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
438a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén{
439a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	int err;
440a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	u8 i2c_data;
441a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
442a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
443a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
444a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	PDEBUG(D_V4L2, "Set vertical flip to %d", val);
445a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	sensor_settings[VFLIP_IDX] = val;
446a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
447a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
448a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
449a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	if (err < 0)
450a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		return err;
451a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
452a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	/* When vflip is toggled we need to readjust the bridge hsync/vsync */
453a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	if (gspca_dev->streaming)
454a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén		err = ov7660_start(sd);
455a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
456a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén	return err;
457a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén}
458a66887d2ba2f829cbbc23a64e19a0b757b79c39eErik Andrén
4594763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd)
4604763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
4614763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	int address;
462bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches	pr_info("Dumping the ov7660 register state\n");
4634763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	for (address = 0; address < 0xa9; address++) {
4644763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 value;
4654763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &value, 1);
466bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches		pr_info("register 0x%x contains 0x%x\n", address, value);
4674763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
4684763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
469bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches	pr_info("ov7660 register state dump complete\n");
4704763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
471bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches	pr_info("Probing for which registers that are read/write\n");
4724763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	for (address = 0; address < 0xff; address++) {
4734763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 old_value, ctrl_value;
4744763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 test_value[2] = {0xff, 0xff};
4754763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4764763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &old_value, 1);
4774763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_write_sensor(sd, address, test_value, 1);
4784763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &ctrl_value, 1);
4794763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4804763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		if (ctrl_value == test_value[0])
481bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches			pr_info("register 0x%x is writeable\n", address);
4824763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		else
483bdfe91f411bd05392952efc1afdce8bda1923517Joe Perches			pr_info("register 0x%x is read only\n", address);
4844763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4854763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		/* Restore original value */
4864763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_write_sensor(sd, address, &old_value, 1);
4874763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
4884763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
489