Skip to content

Commit 445e4b6

Browse files
committed
drivers: video: ov2640 driver: Enhancing ov2640 driver
Enabling proper zoom/scaling for smaller resolutions (e.g. QQVGA) This is basically a copy paste from linux driver with some tweaks Signed-off-by: Roman Pustobaiev <[email protected]>
1 parent aa6f87d commit 445e4b6

File tree

1 file changed

+177
-74
lines changed

1 file changed

+177
-74
lines changed

drivers/video/ov2640.c

Lines changed: 177 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,114 @@ LOG_MODULE_REGISTER(video_ov2640, CONFIG_VIDEO_LOG_LEVEL);
152152
#define REG32_UXGA 0x36
153153

154154
/* Configuration arrays */
155-
#define SVGA_HSIZE (800)
156-
#define SVGA_VSIZE (600)
157-
158-
#define UXGA_HSIZE (1600)
159-
#define UXGA_VSIZE (1200)
155+
#define SVGA_HSIZE (800UL)
156+
#define SVGA_VSIZE (600UL)
157+
158+
#define UXGA_HSIZE (1600UL)
159+
#define UXGA_VSIZE (1200UL)
160+
161+
#define VAL_SET(x, mask, rshift, lshift) ((((x) >> rshift) & mask) << lshift)
162+
163+
#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)
164+
#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)
165+
#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)
166+
#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)
167+
168+
#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)
169+
#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8 + 2), 2)
170+
#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8 + 2), 0)
171+
172+
#define CIF_WIDTH 352
173+
#define CIF_HEIGHT 288
174+
#define HD_720_WIDTH 1280
175+
#define HD_720_HEIGHT 720
176+
#define HD_1080_WIDTH 1920
177+
#define HD_1080_HEIGHT 1080
178+
#define QCIF_WIDTH 176
179+
#define QCIF_HEIGHT 144
180+
#define QQCIF_WIDTH 88
181+
#define QQCIF_HEIGHT 72
182+
#define QQVGA_WIDTH 160
183+
#define QQVGA_HEIGHT 120
184+
#define QVGA_WIDTH 320
185+
#define QVGA_HEIGHT 240
186+
#define SVGA_WIDTH 800
187+
#define SVGA_HEIGHT 600
188+
#define SXGA_WIDTH 1280
189+
#define SXGA_HEIGHT 1024
190+
#define VGA_WIDTH 640
191+
#define VGA_HEIGHT 480
192+
#define UXGA_WIDTH 1600
193+
#define UXGA_HEIGHT 1200
194+
#define XGA_WIDTH 1024
195+
#define XGA_HEIGHT 768
160196

161197
struct ov2640_reg {
162198
uint8_t addr;
163199
uint8_t value;
164200
};
165201

