11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************
2f327ebbd004fb2f08291ca4c6637f5f27319683cLuca Risolia * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera  *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Controllers                                                             *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                                         *
5f327ebbd004fb2f08291ca4c6637f5f27319683cLuca Risolia * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                                         *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify    *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by    *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or       *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.                                     *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                                         *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,         *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.                            *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                                         *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License       *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software             *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ***************************************************************************/
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sn9c102_sensor.h"
23d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuil#include "sn9c102_devtable.h"
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tas5110c1b_init(struct sn9c102_device* cam)
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30c680dd603857d7218b84751e9f6f0654bbfbefa2Trent Piepho	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01},
31c680dd603857d7218b84751e9f6f0654bbfbefa2Trent Piepho				       {0x00, 0x10}, {0x00, 0x11},
32c680dd603857d7218b84751e9f6f0654bbfbefa2Trent Piepho				       {0x0a, 0x14}, {0x60, 0x17},
33c680dd603857d7218b84751e9f6f0654bbfbefa2Trent Piepho				       {0x06, 0x18}, {0xfb, 0x19});
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_i2c_write(cam, 0xc0, 0x80);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehabstatic int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
42d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab			       const struct v4l2_control* ctrl)
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ctrl->id) {
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case V4L2_CID_GAIN:
48b9df978f1974fea373741367b5d79a2ed3b7dcf9Luca Risolia		err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err ? -EIO : 0;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehabstatic int tas5110c1b_set_crop(struct sn9c102_device* cam,
59d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab			       const struct v4l2_rect* rect)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
61f327ebbd004fb2f08291ca4c6637f5f27319683cLuca Risolia	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_write_reg(cam, h_start, 0x12);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_write_reg(cam, v_start, 0x13);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Don't change ! */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_write_reg(cam, 0x14, 0x1a);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_write_reg(cam, 0x0a, 0x1b);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehabstatic int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
79d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab				     const struct v4l2_pix_format* pix)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err += sn9c102_write_reg(cam, 0x2b, 0x19);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err += sn9c102_write_reg(cam, 0xfb, 0x19);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92480b55c26e2f6408e86f22a69fcecc29e019e819Luca Risoliastatic const struct sn9c102_sensor tas5110c1b = {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "TAS5110C1B",
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
95f423b9a86a6dd3d2bc08d78f4d21525a14c40a6bLuca Risolia	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sysfs_ops = SN9C102_I2C_WRITE,
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.frequency = SN9C102_I2C_100KHZ,
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.interface = SN9C102_I2C_3WIRES,
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init = &tas5110c1b_init,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.qctrl = {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.id = V4L2_CID_GAIN,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.type = V4L2_CTRL_TYPE_INTEGER,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.name = "global gain",
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.minimum = 0x00,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.maximum = 0xf6,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.step = 0x01,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.default_value = 0x40,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.flags = 0,
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		},
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_ctrl = &tas5110c1b_set_ctrl,
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cropcap = {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.bounds = {
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.left = 0,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.top = 0,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.width = 352,
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.height = 288,
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		},
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.defrect = {
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.left = 0,
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.top = 0,
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.width = 352,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			.height = 288,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		},
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_crop = &tas5110c1b_set_crop,
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pix_format = {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.width = 352,
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.height = 288,
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.pixelformat = V4L2_PIX_FMT_SBGGR8,
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.priv = 8,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_pix_format = &tas5110c1b_set_pix_format
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1402ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia	const struct usb_device_id tas5110c1b_id_table[] = {
1412ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia		{ USB_DEVICE(0x0c45, 0x6001), },
1422ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia		{ USB_DEVICE(0x0c45, 0x6005), },
1432ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia		{ USB_DEVICE(0x0c45, 0x60ab), },
1442ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia		{ }
1452ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia	};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Sensor detection is based on USB pid/vid */
1482ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia	if (!sn9c102_match_id(cam, tas5110c1b_id_table))
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1512ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia	sn9c102_attach_sensor(cam, &tas5110c1b);
1522ffab02fea5880da284dc5511479b25a796a8deeLuca Risolia
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
155