@@ -33,15 +33,43 @@ LOG_MODULE_REGISTER(hm01b0, CONFIG_VIDEO_LOG_LEVEL);
3333#define HM01B0_CCI_RESET HM01B0_REG8(0x0103)
3434#define HM01B0_CCI_GRP_PARAM_HOLD HM01B0_REG8(0x0104)
3535#define HM01B0_CCI_INTEGRATION_H HM01B0_REG16(0x0202)
36+ #define HM01B0_CCI_ANALOG_GAIN HM01B0_REG8(0x0205)
37+ #define HM01B0_CCI_DIGITAL_GAIN_H HM01B0_REG16(0x020E)
3638#define HM01B0_CCI_FRAME_LENGTH_LINES HM01B0_REG16(0x0340)
3739#define HM01B0_CCI_LINE_LENGTH_PCLK HM01B0_REG16(0x0342)
3840#define HM01B0_CCI_WIDTH HM01B0_REG8(0x0383)
3941#define HM01B0_CCI_HEIGHT HM01B0_REG8(0x0387)
4042#define HM01B0_CCI_BINNING_MODE HM01B0_REG8(0x0390)
43+ #define HM01B0_CCI_BLC_CFG HM01B0_REG8(0x1000)
44+ #define HM01B0_CCI_BLC_TGT HM01B0_REG8(0x1003)
45+ #define HM01B0_CCI_BLI_EN HM01B0_REG8(0x1006)
46+ #define HM01B0_CCI_BLC2_TGT HM01B0_REG8(0x1007)
47+ #define HM01B0_CCI_DPC_CTRL HM01B0_REG8(0x1008)
48+ #define HM01B0_CCI_SINGLE_THR_HOT HM01B0_REG8(0x100B)
49+ #define HM01B0_CCI_SINGLE_THR_COLD HM01B0_REG8(0x100C)
50+ #define HM01B0_CCI_STATISTIC_CTRL HM01B0_REG8(0x2000)
51+ #define HM01B0_CCI_AE_CTRL HM01B0_REG8(0x2100)
52+ #define HM01B0_CCI_AE_TARGET_MEAN HM01B0_REG8(0x2101)
53+ #define HM01B0_CCI_AE_MIN_MEAN HM01B0_REG8(0x2102)
54+ #define HM01B0_CCI_CONVERGE_IN_TH HM01B0_REG8(0x2103)
55+ #define HM01B0_CCI_CONVERGE_OUT_TH HM01B0_REG8(0x2104)
56+ #define HM01B0_CCI_MAX_INTG HM01B0_REG16(0x2105)
57+ #define HM01B0_CCI_MIN_INTG HM01B0_REG8(0x2107)
58+ #define HM01B0_CCI_MAX_AGAIN_FULL HM01B0_REG8(0x2108)
59+ #define HM01B0_CCI_MAX_AGAIN_BIN2 HM01B0_REG8(0x2109)
60+ #define HM01B0_CCI_MIN_AGAIN HM01B0_REG8(0x210A)
61+ #define HM01B0_CCI_MAX_DGAIN HM01B0_REG8(0x210B)
62+ #define HM01B0_CCI_MIN_DGAIN HM01B0_REG8(0x210C)
63+ #define HM01B0_CCI_DAMPING_FACTOR HM01B0_REG8(0x210D)
64+ #define HM01B0_CCI_FS_CTRL HM01B0_REG8(0x210E)
65+ #define HM01B0_CCI_FS_60HZ_H HM01B0_REG16(0x210F)
66+ #define HM01B0_CCI_FS_50HZ_H HM01B0_REG16(0x2111)
67+ #define HM01B0_CCI_FS_HYST_TH HM01B0_REG8(0x2113)
68+ #define HM01B0_CCI_MD_CTRL HM01B0_REG8(0x2150)
4169#define HM01B0_CCI_QVGA_WIN_EN HM01B0_REG8(0x3010)
4270#define HM01B0_CCI_BIT_CONTROL HM01B0_REG8(0x3059)
4371#define HM01B0_CCI_OSC_CLOCK_DIV HM01B0_REG8(0x3060)
44-
72+ #define HM01B0_CCI_ANA_REGISTER_17 HM01B0_REG8(0x3067)
4573#define HM01B0_SET_HMIRROR (r , x ) ((r & 0xFE) | ((x & 1) << 0))
4674#define HM01B0_SET_VMIRROR (r , x ) ((r & 0xFD) | ((x & 1) << 1))
4775
@@ -50,63 +78,166 @@ LOG_MODULE_REGISTER(hm01b0, CONFIG_VIDEO_LOG_LEVEL);
5078 (data_bits) == 4 ? 0x42 : \
5179 (data_bits) == 1 ? 0x22 : 0x00)
5280
81+ /* Note: Bayer versions do not support 160x120 type settings */
5382enum hm01b0_resolution {
5483 RESOLUTION_160x120 ,
5584 RESOLUTION_320x240 ,
5685 RESOLUTION_320x320 ,
5786 RESOLUTION_164x122 ,
58- RESOLUTION_326x244 ,
59- RESOLUTION_326x324 ,
87+ RESOLUTION_324x244 ,
88+ RESOLUTION_324x324 ,
6089 RESOLUTION_164x122_Y4 ,
61- RESOLUTION_326x244_Y4 ,
62- RESOLUTION_326x324_Y4 ,
63- RESOLUTION_164x122_BAYER ,
64- RESOLUTION_326x244_BAYER ,
65- RESOLUTION_326x324_BAYER ,
90+ RESOLUTION_324x244_Y4 ,
91+ RESOLUTION_324x324_Y4 ,
92+ RESOLUTION_324x244_BAYER ,
93+ RESOLUTION_324x324_BAYER ,
94+ };
95+
96+ enum {
97+ HM01B0_60_FPS ,
98+ HM01B0_30_FPS ,
99+ HM01B0_15_FPS ,
100+ HM01B0_8_FPS ,
66101};
67102
103+ #define HIMAX_LINE_LEN_PCK_FULL 0x178
104+ #define HIMAX_FRAME_LENGTH_FULL 0x109
105+
106+ #define HIMAX_LINE_LEN_PCK_QVGA 0x178
107+ #define HIMAX_FRAME_LENGTH_QVGA 0x104
108+
109+ #define HIMAX_LINE_LEN_PCK_QQVGA 0x178
110+ #define HIMAX_FRAME_LENGTH_QQVGA 0x084
111+
112+
113+
68114struct video_reg hm01b0_160x120_regs [] = {
69115 {HM01B0_CCI_WIDTH , 0x3 },
70116 {HM01B0_CCI_HEIGHT , 0x3 },
71117 {HM01B0_CCI_BINNING_MODE , 0x3 },
72118 {HM01B0_CCI_QVGA_WIN_EN , 0x1 },
73- {HM01B0_CCI_FRAME_LENGTH_LINES , 0x80 },
74- {HM01B0_CCI_LINE_LENGTH_PCLK , 0xD7 },
119+ {HM01B0_CCI_MAX_INTG , HIMAX_FRAME_LENGTH_QQVGA - 2 },
120+ {HM01B0_CCI_FRAME_LENGTH_LINES , HIMAX_FRAME_LENGTH_QQVGA },
121+ {HM01B0_CCI_LINE_LENGTH_PCLK , HIMAX_LINE_LEN_PCK_QQVGA },
75122};
76123
77124struct video_reg hm01b0_320x240_regs [] = {
78125 {HM01B0_CCI_WIDTH , 0x1 },
79126 {HM01B0_CCI_HEIGHT , 0x1 },
80127 {HM01B0_CCI_BINNING_MODE , 0x0 },
81128 {HM01B0_CCI_QVGA_WIN_EN , 0x1 },
82- {HM01B0_CCI_FRAME_LENGTH_LINES , 0x104 },
83- {HM01B0_CCI_LINE_LENGTH_PCLK , 0x178 },
129+ {HM01B0_CCI_MAX_INTG , HIMAX_FRAME_LENGTH_QVGA - 2 },
130+ {HM01B0_CCI_FRAME_LENGTH_LINES , HIMAX_FRAME_LENGTH_QVGA },
131+ {HM01B0_CCI_LINE_LENGTH_PCLK , HIMAX_LINE_LEN_PCK_QVGA },
84132};
85133
86134struct video_reg hm01b0_320x320_regs [] = {
87135 {HM01B0_CCI_WIDTH , 0x1 },
88136 {HM01B0_CCI_HEIGHT , 0x1 },
89137 {HM01B0_CCI_BINNING_MODE , 0x0 },
90138 {HM01B0_CCI_QVGA_WIN_EN , 0x0 },
91- {HM01B0_CCI_FRAME_LENGTH_LINES , 0x158 },
92- {HM01B0_CCI_LINE_LENGTH_PCLK , 0x178 },
139+ {HM01B0_CCI_MAX_INTG , HIMAX_FRAME_LENGTH_QVGA - 2 },
140+ {HM01B0_CCI_FRAME_LENGTH_LINES , HIMAX_FRAME_LENGTH_FULL },
141+ {HM01B0_CCI_LINE_LENGTH_PCLK , HIMAX_LINE_LEN_PCK_FULL },
93142};
94143
95144struct video_reg * hm01b0_init_regs [] = {
96145 [RESOLUTION_160x120 ] = hm01b0_160x120_regs ,
97146 [RESOLUTION_320x240 ] = hm01b0_320x240_regs ,
98147 [RESOLUTION_320x320 ] = hm01b0_320x320_regs ,
99148 [RESOLUTION_164x122 ] = hm01b0_160x120_regs ,
100- [RESOLUTION_326x244 ] = hm01b0_320x240_regs ,
101- [RESOLUTION_326x324 ] = hm01b0_320x320_regs ,
149+ [RESOLUTION_324x244 ] = hm01b0_320x240_regs ,
150+ [RESOLUTION_324x324 ] = hm01b0_320x320_regs ,
102151 [RESOLUTION_164x122_Y4 ] = hm01b0_160x120_regs ,
103- [RESOLUTION_326x244_Y4 ] = hm01b0_320x240_regs ,
104- [RESOLUTION_326x324_Y4 ] = hm01b0_320x320_regs ,
105- [RESOLUTION_164x122_BAYER ] = hm01b0_160x120_regs ,
106- [RESOLUTION_326x244_BAYER ] = hm01b0_320x240_regs ,
107- [RESOLUTION_326x324_BAYER ] = hm01b0_320x320_regs ,
152+ [RESOLUTION_324x244_Y4 ] = hm01b0_320x240_regs ,
153+ [RESOLUTION_324x324_Y4 ] = hm01b0_320x320_regs ,
154+ [RESOLUTION_324x244_BAYER ] = hm01b0_320x240_regs ,
155+ [RESOLUTION_324x324_BAYER ] = hm01b0_320x320_regs ,
156+ };
157+
158+ struct video_reg hm01b0_default_regs [] = {
159+ {HM01B0_CCI_BLC_TGT , 0x08 }, /* BLC target :8 at 8 bit mode */
160+ {HM01B0_CCI_BLC2_TGT , 0x08 }, /* BLI target :8 at 8 bit mode */
161+ {HM01B0_REG8 (0x3044 ), 0x0A }, /* Increase CDS time for settling */
162+ {HM01B0_REG8 (0x3045 ), 0x00 }, /* Make symmetric for cds_tg and rst_tg */
163+ {HM01B0_REG8 (0x3047 ), 0x0A }, /* Increase CDS time for settling */
164+ {HM01B0_REG8 (0x3050 ), 0xC0 }, /* Make negative offset up to 4x */
165+ {HM01B0_REG8 (0x3051 ), 0x42 },
166+ {HM01B0_REG8 (0x3052 ), 0x50 },
167+ {HM01B0_REG8 (0x3053 ), 0x00 },
168+ {HM01B0_REG8 (0x3054 ), 0x03 }, /* tuning sf sig clamping as lowest */
169+ {HM01B0_REG8 (0x3055 ), 0xF7 }, /* tuning dsun */
170+ {HM01B0_REG8 (0x3056 ), 0xF8 }, /* increase adc nonoverlap clk */
171+ {HM01B0_REG8 (0x3057 ), 0x29 }, /* increase adc pwr for missing code */
172+ {HM01B0_REG8 (0x3058 ), 0x1F }, /* turn on dsun */
173+ {HM01B0_REG8 (0x3059 ), 0x1E },
174+ {HM01B0_REG8 (0x3064 ), 0x00 },
175+ {HM01B0_REG8 (0x3065 ), 0x04 }, /* pad pull 0 */
176+ {HM01B0_CCI_ANA_REGISTER_17 , 0x00 }, /* Disable internal oscillator */
177+
178+ {HM01B0_CCI_BLC_CFG , 0x43 }, /* BLC_on, IIR */
179+
180+ {HM01B0_REG8 (0x1001 ), 0x43 }, /* BLC dithering en */
181+ {HM01B0_REG8 (0x1002 ), 0x43 }, /* blc_darkpixel_thd */
182+ {HM01B0_REG8 (0x0350 ), 0x7F }, /* Dgain Control */
183+ {HM01B0_CCI_BLI_EN , 0x01 }, /* BLI enable */
184+ {HM01B0_REG8 (0x1003 ), 0x00 }, /* BLI Target [Def: 0x20] */
185+
186+ {HM01B0_CCI_DPC_CTRL , 0x01 }, /* DPC option 0:DPC off 1:mono3:bayer1 5:bayer2 */
187+ {HM01B0_REG8 (0x1009 ), 0xA0 }, /* cluster hot pixel th */
188+ {HM01B0_REG8 (0x100A ), 0x60 }, /* cluster cold pixel th */
189+ {HM01B0_CCI_SINGLE_THR_HOT , 0x90 }, /* single hot pixel th */
190+ {HM01B0_CCI_SINGLE_THR_COLD , 0x40 }, /* single cold pixel th */
191+ {HM01B0_REG8 (0x1012 ), 0x00 }, /* Sync. shift disable */
192+ {HM01B0_CCI_STATISTIC_CTRL , 0x07 }, /* AE stat en | MD LROI stat en | magic */
193+ {HM01B0_REG8 (0x2003 ), 0x00 },
194+ {HM01B0_REG8 (0x2004 ), 0x1C },
195+ {HM01B0_REG8 (0x2007 ), 0x00 },
196+ {HM01B0_REG8 (0x2008 ), 0x58 },
197+ {HM01B0_REG8 (0x200B ), 0x00 },
198+ {HM01B0_REG8 (0x200C ), 0x7A },
199+ {HM01B0_REG8 (0x200F ), 0x00 },
200+ {HM01B0_REG8 (0x2010 ), 0xB8 },
201+ {HM01B0_REG8 (0x2013 ), 0x00 },
202+ {HM01B0_REG8 (0x2014 ), 0x58 },
203+ {HM01B0_REG8 (0x2017 ), 0x00 },
204+ {HM01B0_REG8 (0x2018 ), 0x9B },
205+
206+ {HM01B0_CCI_AE_CTRL , 0x01 }, /* Automatic Exposure */
207+ {HM01B0_CCI_AE_TARGET_MEAN , 0x64 }, /* AE target mean [Def: 0x3C] */
208+ {HM01B0_CCI_AE_MIN_MEAN , 0x0A }, /* AE min target mean [Def: 0x0A] */
209+ {HM01B0_CCI_CONVERGE_IN_TH , 0x03 }, /* Converge in threshold [Def: 0x03] */
210+ {HM01B0_CCI_CONVERGE_OUT_TH , 0x05 }, /* Converge out threshold [Def: 0x05] */
211+ {HM01B0_CCI_MAX_INTG , (HIMAX_FRAME_LENGTH_QVGA - 2 )}, /* Max INTG High Byte */
212+ {HM01B0_CCI_MAX_AGAIN_FULL , 0x04 }, /* Max Analog gain full frame mode [Def: 0x03] */
213+ {HM01B0_CCI_MAX_AGAIN_BIN2 , 0x04 }, /* Max Analog gain bin2 mode [Def: 0x04] */
214+ {HM01B0_CCI_MAX_DGAIN , 0xC0 },
215+
216+ {HM01B0_CCI_INTEGRATION_H , 0x0108 }, /* Integration H [Def: 0x01] */
217+ {HM01B0_CCI_ANALOG_GAIN , 0x00 }, /* Analog Global Gain [Def: 0x00] */
218+ {HM01B0_CCI_DAMPING_FACTOR , 0x20 }, /* Damping Factor [Def: 0x20] */
219+ {HM01B0_CCI_DIGITAL_GAIN_H , 0x0100 }, /* Digital Gain High [Def: 0x01] */
220+
221+ {HM01B0_CCI_FS_CTRL , 0x00 }, /* Flicker Control */
222+
223+ {HM01B0_CCI_FS_60HZ_H , 0x003C },
224+ {HM01B0_CCI_FS_50HZ_H , 0x0032 },
225+
226+ {HM01B0_CCI_MD_CTRL , 0x00 },
227+ {HM01B0_CCI_FRAME_LENGTH_LINES , HIMAX_FRAME_LENGTH_QVGA },
228+ {HM01B0_CCI_LINE_LENGTH_PCLK , HIMAX_LINE_LEN_PCK_QVGA },
229+ {HM01B0_CCI_QVGA_WIN_EN , 0x01 }, /* Enable QVGA window readout */
230+ {HM01B0_REG8 (0x0383 ), 0x01 },
231+ {HM01B0_REG8 (0x0387 ), 0x01 },
232+ {HM01B0_REG8 (0x0390 ), 0x00 },
233+ {HM01B0_REG8 (0x3011 ), 0x70 },
234+ {HM01B0_REG8 (0x3059 ), 0x02 },
235+ {HM01B0_CCI_OSC_CLOCK_DIV , 0x0B },
236+ {HM01B0_CCI_IMG_ORIENTATION , 0x00 }, /* change the orientation */
237+ {HM01B0_REG8 (0x0104 ), 0x01 },
108238};
109239
240+
110241struct hm01b0_ctrls {
111242 struct video_ctrl hflip ;
112243 struct video_ctrl vflip ;
@@ -146,14 +277,13 @@ static const struct video_format_cap hm01b0_fmts[] = {
146277 HM01B0_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_GREY ),
147278 HM01B0_VIDEO_FORMAT_CAP (320 , 320 , VIDEO_PIX_FMT_GREY ),
148279 HM01B0_VIDEO_FORMAT_CAP (164 , 122 , VIDEO_PIX_FMT_GREY ),
149- HM01B0_VIDEO_FORMAT_CAP (326 , 244 , VIDEO_PIX_FMT_GREY ),
150- HM01B0_VIDEO_FORMAT_CAP (326 , 324 , VIDEO_PIX_FMT_GREY ),
280+ HM01B0_VIDEO_FORMAT_CAP (324 , 244 , VIDEO_PIX_FMT_GREY ),
281+ HM01B0_VIDEO_FORMAT_CAP (324 , 324 , VIDEO_PIX_FMT_GREY ),
151282 HM01B0_VIDEO_FORMAT_CAP (164 , 122 , VIDEO_PIX_FMT_Y4 ),
152- HM01B0_VIDEO_FORMAT_CAP (326 , 324 , VIDEO_PIX_FMT_Y4 ),
153- HM01B0_VIDEO_FORMAT_CAP (326 , 244 , VIDEO_PIX_FMT_Y4 ),
154- HM01B0_VIDEO_FORMAT_CAP (164 , 122 , VIDEO_PIX_FMT_SBGGR8 ),
155- HM01B0_VIDEO_FORMAT_CAP (326 , 324 , VIDEO_PIX_FMT_SBGGR8 ),
156- HM01B0_VIDEO_FORMAT_CAP (326 , 244 , VIDEO_PIX_FMT_SBGGR8 ),
283+ HM01B0_VIDEO_FORMAT_CAP (324 , 244 , VIDEO_PIX_FMT_Y4 ),
284+ HM01B0_VIDEO_FORMAT_CAP (324 , 324 , VIDEO_PIX_FMT_Y4 ),
285+ HM01B0_VIDEO_FORMAT_CAP (324 , 244 , VIDEO_PIX_FMT_SBGGR8 ),
286+ HM01B0_VIDEO_FORMAT_CAP (324 , 324 , VIDEO_PIX_FMT_SBGGR8 ),
157287 {0 },
158288};
159289
@@ -291,30 +421,43 @@ static int hm01b0_set_frmival(const struct device *dev, struct video_frmival *fr
291421 struct video_format fmt ;
292422 struct hm01b0_data * drv_data = dev -> data ;
293423 int ret ;
294-
295424 uint32_t osc_div = 0 ;
296425 bool highres = false;
426+ struct video_frmival_enum fie = {.format = & drv_data -> fmt , .discrete = * frmival };
297427
298428 ret = hm01b0_get_fmt (dev , & fmt );
299429 if (ret < 0 ) {
300430 LOG_ERR ("Can not get format!" );
301431 return ret ;
302432 }
303433
304- if (fmt .width == 320 ) {
434+ if (fmt .width == 320 && fmt . height == 320 ) {
305435 highres = true;
306436 }
307437
438+ video_closest_frmival (dev , & fie );
308439
309- if (frmival -> numerator <= 15 ) {
310- osc_div = highres ? 0x01 : 0x00 ;
311- } else if (frmival -> numerator <= 30 ) {
312- osc_div = highres ? 0x02 : 0x01 ;
313- } else if (frmival -> numerator <= 60 ) {
440+ /*
441+ * Note: in highres mode max FPS is 45 else 60
442+ * OSC clock divider: 00=/8, 01=/4, 10=/2, 11=/1
443+ */
444+
445+ switch (fie .index ) {
446+ case HM01B0_60_FPS :
447+ osc_div = 0x03 ;
448+ break ;
449+ case HM01B0_30_FPS :
314450 osc_div = highres ? 0x03 : 0x02 ;
315- } else {
316- /* Set to the max possible FPS at this resolution. */
317- osc_div = 3 ;
451+ break ;
452+ case HM01B0_15_FPS :
453+ osc_div = highres ? 0x02 : 0x01 ;
454+ break ;
455+ case HM01B0_8_FPS :
456+ osc_div = 0x00 ;
457+ break ;
458+ default :
459+ LOG_ERR ("Unsupported frame interval value" );
460+ return - ENOTSUP ;
318461 }
319462
320463 osc_div |= 0x8 ;
@@ -352,6 +495,31 @@ static int hm01b0_get_frmival(const struct device *dev, struct video_frmival *fr
352495 return 0 ;
353496}
354497
498+ int hm01b0_enum_frmival (const struct device * dev , struct video_frmival_enum * fie )
499+ {
500+ switch (fie -> index ) {
501+ case HM01B0_60_FPS :
502+ fie -> discrete .denominator = 60 ;
503+ break ;
504+ case HM01B0_30_FPS :
505+ fie -> discrete .denominator = 30 ;
506+ break ;
507+ case HM01B0_15_FPS :
508+ fie -> discrete .denominator = 15 ;
509+ break ;
510+ case HM01B0_8_FPS :
511+ fie -> discrete .denominator = 8 ;
512+ break ;
513+ default :
514+ return - EINVAL ;
515+ }
516+
517+ fie -> type = VIDEO_FRMIVAL_TYPE_DISCRETE ;
518+ fie -> discrete .numerator = 1 ;
519+
520+ return 0 ;
521+ }
522+
355523static int hm01b0_init_controls (const struct device * dev )
356524{
357525 int ret ;
@@ -424,6 +592,7 @@ static DEVICE_API(video, hm01b0_driver_api) = {
424592 .get_caps = hm01b0_get_caps ,
425593 .set_frmival = hm01b0_set_frmival ,
426594 .get_frmival = hm01b0_get_frmival ,
595+ .enum_frmival = hm01b0_enum_frmival ,
427596};
428597
429598static bool hm01b0_check_connection (const struct device * dev )
@@ -530,6 +699,15 @@ static int hm01b0_init(const struct device *dev)
530699 return ret ;
531700 }
532701
702+ /* Try to reset the registers to the same as Arduino did at reset */
703+ ret = video_write_cci_multiregs (& config -> i2c , hm01b0_default_regs ,
704+ ARRAY_SIZE (hm01b0_default_regs ));
705+ if (ret < 0 ) {
706+ LOG_ERR ("Failed to write config list registers (%d)" , ret );
707+ return ret ;
708+ }
709+
710+
533711 struct video_format fmt = {
534712 .pixelformat = VIDEO_PIX_FMT_GREY ,
535713 .width = 160 ,
0 commit comments