m5602_ov7660.c revision 456ebe4e92063b92d2672da272bfc7ac70bd8bdd
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
194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén#include "m5602_ov7660.h"
204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
21c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
22c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val);
24cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val);
2568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_get_red_gain(struct gspca_dev *gspca_dev, __s32 *val);
2668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_set_red_gain(struct gspca_dev *gspca_dev, __s32 val);
27f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
28f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 *val);
29f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
30f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 val);
31456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
32456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
33f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
34c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
35c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénconst static struct ctrl ov7660_ctrls[] = {
36c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén#define GAIN_IDX 1
37c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	{
38c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		{
39c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.id		= V4L2_CID_GAIN,
40c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.type		= V4L2_CTRL_TYPE_INTEGER,
41c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.name		= "gain",
42c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.minimum	= 0x00,
43c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.maximum	= 0xff,
44c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.step		= 0x1,
4572b79747a88f1ffcb6689cedacc01235bb545cd6Erik Andrén			.default_value	= OV7660_DEFAULT_GAIN,
46c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén			.flags		= V4L2_CTRL_FLAG_SLIDER
47c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		},
48c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		.set = ov7660_set_gain,
49c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		.get = ov7660_get_gain
50c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	},
51cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén#define BLUE_BALANCE_IDX 2
52cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	{
53cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén		{
54cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.id		= V4L2_CID_BLUE_BALANCE,
55cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.type		= V4L2_CTRL_TYPE_INTEGER,
56cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.name		= "blue balance",
57cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.minimum	= 0x00,
58cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.maximum	= 0x7f,
59cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.step		= 0x1,
60cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.default_value	= OV7660_DEFAULT_BLUE_GAIN,
61cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén			.flags		= V4L2_CTRL_FLAG_SLIDER
62cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén		},
63cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén		.set = ov7660_set_blue_gain,
64cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén		.get = ov7660_get_blue_gain
65cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	},
6668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén#define RED_BALANCE_IDX 3
6768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	{
6868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén		{
6968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.id		= V4L2_CID_RED_BALANCE,
7068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.type		= V4L2_CTRL_TYPE_INTEGER,
7168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.name		= "red balance",
7268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.minimum	= 0x00,
7368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.maximum	= 0x7f,
7468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.step		= 0x1,
7568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.default_value	= OV7660_DEFAULT_RED_GAIN,
7668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén			.flags		= V4L2_CTRL_FLAG_SLIDER
7768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén		},
7868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén		.set = ov7660_set_red_gain,
7968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén		.get = ov7660_get_red_gain
8068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	},
81f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén#define AUTO_WHITE_BALANCE_IDX 4
82f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	{
83f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		{
84f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.id 		= V4L2_CID_AUTO_WHITE_BALANCE,
85f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
86f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.name 		= "auto white balance",
87f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.minimum 	= 0,
88f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.maximum 	= 1,
89f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.step 		= 1,
90f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén			.default_value 	= 1
91f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		},
92f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		.set = ov7660_set_auto_white_balance,
93f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		.get = ov7660_get_auto_white_balance
94f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	},
95456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén#define AUTO_GAIN_CTRL_IDX 5
96456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	{
97456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		{
98456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.id 		= V4L2_CID_AUTOGAIN,
99456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.type 		= V4L2_CTRL_TYPE_BOOLEAN,
100456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.name 		= "auto gain control",
101456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.minimum 	= 0,
102456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.maximum 	= 1,
103456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.step 		= 1,
104456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén			.default_value 	= 1
105456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		},
106456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		.set = ov7660_set_auto_gain,
107456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		.get = ov7660_get_auto_gain
108456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	},
109c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén};
1104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic struct v4l2_pix_format ov7660_modes[] = {
1124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	{
1134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		640,
1144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		480,
1154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		V4L2_PIX_FMT_SBGGR8,
1164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		V4L2_FIELD_NONE,
1174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.sizeimage =
1184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén			640 * 480,
1194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.bytesperline = 640,
1204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.colorspace = V4L2_COLORSPACE_SRGB,
1214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		.priv = 0
1224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
1234763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén};
1244763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1254763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd);
1264763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1274763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_probe(struct sd *sd)
1284763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
129ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	int err = 0, i;
130ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	u8 prod_id = 0, ver_id = 0;
131ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
132ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	s32 *sensor_settings;
133ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
134ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (force_sensor) {
135ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		if (force_sensor == OV7660_SENSOR) {
136ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			info("Forcing an %s sensor", ov7660.name);
137ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			goto sensor_found;
138ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		}
139ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		/* If we want to force another sensor,
140ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		don't try to probe this one */
141ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
142ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
143ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
144ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	/* Do the preinit */
145ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
146ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		u8 data[2];
147ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
148ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		if (preinit_ov7660[i][0] == BRIDGE) {
149ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			err = m5602_write_bridge(sd,
150ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][1],
151ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][2]);
152ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		} else {
153ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			data[0] = preinit_ov7660[i][2];
154ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén			err = m5602_write_sensor(sd,
155ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén				preinit_ov7660[i][1], data, 1);
156ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		}
157ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
158ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (err < 0)
159ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return err;
160ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
161ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
162ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
163ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
164ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
165ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		return -ENODEV;
166ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
167ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	info("Sensor reported 0x%x%x", prod_id, ver_id);
168ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
169ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	if ((prod_id == 0x76) && (ver_id == 0x60)) {
170ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		info("Detected a ov7660 sensor");
171ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		goto sensor_found;
172ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	}
1734763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return -ENODEV;
174ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
175ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrénsensor_found:
176c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sensor_settings = kmalloc(
177c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
178c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	if (!sensor_settings)
179c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		return -ENOMEM;
180c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
181ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->gspca_dev.cam.cam_mode = ov7660_modes;
182ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
183ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->desc->ctrls = ov7660_ctrls;
184ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
185ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
186ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
187ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén		sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
188ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	sd->sensor_priv = sensor_settings;
189ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén
190ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén	return 0;
1914763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
1924763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
1934763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_init(struct sd *sd)
1944763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
1950364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	int i, err = 0;
196c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
1970364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
1980364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	/* Init the sensor */
1990364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
2000364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		u8 data[2];
2010364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
2020364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		if (init_ov7660[i][0] == BRIDGE) {
2030364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén			err = m5602_write_bridge(sd,
2040364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén				init_ov7660[i][1],
2050364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén				init_ov7660[i][2]);
2060364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		} else {
2070364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén			data[0] = init_ov7660[i][2];
2080364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén			err = m5602_write_sensor(sd,
2090364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén					init_ov7660[i][1], data, 1);
2100364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		}
2110364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	}
2120364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
2130364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	if (dump_sensor)
2140364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén		ov7660_dump_registers(sd);
2150364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén
216c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
217c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	if (err < 0)
218c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén		return err;
219c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
220f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = ov7660_set_auto_white_balance(&sd->gspca_dev,
221f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		sensor_settings[AUTO_WHITE_BALANCE_IDX]);
22236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén	if (err < 0)
22336e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén		return err;
22436e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén
225456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	err = ov7660_set_auto_gain(&sd->gspca_dev,
226456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		sensor_settings[AUTO_GAIN_CTRL_IDX]);
227456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	if (err < 0)
228456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		return err;
229456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
23036e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén	err = ov7660_set_blue_gain(&sd->gspca_dev,
23136e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén		sensor_settings[BLUE_BALANCE_IDX]);
23236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén	if (err < 0)
23336e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén		return err;
23436e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén
23536e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén	err = ov7660_set_red_gain(&sd->gspca_dev,
23636e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén		sensor_settings[RED_BALANCE_IDX]);
237f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
2380364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén	return err;
2394763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2404763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
2414763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_start(struct sd *sd)
2424763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
2434763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return 0;
2444763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2454763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
2464763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_stop(struct sd *sd)
2474763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
2484763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	return 0;
2494763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
2504763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
251c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénvoid ov7660_disconnect(struct sd *sd)
252c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
253c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	ov7660_stop(sd);
254c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
255c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sd->sensor = NULL;
256c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	kfree(sd->sensor_priv);
257c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
258c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
259c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
260c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
261c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
262c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
263c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
264c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	*val = sensor_settings[GAIN_IDX];
265c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	PDEBUG(D_V4L2, "Read gain %d", *val);
266c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	return 0;
267c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
268c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
269c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
270c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{
271c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	int err;
272c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	u8 i2c_data;
273c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
274c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	s32 *sensor_settings = sd->sensor_priv;
275c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
276c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	PDEBUG(D_V4L2, "Setting gain to %d", val);
277c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
278c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	sensor_settings[GAIN_IDX] = val;
279c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén
280c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
281c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén	return err;
282c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}
2834763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
284cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val)
285cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{
286cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	struct sd *sd = (struct sd *) gspca_dev;
287cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	s32 *sensor_settings = sd->sensor_priv;
288cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
289cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	*val = sensor_settings[BLUE_BALANCE_IDX];
290cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	PDEBUG(D_V4L2, "Read blue balance %d", *val);
291cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	return 0;
292cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén}
293cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
294cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val)
295cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{
296cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	int err;
297cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	u8 i2c_data;
298cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	struct sd *sd = (struct sd *) gspca_dev;
299cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	s32 *sensor_settings = sd->sensor_priv;
300cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
301cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	PDEBUG(D_V4L2, "Setting blue balance to %d", val);
302cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
303cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	sensor_settings[BLUE_BALANCE_IDX] = val;
304cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
305cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	err = m5602_write_sensor(sd, OV7660_BLUE_GAIN, &i2c_data, 1);
306cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén	return err;
307cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén}
308cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén
30968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_get_red_gain(struct gspca_dev *gspca_dev, __s32 *val)
31068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{
31168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	struct sd *sd = (struct sd *) gspca_dev;
31268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	s32 *sensor_settings = sd->sensor_priv;
31368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
31468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	*val = sensor_settings[RED_BALANCE_IDX];
31568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	PDEBUG(D_V4L2, "Read red balance %d", *val);
31668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	return 0;
31768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén}
31868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
31968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_set_red_gain(struct gspca_dev *gspca_dev, __s32 val)
32068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{
32168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	int err;
32268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	u8 i2c_data;
32368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	struct sd *sd = (struct sd *) gspca_dev;
32468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	s32 *sensor_settings = sd->sensor_priv;
32568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
32668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	PDEBUG(D_V4L2, "Setting red balance to %d", val);
32768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
32868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	sensor_settings[RED_BALANCE_IDX] = val;
32968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
33068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	err = m5602_write_sensor(sd, OV7660_RED_GAIN, &i2c_data, 1);
33168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén	return err;
33268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén}
33368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén
334f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
335f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 *val)
336f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{
337f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
338f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
339f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
340f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
341f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	return 0;
342f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén}
343f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
344f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
345f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén					 __s32 val)
346f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{
347f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	int err;
348f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	u8 i2c_data;
349f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
350f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	s32 *sensor_settings = sd->sensor_priv;
351f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
352f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	PDEBUG(D_V4L2, "Set auto white balance to %d", val);
353f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
354f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
355f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
356f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	if (err < 0)
357f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén		return err;
358f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
359f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
360f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
361f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
362f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén	return err;
363f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén}
364f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén
365456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
366456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{
367456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
368456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	s32 *sensor_settings = sd->sensor_priv;
369456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
370456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
371456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	PDEBUG(D_V4L2, "Read auto gain control %d", *val);
372456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	return 0;
373456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén}
374456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
375456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
376456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{
377456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	int err;
378456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	u8 i2c_data;
379456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	struct sd *sd = (struct sd *) gspca_dev;
380456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	s32 *sensor_settings = sd->sensor_priv;
381456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
382456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	PDEBUG(D_V4L2, "Set auto gain control to %d", val);
383456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
384456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
385456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
386456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	if (err < 0)
387456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén		return err;
388456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
389456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
390456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
391456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén	return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
392456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén}
393456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén
3944763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd)
3954763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{
3964763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	int address;
3974763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	info("Dumping the ov7660 register state");
3984763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	for (address = 0; address < 0xa9; address++) {
3994763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 value;
4004763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &value, 1);
4014763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		info("register 0x%x contains 0x%x",
4024763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		     address, value);
4034763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
4044763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4054763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	info("ov7660 register state dump complete");
4064763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4074763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	info("Probing for which registers that are read/write");
4084763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	for (address = 0; address < 0xff; address++) {
4094763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 old_value, ctrl_value;
4104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		u8 test_value[2] = {0xff, 0xff};
4114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &old_value, 1);
4134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_write_sensor(sd, address, test_value, 1);
4144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_read_sensor(sd, address, &ctrl_value, 1);
4154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		if (ctrl_value == test_value[0])
4174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén			info("register 0x%x is writeable", address);
4184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		else
4194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén			info("register 0x%x is read only", address);
4204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén
4214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		/* Restore original value */
4224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén		m5602_write_sensor(sd, address, &old_value, 1);
4234763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén	}
4244763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}
425