Path: blob/master/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
17988 views
/*1* Support for the sensor part which is integrated (I think) into the2* st6422 stv06xx alike bridge, as its integrated there are no i2c writes3* but instead direct bridge writes.4*5* Copyright (c) 2009 Hans de Goede <[email protected]>6*7* Strongly based on qc-usb-messenger, which is:8* Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher9* Mark Cave-Ayland, Carlo E Prelz, Dick Streefland10* Copyright (c) 2002, 2003 Tuukka Toivonen11*12* This program is free software; you can redistribute it and/or modify13* it under the terms of the GNU General Public License as published by14* the Free Software Foundation; either version 2 of the License, or15* (at your option) any later version.16*17* This program is distributed in the hope that it will be useful,18* but WITHOUT ANY WARRANTY; without even the implied warranty of19* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the20* GNU General Public License for more details.21*22* You should have received a copy of the GNU General Public License23* along with this program; if not, write to the Free Software24* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA25*26*/2728#include "stv06xx_st6422.h"2930/* controls */31enum e_ctrl {32BRIGHTNESS,33CONTRAST,34GAIN,35EXPOSURE,36NCTRLS /* number of controls */37};3839/* sensor settings */40struct st6422_settings {41struct gspca_ctrl ctrls[NCTRLS];42};4344static struct v4l2_pix_format st6422_mode[] = {45/* Note we actually get 124 lines of data, of which we skip the 4st464 as they are garbage */47{48162,49120,50V4L2_PIX_FMT_SGRBG8,51V4L2_FIELD_NONE,52.sizeimage = 162 * 120,53.bytesperline = 162,54.colorspace = V4L2_COLORSPACE_SRGB,55.priv = 156},57/* Note we actually get 248 lines of data, of which we skip the 4st584 as they are garbage, and we tell the app it only gets the59first 240 of the 244 lines it actually gets, so that it ignores60the last 4. */61{62324,63240,64V4L2_PIX_FMT_SGRBG8,65V4L2_FIELD_NONE,66.sizeimage = 324 * 244,67.bytesperline = 324,68.colorspace = V4L2_COLORSPACE_SRGB,69.priv = 070},71};7273/* V4L2 controls supported by the driver */74static void st6422_set_brightness(struct gspca_dev *gspca_dev);75static void st6422_set_contrast(struct gspca_dev *gspca_dev);76static void st6422_set_gain(struct gspca_dev *gspca_dev);77static void st6422_set_exposure(struct gspca_dev *gspca_dev);7879static const struct ctrl st6422_ctrl[NCTRLS] = {80[BRIGHTNESS] = {81{82.id = V4L2_CID_BRIGHTNESS,83.type = V4L2_CTRL_TYPE_INTEGER,84.name = "Brightness",85.minimum = 0,86.maximum = 31,87.step = 1,88.default_value = 389},90.set_control = st6422_set_brightness91},92[CONTRAST] = {93{94.id = V4L2_CID_CONTRAST,95.type = V4L2_CTRL_TYPE_INTEGER,96.name = "Contrast",97.minimum = 0,98.maximum = 15,99.step = 1,100.default_value = 11101},102.set_control = st6422_set_contrast103},104[GAIN] = {105{106.id = V4L2_CID_GAIN,107.type = V4L2_CTRL_TYPE_INTEGER,108.name = "Gain",109.minimum = 0,110.maximum = 255,111.step = 1,112.default_value = 64113},114.set_control = st6422_set_gain115},116[EXPOSURE] = {117{118.id = V4L2_CID_EXPOSURE,119.type = V4L2_CTRL_TYPE_INTEGER,120.name = "Exposure",121.minimum = 0,122#define EXPOSURE_MAX 1023123.maximum = EXPOSURE_MAX,124.step = 1,125.default_value = 256126},127.set_control = st6422_set_exposure128},129};130131static int st6422_probe(struct sd *sd)132{133struct st6422_settings *sensor_settings;134135if (sd->bridge != BRIDGE_ST6422)136return -ENODEV;137138info("st6422 sensor detected");139140sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);141if (!sensor_settings)142return -ENOMEM;143144sd->gspca_dev.cam.cam_mode = st6422_mode;145sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);146sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;147sd->desc.ctrls = st6422_ctrl;148sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);149sd->sensor_priv = sensor_settings;150151return 0;152}153154static int st6422_init(struct sd *sd)155{156int err = 0, i;157158const u16 st6422_bridge_init[][2] = {159{ STV_ISO_ENABLE, 0x00 }, /* disable capture */160{ 0x1436, 0x00 },161{ 0x1432, 0x03 }, /* 0x00-0x1F brightness */162{ 0x143a, 0xf9 }, /* 0x00-0x0F contrast */163{ 0x0509, 0x38 }, /* R */164{ 0x050a, 0x38 }, /* G */165{ 0x050b, 0x38 }, /* B */166{ 0x050c, 0x2a },167{ 0x050d, 0x01 },168169170{ 0x1431, 0x00 }, /* 0x00-0x07 ??? */171{ 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */172{ 0x1438, 0x18 }, /* 640x480 */173/* 18 bayes */174/* 10 compressed? */175176{ 0x1439, 0x00 },177/* anti-noise? 0xa2 gives a perfect image */178179{ 0x143b, 0x05 },180{ 0x143c, 0x00 }, /* 0x00-0x01 - ??? */181182183/* shutter time 0x0000-0x03FF */184/* low value give good picures on moving objects (but requires much light) */185/* high value gives good picures in darkness (but tends to be overexposed) */186{ 0x143e, 0x01 },187{ 0x143d, 0x00 },188189{ 0x1442, 0xe2 },190/* write: 1x1x xxxx */191/* read: 1x1x xxxx */192/* bit 5 == button pressed and hold if 0 */193/* write 0xe2,0xea */194195/* 0x144a */196/* 0x00 init */197/* bit 7 == button has been pressed, but not handled */198199/* interrupt */200/* if(urb->iso_frame_desc[i].status == 0x80) { */201/* if(urb->iso_frame_desc[i].status == 0x88) { */202203{ 0x1500, 0xd0 },204{ 0x1500, 0xd0 },205{ 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */206207{ 0x1501, 0xaf },208/* high val-> light area gets darker */209/* low val -> light area gets lighter */210{ 0x1502, 0xc2 },211/* high val-> light area gets darker */212/* low val -> light area gets lighter */213{ 0x1503, 0x45 },214/* high val-> light area gets darker */215/* low val -> light area gets lighter */216{ 0x1505, 0x02 },217/* 2 : 324x248 80352 bytes */218/* 7 : 248x162 40176 bytes */219/* c+f: 162*124 20088 bytes */220221{ 0x150e, 0x8e },222{ 0x150f, 0x37 },223{ 0x15c0, 0x00 },224{ 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */225226227{ 0x143f, 0x01 }, /* commit settings */228229};230231for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) {232err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0],233st6422_bridge_init[i][1]);234}235236return err;237}238239static void st6422_disconnect(struct sd *sd)240{241sd->sensor = NULL;242kfree(sd->sensor_priv);243}244245static int setbrightness(struct sd *sd)246{247struct st6422_settings *sensor_settings = sd->sensor_priv;248249/* val goes from 0 -> 31 */250return stv06xx_write_bridge(sd, 0x1432,251sensor_settings->ctrls[BRIGHTNESS].val);252}253254static int setcontrast(struct sd *sd)255{256struct st6422_settings *sensor_settings = sd->sensor_priv;257258/* Val goes from 0 -> 15 */259return stv06xx_write_bridge(sd, 0x143a,260sensor_settings->ctrls[CONTRAST].val | 0xf0);261}262263static int setgain(struct sd *sd)264{265struct st6422_settings *sensor_settings = sd->sensor_priv;266u8 gain;267int err;268269gain = sensor_settings->ctrls[GAIN].val;270271/* Set red, green, blue, gain */272err = stv06xx_write_bridge(sd, 0x0509, gain);273if (err < 0)274return err;275276err = stv06xx_write_bridge(sd, 0x050a, gain);277if (err < 0)278return err;279280err = stv06xx_write_bridge(sd, 0x050b, gain);281if (err < 0)282return err;283284/* 2 mystery writes */285err = stv06xx_write_bridge(sd, 0x050c, 0x2a);286if (err < 0)287return err;288289return stv06xx_write_bridge(sd, 0x050d, 0x01);290}291292static int setexposure(struct sd *sd)293{294struct st6422_settings *sensor_settings = sd->sensor_priv;295u16 expo;296int err;297298expo = sensor_settings->ctrls[EXPOSURE].val;299err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);300if (err < 0)301return err;302303return stv06xx_write_bridge(sd, 0x143e, expo >> 8);304}305306static int st6422_start(struct sd *sd)307{308int err;309struct cam *cam = &sd->gspca_dev.cam;310311if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)312err = stv06xx_write_bridge(sd, 0x1505, 0x0f);313else314err = stv06xx_write_bridge(sd, 0x1505, 0x02);315if (err < 0)316return err;317318err = setbrightness(sd);319if (err < 0)320return err;321322err = setcontrast(sd);323if (err < 0)324return err;325326err = setexposure(sd);327if (err < 0)328return err;329330err = setgain(sd);331if (err < 0)332return err;333334/* commit settings */335err = stv06xx_write_bridge(sd, 0x143f, 0x01);336return (err < 0) ? err : 0;337}338339static int st6422_stop(struct sd *sd)340{341PDEBUG(D_STREAM, "Halting stream");342343return 0;344}345346static void st6422_set_brightness(struct gspca_dev *gspca_dev)347{348int err;349struct sd *sd = (struct sd *) gspca_dev;350351err = setbrightness(sd);352353/* commit settings */354if (err >= 0)355err = stv06xx_write_bridge(sd, 0x143f, 0x01);356357gspca_dev->usb_err = err;358}359360static void st6422_set_contrast(struct gspca_dev *gspca_dev)361{362int err;363struct sd *sd = (struct sd *) gspca_dev;364365err = setcontrast(sd);366367/* commit settings */368if (err >= 0)369err = stv06xx_write_bridge(sd, 0x143f, 0x01);370371gspca_dev->usb_err = err;372}373374static void st6422_set_gain(struct gspca_dev *gspca_dev)375{376int err;377struct sd *sd = (struct sd *) gspca_dev;378379err = setgain(sd);380381/* commit settings */382if (err >= 0)383err = stv06xx_write_bridge(sd, 0x143f, 0x01);384385gspca_dev->usb_err = err;386}387388static void st6422_set_exposure(struct gspca_dev *gspca_dev)389{390int err;391struct sd *sd = (struct sd *) gspca_dev;392393err = setexposure(sd);394395/* commit settings */396if (err >= 0)397err = stv06xx_write_bridge(sd, 0x143f, 0x01);398399gspca_dev->usb_err = err;400}401402403