Below is my driver code, modified from the IMX307 code.
//cs_camera.c
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include "cs_camera.h"
#define CREATE_TRACE_POINTS
#ifndef DEBUG_PRINTK
#define debug_printk(s , ... )
#define VEYE_TRACE
#else
#define debug_printk printk
#define VEYE_TRACE printk("%s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
#endif
static const struct of_device_id cs_imx307_of_match[] = {
{ .compatible = "nvidia,cs_imx307",},
{ },
};
MODULE_DEVICE_TABLE(of, cs_imx307_of_match);
static const u32 ctrl_cid_list[] = {
/*TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_FRAME_RATE,
TEGRA_CAMERA_CID_FUSE_ID,
TEGRA_CAMERA_CID_HDR_EN,*/
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};
struct cs_imx307 {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
//u8 fuse_id[VEYE327_FUSE_ID_SIZE];
u32 frame_length;
s64 last_wdr_et_val;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
//.use_single_rw = true,
};
static inline void cs_imx307_get_frame_length_regs(cs307_reg *regs,
u32 frame_length)
{
/*regs->addr = VEYE327_FRAME_LENGTH_ADDR_MSB;
regs->val = (frame_length >> 16) & 0x01;
(regs + 1)->addr = VEYE327_FRAME_LENGTH_ADDR_MID;
(regs + 1)->val = (frame_length >> 8) & 0xff;
(regs + 2)->addr = VEYE327_FRAME_LENGTH_ADDR_LSB;
(regs + 2)->val = (frame_length) & 0xff;*/
VEYE_TRACE
return ;
}
static inline void cs_imx307_get_coarse_time_regs_shs1(cs307_reg *regs,
u32 coarse_time)
{
/*regs->addr = VEYE327_COARSE_TIME_SHS1_ADDR_MSB;
regs->val = (coarse_time >> 16) & 0x01;
(regs + 1)->addr = VEYE327_COARSE_TIME_SHS1_ADDR_MID;
(regs + 1)->val = (coarse_time >> 8) & 0xff;
(regs + 2)->addr = VEYE327_COARSE_TIME_SHS1_ADDR_LSB;
(regs + 2)->val = (coarse_time) & 0xff;*/
VEYE_TRACE
return ;
}
static inline void cs_imx307_get_coarse_time_regs_shs2(cs307_reg *regs,
u32 coarse_time)
{
/*regs->addr = VEYE327_COARSE_TIME_SHS2_ADDR_MSB;
regs->val = (coarse_time >> 16) & 0x01;
(regs + 1)->addr = VEYE327_COARSE_TIME_SHS2_ADDR_MID;
(regs + 1)->val = (coarse_time >> 8) & 0xff;
(regs + 2)->addr = VEYE327_COARSE_TIME_SHS2_ADDR_LSB;
(regs + 2)->val = (coarse_time) & 0xff;*/
VEYE_TRACE
return;
}
static inline void cs_imx307_get_gain_reg(cs307_reg *regs,
u8 gain)
{
/*regs->addr = VEYE327_GAIN_ADDR;
regs->val = (gain) & 0xff;*/
VEYE_TRACE
return;
}
//static int test_mode;
//module_param(test_mode, int, 0644);
static inline int cs_imx307_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, ®_val);
*val = reg_val & 0xFF;
VEYE_TRACE
return err;
}
static int cs_imx307_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err;
struct device *dev = s_data->dev;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(dev, "%s: i2c write failed, 0x%x = %x\n",
__func__, addr, val);
VEYE_TRACE
return err;
}
static int cs_imx307_write_table(struct cs_imx307 *priv,
const cs307_reg table[])
{
struct camera_common_data *s_data = priv->s_data;
return regmap_util_write_table_8(s_data->regmap,
table,
NULL, 0,
CS307_TABLE_WAIT_MS,
CS307_TABLE_END);
}
static int cs_imx307_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
/*struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err;
err = veye327_write_reg(s_data,
VEYE327_GROUP_HOLD_ADDR, val);
if (err) {
dev_dbg(dev,
"%s: Group hold control error\n", __func__);
return err;
}*/
VEYE_TRACE
return 0;
}
#if 0
static int cs_imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct cs_imx307 *priv = (struct cs_imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
cs307_reg reg_list[1];
int err;
u8 gain;
/* translate value */
gain = (u8) (val * 160 / (48 * mode->control_properties.gain_factor));
dev_dbg(dev, "%s: gain reg: %d\n", __func__, gain);
cs_imx307_get_gain_reg(reg_list, gain);
err = cs_imx307_write_reg(priv->s_data, reg_list[0].addr,
reg_list[0].val);
if (err)
goto fail;
return 0;
fail:
dev_dbg(dev, "%s: GAIN control error\n", __func__);
return err;
#endif
VEYE_TRACE
return 0;
}
static int cs_imx307_set_coarse_time(struct cs_imx307 *priv, s64 val)
{
struct camera_common_data *s_data = priv->s_data;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode];
struct device *dev = &priv->i2c_client->dev;
cs307_reg reg_list[3];
int err;
u32 coarse_time_shs1;
u32 reg_shs1;
int i = 0;
coarse_time_shs1 = mode->signal_properties.pixel_clock.val *
val / mode->image_properties.line_length /
mode->control_properties.exposure_factor;
if (priv->frame_length == 0)
priv->frame_length = CS307_MIN_FRAME_LENGTH;
reg_shs1 = priv->frame_length - coarse_time_shs1 - 1;
dev_dbg(dev, "%s: coarse1:%d, shs1:%d, FL:%d\n", __func__,
coarse_time_shs1, reg_shs1, priv->frame_length);
cs_imx307_get_coarse_time_regs_shs1(reg_list, reg_shs1);
for (i = 0; i < 3; i++) {
err = cs_imx307_write_reg(priv->s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
return 0;
fail:
dev_dbg(dev, "%s: set coarse time error\n", __func__);
return err;
VEYE_TRACE
return 0;
}
#endif
#if 0
static int cs_imx307_set_coarse_time_hdr(struct cs_imx307 *priv, s64 val)
{
struct device *dev = &priv->i2c_client->dev;
struct camera_common_data *s_data = priv->s_data;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode];
cs307_reg reg_list_shs1[3];
cs307_reg reg_list_shs2[3];
u32 coarse_time_shs1;
u32 coarse_time_shs2;
u32 reg_shs1;
u32 reg_shs2;
int err;
int i = 0;
if (priv->frame_length == 0)
priv->frame_length = CS307_MIN_FRAME_LENGTH;
priv->last_wdr_et_val = val;
/*WDR, update SHS1 as short ET, and SHS2 is 16x of short*/
coarse_time_shs1 = mode->signal_properties.pixel_clock.val *
val / mode->image_properties.line_length /
mode->control_properties.exposure_factor / 16;
if (coarse_time_shs1 < CS307_MIN_SHS1_1080P_HDR)
coarse_time_shs1 = CS307_MIN_SHS1_1080P_HDR;
if (coarse_time_shs1 > CS307_MAX_SHS1_1080P_HDR)
coarse_time_shs1 = CS307_MAX_SHS1_1080P_HDR;
coarse_time_shs2 = (coarse_time_shs1 - CS307_MIN_SHS1_1080P_HDR) * 16 +
CS307_MIN_SHS2_1080P_HDR;
reg_shs1 = priv->frame_length - coarse_time_shs1 - 1;
reg_shs2 = priv->frame_length - coarse_time_shs2 - 1;
cs_imx307_get_coarse_time_regs_shs1(reg_list_shs1, reg_shs1);
cs_imx307_get_coarse_time_regs_shs2(reg_list_shs2, reg_shs2);
dev_dbg(dev, "%s: coarse1:%d, shs1:%d, coarse2:%d, shs2: %d, FL:%d\n",
__func__,
coarse_time_shs1, reg_shs1,
coarse_time_shs2, reg_shs2,
priv->frame_length);
for (i = 0; i < 3; i++) {
err = cs_imx307_write_reg(priv->s_data, reg_list_shs1[i].addr,
reg_list_shs1[i].val);
if (err)
goto fail;
err = cs_imx307_write_reg(priv->s_data, reg_list_shs2[i].addr,
reg_list_shs2[i].val);
if (err)
goto fail;
}
return 0;
fail:
dev_dbg(dev, "%s: set WDR coarse time error\n", __func__);
return err;
VEYE_TRACE
return 0;
}
static int cs_imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
//debug_printk("veye327_set_frame_rate want set rate %d\n",val);
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct cs_imx307 *priv = (struct cs_imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
cs307_reg reg_list[3];
int err;
u32 frame_length;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
struct v4l2_control control;
int hdr_en;
int i = 0;
frame_length = mode->signal_properties.pixel_clock.val *
mode->control_properties.framerate_factor /
mode->image_properties.line_length / val;
priv->frame_length = frame_length;
if (priv->frame_length > CS307_MAX_FRAME_LENGTH)
priv->frame_length = CS307_MAX_FRAME_LENGTH;
dev_dbg(dev, "%s: val: %lld, , frame_length: %d\n", __func__,
val, priv->frame_length);
cs_imx307_get_frame_length_regs(reg_list, priv->frame_length);
for (i = 0; i < 3; i++) {
err = cs_imx307_write_reg(priv->s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
/* check hdr enable ctrl */
/*
control.id = TEGRA_CAMERA_CID_HDR_EN;
err = camera_common_g_ctrl(s_data, &control);
if (err < 0) {
dev_err(dev, "could not find device ctrl.\n");
return err;
}
hdr_en = switch_ctrl_qmenu[control.value];
if ((hdr_en == SWITCH_ON) && (priv->last_wdr_et_val != 0)) {
err = cs_imx307_set_coarse_time_hdr(priv, priv->last_wdr_et_val);
if (err)
dev_dbg(dev,
"%s: error coarse time SHS1 SHS2 override\n", __func__);
}
*/
return 0;
fail:
dev_dbg(dev, "%s: FRAME_LENGTH control error\n", __func__);
return err;
#endif
VEYE_TRACE
return 0;
}
static int cs_imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct cs_imx307 *priv = (struct cs_imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
int err;
struct v4l2_control control;
int hdr_en;
dev_dbg(dev, "%s: val: %lld\n", __func__, val);
/* check hdr enable ctrl */
control.id = TEGRA_CAMERA_CID_HDR_EN;
err = camera_common_g_ctrl(s_data, &control);
if (err < 0) {
dev_err(dev, "could not find device ctrl.\n");
return err;
}
hdr_en = switch_ctrl_qmenu[control.value];
if (hdr_en == SWITCH_ON) {
err = cs_imx307_set_coarse_time_hdr(priv, val);
if (err)
dev_dbg(dev,
"%s: error coarse time SHS1 SHS2 override\n", __func__);
} else {
err = cs_imx307_set_coarse_time(priv, val);
if (err)
dev_dbg(dev,
"%s: error coarse time SHS1 override\n", __func__);
}
return err;
VEYE_TRACE
#endif
return 0;
}
#endif
static int cs_imx307_fill_string_ctrl(struct tegracam_device *tc_dev,
struct v4l2_ctrl *ctrl)
{
#if 0
struct cs_imx307 *priv = tc_dev->priv;
int i;
switch (ctrl->id) {
case TEGRA_CAMERA_CID_FUSE_ID:
for (i = 0; i < CS307_FUSE_ID_SIZE; i++)
sprintf(&ctrl->p_new.p_char[i*2], "%02x",
priv->fuse_id[i]);
break;
default:
return -EINVAL;
}
ctrl->p_cur.p_char = ctrl->p_new.p_char;
#endif
VEYE_TRACE
return 0;
}
static struct tegracam_ctrl_ops cs_imx307_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
//.string_ctrl_size = {0, CS307_FUSE_ID_STR_SIZE},
//delete for jetpack 4.5
//.set_gain = cs_imx307_set_gain,
//.set_exposure = cs_imx307_set_exposure,
//.set_frame_rate = cs_imx307_set_frame_rate,
.set_group_hold = cs_imx307_set_group_hold,
.fill_string_ctrl = cs_imx307_fill_string_ctrl,
};
static int cs_imx307_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
pw->state = SWITCH_ON;
VEYE_TRACE
return 0;
dev_dbg(dev, "%s: power on\n", __func__);
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
dev_err(dev, "%s failed.\n", __func__);
else
pw->state = SWITCH_ON;
return err;
}
/*exit reset mode: XCLR */
if (pw->reset_gpio) {
gpio_set_value(pw->reset_gpio, 0);
usleep_range(30, 50);
gpio_set_value(pw->reset_gpio, 1);
usleep_range(30, 50);
}
pw->state = SWITCH_ON;
VEYE_TRACE
return 0;
}
static int cs_imx307_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
pw->state = SWITCH_OFF;
VEYE_TRACE
return 0;
dev_dbg(dev, "%s: power off\n", __func__);
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (!err)
goto power_off_done;
else
dev_err(dev, "%s failed.\n", __func__);
return err;
}
/* enter reset mode: XCLR */
usleep_range(1, 2);
if (pw->reset_gpio)
gpio_set_value(pw->reset_gpio, 0);
power_off_done:
pw->state = SWITCH_OFF;
VEYE_TRACE
return 0;
}
static int cs_imx307_power_get(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
const char *mclk_name;
struct clk *parent;
int err = 0;
if(pdata->mclk_name)
{
mclk_name = pdata->mclk_name ?
pdata->mclk_name : "extperiph1";
pw->mclk = devm_clk_get(dev, mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s\n", mclk_name);
return PTR_ERR(pw->mclk);
}
parent = devm_clk_get(dev, "pllp_grtba");
if (IS_ERR(parent))
dev_err(dev, "devm_clk_get failed for pllp_grtba");
else
clk_set_parent(pw->mclk, parent);
}
pw->reset_gpio = pdata->reset_gpio;
pw->state = SWITCH_OFF;
VEYE_TRACE
return err;
}
static int cs_imx307_power_put(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
if (unlikely(!pw))
return -EFAULT;
VEYE_TRACE
return 0;
}
static struct camera_common_pdata *cs_imx307_parse_dt(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *np = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
//struct camera_common_pdata *ret = NULL;
int err;
//int gpio;
if (!np)
return NULL;
match = of_match_device(cs_imx307_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return NULL;
}
board_priv_pdata = devm_kzalloc(dev,
sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
return NULL;
/*gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (gpio < 0) {
if (gpio == -EPROBE_DEFER)
ret = ERR_PTR(-EPROBE_DEFER);
dev_err(dev, "reset-gpios not found \n");
goto error;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;*/
//no reset gpio
board_priv_pdata->reset_gpio = 0;
err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
if (err)
dev_dbg(dev, "mclk name not present, "
"assume sensor driven externally\n");
err = of_property_read_string(np, "avdd-reg",
&board_priv_pdata->regulators.avdd);
err |= of_property_read_string(np, "iovdd-reg",
&board_priv_pdata->regulators.iovdd);
err |= of_property_read_string(np, "dvdd-reg",
&board_priv_pdata->regulators.dvdd);
if (err)
dev_dbg(dev, "avdd, iovdd and/or dvdd reglrs. not present, "
"assume sensor powered independently\n");
board_priv_pdata->has_eeprom =
of_property_read_bool(np, "has-eeprom");
VEYE_TRACE
return board_priv_pdata;
/*error:
devm_kfree(dev, board_priv_pdata);
return ret;*/
}
static int cs_imx307_set_mode(struct tegracam_device *tc_dev)
{
struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
struct device_node *np = dev->of_node;
bool limit_analog_gain = false;
const struct of_device_id *match;
int err;
match = of_match_device(cs_imx307_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return -EINVAL;
}
limit_analog_gain = of_property_read_bool(np, "limit_analog_gain");
err = cs_imx307_write_table(priv, mode_table[s_data->mode_prop_idx]);
if (err)
return err;
/*if (limit_analog_gain) {
err = veye327_write_reg(priv->s_data,
CS307_ANALOG_GAIN_LIMIT_ADDR,
CS307_ANALOG_GAIN_LIMIT_VALUE);
if (err)
return err;
}*/
VEYE_TRACE
return 0;
}
static int cs_imx307_start_streaming(struct tegracam_device *tc_dev)
{
struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
int err;
/*if (test_mode) {
err = veye327_write_table(priv,
mode_table[CS307_MODE_TEST_PATTERN]);
if (err)
return err;
}*/
err = cs_imx307_write_table(priv,
mode_table[CS307_MODE_START_STREAM]);
if (err)
return err;
VEYE_TRACE
return 0;
}
static int cs_imx307_stop_streaming(struct tegracam_device *tc_dev)
{
//struct camera_common_data *s_data = tc_dev->s_data;
struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
int err;
err = cs_imx307_write_table(priv, mode_table[CS307_MODE_STOP_STREAM]);
if (err)
return err;
/* SW_RESET will have no ACK */
//veye327_write_reg(s_data, CS307_SW_RESET_ADDR, 0x01);
/*
* Wait for one frame to make sure sensor is set to
* software standby in V-blank
*
* delay = frame length rows * Tline (10 us)
*/
usleep_range(priv->frame_length * 10, priv->frame_length * 10 + 1000);
VEYE_TRACE
return 0;
}
static struct camera_common_sensor_ops cs_imx307_common_ops = {
.numfrmfmts = ARRAY_SIZE(cs_imx307_frmfmt),
.frmfmt_table = cs_imx307_frmfmt,
.power_on = cs_imx307_power_on,
.power_off = cs_imx307_power_off,
.write_reg = cs_imx307_write_reg,
.read_reg = cs_imx307_read_reg,
.parse_dt = cs_imx307_parse_dt,
.power_get = cs_imx307_power_get,
.power_put = cs_imx307_power_put,
.set_mode = cs_imx307_set_mode,
.start_streaming = cs_imx307_start_streaming,
.stop_streaming = cs_imx307_stop_streaming,
};
static int cs_imx307_fuse_id_setup(struct cs_imx307 *priv)
{
//读一下id试试?
# if 0
int err;
int i;
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
u8 bak = 0;
for (i = 0; i < CS307_FUSE_ID_SIZE; i++) {
err |= cs_imx307_read_reg(s_data,
CS307_FUSE_ID_ADDR + i, &bak);
if (!err)
priv->fuse_id[i] = bak;
else {
dev_err(dev, "%s: can not read fuse id\n", __func__);
return -EINVAL;
}
}
#endif
VEYE_TRACE
return 0;
}
static int cs_imx307_board_setup(struct cs_imx307 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
//struct camera_common_pdata *pdata = s_data->pdata;
int err = 0;
u8 reg_val[2];
// u16 cameraid = 0;
dev_dbg(dev, "%s++\n", __func__);
err = camera_common_mclk_enable(s_data);
/*
if (err) {
dev_err(dev,
"Error %d turning on mclk\n", err);
return err;
}
*/
err = cs_imx307_power_on(s_data);
/*
if (err) {
dev_err(dev,
"Error %d during power on sensor\n", err);
return err;
}
*/
err = cs_imx307_fuse_id_setup(priv);
/*
if (err) {
dev_err(dev,
"Error %d reading fuse id data\n", err);
goto err_power_on;
}
*/
/* Probe sensor model id registers */
err = cs_imx307_read_reg(s_data, PRODUCTID_L, ®_val[0]);
/*
if (err) {
dev_err(dev, "%s: error during i2c read probe (%d)\n",
__func__, err);
goto err_reg_probe;
}
*/
err = cs_imx307_read_reg(s_data, PRODUCTID_H, ®_val[1]);
/*
if (err) {
dev_err(dev, "%s: error during i2c read probe (%d)\n",
__func__, err);
goto err_reg_probe;
}
cameraid = ((u16)reg_val[1]<<8) + reg_val[0];
dev_err(dev,"read sensor id %04x \n", cameraid);
if (cameraid == CS_MIPI_IMX307)
{
err = 0;
dev_err(dev, " camera id is cs-mipi-imx307\n");
}
else
{
err = -ENODEV;
dev_err(dev, "%s: invalid sensor model id: %d\n",
__func__, cameraid);
}
VEYE_TRACE
err_reg_probe:
cs_imx307_power_off(s_data);
err_power_on:
if (pdata->mclk_name)
camera_common_mclk_disable(s_data);
*/
//return err;
return 0;
}
static int cs_imx307_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_dbg(&client->dev, "%s:\n", __func__);
VEYE_TRACE
return 0;
}
static const struct v4l2_subdev_internal_ops cs_imx307_subdev_internal_ops = {
.open = cs_imx307_open,
};
static int cs_imx307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct tegracam_device *tc_dev;
struct cs_imx307 *priv;
int err;
dev_info(dev, "probing v4l2 sensor\n");
VEYE_TRACE
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return -EINVAL;
priv = devm_kzalloc(dev,
sizeof(struct cs_imx307), GFP_KERNEL);
if (!priv)
return -ENOMEM;
tc_dev = devm_kzalloc(dev,
sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strncpy(tc_dev->name, "csx307", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &cs_imx307_common_ops;
tc_dev->v4l2sd_internal_ops = &cs_imx307_subdev_internal_ops;
tc_dev->tcctrl_ops = &cs_imx307_ctrl_ops;
err = tegracam_device_register(tc_dev);
if (err) {
dev_err(dev, "tegra camera driver registration failed %d\n",err);
return err;
}
priv->tc_dev = tc_dev;
priv->s_data = tc_dev->s_data;
priv->subdev = &tc_dev->s_data->subdev;
tegracam_set_privdata(tc_dev, (void *)priv);
err = cs_imx307_board_setup(priv);
/*
if (err) {
dev_err(dev, "board setup failed\n");
return err;
}
*/
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}
dev_info(dev, "Detected CS307 sensor\n");
return 0;
}
static int
cs_imx307_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct cs_imx307 *priv = (struct cs_imx307 *)s_data->priv;
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
VEYE_TRACE
return 0;
}
static const struct i2c_device_id cs_imx307_id[] = {
{ "csx307", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs_imx307_id);
static struct i2c_driver cs_imx307_i2c_driver = {
.driver = {
.name = "csx307",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(cs_imx307_of_match),
},
.probe = cs_imx307_probe,
.remove = cs_imx307_remove,
.id_table = cs_imx307_id,
};
module_i2c_driver(cs_imx307_i2c_driver);
MODULE_DESCRIPTION("");
MODULE_AUTHOR("");
MODULE_LICENSE("GPL v2");
/*
* cs307.h - cs307 sensor mode tables
*
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CSIMX307_I2C_TABLES__
#define __CSIMX307_I2C_TABLES__
#include <media/camera_common.h>
#include <linux/miscdevice.h>
#define CS307_TABLE_WAIT_MS 0
#define CS307_TABLE_END 1
#define CS307_MAX_RETRIES 3
#define CS307_WAIT_MS_STOP 1
#define CS307_WAIT_MS_START 30
#define CS307_WAIT_MS_CMD 5
#define CS307_WAIT_MS_STREAM 5
#define CS307_GAIN_TABLE_SIZE 255
/* #define INIT_ET_INSETTING 1 */
#define cs307_reg struct reg_8
typedef enum
{
CS_MIPI_IMX307 = 0x0037,
CS_LVDS_IMX307 = 0x0038,
CS_USB_IMX307 = 0x0039,
CS_MIPI_SC132 = 0x0132,
CS_LVDS_SC132 = 0x0133,
CS_USB_SC132 = 0x0134
}ENProductID;
typedef enum
{
deviceID = 0x00,
HardWare = 0x01,
LoadingDone = 0x02,
Csi2_Enable = 0x03,
Fpga_CAP_L = 0x04,
Fpga_CAP_H = 0x05,
TriggerMode = 0x10,
SlaveMode = 0x11,
TrigDly_H = 0x12,
TrigDly_M = 0x13,
TrigDly_U = 0x14,
TrigDly_L = 0x15,
VerTotalTime_H = 0x16,
VerTotalTime_L = 0x17,
HorTotalTime_H = 0x18,
HorTotalTime_L = 0x19,
ARM_VER_L = 0x0100,
ARM_VER_H = 0x0101,
PRODUCTID_L = 0x0102,
PRODUCTID_H = 0x0103,
SYSTEM_RESET = 0x0104,
PARAM_SAVE = 0x0105,
VIDEOFMT_CAP = 0x0106,
VIDEOFMT_NUM = 0x0107,
FMTCAP_WIDTH_L = 0x0108,
FMTCAP_WIDTH_H = 0x0109,
FMTCAP_HEIGHT_L = 0x010A,
FMTCAP_HEIGHT_H = 0x010B,
FMTCAP_FRAMRAT_L = 0x010C,
FMTCAP_FRAMRAT_H = 0x010D,
FMT_WIDTH_L = 0x0180,
FMT_WIDTH_H = 0x0181,
FMT_HEIGHT_L = 0x0182,
FMT_HEIGHT_H = 0x0183,
FMT_FRAMRAT_L = 0x0184,
FMT_FRAMRAT_H = 0x0185,
IMAGE_DIR = 0x0186,
SYSTEM_REBOOT = 0x0187,
NEW_FMT_FRAMRAT_MODE = 0x0188,
NEW_FMT_FRAMRAT_L = 0x0189,
NEW_FMT_FRAMRAT_H = 0x018A,
EXP_FRM_MODE = 0x020F,
AE_MODE = 0x0210,
EXP_TIME_L = 0x0211,
EXP_TIME_M = 0x0212,
EXP_TIME_H = 0x0213,
EXP_TIME_E = 0x0214,
AGAIN_NOW_DEC = 0x0215,
AGAIN_NOW_INTER = 0x0216,
DGAIN_NOW_DEC = 0x0217,
DGAIN_NOW_INTER = 0x0218,
AE_SPEED = 0x0219,
AE_TARGET = 0x021A,
AE_MAXTIME_L = 0x021B,
AE_MAXTIME_M = 0x021C,
AE_MAXTIME_H = 0x021D,
AE_MAXTIME_E = 0x021E,
AE_MAXGAIN_DEC = 0x021F,
AE_MAXGAIN_INTER = 0x0220,
//ISP cap
ISP_CAP_L = 0x0200,
ISP_CAP_M = 0x0201,
ISP_CAP_H = 0x0202,
ISP_CAP_E = 0x0203,
POWER_HZ = 0x0204,
}ECAMERA_REG;
static cs307_reg cs307_start[] = {
//{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_START},
};
static cs307_reg cs307_stop[] = {
//{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_STOP},
};
//video format capbility
//will check the format if supported later
/* Stream and Control Info Struct */
typedef struct _isp_stream_info {
uint16_t width;
uint16_t height;
uint8_t frame_rate;
} ISP_STREAM_INFO;
struct cs_imx307_private {
u16 module_id;
int num_streams;
ISP_STREAM_INFO *stream_info;
};
static cs307_reg cs307_reg_1920x1080_30fps[] = {
/*
{FMT_WIDTH_L,0x80},
{FMT_WIDTH_H,0x7},
{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_CMD},
{FMT_HEIGHT_L,0x38},
{FMT_HEIGHT_H,0x4},
{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_CMD},
{FMT_FRAMRAT_L,0x1E},
{FMT_FRAMRAT_H,0x00},
{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_STREAM},
{CS307_TABLE_END, 0x00}
*/
};
enum {
CS307_MODE_1920X1080_30FPS,
CS307_MODE_START_STREAM,
CS307_MODE_STOP_STREAM,
//IMX307_MODE_TEST_PATTERN
};
static cs307_reg *mode_table[] = {
[CS307_MODE_1920X1080_30FPS] = cs307_reg_1920x1080_30fps,
[CS307_MODE_START_STREAM] = cs307_start,
[CS307_MODE_STOP_STREAM] = cs307_stop,
//[IMX307_MODE_TEST_PATTERN] = tp_colorbars,
};
static const int camera_fps[] = {
//20,
50,
};
/*
* WARNING: frmfmt ordering need to match mode definition in
* device tree!
*/
static const struct camera_common_frmfmt cs_imx307_frmfmt[] = {
{ { 800, 600}, camera_fps,
ARRAY_SIZE(camera_fps), 0, 0
},
};
#endif /* __CSIMX307_I2C_TABLES__ */
/*
* sensor_common.c - utilities for tegra sensor drivers
*
* Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <media/sensor_common.h>
#include <linux/of_graph.h>
#include <linux/string.h>
static int read_property_u32(
struct device_node *node, const char *name, u32 *value)
{
const char *str;
int err = 0;
err = of_property_read_string(node, name, &str);
if (err)
return -ENODATA;
err = kstrtou32(str, 10, value);
if (err)
return -EFAULT;
return 0;
}
static int read_property_u64(
struct device_node *node, const char *name, u64 *value)
{
const char *str;
int err = 0;
err = of_property_read_string(node, name, &str);
if (err)
return -ENODATA;
err = kstrtou64(str, 10, value);
if (err)
return -EFAULT;
return 0;
}
static int sensor_common_parse_signal_props(
struct device *dev, struct device_node *node,
struct sensor_signal_properties *signal)
{
const char *temp_str;
int err = 0;
u32 value = 0;
u64 val64 = 0;
u64 rate;
int depth;
err = of_property_read_string(node, "phy_mode", &temp_str);
if (err) {
dev_dbg(dev, "%s: use default phy mode DPHY\n", __func__);
signal->phy_mode = CSI_PHY_MODE_DPHY;
} else {
if (strcmp(temp_str, "CPHY") == 0)
signal->phy_mode = CSI_PHY_MODE_CPHY;
else if (strcmp(temp_str, "DPHY") == 0)
signal->phy_mode = CSI_PHY_MODE_DPHY;
else if (strcmp(temp_str, "SLVS") == 0)
signal->phy_mode = SLVS_EC;
else {
dev_err(dev, "%s: Invalid Phy mode\n", __func__);
return -EINVAL;
}
}
/* Do not report error for these properties yet */
err = read_property_u32(node, "readout_orientation", &value);
if (err)
signal->readout_orientation = 0;
else
signal->readout_orientation = value;
err = read_property_u32(node, "mclk_khz", &value);
if (err)
signal->mclk_freq = 0;
else
signal->mclk_freq = value;
err = read_property_u32(node, "num_lanes", &value);
if (err) {
dev_err(dev, "%s:num_lanes property missing\n", __func__);
return err;
}
signal->num_lanes = value;
err = read_property_u64(node, "pix_clk_hz", &val64);
if (err) {
dev_err(dev, "%s:pix_clk_hz property missing\n", __func__);
return err;
}
signal->pixel_clock.val = val64;
err = read_property_u64(node, "serdes_pix_clk_hz", &val64);
if (err)
signal->serdes_pixel_clock.val = 0;
else
signal->serdes_pixel_clock.val = val64;
if (signal->serdes_pixel_clock.val != 0ULL) {
if (signal->serdes_pixel_clock.val < signal->pixel_clock.val) {
dev_err(dev,
"%s: serdes_pix_clk_hz is lower than pix_clk_hz!\n",
__func__);
return -EINVAL;
}
rate = signal->serdes_pixel_clock.val;
} else {
rate = signal->pixel_clock.val;
}
err = read_property_u32(node, "csi_pixel_bit_depth", &depth);
if (err) {
dev_err(dev,
"%s:csi_pixel_bit_depth property missing.\n",
__func__);
return err;
}
/* Convert pixel rate to lane data rate */
rate = rate * depth / signal->num_lanes;
if (signal->phy_mode == CSI_PHY_MODE_DPHY) {
/* MIPI clock rate */
signal->mipi_clock.val = rate / 2;
} else if (signal->phy_mode == CSI_PHY_MODE_CPHY) {
/* Symbol rate */
signal->mipi_clock.val = rate * 7 / 16;
} else {
/* Data rate */
signal->mipi_clock.val = rate;
}
err = read_property_u32(node, "cil_settletime", &value);
if (err)
signal->cil_settletime = 0;
else
signal->cil_settletime = value;
err = read_property_u32(node, "lane_polarity", &value);
/* absence of this value is not an error and default behaviour is
* no polarity swap on any CSI lane */
if (err)
signal->lane_polarity = 0;
else
signal->lane_polarity = value;
/* initialize default if this prop not available */
err = of_property_read_string(node, "discontinuous_clk", &temp_str);
if (!err)
signal->discontinuous_clk =
!strncmp(temp_str, "yes", sizeof("yes"));
else
signal->discontinuous_clk = 1;
/* initialize default if this prop not available */
err = of_property_read_string(node, "dpcm_enable", &temp_str);
if (!err)
signal->dpcm_enable =
!strncmp(temp_str, "true", sizeof("true"));
else
signal->dpcm_enable = 0;
/* initialize default if this prop not available */
err = of_property_read_string(node,
"deskew_initial_enable", &temp_str);
if (!err)
signal->deskew_initial_enable =
!strncmp(temp_str, "true", sizeof("true"));
else
signal->deskew_initial_enable = 0;
err = of_property_read_string(node,
"deskew_periodic_enable", &temp_str);
if (!err)
signal->deskew_periodic_enable =
!strncmp(temp_str, "true", sizeof("true"));
else
signal->deskew_periodic_enable = 0;
err = of_property_read_string(node, "tegra_sinterface", &temp_str);
if (err) {
dev_err(dev,
"%s: tegra_sinterface property missing\n", __func__);
return err;
}
if (strcmp(temp_str, "serial_a") == 0)
signal->tegra_sinterface = 0;
else if (strcmp(temp_str, "serial_b") == 0)
signal->tegra_sinterface = 1;
else if (strcmp(temp_str, "serial_c") == 0)
signal->tegra_sinterface = 2;
else if (strcmp(temp_str, "serial_d") == 0)
signal->tegra_sinterface = 3;
else if (strcmp(temp_str, "serial_e") == 0)
signal->tegra_sinterface = 4;
else if (strcmp(temp_str, "serial_f") == 0)
signal->tegra_sinterface = 5;
else if (strcmp(temp_str, "serial_g") == 0)
signal->tegra_sinterface = 6;
else if (strcmp(temp_str, "serial_h") == 0)
signal->tegra_sinterface = 7;
else if (strcmp(temp_str, "host") == 0)
signal->tegra_sinterface = 0; /* for vivid driver */
else {
dev_err(dev,
"%s: tegra_sinterface property out of range\n",
__func__);
return -EINVAL;
}
return 0;
}
static int extract_pixel_format(
const char *pixel_t, u32 *format)
{
size_t size = strnlen(pixel_t, OF_MAX_STR_LEN);
if (strncmp(pixel_t, "bayer_bggr10", size) == 0)
*format = V4L2_PIX_FMT_SBGGR10;
else if (strncmp(pixel_t, "bayer_rggb10", size) == 0)
*format = V4L2_PIX_FMT_SRGGB10;
else if (strncmp(pixel_t, "bayer_grbg10", size) == 0)
*format = V4L2_PIX_FMT_SGRBG10;
else if (strncmp(pixel_t, "bayer_gbrg10", size) == 0)
*format = V4L2_PIX_FMT_SGBRG10;
else if (strncmp(pixel_t, "bayer_bggr12", size) == 0)
*format = V4L2_PIX_FMT_SBGGR12;
else if (strncmp(pixel_t, "bayer_rggb12", size) == 0)
*format = V4L2_PIX_FMT_SRGGB12;
else if (strncmp(pixel_t, "bayer_gbrg12", size) == 0)
*format = V4L2_PIX_FMT_SGBRG12;
else if (strncmp(pixel_t, "bayer_grbg12", size) == 0)
*format = V4L2_PIX_FMT_SGRBG12;
else if (strncmp(pixel_t, "rgb_rgb88824", size) == 0)
*format = V4L2_PIX_FMT_RGB24;
else if (strncmp(pixel_t, "bayer_wdr_pwl_rggb12", size) == 0)
*format = V4L2_PIX_FMT_SRGGB12;
else if (strncmp(pixel_t, "bayer_wdr_pwl_gbrg12", size) == 0)
*format = V4L2_PIX_FMT_SGBRG12;
else if (strncmp(pixel_t, "bayer_wdr_pwl_grbg12", size) == 0)
*format = V4L2_PIX_FMT_SGRBG12;
else if (strncmp(pixel_t, "bayer_wdr_dol_rggb10", size) == 0)
*format = V4L2_PIX_FMT_SRGGB10;
else if (strncmp(pixel_t, "bayer_xbggr10p", size) == 0)
*format = V4L2_PIX_FMT_XBGGR10P;
else if (strncmp(pixel_t, "bayer_xrggb10p", size) == 0)
*format = V4L2_PIX_FMT_XRGGB10P;
else if (strncmp(pixel_t, "yuv_yuyv16", size) == 0)
*format = V4L2_PIX_FMT_YUYV;
else if (strncmp(pixel_t, "yuv_yvyu16", size) == 0)
*format = V4L2_PIX_FMT_YVYU;
else if (strncmp(pixel_t, "yuv_uyvy16", size) == 0)
*format = V4L2_PIX_FMT_UYVY;
else if (strncmp(pixel_t, "yuv_uyvy8", size) == 0)
*format = V4L2_PIX_FMT_UYVY;
else if (strncmp(pixel_t, "yuv_vyuy16", size) == 0)
*format = V4L2_PIX_FMT_VYUY;
else {
pr_err("%s: Need to extend format%s\n", __func__, pixel_t);
return -EINVAL;
}
return 0;
}
static int sensor_common_parse_image_props(
struct device *dev, struct device_node *node,
struct sensor_image_properties *image)
{
const char *temp_str;
int err = 0, ret = 0;
const char *phase_str, *mode_str;
int depth;
char pix_format[24];
u32 value = 0;
err = read_property_u32(node, "active_w",
&image->width);
if (err) {
dev_err(dev, "%s:active_w property missing\n", __func__);
goto fail;
}
err = read_property_u32(node, "active_h",
&image->height);
if (err) {
dev_err(dev, "%s:active_h property missing\n", __func__);
goto fail;
}
err = read_property_u32(node, "line_length",
&image->line_length);
if (err) {
dev_err(dev, "%s:Line length property missing\n", __func__);
goto fail;
}
/* embedded_metadata_height is optional */
err = read_property_u32(node, "embedded_metadata_height", &value);
if (err)
image->embedded_metadata_height = 0;
else
image->embedded_metadata_height = value;
err = of_property_read_string(node, "pixel_t", &temp_str);
if (err) {
/* pixel_t missing is only an error if alternate not provided */
/* check for alternative format string */
err = of_property_read_string(node, "pixel_phase", &phase_str);
if (err) {
dev_err(dev,
"%s:pixel_phase property missing.\n",
__func__);
dev_err(dev,
"%s:Either pixel_t or alternate must be present.\n",
__func__);
goto fail;
}
err = of_property_read_string(node, "mode_type", &mode_str);
if (err) {
dev_err(dev,
"%s:mode_type property missing.\n",
__func__);
dev_err(dev,
"%s:Either pixel_t or alternate must be present.\n",
__func__);
goto fail;
}
err = read_property_u32(node, "csi_pixel_bit_depth", &depth);
if (err) {
dev_err(dev,
"%s:csi_pixel_bit_depth property missing.\n",
__func__);
dev_err(dev,
"%s:Either pixel_t or alternate must be present.\n",
__func__);
goto fail;
}
ret = sprintf(pix_format, "%s_%s%d", mode_str, phase_str, depth);
if (ret < 0)
return -EINVAL;
temp_str = pix_format;
}
err = extract_pixel_format(temp_str, &image->pixel_format);
if (err) {
dev_err(dev, "Unsupported pixel format\n");
goto fail;
}
fail:
return err;
}
static int sensor_common_parse_dv_timings(
struct device *dev, struct device_node *node,
struct sensor_dv_timings *timings)
{
int err = 0;
u32 value = 0;
/* Do not report error for these properties yet */
err = read_property_u32(node, "horz_front_porch", &value);
if (err)
timings->hfrontporch = 0;
else
timings->hfrontporch = value;
err = read_property_u32(node, "horz_sync", &value);
if (err)
timings->hsync = 0;
else
timings->hsync = value;
err = read_property_u32(node, "horz_back_porch", &value);
if (err)
timings->hbackporch = 0;
else
timings->hbackporch = value;
err = read_property_u32(node, "vert_front_porch", &value);
if (err)
timings->vfrontporch = 0;
else
timings->vfrontporch = value;
err = read_property_u32(node, "vert_sync", &value);
if (err)
timings->vsync = 0;
else
timings->vsync = value;
err = read_property_u32(node, "vert_back_porch", &value);
if (err)
timings->vbackporch = 0;
else
timings->vbackporch = value;
return 0;
}
static int sensor_common_parse_control_props(
struct device *dev, struct device_node *node,
struct sensor_control_properties *control)
{
int err = 0;
u32 value = 0;
u64 val64 = 0;
err = read_property_u32(node, "gain_factor", &value);
if (err) {
dev_dbg(dev, "%s:%s:property missing\n",
__func__, "gain_factor");
control->gain_factor = 1;
return 0;
} else
control->gain_factor = value;
err = read_property_u32(node, "framerate_factor", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "framerate_factor");
control->framerate_factor = 1;
} else
control->framerate_factor = value;
err = read_property_u32(node, "exposure_factor", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "exposure_factor");
control->exposure_factor = 1;
} else
control->exposure_factor = value;
/* ignore err for this prop */
err = read_property_u32(node, "inherent_gain", &value);
if (err)
control->inherent_gain = 0;
else
control->inherent_gain = value;
err = read_property_u32(node, "min_gain_val", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "min_gain_val");
control->min_gain_val = 0;
} else
control->min_gain_val = value;
err = read_property_u32(node, "max_gain_val", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "max_gain_val");
control->max_gain_val = 0;
} else
control->max_gain_val = value;
err = read_property_u32(node, "step_gain_val", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "step_gain_val");
control->step_gain_val = 0;
} else
control->step_gain_val = value;
/* ignore err for this prop */
err = read_property_u32(node, "min_hdr_ratio", &value);
if (err)
control->min_hdr_ratio = 1;
else
control->min_hdr_ratio = value;
err = read_property_u32(node, "max_hdr_ratio", &value);
if (err)
control->max_hdr_ratio = 1;
else
control->max_hdr_ratio = value;
err = read_property_u32(node, "min_framerate", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "min_framerate");
control->min_framerate = 0;
} else
control->min_framerate = value;
err = read_property_u32(node, "max_framerate", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "max_framerate");
control->max_framerate = 0;
} else
control->max_framerate = value;
err = read_property_u32(node, "step_framerate", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "step_framerate");
control->step_framerate = 0;
} else
control->step_framerate = value;
err = read_property_u64(node, "min_exp_time", &val64);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "min_exp_time");
control->min_exp_time.val = 0;
}
control->min_exp_time.val = val64;
err = read_property_u64(node, "max_exp_time", &val64);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "max_exp_time");
control->max_exp_time.val = 0;
} else
control->max_exp_time.val = val64;
err = read_property_u64(node, "step_exp_time", &val64);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "step_exp_time");
control->step_exp_time.val = 0;
} else
control->step_exp_time.val = val64;
err = read_property_u32(node, "default_gain", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "default_gain");
control->default_gain = 0;
} else
control->default_gain = value;
err = read_property_u32(node, "default_framerate", &value);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "default_framerate");
control->default_framerate = 0;
} else
control->default_framerate = value;
err = read_property_u64(node, "default_exp_time", &val64);
if (err) {
dev_err(dev, "%s:%s:property missing\n",
__func__, "default_exp_time");
control->default_exp_time.val = 0;
} else
control->default_exp_time.val = val64;
err = read_property_u32(node, "is_interlaced", &value);
if (err)
control->is_interlaced = 0;
else
control->is_interlaced = value;
err = read_property_u32(node, "interlaced_type", &value);
if (err)
control->interlace_type = 0;
else
control->interlace_type = value;
return 0;
}
int sensor_common_parse_num_modes(const struct device *dev)
{
struct device_node *np;
struct device_node *node = NULL;
char temp_str[OF_MAX_STR_LEN];
int num_modes = 0;
int i, ret;
if (!dev || !dev->of_node)
return 0;
np = dev->of_node;
for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) {
ret = snprintf(temp_str, sizeof(temp_str), "%s%d",
OF_SENSORMODE_PREFIX, i);
if (ret < 0)
return 0;
node = of_get_child_by_name(np, temp_str);
of_node_put(node);
if (node == NULL)
break;
num_modes++;
}
return num_modes;
}
EXPORT_SYMBOL(sensor_common_parse_num_modes);
static int sensor_common_init_i2c_device_config(
struct device *dev, struct device_node *np,
struct sensor_cfg *cfg)
{
struct i2c_sensor_cfg *i2c_sensor = &cfg->u.i2c_sensor;
struct device_node *node = NULL;
struct device_node *parent = NULL;
int err = 0;
u32 value = 0;
bool is_mux_valid = 0;
cfg->type = CAMERA_DEVICE_I2C_SENSOR;
err = of_property_read_u32(np, "reg", &value);
if (err) {
dev_err(dev, "sensor address unavailable\n");
return err;
}
/* Reading more devices has to be supported */
i2c_sensor->num_devs = 1;
i2c_sensor->sd[0].addr = value;
parent = of_get_parent(np);
/* verify the parent is mux or i2c bus */
is_mux_valid =
of_property_read_bool(parent, "i2c-mux,deselect-on-exit");
i2c_sensor->mux.is_mux_valid = is_mux_valid;
if (is_mux_valid) {
/* at mux port read the mux channel */
err = of_property_read_u32(parent, "reg", &value);
if (err) {
dev_err(dev, "mux channel unavailable\n");
return err;
}
i2c_sensor->mux.mux_channel = value;
/* move to mux node */
node = of_get_parent(parent);
of_node_put(parent);
err = of_property_read_u32(node, "reg", &value);
if (err) {
dev_err(dev, "mux address unavailable\n");
return err;
}
i2c_sensor->mux.mux_addr = value;
/* move to i2c bus node */
parent = of_get_parent(node);
of_node_put(node);
} else {
/* move to next parent to check
* if it is a gpio based i2c mux
*/
node = of_get_parent(parent);
if (of_device_is_compatible(node, "i2c-mux-gpio")) {
of_node_put(parent);
/* move to i2c bus node */
parent = of_parse_phandle(node, "i2c-parent", 0);
}
}
/* read parent which is i2c bus */
err = of_property_read_u32_index(parent, "reg", 1, &value);
if (err) {
dev_err(dev, "i2c bus regbase unavailable\n");
return err;
}
i2c_sensor->bus.reg_base = value;
err = of_property_read_u32(parent, "clock-frequency", &value);
if (err) {
dev_err(dev, "bus clock frequency unavailable\n");
return err;
}
i2c_sensor->bus.clk_rate = value;
of_node_put(parent);
/*
* Read any additional flags to configure I2C for any
* special properties of the device like-high-speed mode,
* 10bit addressing etc.,
*/
return 0;
}
static int sensor_common_init_spi_device_config(
struct device *dev, struct device_node *np,
struct sensor_cfg *cfg)
{
struct spi_sensor_cfg *spi_sensor = &cfg->u.spi_sensor;
struct device_node *parent = NULL;
int err = 0;
u32 value = 0;
cfg->type = CAMERA_DEVICE_SPI_SENSOR;
err = of_property_read_u32(np, "reg", &value);
if (err) {
dev_err(dev, "sensor address unavailable\n");
return err;
}
/* Reading more devices has to be supported */
spi_sensor->num_devs = 1;
spi_sensor->sd[0].addr = value;
parent = of_get_parent(np);
/* TODO: Add logic for spi mux if available */
/* read parent which is spi bus */
err = of_property_read_u32_index(parent, "reg", 1, &value);
if (err) {
dev_err(dev, "spi bus regbase unavailable\n");
return err;
}
spi_sensor->bus.reg_base = value;
err = of_property_read_u32(parent, "spi-max-frequency", &value);
if (err) {
dev_err(dev, "bus clock frequency unavailable\n");
return err;
}
spi_sensor->bus.clk_rate = value;
of_node_put(parent);
/* Read any additional flags to configure SPI */
return 0;
}
static int sensor_common_init_device_config(
struct device *dev, struct device_node *np,
struct sensor_cfg *cfg)
{
struct device_node *parent = NULL;
char *tmp;
int err = 0;
if (!np)
return -EINVAL;
parent = of_get_parent(np);
if (!parent)
return -EINVAL;
tmp = strnstr(parent->name, "i2c", 4);
if (tmp != NULL) {
err = sensor_common_init_i2c_device_config(dev, np, cfg);
if (err)
goto exit;
}
tmp = strnstr(parent->name, "spi", 4);
if (tmp != NULL) {
err = sensor_common_init_spi_device_config(dev, np, cfg);
if (err)
goto exit;
}
exit:
of_node_put(parent);
return err;
}
int sensor_common_init_sensor_properties(
struct device *dev, struct device_node *np,
struct sensor_properties *sensor)
{
char temp_str[OF_MAX_STR_LEN];
struct device_node *node = NULL;
int num_modes = 0;
int err, i;
if (sensor == NULL)
return -EINVAL;
err = sensor_common_init_device_config(dev, np, &sensor->cfg);
if (err)
return err;
/* get number of modes */
for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) {
err = snprintf(temp_str, sizeof(temp_str), "%s%d",
OF_SENSORMODE_PREFIX, i);
if (err < 0)
return -EINVAL;
node = of_get_child_by_name(np, temp_str);
of_node_put(node);
if (node == NULL)
break;
num_modes++;
}
sensor->num_modes = num_modes;
sensor->sensor_modes = devm_kzalloc(dev,
num_modes * sizeof(struct sensor_mode_properties),
GFP_KERNEL);
if (!sensor->sensor_modes) {
dev_err(dev, "Failed to allocate memory for sensor modes\n");
err = -ENOMEM;
goto alloc_fail;
}
for (i = 0; i < num_modes; i++) {
err = snprintf(temp_str, sizeof(temp_str), "%s%d",
OF_SENSORMODE_PREFIX, i);
if (err < 0)
return -EINVAL;
node = of_get_child_by_name(np, temp_str);
if (node == NULL) {
dev_err(dev, "Failed to find %s\n", temp_str);
err = -ENODATA;
goto fail;
};
dev_dbg(dev, "parsing for %s props\n", temp_str);
err = sensor_common_parse_signal_props(dev, node,
&sensor->sensor_modes[i].signal_properties);
if (err) {
dev_err(dev, "Failed to read %s signal props\n",
temp_str);
goto fail;
}
err = sensor_common_parse_image_props(dev, node,
&sensor->sensor_modes[i].image_properties);
if (err) {
dev_err(dev, "Failed to read %s image props\n",
temp_str);
goto fail;
}
err = sensor_common_parse_dv_timings(dev, node,
&sensor->sensor_modes[i].dv_timings);
if (err) {
dev_err(dev, "Failed to read %s DV timings\n",
temp_str);
goto fail;
}
err = sensor_common_parse_control_props(dev, node,
&sensor->sensor_modes[i].control_properties);
if (err) {
dev_err(dev, "Failed to read %s control props\n",
temp_str);
goto fail;
}
of_node_put(node);
}
return 0;
fail:
devm_kfree(dev, sensor->sensor_modes);
alloc_fail:
of_node_put(node);
return err;
}
EXPORT_SYMBOL(sensor_common_init_sensor_properties);