10c0d06caSMauro Carvalho Chehab /* 20c0d06caSMauro Carvalho Chehab * Driver for the mt9m111 sensor 30c0d06caSMauro Carvalho Chehab * 40c0d06caSMauro Carvalho Chehab * Copyright (C) 2008 Erik Andrén 50c0d06caSMauro Carvalho Chehab * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 60c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 70c0d06caSMauro Carvalho Chehab * 80c0d06caSMauro Carvalho Chehab * Portions of code to USB interface and ALi driver software, 90c0d06caSMauro Carvalho Chehab * Copyright (c) 2006 Willem Duinker 100c0d06caSMauro Carvalho Chehab * v4l2 interface modeled after the V4L2 driver 110c0d06caSMauro Carvalho Chehab * for SN9C10x PC Camera Controllers 120c0d06caSMauro Carvalho Chehab * 130c0d06caSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or 140c0d06caSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License as 150c0d06caSMauro Carvalho Chehab * published by the Free Software Foundation, version 2. 160c0d06caSMauro Carvalho Chehab * 170c0d06caSMauro Carvalho Chehab */ 180c0d06caSMauro Carvalho Chehab 190c0d06caSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 200c0d06caSMauro Carvalho Chehab 210c0d06caSMauro Carvalho Chehab #include "m5602_mt9m111.h" 220c0d06caSMauro Carvalho Chehab 230c0d06caSMauro Carvalho Chehab static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); 240c0d06caSMauro Carvalho Chehab static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); 250c0d06caSMauro Carvalho Chehab static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); 260c0d06caSMauro Carvalho Chehab static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); 270c0d06caSMauro Carvalho Chehab static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); 280c0d06caSMauro Carvalho Chehab static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); 290c0d06caSMauro Carvalho Chehab static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, 300c0d06caSMauro Carvalho Chehab __s32 val); 310c0d06caSMauro Carvalho Chehab static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, 320c0d06caSMauro Carvalho Chehab __s32 *val); 330c0d06caSMauro Carvalho Chehab static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); 340c0d06caSMauro Carvalho Chehab static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); 350c0d06caSMauro Carvalho Chehab static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); 360c0d06caSMauro Carvalho Chehab static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); 370c0d06caSMauro Carvalho Chehab static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); 380c0d06caSMauro Carvalho Chehab static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); 390c0d06caSMauro Carvalho Chehab 400c0d06caSMauro Carvalho Chehab static struct v4l2_pix_format mt9m111_modes[] = { 410c0d06caSMauro Carvalho Chehab { 420c0d06caSMauro Carvalho Chehab 640, 430c0d06caSMauro Carvalho Chehab 480, 440c0d06caSMauro Carvalho Chehab V4L2_PIX_FMT_SBGGR8, 450c0d06caSMauro Carvalho Chehab V4L2_FIELD_NONE, 460c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480, 470c0d06caSMauro Carvalho Chehab .bytesperline = 640, 480c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 490c0d06caSMauro Carvalho Chehab .priv = 0 500c0d06caSMauro Carvalho Chehab } 510c0d06caSMauro Carvalho Chehab }; 520c0d06caSMauro Carvalho Chehab 530c0d06caSMauro Carvalho Chehab static const struct ctrl mt9m111_ctrls[] = { 540c0d06caSMauro Carvalho Chehab #define VFLIP_IDX 0 550c0d06caSMauro Carvalho Chehab { 560c0d06caSMauro Carvalho Chehab { 570c0d06caSMauro Carvalho Chehab .id = V4L2_CID_VFLIP, 580c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_BOOLEAN, 590c0d06caSMauro Carvalho Chehab .name = "vertical flip", 600c0d06caSMauro Carvalho Chehab .minimum = 0, 610c0d06caSMauro Carvalho Chehab .maximum = 1, 620c0d06caSMauro Carvalho Chehab .step = 1, 630c0d06caSMauro Carvalho Chehab .default_value = 0 640c0d06caSMauro Carvalho Chehab }, 650c0d06caSMauro Carvalho Chehab .set = mt9m111_set_vflip, 660c0d06caSMauro Carvalho Chehab .get = mt9m111_get_vflip 670c0d06caSMauro Carvalho Chehab }, 680c0d06caSMauro Carvalho Chehab #define HFLIP_IDX 1 690c0d06caSMauro Carvalho Chehab { 700c0d06caSMauro Carvalho Chehab { 710c0d06caSMauro Carvalho Chehab .id = V4L2_CID_HFLIP, 720c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_BOOLEAN, 730c0d06caSMauro Carvalho Chehab .name = "horizontal flip", 740c0d06caSMauro Carvalho Chehab .minimum = 0, 750c0d06caSMauro Carvalho Chehab .maximum = 1, 760c0d06caSMauro Carvalho Chehab .step = 1, 770c0d06caSMauro Carvalho Chehab .default_value = 0 780c0d06caSMauro Carvalho Chehab }, 790c0d06caSMauro Carvalho Chehab .set = mt9m111_set_hflip, 800c0d06caSMauro Carvalho Chehab .get = mt9m111_get_hflip 810c0d06caSMauro Carvalho Chehab }, 820c0d06caSMauro Carvalho Chehab #define GAIN_IDX 2 830c0d06caSMauro Carvalho Chehab { 840c0d06caSMauro Carvalho Chehab { 850c0d06caSMauro Carvalho Chehab .id = V4L2_CID_GAIN, 860c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER, 870c0d06caSMauro Carvalho Chehab .name = "gain", 880c0d06caSMauro Carvalho Chehab .minimum = 0, 890c0d06caSMauro Carvalho Chehab .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 900c0d06caSMauro Carvalho Chehab .step = 1, 910c0d06caSMauro Carvalho Chehab .default_value = MT9M111_DEFAULT_GAIN, 920c0d06caSMauro Carvalho Chehab .flags = V4L2_CTRL_FLAG_SLIDER 930c0d06caSMauro Carvalho Chehab }, 940c0d06caSMauro Carvalho Chehab .set = mt9m111_set_gain, 950c0d06caSMauro Carvalho Chehab .get = mt9m111_get_gain 960c0d06caSMauro Carvalho Chehab }, 970c0d06caSMauro Carvalho Chehab #define AUTO_WHITE_BALANCE_IDX 3 980c0d06caSMauro Carvalho Chehab { 990c0d06caSMauro Carvalho Chehab { 1000c0d06caSMauro Carvalho Chehab .id = V4L2_CID_AUTO_WHITE_BALANCE, 1010c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_BOOLEAN, 1020c0d06caSMauro Carvalho Chehab .name = "auto white balance", 1030c0d06caSMauro Carvalho Chehab .minimum = 0, 1040c0d06caSMauro Carvalho Chehab .maximum = 1, 1050c0d06caSMauro Carvalho Chehab .step = 1, 1060c0d06caSMauro Carvalho Chehab .default_value = 0, 1070c0d06caSMauro Carvalho Chehab }, 1080c0d06caSMauro Carvalho Chehab .set = mt9m111_set_auto_white_balance, 1090c0d06caSMauro Carvalho Chehab .get = mt9m111_get_auto_white_balance 1100c0d06caSMauro Carvalho Chehab }, 1110c0d06caSMauro Carvalho Chehab #define GREEN_BALANCE_IDX 4 1120c0d06caSMauro Carvalho Chehab { 1130c0d06caSMauro Carvalho Chehab { 1140c0d06caSMauro Carvalho Chehab .id = M5602_V4L2_CID_GREEN_BALANCE, 1150c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER, 1160c0d06caSMauro Carvalho Chehab .name = "green balance", 1170c0d06caSMauro Carvalho Chehab .minimum = 0x00, 1180c0d06caSMauro Carvalho Chehab .maximum = 0x7ff, 1190c0d06caSMauro Carvalho Chehab .step = 0x1, 1200c0d06caSMauro Carvalho Chehab .default_value = MT9M111_GREEN_GAIN_DEFAULT, 1210c0d06caSMauro Carvalho Chehab .flags = V4L2_CTRL_FLAG_SLIDER 1220c0d06caSMauro Carvalho Chehab }, 1230c0d06caSMauro Carvalho Chehab .set = mt9m111_set_green_balance, 1240c0d06caSMauro Carvalho Chehab .get = mt9m111_get_green_balance 1250c0d06caSMauro Carvalho Chehab }, 1260c0d06caSMauro Carvalho Chehab #define BLUE_BALANCE_IDX 5 1270c0d06caSMauro Carvalho Chehab { 1280c0d06caSMauro Carvalho Chehab { 1290c0d06caSMauro Carvalho Chehab .id = V4L2_CID_BLUE_BALANCE, 1300c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER, 1310c0d06caSMauro Carvalho Chehab .name = "blue balance", 1320c0d06caSMauro Carvalho Chehab .minimum = 0x00, 1330c0d06caSMauro Carvalho Chehab .maximum = 0x7ff, 1340c0d06caSMauro Carvalho Chehab .step = 0x1, 1350c0d06caSMauro Carvalho Chehab .default_value = MT9M111_BLUE_GAIN_DEFAULT, 1360c0d06caSMauro Carvalho Chehab .flags = V4L2_CTRL_FLAG_SLIDER 1370c0d06caSMauro Carvalho Chehab }, 1380c0d06caSMauro Carvalho Chehab .set = mt9m111_set_blue_balance, 1390c0d06caSMauro Carvalho Chehab .get = mt9m111_get_blue_balance 1400c0d06caSMauro Carvalho Chehab }, 1410c0d06caSMauro Carvalho Chehab #define RED_BALANCE_IDX 5 1420c0d06caSMauro Carvalho Chehab { 1430c0d06caSMauro Carvalho Chehab { 1440c0d06caSMauro Carvalho Chehab .id = V4L2_CID_RED_BALANCE, 1450c0d06caSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER, 1460c0d06caSMauro Carvalho Chehab .name = "red balance", 1470c0d06caSMauro Carvalho Chehab .minimum = 0x00, 1480c0d06caSMauro Carvalho Chehab .maximum = 0x7ff, 1490c0d06caSMauro Carvalho Chehab .step = 0x1, 1500c0d06caSMauro Carvalho Chehab .default_value = MT9M111_RED_GAIN_DEFAULT, 1510c0d06caSMauro Carvalho Chehab .flags = V4L2_CTRL_FLAG_SLIDER 1520c0d06caSMauro Carvalho Chehab }, 1530c0d06caSMauro Carvalho Chehab .set = mt9m111_set_red_balance, 1540c0d06caSMauro Carvalho Chehab .get = mt9m111_get_red_balance 1550c0d06caSMauro Carvalho Chehab }, 1560c0d06caSMauro Carvalho Chehab }; 1570c0d06caSMauro Carvalho Chehab 1580c0d06caSMauro Carvalho Chehab static void mt9m111_dump_registers(struct sd *sd); 1590c0d06caSMauro Carvalho Chehab 1600c0d06caSMauro Carvalho Chehab int mt9m111_probe(struct sd *sd) 1610c0d06caSMauro Carvalho Chehab { 1620c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 1630c0d06caSMauro Carvalho Chehab int i; 1640c0d06caSMauro Carvalho Chehab s32 *sensor_settings; 1650c0d06caSMauro Carvalho Chehab 1660c0d06caSMauro Carvalho Chehab if (force_sensor) { 1670c0d06caSMauro Carvalho Chehab if (force_sensor == MT9M111_SENSOR) { 1680c0d06caSMauro Carvalho Chehab pr_info("Forcing a %s sensor\n", mt9m111.name); 1690c0d06caSMauro Carvalho Chehab goto sensor_found; 1700c0d06caSMauro Carvalho Chehab } 1710c0d06caSMauro Carvalho Chehab /* If we want to force another sensor, don't try to probe this 1720c0d06caSMauro Carvalho Chehab * one */ 1730c0d06caSMauro Carvalho Chehab return -ENODEV; 1740c0d06caSMauro Carvalho Chehab } 1750c0d06caSMauro Carvalho Chehab 1760c0d06caSMauro Carvalho Chehab PDEBUG(D_PROBE, "Probing for a mt9m111 sensor"); 1770c0d06caSMauro Carvalho Chehab 1780c0d06caSMauro Carvalho Chehab /* Do the preinit */ 1790c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { 1800c0d06caSMauro Carvalho Chehab if (preinit_mt9m111[i][0] == BRIDGE) { 1810c0d06caSMauro Carvalho Chehab m5602_write_bridge(sd, 1820c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][1], 1830c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][2]); 1840c0d06caSMauro Carvalho Chehab } else { 1850c0d06caSMauro Carvalho Chehab data[0] = preinit_mt9m111[i][2]; 1860c0d06caSMauro Carvalho Chehab data[1] = preinit_mt9m111[i][3]; 1870c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, 1880c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][1], data, 2); 1890c0d06caSMauro Carvalho Chehab } 1900c0d06caSMauro Carvalho Chehab } 1910c0d06caSMauro Carvalho Chehab 1920c0d06caSMauro Carvalho Chehab if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) 1930c0d06caSMauro Carvalho Chehab return -ENODEV; 1940c0d06caSMauro Carvalho Chehab 1950c0d06caSMauro Carvalho Chehab if ((data[0] == 0x14) && (data[1] == 0x3a)) { 1960c0d06caSMauro Carvalho Chehab pr_info("Detected a mt9m111 sensor\n"); 1970c0d06caSMauro Carvalho Chehab goto sensor_found; 1980c0d06caSMauro Carvalho Chehab } 1990c0d06caSMauro Carvalho Chehab 2000c0d06caSMauro Carvalho Chehab return -ENODEV; 2010c0d06caSMauro Carvalho Chehab 2020c0d06caSMauro Carvalho Chehab sensor_found: 2030c0d06caSMauro Carvalho Chehab sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), 2040c0d06caSMauro Carvalho Chehab GFP_KERNEL); 2050c0d06caSMauro Carvalho Chehab if (!sensor_settings) 2060c0d06caSMauro Carvalho Chehab return -ENOMEM; 2070c0d06caSMauro Carvalho Chehab 2080c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.cam_mode = mt9m111_modes; 2090c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); 2100c0d06caSMauro Carvalho Chehab sd->desc->ctrls = mt9m111_ctrls; 2110c0d06caSMauro Carvalho Chehab sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); 2120c0d06caSMauro Carvalho Chehab 2130c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) 2140c0d06caSMauro Carvalho Chehab sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; 2150c0d06caSMauro Carvalho Chehab sd->sensor_priv = sensor_settings; 2160c0d06caSMauro Carvalho Chehab 2170c0d06caSMauro Carvalho Chehab return 0; 2180c0d06caSMauro Carvalho Chehab } 2190c0d06caSMauro Carvalho Chehab 2200c0d06caSMauro Carvalho Chehab int mt9m111_init(struct sd *sd) 2210c0d06caSMauro Carvalho Chehab { 2220c0d06caSMauro Carvalho Chehab int i, err = 0; 2230c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 2240c0d06caSMauro Carvalho Chehab 2250c0d06caSMauro Carvalho Chehab /* Init the sensor */ 2260c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { 2270c0d06caSMauro Carvalho Chehab u8 data[2]; 2280c0d06caSMauro Carvalho Chehab 2290c0d06caSMauro Carvalho Chehab if (init_mt9m111[i][0] == BRIDGE) { 2300c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, 2310c0d06caSMauro Carvalho Chehab init_mt9m111[i][1], 2320c0d06caSMauro Carvalho Chehab init_mt9m111[i][2]); 2330c0d06caSMauro Carvalho Chehab } else { 2340c0d06caSMauro Carvalho Chehab data[0] = init_mt9m111[i][2]; 2350c0d06caSMauro Carvalho Chehab data[1] = init_mt9m111[i][3]; 2360c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 2370c0d06caSMauro Carvalho Chehab init_mt9m111[i][1], data, 2); 2380c0d06caSMauro Carvalho Chehab } 2390c0d06caSMauro Carvalho Chehab } 2400c0d06caSMauro Carvalho Chehab 2410c0d06caSMauro Carvalho Chehab if (dump_sensor) 2420c0d06caSMauro Carvalho Chehab mt9m111_dump_registers(sd); 2430c0d06caSMauro Carvalho Chehab 2440c0d06caSMauro Carvalho Chehab err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); 2450c0d06caSMauro Carvalho Chehab if (err < 0) 2460c0d06caSMauro Carvalho Chehab return err; 2470c0d06caSMauro Carvalho Chehab 2480c0d06caSMauro Carvalho Chehab err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); 2490c0d06caSMauro Carvalho Chehab if (err < 0) 2500c0d06caSMauro Carvalho Chehab return err; 2510c0d06caSMauro Carvalho Chehab 2520c0d06caSMauro Carvalho Chehab err = mt9m111_set_green_balance(&sd->gspca_dev, 2530c0d06caSMauro Carvalho Chehab sensor_settings[GREEN_BALANCE_IDX]); 2540c0d06caSMauro Carvalho Chehab if (err < 0) 2550c0d06caSMauro Carvalho Chehab return err; 2560c0d06caSMauro Carvalho Chehab 2570c0d06caSMauro Carvalho Chehab err = mt9m111_set_blue_balance(&sd->gspca_dev, 2580c0d06caSMauro Carvalho Chehab sensor_settings[BLUE_BALANCE_IDX]); 2590c0d06caSMauro Carvalho Chehab if (err < 0) 2600c0d06caSMauro Carvalho Chehab return err; 2610c0d06caSMauro Carvalho Chehab 2620c0d06caSMauro Carvalho Chehab err = mt9m111_set_red_balance(&sd->gspca_dev, 2630c0d06caSMauro Carvalho Chehab sensor_settings[RED_BALANCE_IDX]); 2640c0d06caSMauro Carvalho Chehab if (err < 0) 2650c0d06caSMauro Carvalho Chehab return err; 2660c0d06caSMauro Carvalho Chehab 2670c0d06caSMauro Carvalho Chehab return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); 2680c0d06caSMauro Carvalho Chehab } 2690c0d06caSMauro Carvalho Chehab 2700c0d06caSMauro Carvalho Chehab int mt9m111_start(struct sd *sd) 2710c0d06caSMauro Carvalho Chehab { 2720c0d06caSMauro Carvalho Chehab int i, err = 0; 2730c0d06caSMauro Carvalho Chehab u8 data[2]; 2740c0d06caSMauro Carvalho Chehab struct cam *cam = &sd->gspca_dev.cam; 2750c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 2760c0d06caSMauro Carvalho Chehab 2770c0d06caSMauro Carvalho Chehab int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; 2780c0d06caSMauro Carvalho Chehab int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; 2790c0d06caSMauro Carvalho Chehab 2800c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { 2810c0d06caSMauro Carvalho Chehab if (start_mt9m111[i][0] == BRIDGE) { 2820c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, 2830c0d06caSMauro Carvalho Chehab start_mt9m111[i][1], 2840c0d06caSMauro Carvalho Chehab start_mt9m111[i][2]); 2850c0d06caSMauro Carvalho Chehab } else { 2860c0d06caSMauro Carvalho Chehab data[0] = start_mt9m111[i][2]; 2870c0d06caSMauro Carvalho Chehab data[1] = start_mt9m111[i][3]; 2880c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 2890c0d06caSMauro Carvalho Chehab start_mt9m111[i][1], data, 2); 2900c0d06caSMauro Carvalho Chehab } 2910c0d06caSMauro Carvalho Chehab } 2920c0d06caSMauro Carvalho Chehab if (err < 0) 2930c0d06caSMauro Carvalho Chehab return err; 2940c0d06caSMauro Carvalho Chehab 2950c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); 2960c0d06caSMauro Carvalho Chehab if (err < 0) 2970c0d06caSMauro Carvalho Chehab return err; 2980c0d06caSMauro Carvalho Chehab 2990c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); 3000c0d06caSMauro Carvalho Chehab if (err < 0) 3010c0d06caSMauro Carvalho Chehab return err; 3020c0d06caSMauro Carvalho Chehab 3030c0d06caSMauro Carvalho Chehab for (i = 0; i < 2 && !err; i++) 3040c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); 3050c0d06caSMauro Carvalho Chehab if (err < 0) 3060c0d06caSMauro Carvalho Chehab return err; 3070c0d06caSMauro Carvalho Chehab 3080c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 3090c0d06caSMauro Carvalho Chehab if (err < 0) 3100c0d06caSMauro Carvalho Chehab return err; 3110c0d06caSMauro Carvalho Chehab 3120c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); 3130c0d06caSMauro Carvalho Chehab if (err < 0) 3140c0d06caSMauro Carvalho Chehab return err; 3150c0d06caSMauro Carvalho Chehab 3160c0d06caSMauro Carvalho Chehab for (i = 0; i < 2 && !err; i++) 3170c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); 3180c0d06caSMauro Carvalho Chehab if (err < 0) 3190c0d06caSMauro Carvalho Chehab return err; 3200c0d06caSMauro Carvalho Chehab 3210c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 3220c0d06caSMauro Carvalho Chehab (width >> 8) & 0xff); 3230c0d06caSMauro Carvalho Chehab if (err < 0) 3240c0d06caSMauro Carvalho Chehab return err; 3250c0d06caSMauro Carvalho Chehab 3260c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); 3270c0d06caSMauro Carvalho Chehab if (err < 0) 3280c0d06caSMauro Carvalho Chehab return err; 3290c0d06caSMauro Carvalho Chehab 3300c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 3310c0d06caSMauro Carvalho Chehab if (err < 0) 3320c0d06caSMauro Carvalho Chehab return err; 3330c0d06caSMauro Carvalho Chehab 3340c0d06caSMauro Carvalho Chehab switch (width) { 3350c0d06caSMauro Carvalho Chehab case 640: 3360c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Configuring camera for VGA mode"); 3370c0d06caSMauro Carvalho Chehab data[0] = MT9M111_RMB_OVER_SIZED; 3380c0d06caSMauro Carvalho Chehab data[1] = MT9M111_RMB_ROW_SKIP_2X | 3390c0d06caSMauro Carvalho Chehab MT9M111_RMB_COLUMN_SKIP_2X | 3400c0d06caSMauro Carvalho Chehab (sensor_settings[VFLIP_IDX] << 0) | 3410c0d06caSMauro Carvalho Chehab (sensor_settings[HFLIP_IDX] << 1); 3420c0d06caSMauro Carvalho Chehab 3430c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 3440c0d06caSMauro Carvalho Chehab MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 3450c0d06caSMauro Carvalho Chehab break; 3460c0d06caSMauro Carvalho Chehab 3470c0d06caSMauro Carvalho Chehab case 320: 3480c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); 3490c0d06caSMauro Carvalho Chehab data[0] = MT9M111_RMB_OVER_SIZED; 3500c0d06caSMauro Carvalho Chehab data[1] = MT9M111_RMB_ROW_SKIP_4X | 3510c0d06caSMauro Carvalho Chehab MT9M111_RMB_COLUMN_SKIP_4X | 3520c0d06caSMauro Carvalho Chehab (sensor_settings[VFLIP_IDX] << 0) | 3530c0d06caSMauro Carvalho Chehab (sensor_settings[HFLIP_IDX] << 1); 3540c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 3550c0d06caSMauro Carvalho Chehab MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 3560c0d06caSMauro Carvalho Chehab break; 3570c0d06caSMauro Carvalho Chehab } 3580c0d06caSMauro Carvalho Chehab return err; 3590c0d06caSMauro Carvalho Chehab } 3600c0d06caSMauro Carvalho Chehab 3610c0d06caSMauro Carvalho Chehab void mt9m111_disconnect(struct sd *sd) 3620c0d06caSMauro Carvalho Chehab { 3630c0d06caSMauro Carvalho Chehab sd->sensor = NULL; 3640c0d06caSMauro Carvalho Chehab kfree(sd->sensor_priv); 3650c0d06caSMauro Carvalho Chehab } 3660c0d06caSMauro Carvalho Chehab 3670c0d06caSMauro Carvalho Chehab static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) 3680c0d06caSMauro Carvalho Chehab { 3690c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 3700c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 3710c0d06caSMauro Carvalho Chehab 3720c0d06caSMauro Carvalho Chehab *val = sensor_settings[VFLIP_IDX]; 3730c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read vertical flip %d", *val); 3740c0d06caSMauro Carvalho Chehab 3750c0d06caSMauro Carvalho Chehab return 0; 3760c0d06caSMauro Carvalho Chehab } 3770c0d06caSMauro Carvalho Chehab 3780c0d06caSMauro Carvalho Chehab static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 3790c0d06caSMauro Carvalho Chehab { 3800c0d06caSMauro Carvalho Chehab int err; 3810c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 3820c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 3830c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 3840c0d06caSMauro Carvalho Chehab 3850c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set vertical flip to %d", val); 3860c0d06caSMauro Carvalho Chehab 3870c0d06caSMauro Carvalho Chehab sensor_settings[VFLIP_IDX] = val; 3880c0d06caSMauro Carvalho Chehab 3890c0d06caSMauro Carvalho Chehab /* The mt9m111 is flipped by default */ 3900c0d06caSMauro Carvalho Chehab val = !val; 3910c0d06caSMauro Carvalho Chehab 3920c0d06caSMauro Carvalho Chehab /* Set the correct page map */ 3930c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 3940c0d06caSMauro Carvalho Chehab if (err < 0) 3950c0d06caSMauro Carvalho Chehab return err; 3960c0d06caSMauro Carvalho Chehab 3970c0d06caSMauro Carvalho Chehab err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 3980c0d06caSMauro Carvalho Chehab if (err < 0) 3990c0d06caSMauro Carvalho Chehab return err; 4000c0d06caSMauro Carvalho Chehab 4010c0d06caSMauro Carvalho Chehab data[1] = (data[1] & 0xfe) | val; 4020c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, 4030c0d06caSMauro Carvalho Chehab data, 2); 4040c0d06caSMauro Carvalho Chehab return err; 4050c0d06caSMauro Carvalho Chehab } 4060c0d06caSMauro Carvalho Chehab 4070c0d06caSMauro Carvalho Chehab static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) 4080c0d06caSMauro Carvalho Chehab { 4090c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4100c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4110c0d06caSMauro Carvalho Chehab 4120c0d06caSMauro Carvalho Chehab *val = sensor_settings[HFLIP_IDX]; 4130c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read horizontal flip %d", *val); 4140c0d06caSMauro Carvalho Chehab 4150c0d06caSMauro Carvalho Chehab return 0; 4160c0d06caSMauro Carvalho Chehab } 4170c0d06caSMauro Carvalho Chehab 4180c0d06caSMauro Carvalho Chehab static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 4190c0d06caSMauro Carvalho Chehab { 4200c0d06caSMauro Carvalho Chehab int err; 4210c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 4220c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4230c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4240c0d06caSMauro Carvalho Chehab 4250c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set horizontal flip to %d", val); 4260c0d06caSMauro Carvalho Chehab 4270c0d06caSMauro Carvalho Chehab sensor_settings[HFLIP_IDX] = val; 4280c0d06caSMauro Carvalho Chehab 4290c0d06caSMauro Carvalho Chehab /* The mt9m111 is flipped by default */ 4300c0d06caSMauro Carvalho Chehab val = !val; 4310c0d06caSMauro Carvalho Chehab 4320c0d06caSMauro Carvalho Chehab /* Set the correct page map */ 4330c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 4340c0d06caSMauro Carvalho Chehab if (err < 0) 4350c0d06caSMauro Carvalho Chehab return err; 4360c0d06caSMauro Carvalho Chehab 4370c0d06caSMauro Carvalho Chehab err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 4380c0d06caSMauro Carvalho Chehab if (err < 0) 4390c0d06caSMauro Carvalho Chehab return err; 4400c0d06caSMauro Carvalho Chehab 4410c0d06caSMauro Carvalho Chehab data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); 4420c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, 4430c0d06caSMauro Carvalho Chehab data, 2); 4440c0d06caSMauro Carvalho Chehab return err; 4450c0d06caSMauro Carvalho Chehab } 4460c0d06caSMauro Carvalho Chehab 4470c0d06caSMauro Carvalho Chehab static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 4480c0d06caSMauro Carvalho Chehab { 4490c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4500c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4510c0d06caSMauro Carvalho Chehab 4520c0d06caSMauro Carvalho Chehab *val = sensor_settings[GAIN_IDX]; 4530c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read gain %d", *val); 4540c0d06caSMauro Carvalho Chehab 4550c0d06caSMauro Carvalho Chehab return 0; 4560c0d06caSMauro Carvalho Chehab } 4570c0d06caSMauro Carvalho Chehab 4580c0d06caSMauro Carvalho Chehab static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, 4590c0d06caSMauro Carvalho Chehab __s32 val) 4600c0d06caSMauro Carvalho Chehab { 4610c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4620c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4630c0d06caSMauro Carvalho Chehab int err; 4640c0d06caSMauro Carvalho Chehab u8 data[2]; 4650c0d06caSMauro Carvalho Chehab 4660c0d06caSMauro Carvalho Chehab err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 4670c0d06caSMauro Carvalho Chehab if (err < 0) 4680c0d06caSMauro Carvalho Chehab return err; 4690c0d06caSMauro Carvalho Chehab 4700c0d06caSMauro Carvalho Chehab sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; 4710c0d06caSMauro Carvalho Chehab data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); 4720c0d06caSMauro Carvalho Chehab 4730c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 4740c0d06caSMauro Carvalho Chehab 4750c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set auto white balance %d", val); 4760c0d06caSMauro Carvalho Chehab return err; 4770c0d06caSMauro Carvalho Chehab } 4780c0d06caSMauro Carvalho Chehab 4790c0d06caSMauro Carvalho Chehab static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, 4800c0d06caSMauro Carvalho Chehab __s32 *val) { 4810c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4820c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4830c0d06caSMauro Carvalho Chehab 4840c0d06caSMauro Carvalho Chehab *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; 4850c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read auto white balance %d", *val); 4860c0d06caSMauro Carvalho Chehab return 0; 4870c0d06caSMauro Carvalho Chehab } 4880c0d06caSMauro Carvalho Chehab 4890c0d06caSMauro Carvalho Chehab static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) 4900c0d06caSMauro Carvalho Chehab { 4910c0d06caSMauro Carvalho Chehab int err, tmp; 4920c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 4930c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4940c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 4950c0d06caSMauro Carvalho Chehab 4960c0d06caSMauro Carvalho Chehab sensor_settings[GAIN_IDX] = val; 4970c0d06caSMauro Carvalho Chehab 4980c0d06caSMauro Carvalho Chehab /* Set the correct page map */ 4990c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 5000c0d06caSMauro Carvalho Chehab if (err < 0) 5010c0d06caSMauro Carvalho Chehab return err; 5020c0d06caSMauro Carvalho Chehab 5030c0d06caSMauro Carvalho Chehab if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) 5040c0d06caSMauro Carvalho Chehab return -EINVAL; 5050c0d06caSMauro Carvalho Chehab 5060c0d06caSMauro Carvalho Chehab if ((val >= INITIAL_MAX_GAIN * 2 * 2) && 5070c0d06caSMauro Carvalho Chehab (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) 5080c0d06caSMauro Carvalho Chehab tmp = (1 << 10) | (val << 9) | 5090c0d06caSMauro Carvalho Chehab (val << 8) | (val / 8); 5100c0d06caSMauro Carvalho Chehab else if ((val >= INITIAL_MAX_GAIN * 2) && 5110c0d06caSMauro Carvalho Chehab (val < INITIAL_MAX_GAIN * 2 * 2)) 5120c0d06caSMauro Carvalho Chehab tmp = (1 << 9) | (1 << 8) | (val / 4); 5130c0d06caSMauro Carvalho Chehab else if ((val >= INITIAL_MAX_GAIN) && 5140c0d06caSMauro Carvalho Chehab (val < INITIAL_MAX_GAIN * 2)) 5150c0d06caSMauro Carvalho Chehab tmp = (1 << 8) | (val / 2); 5160c0d06caSMauro Carvalho Chehab else 5170c0d06caSMauro Carvalho Chehab tmp = val; 5180c0d06caSMauro Carvalho Chehab 5190c0d06caSMauro Carvalho Chehab data[1] = (tmp & 0xff); 5200c0d06caSMauro Carvalho Chehab data[0] = (tmp & 0xff00) >> 8; 5210c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, 5220c0d06caSMauro Carvalho Chehab data[1], data[0]); 5230c0d06caSMauro Carvalho Chehab 5240c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, 5250c0d06caSMauro Carvalho Chehab data, 2); 5260c0d06caSMauro Carvalho Chehab 5270c0d06caSMauro Carvalho Chehab return err; 5280c0d06caSMauro Carvalho Chehab } 5290c0d06caSMauro Carvalho Chehab 5300c0d06caSMauro Carvalho Chehab static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) 5310c0d06caSMauro Carvalho Chehab { 5320c0d06caSMauro Carvalho Chehab int err; 5330c0d06caSMauro Carvalho Chehab u8 data[2]; 5340c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5350c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 5360c0d06caSMauro Carvalho Chehab 5370c0d06caSMauro Carvalho Chehab sensor_settings[GREEN_BALANCE_IDX] = val; 5380c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 5390c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 5400c0d06caSMauro Carvalho Chehab 5410c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set green balance %d", val); 5420c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, 5430c0d06caSMauro Carvalho Chehab data, 2); 5440c0d06caSMauro Carvalho Chehab if (err < 0) 5450c0d06caSMauro Carvalho Chehab return err; 5460c0d06caSMauro Carvalho Chehab 5470c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, 5480c0d06caSMauro Carvalho Chehab data, 2); 5490c0d06caSMauro Carvalho Chehab } 5500c0d06caSMauro Carvalho Chehab 5510c0d06caSMauro Carvalho Chehab static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) 5520c0d06caSMauro Carvalho Chehab { 5530c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5540c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 5550c0d06caSMauro Carvalho Chehab 5560c0d06caSMauro Carvalho Chehab *val = sensor_settings[GREEN_BALANCE_IDX]; 5570c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read green balance %d", *val); 5580c0d06caSMauro Carvalho Chehab return 0; 5590c0d06caSMauro Carvalho Chehab } 5600c0d06caSMauro Carvalho Chehab 5610c0d06caSMauro Carvalho Chehab static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) 5620c0d06caSMauro Carvalho Chehab { 5630c0d06caSMauro Carvalho Chehab u8 data[2]; 5640c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5650c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 5660c0d06caSMauro Carvalho Chehab 5670c0d06caSMauro Carvalho Chehab sensor_settings[BLUE_BALANCE_IDX] = val; 5680c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 5690c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 5700c0d06caSMauro Carvalho Chehab 5710c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set blue balance %d", val); 5720c0d06caSMauro Carvalho Chehab 5730c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, 5740c0d06caSMauro Carvalho Chehab data, 2); 5750c0d06caSMauro Carvalho Chehab } 5760c0d06caSMauro Carvalho Chehab 5770c0d06caSMauro Carvalho Chehab static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) 5780c0d06caSMauro Carvalho Chehab { 5790c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5800c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 5810c0d06caSMauro Carvalho Chehab 5820c0d06caSMauro Carvalho Chehab *val = sensor_settings[BLUE_BALANCE_IDX]; 5830c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read blue balance %d", *val); 5840c0d06caSMauro Carvalho Chehab return 0; 5850c0d06caSMauro Carvalho Chehab } 5860c0d06caSMauro Carvalho Chehab 5870c0d06caSMauro Carvalho Chehab static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) 5880c0d06caSMauro Carvalho Chehab { 5890c0d06caSMauro Carvalho Chehab u8 data[2]; 5900c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5910c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 5920c0d06caSMauro Carvalho Chehab 5930c0d06caSMauro Carvalho Chehab sensor_settings[RED_BALANCE_IDX] = val; 5940c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 5950c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 5960c0d06caSMauro Carvalho Chehab 5970c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Set red balance %d", val); 5980c0d06caSMauro Carvalho Chehab 5990c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, 6000c0d06caSMauro Carvalho Chehab data, 2); 6010c0d06caSMauro Carvalho Chehab } 6020c0d06caSMauro Carvalho Chehab 6030c0d06caSMauro Carvalho Chehab static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) 6040c0d06caSMauro Carvalho Chehab { 6050c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 6060c0d06caSMauro Carvalho Chehab s32 *sensor_settings = sd->sensor_priv; 6070c0d06caSMauro Carvalho Chehab 6080c0d06caSMauro Carvalho Chehab *val = sensor_settings[RED_BALANCE_IDX]; 6090c0d06caSMauro Carvalho Chehab PDEBUG(D_V4L2, "Read red balance %d", *val); 6100c0d06caSMauro Carvalho Chehab return 0; 6110c0d06caSMauro Carvalho Chehab } 6120c0d06caSMauro Carvalho Chehab 6130c0d06caSMauro Carvalho Chehab static void mt9m111_dump_registers(struct sd *sd) 6140c0d06caSMauro Carvalho Chehab { 6150c0d06caSMauro Carvalho Chehab u8 address, value[2] = {0x00, 0x00}; 6160c0d06caSMauro Carvalho Chehab 6170c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 register state\n"); 6180c0d06caSMauro Carvalho Chehab 6190c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 sensor core registers\n"); 6200c0d06caSMauro Carvalho Chehab value[1] = MT9M111_SENSOR_CORE; 6210c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 6220c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 6230c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 6240c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 6250c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 6260c0d06caSMauro Carvalho Chehab } 6270c0d06caSMauro Carvalho Chehab 6280c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 color pipeline registers\n"); 6290c0d06caSMauro Carvalho Chehab value[1] = MT9M111_COLORPIPE; 6300c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 6310c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 6320c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 6330c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 6340c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 6350c0d06caSMauro Carvalho Chehab } 6360c0d06caSMauro Carvalho Chehab 6370c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 camera control registers\n"); 6380c0d06caSMauro Carvalho Chehab value[1] = MT9M111_CAMERA_CONTROL; 6390c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 6400c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 6410c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 6420c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 6430c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 6440c0d06caSMauro Carvalho Chehab } 6450c0d06caSMauro Carvalho Chehab 6460c0d06caSMauro Carvalho Chehab pr_info("mt9m111 register state dump complete\n"); 6470c0d06caSMauro Carvalho Chehab } 648