aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@nokia.com>2007-07-18 17:04:17 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:02:53 -0400
commita5e90862114124d79e1a3f34641b00fec51d1806 (patch)
treea63cfe76e0202db00c85025b3904affb08334d04 /drivers/media
parent9b5d0f1e6dd6b4a67d0851a1c5a4bcf9b0c2f258 (diff)
V4L/DVB (5863): TCM825x: Add driver.
Add a driver for Toshiba TCM825x VGA camera sensor. This sensor is used e.g. in Nokia N800 internet tablet. This driver uses the new V4L2 internal ioctl interface. Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/Kconfig7
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/tcm825x.c942
-rw-r--r--drivers/media/video/tcm825x.h195
4 files changed, 1146 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e204e7b4028a..675c8574403e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -197,6 +197,13 @@ config VIDEO_OV7670
197 OV7670 VGA camera. It currently only works with the M88ALP01 197 OV7670 VGA camera. It currently only works with the M88ALP01
198 controller. 198 controller.
199 199
200config VIDEO_TCM825X
201 tristate "TCM825x camera sensor support"
202 depends on I2C && VIDEO_V4L2
203 ---help---
204 This is a driver for the Toshiba TCM825x VGA camera sensor.
205 It is used for example in Nokia N800.
206
200config VIDEO_SAA7110 207config VIDEO_SAA7110
201 tristate "Philips SAA7110 video decoder" 208 tristate "Philips SAA7110 video decoder"
202 depends on VIDEO_V4L1 && I2C 209 depends on VIDEO_V4L1 && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index d35306daac2f..8f7205b558f6 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -98,6 +98,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
98obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o 98obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
99obj-$(CONFIG_VIDEO_OV7670) += ov7670.o 99obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
100 100
101obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
102
101obj-$(CONFIG_USB_DABUSB) += dabusb.o 103obj-$(CONFIG_USB_DABUSB) += dabusb.o
102obj-$(CONFIG_USB_OV511) += ov511.o 104obj-$(CONFIG_USB_OV511) += ov511.o
103obj-$(CONFIG_USB_SE401) += se401.o 105obj-$(CONFIG_USB_SE401) += se401.o
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
new file mode 100644
index 000000000000..4b973b099e59
--- /dev/null
+++ b/drivers/media/video/tcm825x.c
@@ -0,0 +1,942 @@
1/*
2 * drivers/media/video/tcm825x.c
3 *
4 * TCM825X camera sensor driver.
5 *
6 * Copyright (C) 2007 Nokia Corporation.
7 *
8 * Contact: Sakari Ailus <sakari.ailus@nokia.com>
9 *
10 * Based on code from David Cohen <david.cohen@indt.org.br>
11 *
12 * This driver was based on ov9640 sensor driver from MontaVista
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * version 2 as published by the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 */
28
29#include <linux/i2c.h>
30#include <media/v4l2-int-device.h>
31
32#include "tcm825x.h"
33
34/*
35 * The sensor has two fps modes: the lower one just gives half the fps
36 * at the same xclk than the high one.
37 */
38#define MAX_FPS 30
39#define MIN_FPS 8
40#define MAX_HALF_FPS (MAX_FPS / 2)
41#define HIGH_FPS_MODE_LOWER_LIMIT 14
42#define DEFAULT_FPS MAX_HALF_FPS
43
44struct tcm825x_sensor {
45 const struct tcm825x_platform_data *platform_data;
46 struct v4l2_int_device *v4l2_int_device;
47 struct i2c_client *i2c_client;
48 struct v4l2_pix_format pix;
49 struct v4l2_fract timeperframe;
50};
51
52/* list of image formats supported by TCM825X sensor */
53const static struct v4l2_fmtdesc tcm825x_formats[] = {
54 {
55 .description = "YUYV (YUV 4:2:2), packed",
56 .pixelformat = V4L2_PIX_FMT_UYVY,
57 }, {
58 /* Note: V4L2 defines RGB565 as:
59 *
60 * Byte 0 Byte 1
61 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
62 *
63 * We interpret RGB565 as:
64 *
65 * Byte 0 Byte 1
66 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
67 */
68 .description = "RGB565, le",
69 .pixelformat = V4L2_PIX_FMT_RGB565,
70 },
71};
72
73#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
74
75/*
76 * TCM825X register configuration for all combinations of pixel format and
77 * image size
78 */
79const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
80const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
81const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
82const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
83const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
84const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
85
86const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
87const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
88
89/* Our own specific controls */
90#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
91#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
92#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
93#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
94#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
95#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
96
97/* Video controls */
98static struct vcontrol {
99 struct v4l2_queryctrl qc;
100 u16 reg;
101 u16 start_bit;
102} video_control[] = {
103 {
104 {
105 .id = V4L2_CID_GAIN,
106 .type = V4L2_CTRL_TYPE_INTEGER,
107 .name = "Gain",
108 .minimum = 0,
109 .maximum = 63,
110 .step = 1,
111 },
112 .reg = TCM825X_AG,
113 .start_bit = 0,
114 },
115 {
116 {
117 .id = V4L2_CID_RED_BALANCE,
118 .type = V4L2_CTRL_TYPE_INTEGER,
119 .name = "Red Balance",
120 .minimum = 0,
121 .maximum = 255,
122 .step = 1,
123 },
124 .reg = TCM825X_MRG,
125 .start_bit = 0,
126 },
127 {
128 {
129 .id = V4L2_CID_BLUE_BALANCE,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Blue Balance",
132 .minimum = 0,
133 .maximum = 255,
134 .step = 1,
135 },
136 .reg = TCM825X_MBG,
137 .start_bit = 0,
138 },
139 {
140 {
141 .id = V4L2_CID_AUTO_WHITE_BALANCE,
142 .type = V4L2_CTRL_TYPE_BOOLEAN,
143 .name = "Auto White Balance",
144 .minimum = 0,
145 .maximum = 1,
146 .step = 0,
147 },
148 .reg = TCM825X_AWBSW,
149 .start_bit = 7,
150 },
151 {
152 {
153 .id = V4L2_CID_EXPOSURE,
154 .type = V4L2_CTRL_TYPE_INTEGER,
155 .name = "Exposure Time",
156 .minimum = 0,
157 .maximum = 0x1fff,
158 .step = 1,
159 },
160 .reg = TCM825X_ESRSPD_U,
161 .start_bit = 0,
162 },
163 {
164 {
165 .id = V4L2_CID_HFLIP,
166 .type = V4L2_CTRL_TYPE_BOOLEAN,
167 .name = "Mirror Image",
168 .minimum = 0,
169 .maximum = 1,
170 .step = 0,
171 },
172 .reg = TCM825X_H_INV,
173 .start_bit = 6,
174 },
175 {
176 {
177 .id = V4L2_CID_VFLIP,
178 .type = V4L2_CTRL_TYPE_BOOLEAN,
179 .name = "Vertical Flip",
180 .minimum = 0,
181 .maximum = 1,
182 .step = 0,
183 },
184 .reg = TCM825X_V_INV,
185 .start_bit = 7,
186 },
187 /* Private controls */
188 {
189 {
190 .id = V4L2_CID_ALC,
191 .type = V4L2_CTRL_TYPE_BOOLEAN,
192 .name = "Auto Luminance Control",
193 .minimum = 0,
194 .maximum = 1,
195 .step = 0,
196 },
197 .reg = TCM825X_ALCSW,
198 .start_bit = 7,
199 },
200 {
201 {
202 .id = V4L2_CID_H_EDGE_EN,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "Horizontal Edge Enhancement",
205 .minimum = 0,
206 .maximum = 0xff,
207 .step = 1,
208 },
209 .reg = TCM825X_HDTG,
210 .start_bit = 0,
211 },
212 {
213 {
214 .id = V4L2_CID_V_EDGE_EN,
215 .type = V4L2_CTRL_TYPE_INTEGER,
216 .name = "Vertical Edge Enhancement",
217 .minimum = 0,
218 .maximum = 0xff,
219 .step = 1,
220 },
221 .reg = TCM825X_VDTG,
222 .start_bit = 0,
223 },
224 {
225 {
226 .id = V4L2_CID_LENS,
227 .type = V4L2_CTRL_TYPE_INTEGER,
228 .name = "Lens Shading Compensation",
229 .minimum = 0,
230 .maximum = 0x3f,
231 .step = 1,
232 },
233 .reg = TCM825X_LENS,
234 .start_bit = 0,
235 },
236 {
237 {
238 .id = V4L2_CID_MAX_EXPOSURE_TIME,
239 .type = V4L2_CTRL_TYPE_INTEGER,
240 .name = "Maximum Exposure Time",
241 .minimum = 0,
242 .maximum = 0x3,
243 .step = 1,
244 },
245 .reg = TCM825X_ESRLIM,
246 .start_bit = 5,
247 },
248};
249
250
251const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
252{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
253
254const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
255{ &yuv422, &rgb565 };
256
257/*
258 * Read a value from a register in an TCM825X sensor device. The value is
259 * returned in 'val'.
260 * Returns zero if successful, or non-zero otherwise.
261 */
262static int tcm825x_read_reg(struct i2c_client *client, int reg)
263{
264 int err;
265 struct i2c_msg msg[2];
266 u8 reg_buf, data_buf = 0;
267
268 if (!client->adapter)
269 return -ENODEV;
270
271 msg[0].addr = client->addr;
272 msg[0].flags = 0;
273 msg[0].len = 1;
274 msg[0].buf = &reg_buf;
275 msg[1].addr = client->addr;
276 msg[1].flags = I2C_M_RD;
277 msg[1].len = 1;
278 msg[1].buf = &data_buf;
279
280 reg_buf = reg;
281
282 err = i2c_transfer(client->adapter, msg, 2);
283 if (err < 0)
284 return err;
285 return data_buf;
286}
287
288/*
289 * Write a value to a register in an TCM825X sensor device.
290 * Returns zero if successful, or non-zero otherwise.
291 */
292static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
293{
294 int err;
295 struct i2c_msg msg[1];
296 unsigned char data[2];
297
298 if (!client->adapter)
299 return -ENODEV;
300
301 msg->addr = client->addr;
302 msg->flags = 0;
303 msg->len = 2;
304 msg->buf = data;
305 data[0] = reg;
306 data[1] = val;
307 err = i2c_transfer(client->adapter, msg, 1);
308 if (err >= 0)
309 return 0;
310 return err;
311}
312
313static int __tcm825x_write_reg_mask(struct i2c_client *client,
314 u8 reg, u8 val, u8 mask)
315{
316 int rc;
317
318 /* need to do read - modify - write */
319 rc = tcm825x_read_reg(client, reg);
320 if (rc < 0)
321 return rc;
322
323 rc &= (~mask); /* Clear the masked bits */
324 val &= mask; /* Enforce mask on value */
325 val |= rc;
326
327 /* write the new value to the register */
328 rc = tcm825x_write_reg(client, reg, val);
329 if (rc)
330 return rc;
331
332 return 0;
333}
334
335#define tcm825x_write_reg_mask(client, regmask, val) \
336 __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
337 TCM825X_MASK((regmask)))
338
339
340/*
341 * Initialize a list of TCM825X registers.
342 * The list of registers is terminated by the pair of values
343 * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
344 * Returns zero if successful, or non-zero otherwise.
345 */
346static int tcm825x_write_default_regs(struct i2c_client *client,
347 const struct tcm825x_reg *reglist)
348{
349 int err;
350 const struct tcm825x_reg *next = reglist;
351
352 while (!((next->reg == TCM825X_REG_TERM)
353 && (next->val == TCM825X_VAL_TERM))) {
354 err = tcm825x_write_reg(client, next->reg, next->val);
355 if (err) {
356 dev_err(&client->dev, "register writing failed\n");
357 return err;
358 }
359 next++;
360 }
361
362 return 0;
363}
364
365static struct vcontrol *find_vctrl(int id)
366{
367 int i;
368
369 if (id < V4L2_CID_BASE)
370 return NULL;
371
372 for (i = 0; i < ARRAY_SIZE(video_control); i++)
373 if (video_control[i].qc.id == id)
374 return &video_control[i];
375
376 return NULL;
377}
378
379/*
380 * Find the best match for a requested image capture size. The best match
381 * is chosen as the nearest match that has the same number or fewer pixels
382 * as the requested size, or the smallest image size if the requested size
383 * has fewer pixels than the smallest image.
384 */
385static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
386 unsigned int width,
387 unsigned int height)
388{
389 enum image_size isize;
390 unsigned long pixels = width * height;
391 struct tcm825x_sensor *sensor = s->priv;
392
393 for (isize = subQCIF; isize < VGA; isize++) {
394 if (tcm825x_sizes[isize + 1].height
395 * tcm825x_sizes[isize + 1].width > pixels) {
396 dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
397
398 return isize;
399 }
400 }
401
402 dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
403
404 return VGA;
405}
406
407/*
408 * Configure the TCM825X for current image size, pixel format, and
409 * frame period. fper is the frame period (in seconds) expressed as a
410 * fraction. Returns zero if successful, or non-zero otherwise. The
411 * actual frame period is returned in fper.
412 */
413static int tcm825x_configure(struct v4l2_int_device *s)
414{
415 struct tcm825x_sensor *sensor = s->priv;
416 struct v4l2_pix_format *pix = &sensor->pix;
417 enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
418 struct v4l2_fract *fper = &sensor->timeperframe;
419 enum pixel_format pfmt;
420 int err;
421 u32 tgt_fps;
422 u8 val;
423
424 /* common register initialization */
425 err = tcm825x_write_default_regs(
426 sensor->i2c_client, sensor->platform_data->default_regs());
427 if (err)
428 return err;
429
430 /* configure image size */
431 val = tcm825x_siz_reg[isize]->val;
432 dev_dbg(&sensor->i2c_client->dev,
433 "configuring image size %d\n", isize);
434 err = tcm825x_write_reg_mask(sensor->i2c_client,
435 tcm825x_siz_reg[isize]->reg, val);
436 if (err)
437 return err;
438
439 /* configure pixel format */
440 switch (pix->pixelformat) {
441 default:
442 case V4L2_PIX_FMT_RGB565:
443 pfmt = RGB565;
444 break;
445 case V4L2_PIX_FMT_UYVY:
446 pfmt = YUV422;
447 break;
448 }
449
450 dev_dbg(&sensor->i2c_client->dev,
451 "configuring pixel format %d\n", pfmt);
452 val = tcm825x_fmt_reg[pfmt]->val;
453
454 err = tcm825x_write_reg_mask(sensor->i2c_client,
455 tcm825x_fmt_reg[pfmt]->reg, val);
456 if (err)
457 return err;
458
459 /*
460 * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
461 * set. Frame rate will be halved from the normal.
462 */
463 tgt_fps = fper->denominator / fper->numerator;
464 if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
465 val = tcm825x_read_reg(sensor->i2c_client, 0x02);
466 val |= 0x80;
467 tcm825x_write_reg(sensor->i2c_client, 0x02, val);
468 }
469
470 return 0;
471}
472
473/*
474 * Given the image capture format in pix, the nominal frame period in
475 * timeperframe, calculate the required xclk frequency.
476 *
477 * TCM825X input frequency characteristics are:
478 * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
479 */
480#define XCLK_MIN 11900000
481#define XCLK_MAX 25000000
482
483static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk)
484{
485 struct tcm825x_sensor *sensor = s->priv;
486 struct v4l2_fract *timeperframe = &sensor->timeperframe;
487 u32 tgt_xclk; /* target xclk */
488 u32 tgt_fps; /* target frames per secound */
489
490 tgt_fps = timeperframe->denominator / timeperframe->numerator;
491
492 tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
493 (2457 * tgt_fps) / MAX_HALF_FPS :
494 (2457 * tgt_fps) / MAX_FPS;
495 tgt_xclk *= 10000;
496
497 tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX);
498 tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN);
499
500 *xclk = tgt_xclk;
501
502 return 0;
503}
504
505static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk)
506{
507 if (xclk > XCLK_MAX || xclk < XCLK_MIN)
508 return -EINVAL;
509
510 return 0;
511}
512
513static int ioctl_queryctrl(struct v4l2_int_device *s,
514 struct v4l2_queryctrl *qc)
515{
516 struct vcontrol *control;
517
518 control = find_vctrl(qc->id);
519
520 if (control == NULL)
521 return -EINVAL;
522
523 *qc = control->qc;
524
525 return 0;
526}
527
528static int ioctl_g_ctrl(struct v4l2_int_device *s,
529 struct v4l2_control *vc)
530{
531 struct tcm825x_sensor *sensor = s->priv;
532 struct i2c_client *client = sensor->i2c_client;
533 int val, r;
534 struct vcontrol *lvc;
535
536 /* exposure time is special, spread accross 2 registers */
537 if (vc->id == V4L2_CID_EXPOSURE) {
538 int val_lower, val_upper;
539
540 val_upper = tcm825x_read_reg(client,
541 TCM825X_ADDR(TCM825X_ESRSPD_U));
542 if (val_upper < 0)
543 return val_upper;
544 val_lower = tcm825x_read_reg(client,
545 TCM825X_ADDR(TCM825X_ESRSPD_L));
546 if (val_lower < 0)
547 return val_lower;
548
549 vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
550 return 0;
551 }
552
553 lvc = find_vctrl(vc->id);
554 if (lvc == NULL)
555 return -EINVAL;
556
557 r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
558 if (r < 0)
559 return r;
560 val = r & TCM825X_MASK(lvc->reg);
561 val >>= lvc->start_bit;
562
563 if (val < 0)
564 return val;
565
566 vc->value = val;
567 return 0;
568}
569
570static int ioctl_s_ctrl(struct v4l2_int_device *s,
571 struct v4l2_control *vc)
572{
573 struct tcm825x_sensor *sensor = s->priv;
574 struct i2c_client *client = sensor->i2c_client;
575 struct vcontrol *lvc;
576 int val = vc->value;
577
578 /* exposure time is special, spread accross 2 registers */
579 if (vc->id == V4L2_CID_EXPOSURE) {
580 int val_lower, val_upper;
581 val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
582 val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
583
584 if (tcm825x_write_reg_mask(client,
585 TCM825X_ESRSPD_U, val_upper))
586 return -EIO;
587
588 if (tcm825x_write_reg_mask(client,
589 TCM825X_ESRSPD_L, val_lower))
590 return -EIO;
591
592 return 0;
593 }
594
595 lvc = find_vctrl(vc->id);
596 if (lvc == NULL)
597 return -EINVAL;
598
599 val = val << lvc->start_bit;
600 if (tcm825x_write_reg_mask(client, lvc->reg, val))
601 return -EIO;
602
603 return 0;
604}
605
606static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
607 struct v4l2_fmtdesc *fmt)
608{
609 int index = fmt->index;
610
611 switch (fmt->type) {
612 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
613 if (index >= TCM825X_NUM_CAPTURE_FORMATS)
614 return -EINVAL;
615 break;
616
617 default:
618 return -EINVAL;
619 }
620
621 fmt->flags = tcm825x_formats[index].flags;
622 strlcpy(fmt->description, tcm825x_formats[index].description,
623 sizeof(fmt->description));
624 fmt->pixelformat = tcm825x_formats[index].pixelformat;
625
626 return 0;
627}
628
629static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
630 struct v4l2_format *f)
631{
632 struct tcm825x_sensor *sensor = s->priv;
633 enum image_size isize;
634 int ifmt;
635 struct v4l2_pix_format *pix = &f->fmt.pix;
636
637 isize = tcm825x_find_size(s, pix->width, pix->height);
638 dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n",
639 isize, TCM825X_NUM_CAPTURE_FORMATS);
640
641 pix->width = tcm825x_sizes[isize].width;
642 pix->height = tcm825x_sizes[isize].height;
643
644 for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
645 if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
646 break;
647
648 if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
649 ifmt = 0; /* Default = YUV 4:2:2 */
650
651 pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
652 pix->field = V4L2_FIELD_NONE;
653 pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
654 pix->sizeimage = pix->bytesperline * pix->height;
655 pix->priv = 0;
656 dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
657 pix->pixelformat);
658
659 switch (pix->pixelformat) {
660 case V4L2_PIX_FMT_UYVY:
661 default:
662 pix->colorspace = V4L2_COLORSPACE_JPEG;
663 break;
664 case V4L2_PIX_FMT_RGB565:
665 pix->colorspace = V4L2_COLORSPACE_SRGB;
666 break;
667 }
668
669 return 0;
670}
671
672static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
673 struct v4l2_format *f)
674{
675 struct tcm825x_sensor *sensor = s->priv;
676 struct v4l2_pix_format *pix = &f->fmt.pix;
677 int rval;
678
679 rval = ioctl_try_fmt_cap(s, f);
680 if (rval)
681 return rval;
682
683 rval = tcm825x_configure(s);
684
685 sensor->pix = *pix;
686
687 return rval;
688}
689
690static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
691 struct v4l2_format *f)
692{
693 struct tcm825x_sensor *sensor = s->priv;
694
695 f->fmt.pix = sensor->pix;
696
697 return 0;
698}
699
700static int ioctl_g_parm(struct v4l2_int_device *s,
701 struct v4l2_streamparm *a)
702{
703 struct tcm825x_sensor *sensor = s->priv;
704 struct v4l2_captureparm *cparm = &a->parm.capture;
705
706 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
707 return -EINVAL;
708
709 memset(a, 0, sizeof(*a));
710 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
711
712 cparm->capability = V4L2_CAP_TIMEPERFRAME;
713 cparm->timeperframe = sensor->timeperframe;
714
715 return 0;
716}
717
718static int ioctl_s_parm(struct v4l2_int_device *s,
719 struct v4l2_streamparm *a)
720{
721 struct tcm825x_sensor *sensor = s->priv;
722 struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
723 u32 tgt_fps; /* target frames per secound */
724 int rval;
725
726 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
727 return -EINVAL;
728
729 if ((timeperframe->numerator == 0)
730 || (timeperframe->denominator == 0)) {
731 timeperframe->denominator = DEFAULT_FPS;
732 timeperframe->numerator = 1;
733 }
734
735 tgt_fps = timeperframe->denominator / timeperframe->numerator;
736
737 if (tgt_fps > MAX_FPS) {
738 timeperframe->denominator = MAX_FPS;
739 timeperframe->numerator = 1;
740 } else if (tgt_fps < MIN_FPS) {
741 timeperframe->denominator = MIN_FPS;
742 timeperframe->numerator = 1;
743 }
744
745 sensor->timeperframe = *timeperframe;
746
747 rval = tcm825x_configure(s);
748
749 return rval;
750}
751
752static int ioctl_s_power(struct v4l2_int_device *s, int on)
753{
754 struct tcm825x_sensor *sensor = s->priv;
755
756 return sensor->platform_data->power_set(on);
757}
758
759static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
760{
761 struct tcm825x_sensor *sensor = s->priv;
762
763 return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
764}
765
766static int ioctl_reset(struct v4l2_int_device *s)
767{
768 return -EBUSY;
769}
770
771static int ioctl_init(struct v4l2_int_device *s)
772{
773 return tcm825x_configure(s);
774}
775
776static int ioctl_dev_exit(struct v4l2_int_device *s)
777{
778 return 0;
779}
780
781static int ioctl_dev_init(struct v4l2_int_device *s)
782{
783 struct tcm825x_sensor *sensor = s->priv;
784 int r;
785
786 r = tcm825x_read_reg(sensor->i2c_client, 0x01);
787 if (r < 0)
788 return r;
789 if (r == 0) {
790 dev_err(&sensor->i2c_client->dev, "device not detected\n");
791 return -EIO;
792 }
793 return 0;
794}
795
796#define NUM_IOCTLS 17
797
798static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = {
799 { vidioc_int_dev_init_num,
800 (v4l2_int_ioctl_func *)&ioctl_dev_init },
801 { vidioc_int_dev_exit_num,
802 (v4l2_int_ioctl_func *)&ioctl_dev_exit },
803 { vidioc_int_s_power_num,
804 (v4l2_int_ioctl_func *)&ioctl_s_power },
805 { vidioc_int_g_ext_clk_num,
806 (v4l2_int_ioctl_func *)&ioctl_g_ext_clk },
807 { vidioc_int_s_ext_clk_num,
808 (v4l2_int_ioctl_func *)&ioctl_s_ext_clk },
809 { vidioc_int_g_needs_reset_num,
810 (v4l2_int_ioctl_func *)&ioctl_g_needs_reset },
811 { vidioc_int_reset_num,
812 (v4l2_int_ioctl_func *)&ioctl_reset },
813 { vidioc_int_init_num,
814 (v4l2_int_ioctl_func *)&ioctl_init },
815 { vidioc_int_enum_fmt_cap_num,
816 (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap },
817 { vidioc_int_try_fmt_cap_num,
818 (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap },
819 { vidioc_int_g_fmt_cap_num,
820 (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap },
821 { vidioc_int_s_fmt_cap_num,
822 (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap },
823 { vidioc_int_g_parm_num,
824 (v4l2_int_ioctl_func *)&ioctl_g_parm },
825 { vidioc_int_s_parm_num,
826 (v4l2_int_ioctl_func *)&ioctl_s_parm },
827 { vidioc_int_queryctrl_num,
828 (v4l2_int_ioctl_func *)&ioctl_queryctrl },
829 { vidioc_int_g_ctrl_num,
830 (v4l2_int_ioctl_func *)&ioctl_g_ctrl },
831 { vidioc_int_s_ctrl_num,
832 (v4l2_int_ioctl_func *)&ioctl_s_ctrl },
833};
834
835static struct v4l2_int_slave tcm825x_slave = {
836 .ioctls = tcm825x_ioctl_desc,
837 .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
838};
839
840static struct tcm825x_sensor tcm825x;
841
842static struct v4l2_int_device tcm825x_int_device = {
843 .module = THIS_MODULE,
844 .name = TCM825X_NAME,
845 .priv = &tcm825x,
846 .type = v4l2_int_type_slave,
847 .u = {
848 .slave = &tcm825x_slave,
849 },
850};
851
852static int tcm825x_probe(struct i2c_client *client)
853{
854 struct tcm825x_sensor *sensor = &tcm825x;
855 int rval;
856
857 if (i2c_get_clientdata(client))
858 return -EBUSY;
859
860 sensor->platform_data = client->dev.platform_data;
861
862 if (sensor->platform_data == NULL
863 && !sensor->platform_data->is_okay())
864 return -ENODEV;
865
866 sensor->v4l2_int_device = &tcm825x_int_device;
867
868 sensor->i2c_client = client;
869 i2c_set_clientdata(client, sensor);
870
871 /* Make the default capture format QVGA RGB565 */
872 sensor->pix.width = tcm825x_sizes[QVGA].width;
873 sensor->pix.height = tcm825x_sizes[QVGA].height;
874 sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
875
876 rval = v4l2_int_device_register(sensor->v4l2_int_device);
877 if (rval)
878 i2c_set_clientdata(client, NULL);
879
880 return rval;
881}
882
883static int __exit tcm825x_remove(struct i2c_client *client)
884{
885 struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
886
887 if (!client->adapter)
888 return -ENODEV; /* our client isn't attached */
889
890 v4l2_int_device_unregister(sensor->v4l2_int_device);
891 i2c_set_clientdata(client, NULL);
892
893 return 0;
894}
895
896static struct i2c_driver tcm825x_i2c_driver = {
897 .driver = {
898 .name = TCM825X_NAME,
899 },
900 .probe = &tcm825x_probe,
901 .remove = __exit_p(&tcm825x_remove),
902};
903
904static struct tcm825x_sensor tcm825x = {
905 .timeperframe = {
906 .numerator = 1,
907 .denominator = DEFAULT_FPS,
908 },
909};
910
911static int __init tcm825x_init(void)
912{
913 int rval;
914 int i = 0;
915
916 /* Just an experiment --- don't use *_cb functions yet. */
917 tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init);
918 BUG_ON(i >= NUM_IOCTLS);
919
920 rval = i2c_add_driver(&tcm825x_i2c_driver);
921 if (rval)
922 printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
923 __FUNCTION__);
924
925 return rval;
926}
927
928static void __exit tcm825x_exit(void)
929{
930 i2c_del_driver(&tcm825x_i2c_driver);
931}
932
933/*
934 * FIXME: Menelaus isn't ready (?) at module_init stage, so use
935 * late_initcall for now.
936 */
937late_initcall(tcm825x_init);
938module_exit(tcm825x_exit);
939
940MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
941MODULE_DESCRIPTION("TCM825x camera sensor driver");
942MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
new file mode 100644
index 000000000000..d6471ec40bc5
--- /dev/null
+++ b/drivers/media/video/tcm825x.h
@@ -0,0 +1,195 @@
1/*
2 * drivers/media/video/tcm825x.h
3 *
4 * Register definitions for the TCM825X CameraChip.
5 *
6 * Author: David Cohen (david.cohen@indt.org.br)
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 *
12 * This file was based on ov9640.h from MontaVista
13 */
14
15#ifndef TCM825X_H
16#define TCM825X_H
17
18#include <linux/videodev2.h>
19
20#include <media/v4l2-int-device.h>
21
22#define TCM825X_NAME "tcm825x"
23
24#define TCM825X_MASK(x) x & 0x00ff
25#define TCM825X_ADDR(x) (x & 0xff00) >> 8
26
27/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
28#define TCM825X_I2C_ADDR 0x3d
29
30/*
31 * define register offsets for the TCM825X sensor chip
32 * OFFSET(8 bits) + MASK(8 bits)
33 * MASK bit 4 and 3 are used when the register uses more than one address
34 */
35#define TCM825X_FPS 0x0280
36#define TCM825X_ACF 0x0240
37#define TCM825X_DOUTBUF 0x020C
38#define TCM825X_DCLKP 0x0202
39#define TCM825X_ACFDET 0x0201
40#define TCM825X_DOUTSW 0x0380
41#define TCM825X_DATAHZ 0x0340
42#define TCM825X_PICSIZ 0x033c
43#define TCM825X_PICFMT 0x0302
44#define TCM825X_V_INV 0x0480
45#define TCM825X_H_INV 0x0440
46#define TCM825X_ESRLSW 0x0430
47#define TCM825X_V_LENGTH 0x040F
48#define TCM825X_ALCSW 0x0580
49#define TCM825X_ESRLIM 0x0560
50#define TCM825X_ESRSPD_U 0x051F
51#define TCM825X_ESRSPD_L 0x06FF
52#define TCM825X_AG 0x07FF
53#define TCM825X_ESRSPD2 0x06FF
54#define TCM825X_ALCMODE 0x0830
55#define TCM825X_ALCH 0x080F
56#define TCM825X_ALCL 0x09FF
57#define TCM825X_AWBSW 0x0A80
58#define TCM825X_MRG 0x0BFF
59#define TCM825X_MBG 0x0CFF
60#define TCM825X_GAMSW 0x0D80
61#define TCM825X_HDTG 0x0EFF
62#define TCM825X_VDTG 0x0FFF
63#define TCM825X_HDTCORE 0x10F0
64#define TCM825X_VDTCORE 0x100F
65#define TCM825X_CONT 0x11FF
66#define TCM825X_BRIGHT 0x12FF
67#define TCM825X_VHUE 0x137F
68#define TCM825X_UHUE 0x147F
69#define TCM825X_VGAIN 0x153F
70#define TCM825X_UGAIN 0x163F
71#define TCM825X_UVCORE 0x170F
72#define TCM825X_SATU 0x187F
73#define TCM825X_MHMODE 0x1980
74#define TCM825X_MHLPFSEL 0x1940
75#define TCM825X_YMODE 0x1930
76#define TCM825X_MIXHG 0x1907
77#define TCM825X_LENS 0x1A3F
78#define TCM825X_AGLIM 0x1BE0
79#define TCM825X_LENSRPOL 0x1B10
80#define TCM825X_LENSRGAIN 0x1B0F
81#define TCM825X_ES100S 0x1CFF
82#define TCM825X_ES120S 0x1DFF
83#define TCM825X_DMASK 0x1EC0
84#define TCM825X_CODESW 0x1E20
85#define TCM825X_CODESEL 0x1E10
86#define TCM825X_TESPIC 0x1E04
87#define TCM825X_PICSEL 0x1E03
88#define TCM825X_HNUM 0x20FF
89#define TCM825X_VOUTPH 0x287F
90#define TCM825X_ESROUT 0x327F
91#define TCM825X_ESROUT2 0x33FF
92#define TCM825X_AGOUT 0x34FF
93#define TCM825X_DGOUT 0x353F
94#define TCM825X_AGSLOW1 0x39C0
95#define TCM825X_FLLSMODE 0x3930
96#define TCM825X_FLLSLIM 0x390F
97#define TCM825X_DETSEL 0x3AF0
98#define TCM825X_ACDETNC 0x3A0F
99#define TCM825X_AGSLOW2 0x3BC0
100#define TCM825X_DG 0x3B3F
101#define TCM825X_REJHLEV 0x3CFF
102#define TCM825X_ALCLOCK 0x3D80
103#define TCM825X_FPSLNKSW 0x3D40
104#define TCM825X_ALCSPD 0x3D30
105#define TCM825X_REJH 0x3D03
106#define TCM825X_SHESRSW 0x3E80
107#define TCM825X_ESLIMSEL 0x3E40
108#define TCM825X_SHESRSPD 0x3E30
109#define TCM825X_ELSTEP 0x3E0C
110#define TCM825X_ELSTART 0x3E03
111#define TCM825X_AGMIN 0x3FFF
112#define TCM825X_PREGRG 0x423F
113#define TCM825X_PREGBG 0x433F
114#define TCM825X_PRERG 0x443F
115#define TCM825X_PREBG 0x453F
116#define TCM825X_MSKBR 0x477F
117#define TCM825X_MSKGR 0x487F
118#define TCM825X_MSKRB 0x497F
119#define TCM825X_MSKGB 0x4A7F
120#define TCM825X_MSKRG 0x4B7F
121#define TCM825X_MSKBG 0x4C7F
122#define TCM825X_HDTCSW 0x4D80
123#define TCM825X_VDTCSW 0x4D40
124#define TCM825X_DTCYL 0x4D3F
125#define TCM825X_HDTPSW 0x4E80
126#define TCM825X_VDTPSW 0x4E40
127#define TCM825X_DTCGAIN 0x4E3F
128#define TCM825X_DTLLIMSW 0x4F10
129#define TCM825X_DTLYLIM 0x4F0F
130#define TCM825X_YLCUTLMSK 0x5080
131#define TCM825X_YLCUTL 0x503F
132#define TCM825X_YLCUTHMSK 0x5180
133#define TCM825X_YLCUTH 0x513F
134#define TCM825X_UVSKNC 0x527F
135#define TCM825X_UVLJ 0x537F
136#define TCM825X_WBGMIN 0x54FF
137#define TCM825X_WBGMAX 0x55FF
138#define TCM825X_WBSPDUP 0x5603
139#define TCM825X_ALLAREA 0x5820
140#define TCM825X_WBLOCK 0x5810
141#define TCM825X_WB2SP 0x580F
142#define TCM825X_KIZUSW 0x5920
143#define TCM825X_PBRSW 0x5910
144#define TCM825X_ABCSW 0x5903
145#define TCM825X_PBDLV 0x5AFF
146#define TCM825X_PBC1LV 0x5BFF
147
148#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
149
150#define TCM825X_BYTES_PER_PIXEL 2
151
152#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
153#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
154
155/* define a structure for tcm825x register initialization values */
156struct tcm825x_reg {
157 u8 val;
158 u16 reg;
159};
160
161enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
162enum pixel_format { YUV422 = 0, RGB565 };
163#define NUM_IMAGE_SIZES 6
164#define NUM_PIXEL_FORMATS 2
165
166struct capture_size {
167 unsigned long width;
168 unsigned long height;
169};
170
171struct tcm825x_platform_data {
172 /* Is the sensor usable? Doesn't yet mean it's there, but you
173 * can try! */
174 int (*is_okay)(void);
175 /* Set power state, zero is off, non-zero is on. */
176 int (*power_set)(int power);
177 /* Default registers written after power-on or reset. */
178 const struct tcm825x_reg *(*default_regs)(void);
179 int (*needs_reset)(struct v4l2_int_device *s, void *buf,
180 struct v4l2_pix_format *fmt);
181};
182
183/* Array of image sizes supported by TCM825X. These must be ordered from
184 * smallest image size to largest.
185 */
186const static struct capture_size tcm825x_sizes[] = {
187 { 128, 96 }, /* subQCIF */
188 { 160, 120 }, /* QQVGA */
189 { 176, 144 }, /* QCIF */
190 { 320, 240 }, /* QVGA */
191 { 352, 288 }, /* CIF */
192 { 640, 480 }, /* VGA */
193};
194
195#endif /* ifndef TCM825X_H */