diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2013-08-20 09:03:59 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-08-21 04:21:55 -0400 |
commit | 4ab0620bdc6fe3ca2365c014552dee64402670a4 (patch) | |
tree | e8f7c8cce83e32a07ae3a54b4e0cfc760daf7241 /drivers/media/usb/gspca/stk1135.c | |
parent | d48de1c73b41d27e3cc6e500eb9588449edb2f14 (diff) |
[media] introduce gspca-stk1135: Syntek STK1135 driver
Hello,
this is a new gspca driver for Syntek STK1135 webcams. The code is completely
new, but register values are based on Syntekdriver (stk11xx) by Nicolas VIVIEN
(http://syntekdriver.sourceforge.net).
Only one webcam type is supported now - vendor 0x174f, device 0x6a31.
It's Asus F5RL laptop flippable webcam with MT9M112.
The camera works better than in Windows - initializes much faster and
provides more resolutions (the sensor can do almost any resolution - just
add it to the stk1135_modes[] - could this feature be somehow used by
applications to avoid SW scaling?).
Autoflip works too - when the camera is flipped around, the image is flipped
automatically.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/usb/gspca/stk1135.c')
-rw-r--r-- | drivers/media/usb/gspca/stk1135.c | 685 |
1 files changed, 685 insertions, 0 deletions
diff --git a/drivers/media/usb/gspca/stk1135.c b/drivers/media/usb/gspca/stk1135.c new file mode 100644 index 000000000000..585868835ace --- /dev/null +++ b/drivers/media/usb/gspca/stk1135.c | |||
@@ -0,0 +1,685 @@ | |||
1 | /* | ||
2 | * Syntek STK1135 subdriver | ||
3 | * | ||
4 | * Copyright (c) 2013 Ondrej Zary | ||
5 | * | ||
6 | * Based on Syntekdriver (stk11xx) by Nicolas VIVIEN: | ||
7 | * http://syntekdriver.sourceforge.net | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
26 | #define MODULE_NAME "stk1135" | ||
27 | |||
28 | #include "gspca.h" | ||
29 | #include "stk1135.h" | ||
30 | |||
31 | MODULE_AUTHOR("Ondrej Zary"); | ||
32 | MODULE_DESCRIPTION("Syntek STK1135 USB Camera Driver"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | |||
36 | /* specific webcam descriptor */ | ||
37 | struct sd { | ||
38 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
39 | |||
40 | u8 pkt_seq; | ||
41 | u8 sensor_page; | ||
42 | |||
43 | bool flip_status; | ||
44 | u8 flip_debounce; | ||
45 | |||
46 | struct v4l2_ctrl *hflip; | ||
47 | struct v4l2_ctrl *vflip; | ||
48 | }; | ||
49 | |||
50 | static const struct v4l2_pix_format stk1135_modes[] = { | ||
51 | {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
52 | .bytesperline = 160, | ||
53 | .sizeimage = 160 * 120, | ||
54 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
55 | {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
56 | .bytesperline = 176, | ||
57 | .sizeimage = 176 * 144, | ||
58 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
59 | {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
60 | .bytesperline = 320, | ||
61 | .sizeimage = 320 * 240, | ||
62 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
63 | {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
64 | .bytesperline = 352, | ||
65 | .sizeimage = 352 * 288, | ||
66 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
67 | {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
68 | .bytesperline = 640, | ||
69 | .sizeimage = 640 * 480, | ||
70 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
71 | {720, 576, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
72 | .bytesperline = 720, | ||
73 | .sizeimage = 720 * 576, | ||
74 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
75 | {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
76 | .bytesperline = 800, | ||
77 | .sizeimage = 800 * 600, | ||
78 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
79 | {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
80 | .bytesperline = 1024, | ||
81 | .sizeimage = 1024 * 768, | ||
82 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
83 | {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | ||
84 | .bytesperline = 1280, | ||
85 | .sizeimage = 1280 * 1024, | ||
86 | .colorspace = V4L2_COLORSPACE_SRGB}, | ||
87 | }; | ||
88 | |||
89 | /* -- read a register -- */ | ||
90 | static u8 reg_r(struct gspca_dev *gspca_dev, u16 index) | ||
91 | { | ||
92 | struct usb_device *dev = gspca_dev->dev; | ||
93 | int ret; | ||
94 | |||
95 | if (gspca_dev->usb_err < 0) | ||
96 | return 0; | ||
97 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
98 | 0x00, | ||
99 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
100 | 0x00, | ||
101 | index, | ||
102 | gspca_dev->usb_buf, 1, | ||
103 | 500); | ||
104 | |||
105 | PDEBUG(D_USBI, "reg_r 0x%x=0x%02x", index, gspca_dev->usb_buf[0]); | ||
106 | if (ret < 0) { | ||
107 | pr_err("reg_r 0x%x err %d\n", index, ret); | ||
108 | gspca_dev->usb_err = ret; | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | return gspca_dev->usb_buf[0]; | ||
113 | } | ||
114 | |||
115 | /* -- write a register -- */ | ||
116 | static void reg_w(struct gspca_dev *gspca_dev, u16 index, u8 val) | ||
117 | { | ||
118 | int ret; | ||
119 | struct usb_device *dev = gspca_dev->dev; | ||
120 | |||
121 | if (gspca_dev->usb_err < 0) | ||
122 | return; | ||
123 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
124 | 0x01, | ||
125 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
126 | val, | ||
127 | index, | ||
128 | NULL, | ||
129 | 0, | ||
130 | 500); | ||
131 | PDEBUG(D_USBO, "reg_w 0x%x:=0x%02x", index, val); | ||
132 | if (ret < 0) { | ||
133 | pr_err("reg_w 0x%x err %d\n", index, ret); | ||
134 | gspca_dev->usb_err = ret; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static void reg_w_mask(struct gspca_dev *gspca_dev, u16 index, u8 val, u8 mask) | ||
139 | { | ||
140 | val = (reg_r(gspca_dev, index) & ~mask) | (val & mask); | ||
141 | reg_w(gspca_dev, index, val); | ||
142 | } | ||
143 | |||
144 | /* this function is called at probe time */ | ||
145 | static int sd_config(struct gspca_dev *gspca_dev, | ||
146 | const struct usb_device_id *id) | ||
147 | { | ||
148 | gspca_dev->cam.cam_mode = stk1135_modes; | ||
149 | gspca_dev->cam.nmodes = ARRAY_SIZE(stk1135_modes); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int stk1135_serial_wait_ready(struct gspca_dev *gspca_dev) | ||
154 | { | ||
155 | int i = 0; | ||
156 | u8 val; | ||
157 | |||
158 | do { | ||
159 | val = reg_r(gspca_dev, STK1135_REG_SICTL + 1); | ||
160 | if (i++ > 500) { /* maximum retry count */ | ||
161 | pr_err("serial bus timeout: status=0x%02x\n", val); | ||
162 | return -1; | ||
163 | } | ||
164 | /* repeat if BUSY or WRITE/READ not finished */ | ||
165 | } while ((val & 0x10) || !(val & 0x05)); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static u8 sensor_read_8(struct gspca_dev *gspca_dev, u8 addr) | ||
171 | { | ||
172 | reg_w(gspca_dev, STK1135_REG_SBUSR, addr); | ||
173 | /* begin read */ | ||
174 | reg_w(gspca_dev, STK1135_REG_SICTL, 0x20); | ||
175 | /* wait until finished */ | ||
176 | if (stk1135_serial_wait_ready(gspca_dev)) { | ||
177 | pr_err("Sensor read failed\n"); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | return reg_r(gspca_dev, STK1135_REG_SBUSR + 1); | ||
182 | } | ||
183 | |||
184 | static u16 sensor_read_16(struct gspca_dev *gspca_dev, u8 addr) | ||
185 | { | ||
186 | return (sensor_read_8(gspca_dev, addr) << 8) | | ||
187 | sensor_read_8(gspca_dev, 0xf1); | ||
188 | } | ||
189 | |||
190 | static void sensor_write_8(struct gspca_dev *gspca_dev, u8 addr, u8 data) | ||
191 | { | ||
192 | /* load address and data registers */ | ||
193 | reg_w(gspca_dev, STK1135_REG_SBUSW, addr); | ||
194 | reg_w(gspca_dev, STK1135_REG_SBUSW + 1, data); | ||
195 | /* begin write */ | ||
196 | reg_w(gspca_dev, STK1135_REG_SICTL, 0x01); | ||
197 | /* wait until finished */ | ||
198 | if (stk1135_serial_wait_ready(gspca_dev)) { | ||
199 | pr_err("Sensor write failed\n"); | ||
200 | return; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void sensor_write_16(struct gspca_dev *gspca_dev, u8 addr, u16 data) | ||
205 | { | ||
206 | sensor_write_8(gspca_dev, addr, data >> 8); | ||
207 | sensor_write_8(gspca_dev, 0xf1, data & 0xff); | ||
208 | } | ||
209 | |||
210 | static void sensor_set_page(struct gspca_dev *gspca_dev, u8 page) | ||
211 | { | ||
212 | struct sd *sd = (struct sd *) gspca_dev; | ||
213 | |||
214 | if (page != sd->sensor_page) { | ||
215 | sensor_write_16(gspca_dev, 0xf0, page); | ||
216 | sd->sensor_page = page; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static u16 sensor_read(struct gspca_dev *gspca_dev, u16 reg) | ||
221 | { | ||
222 | sensor_set_page(gspca_dev, reg >> 8); | ||
223 | return sensor_read_16(gspca_dev, reg & 0xff); | ||
224 | } | ||
225 | |||
226 | static void sensor_write(struct gspca_dev *gspca_dev, u16 reg, u16 val) | ||
227 | { | ||
228 | sensor_set_page(gspca_dev, reg >> 8); | ||
229 | sensor_write_16(gspca_dev, reg & 0xff, val); | ||
230 | } | ||
231 | |||
232 | static void sensor_write_mask(struct gspca_dev *gspca_dev, | ||
233 | u16 reg, u16 val, u16 mask) | ||
234 | { | ||
235 | val = (sensor_read(gspca_dev, reg) & ~mask) | (val & mask); | ||
236 | sensor_write(gspca_dev, reg, val); | ||
237 | } | ||
238 | |||
239 | struct sensor_val { | ||
240 | u16 reg; | ||
241 | u16 val; | ||
242 | }; | ||
243 | |||
244 | /* configure MT9M112 sensor */ | ||
245 | static void stk1135_configure_mt9m112(struct gspca_dev *gspca_dev) | ||
246 | { | ||
247 | static const struct sensor_val cfg[] = { | ||
248 | /* restart&reset, chip enable, reserved */ | ||
249 | { 0x00d, 0x000b }, { 0x00d, 0x0008 }, { 0x035, 0x0022 }, | ||
250 | /* mode ctl: AWB on, AE both, clip aper corr, defect corr, AE */ | ||
251 | { 0x106, 0x700e }, | ||
252 | |||
253 | { 0x2dd, 0x18e0 }, /* B-R thresholds, */ | ||
254 | |||
255 | /* AWB */ | ||
256 | { 0x21f, 0x0180 }, /* Cb and Cr limits */ | ||
257 | { 0x220, 0xc814 }, { 0x221, 0x8080 }, /* lum limits, RGB gain */ | ||
258 | { 0x222, 0xa078 }, { 0x223, 0xa078 }, /* R, B limit */ | ||
259 | { 0x224, 0x5f20 }, { 0x228, 0xea02 }, /* mtx adj lim, adv ctl */ | ||
260 | { 0x229, 0x867a }, /* wide gates */ | ||
261 | |||
262 | /* Color correction */ | ||
263 | /* imager gains base, delta, delta signs */ | ||
264 | { 0x25e, 0x594c }, { 0x25f, 0x4d51 }, { 0x260, 0x0002 }, | ||
265 | /* AWB adv ctl 2, gain offs */ | ||
266 | { 0x2ef, 0x0008 }, { 0x2f2, 0x0000 }, | ||
267 | /* base matrix signs, scale K1-5, K6-9 */ | ||
268 | { 0x202, 0x00ee }, { 0x203, 0x3923 }, { 0x204, 0x0724 }, | ||
269 | /* base matrix coef */ | ||
270 | { 0x209, 0x00cd }, { 0x20a, 0x0093 }, { 0x20b, 0x0004 },/*K1-3*/ | ||
271 | { 0x20c, 0x005c }, { 0x20d, 0x00d9 }, { 0x20e, 0x0053 },/*K4-6*/ | ||
272 | { 0x20f, 0x0008 }, { 0x210, 0x0091 }, { 0x211, 0x00cf },/*K7-9*/ | ||
273 | { 0x215, 0x0000 }, /* delta mtx signs */ | ||
274 | /* delta matrix coef */ | ||
275 | { 0x216, 0x0000 }, { 0x217, 0x0000 }, { 0x218, 0x0000 },/*D1-3*/ | ||
276 | { 0x219, 0x0000 }, { 0x21a, 0x0000 }, { 0x21b, 0x0000 },/*D4-6*/ | ||
277 | { 0x21c, 0x0000 }, { 0x21d, 0x0000 }, { 0x21e, 0x0000 },/*D7-9*/ | ||
278 | /* enable & disable manual WB to apply color corr. settings */ | ||
279 | { 0x106, 0xf00e }, { 0x106, 0x700e }, | ||
280 | |||
281 | /* Lens shading correction */ | ||
282 | { 0x180, 0x0007 }, /* control */ | ||
283 | /* vertical knee 0, 2+1, 4+3 */ | ||
284 | { 0x181, 0xde13 }, { 0x182, 0xebe2 }, { 0x183, 0x00f6 }, /* R */ | ||
285 | { 0x184, 0xe114 }, { 0x185, 0xeadd }, { 0x186, 0xfdf6 }, /* G */ | ||
286 | { 0x187, 0xe511 }, { 0x188, 0xede6 }, { 0x189, 0xfbf7 }, /* B */ | ||
287 | /* horizontal knee 0, 2+1, 4+3, 5 */ | ||
288 | { 0x18a, 0xd613 }, { 0x18b, 0xedec }, /* R .. */ | ||
289 | { 0x18c, 0xf9f2 }, { 0x18d, 0x0000 }, /* .. R */ | ||
290 | { 0x18e, 0xd815 }, { 0x18f, 0xe9ea }, /* G .. */ | ||
291 | { 0x190, 0xf9f1 }, { 0x191, 0x0002 }, /* .. G */ | ||
292 | { 0x192, 0xde10 }, { 0x193, 0xefef }, /* B .. */ | ||
293 | { 0x194, 0xfbf4 }, { 0x195, 0x0002 }, /* .. B */ | ||
294 | /* vertical knee 6+5, 8+7 */ | ||
295 | { 0x1b6, 0x0e06 }, { 0x1b7, 0x2713 }, /* R */ | ||
296 | { 0x1b8, 0x1106 }, { 0x1b9, 0x2713 }, /* G */ | ||
297 | { 0x1ba, 0x0c03 }, { 0x1bb, 0x2a0f }, /* B */ | ||
298 | /* horizontal knee 7+6, 9+8, 10 */ | ||
299 | { 0x1bc, 0x1208 }, { 0x1bd, 0x1a16 }, { 0x1be, 0x0022 }, /* R */ | ||
300 | { 0x1bf, 0x150a }, { 0x1c0, 0x1c1a }, { 0x1c1, 0x002d }, /* G */ | ||
301 | { 0x1c2, 0x1109 }, { 0x1c3, 0x1414 }, { 0x1c4, 0x002a }, /* B */ | ||
302 | { 0x106, 0x740e }, /* enable lens shading correction */ | ||
303 | |||
304 | /* Gamma correction - context A */ | ||
305 | { 0x153, 0x0b03 }, { 0x154, 0x4722 }, { 0x155, 0xac82 }, | ||
306 | { 0x156, 0xdac7 }, { 0x157, 0xf5e9 }, { 0x158, 0xff00 }, | ||
307 | /* Gamma correction - context B */ | ||
308 | { 0x1dc, 0x0b03 }, { 0x1dd, 0x4722 }, { 0x1de, 0xac82 }, | ||
309 | { 0x1df, 0xdac7 }, { 0x1e0, 0xf5e9 }, { 0x1e1, 0xff00 }, | ||
310 | |||
311 | /* output format: RGB, invert output pixclock, output bayer */ | ||
312 | { 0x13a, 0x4300 }, { 0x19b, 0x4300 }, /* for context A, B */ | ||
313 | { 0x108, 0x0180 }, /* format control - enable bayer row flip */ | ||
314 | |||
315 | { 0x22f, 0xd100 }, { 0x29c, 0xd100 }, /* AE A, B */ | ||
316 | |||
317 | /* default prg conf, prg ctl - by 0x2d2, prg advance - PA1 */ | ||
318 | { 0x2d2, 0x0000 }, { 0x2cc, 0x0004 }, { 0x2cb, 0x0001 }, | ||
319 | |||
320 | { 0x22e, 0x0c3c }, { 0x267, 0x1010 }, /* AE tgt ctl, gain lim */ | ||
321 | |||
322 | /* PLL */ | ||
323 | { 0x065, 0xa000 }, /* clk ctl - enable PLL (clear bit 14) */ | ||
324 | { 0x066, 0x2003 }, { 0x067, 0x0501 }, /* PLL M=128, N=3, P=1 */ | ||
325 | { 0x065, 0x2000 }, /* disable PLL bypass (clear bit 15) */ | ||
326 | |||
327 | { 0x005, 0x01b8 }, { 0x007, 0x00d8 }, /* horiz blanking B, A */ | ||
328 | |||
329 | /* AE line size, shutter delay limit */ | ||
330 | { 0x239, 0x06c0 }, { 0x23b, 0x040e }, /* for context A */ | ||
331 | { 0x23a, 0x06c0 }, { 0x23c, 0x0564 }, /* for context B */ | ||
332 | /* shutter width basis 60Hz, 50Hz */ | ||
333 | { 0x257, 0x0208 }, { 0x258, 0x0271 }, /* for context A */ | ||
334 | { 0x259, 0x0209 }, { 0x25a, 0x0271 }, /* for context B */ | ||
335 | |||
336 | { 0x25c, 0x120d }, { 0x25d, 0x1712 }, /* flicker 60Hz, 50Hz */ | ||
337 | { 0x264, 0x5e1c }, /* reserved */ | ||
338 | /* flicker, AE gain limits, gain zone limits */ | ||
339 | { 0x25b, 0x0003 }, { 0x236, 0x7810 }, { 0x237, 0x8304 }, | ||
340 | |||
341 | { 0x008, 0x0021 }, /* vert blanking A */ | ||
342 | }; | ||
343 | int i; | ||
344 | u16 width, height; | ||
345 | |||
346 | for (i = 0; i < ARRAY_SIZE(cfg); i++) | ||
347 | sensor_write(gspca_dev, cfg[i].reg, cfg[i].val); | ||
348 | |||
349 | /* set output size */ | ||
350 | width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width; | ||
351 | height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height; | ||
352 | if (width <= 640) { /* use context A (half readout speed by default) */ | ||
353 | sensor_write(gspca_dev, 0x1a7, width); | ||
354 | sensor_write(gspca_dev, 0x1aa, height); | ||
355 | /* set read mode context A */ | ||
356 | sensor_write(gspca_dev, 0x0c8, 0x0000); | ||
357 | /* set resize, read mode, vblank, hblank context A */ | ||
358 | sensor_write(gspca_dev, 0x2c8, 0x0000); | ||
359 | } else { /* use context B (full readout speed by default) */ | ||
360 | sensor_write(gspca_dev, 0x1a1, width); | ||
361 | sensor_write(gspca_dev, 0x1a4, height); | ||
362 | /* set read mode context B */ | ||
363 | sensor_write(gspca_dev, 0x0c8, 0x0008); | ||
364 | /* set resize, read mode, vblank, hblank context B */ | ||
365 | sensor_write(gspca_dev, 0x2c8, 0x040b); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | static void stk1135_configure_clock(struct gspca_dev *gspca_dev) | ||
370 | { | ||
371 | /* configure SCLKOUT */ | ||
372 | reg_w(gspca_dev, STK1135_REG_TMGEN, 0x12); | ||
373 | /* set 1 clock per pixel */ | ||
374 | /* and positive edge clocked pulse high when pixel counter = 0 */ | ||
375 | reg_w(gspca_dev, STK1135_REG_TCP1 + 0, 0x41); | ||
376 | reg_w(gspca_dev, STK1135_REG_TCP1 + 1, 0x00); | ||
377 | reg_w(gspca_dev, STK1135_REG_TCP1 + 2, 0x00); | ||
378 | reg_w(gspca_dev, STK1135_REG_TCP1 + 3, 0x00); | ||
379 | |||
380 | /* enable CLKOUT for sensor */ | ||
381 | reg_w(gspca_dev, STK1135_REG_SENSO + 0, 0x10); | ||
382 | /* disable STOP clock */ | ||
383 | reg_w(gspca_dev, STK1135_REG_SENSO + 1, 0x00); | ||
384 | /* set lower 8 bits of PLL feedback divider */ | ||
385 | reg_w(gspca_dev, STK1135_REG_SENSO + 3, 0x07); | ||
386 | /* set other PLL parameters */ | ||
387 | reg_w(gspca_dev, STK1135_REG_PLLFD, 0x06); | ||
388 | /* enable timing generator */ | ||
389 | reg_w(gspca_dev, STK1135_REG_TMGEN, 0x80); | ||
390 | /* enable PLL */ | ||
391 | reg_w(gspca_dev, STK1135_REG_SENSO + 2, 0x04); | ||
392 | |||
393 | /* set serial interface clock divider (30MHz/0x1f*16+2) = 60240 kHz) */ | ||
394 | reg_w(gspca_dev, STK1135_REG_SICTL + 2, 0x1f); | ||
395 | } | ||
396 | |||
397 | static void stk1135_camera_disable(struct gspca_dev *gspca_dev) | ||
398 | { | ||
399 | /* set capture end Y position to 0 */ | ||
400 | reg_w(gspca_dev, STK1135_REG_CIEPO + 2, 0x00); | ||
401 | reg_w(gspca_dev, STK1135_REG_CIEPO + 3, 0x00); | ||
402 | /* disable capture */ | ||
403 | reg_w_mask(gspca_dev, STK1135_REG_SCTRL, 0x00, 0x80); | ||
404 | |||
405 | /* enable sensor standby and diasble chip enable */ | ||
406 | sensor_write_mask(gspca_dev, 0x00d, 0x0004, 0x000c); | ||
407 | |||
408 | /* disable PLL */ | ||
409 | reg_w_mask(gspca_dev, STK1135_REG_SENSO + 2, 0x00, 0x01); | ||
410 | /* disable timing generator */ | ||
411 | reg_w(gspca_dev, STK1135_REG_TMGEN, 0x00); | ||
412 | /* enable STOP clock */ | ||
413 | reg_w(gspca_dev, STK1135_REG_SENSO + 1, 0x20); | ||
414 | /* disable CLKOUT for sensor */ | ||
415 | reg_w(gspca_dev, STK1135_REG_SENSO, 0x00); | ||
416 | |||
417 | /* disable sensor (GPIO5) and enable GPIO0,3,6 (?) - sensor standby? */ | ||
418 | reg_w(gspca_dev, STK1135_REG_GCTRL, 0x49); | ||
419 | } | ||
420 | |||
421 | /* this function is called at probe and resume time */ | ||
422 | static int sd_init(struct gspca_dev *gspca_dev) | ||
423 | { | ||
424 | u16 sensor_id; | ||
425 | char *sensor_name; | ||
426 | struct sd *sd = (struct sd *) gspca_dev; | ||
427 | |||
428 | /* set GPIO3,4,5,6 direction to output */ | ||
429 | reg_w(gspca_dev, STK1135_REG_GCTRL + 2, 0x78); | ||
430 | /* enable sensor (GPIO5) */ | ||
431 | reg_w(gspca_dev, STK1135_REG_GCTRL, (1 << 5)); | ||
432 | /* disable ROM interface */ | ||
433 | reg_w(gspca_dev, STK1135_REG_GCTRL + 3, 0x80); | ||
434 | /* enable interrupts from GPIO8 (flip sensor) and GPIO9 (???) */ | ||
435 | reg_w(gspca_dev, STK1135_REG_ICTRL + 1, 0x00); | ||
436 | reg_w(gspca_dev, STK1135_REG_ICTRL + 3, 0x03); | ||
437 | /* enable remote wakeup from GPIO9 (???) */ | ||
438 | reg_w(gspca_dev, STK1135_REG_RMCTL + 1, 0x00); | ||
439 | reg_w(gspca_dev, STK1135_REG_RMCTL + 3, 0x02); | ||
440 | |||
441 | /* reset serial interface */ | ||
442 | reg_w(gspca_dev, STK1135_REG_SICTL, 0x80); | ||
443 | reg_w(gspca_dev, STK1135_REG_SICTL, 0x00); | ||
444 | /* set sensor address */ | ||
445 | reg_w(gspca_dev, STK1135_REG_SICTL + 3, 0xba); | ||
446 | /* disable alt 2-wire serial interface */ | ||
447 | reg_w(gspca_dev, STK1135_REG_ASIC + 3, 0x00); | ||
448 | |||
449 | stk1135_configure_clock(gspca_dev); | ||
450 | |||
451 | /* read sensor ID */ | ||
452 | sd->sensor_page = 0xff; | ||
453 | sensor_id = sensor_read(gspca_dev, 0x000); | ||
454 | |||
455 | switch (sensor_id) { | ||
456 | case 0x148c: | ||
457 | sensor_name = "MT9M112"; | ||
458 | break; | ||
459 | default: | ||
460 | sensor_name = "unknown"; | ||
461 | } | ||
462 | pr_info("Detected sensor type %s (0x%x)\n", sensor_name, sensor_id); | ||
463 | |||
464 | stk1135_camera_disable(gspca_dev); | ||
465 | |||
466 | return gspca_dev->usb_err; | ||
467 | } | ||
468 | |||
469 | /* -- start the camera -- */ | ||
470 | static int sd_start(struct gspca_dev *gspca_dev) | ||
471 | { | ||
472 | struct sd *sd = (struct sd *) gspca_dev; | ||
473 | u16 width, height; | ||
474 | |||
475 | /* enable sensor (GPIO5) */ | ||
476 | reg_w(gspca_dev, STK1135_REG_GCTRL, (1 << 5)); | ||
477 | |||
478 | stk1135_configure_clock(gspca_dev); | ||
479 | |||
480 | /* set capture start position X = 0, Y = 0 */ | ||
481 | reg_w(gspca_dev, STK1135_REG_CISPO + 0, 0x00); | ||
482 | reg_w(gspca_dev, STK1135_REG_CISPO + 1, 0x00); | ||
483 | reg_w(gspca_dev, STK1135_REG_CISPO + 2, 0x00); | ||
484 | reg_w(gspca_dev, STK1135_REG_CISPO + 3, 0x00); | ||
485 | |||
486 | /* set capture end position */ | ||
487 | width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width; | ||
488 | height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height; | ||
489 | reg_w(gspca_dev, STK1135_REG_CIEPO + 0, width & 0xff); | ||
490 | reg_w(gspca_dev, STK1135_REG_CIEPO + 1, width >> 8); | ||
491 | reg_w(gspca_dev, STK1135_REG_CIEPO + 2, height & 0xff); | ||
492 | reg_w(gspca_dev, STK1135_REG_CIEPO + 3, height >> 8); | ||
493 | |||
494 | /* set 8-bit mode */ | ||
495 | reg_w(gspca_dev, STK1135_REG_SCTRL, 0x20); | ||
496 | |||
497 | stk1135_configure_mt9m112(gspca_dev); | ||
498 | |||
499 | /* enable capture */ | ||
500 | reg_w_mask(gspca_dev, STK1135_REG_SCTRL, 0x80, 0x80); | ||
501 | |||
502 | if (gspca_dev->usb_err >= 0) | ||
503 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", | ||
504 | gspca_dev->alt); | ||
505 | |||
506 | sd->pkt_seq = 0; | ||
507 | |||
508 | return gspca_dev->usb_err; | ||
509 | } | ||
510 | |||
511 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
512 | { | ||
513 | struct usb_device *dev = gspca_dev->dev; | ||
514 | |||
515 | usb_set_interface(dev, gspca_dev->iface, 0); | ||
516 | |||
517 | stk1135_camera_disable(gspca_dev); | ||
518 | |||
519 | PDEBUG(D_STREAM, "camera stopped"); | ||
520 | } | ||
521 | |||
522 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
523 | u8 *data, /* isoc packet */ | ||
524 | int len) /* iso packet length */ | ||
525 | { | ||
526 | struct sd *sd = (struct sd *) gspca_dev; | ||
527 | int skip = sizeof(struct stk1135_pkt_header); | ||
528 | bool flip; | ||
529 | enum gspca_packet_type pkt_type = INTER_PACKET; | ||
530 | struct stk1135_pkt_header *hdr = (void *)data; | ||
531 | u8 seq; | ||
532 | |||
533 | if (len < 4) { | ||
534 | PDEBUG(D_PACK, "received short packet (less than 4 bytes)"); | ||
535 | return; | ||
536 | } | ||
537 | |||
538 | /* GPIO 8 is flip sensor (1 = normal position, 0 = flipped to back) */ | ||
539 | flip = !(le16_to_cpu(hdr->gpio) & (1 << 8)); | ||
540 | /* it's a switch, needs software debounce */ | ||
541 | if (sd->flip_status != flip) | ||
542 | sd->flip_debounce++; | ||
543 | else | ||
544 | sd->flip_debounce = 0; | ||
545 | |||
546 | /* check sequence number (not present in new frame packets) */ | ||
547 | if (!(hdr->flags & STK1135_HDR_FRAME_START)) { | ||
548 | seq = hdr->seq & STK1135_HDR_SEQ_MASK; | ||
549 | if (seq != sd->pkt_seq) { | ||
550 | PDEBUG(D_PACK, "received out-of-sequence packet"); | ||
551 | /* resync sequence and discard packet */ | ||
552 | sd->pkt_seq = seq; | ||
553 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
554 | return; | ||
555 | } | ||
556 | } | ||
557 | sd->pkt_seq++; | ||
558 | if (sd->pkt_seq > STK1135_HDR_SEQ_MASK) | ||
559 | sd->pkt_seq = 0; | ||
560 | |||
561 | if (len == sizeof(struct stk1135_pkt_header)) | ||
562 | return; | ||
563 | |||
564 | if (hdr->flags & STK1135_HDR_FRAME_START) { /* new frame */ | ||
565 | skip = 8; /* the header is longer */ | ||
566 | gspca_frame_add(gspca_dev, LAST_PACKET, data, 0); | ||
567 | pkt_type = FIRST_PACKET; | ||
568 | } | ||
569 | gspca_frame_add(gspca_dev, pkt_type, data + skip, len - skip); | ||
570 | } | ||
571 | |||
572 | static void sethflip(struct gspca_dev *gspca_dev, s32 val) | ||
573 | { | ||
574 | struct sd *sd = (struct sd *) gspca_dev; | ||
575 | |||
576 | if (sd->flip_status) | ||
577 | val = !val; | ||
578 | sensor_write_mask(gspca_dev, 0x020, val ? 0x0002 : 0x0000 , 0x0002); | ||
579 | } | ||
580 | |||
581 | static void setvflip(struct gspca_dev *gspca_dev, s32 val) | ||
582 | { | ||
583 | struct sd *sd = (struct sd *) gspca_dev; | ||
584 | |||
585 | if (sd->flip_status) | ||
586 | val = !val; | ||
587 | sensor_write_mask(gspca_dev, 0x020, val ? 0x0001 : 0x0000 , 0x0001); | ||
588 | } | ||
589 | |||
590 | static void stk1135_dq_callback(struct gspca_dev *gspca_dev) | ||
591 | { | ||
592 | struct sd *sd = (struct sd *) gspca_dev; | ||
593 | |||
594 | if (sd->flip_debounce > 100) { | ||
595 | sd->flip_status = !sd->flip_status; | ||
596 | sethflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip)); | ||
597 | setvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->vflip)); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) | ||
602 | { | ||
603 | struct gspca_dev *gspca_dev = | ||
604 | container_of(ctrl->handler, struct gspca_dev, ctrl_handler); | ||
605 | |||
606 | gspca_dev->usb_err = 0; | ||
607 | |||
608 | if (!gspca_dev->streaming) | ||
609 | return 0; | ||
610 | |||
611 | switch (ctrl->id) { | ||
612 | case V4L2_CID_HFLIP: | ||
613 | sethflip(gspca_dev, ctrl->val); | ||
614 | break; | ||
615 | case V4L2_CID_VFLIP: | ||
616 | setvflip(gspca_dev, ctrl->val); | ||
617 | break; | ||
618 | } | ||
619 | |||
620 | return gspca_dev->usb_err; | ||
621 | } | ||
622 | |||
623 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { | ||
624 | .s_ctrl = sd_s_ctrl, | ||
625 | }; | ||
626 | |||
627 | static int sd_init_controls(struct gspca_dev *gspca_dev) | ||
628 | { | ||
629 | struct sd *sd = (struct sd *) gspca_dev; | ||
630 | struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; | ||
631 | |||
632 | gspca_dev->vdev.ctrl_handler = hdl; | ||
633 | v4l2_ctrl_handler_init(hdl, 2); | ||
634 | sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
635 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
636 | sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
637 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
638 | |||
639 | if (hdl->error) { | ||
640 | pr_err("Could not initialize controls\n"); | ||
641 | return hdl->error; | ||
642 | } | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | /* sub-driver description */ | ||
647 | static const struct sd_desc sd_desc = { | ||
648 | .name = MODULE_NAME, | ||
649 | .config = sd_config, | ||
650 | .init = sd_init, | ||
651 | .init_controls = sd_init_controls, | ||
652 | .start = sd_start, | ||
653 | .stopN = sd_stopN, | ||
654 | .pkt_scan = sd_pkt_scan, | ||
655 | .dq_callback = stk1135_dq_callback, | ||
656 | }; | ||
657 | |||
658 | /* -- module initialisation -- */ | ||
659 | static const struct usb_device_id device_table[] = { | ||
660 | {USB_DEVICE(0x174f, 0x6a31)}, /* ASUS laptop, MT9M112 sensor */ | ||
661 | {} | ||
662 | }; | ||
663 | MODULE_DEVICE_TABLE(usb, device_table); | ||
664 | |||
665 | /* -- device connect -- */ | ||
666 | static int sd_probe(struct usb_interface *intf, | ||
667 | const struct usb_device_id *id) | ||
668 | { | ||
669 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
670 | THIS_MODULE); | ||
671 | } | ||
672 | |||
673 | static struct usb_driver sd_driver = { | ||
674 | .name = MODULE_NAME, | ||
675 | .id_table = device_table, | ||
676 | .probe = sd_probe, | ||
677 | .disconnect = gspca_disconnect, | ||
678 | #ifdef CONFIG_PM | ||
679 | .suspend = gspca_suspend, | ||
680 | .resume = gspca_resume, | ||
681 | .reset_resume = gspca_resume, | ||
682 | #endif | ||
683 | }; | ||
684 | |||
685 | module_usb_driver(sd_driver); | ||