mirror of
https://github.com/thead-yocto-mirror/vi-kernel
synced 2026-08-10 08:11:26 +02:00
495 lines
13 KiB
C
Executable File
495 lines
13 KiB
C
Executable File
/****************************************************************************
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* The GPL License (GPL)
|
|
*
|
|
* Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program;
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Note: This software is released under dual MIT and GPL licenses. A
|
|
* recipient may use this file under the terms of either the MIT license or
|
|
* GPL License. If you wish to use only one license not the other, you can
|
|
* indicate your decision by deleting one of the above license notices in your
|
|
* version of this file.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/uaccess.h>
|
|
#include "vvsensor.h"
|
|
#include "sensor_common.h"
|
|
#include "imx290_reg_cfg.h"
|
|
|
|
#define SENSOR_CLK 74250000
|
|
|
|
static struct vvcam_mode_info pimx290_mode_info[] = {
|
|
{
|
|
.index = 0,
|
|
.width = 1920,
|
|
.height = 1080,
|
|
.fps = 30,
|
|
.hdr_mode = SENSOR_MODE_LINEAR,
|
|
.bit_width = 10,
|
|
.bayer_pattern = BAYER_GBRG,
|
|
},
|
|
{
|
|
.index = 1,
|
|
.width = 1920,
|
|
.height = 1080,
|
|
.fps = 30,
|
|
.hdr_mode = SENSOR_MODE_HDR_STITCH,
|
|
.stitching_mode = SENSOR_STITCHING_3DOL,
|
|
.bit_width = 10,
|
|
.bayer_pattern = BAYER_GBRG,
|
|
},
|
|
{
|
|
.index = 2,
|
|
.width = 1280,
|
|
.height = 720,
|
|
.fps = 60,
|
|
.hdr_mode = SENSOR_MODE_LINEAR,
|
|
.bit_width = 10,
|
|
.bayer_pattern = BAYER_GBRG,
|
|
}
|
|
};
|
|
|
|
|
|
static int32_t sensor_query(void *ctx, struct vvcam_mode_info_array *pmode_info_arry)
|
|
{
|
|
if (!pmode_info_arry)
|
|
{
|
|
return -1;
|
|
}
|
|
pmode_info_arry->count = ARRAY_SIZE(pimx290_mode_info);
|
|
|
|
memcpy(pmode_info_arry->modes,pimx290_mode_info,sizeof(pimx290_mode_info));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t sensor_write_reg(void *ctx, uint32_t reg, uint32_t val)
|
|
{
|
|
int32_t ret = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
ret = vvcam_sensor_i2c_write(dev, reg, val);
|
|
|
|
return ret;
|
|
}
|
|
static int32_t sensor_read_reg(void *ctx, uint32_t reg, uint32_t *pval)
|
|
{
|
|
int32_t ret = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
ret = vvcam_sensor_i2c_read(dev, reg, pval);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_write_reg_arry(void *ctx, struct vvcam_sccb_array *parray)
|
|
{
|
|
int32_t ret = 0;
|
|
int32_t index = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
for (index = 0; index < parray->count; index++)
|
|
{
|
|
ret = vvcam_sensor_i2c_write(dev, parray->sccb_data[index].addr, parray->sccb_data[index].data);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_get_chip_id(void *ctx, uint32_t *chip_id)
|
|
{
|
|
int32_t ret = 0;
|
|
int32_t chip_id_high = 0;
|
|
int32_t chip_id_low = 0;
|
|
ret = sensor_read_reg(ctx, 0x300a, &chip_id_high);
|
|
ret |= sensor_read_reg(ctx, 0x300b, &chip_id_low);
|
|
|
|
*chip_id = ((chip_id_high & 0xff)<<8) | (chip_id_low & 0xff);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_init(void *ctx, struct vvcam_mode_info *pmode)
|
|
{
|
|
int32_t ret = 0;
|
|
int32_t i = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
struct vvcam_mode_info *psensor_mode = NULL;
|
|
|
|
for (i=0; i < sizeof(pimx290_mode_info)/ sizeof(struct vvcam_mode_info); i++)
|
|
{
|
|
if (pimx290_mode_info[i].index == pmode->index)
|
|
{
|
|
psensor_mode = &(pimx290_mode_info[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (psensor_mode == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&(dev->sensor_mode),psensor_mode,sizeof(struct vvcam_mode_info));
|
|
|
|
switch(dev->sensor_mode.index)
|
|
{
|
|
case 0:
|
|
ret = sensor_write_reg_arry(ctx,&imx290_mipi4lane_1080p_30fps_linear_arry);
|
|
|
|
dev->ae_info.DefaultFrameLengthLines = 0x466;
|
|
dev->ae_info.CurFrameLengthLines = dev->ae_info.DefaultFrameLengthLines;
|
|
dev->ae_info.one_line_exp_time_ns = 69607;//ns
|
|
|
|
dev->ae_info.max_integration_time = dev->ae_info.CurFrameLengthLines -4;
|
|
dev->ae_info.min_integration_time = 1;
|
|
dev->ae_info.integration_accuracy = 1;
|
|
|
|
dev->ae_info.gain_accuracy = 1024;
|
|
dev->ae_info.max_gain = 22 * dev->ae_info.gain_accuracy;
|
|
dev->ae_info.min_gain = 3 * dev->ae_info.gain_accuracy;
|
|
|
|
dev->ae_info.cur_fps = dev->sensor_mode.fps;
|
|
break;
|
|
case 1:
|
|
ret = sensor_write_reg_arry(ctx,&imx290_mipi4lane_1080p_30fps_linear_arry);
|
|
dev->ae_info.DefaultFrameLengthLines = 0x466;
|
|
dev->ae_info.CurFrameLengthLines = dev->ae_info.DefaultFrameLengthLines;
|
|
dev->ae_info.one_line_exp_time_ns = 69607;//ns
|
|
|
|
dev->ae_info.max_integration_time = dev->ae_info.CurFrameLengthLines -4;
|
|
dev->ae_info.min_integration_time = 1;
|
|
dev->ae_info.integration_accuracy = 1;
|
|
|
|
dev->ae_info.gain_accuracy = 1024;
|
|
dev->ae_info.max_gain = 22 * dev->ae_info.gain_accuracy;
|
|
dev->ae_info.min_gain = 3 * dev->ae_info.gain_accuracy;
|
|
|
|
dev->ae_info.cur_fps = dev->sensor_mode.fps;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_set_stream(void *ctx, uint32_t status)
|
|
{
|
|
int32_t ret = 0;
|
|
if (status)
|
|
{
|
|
ret = sensor_write_reg(ctx, 0x3002, 0x00);
|
|
ret = sensor_write_reg(ctx, 0x3000, 0x00);
|
|
}else
|
|
{
|
|
ret = sensor_write_reg(ctx, 0x3000, 0x01);
|
|
ret = sensor_write_reg(ctx, 0x3002, 0x01);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_set_exp(void *ctx, uint32_t exp_line)
|
|
{
|
|
int32_t ret = 0;
|
|
ret = sensor_write_reg(ctx, 0x3467, 0x00);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x04);
|
|
ret |= sensor_write_reg(ctx, 0x30b6, (exp_line>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x30b7, exp_line & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x14);
|
|
ret |= sensor_write_reg(ctx, 0x3467, 0x01);
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_set_vs_exp(void *ctx, uint32_t exp_line)
|
|
{
|
|
int32_t ret = 0;
|
|
ret = sensor_write_reg(ctx, 0x3467, 0x00);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x04);
|
|
ret |= sensor_write_reg(ctx, 0x30b8, (exp_line>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x30b9, exp_line & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x14);
|
|
ret |= sensor_write_reg(ctx, 0x3467, 0x01);
|
|
return ret;
|
|
|
|
}
|
|
|
|
static int32_t sensor_calc_gain(uint32_t total_gain, uint32_t *pagain, uint32_t *pdgain, uint32_t *phcg)
|
|
{
|
|
uint32_t sensor_gain;
|
|
|
|
sensor_gain = total_gain;
|
|
|
|
if(sensor_gain <= 3072)// 3 * gain_accuracy
|
|
{
|
|
sensor_gain = 3072;
|
|
}
|
|
else if((sensor_gain >= 22528) && (sensor_gain < 23552)) //gain >22*gain_accuracy && gain < 23*gain_accuracy
|
|
{
|
|
sensor_gain = 22528;
|
|
}
|
|
|
|
if (sensor_gain < 4480) //gain < 4.375 * gain_accuracy
|
|
{
|
|
*pagain = 1;
|
|
*phcg = 1;
|
|
}
|
|
else if(sensor_gain < 8960)//gain < 8.75 * gain_accuracy
|
|
{
|
|
*pagain = 2;
|
|
*phcg = 1;
|
|
}
|
|
else if(sensor_gain < 22528)//gain < 22 * gain_accuracy
|
|
{
|
|
*pagain = 3;
|
|
*phcg = 1;
|
|
}
|
|
else if(sensor_gain < 44990)//gain < 44 * gain_accuracy
|
|
{
|
|
*pagain = 0;
|
|
*phcg = 11;
|
|
}
|
|
else if (sensor_gain < 89320)//gain < 88 * gain_accuracy
|
|
{
|
|
*pagain = 1;
|
|
*phcg = 11;
|
|
}
|
|
else if (sensor_gain < 179498)//gain < 176 * gain_accuracy
|
|
{
|
|
*pagain = 2;
|
|
*phcg = 11;
|
|
}else
|
|
{
|
|
*pagain = 3;
|
|
*phcg = 11;
|
|
}
|
|
*pdgain = ((sensor_gain << 8) >> (*pagain)) / (1024 * (*phcg));
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int32_t sensor_set_gain(void *ctx, uint32_t gain)
|
|
{
|
|
int32_t ret = 0;
|
|
uint32_t again = 0;
|
|
uint32_t dgain = 0;
|
|
uint32_t hcg = 1;
|
|
|
|
uint32_t hcg_gain;
|
|
uint32_t lcg_gain;
|
|
|
|
uint32_t hcg_again = 0;
|
|
uint32_t hcg_dgain = 0;
|
|
uint32_t lcg_again = 0;
|
|
uint32_t lcg_dgain = 0;
|
|
|
|
uint32_t reg_val = 0;
|
|
uint32_t hdr_radio;
|
|
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
hdr_radio= dev->ae_info.hdr_radio;
|
|
|
|
switch(dev->sensor_mode.index)
|
|
{
|
|
case 0:
|
|
sensor_calc_gain(gain, &again, &dgain, &hcg);
|
|
|
|
ret = sensor_read_reg(ctx, 0x30bb, ®_val);
|
|
if (hcg == 1)
|
|
{
|
|
reg_val &= ~(1<<6); //LCG
|
|
}else
|
|
{
|
|
reg_val |= (1<<6); //HCG
|
|
}
|
|
reg_val &= ~0x03;
|
|
reg_val |= again;
|
|
ret = sensor_write_reg(ctx, 0x3467, 0x00);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x04);
|
|
ret |= sensor_write_reg(ctx, 0x315a, (dgain>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x315b, dgain & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x30bb, reg_val);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x14);
|
|
ret |= sensor_write_reg(ctx, 0x3467, 0x01);
|
|
break;
|
|
case 1:
|
|
hcg_gain = gain * hdr_radio / 11;
|
|
sensor_calc_gain(gain, &hcg_again, &hcg_dgain, &hcg);
|
|
lcg_gain = gain;
|
|
sensor_calc_gain(gain, &lcg_again, &lcg_dgain, &hcg);
|
|
|
|
ret = sensor_read_reg(ctx, 0x30bb, ®_val);
|
|
reg_val &= ~0x0f;
|
|
reg_val |= (lcg_again<<2)&0x03;
|
|
reg_val |= hcg_again & 0x03;
|
|
|
|
ret = sensor_write_reg(ctx, 0x3467, 0x00);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x04);
|
|
|
|
ret |= sensor_write_reg(ctx, 0x315a, (hcg_dgain>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x315b, hcg_dgain & 0xff);
|
|
|
|
ret |= sensor_write_reg(ctx, 0x315c, (lcg_dgain>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x315d, lcg_dgain & 0xff);
|
|
|
|
ret |= sensor_write_reg(ctx, 0x30bb, reg_val);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x14);
|
|
ret |= sensor_write_reg(ctx, 0x3467, 0x01);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_set_vs_gain(void *ctx, uint32_t gain)
|
|
{
|
|
int32_t ret = 0;
|
|
uint32_t again = 0;
|
|
uint32_t dgain = 0;
|
|
uint32_t sensor_gain;
|
|
uint32_t hcg = 1;
|
|
uint32_t reg_val = 0;
|
|
|
|
sensor_gain = gain;
|
|
|
|
sensor_calc_gain(gain, &again, &dgain, &hcg);
|
|
|
|
ret = sensor_read_reg(ctx, 0x30bb, ®_val);
|
|
|
|
reg_val &= ~0x30;
|
|
reg_val |= (again & 0x03) << 4;
|
|
ret = sensor_write_reg(ctx, 0x3467, 0x00);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x04);
|
|
ret |= sensor_write_reg(ctx, 0x315e, (dgain>>8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x315f, dgain & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x30bb, reg_val);
|
|
ret |= sensor_write_reg(ctx, 0x3464, 0x14);
|
|
ret |= sensor_write_reg(ctx, 0x3467, 0x01);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static int32_t sensor_set_fps(void *ctx, uint32_t fps)
|
|
{
|
|
int32_t ret = 0;
|
|
uint32_t FrameLengthLines = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
if (fps > dev->sensor_mode.fps)
|
|
{
|
|
return -1;
|
|
}
|
|
FrameLengthLines = dev->sensor_mode.fps * dev->ae_info.DefaultFrameLengthLines / fps;
|
|
|
|
if (FrameLengthLines != dev->ae_info.CurFrameLengthLines)
|
|
{
|
|
ret = sensor_write_reg(ctx, 0x30b2, (FrameLengthLines >> 8) & 0xff);
|
|
ret |= sensor_write_reg(ctx, 0x30b3, FrameLengthLines & 0xff);
|
|
if (ret != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
dev->ae_info.CurFrameLengthLines = FrameLengthLines;
|
|
dev->ae_info.max_integration_time = FrameLengthLines-3;
|
|
dev->ae_info.cur_fps = fps;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int32_t sensor_set_resolution(void *ctx, uint32_t width, uint32_t height)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int32_t sensor_set_hdr_mode(void *ctx, uint32_t hdr_mode)
|
|
{
|
|
int32_t ret = 0;
|
|
struct vvcam_sensor_dev *dev = ctx;
|
|
|
|
if (hdr_mode == dev->sensor_mode.hdr_mode)
|
|
{
|
|
return 0;
|
|
}
|
|
if (hdr_mode == SENSOR_MODE_LINEAR)
|
|
{
|
|
// ret = sensor_write_reg(ctx, 0x3190, 0x08);
|
|
dev->sensor_mode.hdr_mode = SENSOR_MODE_LINEAR;
|
|
}
|
|
else if(hdr_mode == SENSOR_MODE_HDR_STITCH)
|
|
{
|
|
// ret = sensor_write_reg(ctx, 0x3190, 0x05);
|
|
dev->sensor_mode.hdr_mode = SENSOR_MODE_HDR_STITCH;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
struct vvcam_sensor_function_s imx290_function =
|
|
{
|
|
.sensor_name = "imx290",
|
|
.reserve_id = 0x290,
|
|
.sensor_clk = SENSOR_CLK,
|
|
.mipi_info.mipi_lane = 4,
|
|
|
|
.sensor_get_chip_id = sensor_get_chip_id,
|
|
.sensor_init = sensor_init,
|
|
.sensor_set_stream = sensor_set_stream,
|
|
.sensor_set_exp = sensor_set_exp,
|
|
.sensor_set_vs_exp = sensor_set_vs_exp,
|
|
.sensor_set_gain = sensor_set_gain,
|
|
.sensor_set_vs_gain = sensor_set_vs_gain,
|
|
.sensor_set_fps = sensor_set_fps,
|
|
.sensor_set_resolution = sensor_set_resolution,
|
|
.sensor_set_hdr_mode = sensor_set_hdr_mode,
|
|
.sensor_query = sensor_query,
|
|
};
|