202+
struct ov2640_win_size {
203+
char *name;
204+
uint32_t width;
205+
uint32_t height;
206+
const struct ov2640_reg *regs;
207+
uint32_t regs_size;
208+
};
209+
210+
#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \
211+
{CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | CTRLI_H_DIV_SET(h_div)}, \
212+
{ZMOW, ZMOW_OUTW_SET(x)}, {ZMOH, ZMOH_OUTH_SET(y)}, \
213+
{ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y)}, {R_DVP_SP, pclk_div}, {RESET, 0x00}
214+
215+
static const struct ov2640_reg ov2640_qqvga_regs[] = {
216+
PER_SIZE_REG_SEQ(QQVGA_WIDTH, QQVGA_HEIGHT, 3, 3, 8),
217+
};
218+
static const struct ov2640_reg ov2640_qcif_regs[] = {
219+
PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4),
220+
};
221+
static const struct ov2640_reg ov2640_qvga_regs[] = {
222+
PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4),
223+
};
224+
static const struct ov2640_reg ov2640_cif_regs[] = {
225+
PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8),
226+
};
227+
static const struct ov2640_reg ov2640_vga_regs[] = {
228+
PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2),
229+
};
230+
static const struct ov2640_reg ov2640_svga_regs[] = {
231+
PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2),
232+
};
233+
static const struct ov2640_reg ov2640_xga_regs[] = {
234+
PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2),
235+
{CTRLI, 0x00},
236+
};
237+
static const struct ov2640_reg ov2640_sxga_regs[] = {
238+
PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2),
239+
{CTRLI, 0x00},
240+
{R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE},
241+
};
242+
static const struct ov2640_reg ov2640_uxga_regs[] = {
243+
PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0),
244+
{CTRLI, 0x00},
245+
{R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE},
246+
};
247+
248+
#define OV2640_SIZE(n, w, h, r) \
249+
{.name = n, .width = w, .height = h, .regs = r, .regs_size = ARRAY_SIZE(r)}
250+
251+
static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
252+
OV2640_SIZE("QQVGA", QQVGA_WIDTH, QQVGA_HEIGHT, ov2640_qqvga_regs),
253+
OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs),
254+
OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs),
255+
OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs),
256+
OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs),
257+
OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs),
258+
OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs),
259+
OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs),
260+
OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs),
261+
};
262+
166263
static const struct ov2640_reg default_regs[] = {
167264
{ BANK_SEL, BANK_SEL_DSP },
168265
{ 0x2c, 0xff },
@@ -346,61 +443,60 @@ static const struct ov2640_reg default_regs[] = {
346443
};
347444

348445
static const struct ov2640_reg uxga_regs[] = {
349-
{ BANK_SEL, BANK_SEL_SENSOR },
446+
{BANK_SEL, BANK_SEL_SENSOR},
350447
/* DSP input image resolution and window size control */
351-
{ COM7, COM7_RES_UXGA},
352-
{ COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */
353-
{ REG32, REG32_UXGA }, /* UXGA=0x36, SVGA/CIF=0x09 */
354-
355-
{ HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */
356-
{ HSTOP, 0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */
357-
358-
{ VSTART, 0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */
359-
{ VSTOP, 0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */
360-
{ 0x3d, 0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */
361-
362-
{ 0x35, 0x88 },
363-
{ 0x22, 0x0a },
364-
{ 0x37, 0x40 },
365-
{ 0x34, 0xa0 },
366-
{ 0x06, 0x02 },
367-
{ 0x0d, 0xb7 },
368-
{ 0x0e, 0x01 },
369-
{ 0x42, 0x83 },
448+
{COM7, COM7_RES_UXGA},
449+
{COM1, 0x0F}, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */
450+
{REG32, REG32_UXGA}, /* UXGA=0x36, SVGA/CIF=0x09 */
451+
452+
{HSTART, 0x11}, /* UXGA=0x11, SVGA/CIF=0x11 */
453+
{HSTOP, 0x75}, /* UXGA=0x75, SVGA/CIF=0x43 */
454+
455+
{VSTART, 0x01}, /* UXGA=0x01, SVGA/CIF=0x00 */
456+
{VSTOP, 0x97}, /* UXGA=0x97, SVGA/CIF=0x4b */
457+
{0x3d, 0x34}, /* UXGA=0x34, SVGA/CIF=0x38 */
458+
459+
{0x35, 0x88},
460+
{0x22, 0x0a},
461+
{0x37, 0x40},
462+
{0x34, 0xa0},
463+
{0x06, 0x02},
464+
{0x0d, 0xb7},
465+
{0x0e, 0x01},
466+
{0x42, 0x83},
370467

371468
/*
372469
* Set DSP input image size and offset.
373470
* The sensor output image can be scaled with OUTW/OUTH
374471
*/
375-
{ BANK_SEL, BANK_SEL_DSP },
376-
{ R_BYPASS, R_BYPASS_DSP_BYPAS },
472+
{BANK_SEL, BANK_SEL_DSP},
473+
{R_BYPASS, R_BYPASS_DSP_BYPAS},
377474

378-
{ RESET, RESET_DVP },
379-
{ HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */
380-
{ VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertical Size VSIZE[10:3] */
475+
{RESET, RESET_DVP},
476+
{HSIZE8, (UXGA_HSIZE >> 3)}, /* Image Horizontal Size HSIZE[10:3] */
477+
{VSIZE8, (UXGA_VSIZE >> 3)}, /* Image Vertical Size VSIZE[10:3] */
381478

382479
/* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */
383-
{ SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)},
480+
{SIZEL, ((UXGA_HSIZE >> 6) & 0x40) | ((UXGA_HSIZE & 0x7) << 3) | (UXGA_VSIZE & 0x7)},
384481

385-
{ XOFFL, 0x00 }, /* OFFSET_X[7:0] */
386-
{ YOFFL, 0x00 }, /* OFFSET_Y[7:0] */
387-
{ HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */
388-
{ VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */
482+
{XOFFL, 0x00}, /* OFFSET_X[7:0] */
483+
{YOFFL, 0x00}, /* OFFSET_Y[7:0] */
484+
{HSIZE, ((UXGA_HSIZE >> 2) & 0xFF)}, /* H_SIZE[7:0] real/4 */
485+
{VSIZE, ((UXGA_VSIZE >> 2) & 0xFF)}, /* V_SIZE[7:0] real/4 */
389486

390487
/* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */
391-
{ VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) },
392-
{ TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */
488+
{VHYX, ((UXGA_VSIZE >> 3) & 0x80) | ((UXGA_HSIZE >> 7) & 0x08)},
489+
{TEST, (UXGA_HSIZE >> 4) & 0x80}, /* H_SIZE[9] */
393490

394-
{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
395-
CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
491+
{CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN},
396492

397493
/* H_DIVIDER/V_DIVIDER */
398-
{ CTRLI, CTRLI_LP_DP | 0x00},
494+
{CTRLI, CTRLI_LP_DP | 0x00},
399495
/* DVP prescaler */
400-
{ R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04},
496+
{R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04},
401497

402-
{ R_BYPASS, R_BYPASS_DSP_EN },
403-
{ RESET, 0x00 },
498+
{R_BYPASS, R_BYPASS_DSP_EN},
499+
/* { RESET, 0x00 }, */
404500
{0, 0},
405501
};
406502

@@ -472,29 +568,23 @@ struct ov2640_data {
472568
}
473569

474570
static const struct video_format_cap fmts[] = {
475-
OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565), /* QQVGA */
476-
OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */
477-
OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_RGB565), /* HQVGA */
478-
OV2640_VIDEO_FORMAT_CAP(240, 240, VIDEO_PIX_FMT_RGB565), /* 240x240 */
479-
OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */
480-
OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */
481-
OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */
482-
OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_RGB565), /* SVGA */
483-
OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_RGB565), /* XVGA */
484-
OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_RGB565), /* SXGA */
485-
OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_RGB565), /* UXGA */
486-
OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_JPEG), /* QQVGA */
487-
OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_JPEG), /* QCIF */
488-
OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_JPEG), /* HQVGA */
489-
OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_JPEG), /* QVGA */
490-
OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_JPEG), /* CIF */
491-
OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_JPEG), /* VGA */
492-
OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_JPEG), /* SVGA */
493-
OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_JPEG), /* XVGA */
494-
OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_JPEG), /* SXGA */
495-
OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_JPEG), /* UXGA */
496-
{ 0 }
497-
};
571+
OV2640_VIDEO_FORMAT_CAP(QQVGA_WIDTH, QQVGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* QQVGA */
572+
OV2640_VIDEO_FORMAT_CAP(QCIF_WIDTH, QCIF_HEIGHT, VIDEO_PIX_FMT_RGB565), /* QCIF */
573+
OV2640_VIDEO_FORMAT_CAP(CIF_WIDTH, CIF_HEIGHT, VIDEO_PIX_FMT_RGB565), /* CIF */
574+
OV2640_VIDEO_FORMAT_CAP(VGA_WIDTH, VGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* VGA */
575+
OV2640_VIDEO_FORMAT_CAP(SVGA_WIDTH, SVGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* SVGA */
576+
OV2640_VIDEO_FORMAT_CAP(XGA_WIDTH, XGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* XVGA */
577+
OV2640_VIDEO_FORMAT_CAP(SXGA_WIDTH, SXGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* SXGA */
578+
OV2640_VIDEO_FORMAT_CAP(UXGA_WIDTH, UXGA_HEIGHT, VIDEO_PIX_FMT_RGB565), /* UXGA */
579+
OV2640_VIDEO_FORMAT_CAP(QQVGA_WIDTH, QQVGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* QQVGA */
580+
OV2640_VIDEO_FORMAT_CAP(QCIF_WIDTH, QCIF_HEIGHT, VIDEO_PIX_FMT_JPEG), /* QCIF */
581+
OV2640_VIDEO_FORMAT_CAP(CIF_WIDTH, CIF_HEIGHT, VIDEO_PIX_FMT_JPEG), /* CIF */
582+
OV2640_VIDEO_FORMAT_CAP(VGA_WIDTH, VGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* VGA */
583+
OV2640_VIDEO_FORMAT_CAP(SVGA_WIDTH, SVGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* SVGA */
584+
OV2640_VIDEO_FORMAT_CAP(XGA_WIDTH, XGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* XVGA */
585+
OV2640_VIDEO_FORMAT_CAP(SXGA_WIDTH, SXGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* SXGA */
586+
OV2640_VIDEO_FORMAT_CAP(UXGA_WIDTH, UXGA_HEIGHT, VIDEO_PIX_FMT_JPEG), /* UXGA */
587+
{0}};
498588

499589
static int ov2640_write_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr,
500590
uint8_t value)
@@ -775,6 +865,19 @@ static int ov2640_set_vertical_flip(const struct device *dev, int enable)
775865
return ret;
776866
}
777867

868+
static const struct ov2640_win_size *ov2640_select_win(uint32_t width, uint32_t height)
869+
{
870+
int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
871+
872+
for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
873+
if (ov2640_supported_win_sizes[i].width >= width &&
874+
ov2640_supported_win_sizes[i].height >= height) {
875+
return &ov2640_supported_win_sizes[i];
876+
}
877+
}
878+
return &ov2640_supported_win_sizes[default_size];
879+
}
880+
778881
static int ov2640_set_resolution(const struct device *dev,
779882
uint16_t img_width, uint16_t img_height)
780883
{
@@ -784,23 +887,23 @@ static int ov2640_set_resolution(const struct device *dev,
784887
uint16_t w = img_width;
785888
uint16_t h = img_height;
786889

890+
const struct ov2640_win_size *win = ov2640_select_win(w, h);
891+
892+
LOG_INF("Selected resolution %s", win->name);
893+
894+
/* Write DSP input registers */
895+
ret |= ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs));
896+
787897
/* Disable DSP */
788898
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
789899
ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_BYPAS);
790900

791-
/* Write output width */
792-
ret |= ov2640_write_reg(&cfg->i2c, ZMOW, (w >> 2) & 0xFF); /* OUTW[7:0] (real/4) */
793-
ret |= ov2640_write_reg(&cfg->i2c, ZMOH, (h >> 2) & 0xFF); /* OUTH[7:0] (real/4) */
794-
ret |= ov2640_write_reg(&cfg->i2c, ZMHH, ((h >> 8) & 0x04) |
795-
((w>>10) & 0x03)); /* OUTH[8]/OUTW[9:8] */
901+
ret |= ov2640_write_all(dev, win->regs, win->regs_size);
796902

797903
/* Set CLKRC */
798904
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
799905
ret |= ov2640_write_reg(&cfg->i2c, CLKRC, cfg->clock_rate_control);
800906

801-
/* Write DSP input registers */
802-
ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs));
803-
804907
/* Enable DSP */
805908
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
806909
ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_EN);

0 commit comments

Comments
 (0)