m5602_ov7660.c revision 456ebe4e92063b92d2672da272bfc7ac70bd8bdd
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); 31456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); 32456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); 33f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 34c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 35c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénconst static struct ctrl ov7660_ctrls[] = { 36c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén#define GAIN_IDX 1 37c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén { 38c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén { 39c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .id = V4L2_CID_GAIN, 40c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 41c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .name = "gain", 42c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .minimum = 0x00, 43c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .maximum = 0xff, 44c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .step = 0x1, 4572b79747a88f1ffcb6689cedacc01235bb545cd6Erik Andrén .default_value = OV7660_DEFAULT_GAIN, 46c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 47c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén }, 48c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .set = ov7660_set_gain, 49c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén .get = ov7660_get_gain 50c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén }, 51cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén#define BLUE_BALANCE_IDX 2 52cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén { 53cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén { 54cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .id = V4L2_CID_BLUE_BALANCE, 55cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 56cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .name = "blue balance", 57cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .minimum = 0x00, 58cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .maximum = 0x7f, 59cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .step = 0x1, 60cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .default_value = OV7660_DEFAULT_BLUE_GAIN, 61cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 62cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén }, 63cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .set = ov7660_set_blue_gain, 64cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén .get = ov7660_get_blue_gain 65cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén }, 6668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén#define RED_BALANCE_IDX 3 6768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén { 6868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén { 6968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .id = V4L2_CID_RED_BALANCE, 7068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .type = V4L2_CTRL_TYPE_INTEGER, 7168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .name = "red balance", 7268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .minimum = 0x00, 7368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .maximum = 0x7f, 7468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .step = 0x1, 7568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .default_value = OV7660_DEFAULT_RED_GAIN, 7668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .flags = V4L2_CTRL_FLAG_SLIDER 7768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén }, 7868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .set = ov7660_set_red_gain, 7968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén .get = ov7660_get_red_gain 8068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén }, 81f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén#define AUTO_WHITE_BALANCE_IDX 4 82f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén { 83f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén { 84f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .id = V4L2_CID_AUTO_WHITE_BALANCE, 85f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .type = V4L2_CTRL_TYPE_BOOLEAN, 86f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .name = "auto white balance", 87f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .minimum = 0, 88f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .maximum = 1, 89f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .step = 1, 90f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .default_value = 1 91f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén }, 92f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .set = ov7660_set_auto_white_balance, 93f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén .get = ov7660_get_auto_white_balance 94f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén }, 95456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén#define AUTO_GAIN_CTRL_IDX 5 96456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén { 97456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén { 98456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .id = V4L2_CID_AUTOGAIN, 99456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .type = V4L2_CTRL_TYPE_BOOLEAN, 100456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .name = "auto gain control", 101456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .minimum = 0, 102456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .maximum = 1, 103456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .step = 1, 104456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .default_value = 1 105456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén }, 106456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .set = ov7660_set_auto_gain, 107456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén .get = ov7660_get_auto_gain 108456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén }, 109c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén}; 1104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic struct v4l2_pix_format ov7660_modes[] = { 1124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén { 1134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 640, 1144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 480, 1154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén V4L2_PIX_FMT_SBGGR8, 1164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén V4L2_FIELD_NONE, 1174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .sizeimage = 1184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 640 * 480, 1194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .bytesperline = 640, 1204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .colorspace = V4L2_COLORSPACE_SRGB, 1214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén .priv = 0 1224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 1234763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén}; 1244763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1254763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd); 1264763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1274763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_probe(struct sd *sd) 1284763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 129ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén int err = 0, i; 130ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén u8 prod_id = 0, ver_id = 0; 131ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 132ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén s32 *sensor_settings; 133ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 134ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (force_sensor) { 135ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (force_sensor == OV7660_SENSOR) { 136ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Forcing an %s sensor", ov7660.name); 137ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén goto sensor_found; 138ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 139ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén /* If we want to force another sensor, 140ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén don't try to probe this one */ 141ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 142ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 143ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 144ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén /* Do the preinit */ 145ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { 146ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén u8 data[2]; 147ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 148ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (preinit_ov7660[i][0] == BRIDGE) { 149ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén err = m5602_write_bridge(sd, 150ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][1], 151ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][2]); 152ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } else { 153ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén data[0] = preinit_ov7660[i][2]; 154ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén err = m5602_write_sensor(sd, 155ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén preinit_ov7660[i][1], data, 1); 156ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 157ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 158ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (err < 0) 159ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return err; 160ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 161ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) 162ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 163ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 164ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) 165ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return -ENODEV; 166ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 167ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Sensor reported 0x%x%x", prod_id, ver_id); 168ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 169ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén if ((prod_id == 0x76) && (ver_id == 0x60)) { 170ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén info("Detected a ov7660 sensor"); 171ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén goto sensor_found; 172ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén } 1734763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return -ENODEV; 174ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 175ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrénsensor_found: 176c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sensor_settings = kmalloc( 177c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); 178c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén if (!sensor_settings) 179c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return -ENOMEM; 180c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 181ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->gspca_dev.cam.cam_mode = ov7660_modes; 182ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); 183ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->desc->ctrls = ov7660_ctrls; 184ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); 185ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 186ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) 187ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; 188ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén sd->sensor_priv = sensor_settings; 189ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén 190ea8f74b168aa4d725c6d1ab98ef4eb4f6f3f3358Erik Andrén return 0; 1914763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 1924763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 1934763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_init(struct sd *sd) 1944763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 1950364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén int i, err = 0; 196c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 1970364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 1980364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén /* Init the sensor */ 1990364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { 2000364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén u8 data[2]; 2010364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 2020364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén if (init_ov7660[i][0] == BRIDGE) { 2030364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén err = m5602_write_bridge(sd, 2040364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][1], 2050364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][2]); 2060364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } else { 2070364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén data[0] = init_ov7660[i][2]; 2080364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén err = m5602_write_sensor(sd, 2090364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén init_ov7660[i][1], data, 1); 2100364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } 2110364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén } 2120364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 2130364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén if (dump_sensor) 2140364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén ov7660_dump_registers(sd); 2150364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén 216c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); 217c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén if (err < 0) 218c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return err; 219c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 220f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = ov7660_set_auto_white_balance(&sd->gspca_dev, 221f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén sensor_settings[AUTO_WHITE_BALANCE_IDX]); 22236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén if (err < 0) 22336e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén return err; 22436e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén 225456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén err = ov7660_set_auto_gain(&sd->gspca_dev, 226456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén sensor_settings[AUTO_GAIN_CTRL_IDX]); 227456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén if (err < 0) 228456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén return err; 229456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 23036e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén err = ov7660_set_blue_gain(&sd->gspca_dev, 23136e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén sensor_settings[BLUE_BALANCE_IDX]); 23236e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén if (err < 0) 23336e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén return err; 23436e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén 23536e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén err = ov7660_set_red_gain(&sd->gspca_dev, 23636e64d5cec0a210d87e8e8c02566a1cbe24c00f3Erik Andrén sensor_settings[RED_BALANCE_IDX]); 237f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 2380364c4ca345175daa36c3c672fdecafd469e05a8Erik Andrén return err; 2394763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2404763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 2414763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_start(struct sd *sd) 2424763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 2434763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return 0; 2444763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2454763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 2464763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénint ov7660_stop(struct sd *sd) 2474763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 2484763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén return 0; 2494763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 2504763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 251c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénvoid ov7660_disconnect(struct sd *sd) 252c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 253c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén ov7660_stop(sd); 254c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 255c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sd->sensor = NULL; 256c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén kfree(sd->sensor_priv); 257c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 258c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 259c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 260c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 261c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén struct sd *sd = (struct sd *) gspca_dev; 262c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 263c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 264c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén *val = sensor_settings[GAIN_IDX]; 265c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén PDEBUG(D_V4L2, "Read gain %d", *val); 266c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return 0; 267c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 268c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 269c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrénstatic int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) 270c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén{ 271c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén int err; 272c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén u8 i2c_data; 273c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén struct sd *sd = (struct sd *) gspca_dev; 274c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén s32 *sensor_settings = sd->sensor_priv; 275c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 276c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén PDEBUG(D_V4L2, "Setting gain to %d", val); 277c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 278c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén sensor_settings[GAIN_IDX] = val; 279c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén 280c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); 281c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén return err; 282c9304e43fb71ad790c5fc995de55e7c95abe5b4aErik Andrén} 2834763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 284cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val) 285cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{ 286cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 287cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén s32 *sensor_settings = sd->sensor_priv; 288cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 289cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén *val = sensor_settings[BLUE_BALANCE_IDX]; 290cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén PDEBUG(D_V4L2, "Read blue balance %d", *val); 291cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén return 0; 292cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén} 293cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 294cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrénstatic int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val) 295cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén{ 296cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén int err; 297cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén u8 i2c_data; 298cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 299cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén s32 *sensor_settings = sd->sensor_priv; 300cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 301cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén PDEBUG(D_V4L2, "Setting blue balance to %d", val); 302cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 303cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén sensor_settings[BLUE_BALANCE_IDX] = val; 304cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 305cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén err = m5602_write_sensor(sd, OV7660_BLUE_GAIN, &i2c_data, 1); 306cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén return err; 307cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén} 308cbd1f7fb7059c629cb9e5131a755febc906496a6Erik Andrén 30968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_get_red_gain(struct gspca_dev *gspca_dev, __s32 *val) 31068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{ 31168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 31268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén s32 *sensor_settings = sd->sensor_priv; 31368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 31468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén *val = sensor_settings[RED_BALANCE_IDX]; 31568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén PDEBUG(D_V4L2, "Read red balance %d", *val); 31668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén return 0; 31768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén} 31868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 31968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrénstatic int ov7660_set_red_gain(struct gspca_dev *gspca_dev, __s32 val) 32068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén{ 32168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén int err; 32268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén u8 i2c_data; 32368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén struct sd *sd = (struct sd *) gspca_dev; 32468fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén s32 *sensor_settings = sd->sensor_priv; 32568fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 32668fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén PDEBUG(D_V4L2, "Setting red balance to %d", val); 32768fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 32868fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén sensor_settings[RED_BALANCE_IDX] = val; 32968fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 33068fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén err = m5602_write_sensor(sd, OV7660_RED_GAIN, &i2c_data, 1); 33168fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén return err; 33268fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén} 33368fdb7a5b52cb060f7824f9d6e98e105af36a474Erik Andrén 334f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, 335f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 *val) 336f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{ 337f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén struct sd *sd = (struct sd *) gspca_dev; 338f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén s32 *sensor_settings = sd->sensor_priv; 339f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 340f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; 341f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return 0; 342f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén} 343f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 344f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrénstatic int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, 345f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén __s32 val) 346f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén{ 347f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén int err; 348f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén u8 i2c_data; 349f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén struct sd *sd = (struct sd *) gspca_dev; 350f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén s32 *sensor_settings = sd->sensor_priv; 351f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 352f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén PDEBUG(D_V4L2, "Set auto white balance to %d", val); 353f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 354f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; 355f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 356f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén if (err < 0) 357f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return err; 358f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 359f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); 360f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 361f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 362f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén return err; 363f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén} 364f1f59fe60e38c4c56b8acba9690cd08d86d2ac0eErik Andrén 365456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) 366456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{ 367456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén struct sd *sd = (struct sd *) gspca_dev; 368456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén s32 *sensor_settings = sd->sensor_priv; 369456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 370456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; 371456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén PDEBUG(D_V4L2, "Read auto gain control %d", *val); 372456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén return 0; 373456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén} 374456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 375456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrénstatic int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) 376456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén{ 377456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén int err; 378456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén u8 i2c_data; 379456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén struct sd *sd = (struct sd *) gspca_dev; 380456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén s32 *sensor_settings = sd->sensor_priv; 381456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 382456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén PDEBUG(D_V4L2, "Set auto gain control to %d", val); 383456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 384456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén sensor_settings[AUTO_GAIN_CTRL_IDX] = val; 385456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); 386456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén if (err < 0) 387456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén return err; 388456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 389456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); 390456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 391456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); 392456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén} 393456ebe4e92063b92d2672da272bfc7ac70bd8bddErik Andrén 3944763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrénstatic void ov7660_dump_registers(struct sd *sd) 3954763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén{ 3964763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén int address; 3974763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("Dumping the ov7660 register state"); 3984763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén for (address = 0; address < 0xa9; address++) { 3994763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 value; 4004763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &value, 1); 4014763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x contains 0x%x", 4024763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén address, value); 4034763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 4044763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 4054763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("ov7660 register state dump complete"); 4064763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 4074763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("Probing for which registers that are read/write"); 4084763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén for (address = 0; address < 0xff; address++) { 4094763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 old_value, ctrl_value; 4104763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén u8 test_value[2] = {0xff, 0xff}; 4114763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 4124763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &old_value, 1); 4134763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_write_sensor(sd, address, test_value, 1); 4144763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_read_sensor(sd, address, &ctrl_value, 1); 4154763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 4164763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén if (ctrl_value == test_value[0]) 4174763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x is writeable", address); 4184763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén else 4194763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén info("register 0x%x is read only", address); 4204763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén 4214763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén /* Restore original value */ 4224763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén m5602_write_sensor(sd, address, &old_value, 1); 4234763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén } 4244763fa84d9942137b011629be2e7547a23cdfbc6Erik Andrén} 425