/* * qce-ga, linux V4L driver for the Quickcam Express and Dexxa Quickcam * * pb0100.c - PB0100 Sensor Implementation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "quickcam.h" #include "pb0100.h" static int pb0100_set_size(struct usb_device * dev, int mode) { if(mode != 0 && mode != 1) goto error; // Set screen output size if (usb_quickcam_set1(dev, STV_Y_CTRL, (mode?2:1))<0) // 1: Y-full, 2: y-half goto error; if (usb_quickcam_set1(dev, STV_X_CTRL, (mode?6:0x0a))<0) // 06/0a : Half/Full goto error; return(0); error: return(-1); } /* * initialise parameters of PB100 sensor. */ static int pb0100_init(struct usb_device *dev, int mode, int *rgain, int *bgain, int *ggain, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); if (*rgain<=0 || *rgain>255) *rgain=RGAIN_DEF; if (*bgain<=0 || *bgain>255) *bgain=BGAIN_DEF; if (*ggain<=0 || *ggain>255) *ggain=GGAIN_DEF; sensor_ctrl->mode=mode; if (mode) { sensor_ctrl->width = 176; sensor_ctrl->height = 144; } else { sensor_ctrl->width = 352; sensor_ctrl->height = 288; } if (usb_quickcam_set1(dev, STV_REG00, 1)<0) goto error; if (usb_quickcam_set1(dev, STV_SCAN_RATE, 0)<0) goto error; // Reset sensor usb_quickcam_i2c_add2(&i2cbuff, PB_RESET, 1); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; usb_quickcam_i2c_add2(&i2cbuff, PB_RESET, 0); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // Disable chip usb_quickcam_i2c_add2(&i2cbuff, PB_CONTROL, 0x28); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // Gain stuff... usb_quickcam_i2c_add2(&i2cbuff, PB_PREADCTRL, 0x1440); usb_quickcam_i2c_add2(&i2cbuff, PB_ADCMAXGAIN, 0x7F); /* gain max */ usb_quickcam_i2c_add2(&i2cbuff, PB_ADCMINGAIN, 1); /* gain min */ if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // Enable auto-exposure... usb_quickcam_i2c_add2(&i2cbuff, PB_EXPGAIN, 17); usb_quickcam_i2c_add2(&i2cbuff, PB_UPDATEINT, 1); usb_quickcam_i2c_add2(&i2cbuff, PB_VOFFSET, 0); /* 0x14 */ usb_quickcam_i2c_add2(&i2cbuff, PB_ADCGAINH, 0x38); /* 0xd */ usb_quickcam_i2c_add2(&i2cbuff, PB_ADCGAINL, 0x0); /* 0x1 */ if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // Set individual colour gains usb_quickcam_i2c_add2(&i2cbuff, PB_RGAIN, *rgain); usb_quickcam_i2c_add2(&i2cbuff, PB_G1GAIN, *ggain); usb_quickcam_i2c_add2(&i2cbuff, PB_G2GAIN, *ggain); usb_quickcam_i2c_add2(&i2cbuff, PB_BGAIN, *bgain); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // ??? if (usb_quickcam_set1(dev, STV_REG04, 0x07)<0) goto error; if (usb_quickcam_set1(dev, STV_REG03, 0x45)<0) goto error; if (usb_quickcam_set1(dev, STV_REG00, 0x11)<0) goto error; // Set screen output size if (pb0100_set_size(dev, mode) <0) goto error; // 0x27b: 635... why? - HDCS uses 847 - if (usb_quickcam_set2(dev, STV_ISO_SIZE, 847)<0) // ISO-Size goto error; // Setup sensor window usb_quickcam_i2c_add2(&i2cbuff, PB_RSTART, 0); usb_quickcam_i2c_add2(&i2cbuff, PB_CSTART, 0); usb_quickcam_i2c_add2(&i2cbuff, PB_RWSIZE, 0x11f); // 0xf7: 240 usb_quickcam_i2c_add2(&i2cbuff, PB_CWSIZE, 0x15f); // 0x13f: 320 if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; // Scan rate? if (usb_quickcam_set1(dev, STV_SCAN_RATE, (mode?0x10:0x20))<0) // larger -> slower goto error; // Scan/timing for the sensor usb_quickcam_i2c_add2(&i2cbuff, PB_ROWSPEED, 0x1a); usb_quickcam_i2c_add2(&i2cbuff, PB_CFILLIN, 0x2f); usb_quickcam_i2c_add2(&i2cbuff, PB_VBL, 0); usb_quickcam_i2c_add2(&i2cbuff, PB_FINTTIME, 0); usb_quickcam_i2c_add2(&i2cbuff, PB_RINTTIME, 0x7b); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) goto error; if (usb_quickcam_set1(dev, STV_REG01, 0xc2)<0) goto error; if (usb_quickcam_set1(dev, STV_REG02, 0xb0)<0) goto error; return(0); error: return(-1); } static int pb0100_set_shutter(struct usb_device * dev, int sval, int xval) { return(0); } static int pb0100_set_gains(struct usb_device * dev, int rgain, int bgain, int ggain) { return(0); } /* Window location and size are controlled by R1, R2, R3 and R4. * The default size is CIF (352x288) with to right at (4,12) * and bottom left at (355, 299) * * We try to ensure that the captured area is in the center of * the camera purely because that's nicer. It would be better * if the PB0100 sensor supported capture scaling! * * We do it in on step otherwise size changemay take more * than one frame (like xawtv who tests 64x48 and uses 352x288) * 3072 = 64x48, 16896 = 352x48, 101376 = 352x288. */ static int pb0100_set_window(struct usb_device *dev, int x, int y, int w, int h, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); /* PB_RSTART = 12 + y */ usb_quickcam_i2c_add2(&i2cbuff,PB_RSTART,12 + y); /* PB_CSTART = 4 + x */ usb_quickcam_i2c_add2(&i2cbuff,PB_CSTART,4 + x); /* PB_RWSIZE = h - 1 */ usb_quickcam_i2c_add2(&i2cbuff,PB_RWSIZE,h - 1); /* PB_CWSIZE = w - 1 */ usb_quickcam_i2c_add2(&i2cbuff,PB_CWSIZE, w - 1); if (sensor_ctrl->mode) { sensor_ctrl->width=w/2; sensor_ctrl->height=h/2; } else { sensor_ctrl->width=w; sensor_ctrl->height=h; } return(usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)); } /* start grabbing */ static int pb0100_start(struct usb_device * dev, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add2(&i2cbuff,PB_CONTROL, 0x2b); return(usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)); } /* stop grabbing */ static int pb0100_stop(struct usb_device * dev, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add2(&i2cbuff,PB_ABORTFRAME, 1); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) return (-3); usb_quickcam_i2c_add2(&i2cbuff,PB_CONTROL, 0x28); if (usb_quickcam_i2c_send(dev,&i2cbuff,PB_ADDR)<0) return (-2); return(0); } /* * Fill the pointers so that the routines are called from quickcam.c */ void load_pb0100_mod(struct sensorctrl *sensor_ctrl) { sensor_ctrl->init = pb0100_init; sensor_ctrl->set_shutter = pb0100_set_shutter; sensor_ctrl->set_gains = pb0100_set_gains; sensor_ctrl->set_window = pb0100_set_window; sensor_ctrl->set_size = pb0100_set_size; sensor_ctrl->start = pb0100_start; sensor_ctrl->stop = pb0100_stop; sensor_ctrl->width = 176; sensor_ctrl->height = 144; sensor_ctrl->mode = 1; }