d5c654914e
Fix default_value of ioctl(VIDIOC_QUERYCTRL)(id=V4L2_CID_3A_STATUS) to AE operating and AWB operating, because both AE and AWB are automatical adjustment mode by default.
3879 lines
98 KiB
C
3879 lines
98 KiB
C
/****************************************************************************
|
|
* drivers/video/isx019.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
#include <nuttx/i2c/i2c_master.h>
|
|
#include <nuttx/signal.h>
|
|
#include <nuttx/clock.h>
|
|
#include <arch/board/board.h>
|
|
#include <nuttx/video/isx019.h>
|
|
#include <nuttx/video/imgsensor.h>
|
|
#include <math.h>
|
|
#include <nuttx/mutex.h>
|
|
|
|
#include "isx019_reg.h"
|
|
#include "isx019_range.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* Wait time on power on sequence. */
|
|
|
|
#define TRANSITION_TIME_TO_STARTUP (130 * USEC_PER_MSEC) /* unit : usec */
|
|
#define TRANSITION_TIME_TO_STREAMING (40 * USEC_PER_MSEC) /* unit : usec */
|
|
#define DELAY_TIME_JPEGDQT_SWAP (35 * USEC_PER_MSEC) /* unit : usec */
|
|
|
|
/* For get_supported_value() I/F */
|
|
|
|
#define SET_RANGE(range, min, max, s, def) \
|
|
do \
|
|
{ \
|
|
(range).minimum = (min); \
|
|
(range).maximum = (max); \
|
|
(range).step = (s); \
|
|
(range).default_value = (def); \
|
|
} \
|
|
while (0);
|
|
|
|
#define SET_DISCRETE(disc, nr, val, def) \
|
|
do \
|
|
{ \
|
|
(disc).nr_values = (nr); \
|
|
(disc).values = (val); \
|
|
(disc).default_value = (def); \
|
|
} \
|
|
while (0);
|
|
|
|
#define SET_ELEMS(elem, nr, min, max, s) \
|
|
do \
|
|
{ \
|
|
(elem).nr_elems = (nr); \
|
|
(elem).minimum = (min); \
|
|
(elem).maximum = (max); \
|
|
(elem).step = (s); \
|
|
} \
|
|
while (0);
|
|
|
|
#define COMPARE_FRAMESIZE(w, h, sup_w, sup_h) (((w) == (sup_w)) && \
|
|
((h) == (sup_h)))
|
|
|
|
#define VALIDATE_FRAMESIZE(w, h) (COMPARE_FRAMESIZE((w), (h), 1280, 960) || \
|
|
COMPARE_FRAMESIZE((w), (h), 1280, 720) || \
|
|
COMPARE_FRAMESIZE((w), (h), 640, 480) || \
|
|
COMPARE_FRAMESIZE((w), (h), 640, 360) || \
|
|
COMPARE_FRAMESIZE((w), (h), 480, 360) || \
|
|
COMPARE_FRAMESIZE((w), (h), 320, 240) || \
|
|
COMPARE_FRAMESIZE((w), (h), 160, 120))
|
|
|
|
#define VALIDATE_THUMNAIL_SIZE(m, s) (((s) != 0) && \
|
|
((m) % (s) == 0) && \
|
|
((m) / (s) < 5) && \
|
|
((m) / (s) > 0))
|
|
|
|
/* For set_value() and get_value() I/F */
|
|
|
|
#define SET_REGINFO(a, c, o, t, s) do \
|
|
{ \
|
|
(a)->category = (c); \
|
|
(a)->offset = (o); \
|
|
(a)->type = (t); \
|
|
(a)->size = (s); \
|
|
} \
|
|
while (0);
|
|
|
|
/* Register type, which represents the number of bits and
|
|
* whether it is signed or unsigned.
|
|
*/
|
|
|
|
#define ISX019_REGTYPE_INT8 (0)
|
|
#define ISX019_REGTYPE_UINT8 (1)
|
|
#define ISX019_REGTYPE_INT16 (2)
|
|
|
|
#define SET_REGINFO_INT8(a, c, o) SET_REGINFO(a, c, o, ISX019_REGTYPE_INT8, 1)
|
|
#define SET_REGINFO_UINT8(a, c, o) SET_REGINFO(a, c, o, ISX019_REGTYPE_UINT8, 1)
|
|
#define SET_REGINFO_INT16(a, c, o) SET_REGINFO(a, c, o, ISX019_REGTYPE_INT16, 2)
|
|
|
|
#define VALIDATE_RANGE(v, min, max, step) (((v) >= (min)) && \
|
|
((v) <= (max)) && \
|
|
(((v) - (min)) % (step) == 0))
|
|
|
|
/* Offset for IMGSENSOR_ID_3A_PARAMETER control */
|
|
|
|
#define OFFSET_3APARAMETER_AWB_R (0)
|
|
#define OFFSET_3APARAMETER_AWB_B (2)
|
|
#define OFFSET_3APARAMETER_AE_SHTTIME (4)
|
|
#define OFFSET_3APARAMETER_AE_GAIN (8)
|
|
|
|
/* Index of array for drive mode setting */
|
|
|
|
#define INDEX_SENS (0)
|
|
#define INDEX_POST (1)
|
|
#define INDEX_SENSPOST (2)
|
|
#define INDEX_IO (3)
|
|
|
|
/* Timer value for power on control */
|
|
|
|
#define ISX019_ACCESSIBLE_WAIT_SEC (0)
|
|
#define ISX019_ACCESSIBLE_WAIT_USEC (200000)
|
|
#define FPGA_ACCESSIBLE_WAIT_SEC (1)
|
|
#define FPGA_ACCESSIBLE_WAIT_USEC (0)
|
|
|
|
/* Array size of DQT setting for JPEG quality */
|
|
|
|
#define JPEG_DQT_ARRAY_SIZE (64)
|
|
|
|
/* ISX019 standard master clock */
|
|
|
|
#define ISX019_STANDARD_MASTER_CLOCK (27000000)
|
|
|
|
/* Vivid colors setting */
|
|
|
|
#define VIVID_COLORS_SATURATION (0xf0)
|
|
#define VIVID_COLORS_SHARPNESS (0x20)
|
|
|
|
/* Black white colors setting */
|
|
|
|
#define BW_COLORS_SATURATION (0x00)
|
|
|
|
/* Definition for calculation of extended frame number */
|
|
|
|
#define VTIME_PER_FRAME (30518)
|
|
#define INTERVAL_PER_FRAME (33333)
|
|
|
|
/* ISX019 image sensor output frame size. */
|
|
|
|
#define ISX019_WIDTH (1280)
|
|
#define ISX019_HEIGHT (960)
|
|
|
|
/* The number of whole image splits for spot position decision. */
|
|
|
|
#define ISX019_SPOT_POSITION_SPLIT_NUM_X (9)
|
|
#define ISX019_SPOT_POSITION_SPLIT_NUM_Y (7)
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct isx019_default_value_s
|
|
{
|
|
int32_t brightness;
|
|
int32_t contrast;
|
|
int32_t saturation;
|
|
int32_t hue;
|
|
int32_t awb;
|
|
int32_t gamma;
|
|
int32_t ev;
|
|
int32_t hflip_video;
|
|
int32_t vflip_video;
|
|
int32_t hflip_still;
|
|
int32_t vflip_still;
|
|
int32_t sharpness;
|
|
int32_t ae;
|
|
int32_t wbmode;
|
|
int32_t hdr;
|
|
int32_t iso_auto;
|
|
int32_t meter;
|
|
int32_t spot_pos;
|
|
int32_t threealock;
|
|
int32_t jpgquality;
|
|
};
|
|
|
|
typedef struct isx019_default_value_s isx019_default_value_t;
|
|
|
|
struct isx019_rect_s
|
|
{
|
|
int32_t left;
|
|
int32_t top;
|
|
uint32_t width;
|
|
uint32_t height;
|
|
};
|
|
|
|
typedef struct isx019_rect_s isx019_rect_t;
|
|
|
|
struct isx019_dev_s
|
|
{
|
|
struct imgsensor_s sensor;
|
|
mutex_t fpga_lock;
|
|
mutex_t i2c_lock;
|
|
FAR struct i2c_master_s *i2c;
|
|
struct i2c_config_s i2c_cfg;
|
|
float clock_ratio;
|
|
isx019_default_value_t default_value;
|
|
imgsensor_stream_type_t stream;
|
|
imgsensor_white_balance_t wb_mode;
|
|
uint8_t flip_video;
|
|
uint8_t flip_still;
|
|
isx019_rect_t clip_video;
|
|
isx019_rect_t clip_still;
|
|
double gamma;
|
|
int32_t jpg_quality;
|
|
int32_t hue;
|
|
imgsensor_colorfx_t colorfx;
|
|
};
|
|
|
|
typedef struct isx019_dev_s isx019_dev_t;
|
|
|
|
typedef CODE int32_t (*convert_t)(int32_t value32);
|
|
|
|
typedef CODE int (*setvalue_t)(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t value);
|
|
typedef CODE int (*getvalue_t)(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *value);
|
|
|
|
struct isx019_reginfo_s
|
|
{
|
|
uint16_t category;
|
|
uint16_t offset;
|
|
uint8_t type;
|
|
uint8_t size;
|
|
};
|
|
|
|
typedef struct isx019_reginfo_s isx019_reginfo_t;
|
|
|
|
struct isx019_fpga_jpg_quality_s
|
|
{
|
|
/* JPEG quality */
|
|
|
|
int quality;
|
|
|
|
/* DQT header setting for y component */
|
|
|
|
uint8_t y_head[JPEG_DQT_ARRAY_SIZE];
|
|
|
|
/* DQT calculation data for y component */
|
|
|
|
uint8_t y_calc[JPEG_DQT_ARRAY_SIZE];
|
|
|
|
/* DQT header setting for c component */
|
|
|
|
uint8_t c_head[JPEG_DQT_ARRAY_SIZE];
|
|
|
|
/* DQT calculation data for c component */
|
|
|
|
uint8_t c_calc[JPEG_DQT_ARRAY_SIZE];
|
|
};
|
|
|
|
typedef struct isx019_fpga_jpg_quality_s isx019_fpga_jpg_quality_t;
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static bool isx019_is_available(FAR struct imgsensor_s *sensor);
|
|
static int isx019_init(FAR struct imgsensor_s *sensor);
|
|
static int isx019_uninit(FAR struct imgsensor_s *sensor);
|
|
static FAR const char *
|
|
isx019_get_driver_name(FAR struct imgsensor_s *sensor);
|
|
static int isx019_validate_frame_setting(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
uint8_t nr_datafmt,
|
|
FAR imgsensor_format_t *datafmts,
|
|
FAR imgsensor_interval_t *interval);
|
|
static int isx019_start_capture(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
uint8_t nr_datafmt,
|
|
FAR imgsensor_format_t *datafmts,
|
|
FAR imgsensor_interval_t *interval);
|
|
static int isx019_stop_capture(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type);
|
|
static int isx019_get_frame_interval(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
FAR imgsensor_interval_t *interval);
|
|
static int isx019_get_supported_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id,
|
|
FAR imgsensor_supported_value_t *value);
|
|
static int isx019_get_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id, uint32_t size,
|
|
FAR imgsensor_value_t *value);
|
|
static int isx019_set_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id, uint32_t size,
|
|
imgsensor_value_t value);
|
|
static int initialize_jpg_quality(FAR isx019_dev_t *priv);
|
|
static void initialize_wbmode(FAR isx019_dev_t *priv);
|
|
static int send_read_cmd(FAR isx019_dev_t *priv,
|
|
FAR const struct i2c_config_s *config,
|
|
uint8_t cat,
|
|
uint16_t addr,
|
|
uint8_t size);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const struct imgsensor_ops_s g_isx019_ops =
|
|
{
|
|
isx019_is_available,
|
|
isx019_init,
|
|
isx019_uninit,
|
|
isx019_get_driver_name,
|
|
isx019_validate_frame_setting,
|
|
isx019_start_capture,
|
|
isx019_stop_capture,
|
|
isx019_get_frame_interval,
|
|
isx019_get_supported_value,
|
|
isx019_get_value,
|
|
isx019_set_value,
|
|
};
|
|
|
|
static isx019_dev_t g_isx019_private =
|
|
{
|
|
{
|
|
&g_isx019_ops
|
|
},
|
|
NXMUTEX_INITIALIZER,
|
|
NXMUTEX_INITIALIZER,
|
|
};
|
|
|
|
static const isx019_fpga_jpg_quality_t g_isx019_jpg_quality[] =
|
|
{
|
|
{
|
|
10,
|
|
{
|
|
21, 16, 16, 26, 18, 26, 43, 21,
|
|
21, 43, 43, 43, 32, 43, 43, 43,
|
|
43, 43, 43, 43, 43, 64, 43, 43,
|
|
43, 43, 43, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
3, 4, 133, 131, 131, 131, 1, 1,
|
|
4, 135, 3, 131, 131, 131, 1, 1,
|
|
133, 3, 2, 131, 131, 1, 1, 1,
|
|
131, 131, 131, 131, 1, 1, 1, 1,
|
|
131, 131, 131, 1, 1, 1, 1, 1,
|
|
131, 131, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
},
|
|
{
|
|
21, 26, 26, 32, 26, 32, 43, 26,
|
|
26, 43, 64, 43, 32, 43, 64, 64,
|
|
64, 43, 43, 64, 64, 64, 64, 64,
|
|
43, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
3, 133, 2, 131, 1, 1, 1, 1,
|
|
133, 133, 133, 131, 1, 1, 1, 1,
|
|
2, 133, 2, 131, 1, 1, 1, 1,
|
|
131, 131, 131, 131, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
}
|
|
},
|
|
{
|
|
20,
|
|
{
|
|
18, 14, 14, 14, 16, 14, 21, 16,
|
|
16, 21, 32, 21, 16, 21, 32, 32,
|
|
26, 21, 21, 26, 32, 32, 26, 26,
|
|
26, 26, 26, 32, 43, 32, 32, 32,
|
|
32, 32, 32, 43, 43, 43, 43, 43,
|
|
43, 43, 43, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
135, 137, 137, 3, 2, 2, 2, 131,
|
|
137, 4, 4, 3, 133, 133, 2, 131,
|
|
137, 4, 4, 3, 133, 2, 131, 1,
|
|
3, 3, 3, 133, 2, 131, 1, 1,
|
|
2, 133, 133, 2, 131, 1, 1, 1,
|
|
2, 133, 2, 131, 1, 1, 1, 1,
|
|
2, 2, 131, 1, 1, 1, 1, 1,
|
|
131, 131, 1, 1, 1, 1, 1, 1,
|
|
},
|
|
{
|
|
21, 21, 21, 21, 26, 21, 26, 21,
|
|
21, 26, 26, 21, 26, 21, 26, 32,
|
|
26, 26, 26, 26, 32, 43, 32, 32,
|
|
32, 32, 32, 43, 64, 43, 43, 43,
|
|
43, 43, 43, 64, 64, 64, 43, 43,
|
|
43, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
3, 3, 3, 133, 133, 2, 131, 1,
|
|
3, 133, 3, 3, 133, 2, 131, 1,
|
|
3, 3, 133, 133, 2, 131, 1, 1,
|
|
133, 3, 133, 2, 131, 131, 1, 1,
|
|
133, 133, 2, 131, 131, 1, 1, 1,
|
|
2, 2, 131, 131, 1, 1, 1, 1,
|
|
131, 131, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
}
|
|
},
|
|
{
|
|
30,
|
|
{
|
|
16, 11, 11, 11, 12, 11, 16, 12,
|
|
12, 16, 21, 14, 13, 14, 21, 26,
|
|
21, 16, 16, 21, 26, 32, 21, 21,
|
|
21, 21, 21, 32, 32, 21, 26, 26,
|
|
26, 26, 21, 32, 32, 32, 32, 43,
|
|
32, 32, 32, 43, 43, 43, 43, 43,
|
|
43, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
4, 6, 6, 4, 3, 133, 2, 2,
|
|
6, 139, 139, 137, 3, 3, 3, 2,
|
|
6, 139, 5, 4, 3, 133, 2, 131,
|
|
4, 137, 4, 3, 133, 2, 131, 1,
|
|
3, 3, 3, 133, 131, 131, 1, 1,
|
|
133, 3, 133, 2, 131, 1, 1, 1,
|
|
2, 3, 2, 131, 1, 1, 1, 1,
|
|
2, 2, 131, 1, 1, 1, 1, 1,
|
|
},
|
|
{
|
|
16, 14, 14, 16, 18, 16, 21, 18,
|
|
18, 21, 21, 16, 21, 16, 21, 26,
|
|
21, 21, 21, 21, 26, 43, 26, 26,
|
|
26, 26, 26, 43, 43, 32, 32, 32,
|
|
32, 32, 32, 43, 43, 43, 43, 43,
|
|
43, 43, 43, 43, 43, 43, 43, 43,
|
|
43, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
4, 137, 4, 3, 3, 133, 131, 131,
|
|
137, 135, 135, 4, 3, 133, 2, 131,
|
|
4, 135, 3, 3, 133, 2, 131, 131,
|
|
3, 4, 3, 133, 2, 131, 131, 1,
|
|
3, 3, 133, 2, 131, 131, 1, 1,
|
|
133, 133, 2, 131, 131, 1, 1, 1,
|
|
131, 2, 131, 131, 1, 1, 1, 1,
|
|
131, 131, 131, 1, 1, 1, 1, 1,
|
|
}
|
|
},
|
|
{
|
|
40,
|
|
{
|
|
12, 8, 8, 8, 9, 8, 12, 9,
|
|
9, 12, 16, 11, 10, 11, 16, 21,
|
|
14, 12, 12, 14, 21, 26, 18, 18,
|
|
21, 18, 18, 26, 21, 18, 21, 21,
|
|
21, 21, 18, 21, 21, 26, 26, 32,
|
|
26, 26, 21, 32, 32, 43, 43, 32,
|
|
32, 43, 43, 43, 43, 43, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
139, 8, 8, 139, 4, 3, 133, 3,
|
|
8, 7, 7, 6, 137, 135, 135, 3,
|
|
8, 7, 141, 139, 135, 3, 133, 2,
|
|
139, 6, 139, 3, 3, 133, 2, 131,
|
|
4, 137, 135, 3, 2, 131, 131, 1,
|
|
3, 135, 3, 133, 131, 131, 1, 1,
|
|
133, 135, 133, 2, 131, 1, 1, 1,
|
|
3, 3, 2, 131, 1, 1, 1, 1,
|
|
},
|
|
{
|
|
13, 11, 11, 13, 14, 13, 16, 14,
|
|
14, 16, 21, 14, 14, 14, 21, 21,
|
|
16, 16, 16, 16, 21, 26, 21, 21,
|
|
21, 21, 21, 26, 32, 26, 21, 21,
|
|
21, 21, 26, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 43, 43, 32, 32, 43,
|
|
43, 43, 43, 43, 43, 43, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
},
|
|
{
|
|
5, 6, 5, 4, 3, 3, 133, 2,
|
|
6, 137, 137, 137, 4, 3, 133, 2,
|
|
5, 137, 137, 4, 3, 3, 2, 131,
|
|
4, 137, 4, 3, 3, 2, 131, 131,
|
|
3, 4, 3, 3, 2, 2, 131, 1,
|
|
3, 3, 3, 2, 2, 131, 1, 1,
|
|
133, 133, 2, 131, 131, 1, 1, 1,
|
|
2, 2, 131, 131, 1, 1, 1, 1,
|
|
}
|
|
},
|
|
{
|
|
50,
|
|
{
|
|
8, 6, 6, 6, 6, 6, 8, 6,
|
|
6, 8, 12, 8, 7, 8, 12, 14,
|
|
10, 8, 8, 10, 14, 16, 13, 13,
|
|
14, 13, 13, 16, 16, 12, 14, 13,
|
|
13, 14, 12, 16, 14, 18, 18, 21,
|
|
18, 18, 14, 26, 26, 26, 26, 26,
|
|
26, 32, 32, 32, 32, 32, 43, 43,
|
|
43, 43, 43, 43, 43, 43, 43, 43,
|
|
},
|
|
{
|
|
8, 11, 11, 8, 139, 137, 4, 4,
|
|
11, 11, 11, 8, 141, 5, 139, 137,
|
|
11, 11, 9, 8, 5, 137, 135, 133,
|
|
8, 8, 8, 137, 5, 135, 133, 2,
|
|
139, 141, 5, 5, 3, 133, 2, 131,
|
|
137, 5, 137, 135, 133, 2, 131, 131,
|
|
4, 139, 135, 133, 2, 131, 131, 131,
|
|
4, 137, 133, 2, 131, 131, 131, 131,
|
|
},
|
|
{
|
|
9, 8, 8, 9, 10, 9, 11, 9,
|
|
9, 11, 14, 11, 13, 11, 14, 16,
|
|
14, 14, 14, 14, 16, 18, 13, 13,
|
|
14, 13, 13, 18, 26, 16, 14, 14,
|
|
14, 14, 16, 26, 21, 21, 21, 21,
|
|
21, 21, 21, 26, 26, 26, 26, 26,
|
|
26, 32, 32, 32, 32, 32, 43, 43,
|
|
43, 43, 43, 43, 43, 43, 43, 43,
|
|
},
|
|
{
|
|
7, 8, 7, 6, 137, 4, 135, 133,
|
|
8, 141, 7, 6, 137, 5, 4, 3,
|
|
7, 7, 5, 137, 5, 137, 3, 133,
|
|
6, 6, 137, 137, 137, 3, 133, 2,
|
|
137, 137, 5, 137, 3, 133, 2, 131,
|
|
4, 5, 137, 3, 133, 2, 131, 131,
|
|
135, 4, 3, 133, 2, 131, 131, 131,
|
|
133, 3, 133, 2, 131, 131, 131, 131,
|
|
}
|
|
},
|
|
{
|
|
60,
|
|
{
|
|
6, 4, 4, 4, 5, 4, 6, 5,
|
|
5, 6, 9, 6, 5, 6, 9, 11,
|
|
8, 6, 6, 8, 11, 12, 10, 10,
|
|
11, 10, 10, 12, 16, 12, 12, 12,
|
|
12, 12, 12, 16, 12, 14, 14, 16,
|
|
14, 14, 12, 18, 18, 21, 21, 18,
|
|
18, 26, 26, 26, 26, 26, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
},
|
|
{
|
|
11, 16, 16, 11, 7, 6, 139, 4,
|
|
16, 13, 13, 11, 8, 141, 139, 139,
|
|
16, 13, 13, 11, 141, 139, 137, 135,
|
|
11, 11, 11, 6, 139, 137, 135, 133,
|
|
7, 8, 141, 139, 4, 3, 133, 2,
|
|
6, 141, 139, 137, 3, 133, 2, 2,
|
|
139, 139, 137, 135, 133, 2, 2, 2,
|
|
4, 139, 135, 133, 2, 2, 2, 2,
|
|
},
|
|
{
|
|
7, 7, 7, 13, 12, 13, 26, 16,
|
|
16, 26, 26, 21, 16, 21, 26, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32,
|
|
},
|
|
{
|
|
9, 9, 5, 133, 133, 2, 2, 2,
|
|
9, 139, 4, 3, 2, 2, 2, 2,
|
|
5, 4, 4, 2, 2, 2, 2, 2,
|
|
133, 3, 2, 2, 2, 2, 2, 2,
|
|
133, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
}
|
|
},
|
|
{
|
|
70,
|
|
{
|
|
4, 3, 3, 3, 3, 3, 4, 3,
|
|
3, 4, 6, 4, 3, 4, 6, 7,
|
|
5, 4, 4, 5, 7, 8, 6, 6,
|
|
7, 6, 6, 8, 10, 8, 9, 9,
|
|
9, 9, 8, 10, 10, 12, 12, 12,
|
|
12, 12, 10, 12, 12, 13, 13, 12,
|
|
12, 16, 16, 16, 16, 16, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
},
|
|
{
|
|
16, 21, 21, 16, 11, 9, 8, 141,
|
|
21, 21, 21, 16, 13, 11, 8, 141,
|
|
21, 21, 21, 16, 11, 7, 139, 139,
|
|
16, 16, 16, 9, 7, 139, 139, 4,
|
|
11, 13, 11, 7, 139, 5, 4, 3,
|
|
9, 11, 7, 139, 5, 4, 3, 3,
|
|
8, 8, 139, 139, 4, 3, 3, 3,
|
|
141, 141, 139, 4, 3, 3, 3, 3,
|
|
},
|
|
{
|
|
4, 5, 5, 8, 7, 8, 14, 10,
|
|
10, 14, 21, 14, 14, 14, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
},
|
|
{
|
|
16, 13, 8, 137, 3, 3, 3, 3,
|
|
13, 9, 141, 137, 3, 3, 3, 3,
|
|
8, 141, 137, 3, 3, 3, 3, 3,
|
|
137, 137, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
}
|
|
},
|
|
{
|
|
80,
|
|
{
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 3, 2, 2, 2, 3, 4,
|
|
3, 2, 2, 3, 4, 5, 4, 4,
|
|
4, 4, 4, 5, 6, 5, 5, 5,
|
|
5, 5, 5, 6, 6, 7, 7, 8,
|
|
7, 7, 6, 9, 9, 10, 10, 9,
|
|
9, 12, 12, 12, 12, 12, 12, 12,
|
|
12, 12, 12, 12, 12, 12, 12, 12,
|
|
},
|
|
{
|
|
32, 32, 32, 32, 21, 16, 13, 11,
|
|
32, 32, 32, 32, 21, 16, 13, 11,
|
|
32, 32, 32, 32, 16, 13, 9, 7,
|
|
32, 32, 32, 16, 13, 9, 7, 139,
|
|
21, 21, 16, 13, 8, 141, 139, 139,
|
|
16, 16, 13, 9, 141, 139, 139, 139,
|
|
13, 13, 9, 7, 139, 139, 139, 139,
|
|
11, 11, 7, 139, 139, 139, 139, 139,
|
|
},
|
|
{
|
|
3, 3, 3, 5, 4, 5, 9, 6,
|
|
6, 9, 13, 11, 9, 11, 13, 14,
|
|
14, 14, 14, 14, 14, 14, 12, 12,
|
|
12, 12, 12, 14, 14, 12, 12, 12,
|
|
12, 12, 12, 14, 12, 12, 12, 12,
|
|
12, 12, 12, 12, 12, 12, 12, 12,
|
|
12, 12, 12, 12, 12, 12, 12, 12,
|
|
12, 12, 12, 12, 12, 12, 12, 12,
|
|
},
|
|
{
|
|
21, 21, 13, 7, 5, 137, 137, 137,
|
|
21, 16, 11, 6, 137, 139, 139, 139,
|
|
13, 11, 7, 137, 139, 139, 139, 139,
|
|
7, 6, 137, 139, 139, 139, 139, 139,
|
|
5, 137, 139, 139, 139, 139, 139, 139,
|
|
137, 139, 139, 139, 139, 139, 139, 139,
|
|
137, 139, 139, 139, 139, 139, 139, 139,
|
|
137, 139, 139, 139, 139, 139, 139, 139,
|
|
}
|
|
},
|
|
{
|
|
90,
|
|
{
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 2, 1, 1, 1, 2, 2,
|
|
2, 1, 1, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 3, 2, 3, 3,
|
|
3, 3, 2, 3, 3, 4, 4, 4,
|
|
4, 4, 3, 5, 5, 5, 5, 5,
|
|
5, 7, 7, 7, 7, 7, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
},
|
|
{
|
|
64, 64, 64, 64, 32, 32, 32, 21,
|
|
64, 64, 64, 64, 32, 32, 32, 21,
|
|
64, 64, 64, 64, 32, 21, 16, 13,
|
|
64, 64, 64, 32, 21, 16, 13, 9,
|
|
32, 32, 32, 21, 16, 13, 9, 8,
|
|
32, 32, 21, 16, 13, 9, 8, 8,
|
|
32, 32, 16, 13, 9, 8, 8, 8,
|
|
21, 21, 13, 9, 8, 8, 8, 8,
|
|
},
|
|
{
|
|
1, 1, 1, 2, 2, 2, 5, 3,
|
|
3, 5, 7, 5, 4, 5, 7, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
},
|
|
{
|
|
64, 64, 32, 13, 9, 8, 8, 8,
|
|
64, 32, 21, 13, 8, 8, 8, 8,
|
|
32, 21, 16, 8, 8, 8, 8, 8,
|
|
13, 13, 8, 8, 8, 8, 8, 8,
|
|
9, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8,
|
|
}
|
|
},
|
|
{
|
|
100,
|
|
{
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
},
|
|
{
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 32,
|
|
64, 64, 64, 64, 64, 64, 32, 32,
|
|
64, 64, 64, 64, 64, 32, 32, 21,
|
|
64, 64, 64, 64, 32, 32, 21, 21,
|
|
64, 64, 64, 32, 32, 21, 21, 21,
|
|
64, 64, 32, 32, 21, 21, 21, 21,
|
|
},
|
|
{
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 2, 2, 1, 2, 2, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3,
|
|
},
|
|
{
|
|
64, 64, 64, 64, 32, 21, 21, 21,
|
|
64, 64, 64, 32, 21, 21, 21, 21,
|
|
64, 64, 64, 21, 21, 21, 21, 21,
|
|
64, 32, 21, 21, 21, 21, 21, 21,
|
|
32, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
21, 21, 21, 21, 21, 21, 21, 21,
|
|
}
|
|
}
|
|
};
|
|
|
|
#define NR_JPGSETTING_TBL \
|
|
(sizeof(g_isx019_jpg_quality) / sizeof(isx019_fpga_jpg_quality_t))
|
|
|
|
static const int32_t g_isx019_colorfx[] =
|
|
{
|
|
IMGSENSOR_COLORFX_NONE,
|
|
IMGSENSOR_COLORFX_BW,
|
|
IMGSENSOR_COLORFX_VIVID,
|
|
};
|
|
|
|
#define NR_COLORFX (sizeof(g_isx019_colorfx) / sizeof(int32_t))
|
|
|
|
static const int32_t g_isx019_wbmode[] =
|
|
{
|
|
IMGSENSOR_WHITE_BALANCE_AUTO,
|
|
IMGSENSOR_WHITE_BALANCE_INCANDESCENT,
|
|
IMGSENSOR_WHITE_BALANCE_FLUORESCENT,
|
|
IMGSENSOR_WHITE_BALANCE_DAYLIGHT,
|
|
IMGSENSOR_WHITE_BALANCE_CLOUDY,
|
|
IMGSENSOR_WHITE_BALANCE_SHADE,
|
|
};
|
|
|
|
#define NR_WBMODE (sizeof(g_isx019_wbmode) / sizeof(int32_t))
|
|
|
|
static const int32_t g_isx019_iso[] =
|
|
{
|
|
1000, /* ISO1 */
|
|
1200, /* ISO1.2 */
|
|
1600, /* ISO1.6 */
|
|
2000, /* ISO2 */
|
|
2500, /* ISO2.5 */
|
|
3000, /* ISO3 */
|
|
4000, /* ISO4 */
|
|
5000, /* ISO5 */
|
|
6000, /* ISO6 */
|
|
8000, /* ISO8 */
|
|
10000, /* ISO10 */
|
|
12000, /* ISO12 */
|
|
16000, /* ISO16 */
|
|
20000, /* ISO20 */
|
|
25000, /* ISO25 */
|
|
32000, /* ISO32 */
|
|
40000, /* ISO40 */
|
|
50000, /* ISO50 */
|
|
64000, /* ISO64 */
|
|
80000, /* ISO80 */
|
|
100000, /* ISO100 */
|
|
125000, /* ISO125 */
|
|
160000, /* ISO160 */
|
|
200000, /* ISO200 */
|
|
250000, /* ISO250 */
|
|
320000, /* ISO320 */
|
|
400000, /* ISO400 */
|
|
500000, /* ISO500 */
|
|
640000, /* ISO640 */
|
|
800000, /* ISO800 */
|
|
1000000, /* ISO1000 */
|
|
1250000, /* ISO1250 */
|
|
1600000, /* ISO1600 */
|
|
2000000, /* ISO2000 */
|
|
2500000, /* ISO2500 */
|
|
3200000, /* ISO3200 */
|
|
4000000, /* ISO4000 */
|
|
5000000, /* ISO5000 */
|
|
};
|
|
|
|
#define NR_ISO (sizeof(g_isx019_iso) / sizeof(int32_t))
|
|
|
|
/* Gain values corresponding to each element of g_isx019_iso table.
|
|
* This needs to have the same size as g_isx019_iso.
|
|
*/
|
|
|
|
static const uint8_t g_isx019_gain[] =
|
|
{
|
|
1, /* gain for ISO1 */
|
|
2, /* gain for ISO1.2 */
|
|
3, /* gain for ISO1.6 */
|
|
4, /* gain for ISO2 */
|
|
5, /* gain for ISO2.5 */
|
|
6, /* gain for ISO3 */
|
|
7, /* gain for ISO4 */
|
|
8, /* gain for ISO5 */
|
|
9, /* gain for ISO6 */
|
|
10, /* gain for ISO8 */
|
|
11, /* gain for ISO10 */
|
|
12, /* gain for ISO12 */
|
|
13, /* gain for ISO16 */
|
|
14, /* gain for ISO20 */
|
|
15, /* gain for ISO25 */
|
|
16, /* gain for ISO32 */
|
|
17, /* gain for ISO40 */
|
|
18, /* gain for ISO50 */
|
|
19, /* gain for ISO64 */
|
|
20, /* gain for ISO80 */
|
|
21, /* gain for ISO100 */
|
|
22, /* gain for ISO125 */
|
|
23, /* gain for ISO160 */
|
|
24, /* gain for ISO200 */
|
|
25, /* gain for ISO250 */
|
|
26, /* gain for ISO320 */
|
|
27, /* gain for ISO400 */
|
|
28, /* gain for ISO500 */
|
|
29, /* gain for ISO640 */
|
|
30, /* gain for ISO800 */
|
|
31, /* gain for ISO1000 */
|
|
32, /* gain for ISO1250 */
|
|
33, /* gain for ISO1600 */
|
|
34, /* gain for ISO2000 */
|
|
35, /* gain for ISO2500 */
|
|
36, /* gain for ISO3200 */
|
|
37, /* gain for ISO4000 */
|
|
38, /* gain for ISO5000 */
|
|
};
|
|
|
|
static const int32_t g_isx019_iso_auto[] =
|
|
{
|
|
IMGSENSOR_ISO_SENSITIVITY_MANUAL,
|
|
IMGSENSOR_ISO_SENSITIVITY_AUTO,
|
|
};
|
|
|
|
#define NR_ISO_AUTO (sizeof(g_isx019_iso_auto) / sizeof(int32_t))
|
|
|
|
static const int32_t g_isx019_metering[] =
|
|
{
|
|
IMGSENSOR_EXPOSURE_METERING_AVERAGE,
|
|
IMGSENSOR_EXPOSURE_METERING_CENTER_WEIGHTED,
|
|
IMGSENSOR_EXPOSURE_METERING_SPOT,
|
|
IMGSENSOR_EXPOSURE_METERING_MATRIX,
|
|
};
|
|
|
|
#define NR_METERING (sizeof(g_isx019_metering) / sizeof(int32_t))
|
|
|
|
static const int32_t g_isx019_ae[] =
|
|
{
|
|
IMGSENSOR_EXPOSURE_AUTO,
|
|
IMGSENSOR_EXPOSURE_MANUAL,
|
|
};
|
|
|
|
#define NR_AE (sizeof(g_isx019_ae) / sizeof(int32_t))
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
static int fpga_i2c_write(FAR isx019_dev_t *priv, uint8_t addr,
|
|
FAR const void *data, uint8_t size)
|
|
{
|
|
static uint8_t buf[FPGA_I2C_REGSIZE_MAX + FPGA_I2C_REGADDR_LEN];
|
|
int ret;
|
|
|
|
DEBUGASSERT(size <= FPGA_I2C_REGSIZE_MAX);
|
|
|
|
priv->i2c_cfg.address = FPGA_I2C_SLVADDR;
|
|
|
|
nxmutex_lock(&priv->i2c_lock);
|
|
buf[FPGA_I2C_OFFSET_ADDR] = addr;
|
|
memcpy(&buf[FPGA_I2C_OFFSET_WRITEDATA], data, size);
|
|
ret = i2c_write(priv->i2c,
|
|
&priv->i2c_cfg,
|
|
buf,
|
|
size + FPGA_I2C_REGADDR_LEN);
|
|
nxmutex_unlock(&priv->i2c_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fpga_i2c_read(FAR isx019_dev_t *priv, uint8_t addr,
|
|
FAR void *data, uint8_t size)
|
|
{
|
|
int ret;
|
|
|
|
DEBUGASSERT(size <= FPGA_I2C_REGSIZE_MAX);
|
|
|
|
priv->i2c_cfg.address = FPGA_I2C_SLVADDR;
|
|
|
|
nxmutex_lock(&priv->i2c_lock);
|
|
ret = i2c_write(priv->i2c,
|
|
&priv->i2c_cfg,
|
|
&addr,
|
|
FPGA_I2C_REGADDR_LEN);
|
|
if (ret >= 0)
|
|
{
|
|
ret = i2c_read(priv->i2c, &priv->i2c_cfg, data, size);
|
|
}
|
|
|
|
nxmutex_unlock(&priv->i2c_lock);
|
|
return ret;
|
|
}
|
|
|
|
static void fpga_activate_setting(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t regval = FPGA_ACTIVATE_REQUEST;
|
|
fpga_i2c_write(priv, FPGA_ACTIVATE, ®val, 1);
|
|
|
|
while (1)
|
|
{
|
|
fpga_i2c_read(priv, FPGA_ACTIVATE, ®val, 1);
|
|
if (regval == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint8_t calc_isx019_chksum(FAR const uint8_t *data, uint8_t len)
|
|
{
|
|
int i;
|
|
uint8_t chksum = 0;
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
/* ISX019 checksum is lower 8bit of addition result.
|
|
* So, no problem even if overflow occur.
|
|
*/
|
|
|
|
chksum += data[i];
|
|
}
|
|
|
|
return chksum;
|
|
}
|
|
|
|
static bool validate_isx019_chksum(FAR const uint8_t *data, uint8_t len)
|
|
{
|
|
uint8_t chksum;
|
|
|
|
chksum = calc_isx019_chksum(data, len - 1);
|
|
|
|
return data[len - 1] == chksum;
|
|
}
|
|
|
|
static int recv_write_response(FAR isx019_dev_t *priv,
|
|
FAR const struct i2c_config_s *config)
|
|
{
|
|
int ret;
|
|
uint8_t buf[ISX019_I2C_WRRES_TOTALLEN];
|
|
|
|
ret = i2c_read(priv->i2c, config, buf, sizeof(buf));
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ((buf[ISX019_I2C_OFFSET_TOTALLEN] != ISX019_I2C_WRRES_TOTALLEN) ||
|
|
(buf[ISX019_I2C_OFFSET_CMDNUM] != 1) ||
|
|
(buf[ISX019_I2C_OFFSET_CMDLEN] != ISX019_I2C_WRRES_LEN) ||
|
|
(buf[ISX019_I2C_OFFSET_STS] != ISX019_I2C_STS_OK) ||
|
|
!validate_isx019_chksum(buf, ISX019_I2C_WRRES_TOTALLEN))
|
|
{
|
|
return -EPROTO;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int recv_read_response(FAR isx019_dev_t *priv,
|
|
FAR const struct i2c_config_s *config,
|
|
FAR void *data,
|
|
uint8_t size)
|
|
{
|
|
int ret;
|
|
uint8_t buf[ISX019_I2C_WRREQ_TOTALLEN(ISX019_I2C_REGSIZE_MAX)] =
|
|
{
|
|
0
|
|
};
|
|
|
|
DEBUGASSERT(size <= ISX019_I2C_REGSIZE_MAX);
|
|
|
|
ret = i2c_read(priv->i2c,
|
|
config, buf, ISX019_I2C_RDRES_TOTALLEN(size));
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
if ((buf[ISX019_I2C_OFFSET_TOTALLEN] != ISX019_I2C_RDRES_TOTALLEN(size)) ||
|
|
(buf[ISX019_I2C_OFFSET_CMDNUM] != 1) ||
|
|
(buf[ISX019_I2C_OFFSET_CMDLEN] != ISX019_I2C_RDRES_LEN(size)) ||
|
|
(buf[ISX019_I2C_OFFSET_STS] != ISX019_I2C_STS_OK) ||
|
|
!validate_isx019_chksum(buf, ISX019_I2C_RDRES_TOTALLEN(size)))
|
|
{
|
|
return -EPROTO;
|
|
}
|
|
|
|
memcpy(data, &buf[ISX019_I2C_OFFSET_READDATA], size);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int send_write_cmd(FAR isx019_dev_t *priv,
|
|
FAR const struct i2c_config_s *config,
|
|
uint8_t cat,
|
|
uint16_t addr,
|
|
FAR const void *data,
|
|
uint8_t size)
|
|
{
|
|
int len;
|
|
uint8_t buf[ISX019_I2C_WRREQ_TOTALLEN(ISX019_I2C_REGSIZE_MAX)] =
|
|
{
|
|
0
|
|
};
|
|
|
|
DEBUGASSERT(size <= ISX019_I2C_REGSIZE_MAX);
|
|
|
|
buf[ISX019_I2C_OFFSET_TOTALLEN] = ISX019_I2C_WRREQ_TOTALLEN(size);
|
|
buf[ISX019_I2C_OFFSET_CMDNUM] = 1;
|
|
buf[ISX019_I2C_OFFSET_CMDLEN] = ISX019_I2C_WRREQ_LEN(size);
|
|
buf[ISX019_I2C_OFFSET_CMD] = ISX019_I2C_CMD_WRITE;
|
|
buf[ISX019_I2C_OFFSET_CATEGORY] = cat;
|
|
buf[ISX019_I2C_OFFSET_ADDRESS_H] = addr >> 8;
|
|
buf[ISX019_I2C_OFFSET_ADDRESS_L] = addr & 0xff;
|
|
|
|
memcpy(&buf[ISX019_I2C_OFFSET_WRITEDATA], data, size);
|
|
|
|
len = ISX019_I2C_OFFSET_WRITEDATA + size;
|
|
buf[len] = calc_isx019_chksum(buf, len);
|
|
len++;
|
|
|
|
return i2c_write(priv->i2c, config, buf, len);
|
|
}
|
|
|
|
static int isx019_i2c_write(FAR isx019_dev_t *priv,
|
|
uint8_t cat,
|
|
uint16_t addr,
|
|
FAR const void *data,
|
|
uint8_t size)
|
|
{
|
|
int ret;
|
|
|
|
DEBUGASSERT(size <= ISX019_I2C_REGSIZE_MAX);
|
|
|
|
priv->i2c_cfg.address = ISX019_I2C_SLVADDR;
|
|
|
|
nxmutex_lock(&priv->i2c_lock);
|
|
|
|
ret = send_write_cmd(priv, &priv->i2c_cfg, cat, addr, data, size);
|
|
if (ret == OK)
|
|
{
|
|
ret = recv_write_response(priv, &priv->i2c_cfg);
|
|
}
|
|
|
|
nxmutex_unlock(&priv->i2c_lock);
|
|
return ret;
|
|
}
|
|
|
|
static int send_read_cmd(FAR isx019_dev_t *priv,
|
|
FAR const struct i2c_config_s *config,
|
|
uint8_t cat,
|
|
uint16_t addr,
|
|
uint8_t size)
|
|
{
|
|
int ret;
|
|
int len;
|
|
uint8_t buf[ISX019_I2C_RDREQ_TOTALLEN] =
|
|
{
|
|
0
|
|
};
|
|
|
|
buf[ISX019_I2C_OFFSET_TOTALLEN] = ISX019_I2C_RDREQ_TOTALLEN;
|
|
buf[ISX019_I2C_OFFSET_CMDNUM] = 1;
|
|
buf[ISX019_I2C_OFFSET_CMDLEN] = ISX019_I2C_RDREQ_LEN;
|
|
buf[ISX019_I2C_OFFSET_CMD] = ISX019_I2C_CMD_READ;
|
|
buf[ISX019_I2C_OFFSET_CATEGORY] = cat;
|
|
buf[ISX019_I2C_OFFSET_ADDRESS_H] = addr >> 8;
|
|
buf[ISX019_I2C_OFFSET_ADDRESS_L] = addr & 0xff;
|
|
buf[ISX019_I2C_OFFSET_READSIZE] = size;
|
|
|
|
len = ISX019_I2C_OFFSET_READSIZE + 1;
|
|
buf[len] = calc_isx019_chksum(buf, len);
|
|
len++;
|
|
|
|
ret = i2c_write(priv->i2c, config, buf, len);
|
|
return ret;
|
|
}
|
|
|
|
static int isx019_i2c_read(FAR isx019_dev_t *priv,
|
|
uint8_t cat,
|
|
uint16_t addr,
|
|
FAR void *data,
|
|
uint8_t size)
|
|
{
|
|
int ret;
|
|
|
|
DEBUGASSERT(size <= ISX019_I2C_REGSIZE_MAX);
|
|
|
|
priv->i2c_cfg.address = ISX019_I2C_SLVADDR;
|
|
|
|
nxmutex_lock(&priv->i2c_lock);
|
|
|
|
ret = send_read_cmd(priv, &priv->i2c_cfg, cat, addr, size);
|
|
if (ret == OK)
|
|
{
|
|
ret = recv_read_response(priv, &priv->i2c_cfg, data, size);
|
|
}
|
|
|
|
nxmutex_unlock(&priv->i2c_lock);
|
|
return ret;
|
|
}
|
|
|
|
static void fpga_init(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t regval;
|
|
|
|
regval = FPGA_RESET_ENABLE;
|
|
fpga_i2c_write(priv, FPGA_RESET, ®val, 1);
|
|
regval = FPGA_DATA_OUTPUT_STOP;
|
|
fpga_i2c_write(priv, FPGA_DATA_OUTPUT, ®val, 1);
|
|
fpga_activate_setting(priv);
|
|
regval = FPGA_RESET_RELEASE;
|
|
fpga_i2c_write(priv, FPGA_RESET, ®val, 1);
|
|
fpga_activate_setting(priv);
|
|
}
|
|
|
|
static int set_drive_mode(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t drv[] =
|
|
{
|
|
#ifdef CONFIG_VIDEO_ISX019_DOL2
|
|
DOL2_30FPS_SENS, DOL2_30FPS_POST, DOL2_30FPS_SENSPOST, DOL2_30FPS_IO
|
|
#else
|
|
DOL3_30FPS_SENS, DOL3_30FPS_POST, DOL3_30FPS_SENSPOST, DOL3_30FPS_IO
|
|
#endif
|
|
};
|
|
|
|
nxsig_usleep(TRANSITION_TIME_TO_STARTUP);
|
|
|
|
isx019_i2c_write(priv, CAT_CONFIG, MODE_SENSSEL, &drv[INDEX_SENS], 1);
|
|
isx019_i2c_write(priv, CAT_CONFIG, MODE_POSTSEL, &drv[INDEX_POST], 1);
|
|
isx019_i2c_write(priv,
|
|
CAT_CONFIG, MODE_SENSPOST_SEL, &drv[INDEX_SENSPOST], 1);
|
|
|
|
nxsig_usleep(TRANSITION_TIME_TO_STREAMING);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static bool try_repeat(int sec, int usec, FAR isx019_dev_t *priv,
|
|
CODE int (*trial_func)(FAR isx019_dev_t *))
|
|
{
|
|
int ret;
|
|
struct timespec start;
|
|
struct timespec now;
|
|
struct timespec delta;
|
|
|
|
ret = clock_systime_timespec(&start);
|
|
if (ret < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
ret = trial_func(priv);
|
|
if (ret >= 0)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ret = clock_systime_timespec(&now);
|
|
if (ret < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
clock_timespec_subtract(&now, &start, &delta);
|
|
if ((delta.tv_sec > sec) ||
|
|
((delta.tv_sec == sec) &&
|
|
(delta.tv_nsec > (usec * NSEC_PER_USEC))))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
static int try_isx019_i2c(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t buf;
|
|
return isx019_i2c_read(priv, CAT_SYSCOM, DEVSTS, &buf, 1);
|
|
}
|
|
|
|
static int try_fpga_i2c(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t buf;
|
|
return fpga_i2c_read(priv, FPGA_VERSION, &buf, 1);
|
|
}
|
|
|
|
static void power_on(FAR isx019_dev_t *priv)
|
|
{
|
|
priv->i2c = board_isx019_initialize();
|
|
priv->i2c_cfg.frequency = ISX019_I2C_FREQUENCY;
|
|
priv->i2c_cfg.addrlen = ISX019_I2C_SLVADDR_LEN;
|
|
board_isx019_power_on();
|
|
board_isx019_release_reset();
|
|
}
|
|
|
|
static void power_off(FAR isx019_dev_t *priv)
|
|
{
|
|
board_isx019_set_reset();
|
|
board_isx019_power_off();
|
|
board_isx019_uninitialize(priv->i2c);
|
|
}
|
|
|
|
static bool isx019_is_available(FAR struct imgsensor_s *sensor)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
bool ret;
|
|
|
|
power_on(priv);
|
|
|
|
/* Try to access via I2C
|
|
* about both ISX019 image sensor and FPGA.
|
|
*/
|
|
|
|
ret = false;
|
|
if (try_repeat(ISX019_ACCESSIBLE_WAIT_SEC,
|
|
ISX019_ACCESSIBLE_WAIT_USEC,
|
|
priv, try_isx019_i2c))
|
|
{
|
|
if (try_repeat(FPGA_ACCESSIBLE_WAIT_SEC,
|
|
FPGA_ACCESSIBLE_WAIT_USEC,
|
|
priv, try_fpga_i2c))
|
|
{
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
power_off(priv);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t get_value32(FAR isx019_dev_t *priv, uint32_t id)
|
|
{
|
|
imgsensor_value_t val;
|
|
isx019_get_value(&priv->sensor, id, 0, &val);
|
|
return val.value32;
|
|
}
|
|
|
|
static void store_default_value(FAR isx019_dev_t *priv)
|
|
{
|
|
FAR isx019_default_value_t *def = &priv->default_value;
|
|
|
|
def->brightness = get_value32(priv, IMGSENSOR_ID_BRIGHTNESS);
|
|
def->contrast = get_value32(priv, IMGSENSOR_ID_CONTRAST);
|
|
def->saturation = get_value32(priv, IMGSENSOR_ID_SATURATION);
|
|
def->hue = get_value32(priv, IMGSENSOR_ID_HUE);
|
|
def->awb = get_value32(priv, IMGSENSOR_ID_AUTO_WHITE_BALANCE);
|
|
def->gamma = get_value32(priv, IMGSENSOR_ID_GAMMA);
|
|
def->ev = get_value32(priv, IMGSENSOR_ID_EXPOSURE);
|
|
def->hflip_video = get_value32(priv, IMGSENSOR_ID_HFLIP_VIDEO);
|
|
def->vflip_video = get_value32(priv, IMGSENSOR_ID_VFLIP_VIDEO);
|
|
def->hflip_still = get_value32(priv, IMGSENSOR_ID_HFLIP_STILL);
|
|
def->vflip_still = get_value32(priv, IMGSENSOR_ID_VFLIP_STILL);
|
|
def->sharpness = get_value32(priv, IMGSENSOR_ID_SHARPNESS);
|
|
def->ae = get_value32(priv, IMGSENSOR_ID_EXPOSURE_AUTO);
|
|
def->wbmode = get_value32(priv, IMGSENSOR_ID_AUTO_N_PRESET_WB);
|
|
def->hdr = get_value32(priv, IMGSENSOR_ID_WIDE_DYNAMIC_RANGE);
|
|
def->iso_auto = get_value32(priv, IMGSENSOR_ID_ISO_SENSITIVITY_AUTO);
|
|
def->meter = get_value32(priv, IMGSENSOR_ID_EXPOSURE_METERING);
|
|
def->spot_pos = get_value32(priv, IMGSENSOR_ID_SPOT_POSITION);
|
|
def->threealock = get_value32(priv, IMGSENSOR_ID_3A_LOCK);
|
|
def->jpgquality = get_value32(priv, IMGSENSOR_ID_JPEG_QUALITY);
|
|
}
|
|
|
|
static int isx019_init(FAR struct imgsensor_s *sensor)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
uint32_t clk;
|
|
|
|
power_on(priv);
|
|
set_drive_mode(priv);
|
|
fpga_init(priv);
|
|
initialize_wbmode(priv);
|
|
initialize_jpg_quality(priv);
|
|
|
|
/* Set initial gamma value for getting current value API. */
|
|
|
|
priv->gamma = 1000;
|
|
|
|
/* Because store_default_value() needs the clock ratio,
|
|
* clock_ratio has to be calculated first.
|
|
*/
|
|
|
|
clk = board_isx019_get_master_clock();
|
|
priv->clock_ratio = (float)clk / ISX019_STANDARD_MASTER_CLOCK;
|
|
store_default_value(priv);
|
|
|
|
/* Store initial HUE value for getting current value API. */
|
|
|
|
priv->hue = priv->default_value.hue;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int isx019_uninit(FAR struct imgsensor_s *sensor)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
|
|
power_off(priv);
|
|
return OK;
|
|
}
|
|
|
|
static FAR const char *isx019_get_driver_name(FAR struct imgsensor_s *sensor)
|
|
{
|
|
#ifdef CONFIG_VIDEO_ISX019_NAME_WITH_VERSION
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
static char name[20];
|
|
uint8_t f_ver = 0;
|
|
uint16_t is_ver = 0;
|
|
|
|
isx019_i2c_read(priv, CAT_VERSION, ROM_VERSION, &is_ver, 2);
|
|
fpga_i2c_read(priv, FPGA_VERSION, &f_ver, 1);
|
|
snprintf(name, sizeof(name), "ISX019 v%04x_%02d", is_ver, f_ver);
|
|
|
|
return name;
|
|
#else
|
|
return "ISX019";
|
|
#endif
|
|
}
|
|
|
|
static int validate_format(int nr_fmt, FAR imgsensor_format_t *fmt)
|
|
{
|
|
int ret;
|
|
|
|
uint16_t main_w;
|
|
uint16_t main_h;
|
|
uint16_t sub_w;
|
|
uint16_t sub_h;
|
|
|
|
if ((nr_fmt < 1) || (nr_fmt > 2))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (fmt == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
main_w = fmt[IMGSENSOR_FMT_MAIN].width;
|
|
main_h = fmt[IMGSENSOR_FMT_MAIN].height;
|
|
|
|
switch (fmt[IMGSENSOR_FMT_MAIN].pixelformat)
|
|
{
|
|
case IMGSENSOR_PIX_FMT_UYVY: /* YUV 4:2:2 */
|
|
case IMGSENSOR_PIX_FMT_RGB565: /* RGB565 */
|
|
case IMGSENSOR_PIX_FMT_JPEG: /* JPEG */
|
|
case IMGSENSOR_PIX_FMT_JPEG_WITH_SUBIMG: /* JPEG + sub image */
|
|
|
|
if (!VALIDATE_FRAMESIZE(main_w, main_h))
|
|
{
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (nr_fmt > 1)
|
|
{
|
|
sub_w = fmt[IMGSENSOR_FMT_SUB].width;
|
|
sub_h = fmt[IMGSENSOR_FMT_SUB].height;
|
|
if (!VALIDATE_THUMNAIL_SIZE(main_w, sub_w) ||
|
|
!VALIDATE_THUMNAIL_SIZE(main_h, sub_h))
|
|
{
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret = OK;
|
|
break;
|
|
|
|
default: /* otherwise */
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_frameinterval(FAR imgsensor_interval_t *interval)
|
|
{
|
|
int ret = -EINVAL;
|
|
|
|
if (interval == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Avoid multiplication overflow */
|
|
|
|
if ((interval->denominator * 10) / 10 != interval->denominator)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Avoid division by zero */
|
|
|
|
if (interval->numerator == 0)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch ((interval->denominator * 10) / interval->numerator)
|
|
{
|
|
case 300: /* 30FPS */
|
|
case 150: /* 15FPS */
|
|
case 100: /* 10FPS */
|
|
case 75: /* 7.5FPS */
|
|
ret = OK;
|
|
break;
|
|
|
|
default: /* otherwise */
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int isx019_validate_frame_setting(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
uint8_t nr_fmt,
|
|
FAR imgsensor_format_t *fmt,
|
|
FAR imgsensor_interval_t *interval)
|
|
{
|
|
int ret = OK;
|
|
|
|
ret = validate_format(nr_fmt, fmt);
|
|
if (ret != OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
return validate_frameinterval(interval);
|
|
}
|
|
|
|
static int activate_flip(FAR isx019_dev_t *priv,
|
|
imgsensor_stream_type_t type)
|
|
{
|
|
uint8_t flip;
|
|
|
|
flip = (type == IMGSENSOR_STREAM_TYPE_VIDEO) ?
|
|
priv->flip_video : priv->flip_still;
|
|
|
|
return isx019_i2c_write(priv, CAT_CONFIG, REVERSE, &flip, 1);
|
|
}
|
|
|
|
static int activate_clip(FAR isx019_dev_t *priv,
|
|
imgsensor_stream_type_t type,
|
|
uint16_t w,
|
|
uint16_t h)
|
|
{
|
|
FAR isx019_rect_t *clip;
|
|
uint8_t size;
|
|
uint8_t top;
|
|
uint8_t left = 0;
|
|
|
|
clip = (type == IMGSENSOR_STREAM_TYPE_VIDEO) ?
|
|
&priv->clip_video : &priv->clip_still;
|
|
|
|
switch (w)
|
|
{
|
|
case 1280:
|
|
if (clip->width == 640) /* In this case, c_h == 360 */
|
|
{
|
|
size = FPGA_CLIP_640_360;
|
|
top = clip->top / FPGA_CLIP_UNIT;
|
|
left = clip->left / FPGA_CLIP_UNIT;
|
|
|
|
if (h == 720)
|
|
{
|
|
/* Shift (960 - 720) / 2 lines */
|
|
|
|
top += 120 / FPGA_CLIP_UNIT;
|
|
}
|
|
}
|
|
else if (clip->width == 1280)
|
|
{
|
|
/* In this case, clip->height == 720 */
|
|
|
|
size = FPGA_CLIP_1280_720;
|
|
top = clip->top / FPGA_CLIP_UNIT;
|
|
left = clip->left / FPGA_CLIP_UNIT;
|
|
}
|
|
else /* no clip */
|
|
{
|
|
if (h == 720)
|
|
{
|
|
size = FPGA_CLIP_1280_720;
|
|
|
|
/* Shift (960 - 720) / 2 lines */
|
|
|
|
top = 120 / FPGA_CLIP_UNIT;
|
|
}
|
|
else
|
|
{
|
|
size = FPGA_CLIP_NON;
|
|
top = 0;
|
|
left = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 640:
|
|
if (clip->width == 640)
|
|
{
|
|
/* In this case, clip->height == 360 */
|
|
|
|
size = FPGA_CLIP_640_360;
|
|
top = clip->top / FPGA_CLIP_UNIT;
|
|
left = clip->left / FPGA_CLIP_UNIT;
|
|
}
|
|
else /* no clip */
|
|
{
|
|
if (h == 360)
|
|
{
|
|
size = FPGA_CLIP_640_360;
|
|
|
|
/* Shift (480 - 360) / 2 lines */
|
|
|
|
top = 60 / FPGA_CLIP_UNIT;
|
|
}
|
|
else
|
|
{
|
|
size = FPGA_CLIP_NON;
|
|
top = 0;
|
|
left = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default: /* Otherwise, clear clip setting. */
|
|
size = FPGA_CLIP_NON;
|
|
top = 0;
|
|
left = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
fpga_i2c_write(priv, FPGA_CLIP_SIZE, &size, 1);
|
|
fpga_i2c_write(priv, FPGA_CLIP_TOP, &top, 1);
|
|
fpga_i2c_write(priv, FPGA_CLIP_LEFT, &left, 1);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int isx019_start_capture(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
uint8_t nr_fmt,
|
|
FAR imgsensor_format_t *fmt,
|
|
FAR imgsensor_interval_t *interval)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
int ret;
|
|
uint8_t regval = 0;
|
|
|
|
ret = isx019_validate_frame_setting(sensor, type, nr_fmt, fmt, interval);
|
|
if (ret != OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = activate_flip(priv, type);
|
|
if (ret != OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
nxmutex_lock(&priv->fpga_lock);
|
|
|
|
/* Update FORMAT_AND_SCALE register of FPGA */
|
|
|
|
switch (fmt[IMGSENSOR_FMT_MAIN].pixelformat)
|
|
{
|
|
case IMGSENSOR_PIX_FMT_RGB565:
|
|
regval |= FPGA_FORMAT_RGB;
|
|
break;
|
|
|
|
case IMGSENSOR_PIX_FMT_UYVY:
|
|
regval |= FPGA_FORMAT_YUV;
|
|
break;
|
|
|
|
case IMGSENSOR_PIX_FMT_JPEG:
|
|
regval |= FPGA_FORMAT_JPEG;
|
|
break;
|
|
|
|
default: /* IMGSENSOR_PIX_FMT_JPEG_WITH_SUBIMG */
|
|
if (nr_fmt == 1)
|
|
{
|
|
regval |= FPGA_FORMAT_JPEG;
|
|
}
|
|
else
|
|
{
|
|
regval |= FPGA_FORMAT_THUMBNAIL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
switch (fmt[IMGSENSOR_FMT_MAIN].width)
|
|
{
|
|
case 1280:
|
|
regval |= FPGA_SCALE_1280_960;
|
|
break;
|
|
|
|
case 640:
|
|
regval |= FPGA_SCALE_640_480;
|
|
break;
|
|
|
|
case 320:
|
|
regval |= FPGA_SCALE_320_240;
|
|
break;
|
|
|
|
default: /* 160 */
|
|
regval |= FPGA_SCALE_160_120;
|
|
break;
|
|
}
|
|
|
|
activate_clip(priv, type,
|
|
fmt[IMGSENSOR_FMT_MAIN].width,
|
|
fmt[IMGSENSOR_FMT_MAIN].height);
|
|
|
|
fpga_i2c_write(priv, FPGA_FORMAT_AND_SCALE, ®val, 1);
|
|
|
|
/* Update FPS_AND_THUMBNAIL register of FPGA */
|
|
|
|
regval = 0;
|
|
|
|
if (nr_fmt == 2)
|
|
{
|
|
switch (fmt[IMGSENSOR_FMT_MAIN].width / fmt[IMGSENSOR_FMT_SUB].width)
|
|
{
|
|
case 1 : /* 1/1 */
|
|
regval |= FPGA_THUMBNAIL_SCALE_1_1;
|
|
break;
|
|
|
|
case 2 : /* 1/2 */
|
|
regval |= FPGA_THUMBNAIL_SCALE_1_2;
|
|
break;
|
|
|
|
case 4 : /* 1/4 */
|
|
regval |= FPGA_THUMBNAIL_SCALE_1_4;
|
|
break;
|
|
|
|
default : /* 1/8 */
|
|
regval |= FPGA_THUMBNAIL_SCALE_1_8;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch ((interval->denominator * 10) / interval->numerator)
|
|
{
|
|
case 300: /* 30FPS */
|
|
regval |= FPGA_FPS_1_1;
|
|
break;
|
|
|
|
case 150: /* 15FPS */
|
|
regval |= FPGA_FPS_1_2;
|
|
break;
|
|
|
|
case 100: /* 10FPS */
|
|
regval |= FPGA_FPS_1_3;
|
|
break;
|
|
|
|
case 75: /* 7.5FPS */
|
|
regval |= FPGA_FPS_1_4;
|
|
break;
|
|
|
|
default: /* otherwise */
|
|
|
|
/* It may not come here because the value has already been validated
|
|
* in validate_frameinterval().
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
fpga_i2c_write(priv, FPGA_FPS_AND_THUMBNAIL, ®val, 1);
|
|
|
|
regval = FPGA_DATA_OUTPUT_START;
|
|
fpga_i2c_write(priv, FPGA_DATA_OUTPUT, ®val, 1);
|
|
|
|
fpga_activate_setting(priv);
|
|
nxmutex_unlock(&priv->fpga_lock);
|
|
priv->stream = type;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int isx019_stop_capture(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
static int calc_gcm(int a, int b)
|
|
{
|
|
int r;
|
|
|
|
DEBUGASSERT((a != 0) && (b != 0));
|
|
|
|
while ((r = a % b) != 0)
|
|
{
|
|
a = b;
|
|
b = r;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
static int isx019_get_frame_interval(FAR struct imgsensor_s *sensor,
|
|
imgsensor_stream_type_t type,
|
|
FAR imgsensor_interval_t *interval)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
uint32_t vtime = VTIME_PER_FRAME;
|
|
uint32_t frame = 1;
|
|
uint8_t fps = FPGA_FPS_1_1;
|
|
int decimation = 1;
|
|
int gcm;
|
|
|
|
if (interval == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* ISX019's base frame interval = 1/30. */
|
|
|
|
interval->denominator = 30;
|
|
interval->numerator = 1;
|
|
|
|
/* ISX019 has the frame extension feature, which automatically
|
|
* exposes longer than one frame in dark environment.
|
|
* The number of extended frame is calculated from V_TIME register,
|
|
* which has the value
|
|
* VTIME_PER_FRAME + INTERVAL_PER_FRAME * (frame number - 1)
|
|
*/
|
|
|
|
isx019_i2c_read(priv, CAT_AESOUT, V_TIME, &vtime, 4);
|
|
frame = 1 + (vtime - VTIME_PER_FRAME) / INTERVAL_PER_FRAME;
|
|
interval->numerator *= frame;
|
|
|
|
/* Also, consider frame decimation by FPGA.
|
|
* decimation amount is gotten from FPGA register.
|
|
*/
|
|
|
|
fpga_i2c_read(priv, FPGA_FPS_AND_THUMBNAIL, &fps, 1);
|
|
switch (fps & FPGA_FPS_BITS)
|
|
{
|
|
case FPGA_FPS_1_1:
|
|
decimation = 1;
|
|
break;
|
|
|
|
case FPGA_FPS_1_2:
|
|
decimation = 2;
|
|
break;
|
|
|
|
case FPGA_FPS_1_3:
|
|
decimation = 3;
|
|
break;
|
|
|
|
default: /* FPGA_FPS_1_4 */
|
|
decimation = 4;
|
|
break;
|
|
}
|
|
|
|
interval->numerator *= decimation;
|
|
|
|
/* Reduce the fraction. */
|
|
|
|
gcm = calc_gcm(30, frame * decimation);
|
|
interval->denominator /= gcm;
|
|
interval->numerator /= gcm;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int isx019_get_supported_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id,
|
|
FAR imgsensor_supported_value_t *val)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
FAR struct isx019_default_value_s *def = &priv->default_value;
|
|
int ret = OK;
|
|
|
|
DEBUGASSERT(val);
|
|
|
|
switch (id)
|
|
{
|
|
case IMGSENSOR_ID_BRIGHTNESS:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_BRIGHTNESS, MAX_BRIGHTNESS,
|
|
STEP_BRIGHTNESS, def->brightness);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_CONTRAST:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_CONTRAST, MAX_CONTRAST,
|
|
STEP_CONTRAST, def->contrast);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SATURATION:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_SATURATION, MAX_SATURATION,
|
|
STEP_SATURATION, def->saturation);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HUE:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_HUE, MAX_HUE,
|
|
STEP_HUE, def->hue);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_WHITE_BALANCE:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BOOLEAN;
|
|
SET_RANGE(val->u.range, MIN_AWB, MAX_AWB,
|
|
STEP_AWB, def->awb);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_GAMMA:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_GAMMA, MAX_GAMMA,
|
|
STEP_GAMMA, def->gamma);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_EXPOSURE, MAX_EXPOSURE,
|
|
STEP_EXPOSURE, def->ev);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_VIDEO:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BOOLEAN;
|
|
SET_RANGE(val->u.range, MIN_HFLIP, MAX_HFLIP,
|
|
STEP_HFLIP, def->hflip_video);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_VIDEO:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BOOLEAN;
|
|
SET_RANGE(val->u.range, MIN_VFLIP, MAX_VFLIP,
|
|
STEP_VFLIP, def->vflip_video);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_STILL:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BOOLEAN;
|
|
SET_RANGE(val->u.range, MIN_HFLIP, MAX_HFLIP,
|
|
STEP_HFLIP, def->hflip_still);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_STILL:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BOOLEAN;
|
|
SET_RANGE(val->u.range, MIN_VFLIP, MAX_VFLIP,
|
|
STEP_VFLIP, def->hflip_still);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SHARPNESS:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_SHARPNESS, MAX_SHARPNESS,
|
|
STEP_SHARPNESS, def->sharpness);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_COLORFX:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_COLORFX,
|
|
g_isx019_colorfx,
|
|
IMGSENSOR_COLORFX_NONE);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_AUTO:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_AE,
|
|
g_isx019_ae,
|
|
IMGSENSOR_EXPOSURE_AUTO);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_ABSOLUTE:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_EXPOSURETIME, MAX_EXPOSURETIME,
|
|
STEP_EXPOSURETIME, 0); /* 0 means undefined */
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_N_PRESET_WB:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_WBMODE,
|
|
g_isx019_wbmode,
|
|
IMGSENSOR_WHITE_BALANCE_AUTO);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_WIDE_DYNAMIC_RANGE:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_HDR, MAX_HDR,
|
|
STEP_HDR, def->hdr);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_ISO,
|
|
g_isx019_iso,
|
|
0); /* 0 means undefined */
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY_AUTO:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_ISO_AUTO,
|
|
g_isx019_iso_auto,
|
|
IMGSENSOR_ISO_SENSITIVITY_AUTO);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_METERING:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
|
|
SET_DISCRETE(val->u.discrete,
|
|
NR_METERING,
|
|
g_isx019_metering,
|
|
IMGSENSOR_EXPOSURE_METERING_AVERAGE);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SPOT_POSITION:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_SPOTPOS, MAX_SPOTPOS,
|
|
STEP_SPOTPOS, def->spot_pos);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_LOCK:
|
|
val->type = IMGSENSOR_CTRL_TYPE_BITMASK;
|
|
SET_RANGE(val->u.range, MIN_3ALOCK, MAX_3ALOCK,
|
|
STEP_3ALOCK, def->threealock);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_PARAMETER:
|
|
val->type = IMGSENSOR_CTRL_TYPE_U8;
|
|
SET_ELEMS(val->u.elems, NRELEM_3APARAM, MIN_3APARAM, MAX_3APARAM,
|
|
STEP_3APARAM);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_STATUS:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_3ASTATUS,
|
|
MAX_3ASTATUS, STEP_3ASTATUS,
|
|
IMGSENSOR_3A_STATUS_AE_OPERATING
|
|
| IMGSENSOR_3A_STATUS_AWB_OPERATING);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_JPEG_QUALITY:
|
|
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
|
|
SET_RANGE(val->u.range, MIN_JPGQUALITY, MAX_JPGQUALITY,
|
|
STEP_JPGQUALITY, def->jpgquality);
|
|
break;
|
|
|
|
case IMGSENSOR_ID_CLIP_VIDEO:
|
|
case IMGSENSOR_ID_CLIP_STILL:
|
|
val->type = IMGSENSOR_CTRL_TYPE_U32;
|
|
SET_ELEMS(val->u.elems, NRELEM_CLIP, MIN_CLIP, MAX_CLIP,
|
|
STEP_CLIP);
|
|
break;
|
|
|
|
default:
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t not_convert(int32_t val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
static int32_t convert_brightness_is2reg(int32_t val)
|
|
{
|
|
return (val * 4);
|
|
}
|
|
|
|
static int32_t convert_brightness_reg2is(int32_t val)
|
|
{
|
|
return (val / 4);
|
|
}
|
|
|
|
static int32_t convert_hdr_is2reg(int32_t val)
|
|
{
|
|
int32_t ret = AEWDMODE_AUTO;
|
|
|
|
switch (val)
|
|
{
|
|
case 0:
|
|
ret = AEWDMODE_NORMAL;
|
|
break;
|
|
|
|
case 1:
|
|
ret = AEWDMODE_AUTO;
|
|
break;
|
|
|
|
case 2:
|
|
ret = AEWDMODE_HDR;
|
|
break;
|
|
|
|
default:
|
|
/* It may not come here because the value has already been validated
|
|
* in validate_value().
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t convert_hdr_reg2is(int32_t val)
|
|
{
|
|
int32_t ret;
|
|
|
|
switch (val)
|
|
{
|
|
case AEWDMODE_NORMAL:
|
|
ret = 0;
|
|
break;
|
|
|
|
case AEWDMODE_AUTO:
|
|
ret = 1;
|
|
break;
|
|
|
|
default: /* AEWDMODE_HDR */
|
|
ret = 2;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static convert_t get_reginfo(uint32_t id, bool is_set,
|
|
FAR isx019_reginfo_t *reg)
|
|
{
|
|
convert_t cvrt = NULL;
|
|
|
|
DEBUGASSERT(reg);
|
|
|
|
switch (id)
|
|
{
|
|
case IMGSENSOR_ID_BRIGHTNESS:
|
|
SET_REGINFO_INT16(reg, CAT_PICTTUNE, UIBRIGHTNESS);
|
|
cvrt = is_set ? convert_brightness_is2reg
|
|
: convert_brightness_reg2is;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_CONTRAST:
|
|
SET_REGINFO_UINT8(reg, CAT_PICTTUNE, UICONTRAST);
|
|
cvrt = not_convert;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SATURATION:
|
|
SET_REGINFO_UINT8(reg, CAT_PICTTUNE, UISATURATION);
|
|
cvrt = not_convert;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE:
|
|
SET_REGINFO_INT8(reg, CAT_AEDGRM, EVSEL);
|
|
cvrt = not_convert;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SHARPNESS:
|
|
SET_REGINFO_UINT8(reg, CAT_PICTTUNE, UISHARPNESS);
|
|
cvrt = not_convert;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_WIDE_DYNAMIC_RANGE:
|
|
SET_REGINFO_UINT8(reg, CAT_AEWD, AEWDMODE);
|
|
cvrt = is_set ? convert_hdr_is2reg : convert_hdr_reg2is;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return cvrt;
|
|
}
|
|
|
|
static int set_hue(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
int ret;
|
|
int val32 = val.value32 * 90 / 128;
|
|
|
|
ret = isx019_i2c_write(priv, CAT_PICTTUNE, UIHUE, &val32, 1);
|
|
if (ret == OK)
|
|
{
|
|
/* Store value before conversion for get_hue(). */
|
|
|
|
priv->hue = val.value32;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void set_flip(FAR uint8_t *flip, uint8_t direction, int32_t val)
|
|
{
|
|
DEBUGASSERT(flip);
|
|
|
|
*flip = (val == 0) ? (*flip & ~direction) : (*flip | direction);
|
|
}
|
|
|
|
static int set_hflip_video(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
set_flip(&priv->flip_video, H_REVERSE, val.value32);
|
|
if (priv->stream == IMGSENSOR_STREAM_TYPE_VIDEO)
|
|
{
|
|
activate_flip(priv, IMGSENSOR_STREAM_TYPE_VIDEO);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_vflip_video(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
set_flip(&priv->flip_video, V_REVERSE, val.value32);
|
|
if (priv->stream == IMGSENSOR_STREAM_TYPE_VIDEO)
|
|
{
|
|
activate_flip(priv, IMGSENSOR_STREAM_TYPE_VIDEO);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_hflip_still(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
set_flip(&priv->flip_still, H_REVERSE, val.value32);
|
|
if (priv->stream == IMGSENSOR_STREAM_TYPE_STILL)
|
|
{
|
|
activate_flip(priv, IMGSENSOR_STREAM_TYPE_STILL);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_vflip_still(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
set_flip(&priv->flip_still, V_REVERSE, val.value32);
|
|
if (priv->stream == IMGSENSOR_STREAM_TYPE_STILL)
|
|
{
|
|
activate_flip(priv, IMGSENSOR_STREAM_TYPE_STILL);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_colorfx(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
int ret = -EINVAL;
|
|
FAR isx019_default_value_t *def = &priv->default_value;
|
|
int32_t sat;
|
|
int32_t sharp;
|
|
|
|
/* ISX019 realize color effects by adjusting saturation and sharpness. */
|
|
|
|
switch (val.value32)
|
|
{
|
|
case IMGSENSOR_COLORFX_NONE:
|
|
|
|
sat = def->saturation;
|
|
sharp = def->sharpness;
|
|
break;
|
|
|
|
case IMGSENSOR_COLORFX_BW:
|
|
|
|
sat = BW_COLORS_SATURATION;
|
|
sharp = def->sharpness;
|
|
break;
|
|
|
|
case IMGSENSOR_COLORFX_VIVID:
|
|
|
|
sat = VIVID_COLORS_SATURATION;
|
|
sharp = VIVID_COLORS_SHARPNESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* It may not come here because the value has already been validated
|
|
* in validate_value().
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
ret = isx019_i2c_write(priv, CAT_PICTTUNE, UISATURATION, &sat, 1);
|
|
if (ret == OK)
|
|
{
|
|
ret = isx019_i2c_write(priv, CAT_PICTTUNE, UISHARPNESS, &sharp, 1);
|
|
if (ret == OK)
|
|
{
|
|
priv->colorfx = val.value32;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int set_ae(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint32_t regval = 0;
|
|
|
|
if (val.value32 == IMGSENSOR_EXPOSURE_AUTO)
|
|
{
|
|
regval = 0;
|
|
}
|
|
else
|
|
{
|
|
isx019_i2c_read(priv, CAT_AESOUT, SHT_TIME, ®val, 4);
|
|
}
|
|
|
|
return isx019_i2c_write(priv, CAT_CATAE, SHT_PRIMODE, ®val, 4);
|
|
}
|
|
|
|
static int set_exptime(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint32_t regval;
|
|
|
|
/* Take into account the master clock and convert unit.
|
|
* image sensor I/F : 100usec
|
|
* register : 1usec
|
|
*/
|
|
|
|
regval = val.value32 * 100 * priv->clock_ratio;
|
|
|
|
return isx019_i2c_write(priv, CAT_CATAE, SHT_PRIMODE, ®val, 4);
|
|
}
|
|
|
|
static int set_awb_hold(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t mode = AWBMODE_HOLD;
|
|
return isx019_i2c_write(priv, CAT_CATAWB, AWBMODE, &mode, 1);
|
|
}
|
|
|
|
static void initialize_wbmode(FAR isx019_dev_t *priv)
|
|
{
|
|
priv->wb_mode = IMGSENSOR_WHITE_BALANCE_AUTO;
|
|
}
|
|
|
|
static int update_wbmode_reg(FAR isx019_dev_t *priv,
|
|
int32_t val)
|
|
{
|
|
/* AWBMODE mode0 : auto, mode4 : user defined white balance
|
|
* AWBUSER_NO definition number for AWBMODE = mode4
|
|
* USER0_R, USER1_B : R,B value for AWBUSER_NO = 0
|
|
* USER1_R, USER1_B : R,B value for AWBUSER_NO = 1
|
|
*/
|
|
|
|
uint8_t mode;
|
|
uint16_t r_addr;
|
|
uint16_t b_addr;
|
|
uint16_t r;
|
|
uint16_t b;
|
|
static bool toggle = false;
|
|
|
|
if (toggle)
|
|
{
|
|
r_addr = USER0_R;
|
|
b_addr = USER0_B;
|
|
toggle = false;
|
|
}
|
|
else
|
|
{
|
|
r_addr = USER1_R;
|
|
b_addr = USER1_B;
|
|
toggle = true;
|
|
}
|
|
|
|
switch (val)
|
|
{
|
|
case IMGSENSOR_WHITE_BALANCE_AUTO:
|
|
mode = AWBMODE_AUTO;
|
|
break;
|
|
|
|
case IMGSENSOR_WHITE_BALANCE_INCANDESCENT:
|
|
r = RED_INCANDESCENT;
|
|
b = BLUE_INCANDESCENT;
|
|
mode = AWBMODE_MANUAL;
|
|
break;
|
|
|
|
case IMGSENSOR_WHITE_BALANCE_FLUORESCENT:
|
|
r = RED_FLUORESCENT;
|
|
b = BLUE_FLUORESCENT;
|
|
mode = AWBMODE_MANUAL;
|
|
break;
|
|
|
|
case IMGSENSOR_WHITE_BALANCE_DAYLIGHT:
|
|
r = RED_DAYLIGHT;
|
|
b = BLUE_DAYLIGHT;
|
|
mode = AWBMODE_MANUAL;
|
|
break;
|
|
|
|
case IMGSENSOR_WHITE_BALANCE_CLOUDY:
|
|
r = RED_CLOUDY;
|
|
b = BLUE_CLOUDY;
|
|
mode = AWBMODE_MANUAL;
|
|
break;
|
|
|
|
default: /* IMGSENSOR_WHITE_BALANCE_SHADE */
|
|
r = RED_SHADE;
|
|
b = BLUE_SHADE;
|
|
mode = AWBMODE_MANUAL;
|
|
break;
|
|
}
|
|
|
|
isx019_i2c_write(priv, CAT_AWB_USERTYPE, r_addr, &r, 2);
|
|
isx019_i2c_write(priv, CAT_AWB_USERTYPE, b_addr, &b, 2);
|
|
isx019_i2c_write(priv, CAT_CATAWB, AWBUSER_NO, &toggle, 1);
|
|
isx019_i2c_write(priv, CAT_CATAWB, AWBMODE, &mode, 1);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static bool is_awb_enable(FAR isx019_dev_t *priv)
|
|
{
|
|
uint8_t mode = AWBMODE_AUTO;
|
|
|
|
isx019_i2c_read(priv, CAT_CATAWB, AWBMODE, &mode, 1);
|
|
|
|
return mode != AWBMODE_HOLD;
|
|
}
|
|
|
|
static int set_wbmode(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
/* Update register only if IMGSENSOR_ID_AUTO_WHITE_BALANCE = 1. */
|
|
|
|
if (is_awb_enable(priv))
|
|
{
|
|
update_wbmode_reg(priv, val.value32);
|
|
}
|
|
|
|
priv->wb_mode = val.value32;
|
|
return OK;
|
|
}
|
|
|
|
static int set_awb(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
/* true -> false : Update regster to HOLD
|
|
* false -> true : Update register
|
|
* with IMGSENSOR_ID_AUTO_N_PRESET_WB setting
|
|
* otherwise : Nothing to do
|
|
*/
|
|
|
|
if (is_awb_enable(priv))
|
|
{
|
|
if (val.value32 == 0)
|
|
{
|
|
set_awb_hold(priv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (val.value32 == 1)
|
|
{
|
|
update_wbmode_reg(priv, priv->wb_mode);
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_meter(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint8_t normal;
|
|
uint8_t hdr;
|
|
|
|
switch (val.value32)
|
|
{
|
|
case IMGSENSOR_EXPOSURE_METERING_AVERAGE:
|
|
normal = AEWEIGHT_AVERAGE;
|
|
hdr = AEWEIGHTHDR_AVERAGE;
|
|
break;
|
|
|
|
case IMGSENSOR_EXPOSURE_METERING_CENTER_WEIGHTED:
|
|
normal = AEWEIGHT_CENTER;
|
|
hdr = AEWEIGHTHDR_CENTER;
|
|
break;
|
|
|
|
case IMGSENSOR_EXPOSURE_METERING_SPOT:
|
|
normal = AEWEIGHT_SPOT;
|
|
hdr = AEWEIGHTHDR_SPOT;
|
|
break;
|
|
|
|
default: /* IMGSENSOR_EXPOSURE_METERING_MATRIX */
|
|
normal = AEWEIGHT_MATRIX;
|
|
hdr = AEWEIGHTHDR_MATRIX;
|
|
break;
|
|
}
|
|
|
|
isx019_i2c_write(priv, CAT_AUTOCTRL, AEWEIGHTMODE, &normal, 1);
|
|
isx019_i2c_write(priv, CAT_AEWD, AEWEIGHTMODE_WD, &hdr, 1);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void get_current_framesize(FAR isx019_dev_t *priv,
|
|
FAR uint16_t *w, FAR uint16_t *h)
|
|
{
|
|
uint8_t frmsz;
|
|
|
|
DEBUGASSERT(w && h);
|
|
|
|
fpga_i2c_read(priv, FPGA_FORMAT_AND_SCALE, &frmsz, 1);
|
|
|
|
switch (frmsz & 0xf0)
|
|
{
|
|
case FPGA_SCALE_1280_960:
|
|
*w = 1280;
|
|
*h = 960;
|
|
break;
|
|
|
|
case FPGA_SCALE_640_480:
|
|
*w = 640;
|
|
*h = 480;
|
|
break;
|
|
|
|
case FPGA_SCALE_320_240:
|
|
*w = 320;
|
|
*h = 240;
|
|
break;
|
|
|
|
case FPGA_SCALE_160_120:
|
|
*w = 160;
|
|
*h = 120;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* It may not come here due to register specification */
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void get_current_clip_setting(FAR isx019_dev_t *priv,
|
|
FAR uint16_t *w,
|
|
FAR uint16_t *h,
|
|
FAR uint16_t *offset_x,
|
|
FAR uint16_t *offset_y)
|
|
{
|
|
uint8_t sz;
|
|
uint8_t top;
|
|
uint8_t left;
|
|
|
|
fpga_i2c_read(priv, FPGA_CLIP_SIZE, &sz, 1);
|
|
fpga_i2c_read(priv, FPGA_CLIP_TOP, &top, 1);
|
|
fpga_i2c_read(priv, FPGA_CLIP_LEFT, &left, 1);
|
|
|
|
*offset_x = left * FPGA_CLIP_UNIT;
|
|
*offset_y = top * FPGA_CLIP_UNIT;
|
|
|
|
switch (sz)
|
|
{
|
|
case FPGA_CLIP_NON:
|
|
*w = 0;
|
|
*h = 0;
|
|
*offset_x = 0;
|
|
*offset_y = 0;
|
|
break;
|
|
|
|
case FPGA_CLIP_1280_720:
|
|
*w = 1280;
|
|
*h = 720;
|
|
break;
|
|
|
|
case FPGA_CLIP_640_360:
|
|
*w = 640;
|
|
*h = 360;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* It may not come here due to register specification */
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int calc_spot_position_regval(uint16_t val,
|
|
uint16_t basis,
|
|
uint16_t sz,
|
|
uint16_t offset,
|
|
int split)
|
|
{
|
|
int ret;
|
|
int ratio;
|
|
|
|
/* Change basis from `sz` to `basis` about `val` and `offset`. */
|
|
|
|
ratio = basis / sz;
|
|
ret = val * ratio;
|
|
ret += (offset * FPGA_CLIP_UNIT * ratio);
|
|
|
|
return (ret * split) / basis;
|
|
}
|
|
|
|
static int set_spot_position(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint8_t regval;
|
|
uint8_t reg_x;
|
|
uint8_t reg_y;
|
|
uint16_t w;
|
|
uint16_t h;
|
|
uint16_t clip_w;
|
|
uint16_t clip_h;
|
|
uint16_t offset_x;
|
|
uint16_t offset_y;
|
|
uint16_t x = (uint16_t)(val.value32 >> 16);
|
|
uint16_t y = (uint16_t)(val.value32 & 0xffff);
|
|
int split;
|
|
|
|
/* Spot position of ISX019 is divided into 9x7 sections.
|
|
* - Horizontal direction is devided into 9 sections.
|
|
* - Vertical direction is divided into 7 sections.
|
|
* The register value 0 means left top.
|
|
* The register value 62 means right bottom.
|
|
* Then, the following ISX019 board flow.
|
|
* - image sensor output the 1280x960 image
|
|
* - FPGA scale
|
|
* - FPGA clipping
|
|
*/
|
|
|
|
get_current_framesize(priv, &w, &h);
|
|
if ((x >= w) || (y >= h))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y);
|
|
if ((clip_w != 0) && (clip_h != 0))
|
|
{
|
|
if ((x >= clip_w) || (y >= clip_h))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
split = ISX019_SPOT_POSITION_SPLIT_NUM_X;
|
|
reg_x = calc_spot_position_regval(x, 1280, w, offset_x, split);
|
|
split = ISX019_SPOT_POSITION_SPLIT_NUM_Y;
|
|
reg_y = calc_spot_position_regval(y, 960, h, offset_y, split);
|
|
|
|
regval = reg_y * ISX019_SPOT_POSITION_SPLIT_NUM_X + reg_x;
|
|
return isx019_i2c_write(priv, CAT_CATAE, SPOT_FRM_NUM, ®val, 1);
|
|
}
|
|
|
|
static int set_3alock(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint8_t regval;
|
|
|
|
regval = (val.value32 & IMGSENSOR_LOCK_WHITE_BALANCE) ? AWBMODE_HOLD
|
|
: AWBMODE_AUTO;
|
|
isx019_i2c_write(priv, CAT_CATAWB, AWBMODE, ®val, 1);
|
|
|
|
regval = (val.value32 & IMGSENSOR_LOCK_EXPOSURE) ? AEMODE_HOLD
|
|
: AEMODE_AUTO;
|
|
isx019_i2c_write(priv, CAT_CATAE, AEMODE, ®val, 1);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_3aparameter(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint16_t gain;
|
|
uint8_t regval;
|
|
|
|
if (val.p_u8 == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Convert unit
|
|
* GAIN_LEVEL register(accessed in get_3aparameter()) : 0.3dB
|
|
* GAIN_PRIMODE register(accessed in this function) : 0.1dB
|
|
*/
|
|
|
|
gain = val.p_u8[OFFSET_3APARAMETER_AE_GAIN] * 3;
|
|
|
|
isx019_i2c_write(priv,
|
|
CAT_AWB_USERTYPE, USER4_R, &val.p_u8[OFFSET_3APARAMETER_AWB_R], 2);
|
|
isx019_i2c_write(priv,
|
|
CAT_AWB_USERTYPE, USER4_B, &val.p_u8[OFFSET_3APARAMETER_AWB_B], 2);
|
|
|
|
regval = 4;
|
|
isx019_i2c_write(priv, CAT_CATAWB, AWBUSER_NO, ®val, 1);
|
|
|
|
regval = AWBMODE_MANUAL;
|
|
isx019_i2c_write(priv, CAT_CATAWB, AWBMODE, ®val, 1);
|
|
|
|
isx019_i2c_write(priv,
|
|
CAT_CATAE, SHT_PRIMODE, &val.p_u8[OFFSET_3APARAMETER_AE_SHTTIME], 4);
|
|
isx019_i2c_write(priv, CAT_CATAE, GAIN_PRIMODE, &gain, 2);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static uint16_t get_gain_from_iso(int32_t iso)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NR_ISO; i++)
|
|
{
|
|
if (g_isx019_iso[i] == iso)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Return gain corresponding to specified ISO sensitivity. */
|
|
|
|
return (uint16_t)g_isx019_gain[i];
|
|
}
|
|
|
|
static int set_iso(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint16_t gain;
|
|
|
|
/* ISX019 has not ISO sensitivity register but gain register.
|
|
* So, calculate gain from ISO sensitivity.
|
|
*/
|
|
|
|
gain = get_gain_from_iso(val.value32) * 10;
|
|
isx019_i2c_write(priv, CAT_CATAE, GAIN_PRIMODE, &gain, 2);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_iso_auto(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
uint8_t buf;
|
|
uint16_t gain;
|
|
|
|
if (val.value32 == IMGSENSOR_ISO_SENSITIVITY_AUTO)
|
|
{
|
|
gain = 0;
|
|
}
|
|
else /* IMGSENSOR_ISO_SENSITIVITY_MANUAL */
|
|
{
|
|
isx019_i2c_read(priv, CAT_CATAE, GAIN_PRIMODE, &gain, 2);
|
|
|
|
if (gain == 0)
|
|
{
|
|
/* gain = 0 means auto adjustment mode.
|
|
* In such a case, apply current auto adjustment value
|
|
* as manual setting.
|
|
* Note : auto adjustment value register has the unit 0.3dB.
|
|
* So, convert the unit to 0.1dB.
|
|
*/
|
|
|
|
isx019_i2c_read(priv, CAT_AECOM, GAIN_LEVEL, &buf, 1);
|
|
gain = buf * 3;
|
|
}
|
|
}
|
|
|
|
return isx019_i2c_write(priv, CAT_CATAE, GAIN_PRIMODE, &gain, 2);
|
|
}
|
|
|
|
static uint16_t calc_gamma_regval(double in, double gamma)
|
|
{
|
|
double out;
|
|
|
|
/* 1) Calculate the normalized result.
|
|
* formula : output = input^gamma
|
|
* 2) Perform scaling for ISX019 register.
|
|
* 3) Change the format from the floating-point number type
|
|
* to the fixed-point number type according to the register.
|
|
*/
|
|
|
|
out = pow(in, gamma);
|
|
out *= GAM_OUTPUT_SCALE;
|
|
|
|
return ((uint8_t)out) << 2;
|
|
}
|
|
|
|
static int set_gamma(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
int i;
|
|
uint16_t regval;
|
|
uint16_t offset;
|
|
double gamma;
|
|
|
|
gamma = (double)val.value32 / 1000;
|
|
|
|
/* ISX019 gamma adjustment feature is constructed by
|
|
* registers for low-input and registers for high-input.
|
|
*/
|
|
|
|
offset = GAM_KNOT_C0;
|
|
|
|
for (i = 0; i < NR_GAM_KNOT_LOWINPUT; i++)
|
|
{
|
|
regval = calc_gamma_regval((double)i * GAM_LOWINPUT_INTERVAL, gamma);
|
|
isx019_i2c_write(priv, CAT_PICTGAMMA, offset, ®val, 2);
|
|
offset += 2;
|
|
}
|
|
|
|
offset = GAM_KNOT_C11;
|
|
|
|
for (i = 0; i < NR_GAM_KNOT_HIGHINPUT; i++)
|
|
{
|
|
regval = calc_gamma_regval
|
|
((double)(i + 1) * GAM_HIGHINPUT_INTERVAL, gamma);
|
|
isx019_i2c_write(priv, CAT_PICTGAMMA, offset, ®val, 2);
|
|
offset += 2;
|
|
}
|
|
|
|
/* Special register setting.
|
|
* GAM_KNOT_C9 and GAM_KNOT_C10 need to be set
|
|
* to be continuous.
|
|
* So, this driver set GAM_KNOT_C10 = GAM_KNOT_C8,
|
|
* GAM_KNOT_C9 = GAM_KNOT_C11.
|
|
*/
|
|
|
|
isx019_i2c_read(priv, CAT_PICTGAMMA, GAM_KNOT_C8, ®val, 2);
|
|
isx019_i2c_write(priv, CAT_PICTGAMMA, GAM_KNOT_C10, ®val, 2);
|
|
isx019_i2c_read(priv, CAT_PICTGAMMA, GAM_KNOT_C11, ®val, 2);
|
|
isx019_i2c_write(priv, CAT_PICTGAMMA, GAM_KNOT_C9, ®val, 2);
|
|
|
|
priv->gamma = val.value32;
|
|
return OK;
|
|
}
|
|
|
|
static void search_dqt_data(int32_t quality,
|
|
FAR const uint8_t **y_head,
|
|
FAR const uint8_t **y_calc,
|
|
FAR const uint8_t **c_head,
|
|
FAR const uint8_t **c_calc)
|
|
{
|
|
int i;
|
|
FAR const isx019_fpga_jpg_quality_t *jpg = &g_isx019_jpg_quality[0];
|
|
|
|
*y_head = NULL;
|
|
*y_calc = NULL;
|
|
*c_head = NULL;
|
|
*c_calc = NULL;
|
|
|
|
/* Search approximate DQT data from a table by rounding quality. */
|
|
|
|
quality = ((quality + 5) / 10) * 10;
|
|
if (quality == 0)
|
|
{
|
|
/* Set the minimum value of quality to 10. */
|
|
|
|
quality = 10;
|
|
}
|
|
|
|
for (i = 0; i < NR_JPGSETTING_TBL; i++)
|
|
{
|
|
if (quality == jpg->quality)
|
|
{
|
|
*y_head = jpg->y_head;
|
|
*y_calc = jpg->y_calc;
|
|
*c_head = jpg->c_head;
|
|
*c_calc = jpg->c_calc;
|
|
break;
|
|
}
|
|
|
|
jpg++;
|
|
}
|
|
}
|
|
|
|
int set_dqt(FAR isx019_dev_t *priv, uint8_t component,
|
|
uint8_t target, FAR const uint8_t *buf)
|
|
{
|
|
int i;
|
|
uint8_t addr;
|
|
uint8_t select;
|
|
uint8_t data;
|
|
uint8_t regval;
|
|
|
|
if (target == FPGA_DQT_DATA)
|
|
{
|
|
addr = FPGA_DQT_ADDRESS;
|
|
select = FPGA_DQT_SELECT;
|
|
data = FPGA_DQT_DATA;
|
|
}
|
|
else
|
|
{
|
|
addr = FPGA_DQT_CALC_ADDRESS;
|
|
select = FPGA_DQT_CALC_SELECT;
|
|
data = FPGA_DQT_CALC_DATA;
|
|
}
|
|
|
|
fpga_i2c_write(priv, select, &component, 1);
|
|
for (i = 0; i < JPEG_DQT_ARRAY_SIZE; i++)
|
|
{
|
|
regval = i | FPGA_DQT_WRITE | FPGA_DQT_BUFFER;
|
|
fpga_i2c_write(priv, addr, ®val, 1);
|
|
fpga_i2c_write(priv, data, &buf[i], 1);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_jpg_quality(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
FAR const uint8_t *y_head;
|
|
FAR const uint8_t *y_calc;
|
|
FAR const uint8_t *c_head;
|
|
FAR const uint8_t *c_calc;
|
|
|
|
/* Set JPEG quality by setting DQT information to FPGA. */
|
|
|
|
search_dqt_data(val.value32, &y_head, &y_calc, &c_head, &c_calc);
|
|
if ((y_head == NULL) ||
|
|
(y_calc == NULL) ||
|
|
(c_head == NULL) ||
|
|
(c_calc == NULL))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
nxmutex_lock(&priv->fpga_lock);
|
|
|
|
/* Update DQT data and activate them. */
|
|
|
|
set_dqt(priv, FPGA_DQT_LUMA, FPGA_DQT_DATA, y_head);
|
|
set_dqt(priv, FPGA_DQT_CHROMA, FPGA_DQT_DATA, c_head);
|
|
set_dqt(priv, FPGA_DQT_LUMA, FPGA_DQT_CALC_DATA, y_calc);
|
|
set_dqt(priv, FPGA_DQT_CHROMA, FPGA_DQT_CALC_DATA, c_calc);
|
|
fpga_activate_setting(priv);
|
|
|
|
/* Wait for swap of non-active side and active side. */
|
|
|
|
nxsig_usleep(DELAY_TIME_JPEGDQT_SWAP);
|
|
|
|
/* Update non-active side in preparation for other activation trigger. */
|
|
|
|
set_dqt(priv, FPGA_DQT_LUMA, FPGA_DQT_DATA, y_head);
|
|
set_dqt(priv, FPGA_DQT_CHROMA, FPGA_DQT_DATA, c_head);
|
|
set_dqt(priv, FPGA_DQT_LUMA, FPGA_DQT_CALC_DATA, y_calc);
|
|
set_dqt(priv, FPGA_DQT_CHROMA, FPGA_DQT_CALC_DATA, c_calc);
|
|
|
|
nxmutex_unlock(&priv->fpga_lock);
|
|
|
|
priv->jpg_quality = val.value32;
|
|
return OK;
|
|
}
|
|
|
|
static int initialize_jpg_quality(FAR isx019_dev_t *priv)
|
|
{
|
|
imgsensor_value_t val;
|
|
|
|
val.value32 = CONFIG_VIDEO_ISX019_INITIAL_JPEG_QUALITY;
|
|
return set_jpg_quality(priv, val);
|
|
}
|
|
|
|
static bool validate_clip_setting(FAR uint32_t *clip)
|
|
{
|
|
bool ret = false;
|
|
uint32_t w;
|
|
uint32_t h;
|
|
|
|
DEBUGASSERT(clip);
|
|
|
|
w = clip[IMGSENSOR_CLIP_INDEX_WIDTH];
|
|
h = clip[IMGSENSOR_CLIP_INDEX_HEIGHT];
|
|
|
|
if (((w == 1280) && (h == 720)) ||
|
|
((w == 640) && (h == 360)) ||
|
|
((w == 0) && (h == 0)))
|
|
{
|
|
ret = true;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int set_clip(FAR uint32_t *val, FAR isx019_rect_t *target)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!validate_clip_setting(val))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
target->left = (int32_t)val[IMGSENSOR_CLIP_INDEX_LEFT];
|
|
target->top = (int32_t)val[IMGSENSOR_CLIP_INDEX_TOP];
|
|
target->width = val[IMGSENSOR_CLIP_INDEX_WIDTH];
|
|
target->height = val[IMGSENSOR_CLIP_INDEX_HEIGHT];
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int set_clip_video(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
return set_clip(val.p_u32, &priv->clip_video);
|
|
}
|
|
|
|
static int set_clip_still(FAR isx019_dev_t *priv,
|
|
imgsensor_value_t val)
|
|
{
|
|
return set_clip(val.p_u32, &priv->clip_still);
|
|
}
|
|
|
|
static setvalue_t set_value_func(uint32_t id)
|
|
{
|
|
setvalue_t func = NULL;
|
|
|
|
switch (id)
|
|
{
|
|
case IMGSENSOR_ID_HUE:
|
|
func = set_hue;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_GAMMA:
|
|
func = set_gamma;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_VIDEO:
|
|
func = set_hflip_video;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_VIDEO:
|
|
func = set_vflip_video;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_STILL:
|
|
func = set_hflip_still;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_STILL:
|
|
func = set_vflip_still;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_COLORFX:
|
|
func = set_colorfx;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_AUTO:
|
|
func = set_ae;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_ABSOLUTE:
|
|
func = set_exptime;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_WHITE_BALANCE:
|
|
func = set_awb;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_N_PRESET_WB:
|
|
func = set_wbmode;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY:
|
|
func = set_iso;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY_AUTO:
|
|
func = set_iso_auto;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_METERING:
|
|
func = set_meter;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SPOT_POSITION:
|
|
func = set_spot_position;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_LOCK:
|
|
func = set_3alock;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_PARAMETER:
|
|
func = set_3aparameter;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_JPEG_QUALITY:
|
|
func = set_jpg_quality;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_CLIP_VIDEO:
|
|
func = set_clip_video;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_CLIP_STILL:
|
|
func = set_clip_still;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return func;
|
|
}
|
|
|
|
static int get_hue(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Return stored value without reading register. */
|
|
|
|
val->value32 = priv->hue;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t get_flip(FAR uint8_t *flip, uint8_t direction)
|
|
{
|
|
DEBUGASSERT(flip);
|
|
|
|
return (*flip & direction) ? 1 : 0;
|
|
}
|
|
|
|
static int get_hflip_video(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = get_flip(&priv->flip_video, H_REVERSE);
|
|
return OK;
|
|
}
|
|
|
|
static int get_vflip_video(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = get_flip(&priv->flip_video, V_REVERSE);
|
|
return OK;
|
|
}
|
|
|
|
static int get_hflip_still(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = get_flip(&priv->flip_still, H_REVERSE);
|
|
return OK;
|
|
}
|
|
|
|
static int get_vflip_still(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = get_flip(&priv->flip_still, V_REVERSE);
|
|
return OK;
|
|
}
|
|
|
|
static int get_colorfx(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = priv->colorfx;
|
|
return OK;
|
|
}
|
|
|
|
static int get_ae(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint32_t regval;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv, CAT_CATAE, SHT_PRIMODE, ®val, 4);
|
|
|
|
val->value32 = (regval == 0) ? IMGSENSOR_EXPOSURE_AUTO
|
|
: IMGSENSOR_EXPOSURE_MANUAL;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_exptime(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint32_t regval;
|
|
|
|
isx019_i2c_read(priv, CAT_AESOUT, SHT_TIME, ®val, 4);
|
|
|
|
/* Round up to the nearest 100usec for eliminating errors in reverting to
|
|
* application value because this driver converts application value to
|
|
* value that takes into account the clock ratio and unit difference.
|
|
*/
|
|
|
|
val->value32 = ((regval / priv->clock_ratio) + 99) / 100;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_awb(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = is_awb_enable(priv);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_wbmode(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = priv->wb_mode;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_meter(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint8_t regval;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv, CAT_AUTOCTRL, AEWEIGHTMODE, ®val, 1);
|
|
|
|
switch (regval)
|
|
{
|
|
case AEWEIGHT_AVERAGE:
|
|
val->value32 = IMGSENSOR_EXPOSURE_METERING_AVERAGE;
|
|
break;
|
|
|
|
case AEWEIGHT_CENTER:
|
|
val->value32 = IMGSENSOR_EXPOSURE_METERING_CENTER_WEIGHTED;
|
|
break;
|
|
|
|
case AEWEIGHT_SPOT:
|
|
val->value32 = IMGSENSOR_EXPOSURE_METERING_SPOT;
|
|
break;
|
|
|
|
default: /* AEWEIGHT_MATRIX */
|
|
val->value32 = IMGSENSOR_EXPOSURE_METERING_MATRIX;
|
|
break;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static uint32_t restore_spot_position(uint16_t regval,
|
|
uint16_t basis,
|
|
uint16_t sz,
|
|
uint16_t clip_sz,
|
|
uint16_t offset,
|
|
uint16_t split)
|
|
{
|
|
uint16_t ret;
|
|
uint16_t unit;
|
|
uint16_t border;
|
|
|
|
/* First, convert register value to coordinate value. */
|
|
|
|
unit = basis / split;
|
|
|
|
ret = (regval * unit) + (unit / 2);
|
|
|
|
/* Second, consider the ratio between basis size and frame size. */
|
|
|
|
ret = ret * sz / basis;
|
|
|
|
/* Third, consider offset value of clip setting. */
|
|
|
|
if (ret > offset)
|
|
{
|
|
ret = ret - offset;
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
|
|
/* If the coordinate protrudes from the frame,
|
|
* regard it as the boader of the frame.
|
|
*/
|
|
|
|
border = (clip_sz != 0) ? (clip_sz - 1) : (sz - 1);
|
|
if (ret > border)
|
|
{
|
|
ret = border;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int get_spot_position(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint8_t regval;
|
|
uint8_t regx;
|
|
uint8_t regy;
|
|
uint16_t w;
|
|
uint16_t h;
|
|
uint32_t x;
|
|
uint32_t y;
|
|
uint16_t clip_w;
|
|
uint16_t clip_h;
|
|
uint16_t offset_x;
|
|
uint16_t offset_y;
|
|
int split;
|
|
|
|
isx019_i2c_read(priv, CAT_CATAE, SPOT_FRM_NUM, ®val, 1);
|
|
|
|
regx = regval % ISX019_SPOT_POSITION_SPLIT_NUM_X;
|
|
regy = regval / ISX019_SPOT_POSITION_SPLIT_NUM_X;
|
|
|
|
get_current_framesize(priv, &w, &h);
|
|
get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y);
|
|
split = ISX019_SPOT_POSITION_SPLIT_NUM_X;
|
|
x = restore_spot_position(regx, ISX019_WIDTH, w, clip_w, offset_x, split);
|
|
split = ISX019_SPOT_POSITION_SPLIT_NUM_Y;
|
|
y = restore_spot_position(regy, ISX019_HEIGHT, h, clip_h, offset_y, split);
|
|
|
|
val->value32 = (int32_t)((x << 16) | y);
|
|
return OK;
|
|
}
|
|
|
|
static int get_3alock(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint8_t regval;
|
|
uint8_t awb;
|
|
uint8_t ae;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv, CAT_CATAWB, AWBMODE, ®val, 1);
|
|
awb = (regval == AWBMODE_AUTO) ? 0 : IMGSENSOR_LOCK_WHITE_BALANCE;
|
|
|
|
isx019_i2c_read(priv, CAT_CATAE, AEMODE, ®val, 1);
|
|
ae = (regval == AEMODE_AUTO) ? 0 : IMGSENSOR_LOCK_EXPOSURE;
|
|
|
|
val->value32 = awb | ae;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_3aparameter(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (val->p_u8 == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv,
|
|
CAT_AWBSOUT, CONT_R, &val->p_u8[OFFSET_3APARAMETER_AWB_R], 2);
|
|
isx019_i2c_read(priv,
|
|
CAT_AWBSOUT, CONT_B, &val->p_u8[OFFSET_3APARAMETER_AWB_B], 2);
|
|
isx019_i2c_read(priv,
|
|
CAT_AESOUT, SHT_TIME, &val->p_u8[OFFSET_3APARAMETER_AE_SHTTIME], 4);
|
|
isx019_i2c_read(priv,
|
|
CAT_AECOM, GAIN_LEVEL, &val->p_u8[OFFSET_3APARAMETER_AE_GAIN], 1);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_3astatus(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint8_t regval;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv, CAT_AWBSOUT, AWBSTS, ®val, 1);
|
|
|
|
switch (regval)
|
|
{
|
|
case AWBSTS_STABLE:
|
|
val->value32 = IMGSENSOR_3A_STATUS_STABLE;
|
|
break;
|
|
|
|
case AWBSTS_AEWAIT:
|
|
val->value32 = IMGSENSOR_3A_STATUS_AE_OPERATING;
|
|
break;
|
|
|
|
default:
|
|
val->value32 = IMGSENSOR_3A_STATUS_AE_OPERATING |
|
|
IMGSENSOR_3A_STATUS_AWB_OPERATING;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t get_iso_from_gain(uint8_t gain)
|
|
{
|
|
int i;
|
|
|
|
/* g_isx019_gain and g_isx019_iso has the common index. */
|
|
|
|
for (i = 0; i < NR_ISO; i++)
|
|
{
|
|
if (g_isx019_gain[i] == gain)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= NR_ISO)
|
|
{
|
|
i = NR_ISO - 1;
|
|
}
|
|
|
|
return g_isx019_iso[i];
|
|
}
|
|
|
|
static int get_iso(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint8_t gain = 0;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* The current gain value register has the 0.3dB unit.
|
|
* So, round the gain to integer, and convert to ISO.
|
|
*/
|
|
|
|
isx019_i2c_read(priv, CAT_AECOM, GAIN_LEVEL, &gain, 1);
|
|
gain = ((gain * 3) + 5) / 10;
|
|
|
|
val->value32 = get_iso_from_gain(gain);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_iso_auto(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
uint16_t gain;
|
|
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
isx019_i2c_read(priv, CAT_CATAE, GAIN_PRIMODE, &gain, 2);
|
|
|
|
val->value32 = (gain == 0) ? IMGSENSOR_ISO_SENSITIVITY_AUTO
|
|
: IMGSENSOR_ISO_SENSITIVITY_MANUAL;
|
|
return OK;
|
|
}
|
|
|
|
static int get_gamma(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = priv->gamma;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int get_jpg_quality(FAR isx019_dev_t *priv,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
val->value32 = priv->jpg_quality;
|
|
return OK;
|
|
}
|
|
|
|
static getvalue_t get_value_func(uint32_t id)
|
|
{
|
|
getvalue_t func = NULL;
|
|
|
|
switch (id)
|
|
{
|
|
case IMGSENSOR_ID_HUE:
|
|
func = get_hue;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_GAMMA:
|
|
func = get_gamma;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_VIDEO:
|
|
func = get_hflip_video;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_VIDEO:
|
|
func = get_vflip_video;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_HFLIP_STILL:
|
|
func = get_hflip_still;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_VFLIP_STILL:
|
|
func = get_vflip_still;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_COLORFX:
|
|
func = get_colorfx;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_AUTO:
|
|
func = get_ae;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_ABSOLUTE:
|
|
func = get_exptime;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_WHITE_BALANCE:
|
|
func = get_awb;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_AUTO_N_PRESET_WB:
|
|
func = get_wbmode;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY:
|
|
func = get_iso;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_ISO_SENSITIVITY_AUTO:
|
|
func = get_iso_auto;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_EXPOSURE_METERING:
|
|
func = get_meter;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_SPOT_POSITION:
|
|
func = get_spot_position;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_LOCK:
|
|
func = get_3alock;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_PARAMETER:
|
|
func = get_3aparameter;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_3A_STATUS:
|
|
func = get_3astatus;
|
|
break;
|
|
|
|
case IMGSENSOR_ID_JPEG_QUALITY:
|
|
func = get_jpg_quality;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return func;
|
|
}
|
|
|
|
static int isx019_get_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id, uint32_t size,
|
|
FAR imgsensor_value_t *val)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
int ret = -EINVAL;
|
|
isx019_reginfo_t reg;
|
|
convert_t cvrt;
|
|
getvalue_t get;
|
|
union
|
|
{
|
|
int32_t i32;
|
|
int16_t i16;
|
|
int8_t i8;
|
|
} regval;
|
|
|
|
DEBUGASSERT(val);
|
|
|
|
cvrt = get_reginfo(id, false, ®);
|
|
if (cvrt)
|
|
{
|
|
memset(®val, 0, sizeof(regval));
|
|
ret = isx019_i2c_read(priv,
|
|
reg.category, reg.offset, ®val.i32, reg.size);
|
|
|
|
switch (reg.type)
|
|
{
|
|
case ISX019_REGTYPE_INT8:
|
|
regval.i32 = (int32_t)regval.i8;
|
|
break;
|
|
|
|
case ISX019_REGTYPE_INT16:
|
|
regval.i32 = (int32_t)regval.i16;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
val->value32 = cvrt(regval.i32);
|
|
}
|
|
else
|
|
{
|
|
get = get_value_func(id);
|
|
if (get)
|
|
{
|
|
ret = get(priv, val);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_range(int32_t val,
|
|
FAR imgsensor_capability_range_t *range)
|
|
{
|
|
int ret = OK;
|
|
|
|
if (!VALIDATE_RANGE(val, range->minimum, range->maximum, range->step))
|
|
{
|
|
ret = -ERANGE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_discrete(int32_t val,
|
|
FAR imgsensor_capability_discrete_t *disc)
|
|
{
|
|
int ret = -EINVAL;
|
|
int i;
|
|
|
|
for (i = 0; i < disc->nr_values; i++)
|
|
{
|
|
if (val == disc->values[i])
|
|
{
|
|
ret = OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_elems_u8(FAR uint8_t *val, uint32_t sz,
|
|
FAR imgsensor_capability_elems_t *elems)
|
|
{
|
|
int ret = OK;
|
|
int i;
|
|
|
|
if (sz != elems->nr_elems)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < elems->nr_elems; i++)
|
|
{
|
|
if (!VALIDATE_RANGE
|
|
(val[i], elems->minimum, elems->maximum, elems->step))
|
|
{
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_elems_u16(FAR uint16_t *val, uint32_t sz,
|
|
FAR imgsensor_capability_elems_t *elems)
|
|
{
|
|
int ret = OK;
|
|
int i;
|
|
|
|
if (sz != elems->nr_elems * sizeof(uint16_t))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < elems->nr_elems; i++)
|
|
{
|
|
if (!VALIDATE_RANGE
|
|
(val[i], elems->minimum, elems->maximum, elems->step))
|
|
{
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_elems_u32(FAR uint32_t *val, uint32_t sz,
|
|
FAR imgsensor_capability_elems_t *elems)
|
|
{
|
|
int ret = OK;
|
|
int i;
|
|
|
|
if (sz != elems->nr_elems * sizeof(uint32_t))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < elems->nr_elems; i++)
|
|
{
|
|
if (!VALIDATE_RANGE
|
|
(val[i], elems->minimum, elems->maximum, elems->step))
|
|
{
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int validate_value(FAR isx019_dev_t *priv,
|
|
uint32_t id, uint32_t size,
|
|
imgsensor_value_t val)
|
|
{
|
|
int ret;
|
|
imgsensor_supported_value_t sup;
|
|
|
|
ret = isx019_get_supported_value(&priv->sensor, id, &sup);
|
|
if (ret != OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
switch (sup.type)
|
|
{
|
|
case IMGSENSOR_CTRL_TYPE_INTEGER_MENU:
|
|
ret = validate_discrete(val.value32, &sup.u.discrete);
|
|
break;
|
|
|
|
case IMGSENSOR_CTRL_TYPE_U8:
|
|
ret = validate_elems_u8(val.p_u8, size, &sup.u.elems);
|
|
break;
|
|
|
|
case IMGSENSOR_CTRL_TYPE_U16:
|
|
ret = validate_elems_u16(val.p_u16, size, &sup.u.elems);
|
|
break;
|
|
|
|
case IMGSENSOR_CTRL_TYPE_U32:
|
|
ret = validate_elems_u32(val.p_u32, size, &sup.u.elems);
|
|
break;
|
|
|
|
default:
|
|
ret = validate_range(val.value32, &sup.u.range);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int isx019_set_value(FAR struct imgsensor_s *sensor,
|
|
uint32_t id, uint32_t size,
|
|
imgsensor_value_t val)
|
|
{
|
|
FAR isx019_dev_t *priv = (FAR isx019_dev_t *)sensor;
|
|
int ret = -EINVAL;
|
|
isx019_reginfo_t reg;
|
|
convert_t cvrt;
|
|
setvalue_t set;
|
|
int32_t val32;
|
|
|
|
ret = validate_value(priv, id, size, val);
|
|
if (ret != OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
cvrt = get_reginfo(id, true, ®);
|
|
if (cvrt)
|
|
{
|
|
val32 = cvrt(val.value32);
|
|
ret = isx019_i2c_write(priv,
|
|
reg.category, reg.offset, &val32, reg.size);
|
|
}
|
|
else
|
|
{
|
|
set = set_value_func(id);
|
|
if (set)
|
|
{
|
|
ret = set(priv, val);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int isx019_initialize(void)
|
|
{
|
|
FAR isx019_dev_t *priv = &g_isx019_private;
|
|
imgsensor_register(&priv->sensor);
|
|
return OK;
|
|
}
|
|
|
|
int isx019_uninitialize(void)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
#ifdef CONFIG_VIDEO_ISX019_REGDEBUG
|
|
int isx019_read_register(uint8_t cat,
|
|
uint16_t addr,
|
|
FAR uint8_t *buf,
|
|
uint8_t size)
|
|
{
|
|
FAR isx019_dev_t *priv = &g_isx019_private;
|
|
int ret;
|
|
|
|
if (cat == 0xff)
|
|
{
|
|
ret = fpga_i2c_read(priv, (uint8_t)addr, buf, size);
|
|
}
|
|
else
|
|
{
|
|
ret = isx019_i2c_read(priv, cat, addr, buf, size);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|