^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Copyright (c) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/videodev2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/div64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <media/v4l2-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <media/v4l2-ctrls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <media/i2c/mt9v011.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) MODULE_AUTHOR("Mauro Carvalho Chehab");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static int debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) module_param(debug, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) MODULE_PARM_DESC(debug, "Debug level (0-2)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define R00_MT9V011_CHIP_VERSION 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define R01_MT9V011_ROWSTART 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define R02_MT9V011_COLSTART 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define R03_MT9V011_HEIGHT 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define R04_MT9V011_WIDTH 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define R05_MT9V011_HBLANK 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define R06_MT9V011_VBLANK 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define R07_MT9V011_OUT_CTRL 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define R09_MT9V011_SHUTTER_WIDTH 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define R0A_MT9V011_CLK_SPEED 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define R0B_MT9V011_RESTART 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define R0C_MT9V011_SHUTTER_DELAY 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define R0D_MT9V011_RESET 0x0d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define R1E_MT9V011_DIGITAL_ZOOM 0x1e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define R20_MT9V011_READ_MODE 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define R2B_MT9V011_GREEN_1_GAIN 0x2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define R2C_MT9V011_BLUE_GAIN 0x2c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define R2D_MT9V011_RED_GAIN 0x2d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define R2E_MT9V011_GREEN_2_GAIN 0x2e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define R35_MT9V011_GLOBAL_GAIN 0x35
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define RF1_MT9V011_CHIP_ENABLE 0xf1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define MT9V011_VERSION 0x8232
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define MT9V011_REV_B_VERSION 0x8243
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct mt9v011 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct v4l2_subdev sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #ifdef CONFIG_MEDIA_CONTROLLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct media_pad pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct v4l2_ctrl_handler ctrls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned width, height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned xtal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned hflip:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) unsigned vflip:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u16 global_gain, exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) s16 red_bal, blue_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return container_of(sd, struct mt9v011, sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct i2c_client *c = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) __be16 buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int rc, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) rc = i2c_master_send(c, &addr, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (rc != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) v4l2_dbg(0, debug, sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) "i2c i/o error: rc == %d (should be 1)\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) msleep(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) rc = i2c_master_recv(c, (char *)&buffer, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (rc != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) v4l2_dbg(0, debug, sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) "i2c i/o error: rc == %d (should be 2)\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) val = be16_to_cpu(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct i2c_client *c = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) unsigned char buffer[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) buffer[0] = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) buffer[1] = value >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) buffer[2] = value & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) v4l2_dbg(2, debug, sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) rc = i2c_master_send(c, buffer, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (rc != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) v4l2_dbg(0, debug, sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) "i2c i/o error: rc == %d (should be 3)\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct i2c_reg_value {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned char reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u16 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * Values used at the original driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Some values are marked as Reserved at the datasheet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static const struct i2c_reg_value mt9v011_init_default[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) { R0D_MT9V011_RESET, 0x0001 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) { R0D_MT9V011_RESET, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) { R0C_MT9V011_SHUTTER_DELAY, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) { R09_MT9V011_SHUTTER_WIDTH, 0x1fc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) { R0A_MT9V011_CLK_SPEED, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static u16 calc_mt9v011_gain(s16 lineargain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u16 digitalgain = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) u16 analogmult = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) u16 analoginit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (lineargain < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) lineargain = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* recommended minimum */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) lineargain += 0x0020;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (lineargain > 2047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) lineargain = 2047;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (lineargain > 1023) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) digitalgain = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) analogmult = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) analoginit = lineargain / 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) } else if (lineargain > 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) digitalgain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) analogmult = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) analoginit = lineargain / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) } else if (lineargain > 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) analogmult = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) analoginit = lineargain / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) } else if (lineargain > 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) analogmult = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) analoginit = lineargain / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) analoginit = lineargain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return analoginit + (analogmult << 7) + (digitalgain << 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static void set_balance(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) u16 green_gain, blue_gain, red_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) u16 exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) s16 bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) exposure = core->exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) green_gain = calc_mt9v011_gain(core->global_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) bal = core->global_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) bal += (core->blue_bal * core->global_gain / (1 << 7));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) blue_gain = calc_mt9v011_gain(bal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) bal = core->global_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) bal += (core->red_bal * core->global_gain / (1 << 7));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) red_gain = calc_mt9v011_gain(bal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned height, width, hblank, vblank, speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) unsigned row_time, t_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) u64 frames_per_ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) unsigned tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) width = mt9v011_read(sd, R04_MT9V011_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) row_time = (width + 113 + hblank) * (speed + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) t_time = row_time * (height + vblank + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) frames_per_ms = core->xtal * 1000l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) do_div(frames_per_ms, t_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) tmp = frames_per_ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) tmp / 1000, tmp % 1000, t_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (numerator && denominator) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *numerator = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *denominator = (u32)frames_per_ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unsigned height, width, hblank, vblank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) unsigned row_time, line_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) u64 t_time, speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* Avoid bogus calculus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (!numerator || !denominator)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) width = mt9v011_read(sd, R04_MT9V011_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) row_time = width + 113 + hblank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) line_time = height + vblank + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) t_time = core->xtal * ((u64)numerator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* round to the closest value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) t_time += denominator / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) do_div(t_time, denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) speed = t_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) do_div(speed, row_time * line_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* Avoid having a negative value for speed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (speed < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) speed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) speed -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* Avoid speed overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (speed > 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return (u16)speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static void set_res(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) unsigned vstart, hstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * The mt9v011 doesn't have scaling. So, in order to select the desired
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * resolution, we're cropping at the middle of the sensor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * hblank and vblank should be adjusted, in order to warrant that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * we'll preserve the line timings for 30 fps, no matter what resolution
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * is selected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * NOTE: datasheet says that width (and height) should be filled with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * width-1. However, this doesn't work, since one pixel per line will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * be missing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) hstart = 20 + (640 - core->width) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) vstart = 8 + (480 - core->height) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) calc_fps(sd, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static void set_read_mode(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) unsigned mode = 0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (core->hflip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) mode |= 0x4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (core->vflip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) mode |= 0x8000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) mt9v011_write(sd, R20_MT9V011_READ_MODE, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) mt9v011_write(sd, mt9v011_init_default[i].reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) mt9v011_init_default[i].value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) set_balance(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) set_res(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) set_read_mode(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct v4l2_subdev_mbus_code_enum *code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (code->pad || code->index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) code->code = MEDIA_BUS_FMT_SGRBG8_1X8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static int mt9v011_set_fmt(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct v4l2_subdev_format *format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct v4l2_mbus_framefmt *fmt = &format->format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (format->pad || fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) v4l_bound_align_image(&fmt->width, 48, 639, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) &fmt->height, 32, 480, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) fmt->field = V4L2_FIELD_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) fmt->colorspace = V4L2_COLORSPACE_SRGB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) core->width = fmt->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) core->height = fmt->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) set_res(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) cfg->try_fmt = *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct v4l2_subdev_frame_interval *ival)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) calc_fps(sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) &ival->interval.numerator,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) &ival->interval.denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) struct v4l2_subdev_frame_interval *ival)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct v4l2_fract *tpf = &ival->interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) u16 speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) speed = calc_speed(sd, tpf->numerator, tpf->denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* Recalculate and update fps info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) calc_fps(sd, &tpf->numerator, &tpf->denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) #ifdef CONFIG_VIDEO_ADV_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static int mt9v011_g_register(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct v4l2_dbg_register *reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) reg->val = mt9v011_read(sd, reg->reg & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) reg->size = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) static int mt9v011_s_register(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) const struct v4l2_dbg_register *reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct mt9v011 *core =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) container_of(ctrl->handler, struct mt9v011, ctrls);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct v4l2_subdev *sd = &core->sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) switch (ctrl->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case V4L2_CID_GAIN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) core->global_gain = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case V4L2_CID_EXPOSURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) core->exposure = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) case V4L2_CID_RED_BALANCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) core->red_bal = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) case V4L2_CID_BLUE_BALANCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) core->blue_bal = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) case V4L2_CID_HFLIP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) core->hflip = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) set_read_mode(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) case V4L2_CID_VFLIP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) core->vflip = ctrl->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) set_read_mode(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) set_balance(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static const struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) .s_ctrl = mt9v011_s_ctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) .reset = mt9v011_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) #ifdef CONFIG_VIDEO_ADV_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) .g_register = mt9v011_g_register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) .s_register = mt9v011_s_register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) .g_frame_interval = mt9v011_g_frame_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) .s_frame_interval = mt9v011_s_frame_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .enum_mbus_code = mt9v011_enum_mbus_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) .set_fmt = mt9v011_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) static const struct v4l2_subdev_ops mt9v011_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) .core = &mt9v011_core_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) .video = &mt9v011_video_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) .pad = &mt9v011_pad_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /****************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) I2C Client & Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ****************************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static int mt9v011_probe(struct i2c_client *c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) u16 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct mt9v011 *core;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct v4l2_subdev *sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) #ifdef CONFIG_MEDIA_CONTROLLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /* Check if the adapter supports the needed features */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!i2c_check_functionality(c->adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) core = devm_kzalloc(&c->dev, sizeof(struct mt9v011), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (!core)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) sd = &core->sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) v4l2_i2c_subdev_init(sd, c, &mt9v011_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) #ifdef CONFIG_MEDIA_CONTROLLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) core->pad.flags = MEDIA_PAD_FL_SOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) ret = media_entity_pads_init(&sd->entity, 1, &core->pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /* Check if the sensor is really a MT9V011 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if ((version != MT9V011_VERSION) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) (version != MT9V011_REV_B_VERSION)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) v4l2_ctrl_handler_init(&core->ctrls, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) V4L2_CID_GAIN, 0, (1 << 12) - 1 - 0x20, 1, 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) V4L2_CID_EXPOSURE, 0, 2047, 1, 0x01fc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) V4L2_CID_RED_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) V4L2_CID_BLUE_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) V4L2_CID_HFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) V4L2_CID_VFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (core->ctrls.error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int ret = core->ctrls.error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) v4l2_err(sd, "control initialization error %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) v4l2_ctrl_handler_free(&core->ctrls);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) core->sd.ctrl_handler = &core->ctrls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) core->global_gain = 0x0024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) core->exposure = 0x01fc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) core->width = 640;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) core->height = 480;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) core->xtal = 27000000; /* Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (c->dev.platform_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct mt9v011_platform_data *pdata = c->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) core->xtal = pdata->xtal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) core->xtal / 1000000, (core->xtal / 1000) % 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) c->addr << 1, c->adapter->name, version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) static int mt9v011_remove(struct i2c_client *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct v4l2_subdev *sd = i2c_get_clientdata(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct mt9v011 *core = to_mt9v011(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) v4l2_dbg(1, debug, sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) "mt9v011.c: removing mt9v011 adapter on address 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) c->addr << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) v4l2_device_unregister_subdev(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) v4l2_ctrl_handler_free(&core->ctrls);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /* ----------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static const struct i2c_device_id mt9v011_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) { "mt9v011", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) MODULE_DEVICE_TABLE(i2c, mt9v011_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static struct i2c_driver mt9v011_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) .name = "mt9v011",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) .probe = mt9v011_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) .remove = mt9v011_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) .id_table = mt9v011_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) module_i2c_driver(mt9v011_driver);