diff options
Diffstat (limited to 'linux/drivers/media/video/gspca/m5602/m5602_po1030.c')
-rw-r--r-- | linux/drivers/media/video/gspca/m5602/m5602_po1030.c | 251 |
1 files changed, 238 insertions, 13 deletions
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c index 26ac61978..840a3ca53 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -26,6 +26,8 @@ static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); @@ -34,9 +36,22 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val); static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val); +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val); static struct v4l2_pix_format po1030_modes[] = { { + 320, + 240, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = 320 * 240, + .bytesperline = 320, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 + }, { 640, 480, V4L2_PIX_FMT_SBGGR8, @@ -44,7 +59,7 @@ static struct v4l2_pix_format po1030_modes[] = { .sizeimage = 640 * 480, .bytesperline = 640, .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 + .priv = 2 } }; @@ -150,7 +165,36 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_auto_white_balance, .get = po1030_get_auto_white_balance - } + }, +#define AUTO_EXPOSURE_IDX 7 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_auto_exposure, + .get = po1030_get_auto_exposure + }, +#define GREEN_BALANCE_IDX 8 + { + { + .id = M5602_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_green_balance, + .get = po1030_get_green_balance + }, }; static void po1030_dump_registers(struct sd *sd); @@ -269,25 +313,145 @@ int po1030_init(struct sd *sd) if (err < 0) return err; + err = po1030_set_green_balance(&sd->gspca_dev, + sensor_settings[GREEN_BALANCE_IDX]); + if (err < 0) + return err; + err = po1030_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); return err; } int po1030_start(struct sd *sd) { + struct cam *cam = &sd->gspca_dev.cam; int i, err = 0; - /* Synthesize the vsync/hsync setup */ - for (i = 0; i < ARRAY_SIZE(start_po1030) && !err; i++) { - if (start_po1030[i][0] == BRIDGE) - err = m5602_write_bridge(sd, start_po1030[i][1], - start_po1030[i][2]); - else if (start_po1030[i][0] == SENSOR) { - u8 data = start_po1030[i][2]; - err = m5602_write_sensor(sd, - start_po1030[i][1], &data, 1); - } + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; + int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + u8 data; + + switch (width) { + case 320: + data = PO1030_SUBSAMPLING; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 1) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 1) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 6; + width -= 1; + break; + + case 640: + data = 0; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 7) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 7) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 12; + width -= 2; + break; } + err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, + ((ver_offs >> 8) & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); return err; } @@ -475,6 +639,37 @@ static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GREEN_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read green gain %d", *val); + + return 0; +} + +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[GREEN_BALANCE_IDX] = val; + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); + + err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, + &i2c_data, 1); + if (err < 0) + return err; + + return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN, + &i2c_data, 1); +} + static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) { @@ -501,11 +696,41 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, if (err < 0) return err; + PDEBUG(D_V4L2, "Set auto white balance to %d", val); i2c_data = (i2c_data & 0xfe) | (val & 0x01); err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); return err; } +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Auto exposure is %d", *val); + return 0; +} + +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + if (err < 0) + return err; + + PDEBUG(D_V4L2, "Set auto exposure to %d", val); + i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); + return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); +} + void po1030_disconnect(struct sd *sd) { sd->sensor = NULL; |