m5602_ov7660.c revision 36e64d5cec0a210d87e8e8c02566a1cbe24c00f3
14763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén/* 24763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Driver for the ov7660 sensor 34763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * 44763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2009 Erik Andrén 54763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 64763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 74763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * 84763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Portions of code to USB interface and ALi driver software, 94763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * Copyright (c) 2006 Willem Duinker 104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * v4l2 interface modeled after the V4L2 driver 114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * for SN9C10x PC Camera Controllers 124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * 134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * This program is free software; you can redistribute it and/or 144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * modify it under the terms of the GNU General Public License as 154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * published by the Free Software Foundation, version 2. 164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén * 174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén */ 184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén#include "m5602_ov7660.h" 204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 21c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); 22c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); 23cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val); 24cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val); 2568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_get_red_gain(struct gspca_dev *gspca_dev, __s32 *val); 2668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_set_red_gain(struct gspca_dev *gspca_dev, __s32 val); 27f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, 28f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 *val); 29f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, 30f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 val); 31f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 32c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 33c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénconst static struct ctrl ov7660_ctrls[] = { 34c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén#define GAIN_IDX 1 35c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén { 36c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén { 37c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .id = V4L2_CID_GAIN, 38c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 39c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .name = "gain", 40c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .minimum = 0x00, 41c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .maximum = 0xff, 42c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .step = 0x1, 4372b79747a88f1ffcb6689cedacc01235bb545cd6Erik Andrén .default_value = OV7660_DEFAULT_GAIN, 44c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 45c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén }, 46c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .set = ov7660_set_gain, 47c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .get = ov7660_get_gain 48c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén }, 49cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén#define BLUE_BALANCE_IDX 2 50cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén { 51cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén { 52cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .id = V4L2_CID_BLUE_BALANCE, 53cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 54cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .name = "blue balance", 55cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .minimum = 0x00, 56cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .maximum = 0x7f, 57cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .step = 0x1, 58cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .default_value = OV7660_DEFAULT_BLUE_GAIN, 59cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 60cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén }, 61cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .set = ov7660_set_blue_gain, 62cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .get = ov7660_get_blue_gain 63cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén }, 6468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén#define RED_BALANCE_IDX 3 6568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén { 6668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén { 6768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .id = V4L2_CID_RED_BALANCE, 6868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 6968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .name = "red balance", 7068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .minimum = 0x00, 7168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .maximum = 0x7f, 7268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .step = 0x1, 7368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .default_value = OV7660_DEFAULT_RED_GAIN, 7468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 7568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén }, 7668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .set = ov7660_set_red_gain, 7768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .get = ov7660_get_red_gain 7868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén }, 79f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén#define AUTO_WHITE_BALANCE_IDX 4 80f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén { 81f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén { 82f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .id = V4L2_CID_AUTO_WHITE_BALANCE, 83f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .type = V4L2_CTRL_TYPE_BOOLEAN, 84f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .name = "auto white balance", 85f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .minimum = 0, 86f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .maximum = 1, 87f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .step = 1, 88f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .default_value = 1 89f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén }, 90f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .set = ov7660_set_auto_white_balance, 91f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .get = ov7660_get_auto_white_balance 92f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén }, 93f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 94c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}; 954763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 964763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic struct v4l2_pix_format ov7660_modes[] = { 974763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén { 984763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 640, 994763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 480, 1004763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén V4L2_PIX_FMT_SBGGR8, 1014763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén V4L2_FIELD_NONE, 1024763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .sizeimage = 1034763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 640 * 480, 1044763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .bytesperline = 640, 1054763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .colorspace = V4L2_COLORSPACE_SRGB, 1064763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .priv = 0 1074763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 1084763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}; 1094763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd); 1114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_probe(struct sd *sd) 1134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 114ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén int err = 0, i; 115ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén u8 prod_id = 0, ver_id = 0; 116ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 117ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén s32 *sensor_settings; 118ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 119ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (force_sensor) { 120ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (force_sensor == OV7660_SENSOR) { 121ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Forcing an %s sensor", ov7660.name); 122ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén goto sensor_found; 123ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 124ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén /* If we want to force another sensor, 125ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén don't try to probe this one */ 126ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 127ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 128ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 129ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén /* Do the preinit */ 130ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { 131ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén u8 data[2]; 132ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 133ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (preinit_ov7660[i][0] == BRIDGE) { 134ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén err = m5602_write_bridge(sd, 135ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][1], 136ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][2]); 137ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } else { 138ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén data[0] = preinit_ov7660[i][2]; 139ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén err = m5602_write_sensor(sd, 140ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][1], data, 1); 141ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 142ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 143ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (err < 0) 144ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return err; 145ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 146ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) 147ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 148ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 149ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) 150ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 151ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 152ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Sensor reported 0x%x%x", prod_id, ver_id); 153ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 154ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if ((prod_id == 0x76) && (ver_id == 0x60)) { 155ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Detected a ov7660 sensor"); 156ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén goto sensor_found; 157ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 1584763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return -ENODEV; 159ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 160ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrénsensor_found: 161c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sensor_settings = kmalloc( 162c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); 163c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén if (!sensor_settings) 164c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return -ENOMEM; 165c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 166ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->gspca_dev.cam.cam_mode = ov7660_modes; 167ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); 168ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->desc->ctrls = ov7660_ctrls; 169ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); 170ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 171ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) 172ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; 173ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->sensor_priv = sensor_settings; 174ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 175ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return 0; 1764763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 1774763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1784763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_init(struct sd *sd) 1794763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 1800364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén int i, err = 0; 181c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 1820364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 1830364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén /* Init the sensor */ 1840364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { 1850364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén u8 data[2]; 1860364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 1870364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén if (init_ov7660[i][0] == BRIDGE) { 1880364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén err = m5602_write_bridge(sd, 1890364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][1], 1900364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][2]); 1910364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } else { 1920364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén data[0] = init_ov7660[i][2]; 1930364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén err = m5602_write_sensor(sd, 1940364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][1], data, 1); 1950364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } 1960364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } 1970364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 1980364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén if (dump_sensor) 1990364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén ov7660_dump_registers(sd); 2000364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 201c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); 202c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén if (err < 0) 203c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return err; 204c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 205f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = ov7660_set_auto_white_balance(&sd->gspca_dev, 206f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén sensor_settings[AUTO_WHITE_BALANCE_IDX]); 20736e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén if (err < 0) 20836e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén return err; 20936e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén 21036e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén err = ov7660_set_blue_gain(&sd->gspca_dev, 21136e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén sensor_settings[BLUE_BALANCE_IDX]); 21236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén if (err < 0) 21336e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén return err; 21436e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén 21536e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén err = ov7660_set_red_gain(&sd->gspca_dev, 21636e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén sensor_settings[RED_BALANCE_IDX]); 217f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 2180364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén return err; 2194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 2214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_start(struct sd *sd) 2224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 2234763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return 0; 2244763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2254763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 2264763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_stop(struct sd *sd) 2274763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 2284763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return 0; 2294763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2304763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 231c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénvoid ov7660_disconnect(struct sd *sd) 232c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 233c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén ov7660_stop(sd); 234c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 235c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sd->sensor = NULL; 236c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén kfree(sd->sensor_priv); 237c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 238c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 239c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 240c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 241c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén struct sd *sd = (struct sd *) gspca_dev; 242c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 243c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 244c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén *val = sensor_settings[GAIN_IDX]; 245c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén PDEBUG(D_V4L2, "Read gain %d", *val); 246c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return 0; 247c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 248c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 249c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) 250c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 251c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén int err; 252c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén u8 i2c_data; 253c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén struct sd *sd = (struct sd *) gspca_dev; 254c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 255c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 256c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén PDEBUG(D_V4L2, "Setting gain to %d", val); 257c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 258c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sensor_settings[GAIN_IDX] = val; 259c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 260c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); 261c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return err; 262c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 2634763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 264cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val) 265cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{ 266cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 267cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén s32 *sensor_settings = sd->sensor_priv; 268cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 269cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén *val = sensor_settings[BLUE_BALANCE_IDX]; 270cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén PDEBUG(D_V4L2, "Read blue balance %d", *val); 271cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén return 0; 272cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén} 273cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 274cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val) 275cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{ 276cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén int err; 277cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén u8 i2c_data; 278cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 279cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén s32 *sensor_settings = sd->sensor_priv; 280cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 281cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén PDEBUG(D_V4L2, "Setting blue balance to %d", val); 282cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 283cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén sensor_settings[BLUE_BALANCE_IDX] = val; 284cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 285cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén err = m5602_write_sensor(sd, OV7660_BLUE_GAIN, &i2c_data, 1); 286cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén return err; 287cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén} 288cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 28968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_get_red_gain(struct gspca_dev *gspca_dev, __s32 *val) 29068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{ 29168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 29268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén s32 *sensor_settings = sd->sensor_priv; 29368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 29468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén *val = sensor_settings[RED_BALANCE_IDX]; 29568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén PDEBUG(D_V4L2, "Read red balance %d", *val); 29668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén return 0; 29768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén} 29868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 29968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_set_red_gain(struct gspca_dev *gspca_dev, __s32 val) 30068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{ 30168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén int err; 30268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén u8 i2c_data; 30368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 30468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén s32 *sensor_settings = sd->sensor_priv; 30568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 30668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén PDEBUG(D_V4L2, "Setting red balance to %d", val); 30768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 30868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén sensor_settings[RED_BALANCE_IDX] = val; 30968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 31068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén err = m5602_write_sensor(sd, OV7660_RED_GAIN, &i2c_data, 1); 31168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén return err; 31268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén} 31368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 314f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, 315f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 *val) 316f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{ 317f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén struct sd *sd = (struct sd *) gspca_dev; 318f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén s32 *sensor_settings = sd->sensor_priv; 319f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 320f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; 321f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return 0; 322f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén} 323f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 324f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, 325f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 val) 326f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{ 327f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén int err; 328f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén u8 i2c_data; 329f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén struct sd *sd = (struct sd *) gspca_dev; 330f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén s32 *sensor_settings = sd->sensor_priv; 331f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 332f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén PDEBUG(D_V4L2, "Set auto white balance to %d", val); 333f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 334f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; 335f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 336f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén if (err < 0) 337f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return err; 338f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 339f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); 340f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 341f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 342f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return err; 343f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén} 344f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 3454763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd) 3464763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 3474763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén int address; 3484763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("Dumping the ov7660 register state"); 3494763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén for (address = 0; address < 0xa9; address++) { 3504763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 value; 3514763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &value, 1); 3524763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x contains 0x%x", 3534763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén address, value); 3544763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 3554763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 3564763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("ov7660 register state dump complete"); 3574763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 3584763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("Probing for which registers that are read/write"); 3594763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén for (address = 0; address < 0xff; address++) { 3604763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 old_value, ctrl_value; 3614763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 test_value[2] = {0xff, 0xff}; 3624763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 3634763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &old_value, 1); 3644763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_write_sensor(sd, address, test_value, 1); 3654763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &ctrl_value, 1); 3664763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 3674763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén if (ctrl_value == test_value[0]) 3684763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x is writeable", address); 3694763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén else 3704763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x is read only", address); 3714763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 3724763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén /* Restore original value */ 3734763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_write_sensor(sd, address, &old_value, 1); 3744763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 3754763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 376