aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/sn9c102
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/sn9c102
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/video/sn9c102')
-rw-r--r--drivers/media/video/sn9c102/Kconfig14
-rw-r--r--drivers/media/video/sn9c102/Makefile15
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h211
-rw-r--r--drivers/media/video/sn9c102/sn9c102_config.h86
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c3446
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h147
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131d.c264
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131r.c363
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0343.c352
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0360.c453
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mt9v111.c260
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c626
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c538
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas106b.c302
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c335
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h307
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110c1b.c154
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110d.c119
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5130d1b.c165
19 files changed, 8157 insertions, 0 deletions
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
new file mode 100644
index 00000000000..6ebaf2940d0
--- /dev/null
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -0,0 +1,14 @@
1config USB_SN9C102
2 tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)"
3 depends on VIDEO_V4L2
4 ---help---
5 This driver is DEPRECATED please use the gspca sonixb and
6 sonixj modules instead.
7
8 Say Y here if you want support for cameras based on SONiX SN9C101,
9 SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
10
11 See <file:Documentation/video4linux/sn9c102.txt> for more info.
12
13 To compile this driver as a module, choose M here: the
14 module will be called sn9c102.
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
new file mode 100644
index 00000000000..7ecd5a90c7c
--- /dev/null
+++ b/drivers/media/video/sn9c102/Makefile
@@ -0,0 +1,15 @@
1sn9c102-objs := sn9c102_core.o \
2 sn9c102_hv7131d.o \
3 sn9c102_hv7131r.o \
4 sn9c102_mi0343.o \
5 sn9c102_mi0360.o \
6 sn9c102_mt9v111.o \
7 sn9c102_ov7630.o \
8 sn9c102_ov7660.o \
9 sn9c102_pas106b.o \
10 sn9c102_pas202bcb.o \
11 sn9c102_tas5110c1b.o \
12 sn9c102_tas5110d.o \
13 sn9c102_tas5130d1b.o
14
15obj-$(CONFIG_USB_SN9C102) += sn9c102.o
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
new file mode 100644
index 00000000000..22ea211ab54
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -0,0 +1,211 @@
1/***************************************************************************
2 * V4L2 driver for SN9C1xx PC Camera Controllers *
3 * *
4 * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 ***************************************************************************/
20
21#ifndef _SN9C102_H_
22#define _SN9C102_H_
23
24#include <linux/usb.h>
25#include <linux/videodev2.h>
26#include <media/v4l2-common.h>
27#include <media/v4l2-ioctl.h>
28#include <linux/device.h>
29#include <linux/list.h>
30#include <linux/spinlock.h>
31#include <linux/time.h>
32#include <linux/wait.h>
33#include <linux/types.h>
34#include <linux/param.h>
35#include <linux/rwsem.h>
36#include <linux/mutex.h>
37#include <linux/string.h>
38#include <linux/stddef.h>
39#include <linux/kref.h>
40
41#include "sn9c102_config.h"
42#include "sn9c102_sensor.h"
43#include "sn9c102_devtable.h"
44
45
46enum sn9c102_frame_state {
47 F_UNUSED,
48 F_QUEUED,
49 F_GRABBING,
50 F_DONE,
51 F_ERROR,
52};
53
54struct sn9c102_frame_t {
55 void* bufmem;
56 struct v4l2_buffer buf;
57 enum sn9c102_frame_state state;
58 struct list_head frame;
59 unsigned long vma_use_count;
60};
61
62enum sn9c102_dev_state {
63 DEV_INITIALIZED = 0x01,
64 DEV_DISCONNECTED = 0x02,
65 DEV_MISCONFIGURED = 0x04,
66};
67
68enum sn9c102_io_method {
69 IO_NONE,
70 IO_READ,
71 IO_MMAP,
72};
73
74enum sn9c102_stream_state {
75 STREAM_OFF,
76 STREAM_INTERRUPT,
77 STREAM_ON,
78};
79
80typedef char sn9c102_sof_header_t[62];
81
82struct sn9c102_sof_t {
83 sn9c102_sof_header_t header;
84 u16 bytesread;
85};
86
87struct sn9c102_sysfs_attr {
88 u16 reg, i2c_reg;
89 sn9c102_sof_header_t frame_header;
90};
91
92struct sn9c102_module_param {
93 u8 force_munmap;
94 u16 frame_timeout;
95};
96
97static DEFINE_MUTEX(sn9c102_sysfs_lock);
98static DECLARE_RWSEM(sn9c102_dev_lock);
99
100struct sn9c102_device {
101 struct video_device* v4ldev;
102
103 enum sn9c102_bridge bridge;
104 struct sn9c102_sensor sensor;
105
106 struct usb_device* usbdev;
107 struct urb* urb[SN9C102_URBS];
108 void* transfer_buffer[SN9C102_URBS];
109 u8* control_buffer;
110
111 struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
112 struct list_head inqueue, outqueue;
113 u32 frame_count, nbuffers, nreadbuffers;
114
115 enum sn9c102_io_method io;
116 enum sn9c102_stream_state stream;
117
118 struct v4l2_jpegcompression compression;
119
120 struct sn9c102_sysfs_attr sysfs;
121 struct sn9c102_sof_t sof;
122 u16 reg[384];
123
124 struct sn9c102_module_param module_param;
125
126 struct kref kref;
127 enum sn9c102_dev_state state;
128 u8 users;
129
130 struct completion probe;
131 struct mutex open_mutex, fileop_mutex;
132 spinlock_t queue_lock;
133 wait_queue_head_t wait_open, wait_frame, wait_stream;
134};
135
136/*****************************************************************************/
137
138struct sn9c102_device*
139sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
140{
141 return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
142}
143
144
145void
146sn9c102_attach_sensor(struct sn9c102_device* cam,
147 const struct sn9c102_sensor* sensor)
148{
149 memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
150}
151
152
153enum sn9c102_bridge
154sn9c102_get_bridge(struct sn9c102_device* cam)
155{
156 return cam->bridge;
157}
158
159
160struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
161{
162 return &cam->sensor;
163}
164
165/*****************************************************************************/
166
167#undef DBG
168#undef KDBG
169#ifdef SN9C102_DEBUG
170# define DBG(level, fmt, args...) \
171do { \
172 if (debug >= (level)) { \
173 if ((level) == 1) \
174 dev_err(&cam->usbdev->dev, fmt "\n", ## args); \
175 else if ((level) == 2) \
176 dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
177 else if ((level) >= 3) \
178 dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
179 __func__, __LINE__ , ## args); \
180 } \
181} while (0)
182# define V4LDBG(level, name, cmd) \
183do { \
184 if (debug >= (level)) \
185 v4l_print_ioctl(name, cmd); \
186} while (0)
187# define KDBG(level, fmt, args...) \
188do { \
189 if (debug >= (level)) { \
190 if ((level) == 1 || (level) == 2) \
191 pr_info("sn9c102: " fmt "\n", ## args); \
192 else if ((level) == 3) \
193 pr_debug("sn9c102: [%s:%d] " fmt "\n", \
194 __func__, __LINE__ , ## args); \
195 } \
196} while (0)
197#else
198# define DBG(level, fmt, args...) do {;} while(0)
199# define V4LDBG(level, name, cmd) do {;} while(0)
200# define KDBG(level, fmt, args...) do {;} while(0)
201#endif
202
203#undef PDBG
204#define PDBG(fmt, args...) \
205dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
206 __LINE__ , ## args)
207
208#undef PDBGG
209#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
210
211#endif /* _SN9C102_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/video/sn9c102/sn9c102_config.h
new file mode 100644
index 00000000000..0f4e0378b07
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_config.h
@@ -0,0 +1,86 @@
1/***************************************************************************
2 * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
3 * *
4 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 ***************************************************************************/
20
21#ifndef _SN9C102_CONFIG_H_
22#define _SN9C102_CONFIG_H_
23
24#include <linux/types.h>
25#include <linux/jiffies.h>
26
27#define SN9C102_DEBUG
28#define SN9C102_DEBUG_LEVEL 2
29#define SN9C102_MAX_DEVICES 64
30#define SN9C102_PRESERVE_IMGSCALE 0
31#define SN9C102_FORCE_MUNMAP 0
32#define SN9C102_MAX_FRAMES 32
33#define SN9C102_URBS 2
34#define SN9C102_ISO_PACKETS 7
35#define SN9C102_ALTERNATE_SETTING 8
36#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
37#define SN9C102_CTRL_TIMEOUT 300
38#define SN9C102_FRAME_TIMEOUT 0
39
40/*****************************************************************************/
41
42static const u8 SN9C102_Y_QTABLE0[64] = {
43 8, 5, 5, 8, 12, 20, 25, 30,
44 6, 6, 7, 9, 13, 29, 30, 27,
45 7, 6, 8, 12, 20, 28, 34, 28,
46 7, 8, 11, 14, 25, 43, 40, 31,
47 9, 11, 18, 28, 34, 54, 51, 38,
48 12, 17, 27, 32, 40, 52, 56, 46,
49 24, 32, 39, 43, 51, 60, 60, 50,
50 36, 46, 47, 49, 56, 50, 51, 49
51};
52
53static const u8 SN9C102_UV_QTABLE0[64] = {
54 8, 9, 12, 23, 49, 49, 49, 49,
55 9, 10, 13, 33, 49, 49, 49, 49,
56 12, 13, 28, 49, 49, 49, 49, 49,
57 23, 33, 49, 49, 49, 49, 49, 49,
58 49, 49, 49, 49, 49, 49, 49, 49,
59 49, 49, 49, 49, 49, 49, 49, 49,
60 49, 49, 49, 49, 49, 49, 49, 49,
61 49, 49, 49, 49, 49, 49, 49, 49
62};
63
64static const u8 SN9C102_Y_QTABLE1[64] = {
65 16, 11, 10, 16, 24, 40, 51, 61,
66 12, 12, 14, 19, 26, 58, 60, 55,
67 14, 13, 16, 24, 40, 57, 69, 56,
68 14, 17, 22, 29, 51, 87, 80, 62,
69 18, 22, 37, 56, 68, 109, 103, 77,
70 24, 35, 55, 64, 81, 104, 113, 92,
71 49, 64, 78, 87, 103, 121, 120, 101,
72 72, 92, 95, 98, 112, 100, 103, 99
73};
74
75static const u8 SN9C102_UV_QTABLE1[64] = {
76 17, 18, 24, 47, 99, 99, 99, 99,
77 18, 21, 26, 66, 99, 99, 99, 99,
78 24, 26, 56, 99, 99, 99, 99, 99,
79 47, 66, 99, 99, 99, 99, 99, 99,
80 99, 99, 99, 99, 99, 99, 99, 99,
81 99, 99, 99, 99, 99, 99, 99, 99,
82 99, 99, 99, 99, 99, 99, 99, 99,
83 99, 99, 99, 99, 99, 99, 99, 99
84};
85
86#endif /* _SN9C102_CONFIG_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
new file mode 100644
index 00000000000..16cb07c5c27
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -0,0 +1,3446 @@
1/***************************************************************************
2 * V4L2 driver for SN9C1xx PC Camera Controllers *
3 * *
4 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 ***************************************************************************/
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/kernel.h>
24#include <linux/param.h>
25#include <linux/errno.h>
26#include <linux/slab.h>
27#include <linux/device.h>
28#include <linux/fs.h>
29#include <linux/delay.h>
30#include <linux/compiler.h>
31#include <linux/ioctl.h>
32#include <linux/poll.h>
33#include <linux/stat.h>
34#include <linux/mm.h>
35#include <linux/vmalloc.h>
36#include <linux/version.h>
37#include <linux/page-flags.h>
38#include <asm/byteorder.h>
39#include <asm/page.h>
40#include <asm/uaccess.h>
41
42#include "sn9c102.h"
43
44/*****************************************************************************/
45
46#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
47#define SN9C102_MODULE_ALIAS "sn9c1xx"
48#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
49#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
50#define SN9C102_MODULE_LICENSE "GPL"
51#define SN9C102_MODULE_VERSION "1:1.48"
52
53/*****************************************************************************/
54
55MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
56
57MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
58MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
59MODULE_ALIAS(SN9C102_MODULE_ALIAS);
60MODULE_VERSION(SN9C102_MODULE_VERSION);
61MODULE_LICENSE(SN9C102_MODULE_LICENSE);
62
63static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
64module_param_array(video_nr, short, NULL, 0444);
65MODULE_PARM_DESC(video_nr,
66 " <-1|n[,...]>"
67 "\nSpecify V4L2 minor mode number."
68 "\n-1 = use next available (default)"
69 "\n n = use minor number n (integer >= 0)"
70 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
71 " cameras this way."
72 "\nFor example:"
73 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
74 "\nthe second camera and use auto for the first"
75 "\none and for every other camera."
76 "\n");
77
78static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
79 SN9C102_FORCE_MUNMAP};
80module_param_array(force_munmap, bool, NULL, 0444);
81MODULE_PARM_DESC(force_munmap,
82 " <0|1[,...]>"
83 "\nForce the application to unmap previously"
84 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
85 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
86 "\nthis feature. This parameter is specific for each"
87 "\ndetected camera."
88 "\n0 = do not force memory unmapping"
89 "\n1 = force memory unmapping (save memory)"
90 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
91 "\n");
92
93static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
94 SN9C102_FRAME_TIMEOUT};
95module_param_array(frame_timeout, uint, NULL, 0644);
96MODULE_PARM_DESC(frame_timeout,
97 " <0|n[,...]>"
98 "\nTimeout for a video frame in seconds before"
99 "\nreturning an I/O error; 0 for infinity."
100 "\nThis parameter is specific for each detected camera."
101 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
102 "\n");
103
104#ifdef SN9C102_DEBUG
105static unsigned short debug = SN9C102_DEBUG_LEVEL;
106module_param(debug, ushort, 0644);
107MODULE_PARM_DESC(debug,
108 " <n>"
109 "\nDebugging information level, from 0 to 3:"
110 "\n0 = none (use carefully)"
111 "\n1 = critical errors"
112 "\n2 = significant informations"
113 "\n3 = more verbose messages"
114 "\nLevel 3 is useful for testing only."
115 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
116 "\n");
117#endif
118
119/*
120 Add the probe entries to this table. Be sure to add the entry in the right
121 place, since, on failure, the next probing routine is called according to
122 the order of the list below, from top to bottom.
123*/
124static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = {
125 &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
126 &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
127 &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
128 &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
129 &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
130 &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
131 &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
132 &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
133 &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
134 &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
135 &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
136 &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
137};
138
139/*****************************************************************************/
140
141static u32
142sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
143 enum sn9c102_io_method io)
144{
145 struct v4l2_pix_format* p = &(cam->sensor.pix_format);
146 struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
147 size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
148 (p->width * p->height * p->priv) / 8 :
149 (r->width * r->height * p->priv) / 8;
150 void* buff = NULL;
151 u32 i;
152
153 if (count > SN9C102_MAX_FRAMES)
154 count = SN9C102_MAX_FRAMES;
155
156 if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120)
157 imagesize += 589 + 2; /* length of JPEG header + EOI marker */
158
159 cam->nbuffers = count;
160 while (cam->nbuffers > 0) {
161 if ((buff = vmalloc_32_user(cam->nbuffers *
162 PAGE_ALIGN(imagesize))))
163 break;
164 cam->nbuffers--;
165 }
166
167 for (i = 0; i < cam->nbuffers; i++) {
168 cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
169 cam->frame[i].buf.index = i;
170 cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
171 cam->frame[i].buf.length = imagesize;
172 cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
173 cam->frame[i].buf.sequence = 0;
174 cam->frame[i].buf.field = V4L2_FIELD_NONE;
175 cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
176 cam->frame[i].buf.flags = 0;
177 }
178
179 return cam->nbuffers;
180}
181
182
183static void sn9c102_release_buffers(struct sn9c102_device* cam)
184{
185 if (cam->nbuffers) {
186 vfree(cam->frame[0].bufmem);
187 cam->nbuffers = 0;
188 }
189 cam->frame_current = NULL;
190}
191
192
193static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
194{
195 u32 i;
196
197 INIT_LIST_HEAD(&cam->inqueue);
198 INIT_LIST_HEAD(&cam->outqueue);
199
200 for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
201 cam->frame[i].state = F_UNUSED;
202 cam->frame[i].buf.bytesused = 0;
203 }
204}
205
206
207static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
208{
209 struct sn9c102_frame_t *i;
210
211 list_for_each_entry(i, &cam->outqueue, frame) {
212 i->state = F_QUEUED;
213 list_add(&i->frame, &cam->inqueue);
214 }
215
216 INIT_LIST_HEAD(&cam->outqueue);
217}
218
219
220static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
221{
222 unsigned long lock_flags;
223 u32 i;
224
225 for (i = 0; i < cam->nbuffers; i++)
226 if (cam->frame[i].state == F_UNUSED) {
227 cam->frame[i].state = F_QUEUED;
228 spin_lock_irqsave(&cam->queue_lock, lock_flags);
229 list_add_tail(&cam->frame[i].frame, &cam->inqueue);
230 spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
231 }
232}
233
234/*****************************************************************************/
235
236/*
237 Write a sequence of count value/register pairs. Returns -1 after the first
238 failed write, or 0 for no errors.
239*/
240int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
241 int count)
242{
243 struct usb_device* udev = cam->usbdev;
244 u8* buff = cam->control_buffer;
245 int i, res;
246
247 for (i = 0; i < count; i++) {
248 u8 index = valreg[i][1];
249
250 /*
251 index is a u8, so it must be <256 and can't be out of range.
252 If we put in a check anyway, gcc annoys us with a warning
253 hat our check is useless. People get all uppity when they
254 see warnings in the kernel compile.
255 */
256
257 *buff = valreg[i][0];
258
259 res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08,
260 0x41, index, 0, buff, 1,
261 SN9C102_CTRL_TIMEOUT);
262
263 if (res < 0) {
264 DBG(3, "Failed to write a register (value 0x%02X, "
265 "index 0x%02X, error %d)", *buff, index, res);
266 return -1;
267 }
268
269 cam->reg[index] = *buff;
270 }
271
272 return 0;
273}
274
275
276int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
277{
278 struct usb_device* udev = cam->usbdev;
279 u8* buff = cam->control_buffer;
280 int res;
281
282 if (index >= ARRAY_SIZE(cam->reg))
283 return -1;
284
285 *buff = value;
286
287 res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
288 index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
289 if (res < 0) {
290 DBG(3, "Failed to write a register (value 0x%02X, index "
291 "0x%02X, error %d)", value, index, res);
292 return -1;
293 }
294
295 cam->reg[index] = value;
296
297 return 0;
298}
299
300
301/* NOTE: with the SN9C10[123] reading some registers always returns 0 */
302int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
303{
304 struct usb_device* udev = cam->usbdev;
305 u8* buff = cam->control_buffer;
306 int res;
307
308 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
309 index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
310 if (res < 0)
311 DBG(3, "Failed to read a register (index 0x%02X, error %d)",
312 index, res);
313
314 return (res >= 0) ? (int)(*buff) : -1;
315}
316
317
318int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
319{
320 if (index >= ARRAY_SIZE(cam->reg))
321 return -1;
322
323 return cam->reg[index];
324}
325
326
327static int
328sn9c102_i2c_wait(struct sn9c102_device* cam,
329 const struct sn9c102_sensor* sensor)
330{
331 int i, r;
332
333 for (i = 1; i <= 5; i++) {
334 r = sn9c102_read_reg(cam, 0x08);
335 if (r < 0)
336 return -EIO;
337 if (r & 0x04)
338 return 0;
339 if (sensor->frequency & SN9C102_I2C_400KHZ)
340 udelay(5*16);
341 else
342 udelay(16*16);
343 }
344 return -EBUSY;
345}
346
347
348static int
349sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
350 const struct sn9c102_sensor* sensor)
351{
352 int r , err = 0;
353
354 r = sn9c102_read_reg(cam, 0x08);
355 if (r < 0)
356 err += r;
357
358 if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
359 if (!(r & 0x08))
360 err += -1;
361 } else {
362 if (r & 0x08)
363 err += -1;
364 }
365
366 return err ? -EIO : 0;
367}
368
369
370static int
371sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
372 const struct sn9c102_sensor* sensor)
373{
374 int r;
375 r = sn9c102_read_reg(cam, 0x08);
376 return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
377}
378
379
380int
381sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
382 const struct sn9c102_sensor* sensor, u8 data0,
383 u8 data1, u8 n, u8 buffer[])
384{
385 struct usb_device* udev = cam->usbdev;
386 u8* data = cam->control_buffer;
387 int i = 0, err = 0, res;
388
389 /* Write cycle */
390 data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
391 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
392 data[1] = data0; /* I2C slave id */
393 data[2] = data1; /* address */
394 data[7] = 0x10;
395 res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
396 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
397 if (res < 0)
398 err += res;
399
400 err += sn9c102_i2c_wait(cam, sensor);
401
402 /* Read cycle - n bytes */
403 data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
404 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
405 (n << 4) | 0x02;
406 data[1] = data0;
407 data[7] = 0x10;
408 res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
409 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
410 if (res < 0)
411 err += res;
412
413 err += sn9c102_i2c_wait(cam, sensor);
414
415 /* The first read byte will be placed in data[4] */
416 res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
417 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
418 if (res < 0)
419 err += res;
420
421 err += sn9c102_i2c_detect_read_error(cam, sensor);
422
423 PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
424 data[4]);
425
426 if (err) {
427 DBG(3, "I2C read failed for %s image sensor", sensor->name);
428 return -1;
429 }
430
431 if (buffer)
432 for (i = 0; i < n && i < 5; i++)
433 buffer[n-i-1] = data[4-i];
434
435 return (int)data[4];
436}
437
438
439int
440sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
441 const struct sn9c102_sensor* sensor, u8 n, u8 data0,
442 u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
443{
444 struct usb_device* udev = cam->usbdev;
445 u8* data = cam->control_buffer;
446 int err = 0, res;
447
448 /* Write cycle. It usually is address + value */
449 data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
450 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
451 | ((n - 1) << 4);
452 data[1] = data0;
453 data[2] = data1;
454 data[3] = data2;
455 data[4] = data3;
456 data[5] = data4;
457 data[6] = data5;
458 data[7] = 0x17;
459 res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
460 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
461 if (res < 0)
462 err += res;
463
464 err += sn9c102_i2c_wait(cam, sensor);
465 err += sn9c102_i2c_detect_write_error(cam, sensor);
466
467 if (err)
468 DBG(3, "I2C write failed for %s image sensor", sensor->name);
469
470 PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
471 "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
472 n, data0, data1, data2, data3, data4, data5);
473
474 return err ? -1 : 0;
475}
476
477
478int
479sn9c102_i2c_try_read(struct sn9c102_device* cam,
480 const struct sn9c102_sensor* sensor, u8 address)
481{
482 return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
483 address, 1, NULL);
484}
485
486
487static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
488 const struct sn9c102_sensor* sensor,
489 u8 address, u8 value)
490{
491 return sn9c102_i2c_try_raw_write(cam, sensor, 3,
492 sensor->i2c_slave_id, address,
493 value, 0, 0, 0);
494}
495
496
497int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
498{
499 return sn9c102_i2c_try_read(cam, &cam->sensor, address);
500}
501
502
503int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
504{
505 return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
506}
507
508/*****************************************************************************/
509
510static size_t sn9c102_sof_length(struct sn9c102_device* cam)
511{
512 switch (cam->bridge) {
513 case BRIDGE_SN9C101:
514 case BRIDGE_SN9C102:
515 return 12;
516 case BRIDGE_SN9C103:
517 return 18;
518 case BRIDGE_SN9C105:
519 case BRIDGE_SN9C120:
520 return 62;
521 }
522
523 return 0;
524}
525
526
527static void*
528sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
529{
530 static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
531 const char *m = mem;
532 size_t soflen = 0, i, j;
533
534 soflen = sn9c102_sof_length(cam);
535
536 for (i = 0; i < len; i++) {
537 size_t b;
538
539 /* Read the variable part of the header */
540 if (unlikely(cam->sof.bytesread >= sizeof(marker))) {
541 cam->sof.header[cam->sof.bytesread] = *(m+i);
542 if (++cam->sof.bytesread == soflen) {
543 cam->sof.bytesread = 0;
544 return mem + i;
545 }
546 continue;
547 }
548
549 /* Search for the SOF marker (fixed part) in the header */
550 for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
551 if (unlikely(i+j == len))
552 return NULL;
553 if (*(m+i+j) == marker[cam->sof.bytesread]) {
554 cam->sof.header[cam->sof.bytesread] = *(m+i+j);
555 if (++cam->sof.bytesread == sizeof(marker)) {
556 PDBGG("Bytes to analyze: %zd. SOF "
557 "starts at byte #%zd", len, i);
558 i += j+1;
559 break;
560 }
561 } else {
562 cam->sof.bytesread = 0;
563 break;
564 }
565 }
566 }
567
568 return NULL;
569}
570
571
572static void*
573sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
574{
575 static const u8 eof_header[4][4] = {
576 {0x00, 0x00, 0x00, 0x00},
577 {0x40, 0x00, 0x00, 0x00},
578 {0x80, 0x00, 0x00, 0x00},
579 {0xc0, 0x00, 0x00, 0x00},
580 };
581 size_t i, j;
582
583 /* The EOF header does not exist in compressed data */
584 if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
585 cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
586 return NULL;
587
588 /*
589 The EOF header might cross the packet boundary, but this is not a
590 problem, since the end of a frame is determined by checking its size
591 in the first place.
592 */
593 for (i = 0; (len >= 4) && (i <= len - 4); i++)
594 for (j = 0; j < ARRAY_SIZE(eof_header); j++)
595 if (!memcmp(mem + i, eof_header[j], 4))
596 return mem + i;
597
598 return NULL;
599}
600
601
602static void
603sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
604{
605 static const u8 jpeg_header[589] = {
606 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
607 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
608 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
609 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
610 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
611 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
612 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
613 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
614 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
615 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
616 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
617 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
618 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
619 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
620 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
622 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
623 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
624 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
625 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
626 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
627 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
628 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
629 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
630 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
631 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
632 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
633 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
634 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
635 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
636 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
637 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
638 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
639 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
640 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
641 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
642 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
643 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
644 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
645 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
646 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
647 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
648 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
649 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
650 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
651 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
652 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
653 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
654 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
655 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
656 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
657 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
658 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
659 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
660 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
661 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
662 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
663 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
664 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
665 };
666 u8 *pos = f->bufmem;
667
668 memcpy(pos, jpeg_header, sizeof(jpeg_header));
669 *(pos + 6) = 0x00;
670 *(pos + 7 + 64) = 0x01;
671 if (cam->compression.quality == 0) {
672 memcpy(pos + 7, SN9C102_Y_QTABLE0, 64);
673 memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64);
674 } else if (cam->compression.quality == 1) {
675 memcpy(pos + 7, SN9C102_Y_QTABLE1, 64);
676 memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64);
677 }
678 *(pos + 564) = cam->sensor.pix_format.width & 0xFF;
679 *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF;
680 *(pos + 562) = cam->sensor.pix_format.height & 0xFF;
681 *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF;
682 *(pos + 567) = 0x21;
683
684 f->buf.bytesused += sizeof(jpeg_header);
685}
686
687
688static void sn9c102_urb_complete(struct urb *urb)
689{
690 struct sn9c102_device* cam = urb->context;
691 struct sn9c102_frame_t** f;
692 size_t imagesize, soflen;
693 u8 i;
694 int err = 0;
695
696 if (urb->status == -ENOENT)
697 return;
698
699 f = &cam->frame_current;
700
701 if (cam->stream == STREAM_INTERRUPT) {
702 cam->stream = STREAM_OFF;
703 if ((*f))
704 (*f)->state = F_QUEUED;
705 cam->sof.bytesread = 0;
706 DBG(3, "Stream interrupted by application");
707 wake_up(&cam->wait_stream);
708 }
709
710 if (cam->state & DEV_DISCONNECTED)
711 return;
712
713 if (cam->state & DEV_MISCONFIGURED) {
714 wake_up_interruptible(&cam->wait_frame);
715 return;
716 }
717
718 if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
719 goto resubmit_urb;
720
721 if (!(*f))
722 (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
723 frame);
724
725 imagesize = (cam->sensor.pix_format.width *
726 cam->sensor.pix_format.height *
727 cam->sensor.pix_format.priv) / 8;
728 if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
729 imagesize += 589; /* length of jpeg header */
730 soflen = sn9c102_sof_length(cam);
731
732 for (i = 0; i < urb->number_of_packets; i++) {
733 unsigned int img, len, status;
734 void *pos, *sof, *eof;
735
736 len = urb->iso_frame_desc[i].actual_length;
737 status = urb->iso_frame_desc[i].status;
738 pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
739
740 if (status) {
741 DBG(3, "Error in isochronous frame");
742 (*f)->state = F_ERROR;
743 cam->sof.bytesread = 0;
744 continue;
745 }
746
747 PDBGG("Isochrnous frame: length %u, #%u i", len, i);
748
749redo:
750 sof = sn9c102_find_sof_header(cam, pos, len);
751 if (likely(!sof)) {
752 eof = sn9c102_find_eof_header(cam, pos, len);
753 if ((*f)->state == F_GRABBING) {
754end_of_frame:
755 img = len;
756
757 if (eof)
758 img = (eof > pos) ? eof - pos - 1 : 0;
759
760 if ((*f)->buf.bytesused + img > imagesize) {
761 u32 b;
762 b = (*f)->buf.bytesused + img -
763 imagesize;
764 img = imagesize - (*f)->buf.bytesused;
765 PDBGG("Expected EOF not found: video "
766 "frame cut");
767 if (eof)
768 DBG(3, "Exceeded limit: +%u "
769 "bytes", (unsigned)(b));
770 }
771
772 memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
773 img);
774
775 if ((*f)->buf.bytesused == 0)
776 do_gettimeofday(&(*f)->buf.timestamp);
777
778 (*f)->buf.bytesused += img;
779
780 if ((*f)->buf.bytesused == imagesize ||
781 ((cam->sensor.pix_format.pixelformat ==
782 V4L2_PIX_FMT_SN9C10X ||
783 cam->sensor.pix_format.pixelformat ==
784 V4L2_PIX_FMT_JPEG) && eof)) {
785 u32 b;
786
787 b = (*f)->buf.bytesused;
788 (*f)->state = F_DONE;
789 (*f)->buf.sequence= ++cam->frame_count;
790
791 spin_lock(&cam->queue_lock);
792 list_move_tail(&(*f)->frame,
793 &cam->outqueue);
794 if (!list_empty(&cam->inqueue))
795 (*f) = list_entry(
796 cam->inqueue.next,
797 struct sn9c102_frame_t,
798 frame );
799 else
800 (*f) = NULL;
801 spin_unlock(&cam->queue_lock);
802
803 memcpy(cam->sysfs.frame_header,
804 cam->sof.header, soflen);
805
806 DBG(3, "Video frame captured: %lu "
807 "bytes", (unsigned long)(b));
808
809 if (!(*f))
810 goto resubmit_urb;
811
812 } else if (eof) {
813 (*f)->state = F_ERROR;
814 DBG(3, "Not expected EOF after %lu "
815 "bytes of image data",
816 (unsigned long)
817 ((*f)->buf.bytesused));
818 }
819
820 if (sof) /* (1) */
821 goto start_of_frame;
822
823 } else if (eof) {
824 DBG(3, "EOF without SOF");
825 continue;
826
827 } else {
828 PDBGG("Ignoring pointless isochronous frame");
829 continue;
830 }
831
832 } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
833start_of_frame:
834 (*f)->state = F_GRABBING;
835 (*f)->buf.bytesused = 0;
836 len -= (sof - pos);
837 pos = sof;
838 if (cam->sensor.pix_format.pixelformat ==
839 V4L2_PIX_FMT_JPEG)
840 sn9c102_write_jpegheader(cam, (*f));
841 DBG(3, "SOF detected: new video frame");
842 if (len)
843 goto redo;
844
845 } else if ((*f)->state == F_GRABBING) {
846 eof = sn9c102_find_eof_header(cam, pos, len);
847 if (eof && eof < sof)
848 goto end_of_frame; /* (1) */
849 else {
850 if (cam->sensor.pix_format.pixelformat ==
851 V4L2_PIX_FMT_SN9C10X ||
852 cam->sensor.pix_format.pixelformat ==
853 V4L2_PIX_FMT_JPEG) {
854 if (sof - pos >= soflen) {
855 eof = sof - soflen;
856 } else { /* remove header */
857 eof = pos;
858 (*f)->buf.bytesused -=
859 (soflen - (sof - pos));
860 }
861 goto end_of_frame;
862 } else {
863 DBG(3, "SOF before expected EOF after "
864 "%lu bytes of image data",
865 (unsigned long)
866 ((*f)->buf.bytesused));
867 goto start_of_frame;
868 }
869 }
870 }
871 }
872
873resubmit_urb:
874 urb->dev = cam->usbdev;
875 err = usb_submit_urb(urb, GFP_ATOMIC);
876 if (err < 0 && err != -EPERM) {
877 cam->state |= DEV_MISCONFIGURED;
878 DBG(1, "usb_submit_urb() failed");
879 }
880
881 wake_up_interruptible(&cam->wait_frame);
882}
883
884
885static int sn9c102_start_transfer(struct sn9c102_device* cam)
886{
887 struct usb_device *udev = cam->usbdev;
888 struct urb* urb;
889 struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
890 usb_ifnum_to_if(udev, 0),
891 SN9C102_ALTERNATE_SETTING);
892 const unsigned int psz = le16_to_cpu(altsetting->
893 endpoint[0].desc.wMaxPacketSize);
894 s8 i, j;
895 int err = 0;
896
897 for (i = 0; i < SN9C102_URBS; i++) {
898 cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
899 GFP_KERNEL);
900 if (!cam->transfer_buffer[i]) {
901 err = -ENOMEM;
902 DBG(1, "Not enough memory");
903 goto free_buffers;
904 }
905 }
906
907 for (i = 0; i < SN9C102_URBS; i++) {
908 urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
909 cam->urb[i] = urb;
910 if (!urb) {
911 err = -ENOMEM;
912 DBG(1, "usb_alloc_urb() failed");
913 goto free_urbs;
914 }
915 urb->dev = udev;
916 urb->context = cam;
917 urb->pipe = usb_rcvisocpipe(udev, 1);
918 urb->transfer_flags = URB_ISO_ASAP;
919 urb->number_of_packets = SN9C102_ISO_PACKETS;
920 urb->complete = sn9c102_urb_complete;
921 urb->transfer_buffer = cam->transfer_buffer[i];
922 urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
923 urb->interval = 1;
924 for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
925 urb->iso_frame_desc[j].offset = psz * j;
926 urb->iso_frame_desc[j].length = psz;
927 }
928 }
929
930 /* Enable video */
931 if (!(cam->reg[0x01] & 0x04)) {
932 err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
933 if (err) {
934 err = -EIO;
935 DBG(1, "I/O hardware error");
936 goto free_urbs;
937 }
938 }
939
940 err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
941 if (err) {
942 DBG(1, "usb_set_interface() failed");
943 goto free_urbs;
944 }
945
946 cam->frame_current = NULL;
947 cam->sof.bytesread = 0;
948
949 for (i = 0; i < SN9C102_URBS; i++) {
950 err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
951 if (err) {
952 for (j = i-1; j >= 0; j--)
953 usb_kill_urb(cam->urb[j]);
954 DBG(1, "usb_submit_urb() failed, error %d", err);
955 goto free_urbs;
956 }
957 }
958
959 return 0;
960
961free_urbs:
962 for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++)
963 usb_free_urb(cam->urb[i]);
964
965free_buffers:
966 for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
967 kfree(cam->transfer_buffer[i]);
968
969 return err;
970}
971
972
973static int sn9c102_stop_transfer(struct sn9c102_device* cam)
974{
975 struct usb_device *udev = cam->usbdev;
976 s8 i;
977 int err = 0;
978
979 if (cam->state & DEV_DISCONNECTED)
980 return 0;
981
982 for (i = SN9C102_URBS-1; i >= 0; i--) {
983 usb_kill_urb(cam->urb[i]);
984 usb_free_urb(cam->urb[i]);
985 kfree(cam->transfer_buffer[i]);
986 }
987
988 err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
989 if (err)
990 DBG(3, "usb_set_interface() failed");
991
992 return err;
993}
994
995
996static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
997{
998 long timeout;
999
1000 cam->stream = STREAM_INTERRUPT;
1001 timeout = wait_event_timeout(cam->wait_stream,
1002 (cam->stream == STREAM_OFF) ||
1003 (cam->state & DEV_DISCONNECTED),
1004 SN9C102_URB_TIMEOUT);
1005 if (cam->state & DEV_DISCONNECTED)
1006 return -ENODEV;
1007 else if (cam->stream != STREAM_OFF) {
1008 cam->state |= DEV_MISCONFIGURED;
1009 DBG(1, "URB timeout reached. The camera is misconfigured. "
1010 "To use it, close and open %s again.",
1011 video_device_node_name(cam->v4ldev));
1012 return -EIO;
1013 }
1014
1015 return 0;
1016}
1017
1018/*****************************************************************************/
1019
1020#ifdef CONFIG_VIDEO_ADV_DEBUG
1021static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
1022{
1023 char str[7];
1024 char* endp;
1025 unsigned long val;
1026
1027 if (len < 6) {
1028 strncpy(str, buff, len);
1029 str[len] = '\0';
1030 } else {
1031 strncpy(str, buff, 6);
1032 str[6] = '\0';
1033 }
1034
1035 val = simple_strtoul(str, &endp, 0);
1036
1037 *count = 0;
1038 if (val <= 0xffff)
1039 *count = (ssize_t)(endp - str);
1040 if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
1041 *count += 1;
1042
1043 return (u16)val;
1044}
1045
1046/*
1047 NOTE 1: being inside one of the following methods implies that the v4l
1048 device exists for sure (see kobjects and reference counters)
1049 NOTE 2: buffers are PAGE_SIZE long
1050*/
1051
1052static ssize_t sn9c102_show_reg(struct device* cd,
1053 struct device_attribute *attr, char* buf)
1054{
1055 struct sn9c102_device* cam;
1056 ssize_t count;
1057
1058 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1059 return -ERESTARTSYS;
1060
1061 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1062 if (!cam) {
1063 mutex_unlock(&sn9c102_sysfs_lock);
1064 return -ENODEV;
1065 }
1066
1067 count = sprintf(buf, "%u\n", cam->sysfs.reg);
1068
1069 mutex_unlock(&sn9c102_sysfs_lock);
1070
1071 return count;
1072}
1073
1074
1075static ssize_t
1076sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
1077 const char* buf, size_t len)
1078{
1079 struct sn9c102_device* cam;
1080 u16 index;
1081 ssize_t count;
1082
1083 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1084 return -ERESTARTSYS;
1085
1086 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1087 if (!cam) {
1088 mutex_unlock(&sn9c102_sysfs_lock);
1089 return -ENODEV;
1090 }
1091
1092 index = sn9c102_strtou16(buf, len, &count);
1093 if (index >= ARRAY_SIZE(cam->reg) || !count) {
1094 mutex_unlock(&sn9c102_sysfs_lock);
1095 return -EINVAL;
1096 }
1097
1098 cam->sysfs.reg = index;
1099
1100 DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg);
1101 DBG(3, "Written bytes: %zd", count);
1102
1103 mutex_unlock(&sn9c102_sysfs_lock);
1104
1105 return count;
1106}
1107
1108
1109static ssize_t sn9c102_show_val(struct device* cd,
1110 struct device_attribute *attr, char* buf)
1111{
1112 struct sn9c102_device* cam;
1113 ssize_t count;
1114 int val;
1115
1116 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1117 return -ERESTARTSYS;
1118
1119 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1120 if (!cam) {
1121 mutex_unlock(&sn9c102_sysfs_lock);
1122 return -ENODEV;
1123 }
1124
1125 if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
1126 mutex_unlock(&sn9c102_sysfs_lock);
1127 return -EIO;
1128 }
1129
1130 count = sprintf(buf, "%d\n", val);
1131
1132 DBG(3, "Read bytes: %zd, value: %d", count, val);
1133
1134 mutex_unlock(&sn9c102_sysfs_lock);
1135
1136 return count;
1137}
1138
1139
1140static ssize_t
1141sn9c102_store_val(struct device* cd, struct device_attribute *attr,
1142 const char* buf, size_t len)
1143{
1144 struct sn9c102_device* cam;
1145 u16 value;
1146 ssize_t count;
1147 int err;
1148
1149 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1150 return -ERESTARTSYS;
1151
1152 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1153 if (!cam) {
1154 mutex_unlock(&sn9c102_sysfs_lock);
1155 return -ENODEV;
1156 }
1157
1158 value = sn9c102_strtou16(buf, len, &count);
1159 if (!count) {
1160 mutex_unlock(&sn9c102_sysfs_lock);
1161 return -EINVAL;
1162 }
1163
1164 err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
1165 if (err) {
1166 mutex_unlock(&sn9c102_sysfs_lock);
1167 return -EIO;
1168 }
1169
1170 DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X",
1171 cam->sysfs.reg, value);
1172 DBG(3, "Written bytes: %zd", count);
1173
1174 mutex_unlock(&sn9c102_sysfs_lock);
1175
1176 return count;
1177}
1178
1179
1180static ssize_t sn9c102_show_i2c_reg(struct device* cd,
1181 struct device_attribute *attr, char* buf)
1182{
1183 struct sn9c102_device* cam;
1184 ssize_t count;
1185
1186 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1187 return -ERESTARTSYS;
1188
1189 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1190 if (!cam) {
1191 mutex_unlock(&sn9c102_sysfs_lock);
1192 return -ENODEV;
1193 }
1194
1195 count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
1196
1197 DBG(3, "Read bytes: %zd", count);
1198
1199 mutex_unlock(&sn9c102_sysfs_lock);
1200
1201 return count;
1202}
1203
1204
1205static ssize_t
1206sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
1207 const char* buf, size_t len)
1208{
1209 struct sn9c102_device* cam;
1210 u16 index;
1211 ssize_t count;
1212
1213 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1214 return -ERESTARTSYS;
1215
1216 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1217 if (!cam) {
1218 mutex_unlock(&sn9c102_sysfs_lock);
1219 return -ENODEV;
1220 }
1221
1222 index = sn9c102_strtou16(buf, len, &count);
1223 if (!count) {
1224 mutex_unlock(&sn9c102_sysfs_lock);
1225 return -EINVAL;
1226 }
1227
1228 cam->sysfs.i2c_reg = index;
1229
1230 DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
1231 DBG(3, "Written bytes: %zd", count);
1232
1233 mutex_unlock(&sn9c102_sysfs_lock);
1234
1235 return count;
1236}
1237
1238
1239static ssize_t sn9c102_show_i2c_val(struct device* cd,
1240 struct device_attribute *attr, char* buf)
1241{
1242 struct sn9c102_device* cam;
1243 ssize_t count;
1244 int val;
1245
1246 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1247 return -ERESTARTSYS;
1248
1249 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1250 if (!cam) {
1251 mutex_unlock(&sn9c102_sysfs_lock);
1252 return -ENODEV;
1253 }
1254
1255 if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
1256 mutex_unlock(&sn9c102_sysfs_lock);
1257 return -ENOSYS;
1258 }
1259
1260 if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
1261 mutex_unlock(&sn9c102_sysfs_lock);
1262 return -EIO;
1263 }
1264
1265 count = sprintf(buf, "%d\n", val);
1266
1267 DBG(3, "Read bytes: %zd, value: %d", count, val);
1268
1269 mutex_unlock(&sn9c102_sysfs_lock);
1270
1271 return count;
1272}
1273
1274
1275static ssize_t
1276sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
1277 const char* buf, size_t len)
1278{
1279 struct sn9c102_device* cam;
1280 u16 value;
1281 ssize_t count;
1282 int err;
1283
1284 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1285 return -ERESTARTSYS;
1286
1287 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1288 if (!cam) {
1289 mutex_unlock(&sn9c102_sysfs_lock);
1290 return -ENODEV;
1291 }
1292
1293 if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
1294 mutex_unlock(&sn9c102_sysfs_lock);
1295 return -ENOSYS;
1296 }
1297
1298 value = sn9c102_strtou16(buf, len, &count);
1299 if (!count) {
1300 mutex_unlock(&sn9c102_sysfs_lock);
1301 return -EINVAL;
1302 }
1303
1304 err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
1305 if (err) {
1306 mutex_unlock(&sn9c102_sysfs_lock);
1307 return -EIO;
1308 }
1309
1310 DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
1311 cam->sysfs.i2c_reg, value);
1312 DBG(3, "Written bytes: %zd", count);
1313
1314 mutex_unlock(&sn9c102_sysfs_lock);
1315
1316 return count;
1317}
1318
1319
1320static ssize_t
1321sn9c102_store_green(struct device* cd, struct device_attribute *attr,
1322 const char* buf, size_t len)
1323{
1324 struct sn9c102_device* cam;
1325 enum sn9c102_bridge bridge;
1326 ssize_t res = 0;
1327 u16 value;
1328 ssize_t count;
1329
1330 if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
1331 return -ERESTARTSYS;
1332
1333 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1334 if (!cam) {
1335 mutex_unlock(&sn9c102_sysfs_lock);
1336 return -ENODEV;
1337 }
1338
1339 bridge = cam->bridge;
1340
1341 mutex_unlock(&sn9c102_sysfs_lock);
1342
1343 value = sn9c102_strtou16(buf, len, &count);
1344 if (!count)
1345 return -EINVAL;
1346
1347 switch (bridge) {
1348 case BRIDGE_SN9C101:
1349 case BRIDGE_SN9C102:
1350 if (value > 0x0f)
1351 return -EINVAL;
1352 if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
1353 res = sn9c102_store_val(cd, attr, buf, len);
1354 break;
1355 case BRIDGE_SN9C103:
1356 case BRIDGE_SN9C105:
1357 case BRIDGE_SN9C120:
1358 if (value > 0x7f)
1359 return -EINVAL;
1360 if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
1361 res = sn9c102_store_val(cd, attr, buf, len);
1362 break;
1363 }
1364
1365 return res;
1366}
1367
1368
1369static ssize_t
1370sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
1371 const char* buf, size_t len)
1372{
1373 ssize_t res = 0;
1374 u16 value;
1375 ssize_t count;
1376
1377 value = sn9c102_strtou16(buf, len, &count);
1378 if (!count || value > 0x7f)
1379 return -EINVAL;
1380
1381 if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
1382 res = sn9c102_store_val(cd, attr, buf, len);
1383
1384 return res;
1385}
1386
1387
1388static ssize_t
1389sn9c102_store_red(struct device* cd, struct device_attribute *attr,
1390 const char* buf, size_t len)
1391{
1392 ssize_t res = 0;
1393 u16 value;
1394 ssize_t count;
1395
1396 value = sn9c102_strtou16(buf, len, &count);
1397 if (!count || value > 0x7f)
1398 return -EINVAL;
1399
1400 if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
1401 res = sn9c102_store_val(cd, attr, buf, len);
1402
1403 return res;
1404}
1405
1406
1407static ssize_t sn9c102_show_frame_header(struct device* cd,
1408 struct device_attribute *attr,
1409 char* buf)
1410{
1411 struct sn9c102_device* cam;
1412 ssize_t count;
1413
1414 cam = video_get_drvdata(container_of(cd, struct video_device, dev));
1415 if (!cam)
1416 return -ENODEV;
1417
1418 count = sizeof(cam->sysfs.frame_header);
1419 memcpy(buf, cam->sysfs.frame_header, count);
1420
1421 DBG(3, "Frame header, read bytes: %zd", count);
1422
1423 return count;
1424}
1425
1426
1427static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);
1428static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);
1429static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
1430 sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
1431static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
1432 sn9c102_show_i2c_val, sn9c102_store_i2c_val);
1433static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green);
1434static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue);
1435static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red);
1436static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
1437
1438
1439static int sn9c102_create_sysfs(struct sn9c102_device* cam)
1440{
1441 struct device *dev = &(cam->v4ldev->dev);
1442 int err = 0;
1443
1444 if ((err = device_create_file(dev, &dev_attr_reg)))
1445 goto err_out;
1446 if ((err = device_create_file(dev, &dev_attr_val)))
1447 goto err_reg;
1448 if ((err = device_create_file(dev, &dev_attr_frame_header)))
1449 goto err_val;
1450
1451 if (cam->sensor.sysfs_ops) {
1452 if ((err = device_create_file(dev, &dev_attr_i2c_reg)))
1453 goto err_frame_header;
1454 if ((err = device_create_file(dev, &dev_attr_i2c_val)))
1455 goto err_i2c_reg;
1456 }
1457
1458 if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
1459 if ((err = device_create_file(dev, &dev_attr_green)))
1460 goto err_i2c_val;
1461 } else {
1462 if ((err = device_create_file(dev, &dev_attr_blue)))
1463 goto err_i2c_val;
1464 if ((err = device_create_file(dev, &dev_attr_red)))
1465 goto err_blue;
1466 }
1467
1468 return 0;
1469
1470err_blue:
1471 device_remove_file(dev, &dev_attr_blue);
1472err_i2c_val:
1473 if (cam->sensor.sysfs_ops)
1474 device_remove_file(dev, &dev_attr_i2c_val);
1475err_i2c_reg:
1476 if (cam->sensor.sysfs_ops)
1477 device_remove_file(dev, &dev_attr_i2c_reg);
1478err_frame_header:
1479 device_remove_file(dev, &dev_attr_frame_header);
1480err_val:
1481 device_remove_file(dev, &dev_attr_val);
1482err_reg:
1483 device_remove_file(dev, &dev_attr_reg);
1484err_out:
1485 return err;
1486}
1487#endif /* CONFIG_VIDEO_ADV_DEBUG */
1488
1489/*****************************************************************************/
1490
1491static int
1492sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
1493{
1494 int err = 0;
1495
1496 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
1497 pix->pixelformat == V4L2_PIX_FMT_JPEG) {
1498 switch (cam->bridge) {
1499 case BRIDGE_SN9C101:
1500 case BRIDGE_SN9C102:
1501 case BRIDGE_SN9C103:
1502 err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
1503 0x18);
1504 break;
1505 case BRIDGE_SN9C105:
1506 case BRIDGE_SN9C120:
1507 err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
1508 0x18);
1509 break;
1510 }
1511 } else {
1512 switch (cam->bridge) {
1513 case BRIDGE_SN9C101:
1514 case BRIDGE_SN9C102:
1515 case BRIDGE_SN9C103:
1516 err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
1517 0x18);
1518 break;
1519 case BRIDGE_SN9C105:
1520 case BRIDGE_SN9C120:
1521 err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
1522 0x18);
1523 break;
1524 }
1525 }
1526
1527 return err ? -EIO : 0;
1528}
1529
1530
1531static int
1532sn9c102_set_compression(struct sn9c102_device* cam,
1533 struct v4l2_jpegcompression* compression)
1534{
1535 int i, err = 0;
1536
1537 switch (cam->bridge) {
1538 case BRIDGE_SN9C101:
1539 case BRIDGE_SN9C102:
1540 case BRIDGE_SN9C103:
1541 if (compression->quality == 0)
1542 err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
1543 0x17);
1544 else if (compression->quality == 1)
1545 err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
1546 0x17);
1547 break;
1548 case BRIDGE_SN9C105:
1549 case BRIDGE_SN9C120:
1550 if (compression->quality == 0) {
1551 for (i = 0; i <= 63; i++) {
1552 err += sn9c102_write_reg(cam,
1553 SN9C102_Y_QTABLE1[i],
1554 0x100 + i);
1555 err += sn9c102_write_reg(cam,
1556 SN9C102_UV_QTABLE1[i],
1557 0x140 + i);
1558 }
1559 err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
1560 0x18);
1561 } else if (compression->quality == 1) {
1562 for (i = 0; i <= 63; i++) {
1563 err += sn9c102_write_reg(cam,
1564 SN9C102_Y_QTABLE1[i],
1565 0x100 + i);
1566 err += sn9c102_write_reg(cam,
1567 SN9C102_UV_QTABLE1[i],
1568 0x140 + i);
1569 }
1570 err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40,
1571 0x18);
1572 }
1573 break;
1574 }
1575
1576 return err ? -EIO : 0;
1577}
1578
1579
1580static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
1581{
1582 u8 r = 0;
1583 int err = 0;
1584
1585 if (scale == 1)
1586 r = cam->reg[0x18] & 0xcf;
1587 else if (scale == 2) {
1588 r = cam->reg[0x18] & 0xcf;
1589 r |= 0x10;
1590 } else if (scale == 4)
1591 r = cam->reg[0x18] | 0x20;
1592
1593 err += sn9c102_write_reg(cam, r, 0x18);
1594 if (err)
1595 return -EIO;
1596
1597 PDBGG("Scaling factor: %u", scale);
1598
1599 return 0;
1600}
1601
1602
1603static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
1604{
1605 struct sn9c102_sensor* s = &cam->sensor;
1606 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
1607 v_start = (u8)(rect->top - s->cropcap.bounds.top),
1608 h_size = (u8)(rect->width / 16),
1609 v_size = (u8)(rect->height / 16);
1610 int err = 0;
1611
1612 err += sn9c102_write_reg(cam, h_start, 0x12);
1613 err += sn9c102_write_reg(cam, v_start, 0x13);
1614 err += sn9c102_write_reg(cam, h_size, 0x15);
1615 err += sn9c102_write_reg(cam, v_size, 0x16);
1616 if (err)
1617 return -EIO;
1618
1619 PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
1620 "%u %u %u %u", h_start, v_start, h_size, v_size);
1621
1622 return 0;
1623}
1624
1625
1626static int sn9c102_init(struct sn9c102_device* cam)
1627{
1628 struct sn9c102_sensor* s = &cam->sensor;
1629 struct v4l2_control ctrl;
1630 struct v4l2_queryctrl *qctrl;
1631 struct v4l2_rect* rect;
1632 u8 i = 0;
1633 int err = 0;
1634
1635 if (!(cam->state & DEV_INITIALIZED)) {
1636 mutex_init(&cam->open_mutex);
1637 init_waitqueue_head(&cam->wait_open);
1638 qctrl = s->qctrl;
1639 rect = &(s->cropcap.defrect);
1640 } else { /* use current values */
1641 qctrl = s->_qctrl;
1642 rect = &(s->_rect);
1643 }
1644
1645 err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
1646 err += sn9c102_set_crop(cam, rect);
1647 if (err)
1648 return err;
1649
1650 if (s->init) {
1651 err = s->init(cam);
1652 if (err) {
1653 DBG(3, "Sensor initialization failed");
1654 return err;
1655 }
1656 }
1657
1658 if (!(cam->state & DEV_INITIALIZED))
1659 if (cam->bridge == BRIDGE_SN9C101 ||
1660 cam->bridge == BRIDGE_SN9C102 ||
1661 cam->bridge == BRIDGE_SN9C103) {
1662 if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
1663 s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
1664 cam->compression.quality = cam->reg[0x17] & 0x01 ?
1665 0 : 1;
1666 } else {
1667 if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
1668 s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG;
1669 cam->compression.quality = cam->reg[0x18] & 0x40 ?
1670 0 : 1;
1671 err += sn9c102_set_compression(cam, &cam->compression);
1672 }
1673 else
1674 err += sn9c102_set_compression(cam, &cam->compression);
1675 err += sn9c102_set_pix_format(cam, &s->pix_format);
1676 if (s->set_pix_format)
1677 err += s->set_pix_format(cam, &s->pix_format);
1678 if (err)
1679 return err;
1680
1681 if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
1682 s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
1683 DBG(3, "Compressed video format is active, quality %d",
1684 cam->compression.quality);
1685 else
1686 DBG(3, "Uncompressed video format is active");
1687
1688 if (s->set_crop)
1689 if ((err = s->set_crop(cam, rect))) {
1690 DBG(3, "set_crop() failed");
1691 return err;
1692 }
1693
1694 if (s->set_ctrl) {
1695 for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
1696 if (s->qctrl[i].id != 0 &&
1697 !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
1698 ctrl.id = s->qctrl[i].id;
1699 ctrl.value = qctrl[i].default_value;
1700 err = s->set_ctrl(cam, &ctrl);
1701 if (err) {
1702 DBG(3, "Set %s control failed",
1703 s->qctrl[i].name);
1704 return err;
1705 }
1706 DBG(3, "Image sensor supports '%s' control",
1707 s->qctrl[i].name);
1708 }
1709 }
1710
1711 if (!(cam->state & DEV_INITIALIZED)) {
1712 mutex_init(&cam->fileop_mutex);
1713 spin_lock_init(&cam->queue_lock);
1714 init_waitqueue_head(&cam->wait_frame);
1715 init_waitqueue_head(&cam->wait_stream);
1716 cam->nreadbuffers = 2;
1717 memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
1718 memcpy(&(s->_rect), &(s->cropcap.defrect),
1719 sizeof(struct v4l2_rect));
1720 cam->state |= DEV_INITIALIZED;
1721 }
1722
1723 DBG(2, "Initialization succeeded");
1724 return 0;
1725}
1726
1727/*****************************************************************************/
1728
1729static void sn9c102_release_resources(struct kref *kref)
1730{
1731 struct sn9c102_device *cam;
1732
1733 mutex_lock(&sn9c102_sysfs_lock);
1734
1735 cam = container_of(kref, struct sn9c102_device, kref);
1736
1737 DBG(2, "V4L2 device %s deregistered",
1738 video_device_node_name(cam->v4ldev));
1739 video_set_drvdata(cam->v4ldev, NULL);
1740 video_unregister_device(cam->v4ldev);
1741 usb_put_dev(cam->usbdev);
1742 kfree(cam->control_buffer);
1743 kfree(cam);
1744
1745 mutex_unlock(&sn9c102_sysfs_lock);
1746
1747}
1748
1749
1750static int sn9c102_open(struct file *filp)
1751{
1752 struct sn9c102_device* cam;
1753 int err = 0;
1754
1755 /*
1756 A read_trylock() in open() is the only safe way to prevent race
1757 conditions with disconnect(), one close() and multiple (not
1758 necessarily simultaneous) attempts to open(). For example, it
1759 prevents from waiting for a second access, while the device
1760 structure is being deallocated, after a possible disconnect() and
1761 during a following close() holding the write lock: given that, after
1762 this deallocation, no access will be possible anymore, using the
1763 non-trylock version would have let open() gain the access to the
1764 device structure improperly.
1765 For this reason the lock must also not be per-device.
1766 */
1767 if (!down_read_trylock(&sn9c102_dev_lock))
1768 return -ERESTARTSYS;
1769
1770 cam = video_drvdata(filp);
1771
1772 if (wait_for_completion_interruptible(&cam->probe)) {
1773 up_read(&sn9c102_dev_lock);
1774 return -ERESTARTSYS;
1775 }
1776
1777 kref_get(&cam->kref);
1778
1779 /*
1780 Make sure to isolate all the simultaneous opens.
1781 */
1782 if (mutex_lock_interruptible(&cam->open_mutex)) {
1783 kref_put(&cam->kref, sn9c102_release_resources);
1784 up_read(&sn9c102_dev_lock);
1785 return -ERESTARTSYS;
1786 }
1787
1788 if (cam->state & DEV_DISCONNECTED) {
1789 DBG(1, "Device not present");
1790 err = -ENODEV;
1791 goto out;
1792 }
1793
1794 if (cam->users) {
1795 DBG(2, "Device %s is already in use",
1796 video_device_node_name(cam->v4ldev));
1797 DBG(3, "Simultaneous opens are not supported");
1798 /*
1799 open() must follow the open flags and should block
1800 eventually while the device is in use.
1801 */
1802 if ((filp->f_flags & O_NONBLOCK) ||
1803 (filp->f_flags & O_NDELAY)) {
1804 err = -EWOULDBLOCK;
1805 goto out;
1806 }
1807 DBG(2, "A blocking open() has been requested. Wait for the "
1808 "device to be released...");
1809 up_read(&sn9c102_dev_lock);
1810 /*
1811 We will not release the "open_mutex" lock, so that only one
1812 process can be in the wait queue below. This way the process
1813 will be sleeping while holding the lock, without losing its
1814 priority after any wake_up().
1815 */
1816 err = wait_event_interruptible_exclusive(cam->wait_open,
1817 (cam->state & DEV_DISCONNECTED)
1818 || !cam->users);
1819 down_read(&sn9c102_dev_lock);
1820 if (err)
1821 goto out;
1822 if (cam->state & DEV_DISCONNECTED) {
1823 err = -ENODEV;
1824 goto out;
1825 }
1826 }
1827
1828 if (cam->state & DEV_MISCONFIGURED) {
1829 err = sn9c102_init(cam);
1830 if (err) {
1831 DBG(1, "Initialization failed again. "
1832 "I will retry on next open().");
1833 goto out;
1834 }
1835 cam->state &= ~DEV_MISCONFIGURED;
1836 }
1837
1838 if ((err = sn9c102_start_transfer(cam)))
1839 goto out;
1840
1841 filp->private_data = cam;
1842 cam->users++;
1843 cam->io = IO_NONE;
1844 cam->stream = STREAM_OFF;
1845 cam->nbuffers = 0;
1846 cam->frame_count = 0;
1847 sn9c102_empty_framequeues(cam);
1848
1849 DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev));
1850
1851out:
1852 mutex_unlock(&cam->open_mutex);
1853 if (err)
1854 kref_put(&cam->kref, sn9c102_release_resources);
1855
1856 up_read(&sn9c102_dev_lock);
1857 return err;
1858}
1859
1860
1861static int sn9c102_release(struct file *filp)
1862{
1863 struct sn9c102_device* cam;
1864
1865 down_write(&sn9c102_dev_lock);
1866
1867 cam = video_drvdata(filp);
1868
1869 sn9c102_stop_transfer(cam);
1870 sn9c102_release_buffers(cam);
1871 cam->users--;
1872 wake_up_interruptible_nr(&cam->wait_open, 1);
1873
1874 DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev));
1875
1876 kref_put(&cam->kref, sn9c102_release_resources);
1877
1878 up_write(&sn9c102_dev_lock);
1879
1880 return 0;
1881}
1882
1883
1884static ssize_t
1885sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
1886{
1887 struct sn9c102_device *cam = video_drvdata(filp);
1888 struct sn9c102_frame_t* f, * i;
1889 unsigned long lock_flags;
1890 long timeout;
1891 int err = 0;
1892
1893 if (mutex_lock_interruptible(&cam->fileop_mutex))
1894 return -ERESTARTSYS;
1895
1896 if (cam->state & DEV_DISCONNECTED) {
1897 DBG(1, "Device not present");
1898 mutex_unlock(&cam->fileop_mutex);
1899 return -ENODEV;
1900 }
1901
1902 if (cam->state & DEV_MISCONFIGURED) {
1903 DBG(1, "The camera is misconfigured. Close and open it "
1904 "again.");
1905 mutex_unlock(&cam->fileop_mutex);
1906 return -EIO;
1907 }
1908
1909 if (cam->io == IO_MMAP) {
1910 DBG(3, "Close and open the device again to choose "
1911 "the read method");
1912 mutex_unlock(&cam->fileop_mutex);
1913 return -EBUSY;
1914 }
1915
1916 if (cam->io == IO_NONE) {
1917 if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
1918 DBG(1, "read() failed, not enough memory");
1919 mutex_unlock(&cam->fileop_mutex);
1920 return -ENOMEM;
1921 }
1922 cam->io = IO_READ;
1923 cam->stream = STREAM_ON;
1924 }
1925
1926 if (list_empty(&cam->inqueue)) {
1927 if (!list_empty(&cam->outqueue))
1928 sn9c102_empty_framequeues(cam);
1929 sn9c102_queue_unusedframes(cam);
1930 }
1931
1932 if (!count) {
1933 mutex_unlock(&cam->fileop_mutex);
1934 return 0;
1935 }
1936
1937 if (list_empty(&cam->outqueue)) {
1938 if (filp->f_flags & O_NONBLOCK) {
1939 mutex_unlock(&cam->fileop_mutex);
1940 return -EAGAIN;
1941 }
1942 if (!cam->module_param.frame_timeout) {
1943 err = wait_event_interruptible
1944 ( cam->wait_frame,
1945 (!list_empty(&cam->outqueue)) ||
1946 (cam->state & DEV_DISCONNECTED) ||
1947 (cam->state & DEV_MISCONFIGURED) );
1948 if (err) {
1949 mutex_unlock(&cam->fileop_mutex);
1950 return err;
1951 }
1952 } else {
1953 timeout = wait_event_interruptible_timeout
1954 ( cam->wait_frame,
1955 (!list_empty(&cam->outqueue)) ||
1956 (cam->state & DEV_DISCONNECTED) ||
1957 (cam->state & DEV_MISCONFIGURED),
1958 msecs_to_jiffies(
1959 cam->module_param.frame_timeout * 1000
1960 )
1961 );
1962 if (timeout < 0) {
1963 mutex_unlock(&cam->fileop_mutex);
1964 return timeout;
1965 } else if (timeout == 0 &&
1966 !(cam->state & DEV_DISCONNECTED)) {
1967 DBG(1, "Video frame timeout elapsed");
1968 mutex_unlock(&cam->fileop_mutex);
1969 return -EIO;
1970 }
1971 }
1972 if (cam->state & DEV_DISCONNECTED) {
1973 mutex_unlock(&cam->fileop_mutex);
1974 return -ENODEV;
1975 }
1976 if (cam->state & DEV_MISCONFIGURED) {
1977 mutex_unlock(&cam->fileop_mutex);
1978 return -EIO;
1979 }
1980 }
1981
1982 f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
1983
1984 if (count > f->buf.bytesused)
1985 count = f->buf.bytesused;
1986
1987 if (copy_to_user(buf, f->bufmem, count)) {
1988 err = -EFAULT;
1989 goto exit;
1990 }
1991 *f_pos += count;
1992
1993exit:
1994 spin_lock_irqsave(&cam->queue_lock, lock_flags);
1995 list_for_each_entry(i, &cam->outqueue, frame)
1996 i->state = F_UNUSED;
1997 INIT_LIST_HEAD(&cam->outqueue);
1998 spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
1999
2000 sn9c102_queue_unusedframes(cam);
2001
2002 PDBGG("Frame #%lu, bytes read: %zu",
2003 (unsigned long)f->buf.index, count);
2004
2005 mutex_unlock(&cam->fileop_mutex);
2006
2007 return count;
2008}
2009
2010
2011static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
2012{
2013 struct sn9c102_device *cam = video_drvdata(filp);
2014 struct sn9c102_frame_t* f;
2015 unsigned long lock_flags;
2016 unsigned int mask = 0;
2017
2018 if (mutex_lock_interruptible(&cam->fileop_mutex))
2019 return POLLERR;
2020
2021 if (cam->state & DEV_DISCONNECTED) {
2022 DBG(1, "Device not present");
2023 goto error;
2024 }
2025
2026 if (cam->state & DEV_MISCONFIGURED) {
2027 DBG(1, "The camera is misconfigured. Close and open it "
2028 "again.");
2029 goto error;
2030 }
2031
2032 if (cam->io == IO_NONE) {
2033 if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
2034 IO_READ)) {
2035 DBG(1, "poll() failed, not enough memory");
2036 goto error;
2037 }
2038 cam->io = IO_READ;
2039 cam->stream = STREAM_ON;
2040 }
2041
2042 if (cam->io == IO_READ) {
2043 spin_lock_irqsave(&cam->queue_lock, lock_flags);
2044 list_for_each_entry(f, &cam->outqueue, frame)
2045 f->state = F_UNUSED;
2046 INIT_LIST_HEAD(&cam->outqueue);
2047 spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
2048 sn9c102_queue_unusedframes(cam);
2049 }
2050
2051 poll_wait(filp, &cam->wait_frame, wait);
2052
2053 if (!list_empty(&cam->outqueue))
2054 mask |= POLLIN | POLLRDNORM;
2055
2056 mutex_unlock(&cam->fileop_mutex);
2057
2058 return mask;
2059
2060error:
2061 mutex_unlock(&cam->fileop_mutex);
2062 return POLLERR;
2063}
2064
2065
2066static void sn9c102_vm_open(struct vm_area_struct* vma)
2067{
2068 struct sn9c102_frame_t* f = vma->vm_private_data;
2069 f->vma_use_count++;
2070}
2071
2072
2073static void sn9c102_vm_close(struct vm_area_struct* vma)
2074{
2075 /* NOTE: buffers are not freed here */
2076 struct sn9c102_frame_t* f = vma->vm_private_data;
2077 f->vma_use_count--;
2078}
2079
2080
2081static const struct vm_operations_struct sn9c102_vm_ops = {
2082 .open = sn9c102_vm_open,
2083 .close = sn9c102_vm_close,
2084};
2085
2086
2087static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
2088{
2089 struct sn9c102_device *cam = video_drvdata(filp);
2090 unsigned long size = vma->vm_end - vma->vm_start,
2091 start = vma->vm_start;
2092 void *pos;
2093 u32 i;
2094
2095 if (mutex_lock_interruptible(&cam->fileop_mutex))
2096 return -ERESTARTSYS;
2097
2098 if (cam->state & DEV_DISCONNECTED) {
2099 DBG(1, "Device not present");
2100 mutex_unlock(&cam->fileop_mutex);
2101 return -ENODEV;
2102 }
2103
2104 if (cam->state & DEV_MISCONFIGURED) {
2105 DBG(1, "The camera is misconfigured. Close and open it "
2106 "again.");
2107 mutex_unlock(&cam->fileop_mutex);
2108 return -EIO;
2109 }
2110
2111 if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
2112 mutex_unlock(&cam->fileop_mutex);
2113 return -EACCES;
2114 }
2115
2116 if (cam->io != IO_MMAP ||
2117 size != PAGE_ALIGN(cam->frame[0].buf.length)) {
2118 mutex_unlock(&cam->fileop_mutex);
2119 return -EINVAL;
2120 }
2121
2122 for (i = 0; i < cam->nbuffers; i++) {
2123 if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
2124 break;
2125 }
2126 if (i == cam->nbuffers) {
2127 mutex_unlock(&cam->fileop_mutex);
2128 return -EINVAL;
2129 }
2130
2131 vma->vm_flags |= VM_IO;
2132 vma->vm_flags |= VM_RESERVED;
2133
2134 pos = cam->frame[i].bufmem;
2135 while (size > 0) { /* size is page-aligned */
2136 if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
2137 mutex_unlock(&cam->fileop_mutex);
2138 return -EAGAIN;
2139 }
2140 start += PAGE_SIZE;
2141 pos += PAGE_SIZE;
2142 size -= PAGE_SIZE;
2143 }
2144
2145 vma->vm_ops = &sn9c102_vm_ops;
2146 vma->vm_private_data = &cam->frame[i];
2147 sn9c102_vm_open(vma);
2148
2149 mutex_unlock(&cam->fileop_mutex);
2150
2151 return 0;
2152}
2153
2154/*****************************************************************************/
2155
2156static int
2157sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
2158{
2159 struct v4l2_capability cap = {
2160 .driver = "sn9c102",
2161 .version = LINUX_VERSION_CODE,
2162 .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
2163 V4L2_CAP_STREAMING,
2164 };
2165
2166 strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
2167 if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
2168 strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
2169 sizeof(cap.bus_info));
2170
2171 if (copy_to_user(arg, &cap, sizeof(cap)))
2172 return -EFAULT;
2173
2174 return 0;
2175}
2176
2177
2178static int
2179sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
2180{
2181 struct v4l2_input i;
2182
2183 if (copy_from_user(&i, arg, sizeof(i)))
2184 return -EFAULT;
2185
2186 if (i.index)
2187 return -EINVAL;
2188
2189 memset(&i, 0, sizeof(i));
2190 strcpy(i.name, "Camera");
2191 i.type = V4L2_INPUT_TYPE_CAMERA;
2192 i.capabilities = V4L2_IN_CAP_STD;
2193
2194 if (copy_to_user(arg, &i, sizeof(i)))
2195 return -EFAULT;
2196
2197 return 0;
2198}
2199
2200
2201static int
2202sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
2203{
2204 int index = 0;
2205
2206 if (copy_to_user(arg, &index, sizeof(index)))
2207 return -EFAULT;
2208
2209 return 0;
2210}
2211
2212
2213static int
2214sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
2215{
2216 int index;
2217
2218 if (copy_from_user(&index, arg, sizeof(index)))
2219 return -EFAULT;
2220
2221 if (index != 0)
2222 return -EINVAL;
2223
2224 return 0;
2225}
2226
2227
2228static int
2229sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
2230{
2231 struct sn9c102_sensor* s = &cam->sensor;
2232 struct v4l2_queryctrl qc;
2233 u8 i;
2234
2235 if (copy_from_user(&qc, arg, sizeof(qc)))
2236 return -EFAULT;
2237
2238 for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
2239 if (qc.id && qc.id == s->qctrl[i].id) {
2240 memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
2241 if (copy_to_user(arg, &qc, sizeof(qc)))
2242 return -EFAULT;
2243 return 0;
2244 }
2245
2246 return -EINVAL;
2247}
2248
2249
2250static int
2251sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
2252{
2253 struct sn9c102_sensor* s = &cam->sensor;
2254 struct v4l2_control ctrl;
2255 int err = 0;
2256 u8 i;
2257
2258 if (!s->get_ctrl && !s->set_ctrl)
2259 return -EINVAL;
2260
2261 if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
2262 return -EFAULT;
2263
2264 if (!s->get_ctrl) {
2265 for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
2266 if (ctrl.id && ctrl.id == s->qctrl[i].id) {
2267 ctrl.value = s->_qctrl[i].default_value;
2268 goto exit;
2269 }
2270 return -EINVAL;
2271 } else
2272 err = s->get_ctrl(cam, &ctrl);
2273
2274exit:
2275 if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
2276 return -EFAULT;
2277
2278 PDBGG("VIDIOC_G_CTRL: id %lu, value %lu",
2279 (unsigned long)ctrl.id, (unsigned long)ctrl.value);
2280
2281 return err;
2282}
2283
2284
2285static int
2286sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
2287{
2288 struct sn9c102_sensor* s = &cam->sensor;
2289 struct v4l2_control ctrl;
2290 u8 i;
2291 int err = 0;
2292
2293 if (!s->set_ctrl)
2294 return -EINVAL;
2295
2296 if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
2297 return -EFAULT;
2298
2299 for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
2300 if (ctrl.id == s->qctrl[i].id) {
2301 if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
2302 return -EINVAL;
2303 if (ctrl.value < s->qctrl[i].minimum ||
2304 ctrl.value > s->qctrl[i].maximum)
2305 return -ERANGE;
2306 ctrl.value -= ctrl.value % s->qctrl[i].step;
2307 break;
2308 }
2309 }
2310 if (i == ARRAY_SIZE(s->qctrl))
2311 return -EINVAL;
2312 if ((err = s->set_ctrl(cam, &ctrl)))
2313 return err;
2314
2315 s->_qctrl[i].default_value = ctrl.value;
2316
2317 PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
2318 (unsigned long)ctrl.id, (unsigned long)ctrl.value);
2319
2320 return 0;
2321}
2322
2323
2324static int
2325sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
2326{
2327 struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
2328
2329 cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2330 cc->pixelaspect.numerator = 1;
2331 cc->pixelaspect.denominator = 1;
2332
2333 if (copy_to_user(arg, cc, sizeof(*cc)))
2334 return -EFAULT;
2335
2336 return 0;
2337}
2338
2339
2340static int
2341sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
2342{
2343 struct sn9c102_sensor* s = &cam->sensor;
2344 struct v4l2_crop crop = {
2345 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
2346 };
2347
2348 memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
2349
2350 if (copy_to_user(arg, &crop, sizeof(crop)))
2351 return -EFAULT;
2352
2353 return 0;
2354}
2355
2356
2357static int
2358sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
2359{
2360 struct sn9c102_sensor* s = &cam->sensor;
2361 struct v4l2_crop crop;
2362 struct v4l2_rect* rect;
2363 struct v4l2_rect* bounds = &(s->cropcap.bounds);
2364 struct v4l2_pix_format* pix_format = &(s->pix_format);
2365 u8 scale;
2366 const enum sn9c102_stream_state stream = cam->stream;
2367 const u32 nbuffers = cam->nbuffers;
2368 u32 i;
2369 int err = 0;
2370
2371 if (copy_from_user(&crop, arg, sizeof(crop)))
2372 return -EFAULT;
2373
2374 rect = &(crop.c);
2375
2376 if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2377 return -EINVAL;
2378
2379 if (cam->module_param.force_munmap)
2380 for (i = 0; i < cam->nbuffers; i++)
2381 if (cam->frame[i].vma_use_count) {
2382 DBG(3, "VIDIOC_S_CROP failed. "
2383 "Unmap the buffers first.");
2384 return -EBUSY;
2385 }
2386
2387 /* Preserve R,G or B origin */
2388 rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
2389 rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
2390
2391 if (rect->width < 16)
2392 rect->width = 16;
2393 if (rect->height < 16)
2394 rect->height = 16;
2395 if (rect->width > bounds->width)
2396 rect->width = bounds->width;
2397 if (rect->height > bounds->height)
2398 rect->height = bounds->height;
2399 if (rect->left < bounds->left)
2400 rect->left = bounds->left;
2401 if (rect->top < bounds->top)
2402 rect->top = bounds->top;
2403 if (rect->left + rect->width > bounds->left + bounds->width)
2404 rect->left = bounds->left+bounds->width - rect->width;
2405 if (rect->top + rect->height > bounds->top + bounds->height)
2406 rect->top = bounds->top+bounds->height - rect->height;
2407
2408 rect->width &= ~15L;
2409 rect->height &= ~15L;
2410
2411 if (SN9C102_PRESERVE_IMGSCALE) {
2412 /* Calculate the actual scaling factor */
2413 u32 a, b;
2414 a = rect->width * rect->height;
2415 b = pix_format->width * pix_format->height;
2416 scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
2417 } else
2418 scale = 1;
2419
2420 if (cam->stream == STREAM_ON)
2421 if ((err = sn9c102_stream_interrupt(cam)))
2422 return err;
2423
2424 if (copy_to_user(arg, &crop, sizeof(crop))) {
2425 cam->stream = stream;
2426 return -EFAULT;
2427 }
2428
2429 if (cam->module_param.force_munmap || cam->io == IO_READ)
2430 sn9c102_release_buffers(cam);
2431
2432 err = sn9c102_set_crop(cam, rect);
2433 if (s->set_crop)
2434 err += s->set_crop(cam, rect);
2435 err += sn9c102_set_scale(cam, scale);
2436
2437 if (err) { /* atomic, no rollback in ioctl() */
2438 cam->state |= DEV_MISCONFIGURED;
2439 DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
2440 "use the camera, close and open %s again.",
2441 video_device_node_name(cam->v4ldev));
2442 return -EIO;
2443 }
2444
2445 s->pix_format.width = rect->width/scale;
2446 s->pix_format.height = rect->height/scale;
2447 memcpy(&(s->_rect), rect, sizeof(*rect));
2448
2449 if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
2450 nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
2451 cam->state |= DEV_MISCONFIGURED;
2452 DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
2453 "use the camera, close and open %s again.",
2454 video_device_node_name(cam->v4ldev));
2455 return -ENOMEM;
2456 }
2457
2458 if (cam->io == IO_READ)
2459 sn9c102_empty_framequeues(cam);
2460 else if (cam->module_param.force_munmap)
2461 sn9c102_requeue_outqueue(cam);
2462
2463 cam->stream = stream;
2464
2465 return 0;
2466}
2467
2468
2469static int
2470sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
2471{
2472 struct v4l2_frmsizeenum frmsize;
2473
2474 if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
2475 return -EFAULT;
2476
2477 if (frmsize.index != 0)
2478 return -EINVAL;
2479
2480 switch (cam->bridge) {
2481 case BRIDGE_SN9C101:
2482 case BRIDGE_SN9C102:
2483 case BRIDGE_SN9C103:
2484 if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X &&
2485 frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
2486 return -EINVAL;
2487 case BRIDGE_SN9C105:
2488 case BRIDGE_SN9C120:
2489 if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG &&
2490 frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
2491 return -EINVAL;
2492 }
2493
2494 frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
2495 frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
2496 frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
2497 frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
2498 frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
2499 memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
2500
2501 if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
2502 return -EFAULT;
2503
2504 return 0;
2505}
2506
2507
2508static int
2509sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
2510{
2511 struct v4l2_fmtdesc fmtd;
2512
2513 if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
2514 return -EFAULT;
2515
2516 if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2517 return -EINVAL;
2518
2519 if (fmtd.index == 0) {
2520 strcpy(fmtd.description, "bayer rgb");
2521 fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
2522 } else if (fmtd.index == 1) {
2523 switch (cam->bridge) {
2524 case BRIDGE_SN9C101:
2525 case BRIDGE_SN9C102:
2526 case BRIDGE_SN9C103:
2527 strcpy(fmtd.description, "compressed");
2528 fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
2529 break;
2530 case BRIDGE_SN9C105:
2531 case BRIDGE_SN9C120:
2532 strcpy(fmtd.description, "JPEG");
2533 fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
2534 break;
2535 }
2536 fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
2537 } else
2538 return -EINVAL;
2539
2540 fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2541 memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
2542
2543 if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
2544 return -EFAULT;
2545
2546 return 0;
2547}
2548
2549
2550static int
2551sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
2552{
2553 struct v4l2_format format;
2554 struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
2555
2556 if (copy_from_user(&format, arg, sizeof(format)))
2557 return -EFAULT;
2558
2559 if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2560 return -EINVAL;
2561
2562 pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ?
2563 V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
2564 pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X ||
2565 pfmt->pixelformat == V4L2_PIX_FMT_JPEG)
2566 ? 0 : (pfmt->width * pfmt->priv) / 8;
2567 pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
2568 pfmt->field = V4L2_FIELD_NONE;
2569 memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
2570
2571 if (copy_to_user(arg, &format, sizeof(format)))
2572 return -EFAULT;
2573
2574 return 0;
2575}
2576
2577
2578static int
2579sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
2580 void __user * arg)
2581{
2582 struct sn9c102_sensor* s = &cam->sensor;
2583 struct v4l2_format format;
2584 struct v4l2_pix_format* pix;
2585 struct v4l2_pix_format* pfmt = &(s->pix_format);
2586 struct v4l2_rect* bounds = &(s->cropcap.bounds);
2587 struct v4l2_rect rect;
2588 u8 scale;
2589 const enum sn9c102_stream_state stream = cam->stream;
2590 const u32 nbuffers = cam->nbuffers;
2591 u32 i;
2592 int err = 0;
2593
2594 if (copy_from_user(&format, arg, sizeof(format)))
2595 return -EFAULT;
2596
2597 pix = &(format.fmt.pix);
2598
2599 if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2600 return -EINVAL;
2601
2602 memcpy(&rect, &(s->_rect), sizeof(rect));
2603
2604 { /* calculate the actual scaling factor */
2605 u32 a, b;
2606 a = rect.width * rect.height;
2607 b = pix->width * pix->height;
2608 scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
2609 }
2610
2611 rect.width = scale * pix->width;
2612 rect.height = scale * pix->height;
2613
2614 if (rect.width < 16)
2615 rect.width = 16;
2616 if (rect.height < 16)
2617 rect.height = 16;
2618 if (rect.width > bounds->left + bounds->width - rect.left)
2619 rect.width = bounds->left + bounds->width - rect.left;
2620 if (rect.height > bounds->top + bounds->height - rect.top)
2621 rect.height = bounds->top + bounds->height - rect.top;
2622
2623 rect.width &= ~15L;
2624 rect.height &= ~15L;
2625
2626 { /* adjust the scaling factor */
2627 u32 a, b;
2628 a = rect.width * rect.height;
2629 b = pix->width * pix->height;
2630 scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
2631 }
2632
2633 pix->width = rect.width / scale;
2634 pix->height = rect.height / scale;
2635
2636 switch (cam->bridge) {
2637 case BRIDGE_SN9C101:
2638 case BRIDGE_SN9C102:
2639 case BRIDGE_SN9C103:
2640 if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
2641 pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
2642 pix->pixelformat = pfmt->pixelformat;
2643 break;
2644 case BRIDGE_SN9C105:
2645 case BRIDGE_SN9C120:
2646 if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
2647 pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
2648 pix->pixelformat = pfmt->pixelformat;
2649 break;
2650 }
2651 pix->priv = pfmt->priv; /* bpp */
2652 pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ?
2653 V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
2654 pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
2655 pix->pixelformat == V4L2_PIX_FMT_JPEG)
2656 ? 0 : (pix->width * pix->priv) / 8;
2657 pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
2658 pix->field = V4L2_FIELD_NONE;
2659
2660 if (cmd == VIDIOC_TRY_FMT) {
2661 if (copy_to_user(arg, &format, sizeof(format)))
2662 return -EFAULT;
2663 return 0;
2664 }
2665
2666 if (cam->module_param.force_munmap)
2667 for (i = 0; i < cam->nbuffers; i++)
2668 if (cam->frame[i].vma_use_count) {
2669 DBG(3, "VIDIOC_S_FMT failed. Unmap the "
2670 "buffers first.");
2671 return -EBUSY;
2672 }
2673
2674 if (cam->stream == STREAM_ON)
2675 if ((err = sn9c102_stream_interrupt(cam)))
2676 return err;
2677
2678 if (copy_to_user(arg, &format, sizeof(format))) {
2679 cam->stream = stream;
2680 return -EFAULT;
2681 }
2682
2683 if (cam->module_param.force_munmap || cam->io == IO_READ)
2684 sn9c102_release_buffers(cam);
2685
2686 err += sn9c102_set_pix_format(cam, pix);
2687 err += sn9c102_set_crop(cam, &rect);
2688 if (s->set_pix_format)
2689 err += s->set_pix_format(cam, pix);
2690 if (s->set_crop)
2691 err += s->set_crop(cam, &rect);
2692 err += sn9c102_set_scale(cam, scale);
2693
2694 if (err) { /* atomic, no rollback in ioctl() */
2695 cam->state |= DEV_MISCONFIGURED;
2696 DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
2697 "use the camera, close and open %s again.",
2698 video_device_node_name(cam->v4ldev));
2699 return -EIO;
2700 }
2701
2702 memcpy(pfmt, pix, sizeof(*pix));
2703 memcpy(&(s->_rect), &rect, sizeof(rect));
2704
2705 if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
2706 nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
2707 cam->state |= DEV_MISCONFIGURED;
2708 DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
2709 "use the camera, close and open %s again.",
2710 video_device_node_name(cam->v4ldev));
2711 return -ENOMEM;
2712 }
2713
2714 if (cam->io == IO_READ)
2715 sn9c102_empty_framequeues(cam);
2716 else if (cam->module_param.force_munmap)
2717 sn9c102_requeue_outqueue(cam);
2718
2719 cam->stream = stream;
2720
2721 return 0;
2722}
2723
2724
2725static int
2726sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
2727{
2728 if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
2729 return -EFAULT;
2730
2731 return 0;
2732}
2733
2734
2735static int
2736sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
2737{
2738 struct v4l2_jpegcompression jc;
2739 const enum sn9c102_stream_state stream = cam->stream;
2740 int err = 0;
2741
2742 if (copy_from_user(&jc, arg, sizeof(jc)))
2743 return -EFAULT;
2744
2745 if (jc.quality != 0 && jc.quality != 1)
2746 return -EINVAL;
2747
2748 if (cam->stream == STREAM_ON)
2749 if ((err = sn9c102_stream_interrupt(cam)))
2750 return err;
2751
2752 err += sn9c102_set_compression(cam, &jc);
2753 if (err) { /* atomic, no rollback in ioctl() */
2754 cam->state |= DEV_MISCONFIGURED;
2755 DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. "
2756 "To use the camera, close and open %s again.",
2757 video_device_node_name(cam->v4ldev));
2758 return -EIO;
2759 }
2760
2761 cam->compression.quality = jc.quality;
2762
2763 cam->stream = stream;
2764
2765 return 0;
2766}
2767
2768
2769static int
2770sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
2771{
2772 struct v4l2_requestbuffers rb;
2773 u32 i;
2774 int err;
2775
2776 if (copy_from_user(&rb, arg, sizeof(rb)))
2777 return -EFAULT;
2778
2779 if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2780 rb.memory != V4L2_MEMORY_MMAP)
2781 return -EINVAL;
2782
2783 if (cam->io == IO_READ) {
2784 DBG(3, "Close and open the device again to choose the mmap "
2785 "I/O method");
2786 return -EBUSY;
2787 }
2788
2789 for (i = 0; i < cam->nbuffers; i++)
2790 if (cam->frame[i].vma_use_count) {
2791 DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
2792 "still mapped.");
2793 return -EBUSY;
2794 }
2795
2796 if (cam->stream == STREAM_ON)
2797 if ((err = sn9c102_stream_interrupt(cam)))
2798 return err;
2799
2800 sn9c102_empty_framequeues(cam);
2801
2802 sn9c102_release_buffers(cam);
2803 if (rb.count)
2804 rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
2805
2806 if (copy_to_user(arg, &rb, sizeof(rb))) {
2807 sn9c102_release_buffers(cam);
2808 cam->io = IO_NONE;
2809 return -EFAULT;
2810 }
2811
2812 cam->io = rb.count ? IO_MMAP : IO_NONE;
2813
2814 return 0;
2815}
2816
2817
2818static int
2819sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
2820{
2821 struct v4l2_buffer b;
2822
2823 if (copy_from_user(&b, arg, sizeof(b)))
2824 return -EFAULT;
2825
2826 if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2827 b.index >= cam->nbuffers || cam->io != IO_MMAP)
2828 return -EINVAL;
2829
2830 memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
2831
2832 if (cam->frame[b.index].vma_use_count)
2833 b.flags |= V4L2_BUF_FLAG_MAPPED;
2834
2835 if (cam->frame[b.index].state == F_DONE)
2836 b.flags |= V4L2_BUF_FLAG_DONE;
2837 else if (cam->frame[b.index].state != F_UNUSED)
2838 b.flags |= V4L2_BUF_FLAG_QUEUED;
2839
2840 if (copy_to_user(arg, &b, sizeof(b)))
2841 return -EFAULT;
2842
2843 return 0;
2844}
2845
2846
2847static int
2848sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
2849{
2850 struct v4l2_buffer b;
2851 unsigned long lock_flags;
2852
2853 if (copy_from_user(&b, arg, sizeof(b)))
2854 return -EFAULT;
2855
2856 if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2857 b.index >= cam->nbuffers || cam->io != IO_MMAP)
2858 return -EINVAL;
2859
2860 if (cam->frame[b.index].state != F_UNUSED)
2861 return -EINVAL;
2862
2863 cam->frame[b.index].state = F_QUEUED;
2864
2865 spin_lock_irqsave(&cam->queue_lock, lock_flags);
2866 list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
2867 spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
2868
2869 PDBGG("Frame #%lu queued", (unsigned long)b.index);
2870
2871 return 0;
2872}
2873
2874
2875static int
2876sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
2877 void __user * arg)
2878{
2879 struct v4l2_buffer b;
2880 struct sn9c102_frame_t *f;
2881 unsigned long lock_flags;
2882 long timeout;
2883 int err = 0;
2884
2885 if (copy_from_user(&b, arg, sizeof(b)))
2886 return -EFAULT;
2887
2888 if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
2889 return -EINVAL;
2890
2891 if (list_empty(&cam->outqueue)) {
2892 if (cam->stream == STREAM_OFF)
2893 return -EINVAL;
2894 if (filp->f_flags & O_NONBLOCK)
2895 return -EAGAIN;
2896 if (!cam->module_param.frame_timeout) {
2897 err = wait_event_interruptible
2898 ( cam->wait_frame,
2899 (!list_empty(&cam->outqueue)) ||
2900 (cam->state & DEV_DISCONNECTED) ||
2901 (cam->state & DEV_MISCONFIGURED) );
2902 if (err)
2903 return err;
2904 } else {
2905 timeout = wait_event_interruptible_timeout
2906 ( cam->wait_frame,
2907 (!list_empty(&cam->outqueue)) ||
2908 (cam->state & DEV_DISCONNECTED) ||
2909 (cam->state & DEV_MISCONFIGURED),
2910 cam->module_param.frame_timeout *
2911 1000 * msecs_to_jiffies(1) );
2912 if (timeout < 0)
2913 return timeout;
2914 else if (timeout == 0 &&
2915 !(cam->state & DEV_DISCONNECTED)) {
2916 DBG(1, "Video frame timeout elapsed");
2917 return -EIO;
2918 }
2919 }
2920 if (cam->state & DEV_DISCONNECTED)
2921 return -ENODEV;
2922 if (cam->state & DEV_MISCONFIGURED)
2923 return -EIO;
2924 }
2925
2926 spin_lock_irqsave(&cam->queue_lock, lock_flags);
2927 f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
2928 list_del(cam->outqueue.next);
2929 spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
2930
2931 f->state = F_UNUSED;
2932
2933 memcpy(&b, &f->buf, sizeof(b));
2934 if (f->vma_use_count)
2935 b.flags |= V4L2_BUF_FLAG_MAPPED;
2936
2937 if (copy_to_user(arg, &b, sizeof(b)))
2938 return -EFAULT;
2939
2940 PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
2941
2942 return 0;
2943}
2944
2945
2946static int
2947sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
2948{
2949 int type;
2950
2951 if (copy_from_user(&type, arg, sizeof(type)))
2952 return -EFAULT;
2953
2954 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
2955 return -EINVAL;
2956
2957 cam->stream = STREAM_ON;
2958
2959 DBG(3, "Stream on");
2960
2961 return 0;
2962}
2963
2964
2965static int
2966sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
2967{
2968 int type, err;
2969
2970 if (copy_from_user(&type, arg, sizeof(type)))
2971 return -EFAULT;
2972
2973 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
2974 return -EINVAL;
2975
2976 if (cam->stream == STREAM_ON)
2977 if ((err = sn9c102_stream_interrupt(cam)))
2978 return err;
2979
2980 sn9c102_empty_framequeues(cam);
2981
2982 DBG(3, "Stream off");
2983
2984 return 0;
2985}
2986
2987
2988static int
2989sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
2990{
2991 struct v4l2_streamparm sp;
2992
2993 if (copy_from_user(&sp, arg, sizeof(sp)))
2994 return -EFAULT;
2995
2996 if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2997 return -EINVAL;
2998
2999 sp.parm.capture.extendedmode = 0;
3000 sp.parm.capture.readbuffers = cam->nreadbuffers;
3001
3002 if (copy_to_user(arg, &sp, sizeof(sp)))
3003 return -EFAULT;
3004
3005 return 0;
3006}
3007
3008
3009static int
3010sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
3011{
3012 struct v4l2_streamparm sp;
3013
3014 if (copy_from_user(&sp, arg, sizeof(sp)))
3015 return -EFAULT;
3016
3017 if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
3018 return -EINVAL;
3019
3020 sp.parm.capture.extendedmode = 0;
3021
3022 if (sp.parm.capture.readbuffers == 0)
3023 sp.parm.capture.readbuffers = cam->nreadbuffers;
3024
3025 if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
3026 sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
3027
3028 if (copy_to_user(arg, &sp, sizeof(sp)))
3029 return -EFAULT;
3030
3031 cam->nreadbuffers = sp.parm.capture.readbuffers;
3032
3033 return 0;
3034}
3035
3036
3037static int
3038sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
3039{
3040 struct v4l2_audio audio;
3041
3042 if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
3043 return -EINVAL;
3044
3045 if (copy_from_user(&audio, arg, sizeof(audio)))
3046 return -EFAULT;
3047
3048 if (audio.index != 0)
3049 return -EINVAL;
3050
3051 strcpy(audio.name, "Microphone");
3052 audio.capability = 0;
3053 audio.mode = 0;
3054
3055 if (copy_to_user(arg, &audio, sizeof(audio)))
3056 return -EFAULT;
3057
3058 return 0;
3059}
3060
3061
3062static int
3063sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
3064{
3065 struct v4l2_audio audio;
3066
3067 if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
3068 return -EINVAL;
3069
3070 if (copy_from_user(&audio, arg, sizeof(audio)))
3071 return -EFAULT;
3072
3073 memset(&audio, 0, sizeof(audio));
3074 strcpy(audio.name, "Microphone");
3075
3076 if (copy_to_user(arg, &audio, sizeof(audio)))
3077 return -EFAULT;
3078
3079 return 0;
3080}
3081
3082
3083static int
3084sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
3085{
3086 struct v4l2_audio audio;
3087
3088 if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
3089 return -EINVAL;
3090
3091 if (copy_from_user(&audio, arg, sizeof(audio)))
3092 return -EFAULT;
3093
3094 if (audio.index != 0)
3095 return -EINVAL;
3096
3097 return 0;
3098}
3099
3100
3101static long sn9c102_ioctl_v4l2(struct file *filp,
3102 unsigned int cmd, void __user *arg)
3103{
3104 struct sn9c102_device *cam = video_drvdata(filp);
3105
3106 switch (cmd) {
3107
3108 case VIDIOC_QUERYCAP:
3109 return sn9c102_vidioc_querycap(cam, arg);
3110
3111 case VIDIOC_ENUMINPUT:
3112 return sn9c102_vidioc_enuminput(cam, arg);
3113
3114 case VIDIOC_G_INPUT:
3115 return sn9c102_vidioc_g_input(cam, arg);
3116
3117 case VIDIOC_S_INPUT:
3118 return sn9c102_vidioc_s_input(cam, arg);
3119
3120 case VIDIOC_QUERYCTRL:
3121 return sn9c102_vidioc_query_ctrl(cam, arg);
3122
3123 case VIDIOC_G_CTRL:
3124 return sn9c102_vidioc_g_ctrl(cam, arg);
3125
3126 case VIDIOC_S_CTRL:
3127 return sn9c102_vidioc_s_ctrl(cam, arg);
3128
3129 case VIDIOC_CROPCAP:
3130 return sn9c102_vidioc_cropcap(cam, arg);
3131
3132 case VIDIOC_G_CROP:
3133 return sn9c102_vidioc_g_crop(cam, arg);
3134
3135 case VIDIOC_S_CROP:
3136 return sn9c102_vidioc_s_crop(cam, arg);
3137
3138 case VIDIOC_ENUM_FRAMESIZES:
3139 return sn9c102_vidioc_enum_framesizes(cam, arg);
3140
3141 case VIDIOC_ENUM_FMT:
3142 return sn9c102_vidioc_enum_fmt(cam, arg);
3143
3144 case VIDIOC_G_FMT:
3145 return sn9c102_vidioc_g_fmt(cam, arg);
3146
3147 case VIDIOC_TRY_FMT:
3148 case VIDIOC_S_FMT:
3149 return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
3150
3151 case VIDIOC_G_JPEGCOMP:
3152 return sn9c102_vidioc_g_jpegcomp(cam, arg);
3153
3154 case VIDIOC_S_JPEGCOMP:
3155 return sn9c102_vidioc_s_jpegcomp(cam, arg);
3156
3157 case VIDIOC_REQBUFS:
3158 return sn9c102_vidioc_reqbufs(cam, arg);
3159
3160 case VIDIOC_QUERYBUF:
3161 return sn9c102_vidioc_querybuf(cam, arg);
3162
3163 case VIDIOC_QBUF:
3164 return sn9c102_vidioc_qbuf(cam, arg);
3165
3166 case VIDIOC_DQBUF:
3167 return sn9c102_vidioc_dqbuf(cam, filp, arg);
3168
3169 case VIDIOC_STREAMON:
3170 return sn9c102_vidioc_streamon(cam, arg);
3171
3172 case VIDIOC_STREAMOFF:
3173 return sn9c102_vidioc_streamoff(cam, arg);
3174
3175 case VIDIOC_G_PARM:
3176 return sn9c102_vidioc_g_parm(cam, arg);
3177
3178 case VIDIOC_S_PARM:
3179 return sn9c102_vidioc_s_parm(cam, arg);
3180
3181 case VIDIOC_ENUMAUDIO:
3182 return sn9c102_vidioc_enumaudio(cam, arg);
3183
3184 case VIDIOC_G_AUDIO:
3185 return sn9c102_vidioc_g_audio(cam, arg);
3186
3187 case VIDIOC_S_AUDIO:
3188 return sn9c102_vidioc_s_audio(cam, arg);
3189
3190 default:
3191 return -ENOTTY;
3192
3193 }
3194}
3195
3196
3197static long sn9c102_ioctl(struct file *filp,
3198 unsigned int cmd, unsigned long arg)
3199{
3200 struct sn9c102_device *cam = video_drvdata(filp);
3201 int err = 0;
3202
3203 if (mutex_lock_interruptible(&cam->fileop_mutex))
3204 return -ERESTARTSYS;
3205
3206 if (cam->state & DEV_DISCONNECTED) {
3207 DBG(1, "Device not present");
3208 mutex_unlock(&cam->fileop_mutex);
3209 return -ENODEV;
3210 }
3211
3212 if (cam->state & DEV_MISCONFIGURED) {
3213 DBG(1, "The camera is misconfigured. Close and open it "
3214 "again.");
3215 mutex_unlock(&cam->fileop_mutex);
3216 return -EIO;
3217 }
3218
3219 V4LDBG(3, "sn9c102", cmd);
3220
3221 err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg);
3222
3223 mutex_unlock(&cam->fileop_mutex);
3224
3225 return err;
3226}
3227
3228/*****************************************************************************/
3229
3230static const struct v4l2_file_operations sn9c102_fops = {
3231 .owner = THIS_MODULE,
3232 .open = sn9c102_open,
3233 .release = sn9c102_release,
3234 .unlocked_ioctl = sn9c102_ioctl,
3235 .read = sn9c102_read,
3236 .poll = sn9c102_poll,
3237 .mmap = sn9c102_mmap,
3238};
3239
3240/*****************************************************************************/
3241
3242/* It exists a single interface only. We do not need to validate anything. */
3243static int
3244sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
3245{
3246 struct usb_device *udev = interface_to_usbdev(intf);
3247 struct sn9c102_device* cam;
3248 static unsigned int dev_nr;
3249 unsigned int i;
3250 int err = 0, r;
3251
3252 if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
3253 return -ENOMEM;
3254
3255 cam->usbdev = udev;
3256
3257 if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
3258 DBG(1, "kzalloc() failed");
3259 err = -ENOMEM;
3260 goto fail;
3261 }
3262
3263 if (!(cam->v4ldev = video_device_alloc())) {
3264 DBG(1, "video_device_alloc() failed");
3265 err = -ENOMEM;
3266 goto fail;
3267 }
3268
3269 r = sn9c102_read_reg(cam, 0x00);
3270 if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
3271 DBG(1, "Sorry, this is not a SN9C1xx-based camera "
3272 "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
3273 err = -ENODEV;
3274 goto fail;
3275 }
3276
3277 cam->bridge = id->driver_info;
3278 switch (cam->bridge) {
3279 case BRIDGE_SN9C101:
3280 case BRIDGE_SN9C102:
3281 DBG(2, "SN9C10[12] PC Camera Controller detected "
3282 "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
3283 break;
3284 case BRIDGE_SN9C103:
3285 DBG(2, "SN9C103 PC Camera Controller detected "
3286 "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
3287 break;
3288 case BRIDGE_SN9C105:
3289 DBG(2, "SN9C105 PC Camera Controller detected "
3290 "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
3291 break;
3292 case BRIDGE_SN9C120:
3293 DBG(2, "SN9C120 PC Camera Controller detected "
3294 "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
3295 break;
3296 }
3297
3298 for (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) {
3299 err = sn9c102_sensor_table[i](cam);
3300 if (!err)
3301 break;
3302 }
3303
3304 if (!err) {
3305 DBG(2, "%s image sensor detected", cam->sensor.name);
3306 DBG(3, "Support for %s maintained by %s",
3307 cam->sensor.name, cam->sensor.maintainer);
3308 } else {
3309 DBG(1, "No supported image sensor detected for this bridge");
3310 err = -ENODEV;
3311 goto fail;
3312 }
3313
3314 if (!(cam->bridge & cam->sensor.supported_bridge)) {
3315 DBG(1, "Bridge not supported");
3316 err = -ENODEV;
3317 goto fail;
3318 }
3319
3320 if (sn9c102_init(cam)) {
3321 DBG(1, "Initialization failed. I will retry on open().");
3322 cam->state |= DEV_MISCONFIGURED;
3323 }
3324
3325 strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
3326 cam->v4ldev->fops = &sn9c102_fops;
3327 cam->v4ldev->release = video_device_release;
3328 cam->v4ldev->parent = &udev->dev;
3329
3330 init_completion(&cam->probe);
3331
3332 err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
3333 video_nr[dev_nr]);
3334 if (err) {
3335 DBG(1, "V4L2 device registration failed");
3336 if (err == -ENFILE && video_nr[dev_nr] == -1)
3337 DBG(1, "Free /dev/videoX node not found");
3338 video_nr[dev_nr] = -1;
3339 dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
3340 complete_all(&cam->probe);
3341 goto fail;
3342 }
3343
3344 DBG(2, "V4L2 device registered as %s",
3345 video_device_node_name(cam->v4ldev));
3346
3347 video_set_drvdata(cam->v4ldev, cam);
3348 cam->module_param.force_munmap = force_munmap[dev_nr];
3349 cam->module_param.frame_timeout = frame_timeout[dev_nr];
3350
3351 dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
3352
3353#ifdef CONFIG_VIDEO_ADV_DEBUG
3354 err = sn9c102_create_sysfs(cam);
3355 if (!err)
3356 DBG(2, "Optional device control through 'sysfs' "
3357 "interface ready");
3358 else
3359 DBG(2, "Failed to create optional 'sysfs' interface for "
3360 "device controlling. Error #%d", err);
3361#else
3362 DBG(2, "Optional device control through 'sysfs' interface disabled");
3363 DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
3364 "configuration option to enable it.");
3365#endif
3366
3367 usb_set_intfdata(intf, cam);
3368 kref_init(&cam->kref);
3369 usb_get_dev(cam->usbdev);
3370
3371 complete_all(&cam->probe);
3372
3373 return 0;
3374
3375fail:
3376 if (cam) {
3377 kfree(cam->control_buffer);
3378 if (cam->v4ldev)
3379 video_device_release(cam->v4ldev);
3380 kfree(cam);
3381 }
3382 return err;
3383}
3384
3385
3386static void sn9c102_usb_disconnect(struct usb_interface* intf)
3387{
3388 struct sn9c102_device* cam;
3389
3390 down_write(&sn9c102_dev_lock);
3391
3392 cam = usb_get_intfdata(intf);
3393
3394 DBG(2, "Disconnecting %s...", cam->v4ldev->name);
3395
3396 if (cam->users) {
3397 DBG(2, "Device %s is open! Deregistration and memory "
3398 "deallocation are deferred.",
3399 video_device_node_name(cam->v4ldev));
3400 cam->state |= DEV_MISCONFIGURED;
3401 sn9c102_stop_transfer(cam);
3402 cam->state |= DEV_DISCONNECTED;
3403 wake_up_interruptible(&cam->wait_frame);
3404 wake_up(&cam->wait_stream);
3405 } else
3406 cam->state |= DEV_DISCONNECTED;
3407
3408 wake_up_interruptible_all(&cam->wait_open);
3409
3410 kref_put(&cam->kref, sn9c102_release_resources);
3411
3412 up_write(&sn9c102_dev_lock);
3413}
3414
3415
3416static struct usb_driver sn9c102_usb_driver = {
3417 .name = "sn9c102",
3418 .id_table = sn9c102_id_table,
3419 .probe = sn9c102_usb_probe,
3420 .disconnect = sn9c102_usb_disconnect,
3421};
3422
3423/*****************************************************************************/
3424
3425static int __init sn9c102_module_init(void)
3426{
3427 int err = 0;
3428
3429 KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
3430 KDBG(3, SN9C102_MODULE_AUTHOR);
3431
3432 if ((err = usb_register(&sn9c102_usb_driver)))
3433 KDBG(1, "usb_register() failed");
3434
3435 return err;
3436}
3437
3438
3439static void __exit sn9c102_module_exit(void)
3440{
3441 usb_deregister(&sn9c102_usb_driver);
3442}
3443
3444
3445module_init(sn9c102_module_init);
3446module_exit(sn9c102_module_exit);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
new file mode 100644
index 00000000000..b3d2cc72965
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -0,0 +1,147 @@
1/***************************************************************************
2 * Table of device identifiers of the SN9C1xx PC Camera Controllers *
3 * *
4 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 ***************************************************************************/
20
21#ifndef _SN9C102_DEVTABLE_H_
22#define _SN9C102_DEVTABLE_H_
23
24#include <linux/usb.h>
25
26struct sn9c102_device;
27
28/*
29 Each SN9C1xx camera has proper PID/VID identifiers.
30 SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
31 handle the video class interface.
32*/
33#define SN9C102_USB_DEVICE(vend, prod, bridge) \
34 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
35 USB_DEVICE_ID_MATCH_INT_CLASS, \
36 .idVendor = (vend), \
37 .idProduct = (prod), \
38 .bInterfaceClass = 0xff, \
39 .driver_info = (bridge)
40
41static const struct usb_device_id sn9c102_id_table[] = {
42 /* SN9C101 and SN9C102 */
43#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
44 { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
45 { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
46 { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
47 { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
48 { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
49/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
50 { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
51#endif
52 { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
53 { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
54#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
55 { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
56 { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
57 { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
58#endif
59 { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */
60#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
61 { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
62/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
63 { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
64#endif
65 { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */
66 /* SN9C103 */
67/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */
68 { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */
69#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
70/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
71/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */
72/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */
73/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */
74 { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
75/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
76 { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
77/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */
78/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */
79/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */
80/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
81/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
82/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */
83/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */
84/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */
85 { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
86 { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
87/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */
88/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */
89/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */
90/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */
91/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */
92/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */
93/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */
94#endif
95 /* SN9C105 */
96#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
97 { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
98 { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
99 { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
100 { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
101 { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
102/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */
103/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */
104/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */
105/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */
106/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */
107/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */
108/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */
109 { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
110 { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
111 { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
112 /* SN9C120 */
113 { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
114/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */
115/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */
116/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */
117 { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
118/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
119 { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
120 { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
121 { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
122 { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
123#endif
124 { }
125};
126
127/*
128 Probing functions: on success, you must attach the sensor to the camera
129 by calling sn9c102_attach_sensor().
130 To enable the I2C communication, you might need to perform a really basic
131 initialization of the SN9C1XX chip.
132 Functions must return 0 on success, the appropriate error otherwise.
133*/
134extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
135extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
136extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
137extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
138extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
139extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
140extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
141extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
142extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
143extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
144extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
145extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
146
147#endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
new file mode 100644
index 00000000000..2dce5c908c8
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -0,0 +1,264 @@
1/***************************************************************************
2 * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int hv7131d_init(struct sn9c102_device* cam)
27{
28 int err;
29
30 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
31 {0x00, 0x14}, {0x60, 0x17},
32 {0x0e, 0x18}, {0xf2, 0x19});
33
34 err += sn9c102_i2c_write(cam, 0x01, 0x04);
35 err += sn9c102_i2c_write(cam, 0x02, 0x00);
36 err += sn9c102_i2c_write(cam, 0x28, 0x00);
37
38 return err;
39}
40
41
42static int hv7131d_get_ctrl(struct sn9c102_device* cam,
43 struct v4l2_control* ctrl)
44{
45 switch (ctrl->id) {
46 case V4L2_CID_EXPOSURE:
47 {
48 int r1 = sn9c102_i2c_read(cam, 0x26),
49 r2 = sn9c102_i2c_read(cam, 0x27);
50 if (r1 < 0 || r2 < 0)
51 return -EIO;
52 ctrl->value = (r1 << 8) | (r2 & 0xff);
53 }
54 return 0;
55 case V4L2_CID_RED_BALANCE:
56 if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
57 return -EIO;
58 ctrl->value = 0x3f - (ctrl->value & 0x3f);
59 return 0;
60 case V4L2_CID_BLUE_BALANCE:
61 if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
62 return -EIO;
63 ctrl->value = 0x3f - (ctrl->value & 0x3f);
64 return 0;
65 case SN9C102_V4L2_CID_GREEN_BALANCE:
66 if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
67 return -EIO;
68 ctrl->value = 0x3f - (ctrl->value & 0x3f);
69 return 0;
70 case SN9C102_V4L2_CID_RESET_LEVEL:
71 if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
72 return -EIO;
73 ctrl->value &= 0x3f;
74 return 0;
75 case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
76 if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
77 return -EIO;
78 ctrl->value &= 0x07;
79 return 0;
80 default:
81 return -EINVAL;
82 }
83}
84
85
86static int hv7131d_set_ctrl(struct sn9c102_device* cam,
87 const struct v4l2_control* ctrl)
88{
89 int err = 0;
90
91 switch (ctrl->id) {
92 case V4L2_CID_EXPOSURE:
93 err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
94 err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
95 break;
96 case V4L2_CID_RED_BALANCE:
97 err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
98 break;
99 case V4L2_CID_BLUE_BALANCE:
100 err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
101 break;
102 case SN9C102_V4L2_CID_GREEN_BALANCE:
103 err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
104 break;
105 case SN9C102_V4L2_CID_RESET_LEVEL:
106 err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
107 break;
108 case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
109 err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
110 break;
111 default:
112 return -EINVAL;
113 }
114
115 return err ? -EIO : 0;
116}
117
118
119static int hv7131d_set_crop(struct sn9c102_device* cam,
120 const struct v4l2_rect* rect)
121{
122 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
123 int err = 0;
124 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
125 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
126
127 err += sn9c102_write_reg(cam, h_start, 0x12);
128 err += sn9c102_write_reg(cam, v_start, 0x13);
129
130 return err;
131}
132
133
134static int hv7131d_set_pix_format(struct sn9c102_device* cam,
135 const struct v4l2_pix_format* pix)
136{
137 int err = 0;
138
139 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
140 err += sn9c102_write_reg(cam, 0x42, 0x19);
141 else
142 err += sn9c102_write_reg(cam, 0xf2, 0x19);
143
144 return err;
145}
146
147
148static const struct sn9c102_sensor hv7131d = {
149 .name = "HV7131D",
150 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
151 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
152 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
153 .frequency = SN9C102_I2C_100KHZ,
154 .interface = SN9C102_I2C_2WIRES,
155 .i2c_slave_id = 0x11,
156 .init = &hv7131d_init,
157 .qctrl = {
158 {
159 .id = V4L2_CID_EXPOSURE,
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "exposure",
162 .minimum = 0x0250,
163 .maximum = 0xffff,
164 .step = 0x0001,
165 .default_value = 0x0250,
166 .flags = 0,
167 },
168 {
169 .id = V4L2_CID_RED_BALANCE,
170 .type = V4L2_CTRL_TYPE_INTEGER,
171 .name = "red balance",
172 .minimum = 0x00,
173 .maximum = 0x3f,
174 .step = 0x01,
175 .default_value = 0x00,
176 .flags = 0,
177 },
178 {
179 .id = V4L2_CID_BLUE_BALANCE,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "blue balance",
182 .minimum = 0x00,
183 .maximum = 0x3f,
184 .step = 0x01,
185 .default_value = 0x20,
186 .flags = 0,
187 },
188 {
189 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
190 .type = V4L2_CTRL_TYPE_INTEGER,
191 .name = "green balance",
192 .minimum = 0x00,
193 .maximum = 0x3f,
194 .step = 0x01,
195 .default_value = 0x1e,
196 .flags = 0,
197 },
198 {
199 .id = SN9C102_V4L2_CID_RESET_LEVEL,
200 .type = V4L2_CTRL_TYPE_INTEGER,
201 .name = "reset level",
202 .minimum = 0x19,
203 .maximum = 0x3f,
204 .step = 0x01,
205 .default_value = 0x30,
206 .flags = 0,
207 },
208 {
209 .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
210 .type = V4L2_CTRL_TYPE_INTEGER,
211 .name = "pixel bias voltage",
212 .minimum = 0x00,
213 .maximum = 0x07,
214 .step = 0x01,
215 .default_value = 0x02,
216 .flags = 0,
217 },
218 },
219 .get_ctrl = &hv7131d_get_ctrl,
220 .set_ctrl = &hv7131d_set_ctrl,
221 .cropcap = {
222 .bounds = {
223 .left = 0,
224 .top = 0,
225 .width = 640,
226 .height = 480,
227 },
228 .defrect = {
229 .left = 0,
230 .top = 0,
231 .width = 640,
232 .height = 480,
233 },
234 },
235 .set_crop = &hv7131d_set_crop,
236 .pix_format = {
237 .width = 640,
238 .height = 480,
239 .pixelformat = V4L2_PIX_FMT_SBGGR8,
240 .priv = 8,
241 },
242 .set_pix_format = &hv7131d_set_pix_format
243};
244
245
246int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
247{
248 int r0 = 0, r1 = 0, err;
249
250 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
251 {0x28, 0x17});
252
253 r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
254 r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
255 if (err || r0 < 0 || r1 < 0)
256 return -EIO;
257
258 if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04)
259 return -ENODEV;
260
261 sn9c102_attach_sensor(cam, &hv7131d);
262
263 return 0;
264}
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
new file mode 100644
index 00000000000..4295887ff60
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
@@ -0,0 +1,363 @@
1/***************************************************************************
2 * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int hv7131r_init(struct sn9c102_device* cam)
27{
28 int err = 0;
29
30 switch (sn9c102_get_bridge(cam)) {
31 case BRIDGE_SN9C103:
32 err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04},
33 {0x20, 0x05}, {0x20, 0x06},
34 {0x03, 0x10}, {0x00, 0x14},
35 {0x60, 0x17}, {0x0a, 0x18},
36 {0xf0, 0x19}, {0x1d, 0x1a},
37 {0x10, 0x1b}, {0x02, 0x1c},
38 {0x03, 0x1d}, {0x0f, 0x1e},
39 {0x0c, 0x1f}, {0x00, 0x20},
40 {0x10, 0x21}, {0x20, 0x22},
41 {0x30, 0x23}, {0x40, 0x24},
42 {0x50, 0x25}, {0x60, 0x26},
43 {0x70, 0x27}, {0x80, 0x28},
44 {0x90, 0x29}, {0xa0, 0x2a},
45 {0xb0, 0x2b}, {0xc0, 0x2c},
46 {0xd0, 0x2d}, {0xe0, 0x2e},
47 {0xf0, 0x2f}, {0xff, 0x30});
48 break;
49 case BRIDGE_SN9C105:
50 case BRIDGE_SN9C120:
51 err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
52 {0x00, 0x03}, {0x1a, 0x04},
53 {0x44, 0x05}, {0x3e, 0x06},
54 {0x1a, 0x07}, {0x03, 0x10},
55 {0x08, 0x14}, {0xa3, 0x17},
56 {0x4b, 0x18}, {0x00, 0x19},
57 {0x1d, 0x1a}, {0x10, 0x1b},
58 {0x02, 0x1c}, {0x03, 0x1d},
59 {0x0f, 0x1e}, {0x0c, 0x1f},
60 {0x00, 0x20}, {0x29, 0x21},
61 {0x40, 0x22}, {0x54, 0x23},
62 {0x66, 0x24}, {0x76, 0x25},
63 {0x85, 0x26}, {0x94, 0x27},
64 {0xa1, 0x28}, {0xae, 0x29},
65 {0xbb, 0x2a}, {0xc7, 0x2b},
66 {0xd3, 0x2c}, {0xde, 0x2d},
67 {0xea, 0x2e}, {0xf4, 0x2f},
68 {0xff, 0x30}, {0x00, 0x3F},
69 {0xC7, 0x40}, {0x01, 0x41},
70 {0x44, 0x42}, {0x00, 0x43},
71 {0x44, 0x44}, {0x00, 0x45},
72 {0x44, 0x46}, {0x00, 0x47},
73 {0xC7, 0x48}, {0x01, 0x49},
74 {0xC7, 0x4A}, {0x01, 0x4B},
75 {0xC7, 0x4C}, {0x01, 0x4D},
76 {0x44, 0x4E}, {0x00, 0x4F},
77 {0x44, 0x50}, {0x00, 0x51},
78 {0x44, 0x52}, {0x00, 0x53},
79 {0xC7, 0x54}, {0x01, 0x55},
80 {0xC7, 0x56}, {0x01, 0x57},
81 {0xC7, 0x58}, {0x01, 0x59},
82 {0x44, 0x5A}, {0x00, 0x5B},
83 {0x44, 0x5C}, {0x00, 0x5D},
84 {0x44, 0x5E}, {0x00, 0x5F},
85 {0xC7, 0x60}, {0x01, 0x61},
86 {0xC7, 0x62}, {0x01, 0x63},
87 {0xC7, 0x64}, {0x01, 0x65},
88 {0x44, 0x66}, {0x00, 0x67},
89 {0x44, 0x68}, {0x00, 0x69},
90 {0x44, 0x6A}, {0x00, 0x6B},
91 {0xC7, 0x6C}, {0x01, 0x6D},
92 {0xC7, 0x6E}, {0x01, 0x6F},
93 {0xC7, 0x70}, {0x01, 0x71},
94 {0x44, 0x72}, {0x00, 0x73},
95 {0x44, 0x74}, {0x00, 0x75},
96 {0x44, 0x76}, {0x00, 0x77},
97 {0xC7, 0x78}, {0x01, 0x79},
98 {0xC7, 0x7A}, {0x01, 0x7B},
99 {0xC7, 0x7C}, {0x01, 0x7D},
100 {0x44, 0x7E}, {0x00, 0x7F},
101 {0x14, 0x84}, {0x00, 0x85},
102 {0x27, 0x86}, {0x00, 0x87},
103 {0x07, 0x88}, {0x00, 0x89},
104 {0xEC, 0x8A}, {0x0f, 0x8B},
105 {0xD8, 0x8C}, {0x0f, 0x8D},
106 {0x3D, 0x8E}, {0x00, 0x8F},
107 {0x3D, 0x90}, {0x00, 0x91},
108 {0xCD, 0x92}, {0x0f, 0x93},
109 {0xf7, 0x94}, {0x0f, 0x95},
110 {0x0C, 0x96}, {0x00, 0x97},
111 {0x00, 0x98}, {0x66, 0x99},
112 {0x05, 0x9A}, {0x00, 0x9B},
113 {0x04, 0x9C}, {0x00, 0x9D},
114 {0x08, 0x9E}, {0x00, 0x9F},
115 {0x2D, 0xC0}, {0x2D, 0xC1},
116 {0x3A, 0xC2}, {0x05, 0xC3},
117 {0x04, 0xC4}, {0x3F, 0xC5},
118 {0x00, 0xC6}, {0x00, 0xC7},
119 {0x50, 0xC8}, {0x3C, 0xC9},
120 {0x28, 0xCA}, {0xD8, 0xCB},
121 {0x14, 0xCC}, {0xEC, 0xCD},
122 {0x32, 0xCE}, {0xDD, 0xCF},
123 {0x32, 0xD0}, {0xDD, 0xD1},
124 {0x6A, 0xD2}, {0x50, 0xD3},
125 {0x00, 0xD4}, {0x00, 0xD5},
126 {0x00, 0xD6});
127 break;
128 default:
129 break;
130 }
131
132 err += sn9c102_i2c_write(cam, 0x20, 0x00);
133 err += sn9c102_i2c_write(cam, 0x21, 0xd6);
134 err += sn9c102_i2c_write(cam, 0x25, 0x06);
135
136 return err;
137}
138
139
140static int hv7131r_get_ctrl(struct sn9c102_device* cam,
141 struct v4l2_control* ctrl)
142{
143 switch (ctrl->id) {
144 case V4L2_CID_GAIN:
145 if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
146 return -EIO;
147 return 0;
148 case V4L2_CID_RED_BALANCE:
149 if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
150 return -EIO;
151 ctrl->value = ctrl->value & 0x3f;
152 return 0;
153 case V4L2_CID_BLUE_BALANCE:
154 if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
155 return -EIO;
156 ctrl->value = ctrl->value & 0x3f;
157 return 0;
158 case SN9C102_V4L2_CID_GREEN_BALANCE:
159 if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
160 return -EIO;
161 ctrl->value = ctrl->value & 0x3f;
162 return 0;
163 case V4L2_CID_BLACK_LEVEL:
164 if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
165 return -EIO;
166 ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
167 return 0;
168 default:
169 return -EINVAL;
170 }
171}
172
173
174static int hv7131r_set_ctrl(struct sn9c102_device* cam,
175 const struct v4l2_control* ctrl)
176{
177 int err = 0;
178
179 switch (ctrl->id) {
180 case V4L2_CID_GAIN:
181 err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
182 break;
183 case V4L2_CID_RED_BALANCE:
184 err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
185 break;
186 case V4L2_CID_BLUE_BALANCE:
187 err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
188 break;
189 case SN9C102_V4L2_CID_GREEN_BALANCE:
190 err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
191 break;
192 case V4L2_CID_BLACK_LEVEL:
193 {
194 int r = sn9c102_i2c_read(cam, 0x01);
195 if (r < 0)
196 return -EIO;
197 err += sn9c102_i2c_write(cam, 0x01,
198 (ctrl->value<<3) | (r&0xf7));
199 }
200 break;
201 default:
202 return -EINVAL;
203 }
204
205 return err ? -EIO : 0;
206}
207
208
209static int hv7131r_set_crop(struct sn9c102_device* cam,
210 const struct v4l2_rect* rect)
211{
212 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
213 int err = 0;
214 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
215 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
216
217 err += sn9c102_write_reg(cam, h_start, 0x12);
218 err += sn9c102_write_reg(cam, v_start, 0x13);
219
220 return err;
221}
222
223
224static int hv7131r_set_pix_format(struct sn9c102_device* cam,
225 const struct v4l2_pix_format* pix)
226{
227 int err = 0;
228
229 switch (sn9c102_get_bridge(cam)) {
230 case BRIDGE_SN9C103:
231 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
232 err += sn9c102_write_reg(cam, 0xa0, 0x19);
233 err += sn9c102_i2c_write(cam, 0x01, 0x04);
234 } else {
235 err += sn9c102_write_reg(cam, 0x30, 0x19);
236 err += sn9c102_i2c_write(cam, 0x01, 0x04);
237 }
238 break;
239 case BRIDGE_SN9C105:
240 case BRIDGE_SN9C120:
241 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
242 err += sn9c102_write_reg(cam, 0xa5, 0x17);
243 err += sn9c102_i2c_write(cam, 0x01, 0x24);
244 } else {
245 err += sn9c102_write_reg(cam, 0xa3, 0x17);
246 err += sn9c102_i2c_write(cam, 0x01, 0x04);
247 }
248 break;
249 default:
250 break;
251 }
252
253 return err;
254}
255
256
257static const struct sn9c102_sensor hv7131r = {
258 .name = "HV7131R",
259 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
260 .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
261 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
262 .frequency = SN9C102_I2C_100KHZ,
263 .interface = SN9C102_I2C_2WIRES,
264 .i2c_slave_id = 0x11,
265 .init = &hv7131r_init,
266 .qctrl = {
267 {
268 .id = V4L2_CID_GAIN,
269 .type = V4L2_CTRL_TYPE_INTEGER,
270 .name = "global gain",
271 .minimum = 0x00,
272 .maximum = 0xff,
273 .step = 0x01,
274 .default_value = 0x40,
275 .flags = 0,
276 },
277 {
278 .id = V4L2_CID_RED_BALANCE,
279 .type = V4L2_CTRL_TYPE_INTEGER,
280 .name = "red balance",
281 .minimum = 0x00,
282 .maximum = 0x3f,
283 .step = 0x01,
284 .default_value = 0x08,
285 .flags = 0,
286 },
287 {
288 .id = V4L2_CID_BLUE_BALANCE,
289 .type = V4L2_CTRL_TYPE_INTEGER,
290 .name = "blue balance",
291 .minimum = 0x00,
292 .maximum = 0x3f,
293 .step = 0x01,
294 .default_value = 0x1a,
295 .flags = 0,
296 },
297 {
298 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
299 .type = V4L2_CTRL_TYPE_INTEGER,
300 .name = "green balance",
301 .minimum = 0x00,
302 .maximum = 0x3f,
303 .step = 0x01,
304 .default_value = 0x2f,
305 .flags = 0,
306 },
307 {
308 .id = V4L2_CID_BLACK_LEVEL,
309 .type = V4L2_CTRL_TYPE_BOOLEAN,
310 .name = "auto black level compensation",
311 .minimum = 0x00,
312 .maximum = 0x01,
313 .step = 0x01,
314 .default_value = 0x00,
315 .flags = 0,
316 },
317 },
318 .get_ctrl = &hv7131r_get_ctrl,
319 .set_ctrl = &hv7131r_set_ctrl,
320 .cropcap = {
321 .bounds = {
322 .left = 0,
323 .top = 0,
324 .width = 640,
325 .height = 480,
326 },
327 .defrect = {
328 .left = 0,
329 .top = 0,
330 .width = 640,
331 .height = 480,
332 },
333 },
334 .set_crop = &hv7131r_set_crop,
335 .pix_format = {
336 .width = 640,
337 .height = 480,
338 .pixelformat = V4L2_PIX_FMT_SBGGR8,
339 .priv = 8,
340 },
341 .set_pix_format = &hv7131r_set_pix_format
342};
343
344
345int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
346{
347 int devid, err;
348
349 err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02},
350 {0x34, 0x01}, {0x20, 0x17},
351 {0x34, 0x01}, {0x46, 0x01});
352
353 devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
354 if (err || devid < 0)
355 return -EIO;
356
357 if (devid != 0x02)
358 return -ENODEV;
359
360 sn9c102_attach_sensor(cam, &hv7131r);
361
362 return 0;
363}
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
new file mode 100644
index 00000000000..1f5b09bec89
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c
@@ -0,0 +1,352 @@
1/***************************************************************************
2 * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int mi0343_init(struct sn9c102_device* cam)
27{
28 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
29 int err = 0;
30
31 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
32 {0x0a, 0x14}, {0x40, 0x01},
33 {0x20, 0x17}, {0x07, 0x18},
34 {0xa0, 0x19});
35
36 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
37 0x00, 0x01, 0, 0);
38 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
39 0x00, 0x00, 0, 0);
40 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
41 0x01, 0xe1, 0, 0);
42 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
43 0x02, 0x81, 0, 0);
44 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
45 0x00, 0x17, 0, 0);
46 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
47 0x00, 0x11, 0, 0);
48 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
49 0x04, 0x9a, 0, 0);
50
51 return err;
52}
53
54
55static int mi0343_get_ctrl(struct sn9c102_device* cam,
56 struct v4l2_control* ctrl)
57{
58 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
59 u8 data[2];
60
61 switch (ctrl->id) {
62 case V4L2_CID_EXPOSURE:
63 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2,
64 data) < 0)
65 return -EIO;
66 ctrl->value = data[0];
67 return 0;
68 case V4L2_CID_GAIN:
69 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2,
70 data) < 0)
71 return -EIO;
72 break;
73 case V4L2_CID_HFLIP:
74 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
75 data) < 0)
76 return -EIO;
77 ctrl->value = data[1] & 0x20 ? 1 : 0;
78 return 0;
79 case V4L2_CID_VFLIP:
80 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
81 data) < 0)
82 return -EIO;
83 ctrl->value = data[1] & 0x80 ? 1 : 0;
84 return 0;
85 case V4L2_CID_RED_BALANCE:
86 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
87 data) < 0)
88 return -EIO;
89 break;
90 case V4L2_CID_BLUE_BALANCE:
91 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
92 data) < 0)
93 return -EIO;
94 break;
95 case SN9C102_V4L2_CID_GREEN_BALANCE:
96 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2,
97 data) < 0)
98 return -EIO;
99 break;
100 default:
101 return -EINVAL;
102 }
103
104 switch (ctrl->id) {
105 case V4L2_CID_GAIN:
106 case V4L2_CID_RED_BALANCE:
107 case V4L2_CID_BLUE_BALANCE:
108 case SN9C102_V4L2_CID_GREEN_BALANCE:
109 ctrl->value = data[1] | (data[0] << 8);
110 if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
111 ctrl->value -= 0x10;
112 else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
113 ctrl->value -= 0x60;
114 else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
115 ctrl->value -= 0xe0;
116 }
117
118 return 0;
119}
120
121
122static int mi0343_set_ctrl(struct sn9c102_device* cam,
123 const struct v4l2_control* ctrl)
124{
125 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
126 u16 reg = 0;
127 int err = 0;
128
129 switch (ctrl->id) {
130 case V4L2_CID_GAIN:
131 case V4L2_CID_RED_BALANCE:
132 case V4L2_CID_BLUE_BALANCE:
133 case SN9C102_V4L2_CID_GREEN_BALANCE:
134 if (ctrl->value <= (0x3f-0x10))
135 reg = 0x10 + ctrl->value;
136 else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
137 reg = 0x60 + (ctrl->value - (0x3f-0x10));
138 else
139 reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
140 break;
141 }
142
143 switch (ctrl->id) {
144 case V4L2_CID_EXPOSURE:
145 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
146 0x09, ctrl->value, 0x00,
147 0, 0);
148 break;
149 case V4L2_CID_GAIN:
150 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
151 0x35, reg >> 8, reg & 0xff,
152 0, 0);
153 break;
154 case V4L2_CID_HFLIP:
155 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
156 0x20, ctrl->value ? 0x40:0x00,
157 ctrl->value ? 0x20:0x00,
158 0, 0);
159 break;
160 case V4L2_CID_VFLIP:
161 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
162 0x20, ctrl->value ? 0x80:0x00,
163 ctrl->value ? 0x80:0x00,
164 0, 0);
165 break;
166 case V4L2_CID_RED_BALANCE:
167 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
168 0x2d, reg >> 8, reg & 0xff,
169 0, 0);
170 break;
171 case V4L2_CID_BLUE_BALANCE:
172 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
173 0x2c, reg >> 8, reg & 0xff,
174 0, 0);
175 break;
176 case SN9C102_V4L2_CID_GREEN_BALANCE:
177 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
178 0x2b, reg >> 8, reg & 0xff,
179 0, 0);
180 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
181 0x2e, reg >> 8, reg & 0xff,
182 0, 0);
183 break;
184 default:
185 return -EINVAL;
186 }
187
188 return err ? -EIO : 0;
189}
190
191
192static int mi0343_set_crop(struct sn9c102_device* cam,
193 const struct v4l2_rect* rect)
194{
195 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
196 int err = 0;
197 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
198 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
199
200 err += sn9c102_write_reg(cam, h_start, 0x12);
201 err += sn9c102_write_reg(cam, v_start, 0x13);
202
203 return err;
204}
205
206
207static int mi0343_set_pix_format(struct sn9c102_device* cam,
208 const struct v4l2_pix_format* pix)
209{
210 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
211 int err = 0;
212
213 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
214 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
215 0x0a, 0x00, 0x03, 0, 0);
216 err += sn9c102_write_reg(cam, 0x20, 0x19);
217 } else {
218 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
219 0x0a, 0x00, 0x05, 0, 0);
220 err += sn9c102_write_reg(cam, 0xa0, 0x19);
221 }
222
223 return err;
224}
225
226
227static const struct sn9c102_sensor mi0343 = {
228 .name = "MI-0343",
229 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
230 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
231 .frequency = SN9C102_I2C_100KHZ,
232 .interface = SN9C102_I2C_2WIRES,
233 .i2c_slave_id = 0x5d,
234 .init = &mi0343_init,
235 .qctrl = {
236 {
237 .id = V4L2_CID_EXPOSURE,
238 .type = V4L2_CTRL_TYPE_INTEGER,
239 .name = "exposure",
240 .minimum = 0x00,
241 .maximum = 0x0f,
242 .step = 0x01,
243 .default_value = 0x06,
244 .flags = 0,
245 },
246 {
247 .id = V4L2_CID_GAIN,
248 .type = V4L2_CTRL_TYPE_INTEGER,
249 .name = "global gain",
250 .minimum = 0x00,
251 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
252 .step = 0x01,
253 .default_value = 0x00,
254 .flags = 0,
255 },
256 {
257 .id = V4L2_CID_HFLIP,
258 .type = V4L2_CTRL_TYPE_BOOLEAN,
259 .name = "horizontal mirror",
260 .minimum = 0,
261 .maximum = 1,
262 .step = 1,
263 .default_value = 0,
264 .flags = 0,
265 },
266 {
267 .id = V4L2_CID_VFLIP,
268 .type = V4L2_CTRL_TYPE_BOOLEAN,
269 .name = "vertical mirror",
270 .minimum = 0,
271 .maximum = 1,
272 .step = 1,
273 .default_value = 0,
274 .flags = 0,
275 },
276 {
277 .id = V4L2_CID_RED_BALANCE,
278 .type = V4L2_CTRL_TYPE_INTEGER,
279 .name = "red balance",
280 .minimum = 0x00,
281 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
282 .step = 0x01,
283 .default_value = 0x00,
284 .flags = 0,
285 },
286 {
287 .id = V4L2_CID_BLUE_BALANCE,
288 .type = V4L2_CTRL_TYPE_INTEGER,
289 .name = "blue balance",
290 .minimum = 0x00,
291 .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
292 .step = 0x01,
293 .default_value = 0x00,
294 .flags = 0,
295 },
296 {
297 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
298 .type = V4L2_CTRL_TYPE_INTEGER,
299 .name = "green balance",
300 .minimum = 0x00,
301 .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
302 .step = 0x01,
303 .default_value = 0x00,
304 .flags = 0,
305 },
306 },
307 .get_ctrl = &mi0343_get_ctrl,
308 .set_ctrl = &mi0343_set_ctrl,
309 .cropcap = {
310 .bounds = {
311 .left = 0,
312 .top = 0,
313 .width = 640,
314 .height = 480,
315 },
316 .defrect = {
317 .left = 0,
318 .top = 0,
319 .width = 640,
320 .height = 480,
321 },
322 },
323 .set_crop = &mi0343_set_crop,
324 .pix_format = {
325 .width = 640,
326 .height = 480,
327 .pixelformat = V4L2_PIX_FMT_SBGGR8,
328 .priv = 8,
329 },
330 .set_pix_format = &mi0343_set_pix_format
331};
332
333
334int sn9c102_probe_mi0343(struct sn9c102_device* cam)
335{
336 u8 data[2];
337
338 if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
339 {0x28, 0x17}))
340 return -EIO;
341
342 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
343 2, data) < 0)
344 return -EIO;
345
346 if (data[1] != 0x42 || data[0] != 0xe3)
347 return -ENODEV;
348
349 sn9c102_attach_sensor(cam, &mi0343);
350
351 return 0;
352}
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/video/sn9c102/sn9c102_mi0360.c
new file mode 100644
index 00000000000..d973fc1973d
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_mi0360.c
@@ -0,0 +1,453 @@
1/***************************************************************************
2 * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int mi0360_init(struct sn9c102_device* cam)
27{
28 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
29 int err = 0;
30
31 switch (sn9c102_get_bridge(cam)) {
32 case BRIDGE_SN9C103:
33 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
34 {0x0a, 0x14}, {0x40, 0x01},
35 {0x20, 0x17}, {0x07, 0x18},
36 {0xa0, 0x19}, {0x02, 0x1c},
37 {0x03, 0x1d}, {0x0f, 0x1e},
38 {0x0c, 0x1f}, {0x00, 0x20},
39 {0x10, 0x21}, {0x20, 0x22},
40 {0x30, 0x23}, {0x40, 0x24},
41 {0x50, 0x25}, {0x60, 0x26},
42 {0x70, 0x27}, {0x80, 0x28},
43 {0x90, 0x29}, {0xa0, 0x2a},
44 {0xb0, 0x2b}, {0xc0, 0x2c},
45 {0xd0, 0x2d}, {0xe0, 0x2e},
46 {0xf0, 0x2f}, {0xff, 0x30});
47 break;
48 case BRIDGE_SN9C105:
49 case BRIDGE_SN9C120:
50 err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
51 {0x00, 0x03}, {0x1a, 0x04},
52 {0x50, 0x05}, {0x20, 0x06},
53 {0x10, 0x07}, {0x03, 0x10},
54 {0x08, 0x14}, {0xa2, 0x17},
55 {0x47, 0x18}, {0x00, 0x19},
56 {0x1d, 0x1a}, {0x10, 0x1b},
57 {0x02, 0x1c}, {0x03, 0x1d},
58 {0x0f, 0x1e}, {0x0c, 0x1f},
59 {0x00, 0x20}, {0x29, 0x21},
60 {0x40, 0x22}, {0x54, 0x23},
61 {0x66, 0x24}, {0x76, 0x25},
62 {0x85, 0x26}, {0x94, 0x27},
63 {0xa1, 0x28}, {0xae, 0x29},
64 {0xbb, 0x2a}, {0xc7, 0x2b},
65 {0xd3, 0x2c}, {0xde, 0x2d},
66 {0xea, 0x2e}, {0xf4, 0x2f},
67 {0xff, 0x30}, {0x00, 0x3F},
68 {0xC7, 0x40}, {0x01, 0x41},
69 {0x44, 0x42}, {0x00, 0x43},
70 {0x44, 0x44}, {0x00, 0x45},
71 {0x44, 0x46}, {0x00, 0x47},
72 {0xC7, 0x48}, {0x01, 0x49},
73 {0xC7, 0x4A}, {0x01, 0x4B},
74 {0xC7, 0x4C}, {0x01, 0x4D},
75 {0x44, 0x4E}, {0x00, 0x4F},
76 {0x44, 0x50}, {0x00, 0x51},
77 {0x44, 0x52}, {0x00, 0x53},
78 {0xC7, 0x54}, {0x01, 0x55},
79 {0xC7, 0x56}, {0x01, 0x57},
80 {0xC7, 0x58}, {0x01, 0x59},
81 {0x44, 0x5A}, {0x00, 0x5B},
82 {0x44, 0x5C}, {0x00, 0x5D},
83 {0x44, 0x5E}, {0x00, 0x5F},
84 {0xC7, 0x60}, {0x01, 0x61},
85 {0xC7, 0x62}, {0x01, 0x63},
86 {0xC7, 0x64}, {0x01, 0x65},
87 {0x44, 0x66}, {0x00, 0x67},
88 {0x44, 0x68}, {0x00, 0x69},
89 {0x44, 0x6A}, {0x00, 0x6B},
90 {0xC7, 0x6C}, {0x01, 0x6D},
91 {0xC7, 0x6E}, {0x01, 0x6F},
92 {0xC7, 0x70}, {0x01, 0x71},
93 {0x44, 0x72}, {0x00, 0x73},
94 {0x44, 0x74}, {0x00, 0x75},
95 {0x44, 0x76}, {0x00, 0x77},
96 {0xC7, 0x78}, {0x01, 0x79},
97 {0xC7, 0x7A}, {0x01, 0x7B},
98 {0xC7, 0x7C}, {0x01, 0x7D},
99 {0x44, 0x7E}, {0x00, 0x7F},
100 {0x14, 0x84}, {0x00, 0x85},
101 {0x27, 0x86}, {0x00, 0x87},
102 {0x07, 0x88}, {0x00, 0x89},
103 {0xEC, 0x8A}, {0x0f, 0x8B},
104 {0xD8, 0x8C}, {0x0f, 0x8D},
105 {0x3D, 0x8E}, {0x00, 0x8F},
106 {0x3D, 0x90}, {0x00, 0x91},
107 {0xCD, 0x92}, {0x0f, 0x93},
108 {0xf7, 0x94}, {0x0f, 0x95},
109 {0x0C, 0x96}, {0x00, 0x97},
110 {0x00, 0x98}, {0x66, 0x99},
111 {0x05, 0x9A}, {0x00, 0x9B},
112 {0x04, 0x9C}, {0x00, 0x9D},
113 {0x08, 0x9E}, {0x00, 0x9F},
114 {0x2D, 0xC0}, {0x2D, 0xC1},
115 {0x3A, 0xC2}, {0x05, 0xC3},
116 {0x04, 0xC4}, {0x3F, 0xC5},
117 {0x00, 0xC6}, {0x00, 0xC7},
118 {0x50, 0xC8}, {0x3C, 0xC9},
119 {0x28, 0xCA}, {0xD8, 0xCB},
120 {0x14, 0xCC}, {0xEC, 0xCD},
121 {0x32, 0xCE}, {0xDD, 0xCF},
122 {0x32, 0xD0}, {0xDD, 0xD1},
123 {0x6A, 0xD2}, {0x50, 0xD3},
124 {0x00, 0xD4}, {0x00, 0xD5},
125 {0x00, 0xD6});
126 break;
127 default:
128 break;
129 }
130
131 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
132 0x00, 0x01, 0, 0);
133 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
134 0x00, 0x00, 0, 0);
135 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
136 0x01, 0xe1, 0, 0);
137 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
138 0x02, 0x81, 0, 0);
139 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
140 0x00, 0x17, 0, 0);
141 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
142 0x00, 0x11, 0, 0);
143 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
144 0x04, 0x9a, 0, 0);
145
146 return err;
147}
148
149
150static int mi0360_get_ctrl(struct sn9c102_device* cam,
151 struct v4l2_control* ctrl)
152{
153 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
154 u8 data[2];
155
156 switch (ctrl->id) {
157 case V4L2_CID_EXPOSURE:
158 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2,
159 data) < 0)
160 return -EIO;
161 ctrl->value = data[0];
162 return 0;
163 case V4L2_CID_GAIN:
164 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2,
165 data) < 0)
166 return -EIO;
167 ctrl->value = data[1];
168 return 0;
169 case V4L2_CID_RED_BALANCE:
170 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
171 data) < 0)
172 return -EIO;
173 ctrl->value = data[1];
174 return 0;
175 case V4L2_CID_BLUE_BALANCE:
176 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
177 data) < 0)
178 return -EIO;
179 ctrl->value = data[1];
180 return 0;
181 case SN9C102_V4L2_CID_GREEN_BALANCE:
182 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2,
183 data) < 0)
184 return -EIO;
185 ctrl->value = data[1];
186 return 0;
187 case V4L2_CID_HFLIP:
188 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
189 data) < 0)
190 return -EIO;
191 ctrl->value = data[1] & 0x20 ? 1 : 0;
192 return 0;
193 case V4L2_CID_VFLIP:
194 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
195 data) < 0)
196 return -EIO;
197 ctrl->value = data[1] & 0x80 ? 1 : 0;
198 return 0;
199 default:
200 return -EINVAL;
201 }
202
203 return 0;
204}
205
206
207static int mi0360_set_ctrl(struct sn9c102_device* cam,
208 const struct v4l2_control* ctrl)
209{
210 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
211 int err = 0;
212
213 switch (ctrl->id) {
214 case V4L2_CID_EXPOSURE:
215 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
216 0x09, ctrl->value, 0x00,
217 0, 0);
218 break;
219 case V4L2_CID_GAIN:
220 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
221 0x35, 0x03, ctrl->value,
222 0, 0);
223 break;
224 case V4L2_CID_RED_BALANCE:
225 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
226 0x2c, 0x03, ctrl->value,
227 0, 0);
228 break;
229 case V4L2_CID_BLUE_BALANCE:
230 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
231 0x2d, 0x03, ctrl->value,
232 0, 0);
233 break;
234 case SN9C102_V4L2_CID_GREEN_BALANCE:
235 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
236 0x2b, 0x03, ctrl->value,
237 0, 0);
238 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
239 0x2e, 0x03, ctrl->value,
240 0, 0);
241 break;
242 case V4L2_CID_HFLIP:
243 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
244 0x20, ctrl->value ? 0x40:0x00,
245 ctrl->value ? 0x20:0x00,
246 0, 0);
247 break;
248 case V4L2_CID_VFLIP:
249 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
250 0x20, ctrl->value ? 0x80:0x00,
251 ctrl->value ? 0x80:0x00,
252 0, 0);
253 break;
254 default:
255 return -EINVAL;
256 }
257
258 return err ? -EIO : 0;
259}
260
261
262static int mi0360_set_crop(struct sn9c102_device* cam,
263 const struct v4l2_rect* rect)
264{
265 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
266 int err = 0;
267 u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
268
269 switch (sn9c102_get_bridge(cam)) {
270 case BRIDGE_SN9C103:
271 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0;
272 break;
273 case BRIDGE_SN9C105:
274 case BRIDGE_SN9C120:
275 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
276 break;
277 default:
278 break;
279 }
280
281 err += sn9c102_write_reg(cam, h_start, 0x12);
282 err += sn9c102_write_reg(cam, v_start, 0x13);
283
284 return err;
285}
286
287
288static int mi0360_set_pix_format(struct sn9c102_device* cam,
289 const struct v4l2_pix_format* pix)
290{
291 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
292 int err = 0;
293
294 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
295 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
296 0x0a, 0x00, 0x05, 0, 0);
297 err += sn9c102_write_reg(cam, 0x60, 0x19);
298 if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
299 sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
300 err += sn9c102_write_reg(cam, 0xa6, 0x17);
301 } else {
302 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
303 0x0a, 0x00, 0x02, 0, 0);
304 err += sn9c102_write_reg(cam, 0x20, 0x19);
305 if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
306 sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
307 err += sn9c102_write_reg(cam, 0xa2, 0x17);
308 }
309
310 return err;
311}
312
313
314static const struct sn9c102_sensor mi0360 = {
315 .name = "MI-0360",
316 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
317 .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
318 .frequency = SN9C102_I2C_100KHZ,
319 .interface = SN9C102_I2C_2WIRES,
320 .i2c_slave_id = 0x5d,
321 .init = &mi0360_init,
322 .qctrl = {
323 {
324 .id = V4L2_CID_EXPOSURE,
325 .type = V4L2_CTRL_TYPE_INTEGER,
326 .name = "exposure",
327 .minimum = 0x00,
328 .maximum = 0x0f,
329 .step = 0x01,
330 .default_value = 0x05,
331 .flags = 0,
332 },
333 {
334 .id = V4L2_CID_GAIN,
335 .type = V4L2_CTRL_TYPE_INTEGER,
336 .name = "global gain",
337 .minimum = 0x00,
338 .maximum = 0x7f,
339 .step = 0x01,
340 .default_value = 0x25,
341 .flags = 0,
342 },
343 {
344 .id = V4L2_CID_HFLIP,
345 .type = V4L2_CTRL_TYPE_BOOLEAN,
346 .name = "horizontal mirror",
347 .minimum = 0,
348 .maximum = 1,
349 .step = 1,
350 .default_value = 0,
351 .flags = 0,
352 },
353 {
354 .id = V4L2_CID_VFLIP,
355 .type = V4L2_CTRL_TYPE_BOOLEAN,
356 .name = "vertical mirror",
357 .minimum = 0,
358 .maximum = 1,
359 .step = 1,
360 .default_value = 0,
361 .flags = 0,
362 },
363 {
364 .id = V4L2_CID_BLUE_BALANCE,
365 .type = V4L2_CTRL_TYPE_INTEGER,
366 .name = "blue balance",
367 .minimum = 0x00,
368 .maximum = 0x7f,
369 .step = 0x01,
370 .default_value = 0x0f,
371 .flags = 0,
372 },
373 {
374 .id = V4L2_CID_RED_BALANCE,
375 .type = V4L2_CTRL_TYPE_INTEGER,
376 .name = "red balance",
377 .minimum = 0x00,
378 .maximum = 0x7f,
379 .step = 0x01,
380 .default_value = 0x32,
381 .flags = 0,
382 },
383 {
384 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
385 .type = V4L2_CTRL_TYPE_INTEGER,
386 .name = "green balance",
387 .minimum = 0x00,
388 .maximum = 0x7f,
389 .step = 0x01,
390 .default_value = 0x25,
391 .flags = 0,
392 },
393 },
394 .get_ctrl = &mi0360_get_ctrl,
395 .set_ctrl = &mi0360_set_ctrl,
396 .cropcap = {
397 .bounds = {
398 .left = 0,
399 .top = 0,
400 .width = 640,
401 .height = 480,
402 },
403 .defrect = {
404 .left = 0,
405 .top = 0,
406 .width = 640,
407 .height = 480,
408 },
409 },
410 .set_crop = &mi0360_set_crop,
411 .pix_format = {
412 .width = 640,
413 .height = 480,
414 .pixelformat = V4L2_PIX_FMT_SBGGR8,
415 .priv = 8,
416 },
417 .set_pix_format = &mi0360_set_pix_format
418};
419
420
421int sn9c102_probe_mi0360(struct sn9c102_device* cam)
422{
423
424 u8 data[2];
425
426 switch (sn9c102_get_bridge(cam)) {
427 case BRIDGE_SN9C103:
428 if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
429 {0x28, 0x17}))
430 return -EIO;
431 break;
432 case BRIDGE_SN9C105:
433 case BRIDGE_SN9C120:
434 if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
435 {0x01, 0x01}, {0x00, 0x01},
436 {0x28, 0x17}))
437 return -EIO;
438 break;
439 default:
440 break;
441 }
442
443 if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00,
444 2, data) < 0)
445 return -EIO;
446
447 if (data[0] != 0x82 || data[1] != 0x43)
448 return -ENODEV;
449
450 sn9c102_attach_sensor(cam, &mi0360);
451
452 return 0;
453}
diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
new file mode 100644
index 00000000000..95986eb492e
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
@@ -0,0 +1,260 @@
1/***************************************************************************
2 * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int mt9v111_init(struct sn9c102_device *cam)
27{
28 struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
29 int err = 0;
30
31 err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
32 {0x00, 0x03}, {0x1a, 0x04},
33 {0x1f, 0x05}, {0x20, 0x06},
34 {0x1f, 0x07}, {0x81, 0x08},
35 {0x5c, 0x09}, {0x00, 0x0a},
36 {0x00, 0x0b}, {0x00, 0x0c},
37 {0x00, 0x0d}, {0x00, 0x0e},
38 {0x00, 0x0f}, {0x03, 0x10},
39 {0x00, 0x11}, {0x00, 0x12},
40 {0x02, 0x13}, {0x14, 0x14},
41 {0x28, 0x15}, {0x1e, 0x16},
42 {0xe2, 0x17}, {0x06, 0x18},
43 {0x00, 0x19}, {0x00, 0x1a},
44 {0x00, 0x1b}, {0x08, 0x20},
45 {0x39, 0x21}, {0x51, 0x22},
46 {0x63, 0x23}, {0x73, 0x24},
47 {0x82, 0x25}, {0x8f, 0x26},
48 {0x9b, 0x27}, {0xa7, 0x28},
49 {0xb1, 0x29}, {0xbc, 0x2a},
50 {0xc6, 0x2b}, {0xcf, 0x2c},
51 {0xd8, 0x2d}, {0xe1, 0x2e},
52 {0xea, 0x2f}, {0xf2, 0x30},
53 {0x13, 0x84}, {0x00, 0x85},
54 {0x25, 0x86}, {0x00, 0x87},
55 {0x07, 0x88}, {0x00, 0x89},
56 {0xee, 0x8a}, {0x0f, 0x8b},
57 {0xe5, 0x8c}, {0x0f, 0x8d},
58 {0x2e, 0x8e}, {0x00, 0x8f},
59 {0x30, 0x90}, {0x00, 0x91},
60 {0xd4, 0x92}, {0x0f, 0x93},
61 {0xfc, 0x94}, {0x0f, 0x95},
62 {0x14, 0x96}, {0x00, 0x97},
63 {0x00, 0x98}, {0x60, 0x99},
64 {0x07, 0x9a}, {0x40, 0x9b},
65 {0x20, 0x9c}, {0x00, 0x9d},
66 {0x00, 0x9e}, {0x00, 0x9f},
67 {0x2d, 0xc0}, {0x2d, 0xc1},
68 {0x3a, 0xc2}, {0x05, 0xc3},
69 {0x04, 0xc4}, {0x3f, 0xc5},
70 {0x00, 0xc6}, {0x00, 0xc7},
71 {0x50, 0xc8}, {0x3c, 0xc9},
72 {0x28, 0xca}, {0xd8, 0xcb},
73 {0x14, 0xcc}, {0xec, 0xcd},
74 {0x32, 0xce}, {0xdd, 0xcf},
75 {0x2d, 0xd0}, {0xdd, 0xd1},
76 {0x6a, 0xd2}, {0x50, 0xd3},
77 {0x60, 0xd4}, {0x00, 0xd5},
78 {0x00, 0xd6});
79
80 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
81 0x00, 0x01, 0, 0);
82 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
83 0x00, 0x01, 0, 0);
84 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
85 0x00, 0x00, 0, 0);
86 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
87 0x04, 0x80, 0, 0);
88 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
89 0x00, 0x04, 0, 0);
90 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
91 0x00, 0x08, 0, 0);
92 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
93 0x00, 0x16, 0, 0);
94 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
95 0x01, 0xe7, 0, 0);
96 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
97 0x02, 0x87, 0, 0);
98 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
99 0x00, 0x40, 0, 0);
100 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
101 0x00, 0x09, 0, 0);
102 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
103 0x30, 0x02, 0, 0);
104 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
105 0x00, 0x00, 0, 0);
106 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
107 0x00, 0xb0, 0, 0);
108 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
109 0x00, 0x7c, 0, 0);
110 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
111 0x00, 0x00, 0, 0);
112 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
113 0x00, 0x00, 0, 0);
114 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
115 0x00, 0x00, 0, 0);
116 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
117 0x00, 0x04, 0, 0);
118
119 return err;
120}
121
122static int mt9v111_get_ctrl(struct sn9c102_device *cam,
123 struct v4l2_control *ctrl)
124{
125 struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
126 u8 data[2];
127 int err = 0;
128
129 switch (ctrl->id) {
130 case V4L2_CID_VFLIP:
131 if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
132 data) < 0)
133 return -EIO;
134 ctrl->value = data[1] & 0x80 ? 1 : 0;
135 return 0;
136 default:
137 return -EINVAL;
138 }
139
140 return err ? -EIO : 0;
141}
142
143static int mt9v111_set_ctrl(struct sn9c102_device *cam,
144 const struct v4l2_control *ctrl)
145{
146 struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
147 int err = 0;
148
149 switch (ctrl->id) {
150 case V4L2_CID_VFLIP:
151 err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
152 0x20,
153 ctrl->value ? 0x80 : 0x00,
154 ctrl->value ? 0x80 : 0x00, 0,
155 0);
156 break;
157 default:
158 return -EINVAL;
159 }
160
161 return err ? -EIO : 0;
162}
163
164static int mt9v111_set_crop(struct sn9c102_device *cam,
165 const struct v4l2_rect *rect)
166{
167 struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
168 int err = 0;
169 u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
170
171 err += sn9c102_write_reg(cam, v_start, 0x13);
172
173 return err;
174}
175
176static int mt9v111_set_pix_format(struct sn9c102_device *cam,
177 const struct v4l2_pix_format *pix)
178{
179 int err = 0;
180
181 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
182 err += sn9c102_write_reg(cam, 0xb4, 0x17);
183 } else {
184 err += sn9c102_write_reg(cam, 0xe2, 0x17);
185 }
186
187 return err;
188}
189
190
191static const struct sn9c102_sensor mt9v111 = {
192 .name = "MT9V111",
193 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
194 .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
195 .frequency = SN9C102_I2C_100KHZ,
196 .interface = SN9C102_I2C_2WIRES,
197 .i2c_slave_id = 0x5c,
198 .init = &mt9v111_init,
199 .qctrl = {
200 {
201 .id = V4L2_CID_VFLIP,
202 .type = V4L2_CTRL_TYPE_BOOLEAN,
203 .name = "vertical mirror",
204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
207 .default_value = 0,
208 .flags = 0,
209 },
210 },
211 .get_ctrl = &mt9v111_get_ctrl,
212 .set_ctrl = &mt9v111_set_ctrl,
213 .cropcap = {
214 .bounds = {
215 .left = 0,
216 .top = 0,
217 .width = 640,
218 .height = 480,
219 },
220 .defrect = {
221 .left = 0,
222 .top = 0,
223 .width = 640,
224 .height = 480,
225 },
226 },
227 .set_crop = &mt9v111_set_crop,
228 .pix_format = {
229 .width = 640,
230 .height = 480,
231 .pixelformat = V4L2_PIX_FMT_SBGGR8,
232 .priv = 8,
233 },
234 .set_pix_format = &mt9v111_set_pix_format
235};
236
237
238int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
239{
240 u8 data[2];
241 int err = 0;
242
243 err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
244 {0x29, 0x01}, {0x42, 0x17},
245 {0x62, 0x17}, {0x08, 0x01});
246 err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
247 mt9v111.i2c_slave_id, 0x01, 0x00,
248 0x04, 0, 0);
249 if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
250 mt9v111.i2c_slave_id, 0x36, 2,
251 data) < 0)
252 return -EIO;
253
254 if (data[0] != 0x82 || data[1] != 0x3a)
255 return -ENODEV;
256
257 sn9c102_attach_sensor(cam, &mt9v111);
258
259 return 0;
260}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
new file mode 100644
index 00000000000..803712c29f0
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -0,0 +1,626 @@
1/***************************************************************************
2 * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int ov7630_init(struct sn9c102_device* cam)
27{
28 int err = 0;
29
30 switch (sn9c102_get_bridge(cam)) {
31 case BRIDGE_SN9C101:
32 case BRIDGE_SN9C102:
33 err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17},
34 {0x0f, 0x18}, {0x50, 0x19});
35
36 err += sn9c102_i2c_write(cam, 0x12, 0x8d);
37 err += sn9c102_i2c_write(cam, 0x12, 0x0d);
38 err += sn9c102_i2c_write(cam, 0x11, 0x00);
39 err += sn9c102_i2c_write(cam, 0x15, 0x35);
40 err += sn9c102_i2c_write(cam, 0x16, 0x03);
41 err += sn9c102_i2c_write(cam, 0x17, 0x1c);
42 err += sn9c102_i2c_write(cam, 0x18, 0xbd);
43 err += sn9c102_i2c_write(cam, 0x19, 0x06);
44 err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
45 err += sn9c102_i2c_write(cam, 0x1b, 0x04);
46 err += sn9c102_i2c_write(cam, 0x20, 0x44);
47 err += sn9c102_i2c_write(cam, 0x23, 0xee);
48 err += sn9c102_i2c_write(cam, 0x26, 0xa0);
49 err += sn9c102_i2c_write(cam, 0x27, 0x9a);
50 err += sn9c102_i2c_write(cam, 0x28, 0x20);
51 err += sn9c102_i2c_write(cam, 0x29, 0x30);
52 err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
53 err += sn9c102_i2c_write(cam, 0x30, 0x24);
54 err += sn9c102_i2c_write(cam, 0x32, 0x86);
55 err += sn9c102_i2c_write(cam, 0x60, 0xa9);
56 err += sn9c102_i2c_write(cam, 0x61, 0x42);
57 err += sn9c102_i2c_write(cam, 0x65, 0x00);
58 err += sn9c102_i2c_write(cam, 0x69, 0x38);
59 err += sn9c102_i2c_write(cam, 0x6f, 0x88);
60 err += sn9c102_i2c_write(cam, 0x70, 0x0b);
61 err += sn9c102_i2c_write(cam, 0x71, 0x00);
62 err += sn9c102_i2c_write(cam, 0x74, 0x21);
63 err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
64 break;
65 case BRIDGE_SN9C103:
66 err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
67 {0x1a, 0x04}, {0x20, 0x05},
68 {0x20, 0x06}, {0x20, 0x07},
69 {0x03, 0x10}, {0x0a, 0x14},
70 {0x60, 0x17}, {0x0f, 0x18},
71 {0x50, 0x19}, {0x1d, 0x1a},
72 {0x10, 0x1b}, {0x02, 0x1c},
73 {0x03, 0x1d}, {0x0f, 0x1e},
74 {0x0c, 0x1f}, {0x00, 0x20},
75 {0x10, 0x21}, {0x20, 0x22},
76 {0x30, 0x23}, {0x40, 0x24},
77 {0x50, 0x25}, {0x60, 0x26},
78 {0x70, 0x27}, {0x80, 0x28},
79 {0x90, 0x29}, {0xa0, 0x2a},
80 {0xb0, 0x2b}, {0xc0, 0x2c},
81 {0xd0, 0x2d}, {0xe0, 0x2e},
82 {0xf0, 0x2f}, {0xff, 0x30});
83
84 err += sn9c102_i2c_write(cam, 0x12, 0x8d);
85 err += sn9c102_i2c_write(cam, 0x12, 0x0d);
86 err += sn9c102_i2c_write(cam, 0x15, 0x34);
87 err += sn9c102_i2c_write(cam, 0x11, 0x01);
88 err += sn9c102_i2c_write(cam, 0x1b, 0x04);
89 err += sn9c102_i2c_write(cam, 0x20, 0x44);
90 err += sn9c102_i2c_write(cam, 0x23, 0xee);
91 err += sn9c102_i2c_write(cam, 0x26, 0xa0);
92 err += sn9c102_i2c_write(cam, 0x27, 0x9a);
93 err += sn9c102_i2c_write(cam, 0x28, 0x20);
94 err += sn9c102_i2c_write(cam, 0x29, 0x30);
95 err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
96 err += sn9c102_i2c_write(cam, 0x30, 0x24);
97 err += sn9c102_i2c_write(cam, 0x32, 0x86);
98 err += sn9c102_i2c_write(cam, 0x60, 0xa9);
99 err += sn9c102_i2c_write(cam, 0x61, 0x42);
100 err += sn9c102_i2c_write(cam, 0x65, 0x00);
101 err += sn9c102_i2c_write(cam, 0x69, 0x38);
102 err += sn9c102_i2c_write(cam, 0x6f, 0x88);
103 err += sn9c102_i2c_write(cam, 0x70, 0x0b);
104 err += sn9c102_i2c_write(cam, 0x71, 0x00);
105 err += sn9c102_i2c_write(cam, 0x74, 0x21);
106 err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
107 break;
108 case BRIDGE_SN9C105:
109 case BRIDGE_SN9C120:
110 err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
111 {0x1a, 0x04}, {0x03, 0x10},
112 {0x0a, 0x14}, {0xe2, 0x17},
113 {0x0b, 0x18}, {0x00, 0x19},
114 {0x1d, 0x1a}, {0x10, 0x1b},
115 {0x02, 0x1c}, {0x03, 0x1d},
116 {0x0f, 0x1e}, {0x0c, 0x1f},
117 {0x00, 0x20}, {0x24, 0x21},
118 {0x3b, 0x22}, {0x47, 0x23},
119 {0x60, 0x24}, {0x71, 0x25},
120 {0x80, 0x26}, {0x8f, 0x27},
121 {0x9d, 0x28}, {0xaa, 0x29},
122 {0xb8, 0x2a}, {0xc4, 0x2b},
123 {0xd1, 0x2c}, {0xdd, 0x2d},
124 {0xe8, 0x2e}, {0xf4, 0x2f},
125 {0xff, 0x30}, {0x00, 0x3f},
126 {0xc7, 0x40}, {0x01, 0x41},
127 {0x44, 0x42}, {0x00, 0x43},
128 {0x44, 0x44}, {0x00, 0x45},
129 {0x44, 0x46}, {0x00, 0x47},
130 {0xc7, 0x48}, {0x01, 0x49},
131 {0xc7, 0x4a}, {0x01, 0x4b},
132 {0xc7, 0x4c}, {0x01, 0x4d},
133 {0x44, 0x4e}, {0x00, 0x4f},
134 {0x44, 0x50}, {0x00, 0x51},
135 {0x44, 0x52}, {0x00, 0x53},
136 {0xc7, 0x54}, {0x01, 0x55},
137 {0xc7, 0x56}, {0x01, 0x57},
138 {0xc7, 0x58}, {0x01, 0x59},
139 {0x44, 0x5a}, {0x00, 0x5b},
140 {0x44, 0x5c}, {0x00, 0x5d},
141 {0x44, 0x5e}, {0x00, 0x5f},
142 {0xc7, 0x60}, {0x01, 0x61},
143 {0xc7, 0x62}, {0x01, 0x63},
144 {0xc7, 0x64}, {0x01, 0x65},
145 {0x44, 0x66}, {0x00, 0x67},
146 {0x44, 0x68}, {0x00, 0x69},
147 {0x44, 0x6a}, {0x00, 0x6b},
148 {0xc7, 0x6c}, {0x01, 0x6d},
149 {0xc7, 0x6e}, {0x01, 0x6f},
150 {0xc7, 0x70}, {0x01, 0x71},
151 {0x44, 0x72}, {0x00, 0x73},
152 {0x44, 0x74}, {0x00, 0x75},
153 {0x44, 0x76}, {0x00, 0x77},
154 {0xc7, 0x78}, {0x01, 0x79},
155 {0xc7, 0x7a}, {0x01, 0x7b},
156 {0xc7, 0x7c}, {0x01, 0x7d},
157 {0x44, 0x7e}, {0x00, 0x7f},
158 {0x17, 0x84}, {0x00, 0x85},
159 {0x2e, 0x86}, {0x00, 0x87},
160 {0x09, 0x88}, {0x00, 0x89},
161 {0xe8, 0x8a}, {0x0f, 0x8b},
162 {0xda, 0x8c}, {0x0f, 0x8d},
163 {0x40, 0x8e}, {0x00, 0x8f},
164 {0x37, 0x90}, {0x00, 0x91},
165 {0xcf, 0x92}, {0x0f, 0x93},
166 {0xfa, 0x94}, {0x0f, 0x95},
167 {0x00, 0x96}, {0x00, 0x97},
168 {0x00, 0x98}, {0x66, 0x99},
169 {0x00, 0x9a}, {0x40, 0x9b},
170 {0x20, 0x9c}, {0x00, 0x9d},
171 {0x00, 0x9e}, {0x00, 0x9f},
172 {0x2d, 0xc0}, {0x2d, 0xc1},
173 {0x3a, 0xc2}, {0x00, 0xc3},
174 {0x04, 0xc4}, {0x3f, 0xc5},
175 {0x00, 0xc6}, {0x00, 0xc7},
176 {0x50, 0xc8}, {0x3c, 0xc9},
177 {0x28, 0xca}, {0xd8, 0xcb},
178 {0x14, 0xcc}, {0xec, 0xcd},
179 {0x32, 0xce}, {0xdd, 0xcf},
180 {0x32, 0xd0}, {0xdd, 0xd1},
181 {0x6a, 0xd2}, {0x50, 0xd3},
182 {0x60, 0xd4}, {0x00, 0xd5},
183 {0x00, 0xd6});
184
185 err += sn9c102_i2c_write(cam, 0x12, 0x80);
186 err += sn9c102_i2c_write(cam, 0x12, 0x48);
187 err += sn9c102_i2c_write(cam, 0x01, 0x80);
188 err += sn9c102_i2c_write(cam, 0x02, 0x80);
189 err += sn9c102_i2c_write(cam, 0x03, 0x80);
190 err += sn9c102_i2c_write(cam, 0x04, 0x10);
191 err += sn9c102_i2c_write(cam, 0x05, 0x20);
192 err += sn9c102_i2c_write(cam, 0x06, 0x80);
193 err += sn9c102_i2c_write(cam, 0x11, 0x00);
194 err += sn9c102_i2c_write(cam, 0x0c, 0x20);
195 err += sn9c102_i2c_write(cam, 0x0d, 0x20);
196 err += sn9c102_i2c_write(cam, 0x15, 0x80);
197 err += sn9c102_i2c_write(cam, 0x16, 0x03);
198 err += sn9c102_i2c_write(cam, 0x17, 0x1b);
199 err += sn9c102_i2c_write(cam, 0x18, 0xbd);
200 err += sn9c102_i2c_write(cam, 0x19, 0x05);
201 err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
202 err += sn9c102_i2c_write(cam, 0x1b, 0x04);
203 err += sn9c102_i2c_write(cam, 0x21, 0x1b);
204 err += sn9c102_i2c_write(cam, 0x22, 0x00);
205 err += sn9c102_i2c_write(cam, 0x23, 0xde);
206 err += sn9c102_i2c_write(cam, 0x24, 0x10);
207 err += sn9c102_i2c_write(cam, 0x25, 0x8a);
208 err += sn9c102_i2c_write(cam, 0x26, 0xa0);
209 err += sn9c102_i2c_write(cam, 0x27, 0xca);
210 err += sn9c102_i2c_write(cam, 0x28, 0xa2);
211 err += sn9c102_i2c_write(cam, 0x29, 0x74);
212 err += sn9c102_i2c_write(cam, 0x2a, 0x88);
213 err += sn9c102_i2c_write(cam, 0x2b, 0x34);
214 err += sn9c102_i2c_write(cam, 0x2c, 0x88);
215 err += sn9c102_i2c_write(cam, 0x2e, 0x00);
216 err += sn9c102_i2c_write(cam, 0x2f, 0x00);
217 err += sn9c102_i2c_write(cam, 0x30, 0x00);
218 err += sn9c102_i2c_write(cam, 0x32, 0xc2);
219 err += sn9c102_i2c_write(cam, 0x33, 0x08);
220 err += sn9c102_i2c_write(cam, 0x4c, 0x40);
221 err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
222 err += sn9c102_i2c_write(cam, 0x60, 0x05);
223 err += sn9c102_i2c_write(cam, 0x61, 0x40);
224 err += sn9c102_i2c_write(cam, 0x62, 0x12);
225 err += sn9c102_i2c_write(cam, 0x63, 0x57);
226 err += sn9c102_i2c_write(cam, 0x64, 0x73);
227 err += sn9c102_i2c_write(cam, 0x65, 0x00);
228 err += sn9c102_i2c_write(cam, 0x66, 0x55);
229 err += sn9c102_i2c_write(cam, 0x67, 0x01);
230 err += sn9c102_i2c_write(cam, 0x68, 0xac);
231 err += sn9c102_i2c_write(cam, 0x69, 0x38);
232 err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
233 err += sn9c102_i2c_write(cam, 0x70, 0x01);
234 err += sn9c102_i2c_write(cam, 0x71, 0x00);
235 err += sn9c102_i2c_write(cam, 0x72, 0x10);
236 err += sn9c102_i2c_write(cam, 0x73, 0x50);
237 err += sn9c102_i2c_write(cam, 0x74, 0x20);
238 err += sn9c102_i2c_write(cam, 0x76, 0x01);
239 err += sn9c102_i2c_write(cam, 0x77, 0xf3);
240 err += sn9c102_i2c_write(cam, 0x78, 0x90);
241 err += sn9c102_i2c_write(cam, 0x79, 0x98);
242 err += sn9c102_i2c_write(cam, 0x7a, 0x98);
243 err += sn9c102_i2c_write(cam, 0x7b, 0x00);
244 err += sn9c102_i2c_write(cam, 0x7c, 0x38);
245 err += sn9c102_i2c_write(cam, 0x7d, 0xff);
246 break;
247 default:
248 break;
249 }
250
251 return err;
252}
253
254
255static int ov7630_get_ctrl(struct sn9c102_device* cam,
256 struct v4l2_control* ctrl)
257{
258 enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
259 int err = 0;
260
261 switch (ctrl->id) {
262 case V4L2_CID_EXPOSURE:
263 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
264 return -EIO;
265 break;
266 case V4L2_CID_RED_BALANCE:
267 if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
268 ctrl->value = sn9c102_pread_reg(cam, 0x05);
269 else
270 ctrl->value = sn9c102_pread_reg(cam, 0x07);
271 break;
272 case V4L2_CID_BLUE_BALANCE:
273 ctrl->value = sn9c102_pread_reg(cam, 0x06);
274 break;
275 case SN9C102_V4L2_CID_GREEN_BALANCE:
276 if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
277 ctrl->value = sn9c102_pread_reg(cam, 0x07);
278 else
279 ctrl->value = sn9c102_pread_reg(cam, 0x05);
280 break;
281 break;
282 case V4L2_CID_GAIN:
283 if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
284 return -EIO;
285 ctrl->value &= 0x3f;
286 break;
287 case V4L2_CID_DO_WHITE_BALANCE:
288 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
289 return -EIO;
290 ctrl->value &= 0x3f;
291 break;
292 case V4L2_CID_WHITENESS:
293 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
294 return -EIO;
295 ctrl->value &= 0x3f;
296 break;
297 case V4L2_CID_AUTOGAIN:
298 if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
299 return -EIO;
300 ctrl->value &= 0x01;
301 break;
302 case V4L2_CID_VFLIP:
303 if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
304 return -EIO;
305 ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
306 break;
307 case SN9C102_V4L2_CID_GAMMA:
308 if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
309 return -EIO;
310 ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
311 break;
312 case SN9C102_V4L2_CID_BAND_FILTER:
313 if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
314 return -EIO;
315 ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
316 break;
317 default:
318 return -EINVAL;
319 }
320
321 return err ? -EIO : 0;
322}
323
324
325static int ov7630_set_ctrl(struct sn9c102_device* cam,
326 const struct v4l2_control* ctrl)
327{
328 enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
329 int err = 0;
330
331 switch (ctrl->id) {
332 case V4L2_CID_EXPOSURE:
333 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
334 break;
335 case V4L2_CID_RED_BALANCE:
336 if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
337 err += sn9c102_write_reg(cam, ctrl->value, 0x05);
338 else
339 err += sn9c102_write_reg(cam, ctrl->value, 0x07);
340 break;
341 case V4L2_CID_BLUE_BALANCE:
342 err += sn9c102_write_reg(cam, ctrl->value, 0x06);
343 break;
344 case SN9C102_V4L2_CID_GREEN_BALANCE:
345 if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
346 err += sn9c102_write_reg(cam, ctrl->value, 0x07);
347 else
348 err += sn9c102_write_reg(cam, ctrl->value, 0x05);
349 break;
350 case V4L2_CID_GAIN:
351 err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
352 break;
353 case V4L2_CID_DO_WHITE_BALANCE:
354 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
355 break;
356 case V4L2_CID_WHITENESS:
357 err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
358 break;
359 case V4L2_CID_AUTOGAIN:
360 err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
361 (ctrl->value << 1));
362 break;
363 case V4L2_CID_VFLIP:
364 err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
365 break;
366 case SN9C102_V4L2_CID_GAMMA:
367 err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
368 break;
369 case SN9C102_V4L2_CID_BAND_FILTER:
370 err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
371 break;
372 default:
373 return -EINVAL;
374 }
375
376 return err ? -EIO : 0;
377}
378
379
380static int ov7630_set_crop(struct sn9c102_device* cam,
381 const struct v4l2_rect* rect)
382{
383 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
384 int err = 0;
385 u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
386
387 switch (sn9c102_get_bridge(cam)) {
388 case BRIDGE_SN9C101:
389 case BRIDGE_SN9C102:
390 case BRIDGE_SN9C103:
391 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
392 break;
393 case BRIDGE_SN9C105:
394 case BRIDGE_SN9C120:
395 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
396 break;
397 default:
398 break;
399 }
400
401 err += sn9c102_write_reg(cam, h_start, 0x12);
402 err += sn9c102_write_reg(cam, v_start, 0x13);
403
404 return err;
405}
406
407
408static int ov7630_set_pix_format(struct sn9c102_device* cam,
409 const struct v4l2_pix_format* pix)
410{
411 int err = 0;
412
413 switch (sn9c102_get_bridge(cam)) {
414 case BRIDGE_SN9C101:
415 case BRIDGE_SN9C102:
416 case BRIDGE_SN9C103:
417 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
418 err += sn9c102_write_reg(cam, 0x50, 0x19);
419 else
420 err += sn9c102_write_reg(cam, 0x20, 0x19);
421 break;
422 case BRIDGE_SN9C105:
423 case BRIDGE_SN9C120:
424 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
425 err += sn9c102_write_reg(cam, 0xe5, 0x17);
426 err += sn9c102_i2c_write(cam, 0x11, 0x04);
427 } else {
428 err += sn9c102_write_reg(cam, 0xe2, 0x17);
429 err += sn9c102_i2c_write(cam, 0x11, 0x02);
430 }
431 break;
432 default:
433 break;
434 }
435
436 return err;
437}
438
439
440static const struct sn9c102_sensor ov7630 = {
441 .name = "OV7630",
442 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
443 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
444 BRIDGE_SN9C105 | BRIDGE_SN9C120,
445 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
446 .frequency = SN9C102_I2C_100KHZ,
447 .interface = SN9C102_I2C_2WIRES,
448 .i2c_slave_id = 0x21,
449 .init = &ov7630_init,
450 .qctrl = {
451 {
452 .id = V4L2_CID_GAIN,
453 .type = V4L2_CTRL_TYPE_INTEGER,
454 .name = "global gain",
455 .minimum = 0x00,
456 .maximum = 0x3f,
457 .step = 0x01,
458 .default_value = 0x14,
459 .flags = 0,
460 },
461 {
462 .id = V4L2_CID_EXPOSURE,
463 .type = V4L2_CTRL_TYPE_INTEGER,
464 .name = "exposure",
465 .minimum = 0x00,
466 .maximum = 0xff,
467 .step = 0x01,
468 .default_value = 0x60,
469 .flags = 0,
470 },
471 {
472 .id = V4L2_CID_WHITENESS,
473 .type = V4L2_CTRL_TYPE_INTEGER,
474 .name = "white balance background: red",
475 .minimum = 0x00,
476 .maximum = 0x3f,
477 .step = 0x01,
478 .default_value = 0x20,
479 .flags = 0,
480 },
481 {
482 .id = V4L2_CID_DO_WHITE_BALANCE,
483 .type = V4L2_CTRL_TYPE_INTEGER,
484 .name = "white balance background: blue",
485 .minimum = 0x00,
486 .maximum = 0x3f,
487 .step = 0x01,
488 .default_value = 0x20,
489 .flags = 0,
490 },
491 {
492 .id = V4L2_CID_RED_BALANCE,
493 .type = V4L2_CTRL_TYPE_INTEGER,
494 .name = "red balance",
495 .minimum = 0x00,
496 .maximum = 0x7f,
497 .step = 0x01,
498 .default_value = 0x20,
499 .flags = 0,
500 },
501 {
502 .id = V4L2_CID_BLUE_BALANCE,
503 .type = V4L2_CTRL_TYPE_INTEGER,
504 .name = "blue balance",
505 .minimum = 0x00,
506 .maximum = 0x7f,
507 .step = 0x01,
508 .default_value = 0x20,
509 .flags = 0,
510 },
511 {
512 .id = V4L2_CID_AUTOGAIN,
513 .type = V4L2_CTRL_TYPE_BOOLEAN,
514 .name = "auto adjust",
515 .minimum = 0x00,
516 .maximum = 0x01,
517 .step = 0x01,
518 .default_value = 0x00,
519 .flags = 0,
520 },
521 {
522 .id = V4L2_CID_VFLIP,
523 .type = V4L2_CTRL_TYPE_BOOLEAN,
524 .name = "vertical flip",
525 .minimum = 0x00,
526 .maximum = 0x01,
527 .step = 0x01,
528 .default_value = 0x01,
529 .flags = 0,
530 },
531 {
532 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
533 .type = V4L2_CTRL_TYPE_INTEGER,
534 .name = "green balance",
535 .minimum = 0x00,
536 .maximum = 0x7f,
537 .step = 0x01,
538 .default_value = 0x20,
539 .flags = 0,
540 },
541 {
542 .id = SN9C102_V4L2_CID_BAND_FILTER,
543 .type = V4L2_CTRL_TYPE_BOOLEAN,
544 .name = "band filter",
545 .minimum = 0x00,
546 .maximum = 0x01,
547 .step = 0x01,
548 .default_value = 0x00,
549 .flags = 0,
550 },
551 {
552 .id = SN9C102_V4L2_CID_GAMMA,
553 .type = V4L2_CTRL_TYPE_BOOLEAN,
554 .name = "rgb gamma",
555 .minimum = 0x00,
556 .maximum = 0x01,
557 .step = 0x01,
558 .default_value = 0x00,
559 .flags = 0,
560 },
561 },
562 .get_ctrl = &ov7630_get_ctrl,
563 .set_ctrl = &ov7630_set_ctrl,
564 .cropcap = {
565 .bounds = {
566 .left = 0,
567 .top = 0,
568 .width = 640,
569 .height = 480,
570 },
571 .defrect = {
572 .left = 0,
573 .top = 0,
574 .width = 640,
575 .height = 480,
576 },
577 },
578 .set_crop = &ov7630_set_crop,
579 .pix_format = {
580 .width = 640,
581 .height = 480,
582 .pixelformat = V4L2_PIX_FMT_SN9C10X,
583 .priv = 8,
584 },
585 .set_pix_format = &ov7630_set_pix_format
586};
587
588
589int sn9c102_probe_ov7630(struct sn9c102_device* cam)
590{
591 int pid, ver, err = 0;
592
593 switch (sn9c102_get_bridge(cam)) {
594 case BRIDGE_SN9C101:
595 case BRIDGE_SN9C102:
596 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
597 {0x28, 0x17});
598 break;
599 case BRIDGE_SN9C103: /* do _not_ change anything! */
600 err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01},
601 {0x28, 0x17}, {0x44, 0x02});
602 pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
603 if (err || pid < 0) /* try a different initialization */
604 err += sn9c102_write_const_regs(cam, {0x01, 0x01},
605 {0x00, 0x01});
606 break;
607 case BRIDGE_SN9C105:
608 case BRIDGE_SN9C120:
609 err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
610 {0x29, 0x01}, {0x74, 0x02},
611 {0x0e, 0x01}, {0x44, 0x01});
612 break;
613 default:
614 break;
615 }
616
617 pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
618 ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
619 if (err || pid < 0 || ver < 0)
620 return -EIO;
621 if (pid != 0x76 || ver != 0x31)
622 return -ENODEV;
623 sn9c102_attach_sensor(cam, &ov7630);
624
625 return 0;
626}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
new file mode 100644
index 00000000000..7977795d342
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -0,0 +1,538 @@
1/***************************************************************************
2 * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int ov7660_init(struct sn9c102_device* cam)
27{
28 int err = 0;
29
30 err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
31 {0x1a, 0x04}, {0x03, 0x10},
32 {0x08, 0x14}, {0x20, 0x17},
33 {0x8b, 0x18}, {0x00, 0x19},
34 {0x1d, 0x1a}, {0x10, 0x1b},
35 {0x02, 0x1c}, {0x03, 0x1d},
36 {0x0f, 0x1e}, {0x0c, 0x1f},
37 {0x00, 0x20}, {0x29, 0x21},
38 {0x40, 0x22}, {0x54, 0x23},
39 {0x66, 0x24}, {0x76, 0x25},
40 {0x85, 0x26}, {0x94, 0x27},
41 {0xa1, 0x28}, {0xae, 0x29},
42 {0xbb, 0x2a}, {0xc7, 0x2b},
43 {0xd3, 0x2c}, {0xde, 0x2d},
44 {0xea, 0x2e}, {0xf4, 0x2f},
45 {0xff, 0x30}, {0x00, 0x3f},
46 {0xc7, 0x40}, {0x01, 0x41},
47 {0x44, 0x42}, {0x00, 0x43},
48 {0x44, 0x44}, {0x00, 0x45},
49 {0x44, 0x46}, {0x00, 0x47},
50 {0xc7, 0x48}, {0x01, 0x49},
51 {0xc7, 0x4a}, {0x01, 0x4b},
52 {0xc7, 0x4c}, {0x01, 0x4d},
53 {0x44, 0x4e}, {0x00, 0x4f},
54 {0x44, 0x50}, {0x00, 0x51},
55 {0x44, 0x52}, {0x00, 0x53},
56 {0xc7, 0x54}, {0x01, 0x55},
57 {0xc7, 0x56}, {0x01, 0x57},
58 {0xc7, 0x58}, {0x01, 0x59},
59 {0x44, 0x5a}, {0x00, 0x5b},
60 {0x44, 0x5c}, {0x00, 0x5d},
61 {0x44, 0x5e}, {0x00, 0x5f},
62 {0xc7, 0x60}, {0x01, 0x61},
63 {0xc7, 0x62}, {0x01, 0x63},
64 {0xc7, 0x64}, {0x01, 0x65},
65 {0x44, 0x66}, {0x00, 0x67},
66 {0x44, 0x68}, {0x00, 0x69},
67 {0x44, 0x6a}, {0x00, 0x6b},
68 {0xc7, 0x6c}, {0x01, 0x6d},
69 {0xc7, 0x6e}, {0x01, 0x6f},
70 {0xc7, 0x70}, {0x01, 0x71},
71 {0x44, 0x72}, {0x00, 0x73},
72 {0x44, 0x74}, {0x00, 0x75},
73 {0x44, 0x76}, {0x00, 0x77},
74 {0xc7, 0x78}, {0x01, 0x79},
75 {0xc7, 0x7a}, {0x01, 0x7b},
76 {0xc7, 0x7c}, {0x01, 0x7d},
77 {0x44, 0x7e}, {0x00, 0x7f},
78 {0x14, 0x84}, {0x00, 0x85},
79 {0x27, 0x86}, {0x00, 0x87},
80 {0x07, 0x88}, {0x00, 0x89},
81 {0xec, 0x8a}, {0x0f, 0x8b},
82 {0xd8, 0x8c}, {0x0f, 0x8d},
83 {0x3d, 0x8e}, {0x00, 0x8f},
84 {0x3d, 0x90}, {0x00, 0x91},
85 {0xcd, 0x92}, {0x0f, 0x93},
86 {0xf7, 0x94}, {0x0f, 0x95},
87 {0x0c, 0x96}, {0x00, 0x97},
88 {0x00, 0x98}, {0x66, 0x99},
89 {0x05, 0x9a}, {0x00, 0x9b},
90 {0x04, 0x9c}, {0x00, 0x9d},
91 {0x08, 0x9e}, {0x00, 0x9f},
92 {0x2d, 0xc0}, {0x2d, 0xc1},
93 {0x3a, 0xc2}, {0x05, 0xc3},
94 {0x04, 0xc4}, {0x3f, 0xc5},
95 {0x00, 0xc6}, {0x00, 0xc7},
96 {0x50, 0xc8}, {0x3C, 0xc9},
97 {0x28, 0xca}, {0xd8, 0xcb},
98 {0x14, 0xcc}, {0xec, 0xcd},
99 {0x32, 0xce}, {0xdd, 0xcf},
100 {0x32, 0xd0}, {0xdd, 0xd1},
101 {0x6a, 0xd2}, {0x50, 0xd3},
102 {0x00, 0xd4}, {0x00, 0xd5},
103 {0x00, 0xd6});
104
105 err += sn9c102_i2c_write(cam, 0x12, 0x80);
106 err += sn9c102_i2c_write(cam, 0x11, 0x09);
107 err += sn9c102_i2c_write(cam, 0x00, 0x0A);
108 err += sn9c102_i2c_write(cam, 0x01, 0x80);
109 err += sn9c102_i2c_write(cam, 0x02, 0x80);
110 err += sn9c102_i2c_write(cam, 0x03, 0x00);
111 err += sn9c102_i2c_write(cam, 0x04, 0x00);
112 err += sn9c102_i2c_write(cam, 0x05, 0x08);
113 err += sn9c102_i2c_write(cam, 0x06, 0x0B);
114 err += sn9c102_i2c_write(cam, 0x07, 0x00);
115 err += sn9c102_i2c_write(cam, 0x08, 0x1C);
116 err += sn9c102_i2c_write(cam, 0x09, 0x01);
117 err += sn9c102_i2c_write(cam, 0x0A, 0x76);
118 err += sn9c102_i2c_write(cam, 0x0B, 0x60);
119 err += sn9c102_i2c_write(cam, 0x0C, 0x00);
120 err += sn9c102_i2c_write(cam, 0x0D, 0x08);
121 err += sn9c102_i2c_write(cam, 0x0E, 0x04);
122 err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
123 err += sn9c102_i2c_write(cam, 0x10, 0x20);
124 err += sn9c102_i2c_write(cam, 0x11, 0x03);
125 err += sn9c102_i2c_write(cam, 0x12, 0x05);
126 err += sn9c102_i2c_write(cam, 0x13, 0xC7);
127 err += sn9c102_i2c_write(cam, 0x14, 0x2C);
128 err += sn9c102_i2c_write(cam, 0x15, 0x00);
129 err += sn9c102_i2c_write(cam, 0x16, 0x02);
130 err += sn9c102_i2c_write(cam, 0x17, 0x10);
131 err += sn9c102_i2c_write(cam, 0x18, 0x60);
132 err += sn9c102_i2c_write(cam, 0x19, 0x02);
133 err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
134 err += sn9c102_i2c_write(cam, 0x1B, 0x02);
135 err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
136 err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
137 err += sn9c102_i2c_write(cam, 0x1E, 0x01);
138 err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
139 err += sn9c102_i2c_write(cam, 0x20, 0x05);
140 err += sn9c102_i2c_write(cam, 0x21, 0x05);
141 err += sn9c102_i2c_write(cam, 0x22, 0x05);
142 err += sn9c102_i2c_write(cam, 0x23, 0x05);
143 err += sn9c102_i2c_write(cam, 0x24, 0x68);
144 err += sn9c102_i2c_write(cam, 0x25, 0x58);
145 err += sn9c102_i2c_write(cam, 0x26, 0xD4);
146 err += sn9c102_i2c_write(cam, 0x27, 0x80);
147 err += sn9c102_i2c_write(cam, 0x28, 0x80);
148 err += sn9c102_i2c_write(cam, 0x29, 0x30);
149 err += sn9c102_i2c_write(cam, 0x2A, 0x00);
150 err += sn9c102_i2c_write(cam, 0x2B, 0x00);
151 err += sn9c102_i2c_write(cam, 0x2C, 0x80);
152 err += sn9c102_i2c_write(cam, 0x2D, 0x00);
153 err += sn9c102_i2c_write(cam, 0x2E, 0x00);
154 err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
155 err += sn9c102_i2c_write(cam, 0x30, 0x08);
156 err += sn9c102_i2c_write(cam, 0x31, 0x30);
157 err += sn9c102_i2c_write(cam, 0x32, 0xB4);
158 err += sn9c102_i2c_write(cam, 0x33, 0x00);
159 err += sn9c102_i2c_write(cam, 0x34, 0x07);
160 err += sn9c102_i2c_write(cam, 0x35, 0x84);
161 err += sn9c102_i2c_write(cam, 0x36, 0x00);
162 err += sn9c102_i2c_write(cam, 0x37, 0x0C);
163 err += sn9c102_i2c_write(cam, 0x38, 0x02);
164 err += sn9c102_i2c_write(cam, 0x39, 0x43);
165 err += sn9c102_i2c_write(cam, 0x3A, 0x00);
166 err += sn9c102_i2c_write(cam, 0x3B, 0x0A);
167 err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
168 err += sn9c102_i2c_write(cam, 0x3D, 0x99);
169 err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
170 err += sn9c102_i2c_write(cam, 0x3F, 0x41);
171 err += sn9c102_i2c_write(cam, 0x40, 0xC1);
172 err += sn9c102_i2c_write(cam, 0x41, 0x22);
173 err += sn9c102_i2c_write(cam, 0x42, 0x08);
174 err += sn9c102_i2c_write(cam, 0x43, 0xF0);
175 err += sn9c102_i2c_write(cam, 0x44, 0x10);
176 err += sn9c102_i2c_write(cam, 0x45, 0x78);
177 err += sn9c102_i2c_write(cam, 0x46, 0xA8);
178 err += sn9c102_i2c_write(cam, 0x47, 0x60);
179 err += sn9c102_i2c_write(cam, 0x48, 0x80);
180 err += sn9c102_i2c_write(cam, 0x49, 0x00);
181 err += sn9c102_i2c_write(cam, 0x4A, 0x00);
182 err += sn9c102_i2c_write(cam, 0x4B, 0x00);
183 err += sn9c102_i2c_write(cam, 0x4C, 0x00);
184 err += sn9c102_i2c_write(cam, 0x4D, 0x00);
185 err += sn9c102_i2c_write(cam, 0x4E, 0x00);
186 err += sn9c102_i2c_write(cam, 0x4F, 0x46);
187 err += sn9c102_i2c_write(cam, 0x50, 0x36);
188 err += sn9c102_i2c_write(cam, 0x51, 0x0F);
189 err += sn9c102_i2c_write(cam, 0x52, 0x17);
190 err += sn9c102_i2c_write(cam, 0x53, 0x7F);
191 err += sn9c102_i2c_write(cam, 0x54, 0x96);
192 err += sn9c102_i2c_write(cam, 0x55, 0x40);
193 err += sn9c102_i2c_write(cam, 0x56, 0x40);
194 err += sn9c102_i2c_write(cam, 0x57, 0x40);
195 err += sn9c102_i2c_write(cam, 0x58, 0x0F);
196 err += sn9c102_i2c_write(cam, 0x59, 0xBA);
197 err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
198 err += sn9c102_i2c_write(cam, 0x5B, 0x22);
199 err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
200 err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
201 err += sn9c102_i2c_write(cam, 0x5E, 0x10);
202 err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
203 err += sn9c102_i2c_write(cam, 0x60, 0x05);
204 err += sn9c102_i2c_write(cam, 0x61, 0x60);
205 err += sn9c102_i2c_write(cam, 0x62, 0x00);
206 err += sn9c102_i2c_write(cam, 0x63, 0x00);
207 err += sn9c102_i2c_write(cam, 0x64, 0x50);
208 err += sn9c102_i2c_write(cam, 0x65, 0x30);
209 err += sn9c102_i2c_write(cam, 0x66, 0x00);
210 err += sn9c102_i2c_write(cam, 0x67, 0x80);
211 err += sn9c102_i2c_write(cam, 0x68, 0x7A);
212 err += sn9c102_i2c_write(cam, 0x69, 0x90);
213 err += sn9c102_i2c_write(cam, 0x6A, 0x80);
214 err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
215 err += sn9c102_i2c_write(cam, 0x6C, 0x30);
216 err += sn9c102_i2c_write(cam, 0x6D, 0x48);
217 err += sn9c102_i2c_write(cam, 0x6E, 0x80);
218 err += sn9c102_i2c_write(cam, 0x6F, 0x74);
219 err += sn9c102_i2c_write(cam, 0x70, 0x64);
220 err += sn9c102_i2c_write(cam, 0x71, 0x60);
221 err += sn9c102_i2c_write(cam, 0x72, 0x5C);
222 err += sn9c102_i2c_write(cam, 0x73, 0x58);
223 err += sn9c102_i2c_write(cam, 0x74, 0x54);
224 err += sn9c102_i2c_write(cam, 0x75, 0x4C);
225 err += sn9c102_i2c_write(cam, 0x76, 0x40);
226 err += sn9c102_i2c_write(cam, 0x77, 0x38);
227 err += sn9c102_i2c_write(cam, 0x78, 0x34);
228 err += sn9c102_i2c_write(cam, 0x79, 0x30);
229 err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
230 err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
231 err += sn9c102_i2c_write(cam, 0x7C, 0x03);
232 err += sn9c102_i2c_write(cam, 0x7D, 0x07);
233 err += sn9c102_i2c_write(cam, 0x7E, 0x17);
234 err += sn9c102_i2c_write(cam, 0x7F, 0x34);
235 err += sn9c102_i2c_write(cam, 0x80, 0x41);
236 err += sn9c102_i2c_write(cam, 0x81, 0x4D);
237 err += sn9c102_i2c_write(cam, 0x82, 0x58);
238 err += sn9c102_i2c_write(cam, 0x83, 0x63);
239 err += sn9c102_i2c_write(cam, 0x84, 0x6E);
240 err += sn9c102_i2c_write(cam, 0x85, 0x77);
241 err += sn9c102_i2c_write(cam, 0x86, 0x87);
242 err += sn9c102_i2c_write(cam, 0x87, 0x95);
243 err += sn9c102_i2c_write(cam, 0x88, 0xAF);
244 err += sn9c102_i2c_write(cam, 0x89, 0xC7);
245 err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
246 err += sn9c102_i2c_write(cam, 0x8B, 0x99);
247 err += sn9c102_i2c_write(cam, 0x8C, 0x99);
248 err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
249 err += sn9c102_i2c_write(cam, 0x8E, 0x20);
250 err += sn9c102_i2c_write(cam, 0x8F, 0x26);
251 err += sn9c102_i2c_write(cam, 0x90, 0x10);
252 err += sn9c102_i2c_write(cam, 0x91, 0x0C);
253 err += sn9c102_i2c_write(cam, 0x92, 0x25);
254 err += sn9c102_i2c_write(cam, 0x93, 0x00);
255 err += sn9c102_i2c_write(cam, 0x94, 0x50);
256 err += sn9c102_i2c_write(cam, 0x95, 0x50);
257 err += sn9c102_i2c_write(cam, 0x96, 0x00);
258 err += sn9c102_i2c_write(cam, 0x97, 0x01);
259 err += sn9c102_i2c_write(cam, 0x98, 0x10);
260 err += sn9c102_i2c_write(cam, 0x99, 0x40);
261 err += sn9c102_i2c_write(cam, 0x9A, 0x40);
262 err += sn9c102_i2c_write(cam, 0x9B, 0x20);
263 err += sn9c102_i2c_write(cam, 0x9C, 0x00);
264 err += sn9c102_i2c_write(cam, 0x9D, 0x99);
265 err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
266 err += sn9c102_i2c_write(cam, 0x9F, 0x00);
267 err += sn9c102_i2c_write(cam, 0xA0, 0x00);
268 err += sn9c102_i2c_write(cam, 0xA1, 0x00);
269
270 return err;
271}
272
273
274static int ov7660_get_ctrl(struct sn9c102_device* cam,
275 struct v4l2_control* ctrl)
276{
277 int err = 0;
278
279 switch (ctrl->id) {
280 case V4L2_CID_EXPOSURE:
281 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
282 return -EIO;
283 break;
284 case V4L2_CID_DO_WHITE_BALANCE:
285 if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0)
286 return -EIO;
287 ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
288 break;
289 case V4L2_CID_RED_BALANCE:
290 if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0)
291 return -EIO;
292 ctrl->value &= 0x7f;
293 break;
294 case V4L2_CID_BLUE_BALANCE:
295 if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0)
296 return -EIO;
297 ctrl->value &= 0x7f;
298 break;
299 case SN9C102_V4L2_CID_GREEN_BALANCE:
300 if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0)
301 return -EIO;
302 ctrl->value &= 0x7f;
303 break;
304 case SN9C102_V4L2_CID_BAND_FILTER:
305 if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0)
306 return -EIO;
307 ctrl->value &= 0x08;
308 break;
309 case V4L2_CID_GAIN:
310 if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
311 return -EIO;
312 ctrl->value &= 0x1f;
313 break;
314 case V4L2_CID_AUTOGAIN:
315 if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
316 return -EIO;
317 ctrl->value &= 0x01;
318 break;
319 default:
320 return -EINVAL;
321 }
322
323 return err ? -EIO : 0;
324}
325
326
327static int ov7660_set_ctrl(struct sn9c102_device* cam,
328 const struct v4l2_control* ctrl)
329{
330 int err = 0;
331
332 switch (ctrl->id) {
333 case V4L2_CID_EXPOSURE:
334 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
335 break;
336 case V4L2_CID_DO_WHITE_BALANCE:
337 err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
338 break;
339 case V4L2_CID_RED_BALANCE:
340 err += sn9c102_write_reg(cam, ctrl->value, 0x05);
341 break;
342 case V4L2_CID_BLUE_BALANCE:
343 err += sn9c102_write_reg(cam, ctrl->value, 0x06);
344 break;
345 case SN9C102_V4L2_CID_GREEN_BALANCE:
346 err += sn9c102_write_reg(cam, ctrl->value, 0x07);
347 break;
348 case SN9C102_V4L2_CID_BAND_FILTER:
349 err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b);
350 break;
351 case V4L2_CID_GAIN:
352 err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value);
353 break;
354 case V4L2_CID_AUTOGAIN:
355 err += sn9c102_i2c_write(cam, 0x13, 0xc0 |
356 (ctrl->value * 0x07));
357 break;
358 default:
359 return -EINVAL;
360 }
361
362 return err ? -EIO : 0;
363}
364
365
366static int ov7660_set_crop(struct sn9c102_device* cam,
367 const struct v4l2_rect* rect)
368{
369 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
370 int err = 0;
371 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
372 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
373
374 err += sn9c102_write_reg(cam, h_start, 0x12);
375 err += sn9c102_write_reg(cam, v_start, 0x13);
376
377 return err;
378}
379
380
381static int ov7660_set_pix_format(struct sn9c102_device* cam,
382 const struct v4l2_pix_format* pix)
383{
384 int r0, err = 0;
385
386 r0 = sn9c102_pread_reg(cam, 0x01);
387
388 if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
389 err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
390 err += sn9c102_write_reg(cam, 0xa2, 0x17);
391 err += sn9c102_i2c_write(cam, 0x11, 0x00);
392 } else {
393 err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
394 err += sn9c102_write_reg(cam, 0xa2, 0x17);
395 err += sn9c102_i2c_write(cam, 0x11, 0x0d);
396 }
397
398 return err;
399}
400
401
402static const struct sn9c102_sensor ov7660 = {
403 .name = "OV7660",
404 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
405 .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
406 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
407 .frequency = SN9C102_I2C_100KHZ,
408 .interface = SN9C102_I2C_2WIRES,
409 .i2c_slave_id = 0x21,
410 .init = &ov7660_init,
411 .qctrl = {
412 {
413 .id = V4L2_CID_GAIN,
414 .type = V4L2_CTRL_TYPE_INTEGER,
415 .name = "global gain",
416 .minimum = 0x00,
417 .maximum = 0x1f,
418 .step = 0x01,
419 .default_value = 0x09,
420 .flags = 0,
421 },
422 {
423 .id = V4L2_CID_EXPOSURE,
424 .type = V4L2_CTRL_TYPE_INTEGER,
425 .name = "exposure",
426 .minimum = 0x00,
427 .maximum = 0xff,
428 .step = 0x01,
429 .default_value = 0x27,
430 .flags = 0,
431 },
432 {
433 .id = V4L2_CID_DO_WHITE_BALANCE,
434 .type = V4L2_CTRL_TYPE_BOOLEAN,
435 .name = "night mode",
436 .minimum = 0x00,
437 .maximum = 0x01,
438 .step = 0x01,
439 .default_value = 0x00,
440 .flags = 0,
441 },
442 {
443 .id = V4L2_CID_RED_BALANCE,
444 .type = V4L2_CTRL_TYPE_INTEGER,
445 .name = "red balance",
446 .minimum = 0x00,
447 .maximum = 0x7f,
448 .step = 0x01,
449 .default_value = 0x14,
450 .flags = 0,
451 },
452 {
453 .id = V4L2_CID_BLUE_BALANCE,
454 .type = V4L2_CTRL_TYPE_INTEGER,
455 .name = "blue balance",
456 .minimum = 0x00,
457 .maximum = 0x7f,
458 .step = 0x01,
459 .default_value = 0x14,
460 .flags = 0,
461 },
462 {
463 .id = V4L2_CID_AUTOGAIN,
464 .type = V4L2_CTRL_TYPE_BOOLEAN,
465 .name = "auto adjust",
466 .minimum = 0x00,
467 .maximum = 0x01,
468 .step = 0x01,
469 .default_value = 0x01,
470 .flags = 0,
471 },
472 {
473 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
474 .type = V4L2_CTRL_TYPE_INTEGER,
475 .name = "green balance",
476 .minimum = 0x00,
477 .maximum = 0x7f,
478 .step = 0x01,
479 .default_value = 0x14,
480 .flags = 0,
481 },
482 {
483 .id = SN9C102_V4L2_CID_BAND_FILTER,
484 .type = V4L2_CTRL_TYPE_BOOLEAN,
485 .name = "band filter",
486 .minimum = 0x00,
487 .maximum = 0x01,
488 .step = 0x01,
489 .default_value = 0x00,
490 .flags = 0,
491 },
492 },
493 .get_ctrl = &ov7660_get_ctrl,
494 .set_ctrl = &ov7660_set_ctrl,
495 .cropcap = {
496 .bounds = {
497 .left = 0,
498 .top = 0,
499 .width = 640,
500 .height = 480,
501 },
502 .defrect = {
503 .left = 0,
504 .top = 0,
505 .width = 640,
506 .height = 480,
507 },
508 },
509 .set_crop = &ov7660_set_crop,
510 .pix_format = {
511 .width = 640,
512 .height = 480,
513 .pixelformat = V4L2_PIX_FMT_JPEG,
514 .priv = 8,
515 },
516 .set_pix_format = &ov7660_set_pix_format
517};
518
519
520int sn9c102_probe_ov7660(struct sn9c102_device* cam)
521{
522 int pid, ver, err;
523
524 err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
525 {0x01, 0x01}, {0x00, 0x01},
526 {0x28, 0x17});
527
528 pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
529 ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
530 if (err || pid < 0 || ver < 0)
531 return -EIO;
532 if (pid != 0x76 || ver != 0x60)
533 return -ENODEV;
534
535 sn9c102_attach_sensor(cam, &ov7660);
536
537 return 0;
538}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
new file mode 100644
index 00000000000..81cd969c1b7
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c
@@ -0,0 +1,302 @@
1/***************************************************************************
2 * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include <linux/delay.h>
23#include "sn9c102_sensor.h"
24#include "sn9c102_devtable.h"
25
26
27static int pas106b_init(struct sn9c102_device* cam)
28{
29 int err = 0;
30
31 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
32 {0x00, 0x14}, {0x20, 0x17},
33 {0x20, 0x19}, {0x09, 0x18});
34
35 err += sn9c102_i2c_write(cam, 0x02, 0x0c);
36 err += sn9c102_i2c_write(cam, 0x05, 0x5a);
37 err += sn9c102_i2c_write(cam, 0x06, 0x88);
38 err += sn9c102_i2c_write(cam, 0x07, 0x80);
39 err += sn9c102_i2c_write(cam, 0x10, 0x06);
40 err += sn9c102_i2c_write(cam, 0x11, 0x06);
41 err += sn9c102_i2c_write(cam, 0x12, 0x00);
42 err += sn9c102_i2c_write(cam, 0x14, 0x02);
43 err += sn9c102_i2c_write(cam, 0x13, 0x01);
44
45 msleep(400);
46
47 return err;
48}
49
50
51static int pas106b_get_ctrl(struct sn9c102_device* cam,
52 struct v4l2_control* ctrl)
53{
54 switch (ctrl->id) {
55 case V4L2_CID_EXPOSURE:
56 {
57 int r1 = sn9c102_i2c_read(cam, 0x03),
58 r2 = sn9c102_i2c_read(cam, 0x04);
59 if (r1 < 0 || r2 < 0)
60 return -EIO;
61 ctrl->value = (r1 << 4) | (r2 & 0x0f);
62 }
63 return 0;
64 case V4L2_CID_RED_BALANCE:
65 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
66 return -EIO;
67 ctrl->value &= 0x1f;
68 return 0;
69 case V4L2_CID_BLUE_BALANCE:
70 if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
71 return -EIO;
72 ctrl->value &= 0x1f;
73 return 0;
74 case V4L2_CID_GAIN:
75 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
76 return -EIO;
77 ctrl->value &= 0x1f;
78 return 0;
79 case V4L2_CID_CONTRAST:
80 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
81 return -EIO;
82 ctrl->value &= 0x07;
83 return 0;
84 case SN9C102_V4L2_CID_GREEN_BALANCE:
85 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
86 return -EIO;
87 ctrl->value = (ctrl->value & 0x1f) << 1;
88 return 0;
89 case SN9C102_V4L2_CID_DAC_MAGNITUDE:
90 if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
91 return -EIO;
92 ctrl->value &= 0xf8;
93 return 0;
94 default:
95 return -EINVAL;
96 }
97}
98
99
100static int pas106b_set_ctrl(struct sn9c102_device* cam,
101 const struct v4l2_control* ctrl)
102{
103 int err = 0;
104
105 switch (ctrl->id) {
106 case V4L2_CID_EXPOSURE:
107 err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
108 err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
109 break;
110 case V4L2_CID_RED_BALANCE:
111 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
112 break;
113 case V4L2_CID_BLUE_BALANCE:
114 err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
115 break;
116 case V4L2_CID_GAIN:
117 err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
118 break;
119 case V4L2_CID_CONTRAST:
120 err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
121 break;
122 case SN9C102_V4L2_CID_GREEN_BALANCE:
123 err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
124 err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
125 break;
126 case SN9C102_V4L2_CID_DAC_MAGNITUDE:
127 err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
128 break;
129 default:
130 return -EINVAL;
131 }
132 err += sn9c102_i2c_write(cam, 0x13, 0x01);
133
134 return err ? -EIO : 0;
135}
136
137
138static int pas106b_set_crop(struct sn9c102_device* cam,
139 const struct v4l2_rect* rect)
140{
141 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
142 int err = 0;
143 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
144 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
145
146 err += sn9c102_write_reg(cam, h_start, 0x12);
147 err += sn9c102_write_reg(cam, v_start, 0x13);
148
149 return err;
150}
151
152
153static int pas106b_set_pix_format(struct sn9c102_device* cam,
154 const struct v4l2_pix_format* pix)
155{
156 int err = 0;
157
158 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
159 err += sn9c102_write_reg(cam, 0x2c, 0x17);
160 else
161 err += sn9c102_write_reg(cam, 0x20, 0x17);
162
163 return err;
164}
165
166
167static const struct sn9c102_sensor pas106b = {
168 .name = "PAS106B",
169 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
170 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
171 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
172 .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
173 .interface = SN9C102_I2C_2WIRES,
174 .i2c_slave_id = 0x40,
175 .init = &pas106b_init,
176 .qctrl = {
177 {
178 .id = V4L2_CID_EXPOSURE,
179 .type = V4L2_CTRL_TYPE_INTEGER,
180 .name = "exposure",
181 .minimum = 0x125,
182 .maximum = 0xfff,
183 .step = 0x001,
184 .default_value = 0x140,
185 .flags = 0,
186 },
187 {
188 .id = V4L2_CID_GAIN,
189 .type = V4L2_CTRL_TYPE_INTEGER,
190 .name = "global gain",
191 .minimum = 0x00,
192 .maximum = 0x1f,
193 .step = 0x01,
194 .default_value = 0x0d,
195 .flags = 0,
196 },
197 {
198 .id = V4L2_CID_CONTRAST,
199 .type = V4L2_CTRL_TYPE_INTEGER,
200 .name = "contrast",
201 .minimum = 0x00,
202 .maximum = 0x07,
203 .step = 0x01,
204 .default_value = 0x00, /* 0x00~0x03 have same effect */
205 .flags = 0,
206 },
207 {
208 .id = V4L2_CID_RED_BALANCE,
209 .type = V4L2_CTRL_TYPE_INTEGER,
210 .name = "red balance",
211 .minimum = 0x00,
212 .maximum = 0x1f,
213 .step = 0x01,
214 .default_value = 0x04,
215 .flags = 0,
216 },
217 {
218 .id = V4L2_CID_BLUE_BALANCE,
219 .type = V4L2_CTRL_TYPE_INTEGER,
220 .name = "blue balance",
221 .minimum = 0x00,
222 .maximum = 0x1f,
223 .step = 0x01,
224 .default_value = 0x06,
225 .flags = 0,
226 },
227 {
228 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
229 .type = V4L2_CTRL_TYPE_INTEGER,
230 .name = "green balance",
231 .minimum = 0x00,
232 .maximum = 0x3e,
233 .step = 0x02,
234 .default_value = 0x02,
235 .flags = 0,
236 },
237 {
238 .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
239 .type = V4L2_CTRL_TYPE_INTEGER,
240 .name = "DAC magnitude",
241 .minimum = 0x00,
242 .maximum = 0x1f,
243 .step = 0x01,
244 .default_value = 0x01,
245 .flags = 0,
246 },
247 },
248 .get_ctrl = &pas106b_get_ctrl,
249 .set_ctrl = &pas106b_set_ctrl,
250 .cropcap = {
251 .bounds = {
252 .left = 0,
253 .top = 0,
254 .width = 352,
255 .height = 288,
256 },
257 .defrect = {
258 .left = 0,
259 .top = 0,
260 .width = 352,
261 .height = 288,
262 },
263 },
264 .set_crop = &pas106b_set_crop,
265 .pix_format = {
266 .width = 352,
267 .height = 288,
268 .pixelformat = V4L2_PIX_FMT_SBGGR8,
269 .priv = 8, /* we use this field as 'bits per pixel' */
270 },
271 .set_pix_format = &pas106b_set_pix_format
272};
273
274
275int sn9c102_probe_pas106b(struct sn9c102_device* cam)
276{
277 int r0 = 0, r1 = 0;
278 unsigned int pid = 0;
279
280 /*
281 Minimal initialization to enable the I2C communication
282 NOTE: do NOT change the values!
283 */
284 if (sn9c102_write_const_regs(cam,
285 {0x01, 0x01}, /* sensor power down */
286 {0x00, 0x01}, /* sensor power on */
287 {0x28, 0x17})) /* sensor clock at 24 MHz */
288 return -EIO;
289
290 r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
291 r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
292 if (r0 < 0 || r1 < 0)
293 return -EIO;
294
295 pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
296 if (pid != 0x007)
297 return -ENODEV;
298
299 sn9c102_attach_sensor(cam, &pas106b);
300
301 return 0;
302}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
new file mode 100644
index 00000000000..2e86fdc8698
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -0,0 +1,335 @@
1/***************************************************************************
2 * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
6 * <medaglia@undl.org.br> *
7 * *
8 * Support for SN9C103, DAC Magnitude, exposure and green gain controls *
9 * added by Luca Risolia <luca.risolia@studio.unibo.it> *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the Free Software *
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
24 ***************************************************************************/
25
26#include <linux/delay.h>
27#include "sn9c102_sensor.h"
28#include "sn9c102_devtable.h"
29
30
31static int pas202bcb_init(struct sn9c102_device* cam)
32{
33 int err = 0;
34
35 switch (sn9c102_get_bridge(cam)) {
36 case BRIDGE_SN9C101:
37 case BRIDGE_SN9C102:
38 err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
39 {0x00, 0x14}, {0x20, 0x17},
40 {0x30, 0x19}, {0x09, 0x18});
41 break;
42 case BRIDGE_SN9C103:
43 err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
44 {0x1a, 0x04}, {0x20, 0x05},
45 {0x20, 0x06}, {0x20, 0x07},
46 {0x00, 0x10}, {0x00, 0x11},
47 {0x00, 0x14}, {0x20, 0x17},
48 {0x30, 0x19}, {0x09, 0x18},
49 {0x02, 0x1c}, {0x03, 0x1d},
50 {0x0f, 0x1e}, {0x0c, 0x1f},
51 {0x00, 0x20}, {0x10, 0x21},
52 {0x20, 0x22}, {0x30, 0x23},
53 {0x40, 0x24}, {0x50, 0x25},
54 {0x60, 0x26}, {0x70, 0x27},
55 {0x80, 0x28}, {0x90, 0x29},
56 {0xa0, 0x2a}, {0xb0, 0x2b},
57 {0xc0, 0x2c}, {0xd0, 0x2d},
58 {0xe0, 0x2e}, {0xf0, 0x2f},
59 {0xff, 0x30});
60 break;
61 default:
62 break;
63 }
64
65 err += sn9c102_i2c_write(cam, 0x02, 0x14);
66 err += sn9c102_i2c_write(cam, 0x03, 0x40);
67 err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
68 err += sn9c102_i2c_write(cam, 0x0e, 0x01);
69 err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
70 err += sn9c102_i2c_write(cam, 0x10, 0x08);
71 err += sn9c102_i2c_write(cam, 0x13, 0x63);
72 err += sn9c102_i2c_write(cam, 0x15, 0x70);
73 err += sn9c102_i2c_write(cam, 0x11, 0x01);
74
75 msleep(400);
76
77 return err;
78}
79
80
81static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
82 struct v4l2_control* ctrl)
83{
84 switch (ctrl->id) {
85 case V4L2_CID_EXPOSURE:
86 {
87 int r1 = sn9c102_i2c_read(cam, 0x04),
88 r2 = sn9c102_i2c_read(cam, 0x05);
89 if (r1 < 0 || r2 < 0)
90 return -EIO;
91 ctrl->value = (r1 << 6) | (r2 & 0x3f);
92 }
93 return 0;
94 case V4L2_CID_RED_BALANCE:
95 if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
96 return -EIO;
97 ctrl->value &= 0x0f;
98 return 0;
99 case V4L2_CID_BLUE_BALANCE:
100 if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
101 return -EIO;
102 ctrl->value &= 0x0f;
103 return 0;
104 case V4L2_CID_GAIN:
105 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
106 return -EIO;
107 ctrl->value &= 0x1f;
108 return 0;
109 case SN9C102_V4L2_CID_GREEN_BALANCE:
110 if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
111 return -EIO;
112 ctrl->value &= 0x0f;
113 return 0;
114 case SN9C102_V4L2_CID_DAC_MAGNITUDE:
115 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
116 return -EIO;
117 return 0;
118 default:
119 return -EINVAL;
120 }
121}
122
123
124static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
125 const struct v4l2_pix_format* pix)
126{
127 int err = 0;
128
129 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
130 err += sn9c102_write_reg(cam, 0x28, 0x17);
131 else
132 err += sn9c102_write_reg(cam, 0x20, 0x17);
133
134 return err;
135}
136
137
138static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
139 const struct v4l2_control* ctrl)
140{
141 int err = 0;
142
143 switch (ctrl->id) {
144 case V4L2_CID_EXPOSURE:
145 err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
146 err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
147 break;
148 case V4L2_CID_RED_BALANCE:
149 err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
150 break;
151 case V4L2_CID_BLUE_BALANCE:
152 err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
153 break;
154 case V4L2_CID_GAIN:
155 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
156 break;
157 case SN9C102_V4L2_CID_GREEN_BALANCE:
158 err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
159 break;
160 case SN9C102_V4L2_CID_DAC_MAGNITUDE:
161 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
162 break;
163 default:
164 return -EINVAL;
165 }
166 err += sn9c102_i2c_write(cam, 0x11, 0x01);
167
168 return err ? -EIO : 0;
169}
170
171
172static int pas202bcb_set_crop(struct sn9c102_device* cam,
173 const struct v4l2_rect* rect)
174{
175 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
176 int err = 0;
177 u8 h_start = 0,
178 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
179
180 switch (sn9c102_get_bridge(cam)) {
181 case BRIDGE_SN9C101:
182 case BRIDGE_SN9C102:
183 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
184 break;
185 case BRIDGE_SN9C103:
186 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
187 break;
188 default:
189 break;
190 }
191
192 err += sn9c102_write_reg(cam, h_start, 0x12);
193 err += sn9c102_write_reg(cam, v_start, 0x13);
194
195 return err;
196}
197
198
199static const struct sn9c102_sensor pas202bcb = {
200 .name = "PAS202BCB",
201 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
202 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
203 .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
204 .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
205 .interface = SN9C102_I2C_2WIRES,
206 .i2c_slave_id = 0x40,
207 .init = &pas202bcb_init,
208 .qctrl = {
209 {
210 .id = V4L2_CID_EXPOSURE,
211 .type = V4L2_CTRL_TYPE_INTEGER,
212 .name = "exposure",
213 .minimum = 0x01e5,
214 .maximum = 0x3fff,
215 .step = 0x0001,
216 .default_value = 0x01e5,
217 .flags = 0,
218 },
219 {
220 .id = V4L2_CID_GAIN,
221 .type = V4L2_CTRL_TYPE_INTEGER,
222 .name = "global gain",
223 .minimum = 0x00,
224 .maximum = 0x1f,
225 .step = 0x01,
226 .default_value = 0x0b,
227 .flags = 0,
228 },
229 {
230 .id = V4L2_CID_RED_BALANCE,
231 .type = V4L2_CTRL_TYPE_INTEGER,
232 .name = "red balance",
233 .minimum = 0x00,
234 .maximum = 0x0f,
235 .step = 0x01,
236 .default_value = 0x00,
237 .flags = 0,
238 },
239 {
240 .id = V4L2_CID_BLUE_BALANCE,
241 .type = V4L2_CTRL_TYPE_INTEGER,
242 .name = "blue balance",
243 .minimum = 0x00,
244 .maximum = 0x0f,
245 .step = 0x01,
246 .default_value = 0x05,
247 .flags = 0,
248 },
249 {
250 .id = SN9C102_V4L2_CID_GREEN_BALANCE,
251 .type = V4L2_CTRL_TYPE_INTEGER,
252 .name = "green balance",
253 .minimum = 0x00,
254 .maximum = 0x0f,
255 .step = 0x01,
256 .default_value = 0x00,
257 .flags = 0,
258 },
259 {
260 .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
261 .type = V4L2_CTRL_TYPE_INTEGER,
262 .name = "DAC magnitude",
263 .minimum = 0x00,
264 .maximum = 0xff,
265 .step = 0x01,
266 .default_value = 0x04,
267 .flags = 0,
268 },
269 },
270 .get_ctrl = &pas202bcb_get_ctrl,
271 .set_ctrl = &pas202bcb_set_ctrl,
272 .cropcap = {
273 .bounds = {
274 .left = 0,
275 .top = 0,
276 .width = 640,
277 .height = 480,
278 },
279 .defrect = {
280 .left = 0,
281 .top = 0,
282 .width = 640,
283 .height = 480,
284 },
285 },
286 .set_crop = &pas202bcb_set_crop,
287 .pix_format = {
288 .width = 640,
289 .height = 480,
290 .pixelformat = V4L2_PIX_FMT_SBGGR8,
291 .priv = 8,
292 },
293 .set_pix_format = &pas202bcb_set_pix_format
294};
295
296
297int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
298{
299 int r0 = 0, r1 = 0, err = 0;
300 unsigned int pid = 0;
301
302 /*
303 * Minimal initialization to enable the I2C communication
304 * NOTE: do NOT change the values!
305 */
306 switch (sn9c102_get_bridge(cam)) {
307 case BRIDGE_SN9C101:
308 case BRIDGE_SN9C102:
309 err = sn9c102_write_const_regs(cam,
310 {0x01, 0x01}, /* power down */
311 {0x40, 0x01}, /* power on */
312 {0x28, 0x17});/* clock 24 MHz */
313 break;
314 case BRIDGE_SN9C103: /* do _not_ change anything! */
315 err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01},
316 {0x44, 0x02}, {0x29, 0x17});
317 break;
318 default:
319 break;
320 }
321
322 r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
323 r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
324
325 if (err || r0 < 0 || r1 < 0)
326 return -EIO;
327
328 pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
329 if (pid != 0x017)
330 return -ENODEV;
331
332 sn9c102_attach_sensor(cam, &pas202bcb);
333
334 return 0;
335}
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
new file mode 100644
index 00000000000..3679970dba2
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -0,0 +1,307 @@
1/***************************************************************************
2 * API for image sensors connected to the SN9C1xx PC Camera Controllers *
3 * *
4 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 ***************************************************************************/
20
21#ifndef _SN9C102_SENSOR_H_
22#define _SN9C102_SENSOR_H_
23
24#include <linux/usb.h>
25#include <linux/videodev2.h>
26#include <linux/device.h>
27#include <linux/stddef.h>
28#include <linux/errno.h>
29#include <asm/types.h>
30
31struct sn9c102_device;
32struct sn9c102_sensor;
33
34/*****************************************************************************/
35
36/*
37 OVERVIEW.
38 This is a small interface that allows you to add support for any CCD/CMOS
39 image sensors connected to the SN9C1XX bridges. The entire API is documented
40 below. In the most general case, to support a sensor there are three steps
41 you have to follow:
42 1) define the main "sn9c102_sensor" structure by setting the basic fields;
43 2) write a probing function to be called by the core module when the USB
44 camera is recognized, then add both the USB ids and the name of that
45 function to the two corresponding tables in sn9c102_devtable.h;
46 3) implement the methods that you want/need (and fill the rest of the main
47 structure accordingly).
48 "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
49 NOT need to touch the source code of the core module for the things to work
50 properly, unless you find bugs or flaws in it. Finally, do not forget to
51 read the V4L2 API for completeness.
52*/
53
54/*****************************************************************************/
55
56enum sn9c102_bridge {
57 BRIDGE_SN9C101 = 0x01,
58 BRIDGE_SN9C102 = 0x02,
59 BRIDGE_SN9C103 = 0x04,
60 BRIDGE_SN9C105 = 0x08,
61 BRIDGE_SN9C120 = 0x10,
62};
63
64/* Return the bridge name */
65enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
66
67/* Return a pointer the sensor struct attached to the camera */
68struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
69
70/* Identify a device */
71extern struct sn9c102_device*
72sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
73
74/* Attach a probed sensor to the camera. */
75extern void
76sn9c102_attach_sensor(struct sn9c102_device* cam,
77 const struct sn9c102_sensor* sensor);
78
79/*
80 Read/write routines: they always return -1 on error, 0 or the read value
81 otherwise. NOTE that a real read operation is not supported by the SN9C1XX
82 chip for some of its registers. To work around this problem, a pseudo-read
83 call is provided instead: it returns the last successfully written value
84 on the register (0 if it has never been written), the usual -1 on error.
85*/
86
87/* The "try" I2C I/O versions are used when probing the sensor */
88extern int sn9c102_i2c_try_read(struct sn9c102_device*,
89 const struct sn9c102_sensor*, u8 address);
90
91/*
92 These must be used if and only if the sensor doesn't implement the standard
93 I2C protocol. There are a number of good reasons why you must use the
94 single-byte versions of these functions: do not abuse. The first function
95 writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
96 chip. The second one programs the registers 0x09 and 0x10 with data0 and
97 data1, and places the n bytes read from the sensor register table in the
98 buffer pointed by 'buffer'. Both the functions return -1 on error; the write
99 version returns 0 on success, while the read version returns the first read
100 byte.
101*/
102extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
103 const struct sn9c102_sensor* sensor, u8 n,
104 u8 data0, u8 data1, u8 data2, u8 data3,
105 u8 data4, u8 data5);
106extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
107 const struct sn9c102_sensor* sensor,
108 u8 data0, u8 data1, u8 n, u8 buffer[]);
109
110/* To be used after the sensor struct has been attached to the camera struct */
111extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
112extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
113
114/* I/O on registers in the bridge. Could be used by the sensor methods too */
115extern int sn9c102_read_reg(struct sn9c102_device*, u16 index);
116extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
117extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
118extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2],
119 int count);
120/*
121 Write multiple registers with constant values. For example:
122 sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18});
123 Register addresses must be < 256.
124*/
125#define sn9c102_write_const_regs(sn9c102_device, data...) \
126 ({ static const u8 _valreg[][2] = {data}; \
127 sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); })
128
129/*****************************************************************************/
130
131enum sn9c102_i2c_sysfs_ops {
132 SN9C102_I2C_READ = 0x01,
133 SN9C102_I2C_WRITE = 0x02,
134};
135
136enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
137 SN9C102_I2C_100KHZ = 0x01,
138 SN9C102_I2C_400KHZ = 0x02,
139};
140
141enum sn9c102_i2c_interface {
142 SN9C102_I2C_2WIRES,
143 SN9C102_I2C_3WIRES,
144};
145
146#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
147
148struct sn9c102_sensor {
149 char name[32], /* sensor name */
150 maintainer[64]; /* name of the maintainer <email> */
151
152 enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
153
154 /* Supported operations through the 'sysfs' interface */
155 enum sn9c102_i2c_sysfs_ops sysfs_ops;
156
157 /*
158 These sensor capabilities must be provided if the SN9C1XX controller
159 needs to communicate through the sensor serial interface by using
160 at least one of the i2c functions available.
161 */
162 enum sn9c102_i2c_frequency frequency;
163 enum sn9c102_i2c_interface interface;
164
165 /*
166 This identifier must be provided if the image sensor implements
167 the standard I2C protocol.
168 */
169 u8 i2c_slave_id; /* reg. 0x09 */
170
171 /*
172 NOTE: Where not noted,most of the functions below are not mandatory.
173 Set to null if you do not implement them. If implemented,
174 they must return 0 on success, the proper error otherwise.
175 */
176
177 int (*init)(struct sn9c102_device* cam);
178 /*
179 This function will be called after the sensor has been attached.
180 It should be used to initialize the sensor only, but may also
181 configure part of the SN9C1XX chip if necessary. You don't need to
182 setup picture settings like brightness, contrast, etc.. here, if
183 the corresponding controls are implemented (see below), since
184 they are adjusted in the core driver by calling the set_ctrl()
185 method after init(), where the arguments are the default values
186 specified in the v4l2_queryctrl list of supported controls;
187 Same suggestions apply for other settings, _if_ the corresponding
188 methods are present; if not, the initialization must configure the
189 sensor according to the default configuration structures below.
190 */
191
192 struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
193 /*
194 Optional list of default controls, defined as indicated in the
195 V4L2 API. Menu type controls are not handled by this interface.
196 */
197
198 int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
199 int (*set_ctrl)(struct sn9c102_device* cam,
200 const struct v4l2_control* ctrl);
201 /*
202 You must implement at least the set_ctrl method if you have defined
203 the list above. The returned value must follow the V4L2
204 specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
205 are not supported by this driver, so do not implement them. Also,
206 you don't have to check whether the passed values are out of bounds,
207 given that this is done by the core module.
208 */
209
210 struct v4l2_cropcap cropcap;
211 /*
212 Think the image sensor as a grid of R,G,B monochromatic pixels
213 disposed according to a particular Bayer pattern, which describes
214 the complete array of pixels, from (0,0) to (xmax, ymax). We will
215 use this coordinate system from now on. It is assumed the sensor
216 chip can be programmed to capture/transmit a subsection of that
217 array of pixels: we will call this subsection "active window".
218 It is not always true that the largest achievable active window can
219 cover the whole array of pixels. The V4L2 API defines another
220 area called "source rectangle", which, in turn, is a subrectangle of
221 the active window. The SN9C1XX chip is always programmed to read the
222 source rectangle.
223 The bounds of both the active window and the source rectangle are
224 specified in the cropcap substructures 'bounds' and 'defrect'.
225 By default, the source rectangle should cover the largest possible
226 area. Again, it is not always true that the largest source rectangle
227 can cover the entire active window, although it is a rare case for
228 the hardware we have. The bounds of the source rectangle _must_ be
229 multiple of 16 and must use the same coordinate system as indicated
230 before; their centers shall align initially.
231 If necessary, the sensor chip must be initialized during init() to
232 set the bounds of the active sensor window; however, by default, it
233 usually covers the largest achievable area (maxwidth x maxheight)
234 of pixels, so no particular initialization is needed, if you have
235 defined the correct default bounds in the structures.
236 See the V4L2 API for further details.
237 NOTE: once you have defined the bounds of the active window
238 (struct cropcap.bounds) you must not change them.anymore.
239 Only 'bounds' and 'defrect' fields are mandatory, other fields
240 will be ignored.
241 */
242
243 int (*set_crop)(struct sn9c102_device* cam,
244 const struct v4l2_rect* rect);
245 /*
246 To be called on VIDIOC_C_SETCROP. The core module always calls a
247 default routine which configures the appropriate SN9C1XX regs (also
248 scaling), but you may need to override/adjust specific stuff.
249 'rect' contains width and height values that are multiple of 16: in
250 case you override the default function, you always have to program
251 the chip to match those values; on error return the corresponding
252 error code without rolling back.
253 NOTE: in case, you must program the SN9C1XX chip to get rid of
254 blank pixels or blank lines at the _start_ of each line or
255 frame after each HSYNC or VSYNC, so that the image starts with
256 real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
257 V_SIZE you don't have to care about blank pixels or blank
258 lines at the end of each line or frame).
259 */
260
261 struct v4l2_pix_format pix_format;
262 /*
263 What you have to define here are: 1) initial 'width' and 'height' of
264 the target rectangle 2) the initial 'pixelformat', which can be
265 either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
266 or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
267 the number of bits per pixel for uncompressed video, 8 or 9 (despite
268 the current value of 'pixelformat').
269 NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
270 of cropcap.defrect.width and cropcap.defrect.height. I
271 suggest 1/1.
272 NOTE 2: The initial compression quality is defined by the first bit
273 of reg 0x17 during the initialization of the image sensor.
274 NOTE 3: as said above, you have to program the SN9C1XX chip to get
275 rid of any blank pixels, so that the output of the sensor
276 matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
277 */
278
279 int (*set_pix_format)(struct sn9c102_device* cam,
280 const struct v4l2_pix_format* pix);
281 /*
282 To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
283 SN9C10X pixel format or viceversa. On error return the corresponding
284 error code without rolling back.
285 */
286
287 /*
288 Do NOT write to the data below, it's READ ONLY. It is used by the
289 core module to store successfully updated values of the above
290 settings, for rollbacks..etc..in case of errors during atomic I/O
291 */
292 struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
293 struct v4l2_rect _rect;
294};
295
296/*****************************************************************************/
297
298/* Private ioctl's for control settings supported by some image sensors */
299#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
300#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
301#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
302#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
303#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
304#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
305#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
306
307#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
new file mode 100644
index 00000000000..04cdfdde856
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
@@ -0,0 +1,154 @@
1/***************************************************************************
2 * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int tas5110c1b_init(struct sn9c102_device* cam)
27{
28 int err = 0;
29
30 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01},
31 {0x00, 0x10}, {0x00, 0x11},
32 {0x0a, 0x14}, {0x60, 0x17},
33 {0x06, 0x18}, {0xfb, 0x19});
34
35 err += sn9c102_i2c_write(cam, 0xc0, 0x80);
36
37 return err;
38}
39
40
41static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
42 const struct v4l2_control* ctrl)
43{
44 int err = 0;
45
46 switch (ctrl->id) {
47 case V4L2_CID_GAIN:
48 err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
49 break;
50 default:
51 return -EINVAL;
52 }
53
54 return err ? -EIO : 0;
55}
56
57
58static int tas5110c1b_set_crop(struct sn9c102_device* cam,
59 const struct v4l2_rect* rect)
60{
61 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
62 int err = 0;
63 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
64 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
65
66 err += sn9c102_write_reg(cam, h_start, 0x12);
67 err += sn9c102_write_reg(cam, v_start, 0x13);
68
69 /* Don't change ! */
70 err += sn9c102_write_reg(cam, 0x14, 0x1a);
71 err += sn9c102_write_reg(cam, 0x0a, 0x1b);
72 err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
73
74 return err;
75}
76
77
78static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
79 const struct v4l2_pix_format* pix)
80{
81 int err = 0;
82
83 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
84 err += sn9c102_write_reg(cam, 0x2b, 0x19);
85 else
86 err += sn9c102_write_reg(cam, 0xfb, 0x19);
87
88 return err;
89}
90
91
92static const struct sn9c102_sensor tas5110c1b = {
93 .name = "TAS5110C1B",
94 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
95 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
96 .sysfs_ops = SN9C102_I2C_WRITE,
97 .frequency = SN9C102_I2C_100KHZ,
98 .interface = SN9C102_I2C_3WIRES,
99 .init = &tas5110c1b_init,
100 .qctrl = {
101 {
102 .id = V4L2_CID_GAIN,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "global gain",
105 .minimum = 0x00,
106 .maximum = 0xf6,
107 .step = 0x01,
108 .default_value = 0x40,
109 .flags = 0,
110 },
111 },
112 .set_ctrl = &tas5110c1b_set_ctrl,
113 .cropcap = {
114 .bounds = {
115 .left = 0,
116 .top = 0,
117 .width = 352,
118 .height = 288,
119 },
120 .defrect = {
121 .left = 0,
122 .top = 0,
123 .width = 352,
124 .height = 288,
125 },
126 },
127 .set_crop = &tas5110c1b_set_crop,
128 .pix_format = {
129 .width = 352,
130 .height = 288,
131 .pixelformat = V4L2_PIX_FMT_SBGGR8,
132 .priv = 8,
133 },
134 .set_pix_format = &tas5110c1b_set_pix_format
135};
136
137
138int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
139{
140 const struct usb_device_id tas5110c1b_id_table[] = {
141 { USB_DEVICE(0x0c45, 0x6001), },
142 { USB_DEVICE(0x0c45, 0x6005), },
143 { USB_DEVICE(0x0c45, 0x60ab), },
144 { }
145 };
146
147 /* Sensor detection is based on USB pid/vid */
148 if (!sn9c102_match_id(cam, tas5110c1b_id_table))
149 return -ENODEV;
150
151 sn9c102_attach_sensor(cam, &tas5110c1b);
152
153 return 0;
154}
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
new file mode 100644
index 00000000000..9372e6f9fcf
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
@@ -0,0 +1,119 @@
1/***************************************************************************
2 * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int tas5110d_init(struct sn9c102_device* cam)
27{
28 int err;
29
30 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01},
31 {0x0a, 0x14}, {0x60, 0x17},
32 {0x06, 0x18}, {0xfb, 0x19});
33
34 err += sn9c102_i2c_write(cam, 0x9a, 0xca);
35
36 return err;
37}
38
39
40static int tas5110d_set_crop(struct sn9c102_device* cam,
41 const struct v4l2_rect* rect)
42{
43 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
44 int err = 0;
45 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
46 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
47
48 err += sn9c102_write_reg(cam, h_start, 0x12);
49 err += sn9c102_write_reg(cam, v_start, 0x13);
50
51 err += sn9c102_write_reg(cam, 0x14, 0x1a);
52 err += sn9c102_write_reg(cam, 0x0a, 0x1b);
53
54 return err;
55}
56
57
58static int tas5110d_set_pix_format(struct sn9c102_device* cam,
59 const struct v4l2_pix_format* pix)
60{
61 int err = 0;
62
63 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
64 err += sn9c102_write_reg(cam, 0x3b, 0x19);
65 else
66 err += sn9c102_write_reg(cam, 0xfb, 0x19);
67
68 return err;
69}
70
71
72static const struct sn9c102_sensor tas5110d = {
73 .name = "TAS5110D",
74 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
75 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
76 .sysfs_ops = SN9C102_I2C_WRITE,
77 .frequency = SN9C102_I2C_100KHZ,
78 .interface = SN9C102_I2C_2WIRES,
79 .i2c_slave_id = 0x61,
80 .init = &tas5110d_init,
81 .cropcap = {
82 .bounds = {
83 .left = 0,
84 .top = 0,
85 .width = 352,
86 .height = 288,
87 },
88 .defrect = {
89 .left = 0,
90 .top = 0,
91 .width = 352,
92 .height = 288,
93 },
94 },
95 .set_crop = &tas5110d_set_crop,
96 .pix_format = {
97 .width = 352,
98 .height = 288,
99 .pixelformat = V4L2_PIX_FMT_SBGGR8,
100 .priv = 8,
101 },
102 .set_pix_format = &tas5110d_set_pix_format
103};
104
105
106int sn9c102_probe_tas5110d(struct sn9c102_device* cam)
107{
108 const struct usb_device_id tas5110d_id_table[] = {
109 { USB_DEVICE(0x0c45, 0x6007), },
110 { }
111 };
112
113 if (!sn9c102_match_id(cam, tas5110d_id_table))
114 return -ENODEV;
115
116 sn9c102_attach_sensor(cam, &tas5110d);
117
118 return 0;
119}
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
new file mode 100644
index 00000000000..a30bbc4389f
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
@@ -0,0 +1,165 @@
1/***************************************************************************
2 * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera *
3 * Controllers *
4 * *
5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23#include "sn9c102_devtable.h"
24
25
26static int tas5130d1b_init(struct sn9c102_device* cam)
27{
28 int err;
29
30 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17},
31 {0x04, 0x01}, {0x01, 0x10},
32 {0x00, 0x11}, {0x00, 0x14},
33 {0x60, 0x17}, {0x07, 0x18});
34
35 return err;
36}
37
38
39static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
40 const struct v4l2_control* ctrl)
41{
42 int err = 0;
43
44 switch (ctrl->id) {
45 case V4L2_CID_GAIN:
46 err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
47 break;
48 case V4L2_CID_EXPOSURE:
49 err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
50 break;
51 default:
52 return -EINVAL;
53 }
54
55 return err ? -EIO : 0;
56}
57
58
59static int tas5130d1b_set_crop(struct sn9c102_device* cam,
60 const struct v4l2_rect* rect)
61{
62 struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
63 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
64 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
65 int err = 0;
66
67 err += sn9c102_write_reg(cam, h_start, 0x12);
68 err += sn9c102_write_reg(cam, v_start, 0x13);
69
70 /* Do NOT change! */
71 err += sn9c102_write_reg(cam, 0x1f, 0x1a);
72 err += sn9c102_write_reg(cam, 0x1a, 0x1b);
73 err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
74
75 return err;
76}
77
78
79static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
80 const struct v4l2_pix_format* pix)
81{
82 int err = 0;
83
84 if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
85 err += sn9c102_write_reg(cam, 0x63, 0x19);
86 else
87 err += sn9c102_write_reg(cam, 0xf3, 0x19);
88
89 return err;
90}
91
92
93static const struct sn9c102_sensor tas5130d1b = {
94 .name = "TAS5130D1B",
95 .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
96 .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
97 .sysfs_ops = SN9C102_I2C_WRITE,
98 .frequency = SN9C102_I2C_100KHZ,
99 .interface = SN9C102_I2C_3WIRES,
100 .init = &tas5130d1b_init,
101 .qctrl = {
102 {
103 .id = V4L2_CID_GAIN,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "global gain",
106 .minimum = 0x00,
107 .maximum = 0xf6,
108 .step = 0x02,
109 .default_value = 0x00,
110 .flags = 0,
111 },
112 {
113 .id = V4L2_CID_EXPOSURE,
114 .type = V4L2_CTRL_TYPE_INTEGER,
115 .name = "exposure",
116 .minimum = 0x00,
117 .maximum = 0x47,
118 .step = 0x01,
119 .default_value = 0x00,
120 .flags = 0,
121 },
122 },
123 .set_ctrl = &tas5130d1b_set_ctrl,
124 .cropcap = {
125 .bounds = {
126 .left = 0,
127 .top = 0,
128 .width = 640,
129 .height = 480,
130 },
131 .defrect = {
132 .left = 0,
133 .top = 0,
134 .width = 640,
135 .height = 480,
136 },
137 },
138 .set_crop = &tas5130d1b_set_crop,
139 .pix_format = {
140 .width = 640,
141 .height = 480,
142 .pixelformat = V4L2_PIX_FMT_SBGGR8,
143 .priv = 8,
144 },
145 .set_pix_format = &tas5130d1b_set_pix_format
146};
147
148
149int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
150{
151 const struct usb_device_id tas5130d1b_id_table[] = {
152 { USB_DEVICE(0x0c45, 0x6024), },
153 { USB_DEVICE(0x0c45, 0x6025), },
154 { USB_DEVICE(0x0c45, 0x60aa), },
155 { }
156 };
157
158 /* Sensor detection is based on USB pid/vid */
159 if (!sn9c102_match_id(cam, tas5130d1b_id_table))
160 return -ENODEV;
161
162 sn9c102_attach_sensor(cam, &tas5130d1b);
163
164 return 0;
165}