diff options
author | Pavel <pavel@ucw.cz> | 2018-10-28 15:52:09 +0100 |
---|---|---|
committer | Pavel <pavel@ucw.cz> | 2019-01-07 11:23:40 +0100 |
commit | 69b1dc946d3f760f700af7b3e3552bf4afd036d5 (patch) | |
tree | 8cc5db77f5568819ba58f9e21efe208977042b0f | |
parent | f92729ff3e9e44a5fb158cb156a16ee608cafb27 (diff) | |
download | linux-k-69b1dc946d3f760f700af7b3e3552bf4afd036d5.tar.gz |
n900: camera -- attempt to understand et8ek8 modes. Not too
successful.
-rw-r--r-- | drivers/media/i2c/et8ek8/et8ek8_driver.c | 255 | ||||
-rw-r--r-- | drivers/media/i2c/et8ek8/et8ek8_mode.c | 114 | ||||
-rw-r--r-- | drivers/media/i2c/et8ek8/et8ek8_reg.h | 18 |
3 files changed, 352 insertions, 35 deletions
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 37ef38947e018..72e89ac5561f4 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -58,6 +58,8 @@ struct et8ek8_sensor { struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *exposure; + struct v4l2_ctrl *exposure_abs; + u32 cur_exposure; struct v4l2_ctrl *pixel_rate; struct et8ek8_reglist *current_reglist; @@ -355,13 +357,14 @@ static int et8ek8_i2c_write_reg(struct i2c_client *client, u16 data_length, et8ek8_i2c_create_msg(client, data_length, reg, val, &msg, data); r = i2c_transfer(client->adapter, &msg, 1); - if (r < 0) { + + if (r < 0) dev_err(&client->dev, "wrote 0x%x to offset 0x%x error %d\n", val, reg, r); - return r; - } + else + r = 0; /* on success i2c_transfer() returns messages trasfered */ - return 0; + return r; } static struct et8ek8_reglist *et8ek8_reglist_find_type( @@ -554,6 +557,65 @@ static int et8ek8_reglist_import(struct i2c_client *client, return 0; } +typedef unsigned int fixpoint8; /* .8 fixed point format. */ + +/* + * Return time of one row in microseconds + * If the sensor is not set to any mode, return zero. + */ +fixpoint8 et8ek8_get_row_time(struct et8ek8_sensor *sensor) +{ + unsigned int clock; /* Pixel clock in Hz>>10 fixed point */ + fixpoint8 rt; /* Row time in .8 fixed point */ + + if (!sensor->current_reglist) + return 0; + + clock = sensor->current_reglist->mode.pixel_clock; + clock = (clock + (1 << 9)) >> 10; + rt = sensor->current_reglist->mode.width * (1000000 >> 2); + rt = (rt + (clock >> 1)) / clock; + + return rt; +} + +/* + * Convert exposure time `us' to rows. Modify `us' to make it to + * correspond to the actual exposure time. + */ +static int et8ek8_exposure_us_to_rows(struct et8ek8_sensor *sensor, u32 *us) +{ + unsigned int rows; /* Exposure value as written to HW (ie. rows) */ + fixpoint8 rt; /* Row time in .8 fixed point */ + + /* Assume that the maximum exposure time is at most ~8 s, + * and the maximum width (with blanking) ~8000 pixels. + * The formula here is in principle as simple as + * rows = exptime / 1e6 / width * pixel_clock + * but to get accurate results while coping with value ranges, + * have to do some fixed point math. + */ + + rt = et8ek8_get_row_time(sensor); + rows = ((*us << 8) + (rt >> 1)) / rt; + + if (rows > sensor->current_reglist->mode.max_exp) + rows = sensor->current_reglist->mode.max_exp; + + /* Set the exposure time to the rounded value */ + *us = (rt * rows + (1 << 7)) >> 8; + + return rows; +} + +/* + * Convert exposure time in rows to microseconds + */ +static int et8ek8_exposure_rows_to_us(struct et8ek8_sensor *sensor, int rows) +{ + return (et8ek8_get_row_time(sensor) * rows + (1 << 7)) >> 8; +} + /* Called to change the V4L2 gain control value. This function * rounds and clamps the given value and updates the V4L2 control value. * If power is on, also updates the sensor analog and digital gains. @@ -645,18 +707,24 @@ static int et8ek8_set_ctrl(struct v4l2_ctrl *ctrl) { struct et8ek8_sensor *sensor = container_of(ctrl->handler, struct et8ek8_sensor, ctrl_handler); + u32 val = ctrl->val; switch (ctrl->id) { case V4L2_CID_GAIN: return et8ek8_set_gain(sensor, ctrl->val); + case V4L2_CID_EXPOSURE_ABSOLUTE: + printk("Set Absolute exposure %d\n", val); + val = et8ek8_exposure_us_to_rows(sensor, &val); + /* Fall through */ + case V4L2_CID_EXPOSURE: { - struct i2c_client *client = - v4l2_get_subdevdata(&sensor->subdev); - + struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); + sensor->cur_exposure = val; + printk("Set exposure %d\n", val); return et8ek8_i2c_write_reg(client, ET8EK8_REG_16BIT, 0x1243, - ctrl->val); + val); } case V4L2_CID_TEST_PATTERN: @@ -670,8 +738,32 @@ static int et8ek8_set_ctrl(struct v4l2_ctrl *ctrl) } } +static int et8ek8_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct et8ek8_sensor *sensor = + container_of(ctrl->handler, struct et8ek8_sensor, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ctrl->val = et8ek8_exposure_rows_to_us(sensor, sensor->cur_exposure); + printk("Get absolute exposure %d\n", ctrl->val); + return 0; + + case V4L2_CID_EXPOSURE: + ctrl->val = sensor->cur_exposure; + printk("Get exposure %d\n", ctrl->val); + return 0; + + default: + return -EINVAL; + } +} + + static const struct v4l2_ctrl_ops et8ek8_ctrl_ops = { .s_ctrl = et8ek8_set_ctrl, + .g_volatile_ctrl = et8ek8_get_ctrl, + }; static const char * const et8ek8_test_pattern_menu[] = { @@ -702,9 +794,17 @@ static int et8ek8_init_controls(struct et8ek8_sensor *sensor) u32 min = 1, max = max_rows; sensor->exposure = - v4l2_ctrl_new_std(&sensor->ctrl_handler, - &et8ek8_ctrl_ops, V4L2_CID_EXPOSURE, - min, max, min, max); + v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops, + V4L2_CID_EXPOSURE, min, max, min, max); + //sensor->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + + min = et8ek8_exposure_rows_to_us(sensor, 1); + max = et8ek8_exposure_rows_to_us(sensor, max); + + sensor->exposure_abs = + v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops, + V4L2_CID_EXPOSURE_ABSOLUTE, min, max, min, max); + //sensor->exposure_abs->flags |= V4L2_CTRL_FLAG_VOLATILE; } /* V4L2_CID_PIXEL_RATE */ @@ -734,7 +834,10 @@ static void et8ek8_update_controls(struct et8ek8_sensor *sensor) u32 min, max, pixel_rate; static const int S = 8; + printk("Updating controls for %d x %d @ %d mode -- %s\n", mode->width, mode->height, mode->pixel_clock, mode->name); + ctrl = sensor->exposure; + printk("Updating controls for %d x %d @ %d mode -- %s\n", mode->width, mode->height, mode->pixel_clock, mode->name); min = 1; max = mode->max_exp; @@ -746,11 +849,137 @@ static void et8ek8_update_controls(struct et8ek8_sensor *sensor) */ pixel_rate = ((mode->pixel_clock + (1 << S) - 1) >> S) + mode->width; pixel_rate = mode->window_width * (pixel_rate - 1) / mode->width; + __v4l2_ctrl_modify_range(sensor->exposure, min, max, min, max); - __v4l2_ctrl_modify_range(ctrl, min, max, min, max); + min = et8ek8_exposure_rows_to_us(sensor, 1); + max = et8ek8_exposure_rows_to_us(sensor, max); + __v4l2_ctrl_modify_range(sensor->exposure_abs, min, max, min, max); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate, pixel_rate << S); } +static int read_8(struct i2c_client *client, unsigned long addr) +{ + int val; + et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, addr, &val); + return val; +} + +static int read_16(struct i2c_client *client, unsigned long addr) +{ + return read_8(client, addr); +} + +static void assert_value(struct i2c_client *client, unsigned long addr, unsigned long val) +{ + unsigned long val2 = read_8(client, addr); + if (val != val2) + printk("et8ek8: assertion check %lx / should be %lx is %lx\n", addr, val, val2); +} + +static void assert(struct i2c_client *client, int v, char *msg) +{ + if (!v) + printk("et8ek8: assertion: %s\n", msg); +} + +static void assert_eq(struct i2c_client *client, int v1, int v2, char *msg) +{ + if (v1 != v2) + printk("et8ek8: assertion: %d == %d %s\n", v1, v2, msg); +} + +static void et8ek8_check(struct et8ek8_sensor *sensor) +{ + /* + 1239 4F # CKVAR_DIV + 1238 02 # CKVAR_DIV[8] CKREF_DIV + 123B 70 # MRCK_DIV LVDSCK_DIV + 123A 05 # VCO_DIV SPCK_DIV + 121B 63 # PIC_SIZE MONI_MODE + 1220 85 # H_COUNT + 1221 00 # H_COUNT[10:8] + 1222 58 # V_COUNT + 1223 00 # V_COUNT[12:8] + 121D 63 # H_SIZE H_INTERMIT + 125D 83 # CCP_LVDS_MODE/ _/ _/ _/ _/ CCP_COMP_MODE[2-0] + */ + struct et8ek8_reglist *r = sensor->current_reglist; + struct v4l2_subdev *subdev = &sensor->subdev; + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int vco; + + printk("Mode validation:\n"); + + assert_value(client, 0x1220, (r->mode.width / 24) & 0xff); + assert_value(client, 0x1221, (r->mode.width / 24) >> 8); + + assert_value(client, 0x1222, (r->mode.height / 24) & 0xff); + assert_value(client, 0x1223, (r->mode.height / 24) >> 8); + + { + int ckref_div = read_16(client, 0x1238) & 0xf; + int ckvar_div = ((read_16(client, 0x1238) & 0x80) >> 7) | (read_16(client, 0x1239) << 1); + int vco_div = read_16(client, 0x123A) >> 4; + int spck_div = read_16(client, 0x123A) & 0xf; + int mrck_div = read_16(client, 0x123B) >> 4; + int lvdsck_div = read_16(client, 0x123B) & 0xf; + int ccp2, spck; + + vco = (r->mode.ext_clock * ckvar_div) / (ckref_div + 1); + printk("Vco is %d, %d %d %d\n", vco, r->mode.ext_clock, ckvar_div, ckref_div); + ccp2 = vco / ((lvdsck_div + 1) * (vco_div + 1)); + spck = vco / ((spck_div + 1) * (vco_div + 1)); + + assert_eq(client, r->mode.pixel_clock, spck, "spck"); + } + + assert_eq(client, r->mode.max_exp, r->mode.height - 4, "max_exp"); + + assert(client, !(r->mode.sensor_window_width % r->mode.window_width), "window_width"); + switch(r->mode.sensor_window_width / r->mode.window_width) { + case 1: assert_value(client, 0x121d, 0x64); + break; + case 2: assert_value(client, 0x121d, 0x63); + break; + case 3: assert_value(client, 0x121d, 0x62); + break; + default: + assert(client, 0, "bad window_width"); + } + + assert(client, !(r->mode.sensor_window_height % r->mode.window_height), "window_width"); + switch(r->mode.sensor_window_height / r->mode.window_height) { + case 1: assert_value(client, 0x121b, 0x64); + break; + case 2: assert_value(client, 0x121b, 0x63); + break; + case 3: assert_value(client, 0x121b, 0x62); + break; + default: + assert(client, 0, "bad window_height"); + } + + //assert(r->mode.height * r->mode.width * fps == r->mode.pixel_clock); + + switch (r->mode.bus_format) { + case MEDIA_BUS_FMT_SGRBG10_1X10: + assert_value(client, 0x125D, 0x88); + assert_eq(client, vco, r->mode.pixel_clock * 8, "vco_clock"); + break; + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: + assert_value(client, 0x125D, 0x83); + assert_eq(client, vco, r->mode.pixel_clock * 6, "vco_clock"); + break; + default: + assert(client, 0, "unexpected bus format"); + + /* There are more possibilities, see + https://github.com/maemo-foss/omap3camera-firmware/blob/master/makemodes-et8ek8.pl + */ + } +} + static int et8ek8_configure(struct et8ek8_sensor *sensor) { struct v4l2_subdev *subdev = &sensor->subdev; @@ -803,6 +1032,8 @@ static int et8ek8_s_stream(struct v4l2_subdev *subdev, int streaming) if (ret < 0) return ret; + et8ek8_check(sensor); + return et8ek8_stream_on(sensor); } diff --git a/drivers/media/i2c/et8ek8/et8ek8_mode.c b/drivers/media/i2c/et8ek8/et8ek8_mode.c index a79882a83885b..981eb37f8b447 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_mode.c +++ b/drivers/media/i2c/et8ek8/et8ek8_mode.c @@ -22,6 +22,11 @@ * Stingray sensor mode settings for Scooby */ +/* https://github.com/maemo-foss/omap3camera-firmware/blob/master/makemodes-et8ek8.pl + + /data/l/maemo/kernel-power/kernel-power-2.6.28/drivers/media/video/et8ek8-modes.h +*/ + /* Mode1_poweron_Mode2_16VGA_2592x1968_12.07fps */ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { /* (without the +1) @@ -39,18 +44,20 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { */ .type = ET8EK8_REGLIST_POWERON, .mode = { - .sensor_width = 2592, - .sensor_height = 1968, + .name = "mode1_poweron_mode2_16vga_2592x1968_12_07fps", + + .sensor_width = 259, + .sensor_height = 196, .sensor_window_origin_x = 0, .sensor_window_origin_y = 0, - .sensor_window_width = 2592, - .sensor_window_height = 1968, - .width = 3288, - .height = 2016, + .sensor_window_width = 259, + .sensor_window_height = 196, + .width = 328, + .height = 201, .window_origin_x = 0, .window_origin_y = 0, - .window_width = 2592, - .window_height = 1968, + .window_width = 259, + .window_height = 196, .pixel_clock = 80000000, .ext_clock = 9600000, .timeperframe = { @@ -108,6 +115,65 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { { ET8EK8_REG_8BIT, 0x1648, 0x00 }, { ET8EK8_REG_8BIT, 0x113E, 0x01 }, { ET8EK8_REG_8BIT, 0x113F, 0x22 }, + /* Settings from here on seem to for the 2592x1968 mode. */ + { ET8EK8_REG_8BIT, 0x1239, 0x64 }, + { ET8EK8_REG_8BIT, 0x1238, 0x02 }, + { ET8EK8_REG_8BIT, 0x123B, 0x70 }, + { ET8EK8_REG_8BIT, 0x123A, 0x07 }, + { ET8EK8_REG_8BIT, 0x121B, 0x64 }, + { ET8EK8_REG_8BIT, 0x121D, 0x64 }, + { ET8EK8_REG_8BIT, 0x1221, 0x00 }, + { ET8EK8_REG_8BIT, 0x1220, 0x89 }, + { ET8EK8_REG_8BIT, 0x1223, 0x00 }, + { ET8EK8_REG_8BIT, 0x1222, 0x54 }, + { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/ */ + { ET8EK8_REG_TERM, 0, 0} + } +}; + +static struct et8ek8_reglist mode2_16vga_2592x1968_12_07fps = { +/* (without the +1) + * SPCK = 80 MHz + * CCP2 = 640 MHz + * VCO = 640 MHz + * VCOUNT = 84 (2016) + * HCOUNT = 137 (3288) + * CKREF_DIV = 2 + * CKVAR_DIV = 200 + * VCO_DIV = 0 + * SPCK_DIV = 7 + * MRCK_DIV = 7 + * LVDSCK_DIV = 0 + */ + .type = ET8EK8_REGLIST_MODE, + .mode = { + .name = "mode2_16vga_2592x1968_12_07fps", + + .sensor_width = 2592, + .sensor_height = 1968, + .sensor_window_origin_x = 0, + .sensor_window_origin_y = 0, + .sensor_window_width = 2592, + .sensor_window_height = 1968, + .width = 3288, + .height = 2016, + .window_origin_x = 0, + .window_origin_y = 0, + .window_width = 2592, + .window_height = 1968, + .pixel_clock = 80000000, + .ext_clock = 9600000, + .timeperframe = { + .numerator = 100, + .denominator = 1207 + }, + .max_exp = 2012, + /* .max_gain = 0, */ + .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10, + .sensitivity = 65536 + }, + .regs = { + /* Settings from here on seem to for the 2592x1968 mode. */ { ET8EK8_REG_8BIT, 0x1239, 0x64 }, { ET8EK8_REG_8BIT, 0x1238, 0x02 }, { ET8EK8_REG_8BIT, 0x123B, 0x70 }, @@ -123,6 +189,7 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { } }; + /* Mode1_16VGA_2592x1968_13.12fps_DPCM10-8 */ static struct et8ek8_reglist mode1_16vga_2592x1968_13_12fps_dpcm10_8 = { /* (without the +1) @@ -140,6 +207,7 @@ static struct et8ek8_reglist mode1_16vga_2592x1968_13_12fps_dpcm10_8 = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode1_16vga_2592x1968_13_12fps_dpcm10_8", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -196,6 +264,7 @@ static struct et8ek8_reglist mode3_4vga_1296x984_29_99fps_dpcm10_8 = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode3_4vga_1296x984_29_99fps_dpcm10_8", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -252,6 +321,7 @@ static struct et8ek8_reglist mode4_svga_864x656_29_88fps = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode4_svga_864x656_29_88fps", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -308,6 +378,7 @@ static struct et8ek8_reglist mode5_vga_648x492_29_93fps = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode5_vga_648x492_29_93fps", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -364,6 +435,7 @@ static struct et8ek8_reglist mode2_16vga_2592x1968_3_99fps = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode2_16vga_2592x1968_3_99fps", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -398,6 +470,7 @@ static struct et8ek8_reglist mode2_16vga_2592x1968_3_99fps = { { ET8EK8_REG_8BIT, 0x1220, 0x89 }, { ET8EK8_REG_8BIT, 0x1223, 0x00 }, { ET8EK8_REG_8BIT, 0x1222, 0xFE }, + { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/ */ { ET8EK8_REG_TERM, 0, 0} } }; @@ -419,6 +492,7 @@ static struct et8ek8_reglist mode_648x492_5fps = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode_648x492_5fps", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -475,6 +549,7 @@ static struct et8ek8_reglist mode3_4vga_1296x984_5fps = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode3_4vga_1296x984_5fps", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -531,6 +606,7 @@ static struct et8ek8_reglist mode_4vga_1296x984_25fps_dpcm10_8 = { */ .type = ET8EK8_REGLIST_MODE, .mode = { + .name = "mode_4vga_1296x984_25fps_dpcm10_8", .sensor_width = 2592, .sensor_height = 1968, .sensor_window_origin_x = 0, @@ -573,15 +649,23 @@ static struct et8ek8_reglist mode_4vga_1296x984_25fps_dpcm10_8 = { struct et8ek8_meta_reglist meta_reglist = { .version = "V14 03-June-2008", .reglist = { + /* power on mode; strange & special */ { .ptr = &mode1_poweron_mode2_16vga_2592x1968_12_07fps }, - { .ptr = &mode1_16vga_2592x1968_13_12fps_dpcm10_8 }, - { .ptr = &mode3_4vga_1296x984_29_99fps_dpcm10_8 }, - { .ptr = &mode4_svga_864x656_29_88fps }, - { .ptr = &mode5_vga_648x492_29_93fps }, - { .ptr = &mode2_16vga_2592x1968_3_99fps }, - { .ptr = &mode_648x492_5fps }, - { .ptr = &mode3_4vga_1296x984_5fps }, + /* dpcm10/8 modes */ +#if 0 + { .ptr = &mode1_16vga_2592x1968_13_12fps_dpcm10_8 }, /* No luck */ + { .ptr = &mode3_4vga_1296x984_29_99fps_dpcm10_8 }, /* No luck */ { .ptr = &mode_4vga_1296x984_25fps_dpcm10_8 }, +#endif + /* "normal" modes */ +#if 1 +// { .ptr = &mode2_16vga_2592x1968_12_07fps }, /* My hacks. */ + { .ptr = &mode4_svga_864x656_29_88fps }, /* Works, AFAICT */ + { .ptr = &mode5_vga_648x492_29_93fps }, /* Seems to work with camera.py 640 */ + { .ptr = &mode2_16vga_2592x1968_3_99fps }, /* Does not seem to work: scrolling */ +// { .ptr = &mode_648x492_5fps }, /* Seems to work with /my/v4l-utils/camera.py 640 ; can't get it to work in raw mode */ + { .ptr = &mode3_4vga_1296x984_5fps }, /* Works, AFAICT */ +#endif { .ptr = NULL } } }; diff --git a/drivers/media/i2c/et8ek8/et8ek8_reg.h b/drivers/media/i2c/et8ek8/et8ek8_reg.h index 07f1873a9c3d3..60ab3050ebb49 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_reg.h +++ b/drivers/media/i2c/et8ek8/et8ek8_reg.h @@ -37,19 +37,21 @@ struct et8ek8_mode { u16 sensor_window_height; /* Image data coming from sensor (after scaling) */ - u16 width; + u16 width; /* u */ u16 height; u16 window_origin_x; u16 window_origin_y; - u16 window_width; - u16 window_height; + u16 window_width; /* u */ + u16 window_height; /* u */ - u32 pixel_clock; /* in Hz */ - u32 ext_clock; /* in Hz */ - struct v4l2_fract timeperframe; - u32 max_exp; /* Maximum exposure value */ - u32 bus_format; /* MEDIA_BUS_FMT_ */ + u32 pixel_clock; /* u in Hz */ + u32 ext_clock; /* u in Hz */ + struct v4l2_fract timeperframe; /* u */ + u32 max_exp; /* u Maximum exposure value */ + u32 bus_format; /* u MEDIA_BUS_FMT_ */ u32 sensitivity; /* 16.16 fixed point */ + + char *name; }; #define ET8EK8_REG_8BIT 1 |