mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
media: i2c: ov16880: add read otp support
Signed-off-by: Wang Panzhenzhuan <randy.wang@rock-chips.com> Change-Id: Ib62e11283c4a1a59609d3cbe2c2fab1ae7ad8b2a
This commit is contained in:
committed by
Tao Huang
parent
5075a133a0
commit
2a6adfdae4
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2024 Rockchip Electronics Co., Ltd.
|
||||
*
|
||||
* V0.0X01.0X00 first version.
|
||||
* V0.0X01.0X01 support rk otp spec.
|
||||
*
|
||||
*/
|
||||
//#define DEBUG
|
||||
@@ -26,8 +27,9 @@
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include "otp_eeprom.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01)
|
||||
#define OV16880_MAJOR_I2C_ADDR 0x36
|
||||
#define OV16880_MINOR_I2C_ADDR 0x10
|
||||
|
||||
@@ -112,6 +114,7 @@
|
||||
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
|
||||
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
|
||||
#define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode"
|
||||
#define RK_OTP
|
||||
|
||||
#define OV16880_NAME "ov16880"
|
||||
#define OV16880_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR10_1X10
|
||||
@@ -177,6 +180,9 @@ struct ov16880 {
|
||||
const char *module_facing;
|
||||
const char *module_name;
|
||||
const char *len_name;
|
||||
#ifdef RK_OTP
|
||||
struct otp_info *otp;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define to_ov16880(sd) container_of(sd, struct ov16880, subdev)
|
||||
@@ -1926,14 +1932,103 @@ static int ov16880_g_frame_interval(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RK_OTP
|
||||
static void ov16880_get_otp(struct otp_info *otp,
|
||||
struct rkmodule_inf *inf)
|
||||
{
|
||||
u32 i, j;
|
||||
u32 w, h;
|
||||
|
||||
/* awb */
|
||||
if (otp->awb_data.flag) {
|
||||
inf->awb.flag = 1;
|
||||
inf->awb.r_value = otp->awb_data.r_ratio;
|
||||
inf->awb.b_value = otp->awb_data.b_ratio;
|
||||
inf->awb.gr_value = otp->awb_data.g_ratio;
|
||||
inf->awb.gb_value = 0x0;
|
||||
|
||||
inf->awb.golden_r_value = otp->awb_data.r_golden;
|
||||
inf->awb.golden_b_value = otp->awb_data.b_golden;
|
||||
inf->awb.golden_gr_value = otp->awb_data.g_golden;
|
||||
inf->awb.golden_gb_value = 0x0;
|
||||
}
|
||||
|
||||
/* lsc */
|
||||
if (otp->lsc_data.flag) {
|
||||
inf->lsc.flag = 1;
|
||||
inf->lsc.width = otp->basic_data.size.width;
|
||||
inf->lsc.height = otp->basic_data.size.height;
|
||||
inf->lsc.table_size = otp->lsc_data.table_size;
|
||||
|
||||
for (i = 0; i < 289; i++) {
|
||||
inf->lsc.lsc_r[i] = (otp->lsc_data.data[i * 2] << 8) |
|
||||
otp->lsc_data.data[i * 2 + 1];
|
||||
inf->lsc.lsc_gr[i] = (otp->lsc_data.data[i * 2 + 578] << 8) |
|
||||
otp->lsc_data.data[i * 2 + 579];
|
||||
inf->lsc.lsc_gb[i] = (otp->lsc_data.data[i * 2 + 1156] << 8) |
|
||||
otp->lsc_data.data[i * 2 + 1157];
|
||||
inf->lsc.lsc_b[i] = (otp->lsc_data.data[i * 2 + 1734] << 8) |
|
||||
otp->lsc_data.data[i * 2 + 1735];
|
||||
}
|
||||
}
|
||||
|
||||
/* pdaf */
|
||||
if (otp->pdaf_data.flag) {
|
||||
inf->pdaf.flag = 1;
|
||||
inf->pdaf.gainmap_width = otp->pdaf_data.gainmap_width;
|
||||
inf->pdaf.gainmap_height = otp->pdaf_data.gainmap_height;
|
||||
inf->pdaf.dcc_mode = otp->pdaf_data.dcc_mode;
|
||||
inf->pdaf.dcc_dir = otp->pdaf_data.dcc_dir;
|
||||
inf->pdaf.dccmap_width = otp->pdaf_data.dccmap_width;
|
||||
inf->pdaf.dccmap_height = otp->pdaf_data.dccmap_height;
|
||||
w = otp->pdaf_data.gainmap_width;
|
||||
h = otp->pdaf_data.gainmap_height;
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
inf->pdaf.gainmap[i * w + j] =
|
||||
(otp->pdaf_data.gainmap[(i * w + j) * 2] << 8) |
|
||||
otp->pdaf_data.gainmap[(i * w + j) * 2 + 1];
|
||||
}
|
||||
}
|
||||
w = otp->pdaf_data.dccmap_width;
|
||||
h = otp->pdaf_data.dccmap_height;
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
inf->pdaf.dccmap[i * w + j] =
|
||||
(otp->pdaf_data.dccmap[(i * w + j) * 2] << 8) |
|
||||
otp->pdaf_data.dccmap[(i * w + j) * 2 + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* af */
|
||||
if (otp->af_data.flag) {
|
||||
inf->af.flag = 1;
|
||||
inf->af.dir_cnt = 1;
|
||||
inf->af.af_otp[0].vcm_start = otp->af_data.af_inf;
|
||||
inf->af.af_otp[0].vcm_end = otp->af_data.af_macro;
|
||||
inf->af.af_otp[0].vcm_dir = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ov16880_get_module_inf(struct ov16880 *ov16880,
|
||||
struct rkmodule_inf *inf)
|
||||
{
|
||||
#ifdef RK_OTP
|
||||
struct otp_info *otp = ov16880->otp;
|
||||
#endif
|
||||
|
||||
memset(inf, 0, sizeof(*inf));
|
||||
strscpy(inf->base.sensor, OV16880_NAME, sizeof(inf->base.sensor));
|
||||
strscpy(inf->base.module, ov16880->module_name,
|
||||
sizeof(inf->base.module));
|
||||
strscpy(inf->base.lens, ov16880->len_name, sizeof(inf->base.lens));
|
||||
#ifdef RK_OTP
|
||||
if (otp)
|
||||
ov16880_get_otp(otp, inf);
|
||||
#endif
|
||||
}
|
||||
|
||||
static long ov16880_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
@@ -2672,6 +2767,12 @@ static int ov16880_probe(struct i2c_client *client,
|
||||
char facing[2];
|
||||
int ret;
|
||||
u32 i, hdr_mode = 0;
|
||||
#ifdef RK_OTP
|
||||
struct device_node *eeprom_ctrl_node;
|
||||
struct i2c_client *eeprom_ctrl_client;
|
||||
struct v4l2_subdev *eeprom_ctrl;
|
||||
struct otp_info *otp_ptr;
|
||||
#endif
|
||||
|
||||
dev_info(dev, "driver version: %02x.%02x.%02x",
|
||||
DRIVER_VERSION >> 16,
|
||||
@@ -2765,6 +2866,36 @@ static int ov16880_probe(struct i2c_client *client,
|
||||
ret = ov16880_check_sensor_id(ov16880, client);
|
||||
if (ret)
|
||||
goto err_power_off;
|
||||
#ifdef RK_OTP
|
||||
eeprom_ctrl_node = of_parse_phandle(node, "eeprom-ctrl", 0);
|
||||
if (eeprom_ctrl_node) {
|
||||
eeprom_ctrl_client =
|
||||
of_find_i2c_device_by_node(eeprom_ctrl_node);
|
||||
of_node_put(eeprom_ctrl_node);
|
||||
if (IS_ERR_OR_NULL(eeprom_ctrl_client)) {
|
||||
dev_err(dev, "can not get node\n");
|
||||
goto continue_probe;
|
||||
}
|
||||
eeprom_ctrl = i2c_get_clientdata(eeprom_ctrl_client);
|
||||
if (IS_ERR_OR_NULL(eeprom_ctrl)) {
|
||||
dev_err(dev, "can not get eeprom i2c client\n");
|
||||
} else {
|
||||
otp_ptr = devm_kzalloc(dev, sizeof(*otp_ptr), GFP_KERNEL);
|
||||
if (!otp_ptr)
|
||||
return -ENOMEM;
|
||||
ret = v4l2_subdev_call(eeprom_ctrl,
|
||||
core, ioctl, 0, otp_ptr);
|
||||
if (!ret) {
|
||||
ov16880->otp = otp_ptr;
|
||||
} else {
|
||||
ov16880->otp = NULL;
|
||||
devm_kfree(dev, otp_ptr);
|
||||
dev_warn(dev, "can not get otp info, skip!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
continue_probe:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
sd->internal_ops = &ov16880_internal_ops;
|
||||
|
||||
Reference in New Issue
Block a user