/* * imx490.c - imx490 sensor driver * * Copyright (c) 2018-2020, 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 . */ #include #include #include #include #include #include #include #include // #include // #include // #include #include "imx490_mode_tbls.h" #include #include #define IMX490_DEFAULT_MODE IMX490_MODE_2880x1860_CROP_30FPS #define IMX490_MAX_COARSE_DIFF (9) #define IMX490_MIN_GAIN (10) // #define IMX490_MIN_GAIN (0) #define IMX490_MAX_GAIN (30) // #define IMX490_MAX_GAIN_REG ((IMX490_MAX_GAIN - IMX490_MIN_GAIN) * 10 / 3) #define IMX490_MAX_GAIN_REG (100) #define IMX490_DEFAULT_GAIN IMX490_MIN_GAIN #define IMX490_GAIN_SHIFT 8 #define IMX490_DEFAULT_DATAFMT MEDIA_BUS_FMT_YUYV8_1X16 #define IMX490_MIN_FRAME_LENGTH (1125) #define IMX490_MAX_FRAME_LENGTH (0x57E4) #define IMX490_MIN_EXPOSURE_COARSE (1) #define IMX490_MAX_EXPOSURE_COARSE \ (IMX490_MAX_FRAME_LENGTH-IMX490_MAX_COARSE_DIFF) #define IMX490_DEFAULT_FRAME_LENGTH (2000) #define IMX490_FRAME_LENGTH_ADDR_MSB 0x200A #define IMX490_FRAME_LENGTH_ADDR_MID 0x2009 #define IMX490_FRAME_LENGTH_ADDR_LSB 0x2008 #define IMX490_COARSE_TIME_SHS1_ADDR_MSB 0x36C2 #define IMX490_COARSE_TIME_SHS1_ADDR_MID 0x36C1 #define IMX490_COARSE_TIME_SHS1_ADDR_LSB 0x36C0 #define IMX490_COARSE_TIME_SHS2_ADDR_MSB 0x0012 #define IMX490_COARSE_TIME_SHS2_ADDR_MID 0x0011 #define IMX490_COARSE_TIME_SHS2_ADDR_LSB 0x0010 #define IMX490_GROUP_HOLD_ADDR 0x0008 #define IMX490_ANALOG_GAIN_SP1H_ADDR 0x0018 #define IMX490_ANALOG_GAIN_SP1L_ADDR 0x001A #define IMX490_DEFAULT_EXPOSURE_COARSE \ (IMX490_DEFAULT_FRAME_LENGTH-IMX490_MAX_COARSE_DIFF) // const struct of_device_id imx490_of_match[] = { // { .compatible = "nvidia,imx490",}, // { }, // }; // MODULE_DEVICE_TABLE(of, imx490_of_match); #define IMX490_MIN_SHS1_1080P_HDR (5) #define IMX490_MIN_SHS2_1080P_HDR (82) #define IMX490_MAX_SHS2_1080P_HDR (IMX490_MAX_FRAME_LENGTH - 5) #define IMX490_MAX_SHS1_1080P_HDR (IMX490_MAX_SHS2_1080P_HDR / 16) #define IMX490_GAIN_ADDR 0x3014 /* GAIN ADDR */ /* default image output width */ #define IMX490_DEFAULT_WIDTH 2880 /* default image output height */ #define IMX490_DEFAULT_HEIGHT 1860 /* default output clk frequency for camera */ #define IMX490_DEFAULT_CLK_FREQ 24000000 /* max9296_write_reg_dser */ extern int max9296_write_reg_Dser(struct i2c_client *i2c_client, struct regmap *regmap, unsigned short slaveAddr, u16 addr, u8 val); /* max9295_write_reg_ser */ extern int max9295_write_reg_Ser(struct i2c_client *i2c_client, struct regmap *regmap, unsigned short slaveAddr, u16 addr, u8 val); // static const u32 ctrl_cid_list[] = { // TEGRA_CAMERA_CID_GAIN, // TEGRA_CAMERA_CID_EXPOSURE, // TEGRA_CAMERA_CID_EXPOSURE_SHORT, // TEGRA_CAMERA_CID_FRAME_RATE, // TEGRA_CAMERA_CID_HDR_EN, // }; struct imx490 { struct camera_common_power_rail power; int numctrls; struct v4l2_ctrl_handler ctrl_handler; struct i2c_client *i2c_client; const struct i2c_device_id *id; struct v4l2_subdev *subdev; struct device *ser_dev; struct device *dser_dev; struct media_pad pad; // struct gmsl_link_ctx g_ctx; u32 frame_length; s32 group_hold_prev; bool group_hold_en; s64 last_wdr_et_val; struct regmap *regmap; struct camera_common_data *s_data; // struct tegracam_device *tc_dev; struct camera_common_pdata *pdata; struct v4l2_ctrl *ctrls[]; }; static const struct regmap_config sensor_regmap_config = { .reg_bits = 16, .val_bits = 8, .cache_type = REGCACHE_RBTREE, }; static int imx490_s_ctrl(struct v4l2_ctrl *ctrl); static const struct v4l2_ctrl_ops imx490_ctrl_ops = { .s_ctrl = imx490_s_ctrl, }; static struct v4l2_ctrl_config ctrl_config_list[] = { /* Do not change the name field for the controls! */ { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_GAIN, .name = "Gain", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_SLIDER, .min = IMX490_MIN_GAIN, .max = IMX490_MAX_GAIN, .def = IMX490_DEFAULT_GAIN, .step = 1, }, { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_FRAME_LENGTH, .name = "Frame Length", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_SLIDER, .min = IMX490_MIN_FRAME_LENGTH, .max = IMX490_MAX_FRAME_LENGTH, .def = IMX490_DEFAULT_FRAME_LENGTH, .step = 1, }, { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_COARSE_TIME, .name = "Coarse Time", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_SLIDER, .min = IMX490_MIN_EXPOSURE_COARSE, .max = IMX490_MAX_EXPOSURE_COARSE, .def = IMX490_DEFAULT_EXPOSURE_COARSE, .step = 1, }, { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_COARSE_TIME_SHORT, .name = "Coarse Time Short", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_SLIDER, .min = IMX490_MIN_EXPOSURE_COARSE, .max = IMX490_MAX_EXPOSURE_COARSE, .def = IMX490_DEFAULT_EXPOSURE_COARSE, .step = 1, }, { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_GROUP_HOLD, .name = "Group Hold", .type = V4L2_CTRL_TYPE_INTEGER_MENU, .min = 0, .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, .menu_skip_mask = 0, .def = 0, .qmenu_int = switch_ctrl_qmenu, }, { .ops = &imx490_ctrl_ops, .id = TEGRA_CAMERA_CID_HDR_EN, .name = "HDR enable", .type = V4L2_CTRL_TYPE_INTEGER_MENU, .min = 0, .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, .menu_skip_mask = 0, .def = 0, .qmenu_int = switch_ctrl_qmenu, }, }; static inline void imx490_get_frame_length_regs(imx490_reg *regs, u32 frame_length) { regs->addr = IMX490_FRAME_LENGTH_ADDR_MSB; regs->val = (frame_length >> 16) & 0x01; (regs + 1)->addr = IMX490_FRAME_LENGTH_ADDR_MID; (regs + 1)->val = (frame_length >> 8) & 0xff; (regs + 2)->addr = IMX490_FRAME_LENGTH_ADDR_LSB; (regs + 2)->val = (frame_length) & 0xff; } static inline void imx490_get_coarse_time_regs_shs1(imx490_reg *regs, u32 coarse_time) { regs->addr = IMX490_COARSE_TIME_SHS1_ADDR_MSB; regs->val = (coarse_time >> 16) & 0x0f; (regs + 1)->addr = IMX490_COARSE_TIME_SHS1_ADDR_MID; (regs + 1)->val = (coarse_time >> 8) & 0xff; (regs + 2)->addr = IMX490_COARSE_TIME_SHS1_ADDR_LSB; (regs + 2)->val = (coarse_time) & 0xff; } static inline void imx490_get_coarse_time_regs_shs2(imx490_reg *regs, u32 coarse_time) { regs->addr = IMX490_COARSE_TIME_SHS2_ADDR_MSB; regs->val = (coarse_time >> 16) & 0x0f; (regs + 1)->addr = IMX490_COARSE_TIME_SHS2_ADDR_MID; (regs + 1)->val = (coarse_time >> 8) & 0xff; (regs + 2)->addr = IMX490_COARSE_TIME_SHS2_ADDR_LSB; (regs + 2)->val = (coarse_time) & 0xff; } // static inline void imx490_get_gain_reg(imx490_reg *regs, // u16 gain) // { // regs->addr = IMX490_ANALOG_GAIN_SP1H_ADDR; // regs->val = (gain) & 0xff; // (regs + 1)->addr = IMX490_ANALOG_GAIN_SP1H_ADDR + 1; // (regs + 1)->val = (gain >> 8) & 0xff; // (regs + 2)->addr = IMX490_ANALOG_GAIN_SP1L_ADDR; // (regs + 2)->val = (gain) & 0xff; // (regs + 3)->addr = IMX490_ANALOG_GAIN_SP1L_ADDR + 1; // (regs + 3)->val = (gain >> 8) & 0xff; // } static int test_mode; module_param(test_mode, int, 0644); static inline int imx490_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val) { struct imx490 *priv = (struct imx490 *)s_data->priv; int err = 0; u32 reg_val = 0; // err = regmap_read(s_data->regmap, addr, ®_val); err = regmap_read(priv->regmap, addr, ®_val); *val = reg_val & 0xFF; return err; } static int imx490_read_reg_(struct i2c_client *i2c_client, struct regmap *regmap, int slaveAddr, u16 addr, unsigned int* val) { // struct i2c_client *i2c_client = priv->i2c_client; int err; int bak = i2c_client->addr; i2c_client->addr = slaveAddr / 2; err = regmap_read(regmap, addr, val); if (err){ printk("shaobingadd0---imx490_read_reg_ error\n"); // dev_err(&i2c_client->dev, "%s:i2c read failed, 0x%x = %x\n", // __func__, addr, *val); } msleep(5); i2c_client->addr = bak; return err; } static int imx490_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); struct imx490 *priv = (struct imx490 *)s_data->priv; err = regmap_write(priv->regmap, addr, val); if (err) // dev_err(dev, "%s:i2c write failed, 0x%x = %x\n", pr_err("%s:i2c write failed, 0x%x = %x\n", __func__, addr, val); return err; } static int imx490_write_table(struct imx490 *priv, // const imx490_reg table[]) const struct index_reg_8 table[]) { int ret = 0; int i = 0; unsigned int regVal; // printk("shaobingadd0---imx490_write_table table[i].source=0x%x\n", table[i].source); while(table[i].source != 0x00) { if(table[i].source == 0xda) { // printk("shaobingadd1---imx490_write_table\n"); ret = imx490_write_reg(priv->s_data, table[i].addr, table[i].val); if(0x0010 == table[i].addr) msleep(100); } else if(table[i].source == 0x90) { // printk("shaobingadd2---imx490_write_table\n"); ret = max9296_write_reg_Dser(priv->i2c_client, priv->regmap, table[i].source, table[i].addr, (u8)table[i].val); if(0x0010 == table[i].addr) msleep(100); } // else if(table[i].source == 0xc0) { // // printk("shaobingadd3---imx490_write_table\n"); // ret = max9295_write_reg_Ser(priv->i2c_client, priv->regmap, table[i].source, table[i].addr, (u8)table[i].val); // // if(0x0010 == table[i].addr) // // msleep(100); // } else if((table[i].source == 0x80) || (table[i].source == 0x88) || (table[i].source == 0x82)) { // printk("shaobingadd4---imx490_write_table\n"); ret = max9295_write_reg_Ser(priv->i2c_client, priv->regmap, table[i].source, table[i].addr, (u8)table[i].val); // if (0x0010 == table[i].addr) msleep(100); if((0x02D3 == table[i].addr) || (0x2be == table[i].addr)) { msleep(400); } } // if(0x0010 == table[i].addr) // if(0x2d3 == table[i].addr) // // msleep(100); // msleep(100); // if(0x2be == table[i].addr) // msleep(100); // printk("shaobingadd2---imx490_write_table devAddr=0x%x, regAddr=0x%x, regData=0x%x \n", table[i].source, table[i].addr, (u8)table[i].val ); ret = imx490_read_reg_(priv->i2c_client, priv->regmap, table[i].source, table[i].addr, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x%x, regAddr=0x%x, regData=0x%x \n", table[i].source, table[i].addr, regVal ); regVal = 0; i++; } return 0; // struct camera_common_data *s_data = priv->s_data; // return regmap_util_write_table_8(s_data->regmap, // table, // NULL, 0, // IMX490_TABLE_WAIT_MS, // IMX490_TABLE_END); } // static struct mutex serdes_lock__; // static int imx490_gmsl_serdes_setup(struct imx490 *priv) // { // int err = 0; // int des_err = 0; // struct device *dev; // if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) // return -EINVAL; // dev = &priv->i2c_client->dev; // mutex_lock(&serdes_lock__); // /* For now no separate power on required for serializer device */ // max9296_power_on(priv->dser_dev); // /* setup serdes addressing and control pipeline */ // err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); // if (err) { // dev_err(dev, "gmsl deserializer link config failed\n"); // goto error; // } // err = max9295_setup_control(priv->ser_dev); // /* proceed even if ser setup failed, to setup deser correctly */ // if (err) // dev_err(dev, "gmsl serializer setup failed\n"); // des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev); // if (des_err) { // dev_err(dev, "gmsl deserializer setup failed\n"); // /* overwrite err only if deser setup also failed */ // err = des_err; // } // error: // mutex_unlock(&serdes_lock__); // return err; // } // static void imx490_gmsl_serdes_reset(struct imx490 *priv) // { // mutex_lock(&serdes_lock__); // /* reset serdes addressing and control pipeline */ // max9295_reset_control(priv->ser_dev); // max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev); // max9296_power_off(priv->dser_dev); // mutex_unlock(&serdes_lock__); // } static int imx490_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; // printk("shaobingadd0---imx490_power_on\n"); 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; } printk("shaobingadd0---imx490_power_on pw->reset_gpio=%d\n", pw->reset_gpio); if (pw->reset_gpio) gpio_direction_output(pw->reset_gpio, 0); usleep_range(100, 200); if (pw->reset_gpio){ gpio_direction_output(pw->reset_gpio, 1); printk("shaobingadd1---imx490_power_on\n"); } usleep_range(300, 310); pw->state = SWITCH_ON; return 0; } static int imx490_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; 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 if (err) { dev_err(dev, "%s failed.\n", __func__); return err; } goto power_off_done; } usleep_range(1, 2); if (pw->reset_gpio){ gpio_direction_output(pw->reset_gpio, 0); printk("shaobingadd2---imx490_power_off\n"); } usleep_range(1, 2); power_off_done: pw->state = SWITCH_OFF; return 0; } // static int imx490_power_get(struct tegracam_device *tc_dev) static int imx490_power_get(struct imx490 *priv) { // 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 = priv->pdata; struct camera_common_power_rail *pw = &priv->power; // struct device *dev = &priv->i2c_client->dev; const char *mclk_name; const char *parentclk_name; struct clk *parent; int err = 0; // mclk_name = pdata->mclk_name ? // pdata->mclk_name : "cam_mclk1"; // pw->mclk = devm_clk_get(dev, mclk_name); mclk_name = priv->pdata->mclk_name ? priv->pdata->mclk_name : "cam_mclk1"; pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); if (IS_ERR(pw->mclk)) { // dev_err(dev, "unable to get clock %s\n", mclk_name); dev_err(&priv->i2c_client->dev, "unable to get clock %s\n", mclk_name); return PTR_ERR(pw->mclk); } // parentclk_name = pdata->parentclk_name; parentclk_name = priv->pdata->parentclk_name; if (parentclk_name) { // parent = devm_clk_get(dev, parentclk_name); parent = devm_clk_get(&priv->i2c_client->dev, parentclk_name); if (IS_ERR(parent)) { // dev_err(dev, "unable to get parent clcok %s", dev_err(&priv->i2c_client->dev, "unable to get parent clcok %s", parentclk_name); } else clk_set_parent(pw->mclk, parent); } if (!err) { pw->reset_gpio = pdata->reset_gpio; printk("shaobingadd3---imx490_power_get\n"); } pw->state = SWITCH_OFF; return err; } // static int imx490_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; // return 0; // } static int imx490_set_gain(struct imx490 *priv, s32 val); static int imx490_set_frame_length(struct imx490 *priv, s32 val); static int imx490_set_coarse_time(struct imx490 *priv, s32 val); static int imx490_set_coarse_time_shr(struct imx490 *priv, s32 val); static int imx490_set_coarse_time_hdr(struct imx490 *priv, s32 val); static int imx490_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct camera_common_data *s_data = to_camera_common_data(&client->dev); struct imx490 *priv = (struct imx490 *)s_data->priv; struct v4l2_control control; int err; dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); if (!enable) { return 0; } usleep_range(1000, 1100); if (s_data->override_enable) { /* * write list of override regs for the asking gain, * frame rate and exposure time. */ control.id = TEGRA_CAMERA_CID_GAIN; err = v4l2_g_ctrl(&priv->ctrl_handler, &control); err |= imx490_set_gain(priv, control.value); if (err) dev_dbg(&client->dev, "%s: error gain override\n", __func__); control.id = TEGRA_CAMERA_CID_FRAME_LENGTH; err = v4l2_g_ctrl(&priv->ctrl_handler, &control); err |= imx490_set_frame_length(priv, control.value); if (err) dev_dbg(&client->dev, "%s: error frame length override\n", __func__); control.id = TEGRA_CAMERA_CID_COARSE_TIME; err = v4l2_g_ctrl(&priv->ctrl_handler, &control); err |= imx490_set_coarse_time(priv, control.value); if (err) dev_dbg(&client->dev, "%s: error coarse time override\n", __func__); } return 0; } // static int imx490_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 = imx490_write_reg(s_data, // IMX490_GROUP_HOLD_ADDR, val); // if (err) { // dev_dbg(dev, // "%s: Group hold control error\n", __func__); // return err; // } // return 0; // } // static int imx490_set_gain(struct tegracam_device *tc_dev, s64 val) // { // struct camera_common_data *s_data = tc_dev->s_data; // struct device *dev = tc_dev->dev; // const struct sensor_mode_properties *mode = // &s_data->sensor_props.sensor_modes[s_data->mode_prop_idx]; // imx490_reg reg_list[4]; // int err, i; // u16 gain; // gain = (u16)(val / mode->control_properties.step_gain_val); // dev_dbg(dev, "%s: db: %d\n", __func__, gain); // if (gain > IMX490_MAX_GAIN_REG) // gain = IMX490_MAX_GAIN_REG; // imx490_get_gain_reg(reg_list, gain); // for (i = 0; i < 4; i++) { // err = imx490_write_reg(s_data, reg_list[i].addr, // reg_list[i].val); // if (err) // goto fail; // } // return 0; // fail: // dev_info(dev, "%s: GAIN control error\n", __func__); // return err; // } static int imx490_g_input_status(struct v4l2_subdev *sd, u32 *status) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct camera_common_data *s_data = to_camera_common_data(&client->dev); struct imx490 *priv = (struct imx490 *)s_data->priv; struct camera_common_power_rail *pw = &priv->power; *status = pw->state == SWITCH_ON; return 0; } static struct v4l2_subdev_video_ops imx490_subdev_video_ops = { .s_stream = imx490_s_stream, .g_mbus_config = camera_common_g_mbus_config, .g_input_status = imx490_g_input_status, }; static struct v4l2_subdev_core_ops imx490_subdev_core_ops = { .s_power = camera_common_s_power, }; static int imx490_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { return camera_common_g_fmt(sd, &format->format); } // static int imx490_set_frame_rate(struct tegracam_device *tc_dev, s64 val) // { // struct imx490 *priv = (struct imx490 *)tegracam_get_privdata(tc_dev); // /* fixed 30fps */ // priv->frame_length = IMX490_DEFAULT_FRAME_LENGTH; // return 0; // } static int imx490_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { int ret; if (format->which == V4L2_SUBDEV_FORMAT_TRY) ret = camera_common_try_fmt(sd, &format->format); else ret = camera_common_s_fmt(sd, &format->format); return ret; } static struct v4l2_subdev_pad_ops imx490_subdev_pad_ops = { .set_fmt = imx490_set_fmt, .get_fmt = imx490_get_fmt, .enum_mbus_code = camera_common_enum_mbus_code, .enum_frame_size = camera_common_enum_framesizes, .enum_frame_interval = camera_common_enum_frameintervals, }; static struct v4l2_subdev_ops imx490_subdev_ops = { .core = &imx490_subdev_core_ops, .video = &imx490_subdev_video_ops, .pad = &imx490_subdev_pad_ops, }; const struct of_device_id imx490_of_match[] = { { .compatible = "nvidia,imx490", }, { }, }; static struct camera_common_sensor_ops imx490_common_ops = { // .power_on = imx490_power_on, .power_off = imx490_power_off, .write_reg = imx490_write_reg, .read_reg = imx490_read_reg, }; static int imx490_set_group_hold(struct imx490 *priv, s32 val) { int err; int gh_en = switch_ctrl_qmenu[val]; priv->group_hold_prev = val; return 0; if (gh_en == SWITCH_ON) { err = imx490_write_reg(priv->s_data, IMX490_GROUP_HOLD_ADDR, 0x1); if (err) goto fail; } else if (gh_en == SWITCH_OFF) { err = imx490_write_reg(priv->s_data, IMX490_GROUP_HOLD_ADDR, 0x0); if (err) goto fail; } return 0; fail: dev_dbg(&priv->i2c_client->dev, "%s: Group hold control error\n", __func__); return err; } // static int imx490_set_exposure(struct tegracam_device *tc_dev, s64 val) // { // struct imx490 *priv = (struct imx490 *)tegracam_get_privdata(tc_dev); // struct camera_common_data *s_data = tc_dev->s_data; // const struct sensor_mode_properties *mode = // &s_data->sensor_props.sensor_modes[s_data->mode]; // imx490_reg reg_list[3]; // int err; // u32 coarse_time; // u32 shs1; // int i = 0; // if (priv->frame_length == 0) // priv->frame_length = IMX490_DEFAULT_FRAME_LENGTH; // /* coarse time in lines */ // coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] * // priv->frame_length / mode->control_properties.exposure_factor); // shs1 = priv->frame_length - coarse_time; // /* 0 and 1 are prohibited */ // if (shs1 < 2) // shs1 = 2; // imx490_get_coarse_time_regs_shs1(reg_list, shs1); // for (i = 0; i < 3; i++) { // err = imx490_write_reg(priv->s_data, reg_list[i].addr, // reg_list[i].val); // if (err) // goto fail; // } // imx490_get_coarse_time_regs_shs2(reg_list, shs1); // for (i = 0; i < 3; i++) { // err = imx490_write_reg(priv->s_data, reg_list[i].addr, // reg_list[i].val); // if (err) // goto fail; // } // return 0; // fail: // dev_dbg(&priv->i2c_client->dev, // "%s: set coarse time error\n", __func__); // return err; // } // static struct tegracam_ctrl_ops imx490_ctrl_ops = { // .numctrls = ARRAY_SIZE(ctrl_cid_list), // .ctrl_cid_list = ctrl_cid_list, // .set_gain = imx490_set_gain, // .set_exposure = imx490_set_exposure, // .set_exposure_short = imx490_set_exposure, // .set_frame_rate = imx490_set_frame_rate, // .set_group_hold = imx490_set_group_hold, // }; // static struct camera_common_pdata *imx490_parse_dt(struct tegracam_device *tc_dev) // { // struct device *dev = tc_dev->dev; // struct device_node *node = dev->of_node; // struct camera_common_pdata *board_priv_pdata; // const struct of_device_id *match; // int err; // if (!node) // return NULL; // match = of_match_device(imx490_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); // err = of_property_read_string(node, "mclk", // &board_priv_pdata->mclk_name); // if (err) // dev_err(dev, "mclk not in DT\n"); // return board_priv_pdata; // } static int imx490_set_gain(struct imx490 *priv, s32 val) { imx490_reg reg; int err; u16 gain16; u8 gain; return 0; /* translate value */ gain16 = (u16)(val * 10); gain = (u8)(gain16 / 3); dev_dbg(&priv->i2c_client->dev, "%s: gain reg: %d, db: %d\n", __func__, gain, gain16); if (gain < IMX490_MIN_GAIN) gain = IMX490_MIN_GAIN; else if (gain > IMX490_MAX_GAIN_REG) gain = IMX490_MAX_GAIN_REG; reg.val = gain; reg.addr = IMX490_ANALOG_GAIN_SP1H_ADDR; err = imx490_write_reg(priv->s_data, reg.addr, reg.val); if (err) goto fail; reg.addr = IMX490_ANALOG_GAIN_SP1L_ADDR; reg.val = gain/8; err = imx490_write_reg(priv->s_data, reg.addr, reg.val); goto fail; return 0; fail: dev_dbg(&priv->i2c_client->dev, "%s: GAIN control error\n", __func__); return err; } // static int imx490_set_mode(struct tegracam_device *tc_dev) // { // struct imx490 *priv = (struct imx490 *)tegracam_get_privdata(tc_dev); // struct camera_common_data *s_data = tc_dev->s_data; // struct device *dev = tc_dev->dev; // const struct of_device_id *match; // int err; // match = of_match_device(imx490_of_match, dev); // if (!match) { // dev_err(dev, "Failed to find matching dt id\n"); // return -EINVAL; // } // err = imx490_write_table(priv, mode_table[s_data->mode_prop_idx]); // if (err) // return err; // return 0; // } static int imx490_set_frame_length(struct imx490 *priv, s32 val) { imx490_reg reg_list[3]; int err; int i = 0; s32 frame_length = val; return 0; priv->frame_length = (u32) frame_length; if (priv->frame_length > IMX490_MAX_FRAME_LENGTH) priv->frame_length = IMX490_MAX_FRAME_LENGTH; dev_dbg(&priv->i2c_client->dev, "%s: frame_length: %d\n", __func__, priv->frame_length); imx490_get_frame_length_regs(reg_list, priv->frame_length); for (i = 0; i < 3; i++) { err = imx490_write_reg(priv->s_data, reg_list[i].addr, reg_list[i].val); if (err) goto fail; } return 0; fail: dev_dbg(&priv->i2c_client->dev, "%s: FRAME_LENGTH control error\n", __func__); return err; } // static int imx490_start_streaming(struct tegracam_device *tc_dev) // { // struct imx490 *priv = (struct imx490 *)tegracam_get_privdata(tc_dev); // struct device *dev = tc_dev->dev; // int err; // /* enable serdes streaming */ // err = max9295_setup_streaming(priv->ser_dev); // if (err) // goto exit; // err = max9296_setup_streaming(priv->dser_dev, dev); // if (err) // goto exit; // err = max9296_start_streaming(priv->dser_dev, dev); // if (err) // goto exit; // err = imx490_write_table(priv, // mode_table[IMX490_MODE_START_STREAM]); // if (err) // return err; // msleep(20); // return 0; // exit: // dev_err(dev, "%s: error setting stream\n", __func__); // return err; // } static int imx490_set_coarse_time_shr(struct imx490 *priv, s32 val) { imx490_reg reg_list[3]; int err; u32 coarse_time_shs1; u32 reg_shs1; int i = 0; return 0; coarse_time_shs1 = val; if (priv->frame_length == 0) priv->frame_length = IMX490_MIN_FRAME_LENGTH; if (coarse_time_shs1 < IMX490_MIN_SHS1_1080P_HDR) coarse_time_shs1 = IMX490_MIN_SHS1_1080P_HDR; if (coarse_time_shs1 > priv->frame_length - 5) coarse_time_shs1 = priv->frame_length - 5; reg_shs1 = priv->frame_length - coarse_time_shs1 - 1; imx490_get_coarse_time_regs_shs1(reg_list, reg_shs1); for (i = 0; i < 3; i++) { err = imx490_write_reg(priv->s_data, reg_list[i].addr, reg_list[i].val); if (err) goto fail; } return 0; fail: dev_dbg(&priv->i2c_client->dev, "%s: set coarse time error\n", __func__); return err; } // static int imx490_stop_streaming(struct tegracam_device *tc_dev) // { // struct device *dev = tc_dev->dev; // struct imx490 *priv = (struct imx490 *)tegracam_get_privdata(tc_dev); // int err; // /* disable serdes streaming */ // max9296_stop_streaming(priv->dser_dev, dev); // err = imx490_write_table(priv, mode_table[IMX490_MODE_STOP_STREAM]); // if (err) // return err; // return 0; // } static int imx490_set_coarse_time_hdr(struct imx490 *priv, s32 val) { imx490_reg reg_list_shs1[3]; imx490_reg reg_list_shs2[3]; u32 coarse_time_shs1; u32 coarse_time_shs2; u32 reg_shs1; u32 reg_shs2; int err; int i = 0; return 0; if (priv->frame_length == 0) priv->frame_length = IMX490_MIN_FRAME_LENGTH; priv->last_wdr_et_val = val; /* * WDR, update SHS1 as short ET, and SHS2 is 16x of short * TODO: (coarse_time_shs1 = mode->signal_properties.pixel_clock.val * * val / mode->image_properties.line_length / 16) */ coarse_time_shs1 = val / 16; if (coarse_time_shs1 < IMX490_MIN_SHS1_1080P_HDR) coarse_time_shs1 = IMX490_MIN_SHS1_1080P_HDR; if (coarse_time_shs1 > priv->frame_length - 5) coarse_time_shs1 = priv->frame_length - 5; coarse_time_shs2 = (coarse_time_shs1 - IMX490_MIN_SHS1_1080P_HDR) * 16 + IMX490_MIN_SHS2_1080P_HDR; if (coarse_time_shs2 > priv->frame_length - 5) coarse_time_shs2 = priv->frame_length - 5; reg_shs1 = priv->frame_length - coarse_time_shs1 - 1; reg_shs2 = priv->frame_length - coarse_time_shs2 - 1; imx490_get_coarse_time_regs_shs1(reg_list_shs1, reg_shs1); imx490_get_coarse_time_regs_shs2(reg_list_shs2, reg_shs2); dev_dbg(&priv->i2c_client->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 = imx490_write_reg(priv->s_data, reg_list_shs1[i].addr, reg_list_shs1[i].val); if (err) goto fail; err = imx490_write_reg(priv->s_data, reg_list_shs2[i].addr, reg_list_shs2[i].val); if (err) goto fail; } return 0; fail: dev_dbg(&priv->i2c_client->dev, "%s: set WDR coarse time error\n", __func__); return err; } // static struct camera_common_sensor_ops imx490_common_ops = { // .numfrmfmts = ARRAY_SIZE(imx490_frmfmt), // .frmfmt_table = imx490_frmfmt, // .power_on = imx490_power_on, // .power_off = imx490_power_off, // .write_reg = imx490_write_reg, // .read_reg = imx490_read_reg, // .parse_dt = imx490_parse_dt, // .power_get = imx490_power_get, // .power_put = imx490_power_put, // .set_mode = imx490_set_mode, // .start_streaming = imx490_start_streaming, // .stop_streaming = imx490_stop_streaming, // }; // static int imx490_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__); // return 0; // } // static const struct v4l2_subdev_internal_ops imx490_subdev_internal_ops = { // .open = imx490_open, // }; // static int imx490_board_setup(struct imx490 *priv) // { // struct tegracam_device *tc_dev = priv->tc_dev; // struct device *dev = tc_dev->dev; // struct device_node *node = dev->of_node; // struct device_node *ser_node; // struct i2c_client *ser_i2c = NULL; // struct device_node *dser_node; // struct i2c_client *dser_i2c = NULL; // struct device_node *gmsl; // int value = 0xFFFF; // const char *str_value; // const char *str_value1[2]; // int i; // int err; // err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg); // if (err < 0) { // dev_err(dev, "reg not found\n"); // goto error; // } // err = of_property_read_u32(node, "def-addr", // &priv->g_ctx.sdev_def); // if (err < 0) { // dev_err(dev, "def-addr not found\n"); // goto error; // } // ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); // if (ser_node == NULL) { // dev_err(dev, // "missing %s handle\n", // "nvidia,gmsl-ser-device"); // goto error; // } // err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); // if (err < 0) { // dev_err(dev, "serializer reg not found\n"); // goto error; // } // ser_i2c = of_find_i2c_device_by_node(ser_node); // of_node_put(ser_node); // if (ser_i2c == NULL) { // dev_err(dev, "missing serializer dev handle\n"); // goto error; // } // if (ser_i2c->dev.driver == NULL) { // dev_err(dev, "missing serializer driver\n"); // goto error; // } // priv->ser_dev = &ser_i2c->dev; // dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); // if (dser_node == NULL) { // dev_err(dev, // "missing %s handle\n", // "nvidia,gmsl-dser-device"); // goto error; // } // dser_i2c = of_find_i2c_device_by_node(dser_node); // of_node_put(dser_node); // if (dser_i2c == NULL) { // dev_err(dev, "missing deserializer dev handle\n"); // goto error; // } // if (dser_i2c->dev.driver == NULL) { // dev_err(dev, "missing deserializer driver\n"); // goto error; // } // priv->dser_dev = &dser_i2c->dev; // /* populate g_ctx from DT */ // gmsl = of_get_child_by_name(node, "gmsl-link"); // if (gmsl == NULL) { // dev_err(dev, "missing gmsl-link device node\n"); // err = -EINVAL; // goto error; // } // err = of_property_read_string(gmsl, "dst-csi-port", &str_value); // if (err < 0) { // dev_err(dev, "No dst-csi-port found\n"); // goto error; // } // priv->g_ctx.dst_csi_port = // (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; // err = of_property_read_string(gmsl, "src-csi-port", &str_value); // if (err < 0) { // dev_err(dev, "No src-csi-port found\n"); // goto error; // } // priv->g_ctx.src_csi_port = // (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; // err = of_property_read_string(gmsl, "csi-mode", &str_value); // if (err < 0) { // dev_err(dev, "No csi-mode found\n"); // goto error; // } // if (!strcmp(str_value, "1x4")) { // priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; // } else if (!strcmp(str_value, "2x4")) { // priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; // } else if (!strcmp(str_value, "4x2")) { // priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; // } else if (!strcmp(str_value, "2x2")) { // priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; // } else { // dev_err(dev, "invalid csi mode\n"); // goto error; // } // err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); // if (err < 0) { // dev_err(dev, "No serdes-csi-link found\n"); // goto error; // } // priv->g_ctx.serdes_csi_link = // (!strcmp(str_value, "a")) ? // GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B; // err = of_property_read_u32(gmsl, "st-vc", &value); // if (err < 0) { // dev_err(dev, "No st-vc info\n"); // goto error; // } // priv->g_ctx.st_vc = value; // err = of_property_read_u32(gmsl, "vc-id", &value); // if (err < 0) { // dev_err(dev, "No vc-id info\n"); // goto error; // } // priv->g_ctx.dst_vc = value; // err = of_property_read_u32(gmsl, "num-lanes", &value); // if (err < 0) { // dev_err(dev, "No num-lanes info\n"); // goto error; // } // priv->g_ctx.num_csi_lanes = value; // priv->g_ctx.num_streams = // of_property_count_strings(gmsl, "streams"); // if (priv->g_ctx.num_streams <= 0) { // dev_err(dev, "No streams found\n"); // err = -EINVAL; // goto error; // } // for (i = 0; i < priv->g_ctx.num_streams; i++) { // of_property_read_string_index(gmsl, "streams", i, // &str_value1[i]); // if (!str_value1[i]) { // dev_err(dev, "invalid stream info\n"); // goto error; // } // if (!strcmp(str_value1[i], "raw12")) { // priv->g_ctx.streams[i].st_data_type = // GMSL_CSI_DT_RAW_12; // } else if (!strcmp(str_value1[i], "embed")) { // priv->g_ctx.streams[i].st_data_type = // GMSL_CSI_DT_EMBED; // } else if (!strcmp(str_value1[i], "ued-u1")) { // priv->g_ctx.streams[i].st_data_type = // GMSL_CSI_DT_UED_U1; // } else { // dev_err(dev, "invalid stream data type\n"); // goto error; // } // } // priv->g_ctx.s_dev = dev; // return 0; // error: // dev_err(dev, "board setup failed\n"); // return err; // } static int imx490_set_coarse_time(struct imx490 *priv, s32 val) { int err; struct v4l2_control control; int hdr_en; return 0; dev_dbg(&priv->i2c_client->dev, "%s: val: %d\n", __func__, val); control.id = TEGRA_CAMERA_CID_HDR_EN; err = camera_common_g_ctrl(priv->s_data, &control); if (err < 0) { dev_err(&priv->i2c_client->dev, "could not find device ctrl.\n"); return err; } hdr_en = switch_ctrl_qmenu[control.value]; if (hdr_en == SWITCH_ON) { err = imx490_set_coarse_time_hdr(priv, val); if (err) dev_dbg(&priv->i2c_client->dev, "%s: error coarse time SHS1 SHS2 override\n", __func__); } else { err = imx490_set_coarse_time_shr(priv, val); if (err) dev_dbg(&priv->i2c_client->dev, "%s: error coarse time SHS1 override\n", __func__); } return err; } static int imx490_s_ctrl(struct v4l2_ctrl *ctrl) { struct imx490 *priv = container_of(ctrl->handler, struct imx490, ctrl_handler); int err = 0; if (priv->power.state == SWITCH_OFF) return 0; switch (ctrl->id) { case TEGRA_CAMERA_CID_GAIN: err = imx490_set_gain(priv, ctrl->val); break; case TEGRA_CAMERA_CID_FRAME_LENGTH: err = imx490_set_frame_length(priv, ctrl->val); break; case TEGRA_CAMERA_CID_COARSE_TIME: err = imx490_set_coarse_time(priv, ctrl->val); break; case TEGRA_CAMERA_CID_COARSE_TIME_SHORT: err = imx490_set_coarse_time(priv, ctrl->val); break; case TEGRA_CAMERA_CID_GROUP_HOLD: err = imx490_set_group_hold(priv, ctrl->val); break; case TEGRA_CAMERA_CID_HDR_EN: break; default: pr_err("%s: unknown ctrl id.\n", __func__); return -EINVAL; } return err; } static int imx490_ctrls_init(struct imx490 *priv) { struct i2c_client *client = priv->i2c_client; struct v4l2_ctrl *ctrl; int num_ctrls; int err; int i; dev_dbg(&client->dev, "%s++\n", __func__); num_ctrls = ARRAY_SIZE(ctrl_config_list); v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); for (i = 0; i < num_ctrls; i++) { ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, &ctrl_config_list[i], NULL); if (ctrl == NULL) { dev_err(&client->dev, "Failed to init %s ctrl\n", ctrl_config_list[i].name); continue; } if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { ctrl->p_new.p_char = devm_kzalloc(&client->dev, ctrl_config_list[i].max + 1, GFP_KERNEL); } priv->ctrls[i] = ctrl; } priv->numctrls = num_ctrls; priv->subdev->ctrl_handler = &priv->ctrl_handler; if (priv->ctrl_handler.error) { dev_err(&client->dev, "Error %d adding controls\n", priv->ctrl_handler.error); err = priv->ctrl_handler.error; goto error; } err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); if (err) { dev_err(&client->dev, "Error %d setting default controls\n", err); goto error; } return 0; error: v4l2_ctrl_handler_free(&priv->ctrl_handler); return err; } MODULE_DEVICE_TABLE(of, imx490_of_match); static struct camera_common_pdata *imx490_parse_dt(struct imx490 *priv, struct i2c_client *client, struct camera_common_data *s_data) { struct device_node *node = client->dev.of_node; struct camera_common_pdata *board_priv_pdata; const struct of_device_id *match; int err; if (!node) return NULL; match = of_match_device(imx490_of_match, &client->dev); if (!match) { dev_err(&client->dev, "Failed to find matching dt id\n"); return NULL; } board_priv_pdata = devm_kzalloc(&client->dev, sizeof(*board_priv_pdata), GFP_KERNEL); err = of_property_read_string(node, "mclk", &board_priv_pdata->mclk_name); if (err) dev_err(&client->dev, "mclk not in DT\n"); board_priv_pdata->reset_gpio = of_get_named_gpio(node, "reset-gpios", 0); printk("shaobingadd1---imx490_parse_dt\n"); return board_priv_pdata; } static int imx490_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__); return 0; } static const struct v4l2_subdev_internal_ops imx490_subdev_internal_ops = { .open = imx490_open, }; static const struct media_entity_operations imx490_media_ops = { #ifdef CONFIG_MEDIA_CONTROLLER .link_validate = v4l2_subdev_link_validate, #endif }; static int imx490_probe(struct i2c_client *client, const struct i2c_device_id *id) { // struct device *dev = &client->dev; // struct device_node *node = dev->of_node; // struct tegracam_device *tc_dev; struct camera_common_data *common_data; struct device_node *node = client->dev.of_node; struct imx490 *priv; int err; // uint8_t reg_val[2]; struct device *dev ; unsigned int regVal; static int count = 0; count++; printk("shaobingadd2---imx490_probe count=%d \n", count ); // printk("shaobingadd1---imx490_probe\n"); // dev_info(dev, "probing v4l2 sensor.\n"); dev_info(&client->dev, "probing v4l2 sensor.\n"); if (!IS_ENABLED(CONFIG_OF) || !node) return -EINVAL; common_data = devm_kzalloc(&client->dev, sizeof(struct camera_common_data), GFP_KERNEL); if (!common_data) { dev_err(&client->dev, "unable to allocate memory!\n"); // priv = devm_kzalloc(dev, sizeof(struct imx490), GFP_KERNEL); // if (!priv) { // dev_err(dev, "unable to allocate memory!\n"); 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, "imx490", sizeof(tc_dev->name)); // tc_dev->dev_regmap_config = &sensor_regmap_config; // tc_dev->sensor_ops = &imx490_common_ops; // tc_dev->v4l2sd_internal_ops = &imx490_subdev_internal_ops; // tc_dev->tcctrl_ops = &imx490_ctrl_ops; priv = devm_kzalloc(&client->dev, sizeof(struct imx490) + sizeof(struct v4l2_ctrl *) * ARRAY_SIZE(ctrl_config_list), GFP_KERNEL); if (!priv) { dev_err(&client->dev, "unable to allocate memory!\n"); return -ENOMEM; } // printk("shaobingadd2---imx490_probe\n"); // err = tegracam_device_register(tc_dev); // if (err) { // dev_err(dev, "tegra camera driver registration failed\n"); // return err; priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); if (IS_ERR(priv->regmap)) { dev_err(&client->dev, "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); return -ENODEV; } // 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 = imx490_board_setup(priv); // if (err) { // tegracam_device_unregister(tc_dev); // dev_err(dev, "board setup failed\n"); // return err; common_data->ops = &imx490_common_ops; common_data->ctrl_handler = &priv->ctrl_handler; common_data->dev = &client->dev; common_data->frmfmt = &imx490_frmfmt[0]; common_data->colorfmt = camera_common_find_datafmt( IMX490_DEFAULT_DATAFMT); common_data->power = &priv->power; common_data->ctrls = priv->ctrls; common_data->priv = (void *)priv; common_data->numctrls = ARRAY_SIZE(ctrl_config_list); common_data->numfmts = ARRAY_SIZE(imx490_frmfmt); common_data->def_mode = IMX490_DEFAULT_MODE; common_data->def_width = IMX490_DEFAULT_WIDTH; common_data->def_height = IMX490_DEFAULT_HEIGHT; common_data->fmt_width = common_data->def_width; common_data->fmt_height = common_data->def_height; common_data->def_clk_freq = IMX490_DEFAULT_CLK_FREQ; // printk("shaobingadd3---imx490_probe\n"); priv->pdata = imx490_parse_dt(priv, client, common_data); if (!priv->pdata) { dev_err(&client->dev, "unable to get platform data\n"); return -EFAULT; } // printk("shaobingadd4---imx490_probe\n"); // /* Pair sensor to serializer dev */ // err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); // if (err) { // dev_err(&client->dev, "gmsl ser pairing failed\n"); priv->i2c_client = client; priv->s_data = common_data; priv->subdev = &common_data->subdev; priv->subdev->dev = &client->dev; priv->s_data->dev = &client->dev; priv->last_wdr_et_val = 0; priv->id = id; err = imx490_power_get(priv); if (err) return err; // } // printk("shaobingadd31---imx490_probe\n"); // /* Register sensor to deserializer dev */ // err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx); err = camera_common_initialize(common_data, "imx490"); if (err) { // dev_err(&client->dev, "gmsl deserializer register failed\n"); dev_err(&client->dev, "Failed to initialize imx490.\n"); return err; } // // /* // * gmsl serdes setup // * // * Sensor power on/off should be the right place for serdes // * setup/reset. But the problem is, the total required delay // * in serdes setup/reset exceeds the frame wait timeout, looks to // * be related to multiple channel open and close sequence // * issue (#BUG 200477330). // * Once this bug is fixed, these may be moved to power on/off. // * The delays in serdes is as per guidelines and can't be reduced, // * so it is placed in probe/remove, though for that, deserializer // * would be powered on always post boot, until 1.2v is supplied // * to deserializer from CVB. // */ // err = imx490_gmsl_serdes_setup(priv); // if (err) { // dev_err(&client->dev, // "%s gmsl serdes setup failed\n", __func__); v4l2_i2c_subdev_init(priv->subdev, client, &imx490_subdev_ops); err = imx490_ctrls_init(priv); if (err) return err; // } // err = tegracam_v4l2subdev_register(tc_dev, true); // if (err) { // dev_err(dev, "tegra camera subdev registration failed\n"); priv->subdev->internal_ops = &imx490_subdev_internal_ops; priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; #if defined(CONFIG_MEDIA_CONTROLLER) // printk("shaobingadd5---imx490_probe\n"); priv->pad.flags = MEDIA_PAD_FL_SOURCE; priv->subdev->entity.ops = &imx490_media_ops; err = tegra_media_entity_init(&priv->subdev->entity, 1, &priv->pad, true, true); if (err < 0) { dev_err(&client->dev, "unable to init media entity\n"); return err; } #endif err = v4l2_async_register_subdev(priv->subdev); if (err) return err; printk("shaobingadd6---imx490_probe\n"); dev_info(&client->dev, "Detected IMX490 sensor\n"); if(count == 1){//只reset一次 err = imx490_power_on(priv->s_data); if (err) { dev_err(dev, "error during power on sensor (%d)\n", err); } usleep_range(300*1000, 310*1000); err = imx490_write_table(priv, mode_table[IMX490_MODE_Dser_Ser]); usleep_range(500000, 510000); err = imx490_write_table(priv, mode_table[IMX490_MODE_START_STREAM]); printk("shaobingadd7---imx490_probe\n"); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x112, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x112, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x82, 0x112, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x82, regAddr=0x112, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x11A, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x11A, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x13, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x13, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x01, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x01, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x102, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x102, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x10a, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x10a, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x112, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x112, regData=0x%x \n", regVal ); // err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x80, 0x11a, ®Val ); // printk("shaobingadd2---imx490_read_reg devAddr=0x80, regAddr=0x11a, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x1dc, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x1DC, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x1fc, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x1FC, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x21c, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x21C, regData=0x%x \n", regVal ); err = imx490_read_reg_(priv->i2c_client, priv->regmap, 0x90, 0x23c, ®Val ); printk("shaobingadd2---imx490_read_reg devAddr=0x90, regAddr=0x23C, regData=0x%x \n", regVal ); } // dev = priv->s_data->dev; // err = imx490_read_reg(priv->s_data, 0x00, ®_val[0]); // if (err) { // dev_err(dev, "%s: error during i2c read probe (%d)\n", // __func__, err); // }else { // printk("shaobingadd0---imx490_board_setup, reg_val[0]=0x%x \n", reg_val[0]); // } // err = max9295_write_reg_Ser(priv->i2c_client, priv->regmap, 0x80, 0, 0x82); return 0; } static int imx490_remove(struct i2c_client *client) { struct camera_common_data *s_data = to_camera_common_data(&client->dev); struct imx490 *priv = (struct imx490 *)s_data->priv; // imx490_gmsl_serdes_reset(priv); v4l2_async_unregister_subdev(priv->subdev); #if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&priv->subdev->entity); #endif // tegracam_v4l2subdev_unregister(priv->tc_dev); // tegracam_device_unregister(priv->tc_dev); v4l2_ctrl_handler_free(&priv->ctrl_handler); camera_common_remove_debugfs(s_data); return 0; } static const struct i2c_device_id imx490_id[] = { { "imx490", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, imx490_id); static struct i2c_driver imx490_i2c_driver = { .driver = { .name = "imx490", .owner = THIS_MODULE, .of_match_table = of_match_ptr(imx490_of_match), }, .probe = imx490_probe, .remove = imx490_remove, .id_table = imx490_id, }; static int __init imx490_init(void) { // mutex_init(&serdes_lock__); printk("shaobingadd1---imx490_init\n"); return i2c_add_driver(&imx490_i2c_driver); } static void __exit imx490_exit(void) { // mutex_destroy(&serdes_lock__); i2c_del_driver(&imx490_i2c_driver); } module_init(imx490_init); module_exit(imx490_exit); MODULE_DESCRIPTION("Media Controller driver for Sony IMX490"); MODULE_AUTHOR("NVIDIA Corporation"); MODULE_AUTHOR("Sudhir Vyas