Commit ed922a892e535c14035210b5be328af1f49561c8

Authored by Kuninori Morimoto
Committed by Mauro Carvalho Chehab
1 parent 042d879002

V4L/DVB (10094): Add tw9910 driver

This patch adds tw9910 driver that use soc_camera framework.
It was tested on SH Migo-r board and mplayer.

 create mode 100644 drivers/media/video/tw9910.c
 create mode 100644 include/media/tw9910.h

Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

Showing 5 changed files with 990 additions and 0 deletions Side-by-side Diff

drivers/media/video/Kconfig
... ... @@ -755,6 +755,12 @@
755 755 Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
756 756 extender to switch between 8 and 10 bit datawidth modes
757 757  
  758 +config SOC_CAMERA_TW9910
  759 + tristate "tw9910 support"
  760 + depends on SOC_CAMERA && I2C
  761 + help
  762 + This is a tw9910 video driver
  763 +
758 764 config SOC_CAMERA_PLATFORM
759 765 tristate "platform camera support"
760 766 depends on SOC_CAMERA
drivers/media/video/Makefile
... ... @@ -140,6 +140,7 @@
140 140 obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
141 141 obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
142 142 obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
  143 +obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
143 144  
144 145 obj-$(CONFIG_VIDEO_AU0828) += au0828/
145 146  
drivers/media/video/tw9910.c
  1 +/*
  2 + * tw9910 Video Driver
  3 + *
  4 + * Copyright (C) 2008 Renesas Solutions Corp.
  5 + * Kuninori Morimoto <morimoto.kuninori@renesas.com>
  6 + *
  7 + * Based on ov772x driver,
  8 + *
  9 + * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
  10 + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
  11 + * Copyright (C) 2008 Magnus Damm
  12 + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
  13 + *
  14 + * This program is free software; you can redistribute it and/or modify
  15 + * it under the terms of the GNU General Public License version 2 as
  16 + * published by the Free Software Foundation.
  17 + */
  18 +
  19 +#include <linux/init.h>
  20 +#include <linux/module.h>
  21 +#include <linux/i2c.h>
  22 +#include <linux/slab.h>
  23 +#include <linux/kernel.h>
  24 +#include <linux/delay.h>
  25 +#include <linux/videodev2.h>
  26 +#include <media/v4l2-chip-ident.h>
  27 +#include <media/v4l2-common.h>
  28 +#include <media/soc_camera.h>
  29 +#include <media/tw9910.h>
  30 +
  31 +#define GET_ID(val) ((val & 0xF8) >> 3)
  32 +#define GET_ReV(val) (val & 0x07)
  33 +
  34 +/*
  35 + * register offset
  36 + */
  37 +#define ID 0x00 /* Product ID Code Register */
  38 +#define STATUS1 0x01 /* Chip Status Register I */
  39 +#define INFORM 0x02 /* Input Format */
  40 +#define OPFORM 0x03 /* Output Format Control Register */
  41 +#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */
  42 +#define OUTCTR1 0x05 /* Output Control I */
  43 +#define ACNTL1 0x06 /* Analog Control Register 1 */
  44 +#define CROP_HI 0x07 /* Cropping Register, High */
  45 +#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */
  46 +#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */
  47 +#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */
  48 +#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */
  49 +#define CNTRL1 0x0C /* Control Register I */
  50 +#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */
  51 +#define SCALE_HI 0x0E /* Scaling Register, High */
  52 +#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */
  53 +#define BRIGHT 0x10 /* BRIGHTNESS Control Register */
  54 +#define CONTRAST 0x11 /* CONTRAST Control Register */
  55 +#define SHARPNESS 0x12 /* SHARPNESS Control Register I */
  56 +#define SAT_U 0x13 /* Chroma (U) Gain Register */
  57 +#define SAT_V 0x14 /* Chroma (V) Gain Register */
  58 +#define HUE 0x15 /* Hue Control Register */
  59 +#define CORING1 0x17
  60 +#define CORING2 0x18 /* Coring and IF compensation */
  61 +#define VBICNTL 0x19 /* VBI Control Register */
  62 +#define ACNTL2 0x1A /* Analog Control 2 */
  63 +#define OUTCTR2 0x1B /* Output Control 2 */
  64 +#define SDT 0x1C /* Standard Selection */
  65 +#define SDTR 0x1D /* Standard Recognition */
  66 +#define TEST 0x1F /* Test Control Register */
  67 +#define CLMPG 0x20 /* Clamping Gain */
  68 +#define IAGC 0x21 /* Individual AGC Gain */
  69 +#define AGCGAIN 0x22 /* AGC Gain */
  70 +#define PEAKWT 0x23 /* White Peak Threshold */
  71 +#define CLMPL 0x24 /* Clamp level */
  72 +#define SYNCT 0x25 /* Sync Amplitude */
  73 +#define MISSCNT 0x26 /* Sync Miss Count Register */
  74 +#define PCLAMP 0x27 /* Clamp Position Register */
  75 +#define VCNTL1 0x28 /* Vertical Control I */
  76 +#define VCNTL2 0x29 /* Vertical Control II */
  77 +#define CKILL 0x2A /* Color Killer Level Control */
  78 +#define COMB 0x2B /* Comb Filter Control */
  79 +#define LDLY 0x2C /* Luma Delay and H Filter Control */
  80 +#define MISC1 0x2D /* Miscellaneous Control I */
  81 +#define LOOP 0x2E /* LOOP Control Register */
  82 +#define MISC2 0x2F /* Miscellaneous Control II */
  83 +#define MVSN 0x30 /* Macrovision Detection */
  84 +#define STATUS2 0x31 /* Chip STATUS II */
  85 +#define HFREF 0x32 /* H monitor */
  86 +#define CLMD 0x33 /* CLAMP MODE */
  87 +#define IDCNTL 0x34 /* ID Detection Control */
  88 +#define CLCNTL1 0x35 /* Clamp Control I */
  89 +#define ANAPLLCTL 0x4C
  90 +#define VBIMIN 0x4D
  91 +#define HSLOWCTL 0x4E
  92 +#define WSS3 0x4F
  93 +#define FILLDATA 0x50
  94 +#define SDID 0x51
  95 +#define DID 0x52
  96 +#define WSS1 0x53
  97 +#define WSS2 0x54
  98 +#define VVBI 0x55
  99 +#define LCTL6 0x56
  100 +#define LCTL7 0x57
  101 +#define LCTL8 0x58
  102 +#define LCTL9 0x59
  103 +#define LCTL10 0x5A
  104 +#define LCTL11 0x5B
  105 +#define LCTL12 0x5C
  106 +#define LCTL13 0x5D
  107 +#define LCTL14 0x5E
  108 +#define LCTL15 0x5F
  109 +#define LCTL16 0x60
  110 +#define LCTL17 0x61
  111 +#define LCTL18 0x62
  112 +#define LCTL19 0x63
  113 +#define LCTL20 0x64
  114 +#define LCTL21 0x65
  115 +#define LCTL22 0x66
  116 +#define LCTL23 0x67
  117 +#define LCTL24 0x68
  118 +#define LCTL25 0x69
  119 +#define LCTL26 0x6A
  120 +#define HSGEGIN 0x6B
  121 +#define HSEND 0x6C
  122 +#define OVSDLY 0x6D
  123 +#define OVSEND 0x6E
  124 +#define VBIDELAY 0x6F
  125 +
  126 +/*
  127 + * register detail
  128 + */
  129 +
  130 +/* INFORM */
  131 +#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */
  132 +#define FC27_FF 0x00 /* 0 : Square pixel mode. */
  133 + /* Must use 24.54MHz for 60Hz field rate */
  134 + /* source or 29.5MHz for 50Hz field rate */
  135 +#define IFSEL_S 0x10 /* 01 : S-video decoding */
  136 +#define IFSEL_C 0x00 /* 00 : Composite video decoding */
  137 + /* Y input video selection */
  138 +#define YSEL_M0 0x00 /* 00 : Mux0 selected */
  139 +#define YSEL_M1 0x04 /* 01 : Mux1 selected */
  140 +#define YSEL_M2 0x08 /* 10 : Mux2 selected */
  141 +#define YSEL_M3 0x10 /* 11 : Mux3 selected */
  142 +
  143 +/* OPFORM */
  144 +#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
  145 + /* 1 : ITU-R-656 compatible data sequence format */
  146 +#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
  147 + /* 1 : 16-bit YCrCb 4:2:2 output format.*/
  148 +#define LLCMODE 0x20 /* 1 : LLC output mode. */
  149 + /* 0 : free-run output mode */
  150 +#define AINC 0x10 /* Serial interface auto-indexing control */
  151 + /* 0 : auto-increment */
  152 + /* 1 : non-auto */
  153 +#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */
  154 + /* 0 : Vertical out ctrl by HACTIVE and DVALID */
  155 +#define OEN 0x04 /* Output Enable together with TRI_SEL. */
  156 +
  157 +/* OUTCTR1 */
  158 +#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */
  159 +#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */
  160 + /* VS pin output control */
  161 +#define VSSL_VSYNC 0x00 /* 0 : VSYNC */
  162 +#define VSSL_VACT 0x10 /* 1 : VACT */
  163 +#define VSSL_FIELD 0x20 /* 2 : FIELD */
  164 +#define VSSL_VVALID 0x30 /* 3 : VVALID */
  165 +#define VSSL_ZERO 0x70 /* 7 : 0 */
  166 +#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */
  167 +#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/
  168 + /* HS pin output control */
  169 +#define HSSL_HACT 0x00 /* 0 : HACT */
  170 +#define HSSL_HSYNC 0x01 /* 1 : HSYNC */
  171 +#define HSSL_DVALID 0x02 /* 2 : DVALID */
  172 +#define HSSL_HLOCK 0x03 /* 3 : HLOCK */
  173 +#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */
  174 +#define HSSL_ZERO 0x07 /* 7 : 0 */
  175 +
  176 +/* ACNTL1 */
  177 +#define SRESET 0x80 /* resets the device to its default state
  178 + * but all register content remain unchanged.
  179 + * This bit is self-resetting.
  180 + */
  181 +
  182 +/* VBICNTL */
  183 +/* RTSEL : control the real time signal
  184 +* output from the MPOUT pin
  185 +*/
  186 +#define RTSEL_MASK 0x07
  187 +#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
  188 +#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
  189 +#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
  190 +#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
  191 +#define RTSEL_MONO 0x04 /* 0100 = MONO */
  192 +#define RTSEL_DET50 0x05 /* 0101 = DET50 */
  193 +#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
  194 +#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */
  195 +
  196 +/*
  197 + * structure
  198 + */
  199 +
  200 +struct regval_list {
  201 + unsigned char reg_num;
  202 + unsigned char value;
  203 +};
  204 +
  205 +struct tw9910_scale_ctrl {
  206 + char *name;
  207 + unsigned short width;
  208 + unsigned short height;
  209 + u16 hscale;
  210 + u16 vscale;
  211 +};
  212 +
  213 +struct tw9910_cropping_ctrl {
  214 + u16 vdelay;
  215 + u16 vactive;
  216 + u16 hdelay;
  217 + u16 hactive;
  218 +};
  219 +
  220 +struct tw9910_hsync_ctrl {
  221 + u16 start;
  222 + u16 end;
  223 +};
  224 +
  225 +struct tw9910_priv {
  226 + struct tw9910_video_info *info;
  227 + struct i2c_client *client;
  228 + struct soc_camera_device icd;
  229 + const struct tw9910_scale_ctrl *scale;
  230 +};
  231 +
  232 +/*
  233 + * register settings
  234 + */
  235 +
  236 +#define ENDMARKER { 0xff, 0xff }
  237 +
  238 +static const struct regval_list tw9910_default_regs[] =
  239 +{
  240 + { OPFORM, 0x00 },
  241 + { OUTCTR1, VSP_LO | VSSL_VVALID | HSP_HI | HSSL_HSYNC },
  242 + ENDMARKER,
  243 +};
  244 +
  245 +static const struct soc_camera_data_format tw9910_color_fmt[] = {
  246 + {
  247 + .name = "VYUY",
  248 + .fourcc = V4L2_PIX_FMT_VYUY,
  249 + .depth = 16,
  250 + .colorspace = V4L2_COLORSPACE_SMPTE170M,
  251 + }
  252 +};
  253 +
  254 +static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
  255 + {
  256 + .name = "NTSC SQ",
  257 + .width = 640,
  258 + .height = 480,
  259 + .hscale = 0x0100,
  260 + .vscale = 0x0100,
  261 + },
  262 + {
  263 + .name = "NTSC CCIR601",
  264 + .width = 720,
  265 + .height = 480,
  266 + .hscale = 0x0100,
  267 + .vscale = 0x0100,
  268 + },
  269 + {
  270 + .name = "NTSC SQ (CIF)",
  271 + .width = 320,
  272 + .height = 240,
  273 + .hscale = 0x0200,
  274 + .vscale = 0x0200,
  275 + },
  276 + {
  277 + .name = "NTSC CCIR601 (CIF)",
  278 + .width = 360,
  279 + .height = 240,
  280 + .hscale = 0x0200,
  281 + .vscale = 0x0200,
  282 + },
  283 + {
  284 + .name = "NTSC SQ (QCIF)",
  285 + .width = 160,
  286 + .height = 120,
  287 + .hscale = 0x0400,
  288 + .vscale = 0x0400,
  289 + },
  290 + {
  291 + .name = "NTSC CCIR601 (QCIF)",
  292 + .width = 180,
  293 + .height = 120,
  294 + .hscale = 0x0400,
  295 + .vscale = 0x0400,
  296 + },
  297 +};
  298 +
  299 +static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
  300 + {
  301 + .name = "PAL SQ",
  302 + .width = 768,
  303 + .height = 576,
  304 + .hscale = 0x0100,
  305 + .vscale = 0x0100,
  306 + },
  307 + {
  308 + .name = "PAL CCIR601",
  309 + .width = 720,
  310 + .height = 576,
  311 + .hscale = 0x0100,
  312 + .vscale = 0x0100,
  313 + },
  314 + {
  315 + .name = "PAL SQ (CIF)",
  316 + .width = 384,
  317 + .height = 288,
  318 + .hscale = 0x0200,
  319 + .vscale = 0x0200,
  320 + },
  321 + {
  322 + .name = "PAL CCIR601 (CIF)",
  323 + .width = 360,
  324 + .height = 288,
  325 + .hscale = 0x0200,
  326 + .vscale = 0x0200,
  327 + },
  328 + {
  329 + .name = "PAL SQ (QCIF)",
  330 + .width = 192,
  331 + .height = 144,
  332 + .hscale = 0x0400,
  333 + .vscale = 0x0400,
  334 + },
  335 + {
  336 + .name = "PAL CCIR601 (QCIF)",
  337 + .width = 180,
  338 + .height = 144,
  339 + .hscale = 0x0400,
  340 + .vscale = 0x0400,
  341 + },
  342 +};
  343 +
  344 +static const struct tw9910_cropping_ctrl tw9910_cropping_ctrl = {
  345 + .vdelay = 0x0012,
  346 + .vactive = 0x00F0,
  347 + .hdelay = 0x0010,
  348 + .hactive = 0x02D0,
  349 +};
  350 +
  351 +static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = {
  352 + .start = 0x0260,
  353 + .end = 0x0300,
  354 +};
  355 +
  356 +/*
  357 + * general function
  358 + */
  359 +static int tw9910_set_scale(struct i2c_client *client,
  360 + const struct tw9910_scale_ctrl *scale)
  361 +{
  362 + int ret;
  363 +
  364 + ret = i2c_smbus_write_byte_data(client, SCALE_HI,
  365 + (scale->vscale & 0x0F00) >> 4 |
  366 + (scale->hscale & 0x0F00) >> 8);
  367 + if (ret < 0)
  368 + return ret;
  369 +
  370 + ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
  371 + scale->hscale & 0x00FF);
  372 + if (ret < 0)
  373 + return ret;
  374 +
  375 + ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
  376 + scale->vscale & 0x00FF);
  377 +
  378 + return ret;
  379 +}
  380 +
  381 +static int tw9910_set_cropping(struct i2c_client *client,
  382 + const struct tw9910_cropping_ctrl *cropping)
  383 +{
  384 + int ret;
  385 +
  386 + ret = i2c_smbus_write_byte_data(client, CROP_HI,
  387 + (cropping->vdelay & 0x0300) >> 2 |
  388 + (cropping->vactive & 0x0300) >> 4 |
  389 + (cropping->hdelay & 0x0300) >> 6 |
  390 + (cropping->hactive & 0x0300) >> 8);
  391 + if (ret < 0)
  392 + return ret;
  393 +
  394 + ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
  395 + cropping->vdelay & 0x00FF);
  396 + if (ret < 0)
  397 + return ret;
  398 +
  399 + ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
  400 + cropping->vactive & 0x00FF);
  401 + if (ret < 0)
  402 + return ret;
  403 +
  404 + ret = i2c_smbus_write_byte_data(client, HDELAY_LO,
  405 + cropping->hdelay & 0x00FF);
  406 + if (ret < 0)
  407 + return ret;
  408 +
  409 + ret = i2c_smbus_write_byte_data(client, HACTIVE_LO,
  410 + cropping->hactive & 0x00FF);
  411 +
  412 + return ret;
  413 +}
  414 +
  415 +static int tw9910_set_hsync(struct i2c_client *client,
  416 + const struct tw9910_hsync_ctrl *hsync)
  417 +{
  418 + int ret;
  419 +
  420 + /* bit 10 - 3 */
  421 + ret = i2c_smbus_write_byte_data(client, HSGEGIN,
  422 + (hsync->start & 0x07F8) >> 3);
  423 + if (ret < 0)
  424 + return ret;
  425 +
  426 + /* bit 10 - 3 */
  427 + ret = i2c_smbus_write_byte_data(client, HSEND,
  428 + (hsync->end & 0x07F8) >> 3);
  429 + if (ret < 0)
  430 + return ret;
  431 +
  432 + /* bit 2 - 0 */
  433 + ret = i2c_smbus_read_byte_data(client, HSLOWCTL);
  434 + if (ret < 0)
  435 + return ret;
  436 +
  437 + ret = i2c_smbus_write_byte_data(client, HSLOWCTL,
  438 + (ret & 0x88) |
  439 + (hsync->start & 0x0007) << 4 |
  440 + (hsync->end & 0x0007));
  441 +
  442 + return ret;
  443 +}
  444 +
  445 +static int tw9910_write_array(struct i2c_client *client,
  446 + const struct regval_list *vals)
  447 +{
  448 + while (vals->reg_num != 0xff) {
  449 + int ret = i2c_smbus_write_byte_data(client,
  450 + vals->reg_num,
  451 + vals->value);
  452 + if (ret < 0)
  453 + return ret;
  454 + vals++;
  455 + }
  456 + return 0;
  457 +}
  458 +
  459 +static int tw9910_mask_set(struct i2c_client *client, u8 command,
  460 + u8 mask, u8 set)
  461 +{
  462 + s32 val = i2c_smbus_read_byte_data(client, command);
  463 +
  464 + val &= ~mask;
  465 + val |= set;
  466 +
  467 + return i2c_smbus_write_byte_data(client, command, val);
  468 +}
  469 +
  470 +static void tw9910_reset(struct i2c_client *client)
  471 +{
  472 + i2c_smbus_write_byte_data(client, ACNTL1, SRESET);
  473 + msleep(1);
  474 +}
  475 +
  476 +static const struct tw9910_scale_ctrl*
  477 +tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
  478 +{
  479 + const struct tw9910_scale_ctrl *scale;
  480 + const struct tw9910_scale_ctrl *ret = NULL;
  481 + v4l2_std_id norm = icd->vdev->current_norm;
  482 + __u32 diff = 0xffffffff, tmp;
  483 + int size, i;
  484 +
  485 + if (norm & V4L2_STD_NTSC) {
  486 + scale = tw9910_ntsc_scales;
  487 + size = ARRAY_SIZE(tw9910_ntsc_scales);
  488 + } else if (norm & V4L2_STD_PAL) {
  489 + scale = tw9910_pal_scales;
  490 + size = ARRAY_SIZE(tw9910_pal_scales);
  491 + } else {
  492 + return NULL;
  493 + }
  494 +
  495 + for (i = 0; i < size; i++) {
  496 + tmp = abs(width - scale[i].width) +
  497 + abs(height - scale[i].height);
  498 + if (tmp < diff) {
  499 + diff = tmp;
  500 + ret = scale + i;
  501 + }
  502 + }
  503 +
  504 + return ret;
  505 +}
  506 +
  507 +/*
  508 + * soc_camera_ops function
  509 + */
  510 +static int tw9910_init(struct soc_camera_device *icd)
  511 +{
  512 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  513 + int ret = 0;
  514 +
  515 + if (priv->info->link.power) {
  516 + ret = priv->info->link.power(&priv->client->dev, 1);
  517 + if (ret < 0)
  518 + return ret;
  519 + }
  520 +
  521 + if (priv->info->link.reset)
  522 + ret = priv->info->link.reset(&priv->client->dev);
  523 +
  524 + return ret;
  525 +}
  526 +
  527 +static int tw9910_release(struct soc_camera_device *icd)
  528 +{
  529 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  530 + int ret = 0;
  531 +
  532 + if (priv->info->link.power)
  533 + ret = priv->info->link.power(&priv->client->dev, 0);
  534 +
  535 + return ret;
  536 +}
  537 +
  538 +static int tw9910_start_capture(struct soc_camera_device *icd)
  539 +{
  540 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  541 +
  542 + if (!priv->scale) {
  543 + dev_err(&icd->dev, "norm select error\n");
  544 + return -EPERM;
  545 + }
  546 +
  547 + dev_dbg(&icd->dev, "%s %dx%d\n",
  548 + priv->scale->name,
  549 + priv->scale->width,
  550 + priv->scale->height);
  551 +
  552 + return 0;
  553 +}
  554 +
  555 +static int tw9910_stop_capture(struct soc_camera_device *icd)
  556 +{
  557 + return 0;
  558 +}
  559 +
  560 +static int tw9910_set_bus_param(struct soc_camera_device *icd,
  561 + unsigned long flags)
  562 +{
  563 + return 0;
  564 +}
  565 +
  566 +static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
  567 +{
  568 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  569 + struct soc_camera_link *icl = priv->client->dev.platform_data;
  570 + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
  571 + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
  572 + SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
  573 +
  574 + return soc_camera_apply_sensor_flags(icl, flags);
  575 +}
  576 +
  577 +static int tw9910_get_chip_id(struct soc_camera_device *icd,
  578 + struct v4l2_chip_ident *id)
  579 +{
  580 + id->ident = V4L2_IDENT_TW9910;
  581 + id->revision = 0;
  582 +
  583 + return 0;
  584 +}
  585 +
  586 +static int tw9910_set_std(struct soc_camera_device *icd,
  587 + v4l2_std_id *a)
  588 +{
  589 + int ret = -EINVAL;
  590 +
  591 + if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL))
  592 + ret = 0;
  593 +
  594 + return ret;
  595 +}
  596 +
  597 +static int tw9910_enum_input(struct soc_camera_device *icd,
  598 + struct v4l2_input *inp)
  599 +{
  600 + inp->type = V4L2_INPUT_TYPE_TUNER;
  601 + inp->std = V4L2_STD_UNKNOWN;
  602 + strcpy(inp->name, "Video");
  603 +
  604 + return 0;
  605 +}
  606 +
  607 +#ifdef CONFIG_VIDEO_ADV_DEBUG
  608 +static int tw9910_get_register(struct soc_camera_device *icd,
  609 + struct v4l2_register *reg)
  610 +{
  611 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  612 + int ret;
  613 +
  614 + if (reg->reg > 0xff)
  615 + return -EINVAL;
  616 +
  617 + ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
  618 + if (ret < 0)
  619 + return ret;
  620 +
  621 + /* ret = int
  622 + * reg->val = __u64
  623 + */
  624 + reg->val = (__u64)ret;
  625 +
  626 + return 0;
  627 +}
  628 +
  629 +static int tw9910_set_register(struct soc_camera_device *icd,
  630 + struct v4l2_register *reg)
  631 +{
  632 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  633 +
  634 + if (reg->reg > 0xff ||
  635 + reg->val > 0xff)
  636 + return -EINVAL;
  637 +
  638 + return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
  639 +}
  640 +#endif
  641 +
  642 +static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
  643 + struct v4l2_rect *rect)
  644 +{
  645 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  646 + int ret = -EINVAL;
  647 + u8 val;
  648 +
  649 + /*
  650 + * select suitable norm
  651 + */
  652 + priv->scale = tw9910_select_norm(icd, rect->width, rect->height);
  653 + if (!priv->scale)
  654 + return ret;
  655 +
  656 + /*
  657 + * reset hardware
  658 + */
  659 + tw9910_reset(priv->client);
  660 + ret = tw9910_write_array(priv->client, tw9910_default_regs);
  661 + if (ret < 0)
  662 + return ret;
  663 + /*
  664 + * set bus width
  665 + */
  666 + val = 0x00;
  667 + if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
  668 + val = LEN;
  669 +
  670 + ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
  671 + if (ret < 0)
  672 + return ret;
  673 +
  674 + /*
  675 + * select MPOUT behavior
  676 + */
  677 + switch (priv->info->mpout) {
  678 + case TW9910_MPO_VLOSS:
  679 + val = RTSEL_VLOSS; break;
  680 + case TW9910_MPO_HLOCK:
  681 + val = RTSEL_HLOCK; break;
  682 + case TW9910_MPO_SLOCK:
  683 + val = RTSEL_SLOCK; break;
  684 + case TW9910_MPO_VLOCK:
  685 + val = RTSEL_VLOCK; break;
  686 + case TW9910_MPO_MONO:
  687 + val = RTSEL_MONO; break;
  688 + case TW9910_MPO_DET50:
  689 + val = RTSEL_DET50; break;
  690 + case TW9910_MPO_FIELD:
  691 + val = RTSEL_FIELD; break;
  692 + case TW9910_MPO_RTCO:
  693 + val = RTSEL_RTCO; break;
  694 + default:
  695 + val = 0;
  696 + }
  697 +
  698 + ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
  699 + if (ret < 0)
  700 + return ret;
  701 +
  702 + /*
  703 + * set scale
  704 + */
  705 + ret = tw9910_set_scale(priv->client, priv->scale);
  706 + if (ret < 0)
  707 + return ret;
  708 +
  709 + /*
  710 + * set cropping
  711 + */
  712 + ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
  713 + if (ret < 0)
  714 + return ret;
  715 +
  716 + /*
  717 + * set hsync
  718 + */
  719 + ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
  720 +
  721 + return ret;
  722 +}
  723 +
  724 +static int tw9910_try_fmt(struct soc_camera_device *icd,
  725 + struct v4l2_format *f)
  726 +{
  727 + struct v4l2_pix_format *pix = &f->fmt.pix;
  728 + const struct tw9910_scale_ctrl *scale;
  729 +
  730 + if (V4L2_FIELD_ANY == pix->field) {
  731 + pix->field = V4L2_FIELD_INTERLACED;
  732 + } else if (V4L2_FIELD_INTERLACED != pix->field) {
  733 + dev_err(&icd->dev, "Field type invalid.\n");
  734 + return -EINVAL;
  735 + }
  736 +
  737 + /*
  738 + * select suitable norm
  739 + */
  740 + scale = tw9910_select_norm(icd, pix->width, pix->height);
  741 + if (!scale)
  742 + return -EINVAL;
  743 +
  744 + pix->width = scale->width;
  745 + pix->height = scale->height;
  746 +
  747 + return 0;
  748 +}
  749 +
  750 +static int tw9910_video_probe(struct soc_camera_device *icd)
  751 +{
  752 + struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
  753 + s32 val;
  754 + int ret;
  755 +
  756 + /*
  757 + * We must have a parent by now. And it cannot be a wrong one.
  758 + * So this entire test is completely redundant.
  759 + */
  760 + if (!icd->dev.parent ||
  761 + to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
  762 + return -ENODEV;
  763 +
  764 + /*
  765 + * tw9910 only use 8 or 16 bit bus width
  766 + */
  767 + if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
  768 + SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
  769 + dev_err(&icd->dev, "bus width error\n");
  770 + return -ENODEV;
  771 + }
  772 +
  773 + icd->formats = tw9910_color_fmt;
  774 + icd->num_formats = ARRAY_SIZE(tw9910_color_fmt);
  775 +
  776 + /*
  777 + * check and show Product ID
  778 + */
  779 + val = i2c_smbus_read_byte_data(priv->client, ID);
  780 + if (0x0B != GET_ID(val) ||
  781 + 0x00 != GET_ReV(val)) {
  782 + dev_err(&icd->dev,
  783 + "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val));
  784 + return -ENODEV;
  785 + }
  786 +
  787 + dev_info(&icd->dev,
  788 + "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
  789 +
  790 + ret = soc_camera_video_start(icd);
  791 + if (ret < 0)
  792 + return ret;
  793 +
  794 + icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL;
  795 + icd->vdev->current_norm = V4L2_STD_NTSC;
  796 +
  797 + return ret;
  798 +}
  799 +
  800 +static void tw9910_video_remove(struct soc_camera_device *icd)
  801 +{
  802 + soc_camera_video_stop(icd);
  803 +}
  804 +
  805 +static struct soc_camera_ops tw9910_ops = {
  806 + .owner = THIS_MODULE,
  807 + .probe = tw9910_video_probe,
  808 + .remove = tw9910_video_remove,
  809 + .init = tw9910_init,
  810 + .release = tw9910_release,
  811 + .start_capture = tw9910_start_capture,
  812 + .stop_capture = tw9910_stop_capture,
  813 + .set_fmt = tw9910_set_fmt,
  814 + .try_fmt = tw9910_try_fmt,
  815 + .set_bus_param = tw9910_set_bus_param,
  816 + .query_bus_param = tw9910_query_bus_param,
  817 + .get_chip_id = tw9910_get_chip_id,
  818 + .set_std = tw9910_set_std,
  819 + .enum_input = tw9910_enum_input,
  820 +#ifdef CONFIG_VIDEO_ADV_DEBUG
  821 + .get_register = tw9910_get_register,
  822 + .set_register = tw9910_set_register,
  823 +#endif
  824 +};
  825 +
  826 +/*
  827 + * i2c_driver function
  828 + */
  829 +
  830 +static int tw9910_probe(struct i2c_client *client,
  831 + const struct i2c_device_id *did)
  832 +
  833 +{
  834 + struct tw9910_priv *priv;
  835 + struct tw9910_video_info *info;
  836 + struct soc_camera_device *icd;
  837 + const struct tw9910_scale_ctrl *scale;
  838 + int i, ret;
  839 +
  840 + info = client->dev.platform_data;
  841 + if (!info)
  842 + return -EINVAL;
  843 +
  844 + if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
  845 + I2C_FUNC_SMBUS_BYTE_DATA)) {
  846 + dev_err(&client->dev,
  847 + "I2C-Adapter doesn't support "
  848 + "I2C_FUNC_SMBUS_BYTE_DATA\n");
  849 + return -EIO;
  850 + }
  851 +
  852 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  853 + if (!priv)
  854 + return -ENOMEM;
  855 +
  856 + priv->info = info;
  857 + priv->client = client;
  858 + i2c_set_clientdata(client, priv);
  859 +
  860 + icd = &priv->icd;
  861 + icd->ops = &tw9910_ops;
  862 + icd->control = &client->dev;
  863 + icd->iface = info->link.bus_id;
  864 +
  865 + /*
  866 + * set width and height
  867 + */
  868 + icd->width_max = tw9910_ntsc_scales[0].width; /* set default */
  869 + icd->width_min = tw9910_ntsc_scales[0].width;
  870 + icd->height_max = tw9910_ntsc_scales[0].height;
  871 + icd->height_min = tw9910_ntsc_scales[0].height;
  872 +
  873 + scale = tw9910_ntsc_scales;
  874 + for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
  875 + icd->width_max = max(scale[i].width, icd->width_max);
  876 + icd->width_min = min(scale[i].width, icd->width_min);
  877 + icd->height_max = max(scale[i].height, icd->height_max);
  878 + icd->height_min = min(scale[i].height, icd->height_min);
  879 + }
  880 + scale = tw9910_pal_scales;
  881 + for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
  882 + icd->width_max = max(scale[i].width, icd->width_max);
  883 + icd->width_min = min(scale[i].width, icd->width_min);
  884 + icd->height_max = max(scale[i].height, icd->height_max);
  885 + icd->height_min = min(scale[i].height, icd->height_min);
  886 + }
  887 +
  888 + ret = soc_camera_device_register(icd);
  889 +
  890 + if (ret) {
  891 + i2c_set_clientdata(client, NULL);
  892 + kfree(priv);
  893 + }
  894 +
  895 + return ret;
  896 +}
  897 +
  898 +static int tw9910_remove(struct i2c_client *client)
  899 +{
  900 + struct tw9910_priv *priv = i2c_get_clientdata(client);
  901 +
  902 + soc_camera_device_unregister(&priv->icd);
  903 + i2c_set_clientdata(client, NULL);
  904 + kfree(priv);
  905 + return 0;
  906 +}
  907 +
  908 +static const struct i2c_device_id tw9910_id[] = {
  909 + { "tw9910", 0 },
  910 + { }
  911 +};
  912 +MODULE_DEVICE_TABLE(i2c, tw9910_id);
  913 +
  914 +static struct i2c_driver tw9910_i2c_driver = {
  915 + .driver = {
  916 + .name = "tw9910",
  917 + },
  918 + .probe = tw9910_probe,
  919 + .remove = tw9910_remove,
  920 + .id_table = tw9910_id,
  921 +};
  922 +
  923 +/*
  924 + * module function
  925 + */
  926 +static int __init tw9910_module_init(void)
  927 +{
  928 + return i2c_add_driver(&tw9910_i2c_driver);
  929 +}
  930 +
  931 +static void __exit tw9910_module_exit(void)
  932 +{
  933 + i2c_del_driver(&tw9910_i2c_driver);
  934 +}
  935 +
  936 +module_init(tw9910_module_init);
  937 +module_exit(tw9910_module_exit);
  938 +
  939 +MODULE_DESCRIPTION("SoC Camera driver for tw9910");
  940 +MODULE_AUTHOR("Kuninori Morimoto");
  941 +MODULE_LICENSE("GPL v2");
