| From 28c0004a54ce9b2c5862b38408952583b07458f9 Mon Sep 17 00:00:00 2001 |
| From: David Plowman <david.plowman@raspberrypi.com> |
| Date: Wed, 29 Jan 2020 15:31:28 +0000 |
| Subject: [PATCH] media: ov5647: Add extra 10-bit sensor modes. |
| |
| The 8-bit VGA mode remains, we add the following 10-bit modes: |
| |
| Mode 0: 2592x1944 full resolution. |
| |
| Mode 1: 1920x1080 full resolution, but centre-cropped. |
| (This mode achieves 30fps, mode 0 does not.) |
| |
| Mode 2: 1296x972 full field-of-view 2x2 binned mode. |
| |
| Mode 3: VGA full field of view mode. |
| |
| Signed-off-by: David Plowman <david.plowman@raspberrypi.com> |
| Signed-off-by: Naushir Patuck <naush@raspberrypi.com> |
| --- |
| drivers/media/i2c/ov5647.c | 463 ++++++++++++++++++++++++++++++++++++- |
| 1 file changed, 452 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/media/i2c/ov5647.c |
| +++ b/drivers/media/i2c/ov5647.c |
| @@ -111,6 +111,7 @@ struct ov5647 { |
| struct gpio_desc *pwdn; |
| unsigned int flags; |
| struct v4l2_ctrl_handler ctrls; |
| + bool write_mode_regs; |
| }; |
| |
| static inline struct ov5647 *to_state(struct v4l2_subdev *sd) |
| @@ -130,7 +131,7 @@ static struct regval_list sensor_oe_enab |
| {0x3002, 0xe4}, |
| }; |
| |
| -static struct regval_list ov5647_640x480[] = { |
| +static struct regval_list ov5647_640x480_8bit[] = { |
| {0x0100, 0x00}, |
| {0x0103, 0x01}, |
| {0x3034, 0x08}, |
| @@ -220,9 +221,378 @@ static struct regval_list ov5647_640x480 |
| {0x0100, 0x01}, |
| }; |
| |
| +static struct regval_list ov5647_2592x1944_10bit[] = { |
| + {0x0100, 0x00}, |
| + {0x0103, 0x01}, |
| + {0x3034, 0x1a}, |
| + {0x3035, 0x21}, |
| + {0x3036, 0x69}, |
| + {0x303c, 0x11}, |
| + {0x3106, 0xf5}, |
| + {0x3821, 0x06}, |
| + {0x3820, 0x00}, |
| + {0x3827, 0xec}, |
| + {0x370c, 0x03}, |
| + {0x3612, 0x5b}, |
| + {0x3618, 0x04}, |
| + {0x5000, 0x06}, |
| + {0x5002, 0x41}, |
| + {0x5003, 0x08}, |
| + {0x5a00, 0x08}, |
| + {0x3000, 0x00}, |
| + {0x3001, 0x00}, |
| + {0x3002, 0x00}, |
| + {0x3016, 0x08}, |
| + {0x3017, 0xe0}, |
| + {0x3018, 0x44}, |
| + {0x301c, 0xf8}, |
| + {0x301d, 0xf0}, |
| + {0x3a18, 0x00}, |
| + {0x3a19, 0xf8}, |
| + {0x3c01, 0x80}, |
| + {0x3b07, 0x0c}, |
| + {0x380c, 0x0b}, |
| + {0x380d, 0x1c}, |
| + {0x380e, 0x07}, |
| + {0x380f, 0xb0}, |
| + {0x3814, 0x11}, |
| + {0x3815, 0x11}, |
| + {0x3708, 0x64}, |
| + {0x3709, 0x12}, |
| + {0x3808, 0x0a}, |
| + {0x3809, 0x20}, |
| + {0x380a, 0x07}, |
| + {0x380b, 0x98}, |
| + {0x3800, 0x00}, |
| + {0x3801, 0x00}, |
| + {0x3802, 0x00}, |
| + {0x3803, 0x00}, |
| + {0x3804, 0x0a}, |
| + {0x3805, 0x3f}, |
| + {0x3806, 0x07}, |
| + {0x3807, 0xa3}, |
| + {0x3811, 0x10}, |
| + {0x3813, 0x06}, |
| + {0x3630, 0x2e}, |
| + {0x3632, 0xe2}, |
| + {0x3633, 0x23}, |
| + {0x3634, 0x44}, |
| + {0x3636, 0x06}, |
| + {0x3620, 0x64}, |
| + {0x3621, 0xe0}, |
| + {0x3600, 0x37}, |
| + {0x3704, 0xa0}, |
| + {0x3703, 0x5a}, |
| + {0x3715, 0x78}, |
| + {0x3717, 0x01}, |
| + {0x3731, 0x02}, |
| + {0x370b, 0x60}, |
| + {0x3705, 0x1a}, |
| + {0x3f05, 0x02}, |
| + {0x3f06, 0x10}, |
| + {0x3f01, 0x0a}, |
| + {0x3a08, 0x01}, |
| + {0x3a09, 0x28}, |
| + {0x3a0a, 0x00}, |
| + {0x3a0b, 0xf6}, |
| + {0x3a0d, 0x08}, |
| + {0x3a0e, 0x06}, |
| + {0x3a0f, 0x58}, |
| + {0x3a10, 0x50}, |
| + {0x3a1b, 0x58}, |
| + {0x3a1e, 0x50}, |
| + {0x3a11, 0x60}, |
| + {0x3a1f, 0x28}, |
| + {0x4001, 0x02}, |
| + {0x4004, 0x04}, |
| + {0x4000, 0x09}, |
| + {0x4837, 0x19}, |
| + {0x4800, 0x24}, |
| + {0x3503, 0x03}, |
| + {0x0100, 0x01}, |
| +}; |
| + |
| +static struct regval_list ov5647_1080p30_10bit[] = { |
| + {0x0100, 0x00}, |
| + {0x0103, 0x01}, |
| + {0x3034, 0x1a}, |
| + {0x3035, 0x21}, |
| + {0x3036, 0x62}, |
| + {0x303c, 0x11}, |
| + {0x3106, 0xf5}, |
| + {0x3821, 0x06}, |
| + {0x3820, 0x00}, |
| + {0x3827, 0xec}, |
| + {0x370c, 0x03}, |
| + {0x3612, 0x5b}, |
| + {0x3618, 0x04}, |
| + {0x5000, 0x06}, |
| + {0x5002, 0x41}, |
| + {0x5003, 0x08}, |
| + {0x5a00, 0x08}, |
| + {0x3000, 0x00}, |
| + {0x3001, 0x00}, |
| + {0x3002, 0x00}, |
| + {0x3016, 0x08}, |
| + {0x3017, 0xe0}, |
| + {0x3018, 0x44}, |
| + {0x301c, 0xf8}, |
| + {0x301d, 0xf0}, |
| + {0x3a18, 0x00}, |
| + {0x3a19, 0xf8}, |
| + {0x3c01, 0x80}, |
| + {0x3b07, 0x0c}, |
| + {0x380c, 0x09}, |
| + {0x380d, 0x70}, |
| + {0x380e, 0x04}, |
| + {0x380f, 0x50}, |
| + {0x3814, 0x11}, |
| + {0x3815, 0x11}, |
| + {0x3708, 0x64}, |
| + {0x3709, 0x12}, |
| + {0x3808, 0x07}, |
| + {0x3809, 0x80}, |
| + {0x380a, 0x04}, |
| + {0x380b, 0x38}, |
| + {0x3800, 0x01}, |
| + {0x3801, 0x5c}, |
| + {0x3802, 0x01}, |
| + {0x3803, 0xb2}, |
| + {0x3804, 0x08}, |
| + {0x3805, 0xe3}, |
| + {0x3806, 0x05}, |
| + {0x3807, 0xf1}, |
| + {0x3811, 0x04}, |
| + {0x3813, 0x02}, |
| + {0x3630, 0x2e}, |
| + {0x3632, 0xe2}, |
| + {0x3633, 0x23}, |
| + {0x3634, 0x44}, |
| + {0x3636, 0x06}, |
| + {0x3620, 0x64}, |
| + {0x3621, 0xe0}, |
| + {0x3600, 0x37}, |
| + {0x3704, 0xa0}, |
| + {0x3703, 0x5a}, |
| + {0x3715, 0x78}, |
| + {0x3717, 0x01}, |
| + {0x3731, 0x02}, |
| + {0x370b, 0x60}, |
| + {0x3705, 0x1a}, |
| + {0x3f05, 0x02}, |
| + {0x3f06, 0x10}, |
| + {0x3f01, 0x0a}, |
| + {0x3a08, 0x01}, |
| + {0x3a09, 0x4b}, |
| + {0x3a0a, 0x01}, |
| + {0x3a0b, 0x13}, |
| + {0x3a0d, 0x04}, |
| + {0x3a0e, 0x03}, |
| + {0x3a0f, 0x58}, |
| + {0x3a10, 0x50}, |
| + {0x3a1b, 0x58}, |
| + {0x3a1e, 0x50}, |
| + {0x3a11, 0x60}, |
| + {0x3a1f, 0x28}, |
| + {0x4001, 0x02}, |
| + {0x4004, 0x04}, |
| + {0x4000, 0x09}, |
| + {0x4837, 0x19}, |
| + {0x4800, 0x34}, |
| + {0x3503, 0x03}, |
| + {0x0100, 0x01}, |
| +}; |
| + |
| +static struct regval_list ov5647_2x2binned_10bit[] = { |
| + {0x0100, 0x00}, |
| + {0x0103, 0x01}, |
| + {0x3034, 0x1A}, |
| + {0x3035, 0x21}, |
| + {0x3036, 0x62}, |
| + {0x303C, 0x11}, |
| + {0x3106, 0xF5}, |
| + {0x3827, 0xEC}, |
| + {0x370C, 0x03}, |
| + {0x3612, 0x59}, |
| + {0x3618, 0x00}, |
| + {0x5000, 0x06}, |
| + {0x5002, 0x41}, |
| + {0x5003, 0x08}, |
| + {0x5A00, 0x08}, |
| + {0x3000, 0x00}, |
| + {0x3001, 0x00}, |
| + {0x3002, 0x00}, |
| + {0x3016, 0x08}, |
| + {0x3017, 0xE0}, |
| + {0x3018, 0x44}, |
| + {0x301C, 0xF8}, |
| + {0x301D, 0xF0}, |
| + {0x3A18, 0x00}, |
| + {0x3A19, 0xF8}, |
| + {0x3C01, 0x80}, |
| + {0x3B07, 0x0C}, |
| + {0x3800, 0x00}, |
| + {0x3801, 0x00}, |
| + {0x3802, 0x00}, |
| + {0x3803, 0x00}, |
| + {0x3804, 0x0A}, |
| + {0x3805, 0x3F}, |
| + {0x3806, 0x07}, |
| + {0x3807, 0xA3}, |
| + {0x3808, 0x05}, |
| + {0x3809, 0x10}, |
| + {0x380A, 0x03}, |
| + {0x380B, 0xCC}, |
| + {0x380C, 0x07}, |
| + {0x380D, 0x68}, |
| + {0x3811, 0x0c}, |
| + {0x3813, 0x06}, |
| + {0x3814, 0x31}, |
| + {0x3815, 0x31}, |
| + {0x3630, 0x2E}, |
| + {0x3632, 0xE2}, |
| + {0x3633, 0x23}, |
| + {0x3634, 0x44}, |
| + {0x3636, 0x06}, |
| + {0x3620, 0x64}, |
| + {0x3621, 0xE0}, |
| + {0x3600, 0x37}, |
| + {0x3704, 0xA0}, |
| + {0x3703, 0x5A}, |
| + {0x3715, 0x78}, |
| + {0x3717, 0x01}, |
| + {0x3731, 0x02}, |
| + {0x370B, 0x60}, |
| + {0x3705, 0x1A}, |
| + {0x3F05, 0x02}, |
| + {0x3F06, 0x10}, |
| + {0x3F01, 0x0A}, |
| + {0x3A08, 0x01}, |
| + {0x3A09, 0x28}, |
| + {0x3A0A, 0x00}, |
| + {0x3A0B, 0xF6}, |
| + {0x3A0D, 0x08}, |
| + {0x3A0E, 0x06}, |
| + {0x3A0F, 0x58}, |
| + {0x3A10, 0x50}, |
| + {0x3A1B, 0x58}, |
| + {0x3A1E, 0x50}, |
| + {0x3A11, 0x60}, |
| + {0x3A1F, 0x28}, |
| + {0x4001, 0x02}, |
| + {0x4004, 0x04}, |
| + {0x4000, 0x09}, |
| + {0x4837, 0x16}, |
| + {0x4800, 0x24}, |
| + {0x3503, 0x03}, |
| + {0x3820, 0x41}, |
| + {0x3821, 0x07}, |
| + {0x380E, 0x05}, |
| + {0x380F, 0x9B}, |
| + {0x350A, 0x00}, |
| + {0x350B, 0x10}, |
| + {0x3500, 0x00}, |
| + {0x3501, 0x1A}, |
| + {0x3502, 0xF0}, |
| + {0x3212, 0xA0}, |
| + {0x0100, 0x01}, |
| +}; |
| + |
| +static struct regval_list ov5647_640x480_10bit[] = { |
| + {0x0100, 0x00}, |
| + {0x0103, 0x01}, |
| + {0x3035, 0x11}, |
| + {0x3036, 0x46}, |
| + {0x303c, 0x11}, |
| + {0x3821, 0x07}, |
| + {0x3820, 0x41}, |
| + {0x370c, 0x03}, |
| + {0x3612, 0x59}, |
| + {0x3618, 0x00}, |
| + {0x5000, 0x06}, |
| + {0x5003, 0x08}, |
| + {0x5a00, 0x08}, |
| + {0x3000, 0xff}, |
| + {0x3001, 0xff}, |
| + {0x3002, 0xff}, |
| + {0x301d, 0xf0}, |
| + {0x3a18, 0x00}, |
| + {0x3a19, 0xf8}, |
| + {0x3c01, 0x80}, |
| + {0x3b07, 0x0c}, |
| + {0x380c, 0x07}, |
| + {0x380d, 0x3c}, |
| + {0x380e, 0x01}, |
| + {0x380f, 0xf8}, |
| + {0x3814, 0x35}, |
| + {0x3815, 0x35}, |
| + {0x3708, 0x64}, |
| + {0x3709, 0x52}, |
| + {0x3808, 0x02}, |
| + {0x3809, 0x80}, |
| + {0x380a, 0x01}, |
| + {0x380b, 0xe0}, |
| + {0x3800, 0x00}, |
| + {0x3801, 0x10}, |
| + {0x3802, 0x00}, |
| + {0x3803, 0x00}, |
| + {0x3804, 0x0a}, |
| + {0x3805, 0x2f}, |
| + {0x3806, 0x07}, |
| + {0x3807, 0x9f}, |
| + {0x3630, 0x2e}, |
| + {0x3632, 0xe2}, |
| + {0x3633, 0x23}, |
| + {0x3634, 0x44}, |
| + {0x3620, 0x64}, |
| + {0x3621, 0xe0}, |
| + {0x3600, 0x37}, |
| + {0x3704, 0xa0}, |
| + {0x3703, 0x5a}, |
| + {0x3715, 0x78}, |
| + {0x3717, 0x01}, |
| + {0x3731, 0x02}, |
| + {0x370b, 0x60}, |
| + {0x3705, 0x1a}, |
| + {0x3f05, 0x02}, |
| + {0x3f06, 0x10}, |
| + {0x3f01, 0x0a}, |
| + {0x3a08, 0x01}, |
| + {0x3a09, 0x2e}, |
| + {0x3a0a, 0x00}, |
| + {0x3a0b, 0xfb}, |
| + {0x3a0d, 0x02}, |
| + {0x3a0e, 0x01}, |
| + {0x3a0f, 0x58}, |
| + {0x3a10, 0x50}, |
| + {0x3a1b, 0x58}, |
| + {0x3a1e, 0x50}, |
| + {0x3a11, 0x60}, |
| + {0x3a1f, 0x28}, |
| + {0x4001, 0x02}, |
| + {0x4004, 0x02}, |
| + {0x4000, 0x09}, |
| + {0x3000, 0x00}, |
| + {0x3001, 0x00}, |
| + {0x3002, 0x00}, |
| + {0x3017, 0xe0}, |
| + {0x301c, 0xfc}, |
| + {0x3636, 0x06}, |
| + {0x3016, 0x08}, |
| + {0x3827, 0xec}, |
| + {0x3018, 0x44}, |
| + {0x3035, 0x21}, |
| + {0x3106, 0xf5}, |
| + {0x3034, 0x1a}, |
| + {0x301c, 0xf8}, |
| + {0x4800, 0x34}, |
| + {0x3503, 0x03}, |
| + {0x0100, 0x01}, |
| +}; |
| + |
| static struct ov5647_mode supported_modes_8bit[] = { |
| /* |
| - * Original 8-bit VGA mode |
| + * MODE 0: Original 8-bit VGA mode. |
| * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image. |
| */ |
| { |
| @@ -233,14 +603,70 @@ static struct ov5647_mode supported_mode |
| .width = 640, |
| .height = 480 |
| }, |
| - ov5647_640x480, |
| - ARRAY_SIZE(ov5647_640x480) |
| + ov5647_640x480_8bit, |
| + ARRAY_SIZE(ov5647_640x480_8bit) |
| }, |
| - /* more modes below here... */ |
| }; |
| |
| static struct ov5647_mode supported_modes_10bit[] = { |
| - /* no 10-bit modes yet */ |
| + /* |
| + * MODE 0: 2592x1944 full resolution full FOV 10-bit mode. |
| + */ |
| + { |
| + { |
| + .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| + .colorspace = V4L2_COLORSPACE_SRGB, |
| + .field = V4L2_FIELD_NONE, |
| + .width = 2592, |
| + .height = 1944 |
| + }, |
| + ov5647_2592x1944_10bit, |
| + ARRAY_SIZE(ov5647_2592x1944_10bit) |
| + }, |
| + /* |
| + * MODE 1: 1080p30 10-bit mode. |
| + * Full resolution centre-cropped down to 1080p. |
| + */ |
| + { |
| + { |
| + .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| + .colorspace = V4L2_COLORSPACE_SRGB, |
| + .field = V4L2_FIELD_NONE, |
| + .width = 1920, |
| + .height = 1080 |
| + }, |
| + ov5647_1080p30_10bit, |
| + ARRAY_SIZE(ov5647_1080p30_10bit) |
| + }, |
| + /* |
| + * MODE 2: 2x2 binned full FOV 10-bit mode. |
| + */ |
| + { |
| + { |
| + .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| + .colorspace = V4L2_COLORSPACE_SRGB, |
| + .field = V4L2_FIELD_NONE, |
| + .width = 1296, |
| + .height = 972 |
| + }, |
| + ov5647_2x2binned_10bit, |
| + ARRAY_SIZE(ov5647_2x2binned_10bit) |
| + }, |
| + /* |
| + * MODE 3: 10-bit VGA full FOV mode 60fps. |
| + * 2x2 binned and subsampled down to VGA. |
| + */ |
| + { |
| + { |
| + .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| + .colorspace = V4L2_COLORSPACE_SRGB, |
| + .field = V4L2_FIELD_NONE, |
| + .width = 640, |
| + .height = 480 |
| + }, |
| + ov5647_640x480_10bit, |
| + ARRAY_SIZE(ov5647_640x480_10bit) |
| + }, |
| }; |
| |
| /* Use original 8-bit VGA mode as default. */ |
| @@ -343,11 +769,14 @@ static int __sensor_init(struct v4l2_sub |
| if (ret < 0) |
| return ret; |
| |
| - ret = ov5647_write_array(sd, state->mode->reg_list, |
| - state->mode->num_regs); |
| - if (ret < 0) { |
| - dev_err(&client->dev, "write sensor default regs error\n"); |
| - return ret; |
| + if (state->write_mode_regs) { |
| + ret = ov5647_write_array(sd, state->mode->reg_list, |
| + state->mode->num_regs); |
| + if (ret < 0) { |
| + dev_err(&client->dev, "write sensor default regs error\n"); |
| + return ret; |
| + } |
| + state->write_mode_regs = false; |
| } |
| |
| ret = ov5647_set_virtual_channel(sd, 0); |
| @@ -475,6 +904,9 @@ static int ov5647_sensor_power(struct v4 |
| "Camera not available, check Power\n"); |
| goto out; |
| } |
| + |
| + /* Write out the register set over I2C on stream-on. */ |
| + ov5647->write_mode_regs = true; |
| } else if (!on && ov5647->power_count == 1) { |
| dev_dbg(&client->dev, "OV5647 power off\n"); |
| |
| @@ -650,6 +1082,12 @@ static int ov5647_set_fmt(struct v4l2_su |
| framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); |
| *framefmt = format->format; |
| } else { |
| + /* |
| + * If we have changed modes, write the I2C register list on |
| + * a stream_on(). |
| + */ |
| + if (state->mode != mode) |
| + state->write_mode_regs = true; |
| state->mode = mode; |
| } |
| |
| @@ -967,6 +1405,9 @@ static int ov5647_probe(struct i2c_clien |
| /* Set the default mode before we init the subdev */ |
| sensor->mode = OV5647_DEFAULT_MODE; |
| |
| + /* Write out the register set over I2C on stream-on. */ |
| + sensor->write_mode_regs = true; |
| + |
| sd = &sensor->sd; |
| v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops); |
| sensor->sd.internal_ops = &ov5647_subdev_internal_ops; |