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 23c84e412fSHans de Goede static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl); 24c84e412fSHans de Goede static void mt9m111_dump_registers(struct sd *sd); 250c0d06caSMauro Carvalho Chehab 26349e4dc5SMauro Carvalho Chehab static const unsigned char preinit_mt9m111[][4] = { 27349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 28349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 29349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 30349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 31349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 32349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 33349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 34349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 35349e4dc5SMauro Carvalho Chehab 36349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, 37349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_RESET, 38349e4dc5SMauro Carvalho Chehab MT9M111_RESET | 39349e4dc5SMauro Carvalho Chehab MT9M111_RESTART | 40349e4dc5SMauro Carvalho Chehab MT9M111_ANALOG_STANDBY | 41349e4dc5SMauro Carvalho Chehab MT9M111_CHIP_DISABLE, 42349e4dc5SMauro Carvalho Chehab MT9M111_SHOW_BAD_FRAMES | 43349e4dc5SMauro Carvalho Chehab MT9M111_RESTART_BAD_FRAMES | 44349e4dc5SMauro Carvalho Chehab MT9M111_SYNCHRONIZE_CHANGES}, 45349e4dc5SMauro Carvalho Chehab 46349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, 47349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, 48349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, 49349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, 50349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, 51349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 52349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 53349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 54349e4dc5SMauro Carvalho Chehab 55349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 56349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 57349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, 58349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, 59349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 60349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 61349e4dc5SMauro Carvalho Chehab 62349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00} 63349e4dc5SMauro Carvalho Chehab }; 64349e4dc5SMauro Carvalho Chehab 65349e4dc5SMauro Carvalho Chehab static const unsigned char init_mt9m111[][4] = { 66349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 67349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 68349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 69349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 70349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 71349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 72349e4dc5SMauro Carvalho Chehab 73349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 74349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 75349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, 76349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, 77349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 78349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, 79349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 80349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, 81349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, 82349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, 83349e4dc5SMauro Carvalho Chehab 84349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, 85349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, 86349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, 87349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, 88349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 89349e4dc5SMauro Carvalho Chehab MT9M111_CP_OPERATING_MODE_CTL}, 90349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, 91349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 92349e4dc5SMauro Carvalho Chehab MT9M111_2D_DEFECT_CORRECTION_ENABLE}, 93349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 94349e4dc5SMauro Carvalho Chehab MT9M111_2D_DEFECT_CORRECTION_ENABLE}, 95349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, 96349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, 97349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, 98349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, 99349e4dc5SMauro Carvalho Chehab {SENSOR, 0xcd, 0x00, 0x0e}, 100349e4dc5SMauro Carvalho Chehab {SENSOR, 0xd0, 0x00, 0x40}, 101349e4dc5SMauro Carvalho Chehab 102349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, 103349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, 104349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, 105349e4dc5SMauro Carvalho Chehab 106349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, 107349e4dc5SMauro Carvalho Chehab {SENSOR, 0x33, 0x03, 0x49}, 108349e4dc5SMauro Carvalho Chehab {SENSOR, 0x34, 0xc0, 0x19}, 109349e4dc5SMauro Carvalho Chehab {SENSOR, 0x3f, 0x20, 0x20}, 110349e4dc5SMauro Carvalho Chehab {SENSOR, 0x40, 0x20, 0x20}, 111349e4dc5SMauro Carvalho Chehab {SENSOR, 0x5a, 0xc0, 0x0a}, 112349e4dc5SMauro Carvalho Chehab {SENSOR, 0x70, 0x7b, 0x0a}, 113349e4dc5SMauro Carvalho Chehab {SENSOR, 0x71, 0xff, 0x00}, 114349e4dc5SMauro Carvalho Chehab {SENSOR, 0x72, 0x19, 0x0e}, 115349e4dc5SMauro Carvalho Chehab {SENSOR, 0x73, 0x18, 0x0f}, 116349e4dc5SMauro Carvalho Chehab {SENSOR, 0x74, 0x57, 0x32}, 117349e4dc5SMauro Carvalho Chehab {SENSOR, 0x75, 0x56, 0x34}, 118349e4dc5SMauro Carvalho Chehab {SENSOR, 0x76, 0x73, 0x35}, 119349e4dc5SMauro Carvalho Chehab {SENSOR, 0x77, 0x30, 0x12}, 120349e4dc5SMauro Carvalho Chehab {SENSOR, 0x78, 0x79, 0x02}, 121349e4dc5SMauro Carvalho Chehab {SENSOR, 0x79, 0x75, 0x06}, 122349e4dc5SMauro Carvalho Chehab {SENSOR, 0x7a, 0x77, 0x0a}, 123349e4dc5SMauro Carvalho Chehab {SENSOR, 0x7b, 0x78, 0x09}, 124349e4dc5SMauro Carvalho Chehab {SENSOR, 0x7c, 0x7d, 0x06}, 125349e4dc5SMauro Carvalho Chehab {SENSOR, 0x7d, 0x31, 0x10}, 126349e4dc5SMauro Carvalho Chehab {SENSOR, 0x7e, 0x00, 0x7e}, 127349e4dc5SMauro Carvalho Chehab {SENSOR, 0x80, 0x59, 0x04}, 128349e4dc5SMauro Carvalho Chehab {SENSOR, 0x81, 0x59, 0x04}, 129349e4dc5SMauro Carvalho Chehab {SENSOR, 0x82, 0x57, 0x0a}, 130349e4dc5SMauro Carvalho Chehab {SENSOR, 0x83, 0x58, 0x0b}, 131349e4dc5SMauro Carvalho Chehab {SENSOR, 0x84, 0x47, 0x0c}, 132349e4dc5SMauro Carvalho Chehab {SENSOR, 0x85, 0x48, 0x0e}, 133349e4dc5SMauro Carvalho Chehab {SENSOR, 0x86, 0x5b, 0x02}, 134349e4dc5SMauro Carvalho Chehab {SENSOR, 0x87, 0x00, 0x5c}, 135349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B}, 136349e4dc5SMauro Carvalho Chehab {SENSOR, 0x60, 0x00, 0x80}, 137349e4dc5SMauro Carvalho Chehab {SENSOR, 0x61, 0x00, 0x00}, 138349e4dc5SMauro Carvalho Chehab {SENSOR, 0x62, 0x00, 0x00}, 139349e4dc5SMauro Carvalho Chehab {SENSOR, 0x63, 0x00, 0x00}, 140349e4dc5SMauro Carvalho Chehab {SENSOR, 0x64, 0x00, 0x00}, 141349e4dc5SMauro Carvalho Chehab 142349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */ 143349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */ 144349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */ 145349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */ 146349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */ 147349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */ 148349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */ 149349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */ 150349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */ 151349e4dc5SMauro Carvalho Chehab {SENSOR, 0x30, 0x04, 0x00}, 152349e4dc5SMauro Carvalho Chehab /* Set number of blank rows chosen to 400 */ 153349e4dc5SMauro Carvalho Chehab {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, 154349e4dc5SMauro Carvalho Chehab }; 155349e4dc5SMauro Carvalho Chehab 156349e4dc5SMauro Carvalho Chehab static const unsigned char start_mt9m111[][4] = { 157349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 158349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 159349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 160349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 161349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 162349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 163349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 164349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 165349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 166349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 167349e4dc5SMauro Carvalho Chehab {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 168349e4dc5SMauro Carvalho Chehab }; 169349e4dc5SMauro Carvalho Chehab 1700c0d06caSMauro Carvalho Chehab static struct v4l2_pix_format mt9m111_modes[] = { 1710c0d06caSMauro Carvalho Chehab { 1720c0d06caSMauro Carvalho Chehab 640, 1730c0d06caSMauro Carvalho Chehab 480, 1740c0d06caSMauro Carvalho Chehab V4L2_PIX_FMT_SBGGR8, 1750c0d06caSMauro Carvalho Chehab V4L2_FIELD_NONE, 1760c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480, 1770c0d06caSMauro Carvalho Chehab .bytesperline = 640, 1780c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 1790c0d06caSMauro Carvalho Chehab .priv = 0 1800c0d06caSMauro Carvalho Chehab } 1810c0d06caSMauro Carvalho Chehab }; 1820c0d06caSMauro Carvalho Chehab 183c84e412fSHans de Goede static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { 184c84e412fSHans de Goede .s_ctrl = mt9m111_s_ctrl, 1850c0d06caSMauro Carvalho Chehab }; 1860c0d06caSMauro Carvalho Chehab 187c84e412fSHans de Goede static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { 188c84e412fSHans de Goede .ops = &mt9m111_ctrl_ops, 189c84e412fSHans de Goede .id = M5602_V4L2_CID_GREEN_BALANCE, 190c84e412fSHans de Goede .name = "Green Balance", 191c84e412fSHans de Goede .type = V4L2_CTRL_TYPE_INTEGER, 192c84e412fSHans de Goede .min = 0, 193c84e412fSHans de Goede .max = 0x7ff, 194c84e412fSHans de Goede .step = 1, 195c84e412fSHans de Goede .def = MT9M111_GREEN_GAIN_DEFAULT, 196c84e412fSHans de Goede .flags = V4L2_CTRL_FLAG_SLIDER, 197c84e412fSHans de Goede }; 1980c0d06caSMauro Carvalho Chehab 1990c0d06caSMauro Carvalho Chehab int mt9m111_probe(struct sd *sd) 2000c0d06caSMauro Carvalho Chehab { 2010c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 2020c0d06caSMauro Carvalho Chehab int i; 203c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 2040c0d06caSMauro Carvalho Chehab 2050c0d06caSMauro Carvalho Chehab if (force_sensor) { 2060c0d06caSMauro Carvalho Chehab if (force_sensor == MT9M111_SENSOR) { 2070c0d06caSMauro Carvalho Chehab pr_info("Forcing a %s sensor\n", mt9m111.name); 2080c0d06caSMauro Carvalho Chehab goto sensor_found; 2090c0d06caSMauro Carvalho Chehab } 2100c0d06caSMauro Carvalho Chehab /* If we want to force another sensor, don't try to probe this 2110c0d06caSMauro Carvalho Chehab * one */ 2120c0d06caSMauro Carvalho Chehab return -ENODEV; 2130c0d06caSMauro Carvalho Chehab } 2140c0d06caSMauro Carvalho Chehab 21537d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Probing for a mt9m111 sensor\n"); 2160c0d06caSMauro Carvalho Chehab 2170c0d06caSMauro Carvalho Chehab /* Do the preinit */ 2180c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { 2190c0d06caSMauro Carvalho Chehab if (preinit_mt9m111[i][0] == BRIDGE) { 2200c0d06caSMauro Carvalho Chehab m5602_write_bridge(sd, 2210c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][1], 2220c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][2]); 2230c0d06caSMauro Carvalho Chehab } else { 2240c0d06caSMauro Carvalho Chehab data[0] = preinit_mt9m111[i][2]; 2250c0d06caSMauro Carvalho Chehab data[1] = preinit_mt9m111[i][3]; 2260c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, 2270c0d06caSMauro Carvalho Chehab preinit_mt9m111[i][1], data, 2); 2280c0d06caSMauro Carvalho Chehab } 2290c0d06caSMauro Carvalho Chehab } 2300c0d06caSMauro Carvalho Chehab 2310c0d06caSMauro Carvalho Chehab if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) 2320c0d06caSMauro Carvalho Chehab return -ENODEV; 2330c0d06caSMauro Carvalho Chehab 2340c0d06caSMauro Carvalho Chehab if ((data[0] == 0x14) && (data[1] == 0x3a)) { 2350c0d06caSMauro Carvalho Chehab pr_info("Detected a mt9m111 sensor\n"); 2360c0d06caSMauro Carvalho Chehab goto sensor_found; 2370c0d06caSMauro Carvalho Chehab } 2380c0d06caSMauro Carvalho Chehab 2390c0d06caSMauro Carvalho Chehab return -ENODEV; 2400c0d06caSMauro Carvalho Chehab 2410c0d06caSMauro Carvalho Chehab sensor_found: 2420c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.cam_mode = mt9m111_modes; 2430c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); 2440c0d06caSMauro Carvalho Chehab 2450c0d06caSMauro Carvalho Chehab return 0; 2460c0d06caSMauro Carvalho Chehab } 2470c0d06caSMauro Carvalho Chehab 2480c0d06caSMauro Carvalho Chehab int mt9m111_init(struct sd *sd) 2490c0d06caSMauro Carvalho Chehab { 2500c0d06caSMauro Carvalho Chehab int i, err = 0; 2510c0d06caSMauro Carvalho Chehab 2520c0d06caSMauro Carvalho Chehab /* Init the sensor */ 2530c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { 2540c0d06caSMauro Carvalho Chehab u8 data[2]; 2550c0d06caSMauro Carvalho Chehab 2560c0d06caSMauro Carvalho Chehab if (init_mt9m111[i][0] == BRIDGE) { 2570c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, 2580c0d06caSMauro Carvalho Chehab init_mt9m111[i][1], 2590c0d06caSMauro Carvalho Chehab init_mt9m111[i][2]); 2600c0d06caSMauro Carvalho Chehab } else { 2610c0d06caSMauro Carvalho Chehab data[0] = init_mt9m111[i][2]; 2620c0d06caSMauro Carvalho Chehab data[1] = init_mt9m111[i][3]; 2630c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 2640c0d06caSMauro Carvalho Chehab init_mt9m111[i][1], data, 2); 2650c0d06caSMauro Carvalho Chehab } 2660c0d06caSMauro Carvalho Chehab } 2670c0d06caSMauro Carvalho Chehab 2680c0d06caSMauro Carvalho Chehab if (dump_sensor) 2690c0d06caSMauro Carvalho Chehab mt9m111_dump_registers(sd); 2700c0d06caSMauro Carvalho Chehab 271c84e412fSHans de Goede return 0; 272c84e412fSHans de Goede } 2730c0d06caSMauro Carvalho Chehab 274c84e412fSHans de Goede int mt9m111_init_controls(struct sd *sd) 275c84e412fSHans de Goede { 276c84e412fSHans de Goede struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 2770c0d06caSMauro Carvalho Chehab 278c84e412fSHans de Goede sd->gspca_dev.vdev.ctrl_handler = hdl; 279c84e412fSHans de Goede v4l2_ctrl_handler_init(hdl, 7); 2800c0d06caSMauro Carvalho Chehab 281c84e412fSHans de Goede sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, 282c84e412fSHans de Goede V4L2_CID_AUTO_WHITE_BALANCE, 283c84e412fSHans de Goede 0, 1, 1, 0); 284c84e412fSHans de Goede sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL); 285c84e412fSHans de Goede sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, 286c84e412fSHans de Goede V4L2_CID_RED_BALANCE, 0, 0x7ff, 1, 287c84e412fSHans de Goede MT9M111_RED_GAIN_DEFAULT); 288c84e412fSHans de Goede sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, 289c84e412fSHans de Goede V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1, 290c84e412fSHans de Goede MT9M111_BLUE_GAIN_DEFAULT); 2910c0d06caSMauro Carvalho Chehab 292c84e412fSHans de Goede v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0, 293c84e412fSHans de Goede (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1, 294c84e412fSHans de Goede MT9M111_DEFAULT_GAIN); 2950c0d06caSMauro Carvalho Chehab 296c84e412fSHans de Goede sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP, 297c84e412fSHans de Goede 0, 1, 1, 0); 298c84e412fSHans de Goede sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP, 299c84e412fSHans de Goede 0, 1, 1, 0); 300c84e412fSHans de Goede 301c84e412fSHans de Goede if (hdl->error) { 302c84e412fSHans de Goede pr_err("Could not initialize controls\n"); 303c84e412fSHans de Goede return hdl->error; 304c84e412fSHans de Goede } 305c84e412fSHans de Goede 306c84e412fSHans de Goede v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false); 307c84e412fSHans de Goede v4l2_ctrl_cluster(2, &sd->hflip); 308c84e412fSHans de Goede 309c84e412fSHans de Goede return 0; 3100c0d06caSMauro Carvalho Chehab } 3110c0d06caSMauro Carvalho Chehab 3120c0d06caSMauro Carvalho Chehab int mt9m111_start(struct sd *sd) 3130c0d06caSMauro Carvalho Chehab { 3140c0d06caSMauro Carvalho Chehab int i, err = 0; 3150c0d06caSMauro Carvalho Chehab u8 data[2]; 3160c0d06caSMauro Carvalho Chehab struct cam *cam = &sd->gspca_dev.cam; 317c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 3180c0d06caSMauro Carvalho Chehab 3190c0d06caSMauro Carvalho Chehab int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; 3200c0d06caSMauro Carvalho Chehab int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; 3210c0d06caSMauro Carvalho Chehab 3220c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { 3230c0d06caSMauro Carvalho Chehab if (start_mt9m111[i][0] == BRIDGE) { 3240c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, 3250c0d06caSMauro Carvalho Chehab start_mt9m111[i][1], 3260c0d06caSMauro Carvalho Chehab start_mt9m111[i][2]); 3270c0d06caSMauro Carvalho Chehab } else { 3280c0d06caSMauro Carvalho Chehab data[0] = start_mt9m111[i][2]; 3290c0d06caSMauro Carvalho Chehab data[1] = start_mt9m111[i][3]; 3300c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, 3310c0d06caSMauro Carvalho Chehab start_mt9m111[i][1], data, 2); 3320c0d06caSMauro Carvalho Chehab } 3330c0d06caSMauro Carvalho Chehab } 3340c0d06caSMauro Carvalho Chehab if (err < 0) 3350c0d06caSMauro Carvalho Chehab return err; 3360c0d06caSMauro Carvalho Chehab 3370c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); 3380c0d06caSMauro Carvalho Chehab if (err < 0) 3390c0d06caSMauro Carvalho Chehab return err; 3400c0d06caSMauro Carvalho Chehab 3410c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); 3420c0d06caSMauro Carvalho Chehab if (err < 0) 3430c0d06caSMauro Carvalho Chehab return err; 3440c0d06caSMauro Carvalho Chehab 3450c0d06caSMauro Carvalho Chehab for (i = 0; i < 2 && !err; i++) 3460c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); 3470c0d06caSMauro Carvalho Chehab if (err < 0) 3480c0d06caSMauro Carvalho Chehab return err; 3490c0d06caSMauro Carvalho Chehab 3500c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 3510c0d06caSMauro Carvalho Chehab if (err < 0) 3520c0d06caSMauro Carvalho Chehab return err; 3530c0d06caSMauro Carvalho Chehab 3540c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); 3550c0d06caSMauro Carvalho Chehab if (err < 0) 3560c0d06caSMauro Carvalho Chehab return err; 3570c0d06caSMauro Carvalho Chehab 3580c0d06caSMauro Carvalho Chehab for (i = 0; i < 2 && !err; i++) 3590c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); 3600c0d06caSMauro Carvalho Chehab if (err < 0) 3610c0d06caSMauro Carvalho Chehab return err; 3620c0d06caSMauro Carvalho Chehab 3630c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 3640c0d06caSMauro Carvalho Chehab (width >> 8) & 0xff); 3650c0d06caSMauro Carvalho Chehab if (err < 0) 3660c0d06caSMauro Carvalho Chehab return err; 3670c0d06caSMauro Carvalho Chehab 3680c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); 3690c0d06caSMauro Carvalho Chehab if (err < 0) 3700c0d06caSMauro Carvalho Chehab return err; 3710c0d06caSMauro Carvalho Chehab 3720c0d06caSMauro Carvalho Chehab err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 3730c0d06caSMauro Carvalho Chehab if (err < 0) 3740c0d06caSMauro Carvalho Chehab return err; 3750c0d06caSMauro Carvalho Chehab 3760c0d06caSMauro Carvalho Chehab switch (width) { 3770c0d06caSMauro Carvalho Chehab case 640: 37837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n"); 3790c0d06caSMauro Carvalho Chehab break; 3800c0d06caSMauro Carvalho Chehab 3810c0d06caSMauro Carvalho Chehab case 320: 38237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Configuring camera for QVGA mode\n"); 3830c0d06caSMauro Carvalho Chehab break; 3840c0d06caSMauro Carvalho Chehab } 3850c0d06caSMauro Carvalho Chehab return err; 3860c0d06caSMauro Carvalho Chehab } 3870c0d06caSMauro Carvalho Chehab 3880c0d06caSMauro Carvalho Chehab void mt9m111_disconnect(struct sd *sd) 3890c0d06caSMauro Carvalho Chehab { 3900c0d06caSMauro Carvalho Chehab sd->sensor = NULL; 3910c0d06caSMauro Carvalho Chehab } 3920c0d06caSMauro Carvalho Chehab 393c84e412fSHans de Goede static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev) 3940c0d06caSMauro Carvalho Chehab { 3950c0d06caSMauro Carvalho Chehab int err; 3960c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 3970c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 398c84e412fSHans de Goede int hflip; 399c84e412fSHans de Goede int vflip; 4000c0d06caSMauro Carvalho Chehab 40137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Set hvflip to %d %d\n", 40237d5efb0SJoe Perches sd->hflip->val, sd->vflip->val); 4030c0d06caSMauro Carvalho Chehab 4040c0d06caSMauro Carvalho Chehab /* The mt9m111 is flipped by default */ 405c84e412fSHans de Goede hflip = !sd->hflip->val; 406c84e412fSHans de Goede vflip = !sd->vflip->val; 4070c0d06caSMauro Carvalho Chehab 4080c0d06caSMauro Carvalho Chehab /* Set the correct page map */ 4090c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 4100c0d06caSMauro Carvalho Chehab if (err < 0) 4110c0d06caSMauro Carvalho Chehab return err; 4120c0d06caSMauro Carvalho Chehab 413c84e412fSHans de Goede data[0] = MT9M111_RMB_OVER_SIZED; 4141966bc2aSOndrej Zary if (gspca_dev->pixfmt.width == 640) { 415c84e412fSHans de Goede data[1] = MT9M111_RMB_ROW_SKIP_2X | 416c84e412fSHans de Goede MT9M111_RMB_COLUMN_SKIP_2X | 417c84e412fSHans de Goede (hflip << 1) | vflip; 418c84e412fSHans de Goede } else { 419c84e412fSHans de Goede data[1] = MT9M111_RMB_ROW_SKIP_4X | 420c84e412fSHans de Goede MT9M111_RMB_COLUMN_SKIP_4X | 421c84e412fSHans de Goede (hflip << 1) | vflip; 422c84e412fSHans de Goede } 4230c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, 4240c0d06caSMauro Carvalho Chehab data, 2); 4250c0d06caSMauro Carvalho Chehab return err; 4260c0d06caSMauro Carvalho Chehab } 4270c0d06caSMauro Carvalho Chehab 4280c0d06caSMauro Carvalho Chehab static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, 4290c0d06caSMauro Carvalho Chehab __s32 val) 4300c0d06caSMauro Carvalho Chehab { 4310c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4320c0d06caSMauro Carvalho Chehab int err; 4330c0d06caSMauro Carvalho Chehab u8 data[2]; 4340c0d06caSMauro Carvalho Chehab 4350c0d06caSMauro Carvalho Chehab err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 4360c0d06caSMauro Carvalho Chehab if (err < 0) 4370c0d06caSMauro Carvalho Chehab return err; 4380c0d06caSMauro Carvalho Chehab 4390c0d06caSMauro Carvalho Chehab data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); 4400c0d06caSMauro Carvalho Chehab 4410c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 4420c0d06caSMauro Carvalho Chehab 44337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Set auto white balance %d\n", val); 4440c0d06caSMauro Carvalho Chehab return err; 4450c0d06caSMauro Carvalho Chehab } 4460c0d06caSMauro Carvalho Chehab 4470c0d06caSMauro Carvalho Chehab static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) 4480c0d06caSMauro Carvalho Chehab { 4490c0d06caSMauro Carvalho Chehab int err, tmp; 4500c0d06caSMauro Carvalho Chehab u8 data[2] = {0x00, 0x00}; 4510c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4520c0d06caSMauro Carvalho Chehab 4530c0d06caSMauro Carvalho Chehab /* Set the correct page map */ 4540c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 4550c0d06caSMauro Carvalho Chehab if (err < 0) 4560c0d06caSMauro Carvalho Chehab return err; 4570c0d06caSMauro Carvalho Chehab 4580c0d06caSMauro Carvalho Chehab if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) 4590c0d06caSMauro Carvalho Chehab return -EINVAL; 4600c0d06caSMauro Carvalho Chehab 4610c0d06caSMauro Carvalho Chehab if ((val >= INITIAL_MAX_GAIN * 2 * 2) && 4620c0d06caSMauro Carvalho Chehab (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) 4630c0d06caSMauro Carvalho Chehab tmp = (1 << 10) | (val << 9) | 4640c0d06caSMauro Carvalho Chehab (val << 8) | (val / 8); 4650c0d06caSMauro Carvalho Chehab else if ((val >= INITIAL_MAX_GAIN * 2) && 4660c0d06caSMauro Carvalho Chehab (val < INITIAL_MAX_GAIN * 2 * 2)) 4670c0d06caSMauro Carvalho Chehab tmp = (1 << 9) | (1 << 8) | (val / 4); 4680c0d06caSMauro Carvalho Chehab else if ((val >= INITIAL_MAX_GAIN) && 4690c0d06caSMauro Carvalho Chehab (val < INITIAL_MAX_GAIN * 2)) 4700c0d06caSMauro Carvalho Chehab tmp = (1 << 8) | (val / 2); 4710c0d06caSMauro Carvalho Chehab else 4720c0d06caSMauro Carvalho Chehab tmp = val; 4730c0d06caSMauro Carvalho Chehab 4740c0d06caSMauro Carvalho Chehab data[1] = (tmp & 0xff); 4750c0d06caSMauro Carvalho Chehab data[0] = (tmp & 0xff00) >> 8; 47637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "tmp=%d, data[1]=%d, data[0]=%d\n", tmp, 4770c0d06caSMauro Carvalho Chehab data[1], data[0]); 4780c0d06caSMauro Carvalho Chehab 4790c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, 4800c0d06caSMauro Carvalho Chehab data, 2); 4810c0d06caSMauro Carvalho Chehab 4820c0d06caSMauro Carvalho Chehab return err; 4830c0d06caSMauro Carvalho Chehab } 4840c0d06caSMauro Carvalho Chehab 4850c0d06caSMauro Carvalho Chehab static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) 4860c0d06caSMauro Carvalho Chehab { 4870c0d06caSMauro Carvalho Chehab int err; 4880c0d06caSMauro Carvalho Chehab u8 data[2]; 4890c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4900c0d06caSMauro Carvalho Chehab 4910c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 4920c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 4930c0d06caSMauro Carvalho Chehab 49437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Set green balance %d\n", val); 4950c0d06caSMauro Carvalho Chehab err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, 4960c0d06caSMauro Carvalho Chehab data, 2); 4970c0d06caSMauro Carvalho Chehab if (err < 0) 4980c0d06caSMauro Carvalho Chehab return err; 4990c0d06caSMauro Carvalho Chehab 5000c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, 5010c0d06caSMauro Carvalho Chehab data, 2); 5020c0d06caSMauro Carvalho Chehab } 5030c0d06caSMauro Carvalho Chehab 5040c0d06caSMauro Carvalho Chehab static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) 5050c0d06caSMauro Carvalho Chehab { 5060c0d06caSMauro Carvalho Chehab u8 data[2]; 5070c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5080c0d06caSMauro Carvalho Chehab 5090c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 5100c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 5110c0d06caSMauro Carvalho Chehab 51237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Set blue balance %d\n", val); 5130c0d06caSMauro Carvalho Chehab 5140c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, 5150c0d06caSMauro Carvalho Chehab data, 2); 5160c0d06caSMauro Carvalho Chehab } 5170c0d06caSMauro Carvalho Chehab 5180c0d06caSMauro Carvalho Chehab static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) 5190c0d06caSMauro Carvalho Chehab { 5200c0d06caSMauro Carvalho Chehab u8 data[2]; 5210c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 5220c0d06caSMauro Carvalho Chehab 5230c0d06caSMauro Carvalho Chehab data[1] = (val & 0xff); 5240c0d06caSMauro Carvalho Chehab data[0] = (val & 0xff00) >> 8; 5250c0d06caSMauro Carvalho Chehab 52637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_CONF, "Set red balance %d\n", val); 5270c0d06caSMauro Carvalho Chehab 5280c0d06caSMauro Carvalho Chehab return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, 5290c0d06caSMauro Carvalho Chehab data, 2); 5300c0d06caSMauro Carvalho Chehab } 5310c0d06caSMauro Carvalho Chehab 532c84e412fSHans de Goede static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) 5330c0d06caSMauro Carvalho Chehab { 534c84e412fSHans de Goede struct gspca_dev *gspca_dev = 535c84e412fSHans de Goede container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 5360c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 537c84e412fSHans de Goede int err; 5380c0d06caSMauro Carvalho Chehab 539c84e412fSHans de Goede if (!gspca_dev->streaming) 5400c0d06caSMauro Carvalho Chehab return 0; 541c84e412fSHans de Goede 542c84e412fSHans de Goede switch (ctrl->id) { 543c84e412fSHans de Goede case V4L2_CID_AUTO_WHITE_BALANCE: 544c84e412fSHans de Goede err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val); 545c84e412fSHans de Goede if (err || ctrl->val) 546c84e412fSHans de Goede return err; 547c84e412fSHans de Goede err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val); 548c84e412fSHans de Goede if (err) 549c84e412fSHans de Goede return err; 550c84e412fSHans de Goede err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val); 551c84e412fSHans de Goede if (err) 552c84e412fSHans de Goede return err; 553c84e412fSHans de Goede err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val); 554c84e412fSHans de Goede break; 555c84e412fSHans de Goede case V4L2_CID_GAIN: 556c84e412fSHans de Goede err = mt9m111_set_gain(gspca_dev, ctrl->val); 557c84e412fSHans de Goede break; 558c84e412fSHans de Goede case V4L2_CID_HFLIP: 559c84e412fSHans de Goede err = mt9m111_set_hvflip(gspca_dev); 560c84e412fSHans de Goede break; 561c84e412fSHans de Goede default: 562c84e412fSHans de Goede return -EINVAL; 563c84e412fSHans de Goede } 564c84e412fSHans de Goede 565c84e412fSHans de Goede return err; 5660c0d06caSMauro Carvalho Chehab } 5670c0d06caSMauro Carvalho Chehab 5680c0d06caSMauro Carvalho Chehab static void mt9m111_dump_registers(struct sd *sd) 5690c0d06caSMauro Carvalho Chehab { 5700c0d06caSMauro Carvalho Chehab u8 address, value[2] = {0x00, 0x00}; 5710c0d06caSMauro Carvalho Chehab 5720c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 register state\n"); 5730c0d06caSMauro Carvalho Chehab 5740c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 sensor core registers\n"); 5750c0d06caSMauro Carvalho Chehab value[1] = MT9M111_SENSOR_CORE; 5760c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 5770c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 5780c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 5790c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 5800c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 5810c0d06caSMauro Carvalho Chehab } 5820c0d06caSMauro Carvalho Chehab 5830c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 color pipeline registers\n"); 5840c0d06caSMauro Carvalho Chehab value[1] = MT9M111_COLORPIPE; 5850c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 5860c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 5870c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 5880c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 5890c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 5900c0d06caSMauro Carvalho Chehab } 5910c0d06caSMauro Carvalho Chehab 5920c0d06caSMauro Carvalho Chehab pr_info("Dumping the mt9m111 camera control registers\n"); 5930c0d06caSMauro Carvalho Chehab value[1] = MT9M111_CAMERA_CONTROL; 5940c0d06caSMauro Carvalho Chehab m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 5950c0d06caSMauro Carvalho Chehab for (address = 0; address < 0xff; address++) { 5960c0d06caSMauro Carvalho Chehab m5602_read_sensor(sd, address, value, 2); 5970c0d06caSMauro Carvalho Chehab pr_info("register 0x%x contains 0x%x%x\n", 5980c0d06caSMauro Carvalho Chehab address, value[0], value[1]); 5990c0d06caSMauro Carvalho Chehab } 6000c0d06caSMauro Carvalho Chehab 6010c0d06caSMauro Carvalho Chehab pr_info("mt9m111 register state dump complete\n"); 6020c0d06caSMauro Carvalho Chehab } 603