include/media/tw9910.h
  1 +/*
  2 + * tw9910 Driver header
  3 + *
  4 + * Copyright (C) 2008 Renesas Solutions Corp.
  5 + * Kuninori Morimoto <morimoto.kuninori@renesas.com>
  6 + *
  7 + * Based on ov772x.h
  8 + *
  9 + * Copyright (C) Kuninori Morimoto <morimoto.kuninori@renesas.com>
  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 version 2 as
  13 + * published by the Free Software Foundation.
  14 + */
  15 +
  16 +#ifndef __TW9910_H__
  17 +#define __TW9910_H__
  18 +
  19 +#include <media/soc_camera.h>
  20 +
  21 +enum tw9910_mpout_pin {
  22 + TW9910_MPO_VLOSS,
  23 + TW9910_MPO_HLOCK,
  24 + TW9910_MPO_SLOCK,
  25 + TW9910_MPO_VLOCK,
  26 + TW9910_MPO_MONO,
  27 + TW9910_MPO_DET50,
  28 + TW9910_MPO_FIELD,
  29 + TW9910_MPO_RTCO,
  30 +};
  31 +
  32 +struct tw9910_video_info {
  33 + unsigned long buswidth;
  34 + enum tw9910_mpout_pin mpout;
  35 + struct soc_camera_link link;
  36 +};
  37 +
  38 +
  39 +#endif /* __TW9910_H__ */
include/media/v4l2-chip-ident.h
... ... @@ -87,6 +87,9 @@
87 87 /* module wm8775: just ident 8775 */
88 88 V4L2_IDENT_WM8775 = 8775,
89 89  
  90 + /* module tw9910: just ident 9910 */
  91 + V4L2_IDENT_TW9910 = 9910,
  92 +
90 93 /* module cs53132a: just ident 53132 */
91 94 V4L2_IDENT_CS53l32A = 53132,
92 95