diff options
Diffstat (limited to 'drivers/media/i2c')
55 files changed, 1974 insertions, 2682 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4c3435921f..742bc66560 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -195,6 +195,7 @@ config VIDEO_IMX334 config VIDEO_IMX335 tristate "Sony IMX335 sensor support" depends on OF_GPIO + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX335 camera. @@ -224,6 +225,7 @@ config VIDEO_IMX412 config VIDEO_IMX415 tristate "Sony IMX415 sensor support" depends on OF_GPIO + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX415 camera. @@ -404,6 +406,7 @@ config VIDEO_OV2740 config VIDEO_OV4689 tristate "OmniVision OV4689 sensor support" depends on GPIOLIB + select V4L2_CCI_I2C help This is a Video4Linux2 sensor-level driver for the OmniVision OV4689 camera. @@ -658,6 +661,7 @@ config VIDEO_S5K6A3 config VIDEO_ST_VGXY61 tristate "ST VGXY61 sensor support" + select V4L2_CCI_I2C depends on OF && GPIOLIB help This is a Video4Linux2 sensor driver for the ST VGXY61 @@ -675,6 +679,7 @@ config VIDEO_THP7312 tristate "THine THP7312 support" depends on I2C select FW_LOADER + select FW_UPLOAD select MEDIA_CONTROLLER select V4L2_CCI_I2C select V4L2_FWNODE diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 409b9a37f0..819ff9f7c9 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1057,11 +1057,11 @@ static int adv7182_init(struct adv7180_state *state) ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x17); } - } - else + } else { adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x07); + } adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); } @@ -1486,7 +1486,7 @@ static int adv7180_probe(struct i2c_client *client) if (ret) goto err_media_entity_cleanup; - if (state->irq) { + if (state->irq > 0) { ret = request_threaded_irq(client->irq, NULL, adv7180_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, KBUILD_MODNAME, state); diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index ff21cd4744..4fbe4e1857 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -403,7 +403,7 @@ adv7343_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = of_graph_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!np) return NULL; diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index ec151dc69c..a4db9bae5f 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -214,7 +214,7 @@ static int adv748x_hdmi_set_video_timings(struct adv748x_state *state, * v4l2_subdev_video_ops */ -static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd, +static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); @@ -254,7 +254,7 @@ error: return ret; } -static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, +static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); @@ -269,7 +269,7 @@ static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, +static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); @@ -392,9 +392,6 @@ static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd, } static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = { - .s_dv_timings = adv748x_hdmi_s_dv_timings, - .g_dv_timings = adv748x_hdmi_g_dv_timings, - .query_dv_timings = adv748x_hdmi_query_dv_timings, .g_input_status = adv748x_hdmi_g_input_status, .s_stream = adv748x_hdmi_s_stream, .g_pixelaspect = adv748x_hdmi_g_pixelaspect, @@ -413,7 +410,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi) if (!tx) return -ENOLINK; - adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings); + adv748x_hdmi_query_dv_timings(&hdmi->sd, 0, &timings); return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock); } @@ -610,6 +607,9 @@ static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi = { .get_fmt = adv748x_hdmi_get_format, .get_edid = adv748x_hdmi_get_edid, .set_edid = adv748x_hdmi_set_edid, + .s_dv_timings = adv748x_hdmi_s_dv_timings, + .g_dv_timings = adv748x_hdmi_g_dv_timings, + .query_dv_timings = adv748x_hdmi_query_dv_timings, .dv_timings_cap = adv748x_hdmi_dv_timings_cap, .enum_dv_timings = adv748x_hdmi_enum_dv_timings, }; @@ -734,7 +734,7 @@ int adv748x_hdmi_init(struct adv748x_hdmi *hdmi) struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30; int ret; - adv748x_hdmi_s_dv_timings(&hdmi->sd, &cea1280x720); + adv748x_hdmi_s_dv_timings(&hdmi->sd, 0, &cea1280x720); /* Initialise a default 16:9 aspect ratio */ hdmi->aspect_ratio.numerator = 16; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 6f90f78f58..d2b5e722e9 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -173,7 +173,6 @@ struct adv748x_afe { * * @endpoints: parsed device node endpoints for each port * - * @i2c_addresses: I2C Page addresses * @i2c_clients: I2C clients for the page accesses * @regmap: regmap configuration pages. * diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 0f780eb6ef..79946e9c74 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -995,8 +995,8 @@ static int adv7511_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int adv7511_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int adv7511_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { struct adv7511_state *state = get_adv7511_state(sd); struct v4l2_bt_timings *bt = &timings->bt; @@ -1004,6 +1004,9 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + /* quick sanity check */ if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL)) return -EINVAL; @@ -1042,13 +1045,16 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int adv7511_g_dv_timings(struct v4l2_subdev *sd, +static int adv7511_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv7511_state *state = get_adv7511_state(sd); v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + if (!timings) return -EINVAL; @@ -1078,8 +1084,6 @@ static int adv7511_dv_timings_cap(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops adv7511_video_ops = { .s_stream = adv7511_s_stream, - .s_dv_timings = adv7511_s_dv_timings, - .g_dv_timings = adv7511_g_dv_timings, }; /* ------------------------------ AUDIO OPS ------------------------------ */ @@ -1403,6 +1407,8 @@ static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { .enum_mbus_code = adv7511_enum_mbus_code, .get_fmt = adv7511_get_fmt, .set_fmt = adv7511_set_fmt, + .s_dv_timings = adv7511_s_dv_timings, + .g_dv_timings = adv7511_g_dv_timings, .enum_dv_timings = adv7511_enum_dv_timings, .dv_timings_cap = adv7511_dv_timings_cap, }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 810fa8826f..48230d5109 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1557,8 +1557,8 @@ static unsigned int adv76xx_read_hdmi_pixelclock(struct v4l2_subdev *sd) return freq; } -static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { struct adv76xx_state *state = to_state(sd); const struct adv76xx_chip_info *info = state->info; @@ -1687,8 +1687,8 @@ found: return 0; } -static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { struct adv76xx_state *state = to_state(sd); struct v4l2_bt_timings *bt; @@ -1730,8 +1730,8 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int adv76xx_g_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int adv76xx_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { struct adv76xx_state *state = to_state(sd); @@ -2607,7 +2607,7 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) stdi.lcf, stdi.bl, stdi.lcvs, stdi.interlaced ? "interlaced" : "progressive", stdi.hs_pol, stdi.vs_pol); - if (adv76xx_query_dv_timings(sd, &timings)) + if (adv76xx_query_dv_timings(sd, 0, &timings)) v4l2_info(sd, "No video detected\n"); else v4l2_print_dv_timings(sd->name, "Detected format: ", @@ -2726,9 +2726,6 @@ static const struct v4l2_subdev_core_ops adv76xx_core_ops = { static const struct v4l2_subdev_video_ops adv76xx_video_ops = { .s_routing = adv76xx_s_routing, .g_input_status = adv76xx_g_input_status, - .s_dv_timings = adv76xx_s_dv_timings, - .g_dv_timings = adv76xx_g_dv_timings, - .query_dv_timings = adv76xx_query_dv_timings, }; static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { @@ -2738,6 +2735,9 @@ static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { .set_fmt = adv76xx_set_format, .get_edid = adv76xx_get_edid, .set_edid = adv76xx_set_edid, + .s_dv_timings = adv76xx_s_dv_timings, + .g_dv_timings = adv76xx_g_dv_timings, + .query_dv_timings = adv76xx_query_dv_timings, .dv_timings_cap = adv76xx_dv_timings_cap, .enum_dv_timings = adv76xx_enum_dv_timings, }; @@ -3204,8 +3204,8 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; - /* Parse the endpoint. */ - endpoint = of_graph_get_next_endpoint(np, NULL); + /* FIXME: Parse the endpoint. */ + endpoint = of_graph_get_endpoint_by_regs(np, -1, -1); if (!endpoint) return -EINVAL; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 2ad0f9f550..f2d4217310 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1518,7 +1518,7 @@ static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS; } -static int adv7842_query_dv_timings(struct v4l2_subdev *sd, +static int adv7842_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv7842_state *state = to_state(sd); @@ -1527,6 +1527,9 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + memset(timings, 0, sizeof(struct v4l2_dv_timings)); /* SDP block */ @@ -1643,7 +1646,7 @@ found: return 0; } -static int adv7842_s_dv_timings(struct v4l2_subdev *sd, +static int adv7842_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv7842_state *state = to_state(sd); @@ -1652,6 +1655,9 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + if (state->mode == ADV7842_MODE_SDP) return -ENODATA; @@ -1689,11 +1695,14 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int adv7842_g_dv_timings(struct v4l2_subdev *sd, +static int adv7842_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct adv7842_state *state = to_state(sd); + if (pad != 0) + return -EINVAL; + if (state->mode == ADV7842_MODE_SDP) return -ENODATA; *timings = state->timings; @@ -2780,7 +2789,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) "interlaced" : "progressive", hs_pol, vs_pol); } - if (adv7842_query_dv_timings(sd, &timings)) + if (adv7842_query_dv_timings(sd, 0, &timings)) v4l2_info(sd, "No video detected\n"); else v4l2_print_dv_timings(sd->name, "Detected format: ", @@ -3226,7 +3235,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd) memset(&state->timings, 0, sizeof(struct v4l2_dv_timings)); - adv7842_s_dv_timings(sd, &timings); + adv7842_s_dv_timings(sd, 0, &timings); return ret; } @@ -3298,9 +3307,6 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { .s_routing = adv7842_s_routing, .querystd = adv7842_querystd, .g_input_status = adv7842_g_input_status, - .s_dv_timings = adv7842_s_dv_timings, - .g_dv_timings = adv7842_g_dv_timings, - .query_dv_timings = adv7842_query_dv_timings, }; static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { @@ -3309,6 +3315,9 @@ static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { .set_fmt = adv7842_set_format, .get_edid = adv7842_get_edid, .set_edid = adv7842_set_edid, + .s_dv_timings = adv7842_s_dv_timings, + .g_dv_timings = adv7842_g_dv_timings, + .query_dv_timings = adv7842_query_dv_timings, .enum_dv_timings = adv7842_enum_dv_timings, .dv_timings_cap = adv7842_dv_timings_cap, }; diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 34ff7fad38..272d892da5 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1170,40 +1170,32 @@ static int alvium_set_bayer_pattern(struct alvium_dev *alvium, return 0; } -static int alvium_get_frame_interval(struct alvium_dev *alvium) +static int alvium_get_frame_interval(struct alvium_dev *alvium, + u64 *min_fr, u64 *max_fr) { - u64 dft_fr, min_fr, max_fr; int ret = 0; - alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW, - &dft_fr, &ret); alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R, - &min_fr, &ret); + min_fr, &ret); alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R, - &max_fr, &ret); - if (ret) - return ret; - - alvium->dft_fr = dft_fr; - alvium->min_fr = min_fr; - alvium->max_fr = max_fr; + max_fr, &ret); - return 0; + return ret; } -static int alvium_set_frame_rate(struct alvium_dev *alvium) +static int alvium_set_frame_rate(struct alvium_dev *alvium, u64 fr) { struct device *dev = &alvium->i2c_client->dev; int ret; ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW, - alvium->fr); + fr); if (ret) { dev_err(dev, "Fail to set frame rate lanes reg\n"); return ret; } - dev_dbg(dev, "set frame rate: %llu us\n", alvium->fr); + dev_dbg(dev, "set frame rate: %llu us\n", fr); return 0; } @@ -1472,7 +1464,7 @@ static int alvium_get_hw_features_params(struct alvium_dev *alvium) ret = alvium_get_img_height_params(alvium); if (ret) { - dev_err(dev, "Fail to read img heigth regs\n"); + dev_err(dev, "Fail to read img height regs\n"); return ret; } @@ -1647,44 +1639,28 @@ static int alvium_hw_init(struct alvium_dev *alvium) } /* --------------- Subdev Operations --------------- */ - -static int alvium_g_frame_interval(struct v4l2_subdev *sd, +static int alvium_s_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval *fi) { struct alvium_dev *alvium = sd_to_alvium(sd); - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - fi->interval = alvium->frame_interval; - - return 0; -} - -static int alvium_set_frame_interval(struct alvium_dev *alvium, - struct v4l2_subdev_frame_interval *fi) -{ struct device *dev = &alvium->i2c_client->dev; u64 req_fr, min_fr, max_fr; + struct v4l2_fract *interval; int ret; + if (alvium->streaming) + return -EBUSY; + if (fi->interval.denominator == 0) return -EINVAL; - ret = alvium_get_frame_interval(alvium); + ret = alvium_get_frame_interval(alvium, &min_fr, &max_fr); if (ret) { dev_err(dev, "Fail to get frame interval\n"); return ret; } - min_fr = alvium->min_fr; - max_fr = alvium->max_fr; - dev_dbg(dev, "fi->interval.numerator = %d\n", fi->interval.numerator); dev_dbg(dev, "fi->interval.denominator = %d\n", @@ -1692,39 +1668,17 @@ static int alvium_set_frame_interval(struct alvium_dev *alvium, req_fr = (u64)((fi->interval.denominator * USEC_PER_SEC) / fi->interval.numerator); + req_fr = clamp(req_fr, min_fr, max_fr); - if (req_fr >= max_fr && req_fr <= min_fr) - req_fr = alvium->dft_fr; + interval = v4l2_subdev_state_get_interval(sd_state, 0); - alvium->fr = req_fr; - alvium->frame_interval.numerator = fi->interval.numerator; - alvium->frame_interval.denominator = fi->interval.denominator; + interval->numerator = fi->interval.numerator; + interval->denominator = fi->interval.denominator; - return 0; -} - -static int alvium_s_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *fi) -{ - struct alvium_dev *alvium = sd_to_alvium(sd); - int ret; - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (alvium->streaming) - return -EBUSY; - - ret = alvium_set_frame_interval(alvium, fi); - if (!ret) - ret = alvium_set_frame_rate(alvium); + return 0; - return ret; + return alvium_set_frame_rate(alvium, req_fr); } static int alvium_enum_mbus_code(struct v4l2_subdev *sd, @@ -1872,6 +1826,7 @@ static int alvium_init_state(struct v4l2_subdev *sd, { struct alvium_dev *alvium = sd_to_alvium(sd); struct alvium_mode *mode = &alvium->mode; + struct v4l2_fract *interval; struct v4l2_subdev_format sd_fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, .format = alvium_csi2_default_fmt, @@ -1889,6 +1844,11 @@ static int alvium_init_state(struct v4l2_subdev *sd, *v4l2_subdev_state_get_crop(state, 0) = sd_crop.rect; *v4l2_subdev_state_get_format(state, 0) = sd_fmt.format; + /* Setup initial frame interval*/ + interval = v4l2_subdev_state_get_interval(state, 0); + interval->numerator = 1; + interval->denominator = ALVIUM_DEFAULT_FR_HZ; + return 0; } @@ -2002,7 +1962,7 @@ static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl) int val; switch (ctrl->id) { - case V4L2_CID_GAIN: + case V4L2_CID_ANALOGUE_GAIN: val = alvium_get_gain(alvium); if (val < 0) return val; @@ -2034,7 +1994,7 @@ static int alvium_s_ctrl(struct v4l2_ctrl *ctrl) return 0; switch (ctrl->id) { - case V4L2_CID_GAIN: + case V4L2_CID_ANALOGUE_GAIN: ret = alvium_set_ctrl_gain(alvium, ctrl->val); break; case V4L2_CID_AUTOGAIN: @@ -2163,7 +2123,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) if (alvium->avail_ft.gain) { ctrls->gain = v4l2_ctrl_new_std(hdl, ops, - V4L2_CID_GAIN, + V4L2_CID_ANALOGUE_GAIN, alvium->min_gain, alvium->max_gain, alvium->inc_gain, @@ -2258,7 +2218,7 @@ static const struct v4l2_subdev_pad_ops alvium_pad_ops = { .set_fmt = alvium_set_fmt, .get_selection = alvium_get_selection, .set_selection = alvium_set_selection, - .get_frame_interval = alvium_g_frame_interval, + .get_frame_interval = v4l2_subdev_get_frame_interval, .set_frame_interval = alvium_s_frame_interval, }; @@ -2279,11 +2239,6 @@ static int alvium_subdev_init(struct alvium_dev *alvium) struct v4l2_subdev *sd = &alvium->sd; int ret; - /* Setup initial frame interval*/ - alvium->frame_interval.numerator = 1; - alvium->frame_interval.denominator = ALVIUM_DEFAULT_FR_HZ; - alvium->fr = ALVIUM_DEFAULT_FR_HZ; - /* Setup the initial mode */ alvium->mode.fmt = alvium_csi2_default_fmt; alvium->mode.width = alvium_csi2_default_fmt.width; diff --git a/drivers/media/i2c/alvium-csi2.h b/drivers/media/i2c/alvium-csi2.h index b85a25169e..9463f8604f 100644 --- a/drivers/media/i2c/alvium-csi2.h +++ b/drivers/media/i2c/alvium-csi2.h @@ -442,11 +442,6 @@ struct alvium_dev { s32 inc_sharp; struct alvium_mode mode; - struct v4l2_fract frame_interval; - u64 dft_fr; - u64 min_fr; - u64 max_fr; - u64 fr; u8 h_sup_csi_lanes; u64 link_freq; diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index c7d5fa532a..09331cf95c 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -314,7 +314,7 @@ static void ar0521_calc_pll(struct ar0521_dev *sensor) * In the clock tree: * MIPI_CLK = PIXEL_CLOCK * bpp / 2 / 2 * - * Generic pixel_rate to bus clock frequencey equation: + * Generic pixel_rate to bus clock frequency equation: * MIPI_CLK = V4L2_CID_PIXEL_RATE * bpp / lanes / 2 * * From which we derive the PIXEL_CLOCK to use in the clock tree: @@ -327,7 +327,7 @@ static void ar0521_calc_pll(struct ar0521_dev *sensor) * * TODO: in case we have less data lanes we have to reduce the desired * VCO not to exceed the limits specified by the datasheet and - * consequentially reduce the obtained pixel clock. + * consequently reduce the obtained pixel clock. */ pixel_clock = AR0521_PIXEL_CLOCK_RATE * 2 / sensor->lane_count; bpp = ar0521_code_to_bpp(sensor); @@ -806,7 +806,7 @@ static const struct initial_reg { REGS(be(0x3F00), be(0x0017), /* 3F00: BM_T0 */ be(0x02DD), /* 3F02: BM_T1 */ - /* 3F04: if Ana_gain less than 2, use noise_floor0, multipl */ + /* 3F04: if Ana_gain less than 2, use noise_floor0, multiply */ be(0x0020), /* 3F06: if Ana_gain between 4 and 7, use noise_floor2 and */ be(0x0040), diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index e21287d50c..e1ae0f9fad 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -674,7 +674,7 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_status = pm_runtime_get_if_active(&client->dev, true); + pm_status = pm_runtime_get_if_active(&client->dev); if (!pm_status) return 0; diff --git a/drivers/media/i2c/ccs/ccs-quirk.h b/drivers/media/i2c/ccs/ccs-quirk.h index 0b1a64958d..392c971096 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.h +++ b/drivers/media/i2c/ccs/ccs-quirk.h @@ -28,11 +28,11 @@ struct ccs_sensor; * @reg_access: Register access quirk. The quirk may divert the access * to another register, or no register at all. * - * @write: Is this read (false) or write (true) access? - * @reg: Pointer to the register to access - * @value: Register value, set by the caller on write, or + * -write: Is this read (false) or write (true) access? + * -reg: Pointer to the register to access + * -val: Register value, set by the caller on write, or * by the quirk on read - * @return: 0 on success, -ENOIOCTLCMD if no register + * -return: 0 on success, -ENOIOCTLCMD if no register * access may be done by the caller (default read * value is zero), else negative error code on error * @flags: Quirk flags diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index cc09b32ede..0e88ce0ef8 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -157,6 +157,8 @@ static int dw9714_probe(struct i2c_client *client) return rval; } + usleep_range(1000, 2000); + v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; @@ -308,8 +310,8 @@ module_i2c_driver(dw9714_i2c_driver); MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); MODULE_AUTHOR("Jian Xu Zheng"); -MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>"); -MODULE_AUTHOR("Jouni Ukkonen <jouni.ukkonen@intel.com>"); -MODULE_AUTHOR("Tommi Franttila <tommi.franttila@intel.com>"); +MODULE_AUTHOR("Yuning Pu"); +MODULE_AUTHOR("Jouni Ukkonen"); +MODULE_AUTHOR("Tommi Franttila"); MODULE_DESCRIPTION("DW9714 VCM driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index 38c77d5157..b440f386f0 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -3,10 +3,13 @@ #include <asm/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -633,6 +636,11 @@ struct hi556 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; + /* GPIOs, clocks, etc. */ + struct gpio_desc *reset_gpio; + struct clk *clk; + struct regulator *avdd; + /* Current mode */ const struct hi556_mode *cur_mode; @@ -1206,8 +1214,18 @@ static int hi556_check_hwcfg(struct device *dev) int ret = 0; unsigned int i, j; - if (!fwnode) - return -ENXIO; + /* + * Sometimes the fwnode graph is initialized by the bridge driver, + * wait for this. + */ + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EPROBE_DEFER; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); if (ret) { @@ -1220,15 +1238,6 @@ static int hi556_check_hwcfg(struct device *dev) return -EINVAL; } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); - if (!ep) - return -ENXIO; - - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - fwnode_handle_put(ep); - if (ret) - return ret; - if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { dev_err(dev, "number of CSI2 data lanes %d is not supported", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -1275,6 +1284,47 @@ static void hi556_remove(struct i2c_client *client) mutex_destroy(&hi556->mutex); } +static int hi556_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct hi556 *hi556 = to_hi556(sd); + int ret; + + gpiod_set_value_cansleep(hi556->reset_gpio, 1); + + ret = regulator_disable(hi556->avdd); + if (ret) { + dev_err(dev, "failed to disable avdd: %d\n", ret); + gpiod_set_value_cansleep(hi556->reset_gpio, 0); + return ret; + } + + clk_disable_unprepare(hi556->clk); + return 0; +} + +static int hi556_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct hi556 *hi556 = to_hi556(sd); + int ret; + + ret = clk_prepare_enable(hi556->clk); + if (ret) + return ret; + + ret = regulator_enable(hi556->avdd); + if (ret) { + dev_err(dev, "failed to enable avdd: %d\n", ret); + clk_disable_unprepare(hi556->clk); + return ret; + } + + gpiod_set_value_cansleep(hi556->reset_gpio, 0); + usleep_range(5000, 5500); + return 0; +} + static int hi556_probe(struct i2c_client *client) { struct hi556 *hi556; @@ -1294,12 +1344,35 @@ static int hi556_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); + hi556->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(hi556->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(hi556->reset_gpio), + "failed to get reset GPIO\n"); + + hi556->clk = devm_clk_get_optional(&client->dev, "clk"); + if (IS_ERR(hi556->clk)) + return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), + "failed to get clock\n"); + + /* The regulator core will provide a "dummy" regulator if necessary */ + hi556->avdd = devm_regulator_get(&client->dev, "avdd"); + if (IS_ERR(hi556->avdd)) + return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd), + "failed to get avdd regulator\n"); + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + /* Ensure non ACPI managed resources are enabled */ + ret = hi556_resume(&client->dev); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to power on sensor\n"); + ret = hi556_identify_module(hi556); if (ret) { dev_err(&client->dev, "failed to find sensor: %d", ret); - return ret; + goto probe_error_power_off; } } @@ -1344,9 +1417,16 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(hi556->sd.ctrl_handler); mutex_destroy(&hi556->mutex); +probe_error_power_off: + if (full_power) + hi556_suspend(&client->dev); + return ret; } +static DEFINE_RUNTIME_DEV_PM_OPS(hi556_pm_ops, hi556_suspend, hi556_resume, + NULL); + #ifdef CONFIG_ACPI static const struct acpi_device_id hi556_acpi_ids[] = { {"INT3537"}, @@ -1360,6 +1440,7 @@ static struct i2c_driver hi556_i2c_driver = { .driver = { .name = "hi556", .acpi_match_table = ACPI_PTR(hi556_acpi_ids), + .pm = pm_sleep_ptr(&hi556_pm_ops), }, .probe = hi556_probe, .remove = hi556_remove, diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 9c565ec033..52d9ca68a8 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1851,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd, mutex_lock(&hi846->mutex); switch (sel->which) { case V4L2_SUBDEV_FORMAT_TRY: - v4l2_subdev_state_get_crop(sd_state, sel->pad); + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); break; case V4L2_SUBDEV_FORMAT_ACTIVE: sel->r = hi846->cur_mode->crop; diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index b148b1bd2b..4962cfe7c8 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -968,7 +968,7 @@ static const struct v4l2_subdev_internal_ops imx214_internal_ops = { static const struct regmap_config sensor_regmap_config = { .reg_bits = 16, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int imx214_get_regulators(struct device *dev, struct imx214 *imx214) @@ -1114,6 +1114,7 @@ free_ctrl: v4l2_ctrl_handler_free(&imx214->ctrls); error_power_off: pm_runtime_disable(imx214->dev); + regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies); return ret; } diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index e17ef2e9d9..e78a80b2bb 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -162,8 +162,8 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */ /* To Access Addresses 3000-5fff, send the following commands */ - { CCI_REG8(0x30eb), 0x0c }, { CCI_REG8(0x30eb), 0x05 }, + { CCI_REG8(0x30eb), 0x0c }, { CCI_REG8(0x300a), 0xff }, { CCI_REG8(0x300b), 0xff }, { CCI_REG8(0x30eb), 0x05 }, @@ -551,8 +551,7 @@ static int imx219_init_controls(struct imx219 *imx219) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", - __func__, ret); + dev_err_probe(&client->dev, ret, "Control init failed\n"); goto error; } @@ -1024,17 +1023,15 @@ static int imx219_identify_module(struct imx219 *imx219) u64 val; ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); - if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", - IMX219_CHIP_ID); - return ret; - } + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to read chip id %x\n", + IMX219_CHIP_ID); - if (val != IMX219_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", - IMX219_CHIP_ID, val); - return -EIO; - } + if (val != IMX219_CHIP_ID) + return dev_err_probe(&client->dev, -EIO, + "chip id mismatch: %x!=%llx\n", + IMX219_CHIP_ID, val); return 0; } @@ -1048,35 +1045,36 @@ static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) int ret = -EINVAL; endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); - if (!endpoint) { - dev_err(dev, "endpoint node not found\n"); - return -EINVAL; - } + if (!endpoint) + return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { - dev_err(dev, "could not parse endpoint\n"); + dev_err_probe(dev, -EINVAL, "could not parse endpoint\n"); goto error_out; } /* Check the number of MIPI CSI2 data lanes */ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 && ep_cfg.bus.mipi_csi2.num_data_lanes != 4) { - dev_err(dev, "only 2 or 4 data lanes are currently supported\n"); + dev_err_probe(dev, -EINVAL, + "only 2 or 4 data lanes are currently supported\n"); goto error_out; } imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; /* Check the link frequency set in device tree */ if (!ep_cfg.nr_of_link_frequencies) { - dev_err(dev, "link-frequency property not found in DT\n"); + dev_err_probe(dev, -EINVAL, + "link-frequency property not found in DT\n"); goto error_out; } if (ep_cfg.nr_of_link_frequencies != 1 || (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ? IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) { - dev_err(dev, "Link frequency not supported: %lld\n", - ep_cfg.link_frequencies[0]); + dev_err_probe(dev, -EINVAL, + "Link frequency not supported: %lld\n", + ep_cfg.link_frequencies[0]); goto error_out; } @@ -1107,31 +1105,25 @@ static int imx219_probe(struct i2c_client *client) return -EINVAL; imx219->regmap = devm_cci_regmap_init_i2c(client, 16); - if (IS_ERR(imx219->regmap)) { - ret = PTR_ERR(imx219->regmap); - dev_err(dev, "failed to initialize CCI: %d\n", ret); - return ret; - } + if (IS_ERR(imx219->regmap)) + return dev_err_probe(dev, PTR_ERR(imx219->regmap), + "failed to initialize CCI\n"); /* Get system clock (xclk) */ imx219->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(imx219->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(imx219->xclk); - } + if (IS_ERR(imx219->xclk)) + return dev_err_probe(dev, PTR_ERR(imx219->xclk), + "failed to get xclk\n"); imx219->xclk_freq = clk_get_rate(imx219->xclk); - if (imx219->xclk_freq != IMX219_XCLK_FREQ) { - dev_err(dev, "xclk frequency not supported: %d Hz\n", - imx219->xclk_freq); - return -EINVAL; - } + if (imx219->xclk_freq != IMX219_XCLK_FREQ) + return dev_err_probe(dev, -EINVAL, + "xclk frequency not supported: %d Hz\n", + imx219->xclk_freq); ret = imx219_get_regulators(imx219); - if (ret) { - dev_err(dev, "failed to get regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); /* Request optional enable pin */ imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", @@ -1183,20 +1175,21 @@ static int imx219_probe(struct i2c_client *client) ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); if (ret) { - dev_err(dev, "failed to init entity pads: %d\n", ret); + dev_err_probe(dev, ret, "failed to init entity pads\n"); goto error_handler_free; } imx219->sd.state_lock = imx219->ctrl_handler.lock; ret = v4l2_subdev_init_finalize(&imx219->sd); if (ret < 0) { - dev_err(dev, "subdev init error: %d\n", ret); + dev_err_probe(dev, ret, "subdev init error\n"); goto error_media_entity; } ret = v4l2_async_register_subdev_sensor(&imx219->sd); if (ret < 0) { - dev_err(dev, "failed to register sensor sub-device: %d\n", ret); + dev_err_probe(dev, ret, + "failed to register sensor sub-device\n"); goto error_subdev_cleanup; } diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 352da68b8b..3800de974e 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -151,7 +151,7 @@ struct reg_8 { static const struct regmap_config imx274_regmap_config = { .reg_bits = 16, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index e47eff672e..8fe3933f31 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -70,7 +70,7 @@ #define IMX319_REG_ORIENTATION 0x0101 /* default link frequency and external clock */ -#define IMX319_LINK_FREQ_DEFAULT 482400000 +#define IMX319_LINK_FREQ_DEFAULT 482400000LL #define IMX319_EXT_CLK 19200000 #define IMX319_LINK_FREQ_INDEX 0 @@ -107,8 +107,7 @@ struct imx319_mode { struct imx319_hwcfg { u32 ext_clk; /* sensor external clk */ - s64 *link_freqs; /* CSI-2 link frequencies */ - unsigned int nr_of_link_freqs; + unsigned long link_freq_bitmap; }; struct imx319 { @@ -129,7 +128,6 @@ struct imx319 { const struct imx319_mode *cur_mode; struct imx319_hwcfg *hwcfg; - s64 link_def_freq; /* CSI-2 link default frequency */ /* * Mutex for serialized access: @@ -1654,7 +1652,10 @@ static const char * const imx319_test_pattern_menu[] = { "Pseudorandom Sequence (PN9)", }; -/* supported link frequencies */ +/* + * When adding more than the one below, make sure the disallowed ones will + * actually be disabled in the LINK_FREQ control. + */ static const s64 link_freq_menu_items[] = { IMX319_LINK_FREQ_DEFAULT, }; @@ -2058,7 +2059,7 @@ imx319_set_pad_format(struct v4l2_subdev *sd, *framefmt = fmt->format; } else { imx319->cur_mode = mode; - pixel_rate = imx319->link_def_freq * 2 * 4; + pixel_rate = IMX319_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); __v4l2_ctrl_s_ctrl_int64(imx319->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ @@ -2255,7 +2256,7 @@ static int imx319_init_controls(struct imx319 *imx319) imx319->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = imx319->link_def_freq * 2 * 4; + pixel_rate = IMX319_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); /* By default, PIXEL_RATE is read only */ imx319->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, @@ -2332,7 +2333,6 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); - unsigned int i; int ret; if (!fwnode) @@ -2364,24 +2364,14 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) goto out_err; } - dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); - if (!bus_cfg.nr_of_link_frequencies) { - dev_warn(dev, "no link frequencies defined"); - goto out_err; - } - - cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; - cfg->link_freqs = devm_kcalloc(dev, - bus_cfg.nr_of_link_frequencies + 1, - sizeof(*cfg->link_freqs), GFP_KERNEL); - if (!cfg->link_freqs) + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &cfg->link_freq_bitmap); + if (ret) goto out_err; - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); - } - v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); return cfg; @@ -2397,7 +2387,6 @@ static int imx319_probe(struct i2c_client *client) struct imx319 *imx319; bool full_power; int ret; - u32 i; imx319 = devm_kzalloc(&client->dev, sizeof(*imx319), GFP_KERNEL); if (!imx319) @@ -2425,20 +2414,6 @@ static int imx319_probe(struct i2c_client *client) goto error_probe; } - imx319->link_def_freq = link_freq_menu_items[IMX319_LINK_FREQ_INDEX]; - for (i = 0; i < imx319->hwcfg->nr_of_link_freqs; i++) { - if (imx319->hwcfg->link_freqs[i] == imx319->link_def_freq) { - dev_dbg(&client->dev, "link freq index %d matched", i); - break; - } - } - - if (i == imx319->hwcfg->nr_of_link_freqs) { - dev_err(&client->dev, "no link frequency supported"); - ret = -EINVAL; - goto error_probe; - } - /* Set default mode to max resolution */ imx319->cur_mode = &supported_modes[0]; diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 6725b3e2a7..40863d87d3 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -136,7 +136,7 @@ struct imx334_mode { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls - * @menu_skip_mask: Menu skip mask for link_freq_ctrl + * @link_freq_bitmap: Menu bitmap for link_freq_ctrl * @cur_code: current selected format code */ struct imx334 { @@ -158,7 +158,7 @@ struct imx334 { u32 vblank; const struct imx334_mode *cur_mode; struct mutex mutex; - unsigned long menu_skip_mask; + unsigned long link_freq_bitmap; u32 cur_code; }; @@ -954,9 +954,9 @@ static int imx334_init_state(struct v4l2_subdev *sd, imx334_fill_pad_format(imx334, imx334->cur_mode, &fmt); __v4l2_ctrl_modify_range(imx334->link_freq_ctrl, 0, - __fls(imx334->menu_skip_mask), - ~(imx334->menu_skip_mask), - __ffs(imx334->menu_skip_mask)); + __fls(imx334->link_freq_bitmap), + ~(imx334->link_freq_bitmap), + __ffs(imx334->link_freq_bitmap)); mutex_unlock(&imx334->mutex); @@ -1112,7 +1112,6 @@ static int imx334_parse_hw_config(struct imx334 *imx334) }; struct fwnode_handle *ep; unsigned long rate; - unsigned int i, j; int ret; if (!fwnode) @@ -1157,26 +1156,10 @@ static int imx334_parse_hw_config(struct imx334 *imx334) goto done_endpoint_free; } - if (!bus_cfg.nr_of_link_frequencies) { - dev_err(imx334->dev, "no link frequencies defined"); - ret = -EINVAL; - goto done_endpoint_free; - } - - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - for (j = 0; j < ARRAY_SIZE(link_freq); j++) { - if (bus_cfg.link_frequencies[i] == link_freq[j]) { - set_bit(j, &imx334->menu_skip_mask); - break; - } - } - - if (j == ARRAY_SIZE(link_freq)) { - ret = dev_err_probe(imx334->dev, -EINVAL, - "no supported link freq found\n"); - goto done_endpoint_free; - } - } + ret = v4l2_link_freq_to_bitmap(imx334->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq, ARRAY_SIZE(link_freq), + &imx334->link_freq_bitmap); done_endpoint_free: v4l2_fwnode_endpoint_free(&bus_cfg); @@ -1310,8 +1293,8 @@ static int imx334_init_controls(struct imx334 *imx334) imx334->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx334_ctrl_ops, V4L2_CID_LINK_FREQ, - __fls(imx334->menu_skip_mask), - __ffs(imx334->menu_skip_mask), + __fls(imx334->link_freq_bitmap), + __ffs(imx334->link_freq_bitmap), link_freq); if (imx334->link_freq_ctrl) @@ -1386,7 +1369,7 @@ static int imx334_probe(struct i2c_client *client) } /* Set default mode to max resolution */ - imx334->cur_mode = &supported_modes[__ffs(imx334->menu_skip_mask)]; + imx334->cur_mode = &supported_modes[__ffs(imx334->link_freq_bitmap)]; imx334->cur_code = imx334_mbus_codes[0]; imx334->vblank = imx334->cur_mode->vblank; diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 7a37eb327f..990d74214c 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -11,49 +11,114 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> /* Streaming Mode */ -#define IMX335_REG_MODE_SELECT 0x3000 -#define IMX335_MODE_STANDBY 0x01 -#define IMX335_MODE_STREAMING 0x00 +#define IMX335_REG_MODE_SELECT CCI_REG8(0x3000) +#define IMX335_MODE_STANDBY 0x01 +#define IMX335_MODE_STREAMING 0x00 + +/* Group hold register */ +#define IMX335_REG_HOLD CCI_REG8(0x3001) + +#define IMX335_REG_MASTER_MODE CCI_REG8(0x3002) +#define IMX335_REG_BCWAIT_TIME CCI_REG8(0x300c) +#define IMX335_REG_CPWAIT_TIME CCI_REG8(0x300d) +#define IMX335_REG_WINMODE CCI_REG8(0x3018) +#define IMX335_REG_HTRIMMING_START CCI_REG16_LE(0x302c) +#define IMX335_REG_HNUM CCI_REG8(0x302e) /* Lines per frame */ -#define IMX335_REG_LPFR 0x3030 +#define IMX335_REG_VMAX CCI_REG24_LE(0x3030) + +#define IMX335_REG_OPB_SIZE_V CCI_REG8(0x304c) +#define IMX335_REG_ADBIT CCI_REG8(0x3050) +#define IMX335_REG_Y_OUT_SIZE CCI_REG16_LE(0x3056) + +#define IMX335_REG_SHUTTER CCI_REG24_LE(0x3058) +#define IMX335_EXPOSURE_MIN 1 +#define IMX335_EXPOSURE_OFFSET 9 +#define IMX335_EXPOSURE_STEP 1 +#define IMX335_EXPOSURE_DEFAULT 0x0648 + +#define IMX335_REG_AREA3_ST_ADR_1 CCI_REG16_LE(0x3074) +#define IMX335_REG_AREA3_WIDTH_1 CCI_REG16_LE(0x3076) + +/* Analog and Digital gain control */ +#define IMX335_REG_GAIN CCI_REG8(0x30e8) +#define IMX335_AGAIN_MIN 0 +#define IMX335_AGAIN_MAX 100 +#define IMX335_AGAIN_STEP 1 +#define IMX335_AGAIN_DEFAULT 0 + +#define IMX335_REG_TPG_TESTCLKEN CCI_REG8(0x3148) + +#define IMX335_REG_INCLKSEL1 CCI_REG16_LE(0x314c) +#define IMX335_REG_INCLKSEL2 CCI_REG8(0x315a) +#define IMX335_REG_INCLKSEL3 CCI_REG8(0x3168) +#define IMX335_REG_INCLKSEL4 CCI_REG8(0x316a) + +#define IMX335_REG_MDBIT CCI_REG8(0x319d) +#define IMX335_REG_SYSMODE CCI_REG8(0x319e) + +#define IMX335_REG_XVS_XHS_DRV CCI_REG8(0x31a1) + +/* Test pattern generator */ +#define IMX335_REG_TPG_DIG_CLP_MODE CCI_REG8(0x3280) +#define IMX335_REG_TPG_EN_DUOUT CCI_REG8(0x329c) +#define IMX335_REG_TPG CCI_REG8(0x329e) +#define IMX335_TPG_ALL_000 0 +#define IMX335_TPG_ALL_FFF 1 +#define IMX335_TPG_ALL_555 2 +#define IMX335_TPG_ALL_AAA 3 +#define IMX335_TPG_TOG_555_AAA 4 +#define IMX335_TPG_TOG_AAA_555 5 +#define IMX335_TPG_TOG_000_555 6 +#define IMX335_TPG_TOG_555_000 7 +#define IMX335_TPG_TOG_000_FFF 8 +#define IMX335_TPG_TOG_FFF_000 9 +#define IMX335_TPG_H_COLOR_BARS 10 +#define IMX335_TPG_V_COLOR_BARS 11 +#define IMX335_REG_TPG_COLORWIDTH CCI_REG8(0x32a0) + +#define IMX335_REG_BLKLEVEL CCI_REG16_LE(0x3302) + +#define IMX335_REG_WRJ_OPEN CCI_REG8(0x336c) + +#define IMX335_REG_ADBIT1 CCI_REG16_LE(0x341c) /* Chip ID */ -#define IMX335_REG_ID 0x3912 -#define IMX335_ID 0x00 - -/* Exposure control */ -#define IMX335_REG_SHUTTER 0x3058 -#define IMX335_EXPOSURE_MIN 1 -#define IMX335_EXPOSURE_OFFSET 9 -#define IMX335_EXPOSURE_STEP 1 -#define IMX335_EXPOSURE_DEFAULT 0x0648 - -/* Analog gain control */ -#define IMX335_REG_AGAIN 0x30e8 -#define IMX335_AGAIN_MIN 0 -#define IMX335_AGAIN_MAX 240 -#define IMX335_AGAIN_STEP 1 -#define IMX335_AGAIN_DEFAULT 0 - -/* Group hold register */ -#define IMX335_REG_HOLD 0x3001 +#define IMX335_REG_ID CCI_REG8(0x3912) +#define IMX335_ID 0x00 + +/* Data Lanes */ +#define IMX335_REG_LANEMODE CCI_REG8(0x3a01) +#define IMX335_2LANE 1 +#define IMX335_4LANE 3 + +#define IMX335_REG_TCLKPOST CCI_REG16_LE(0x3a18) +#define IMX335_REG_TCLKPREPARE CCI_REG16_LE(0x3a1a) +#define IMX335_REG_TCLK_TRAIL CCI_REG16_LE(0x3a1c) +#define IMX335_REG_TCLK_ZERO CCI_REG16_LE(0x3a1e) +#define IMX335_REG_THS_PREPARE CCI_REG16_LE(0x3a20) +#define IMX335_REG_THS_ZERO CCI_REG16_LE(0x3a22) +#define IMX335_REG_THS_TRAIL CCI_REG16_LE(0x3a24) +#define IMX335_REG_THS_EXIT CCI_REG16_LE(0x3a26) +#define IMX335_REG_TPLX CCI_REG16_LE(0x3a28) /* Input clock rate */ -#define IMX335_INCLK_RATE 24000000 +#define IMX335_INCLK_RATE 24000000 /* CSI2 HW configuration */ -#define IMX335_LINK_FREQ 594000000 -#define IMX335_NUM_DATA_LANES 4 +#define IMX335_LINK_FREQ_594MHz 594000000LL +#define IMX335_LINK_FREQ_445MHz 445500000LL -#define IMX335_REG_MIN 0x00 -#define IMX335_REG_MAX 0xfffff +#define IMX335_NUM_DATA_LANES 4 /* IMX335 native and active pixel array size. */ #define IMX335_NATIVE_WIDTH 2616U @@ -64,23 +129,13 @@ #define IMX335_PIXEL_ARRAY_HEIGHT 1944U /** - * struct imx335_reg - imx335 sensor register - * @address: Register address - * @val: Register value - */ -struct imx335_reg { - u16 address; - u8 val; -}; - -/** * struct imx335_reg_list - imx335 sensor register list * @num_of_regs: Number of registers in the list * @regs: Pointer to register list */ struct imx335_reg_list { u32 num_of_regs; - const struct imx335_reg *regs; + const struct cci_reg_sequence *regs; }; static const char * const imx335_supply_name[] = { @@ -99,7 +154,6 @@ static const char * const imx335_supply_name[] = { * @vblank_min: Minimum vertical blanking in lines * @vblank_max: Maximum vertical blanking in lines * @pclk: Sensor pixel clock - * @link_freq_idx: Link frequency index * @reg_list: Register list for sensor mode */ struct imx335_mode { @@ -111,7 +165,6 @@ struct imx335_mode { u32 vblank_min; u32 vblank_max; u64 pclk; - u32 link_freq_idx; struct imx335_reg_list reg_list; }; @@ -123,6 +176,7 @@ struct imx335_mode { * @pad: Media pad. Only one pad supported * @reset_gpio: Sensor reset gpio * @supplies: Regulator supplies to handle power control + * @cci: CCI register map * @inclk: Sensor input clock * @ctrl_handler: V4L2 control handler * @link_freq_ctrl: Pointer to link frequency control @@ -132,8 +186,10 @@ struct imx335_mode { * @exp_ctrl: Pointer to exposure control * @again_ctrl: Pointer to analog gain control * @vblank: Vertical blanking in lines + * @lane_mode: Mode for number of connected data lanes * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls + * @link_freq_bitmap: Menu bitmap for link_freq_ctrl * @cur_mbus_code: Currently selected media bus format code */ struct imx335 { @@ -143,6 +199,7 @@ struct imx335 { struct media_pad pad; struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[ARRAY_SIZE(imx335_supply_name)]; + struct regmap *cci; struct clk *inclk; struct v4l2_ctrl_handler ctrl_handler; @@ -155,115 +212,193 @@ struct imx335 { struct v4l2_ctrl *again_ctrl; }; u32 vblank; + u32 lane_mode; const struct imx335_mode *cur_mode; struct mutex mutex; + unsigned long link_freq_bitmap; u32 cur_mbus_code; }; -static const s64 link_freq[] = { - IMX335_LINK_FREQ, +static const char * const imx335_tpg_menu[] = { + "Disabled", + "All 000h", + "All FFFh", + "All 555h", + "All AAAh", + "Toggle 555/AAAh", + "Toggle AAA/555h", + "Toggle 000/555h", + "Toggle 555/000h", + "Toggle 000/FFFh", + "Toggle FFF/000h", + "Horizontal color bars", + "Vertical color bars", +}; + +static const int imx335_tpg_val[] = { + IMX335_TPG_ALL_000, + IMX335_TPG_ALL_000, + IMX335_TPG_ALL_FFF, + IMX335_TPG_ALL_555, + IMX335_TPG_ALL_AAA, + IMX335_TPG_TOG_555_AAA, + IMX335_TPG_TOG_AAA_555, + IMX335_TPG_TOG_000_555, + IMX335_TPG_TOG_555_000, + IMX335_TPG_TOG_000_FFF, + IMX335_TPG_TOG_FFF_000, + IMX335_TPG_H_COLOR_BARS, + IMX335_TPG_V_COLOR_BARS, }; /* Sensor mode registers */ -static const struct imx335_reg mode_2592x1940_regs[] = { - {0x3000, 0x01}, - {0x3002, 0x00}, - {0x300c, 0x3b}, - {0x300d, 0x2a}, - {0x3018, 0x04}, - {0x302c, 0x3c}, - {0x302e, 0x20}, - {0x3056, 0x94}, - {0x3074, 0xc8}, - {0x3076, 0x28}, - {0x304c, 0x00}, - {0x314c, 0xc6}, - {0x315a, 0x02}, - {0x3168, 0xa0}, - {0x316a, 0x7e}, - {0x31a1, 0x00}, - {0x3288, 0x21}, - {0x328a, 0x02}, - {0x3414, 0x05}, - {0x3416, 0x18}, - {0x3648, 0x01}, - {0x364a, 0x04}, - {0x364c, 0x04}, - {0x3678, 0x01}, - {0x367c, 0x31}, - {0x367e, 0x31}, - {0x3706, 0x10}, - {0x3708, 0x03}, - {0x3714, 0x02}, - {0x3715, 0x02}, - {0x3716, 0x01}, - {0x3717, 0x03}, - {0x371c, 0x3d}, - {0x371d, 0x3f}, - {0x372c, 0x00}, - {0x372d, 0x00}, - {0x372e, 0x46}, - {0x372f, 0x00}, - {0x3730, 0x89}, - {0x3731, 0x00}, - {0x3732, 0x08}, - {0x3733, 0x01}, - {0x3734, 0xfe}, - {0x3735, 0x05}, - {0x3740, 0x02}, - {0x375d, 0x00}, - {0x375e, 0x00}, - {0x375f, 0x11}, - {0x3760, 0x01}, - {0x3768, 0x1b}, - {0x3769, 0x1b}, - {0x376a, 0x1b}, - {0x376b, 0x1b}, - {0x376c, 0x1a}, - {0x376d, 0x17}, - {0x376e, 0x0f}, - {0x3776, 0x00}, - {0x3777, 0x00}, - {0x3778, 0x46}, - {0x3779, 0x00}, - {0x377a, 0x89}, - {0x377b, 0x00}, - {0x377c, 0x08}, - {0x377d, 0x01}, - {0x377e, 0x23}, - {0x377f, 0x02}, - {0x3780, 0xd9}, - {0x3781, 0x03}, - {0x3782, 0xf5}, - {0x3783, 0x06}, - {0x3784, 0xa5}, - {0x3788, 0x0f}, - {0x378a, 0xd9}, - {0x378b, 0x03}, - {0x378c, 0xeb}, - {0x378d, 0x05}, - {0x378e, 0x87}, - {0x378f, 0x06}, - {0x3790, 0xf5}, - {0x3792, 0x43}, - {0x3794, 0x7a}, - {0x3796, 0xa1}, - {0x37b0, 0x36}, - {0x3a00, 0x01}, +static const struct cci_reg_sequence mode_2592x1940_regs[] = { + { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, + { IMX335_REG_MASTER_MODE, 0x00 }, + { IMX335_REG_WINMODE, 0x04 }, + { IMX335_REG_HTRIMMING_START, 48 }, + { IMX335_REG_HNUM, 2592 }, + { IMX335_REG_Y_OUT_SIZE, 1944 }, + { IMX335_REG_AREA3_ST_ADR_1, 176 }, + { IMX335_REG_AREA3_WIDTH_1, 3928 }, + { IMX335_REG_OPB_SIZE_V, 0 }, + { IMX335_REG_XVS_XHS_DRV, 0x00 }, + { CCI_REG8(0x3288), 0x21 }, + { CCI_REG8(0x328a), 0x02 }, + { CCI_REG8(0x3414), 0x05 }, + { CCI_REG8(0x3416), 0x18 }, + { CCI_REG8(0x3648), 0x01 }, + { CCI_REG8(0x364a), 0x04 }, + { CCI_REG8(0x364c), 0x04 }, + { CCI_REG8(0x3678), 0x01 }, + { CCI_REG8(0x367c), 0x31 }, + { CCI_REG8(0x367e), 0x31 }, + { CCI_REG8(0x3706), 0x10 }, + { CCI_REG8(0x3708), 0x03 }, + { CCI_REG8(0x3714), 0x02 }, + { CCI_REG8(0x3715), 0x02 }, + { CCI_REG8(0x3716), 0x01 }, + { CCI_REG8(0x3717), 0x03 }, + { CCI_REG8(0x371c), 0x3d }, + { CCI_REG8(0x371d), 0x3f }, + { CCI_REG8(0x372c), 0x00 }, + { CCI_REG8(0x372d), 0x00 }, + { CCI_REG8(0x372e), 0x46 }, + { CCI_REG8(0x372f), 0x00 }, + { CCI_REG8(0x3730), 0x89 }, + { CCI_REG8(0x3731), 0x00 }, + { CCI_REG8(0x3732), 0x08 }, + { CCI_REG8(0x3733), 0x01 }, + { CCI_REG8(0x3734), 0xfe }, + { CCI_REG8(0x3735), 0x05 }, + { CCI_REG8(0x3740), 0x02 }, + { CCI_REG8(0x375d), 0x00 }, + { CCI_REG8(0x375e), 0x00 }, + { CCI_REG8(0x375f), 0x11 }, + { CCI_REG8(0x3760), 0x01 }, + { CCI_REG8(0x3768), 0x1b }, + { CCI_REG8(0x3769), 0x1b }, + { CCI_REG8(0x376a), 0x1b }, + { CCI_REG8(0x376b), 0x1b }, + { CCI_REG8(0x376c), 0x1a }, + { CCI_REG8(0x376d), 0x17 }, + { CCI_REG8(0x376e), 0x0f }, + { CCI_REG8(0x3776), 0x00 }, + { CCI_REG8(0x3777), 0x00 }, + { CCI_REG8(0x3778), 0x46 }, + { CCI_REG8(0x3779), 0x00 }, + { CCI_REG8(0x377a), 0x89 }, + { CCI_REG8(0x377b), 0x00 }, + { CCI_REG8(0x377c), 0x08 }, + { CCI_REG8(0x377d), 0x01 }, + { CCI_REG8(0x377e), 0x23 }, + { CCI_REG8(0x377f), 0x02 }, + { CCI_REG8(0x3780), 0xd9 }, + { CCI_REG8(0x3781), 0x03 }, + { CCI_REG8(0x3782), 0xf5 }, + { CCI_REG8(0x3783), 0x06 }, + { CCI_REG8(0x3784), 0xa5 }, + { CCI_REG8(0x3788), 0x0f }, + { CCI_REG8(0x378a), 0xd9 }, + { CCI_REG8(0x378b), 0x03 }, + { CCI_REG8(0x378c), 0xeb }, + { CCI_REG8(0x378d), 0x05 }, + { CCI_REG8(0x378e), 0x87 }, + { CCI_REG8(0x378f), 0x06 }, + { CCI_REG8(0x3790), 0xf5 }, + { CCI_REG8(0x3792), 0x43 }, + { CCI_REG8(0x3794), 0x7a }, + { CCI_REG8(0x3796), 0xa1 }, + { CCI_REG8(0x37b0), 0x36 }, + { CCI_REG8(0x3a00), 0x00 }, +}; + +static const struct cci_reg_sequence raw10_framefmt_regs[] = { + { IMX335_REG_ADBIT, 0x00 }, + { IMX335_REG_MDBIT, 0x00 }, + { IMX335_REG_ADBIT1, 0x1ff }, +}; + +static const struct cci_reg_sequence raw12_framefmt_regs[] = { + { IMX335_REG_ADBIT, 0x01 }, + { IMX335_REG_MDBIT, 0x01 }, + { IMX335_REG_ADBIT1, 0x47 }, +}; + +static const struct cci_reg_sequence mipi_data_rate_1188Mbps[] = { + { IMX335_REG_BCWAIT_TIME, 0x3b }, + { IMX335_REG_CPWAIT_TIME, 0x2a }, + { IMX335_REG_INCLKSEL1, 0x00c6 }, + { IMX335_REG_INCLKSEL2, 0x02 }, + { IMX335_REG_INCLKSEL3, 0xa0 }, + { IMX335_REG_INCLKSEL4, 0x7e }, + { IMX335_REG_SYSMODE, 0x01 }, + { IMX335_REG_TCLKPOST, 0x8f }, + { IMX335_REG_TCLKPREPARE, 0x4f }, + { IMX335_REG_TCLK_TRAIL, 0x47 }, + { IMX335_REG_TCLK_ZERO, 0x0137 }, + { IMX335_REG_THS_PREPARE, 0x4f }, + { IMX335_REG_THS_ZERO, 0x87 }, + { IMX335_REG_THS_TRAIL, 0x4f }, + { IMX335_REG_THS_EXIT, 0x7f }, + { IMX335_REG_TPLX, 0x3f }, }; -static const struct imx335_reg raw10_framefmt_regs[] = { - {0x3050, 0x00}, - {0x319d, 0x00}, - {0x341c, 0xff}, - {0x341d, 0x01}, +static const struct cci_reg_sequence mipi_data_rate_891Mbps[] = { + { IMX335_REG_BCWAIT_TIME, 0x3b }, + { IMX335_REG_CPWAIT_TIME, 0x2a }, + { IMX335_REG_INCLKSEL1, 0x0129 }, + { IMX335_REG_INCLKSEL2, 0x06 }, + { IMX335_REG_INCLKSEL3, 0xa0 }, + { IMX335_REG_INCLKSEL4, 0x7e }, + { IMX335_REG_SYSMODE, 0x02 }, + { IMX335_REG_TCLKPOST, 0x7f }, + { IMX335_REG_TCLKPREPARE, 0x37 }, + { IMX335_REG_TCLK_TRAIL, 0x37 }, + { IMX335_REG_TCLK_ZERO, 0xf7 }, + { IMX335_REG_THS_PREPARE, 0x3f }, + { IMX335_REG_THS_ZERO, 0x6f }, + { IMX335_REG_THS_TRAIL, 0x3f }, + { IMX335_REG_THS_EXIT, 0x5f }, + { IMX335_REG_TPLX, 0x2f }, }; -static const struct imx335_reg raw12_framefmt_regs[] = { - {0x3050, 0x01}, - {0x319d, 0x01}, - {0x341c, 0x47}, - {0x341d, 0x00}, +static const s64 link_freq[] = { + /* Corresponds to 1188Mbps data lane rate */ + IMX335_LINK_FREQ_594MHz, + /* Corresponds to 891Mbps data lane rate */ + IMX335_LINK_FREQ_445MHz, +}; + +static const struct imx335_reg_list link_freq_reglist[] = { + { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_1188Mbps), + .regs = mipi_data_rate_1188Mbps, + }, + { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_891Mbps), + .regs = mipi_data_rate_891Mbps, + }, }; static const u32 imx335_mbus_codes[] = { @@ -274,13 +409,12 @@ static const u32 imx335_mbus_codes[] = { /* Supported sensor mode configurations */ static const struct imx335_mode supported_mode = { .width = 2592, - .height = 1940, + .height = 1944, .hblank = 342, - .vblank = 2560, - .vblank_min = 2560, + .vblank = 2556, + .vblank_min = 2556, .vblank_max = 133060, .pclk = 396000000, - .link_freq_idx = 0, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), .regs = mode_2592x1940_regs, @@ -299,101 +433,6 @@ static inline struct imx335 *to_imx335(struct v4l2_subdev *subdev) } /** - * imx335_read_reg() - Read registers. - * @imx335: pointer to imx335 device - * @reg: register address - * @len: length of bytes to read. Max supported bytes is 4 - * @val: pointer to register value to be filled. - * - * Big endian register addresses with little endian values. - * - * Return: 0 if successful, error code otherwise. - */ -static int imx335_read_reg(struct imx335 *imx335, u16 reg, u32 len, u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); - struct i2c_msg msgs[2] = {0}; - u8 addr_buf[2] = {0}; - u8 data_buf[4] = {0}; - int ret; - - if (WARN_ON(len > 4)) - return -EINVAL; - - put_unaligned_be16(reg, addr_buf); - - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = data_buf; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *val = get_unaligned_le32(data_buf); - - return 0; -} - -/** - * imx335_write_reg() - Write register - * @imx335: pointer to imx335 device - * @reg: register address - * @len: length of bytes. Max supported bytes is 4 - * @val: register value - * - * Big endian register addresses with little endian values. - * - * Return: 0 if successful, error code otherwise. - */ -static int imx335_write_reg(struct imx335 *imx335, u16 reg, u32 len, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); - u8 buf[6] = {0}; - - if (WARN_ON(len > 4)) - return -EINVAL; - - put_unaligned_be16(reg, buf); - put_unaligned_le32(val, buf + 2); - if (i2c_master_send(client, buf, len + 2) != len + 2) - return -EIO; - - return 0; -} - -/** - * imx335_write_regs() - Write a list of registers - * @imx335: pointer to imx335 device - * @regs: list of registers to be written - * @len: length of registers array - * - * Return: 0 if successful. error code otherwise. - */ -static int imx335_write_regs(struct imx335 *imx335, - const struct imx335_reg *regs, u32 len) -{ - unsigned int i; - int ret; - - for (i = 0; i < len; i++) { - ret = imx335_write_reg(imx335, regs[i].address, 1, regs[i].val); - if (ret) - return ret; - } - - return 0; -} - -/** * imx335_update_controls() - Update control ranges based on streaming mode * @imx335: pointer to imx335 device * @mode: pointer to imx335_mode sensor mode @@ -405,7 +444,8 @@ static int imx335_update_controls(struct imx335 *imx335, { int ret; - ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, mode->link_freq_idx); + ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, + __ffs(imx335->link_freq_bitmap)); if (ret) return ret; @@ -428,7 +468,8 @@ static int imx335_update_controls(struct imx335 *imx335, static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) { u32 lpfr, shutter; - int ret; + int ret_hold; + int ret = 0; lpfr = imx335->vblank + imx335->cur_mode->height; shutter = lpfr - exposure; @@ -436,22 +477,56 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u\n", exposure, gain, shutter, lpfr); - ret = imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 1); - if (ret) - return ret; + cci_write(imx335->cci, IMX335_REG_HOLD, 1, &ret); + cci_write(imx335->cci, IMX335_REG_VMAX, lpfr, &ret); + cci_write(imx335->cci, IMX335_REG_SHUTTER, shutter, &ret); + cci_write(imx335->cci, IMX335_REG_GAIN, gain, &ret); + /* + * Unconditionally attempt to release the hold, but track the + * error if the unhold itself fails. + */ + ret_hold = cci_write(imx335->cci, IMX335_REG_HOLD, 0, NULL); + if (ret_hold) + ret = ret_hold; - ret = imx335_write_reg(imx335, IMX335_REG_LPFR, 3, lpfr); - if (ret) - goto error_release_group_hold; + return ret; +} - ret = imx335_write_reg(imx335, IMX335_REG_SHUTTER, 3, shutter); - if (ret) - goto error_release_group_hold; +static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index) +{ + int ret = 0; - ret = imx335_write_reg(imx335, IMX335_REG_AGAIN, 2, gain); + if (pattern_index >= ARRAY_SIZE(imx335_tpg_val)) + return -EINVAL; -error_release_group_hold: - imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 0); + if (pattern_index) { + const struct cci_reg_sequence tpg_enable_regs[] = { + { IMX335_REG_TPG_TESTCLKEN, 0x10 }, + { IMX335_REG_TPG_DIG_CLP_MODE, 0x00 }, + { IMX335_REG_TPG_EN_DUOUT, 0x01 }, + { IMX335_REG_TPG_COLORWIDTH, 0x11 }, + { IMX335_REG_BLKLEVEL, 0x00 }, + { IMX335_REG_WRJ_OPEN, 0x00 }, + }; + + cci_write(imx335->cci, IMX335_REG_TPG, + imx335_tpg_val[pattern_index], &ret); + + cci_multi_reg_write(imx335->cci, tpg_enable_regs, + ARRAY_SIZE(tpg_enable_regs), &ret); + } else { + const struct cci_reg_sequence tpg_disable_regs[] = { + { IMX335_REG_TPG_TESTCLKEN, 0x00 }, + { IMX335_REG_TPG_DIG_CLP_MODE, 0x01 }, + { IMX335_REG_TPG_EN_DUOUT, 0x00 }, + { IMX335_REG_TPG_COLORWIDTH, 0x10 }, + { IMX335_REG_BLKLEVEL, 0x32 }, + { IMX335_REG_WRJ_OPEN, 0x01 }, + }; + + cci_multi_reg_write(imx335->cci, tpg_disable_regs, + ARRAY_SIZE(tpg_disable_regs), &ret); + } return ret; } @@ -476,26 +551,31 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) u32 exposure; int ret; - switch (ctrl->id) { - case V4L2_CID_VBLANK: + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { imx335->vblank = imx335->vblank_ctrl->val; dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n", imx335->vblank, imx335->vblank + imx335->cur_mode->height); - ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl, - IMX335_EXPOSURE_MIN, - imx335->vblank + - imx335->cur_mode->height - - IMX335_EXPOSURE_OFFSET, - 1, IMX335_EXPOSURE_DEFAULT); - break; - case V4L2_CID_EXPOSURE: - /* Set controls only if sensor is in power on state */ - if (!pm_runtime_get_if_in_use(imx335->dev)) - return 0; + return __v4l2_ctrl_modify_range(imx335->exp_ctrl, + IMX335_EXPOSURE_MIN, + imx335->vblank + + imx335->cur_mode->height - + IMX335_EXPOSURE_OFFSET, + 1, IMX335_EXPOSURE_DEFAULT); + } + /* + * Applying V4L2 control value only happens + * when power is up for streaming. + */ + if (pm_runtime_get_if_in_use(imx335->dev) == 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: exposure = ctrl->val; analog_gain = imx335->again_ctrl->val; @@ -504,7 +584,9 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) ret = imx335_update_exp_gain(imx335, exposure, analog_gain); - pm_runtime_put(imx335->dev); + break; + case V4L2_CID_TEST_PATTERN: + ret = imx335_update_test_pattern(imx335, ctrl->val); break; default: @@ -512,6 +594,8 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) ret = -EINVAL; } + pm_runtime_put(imx335->dev); + return ret; } @@ -691,6 +775,13 @@ static int imx335_init_state(struct v4l2_subdev *sd, fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; imx335_fill_pad_format(imx335, &supported_mode, &fmt); + mutex_lock(&imx335->mutex); + __v4l2_ctrl_modify_range(imx335->link_freq_ctrl, 0, + __fls(imx335->link_freq_bitmap), + ~(imx335->link_freq_bitmap), + __ffs(imx335->link_freq_bitmap)); + mutex_unlock(&imx335->mutex); + return imx335_set_pad_format(sd, sd_state, &fmt); } @@ -733,12 +824,14 @@ static int imx335_set_framefmt(struct imx335 *imx335) { switch (imx335->cur_mbus_code) { case MEDIA_BUS_FMT_SRGGB10_1X10: - return imx335_write_regs(imx335, raw10_framefmt_regs, - ARRAY_SIZE(raw10_framefmt_regs)); + return cci_multi_reg_write(imx335->cci, raw10_framefmt_regs, + ARRAY_SIZE(raw10_framefmt_regs), + NULL); case MEDIA_BUS_FMT_SRGGB12_1X12: - return imx335_write_regs(imx335, raw12_framefmt_regs, - ARRAY_SIZE(raw12_framefmt_regs)); + return cci_multi_reg_write(imx335->cci, raw12_framefmt_regs, + ARRAY_SIZE(raw12_framefmt_regs), + NULL); } return -EINVAL; @@ -755,10 +848,19 @@ static int imx335_start_streaming(struct imx335 *imx335) const struct imx335_reg_list *reg_list; int ret; + /* Setup PLL */ + reg_list = &link_freq_reglist[__ffs(imx335->link_freq_bitmap)]; + ret = cci_multi_reg_write(imx335->cci, reg_list->regs, + reg_list->num_of_regs, NULL); + if (ret) { + dev_err(imx335->dev, "%s failed to set plls\n", __func__); + return ret; + } + /* Write sensor mode registers */ reg_list = &imx335->cur_mode->reg_list; - ret = imx335_write_regs(imx335, reg_list->regs, - reg_list->num_of_regs); + ret = cci_multi_reg_write(imx335->cci, reg_list->regs, + reg_list->num_of_regs, NULL); if (ret) { dev_err(imx335->dev, "fail to write initial registers\n"); return ret; @@ -771,6 +873,12 @@ static int imx335_start_streaming(struct imx335 *imx335) return ret; } + /* Configure lanes */ + ret = cci_write(imx335->cci, IMX335_REG_LANEMODE, + imx335->lane_mode, NULL); + if (ret) + return ret; + /* Setup handler will write actual exposure and gain */ ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler); if (ret) { @@ -779,8 +887,8 @@ static int imx335_start_streaming(struct imx335 *imx335) } /* Start streaming */ - ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, - 1, IMX335_MODE_STREAMING); + ret = cci_write(imx335->cci, IMX335_REG_MODE_SELECT, + IMX335_MODE_STREAMING, NULL); if (ret) { dev_err(imx335->dev, "fail to start streaming\n"); return ret; @@ -800,8 +908,8 @@ static int imx335_start_streaming(struct imx335 *imx335) */ static int imx335_stop_streaming(struct imx335 *imx335) { - return imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, - 1, IMX335_MODE_STANDBY); + return cci_write(imx335->cci, IMX335_REG_MODE_SELECT, + IMX335_MODE_STANDBY, NULL); } /** @@ -852,14 +960,14 @@ error_unlock: static int imx335_detect(struct imx335 *imx335) { int ret; - u32 val; + u64 val; - ret = imx335_read_reg(imx335, IMX335_REG_ID, 2, &val); + ret = cci_read(imx335->cci, IMX335_REG_ID, &val, NULL); if (ret) return ret; if (val != IMX335_ID) { - dev_err(imx335->dev, "chip id mismatch: %x!=%x\n", + dev_err(imx335->dev, "chip id mismatch: %x!=%llx\n", IMX335_ID, val); return -ENXIO; } @@ -931,7 +1039,14 @@ static int imx335_parse_hw_config(struct imx335 *imx335) if (ret) return ret; - if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) { + switch (bus_cfg.bus.mipi_csi2.num_data_lanes) { + case 2: + imx335->lane_mode = IMX335_2LANE; + break; + case 4: + imx335->lane_mode = IMX335_4LANE; + break; + default: dev_err(imx335->dev, "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -939,19 +1054,10 @@ static int imx335_parse_hw_config(struct imx335 *imx335) goto done_endpoint_free; } - if (!bus_cfg.nr_of_link_frequencies) { - dev_err(imx335->dev, "no link frequencies defined\n"); - ret = -EINVAL; - goto done_endpoint_free; - } - - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) - if (bus_cfg.link_frequencies[i] == IMX335_LINK_FREQ) - goto done_endpoint_free; - - dev_err(imx335->dev, "no compatible link frequencies found\n"); - - ret = -EINVAL; + ret = v4l2_link_freq_to_bitmap(imx335->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq, ARRAY_SIZE(link_freq), + &imx335->link_freq_bitmap); done_endpoint_free: v4l2_fwnode_endpoint_free(&bus_cfg); @@ -1052,10 +1158,16 @@ static int imx335_init_controls(struct imx335 *imx335) { struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler; const struct imx335_mode *mode = imx335->cur_mode; + struct v4l2_fwnode_device_properties props; u32 lpfr; int ret; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + ret = v4l2_fwnode_device_parse(imx335->dev, &props); + if (ret) + return ret; + + /* v4l2_fwnode_device_properties can add two more controls */ + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); if (ret) return ret; @@ -1072,6 +1184,14 @@ static int imx335_init_controls(struct imx335 *imx335) IMX335_EXPOSURE_STEP, IMX335_EXPOSURE_DEFAULT); + /* + * The sensor has an analog gain and a digital gain, both controlled + * through a single gain value, expressed in 0.3dB increments. Values + * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values + * up to 72.0dB (240) add further digital gain. Limit the range to + * analog gain only, support for digital gain can be added separately + * if needed. + */ imx335->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, @@ -1089,6 +1209,12 @@ static int imx335_init_controls(struct imx335 *imx335) mode->vblank_max, 1, mode->vblank); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx335_tpg_menu) - 1, + 0, 0, imx335_tpg_menu); + /* Read only controls */ imx335->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, @@ -1099,9 +1225,8 @@ static int imx335_init_controls(struct imx335 *imx335) imx335->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_LINK_FREQ, - ARRAY_SIZE(link_freq) - - 1, - mode->link_freq_idx, + __fls(imx335->link_freq_bitmap), + __ffs(imx335->link_freq_bitmap), link_freq); if (imx335->link_freq_ctrl) imx335->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -1115,6 +1240,8 @@ static int imx335_init_controls(struct imx335 *imx335) if (imx335->hblank_ctrl) imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx335_ctrl_ops, &props); + if (ctrl_hdlr->error) { dev_err(imx335->dev, "control init failed: %d\n", ctrl_hdlr->error); @@ -1143,6 +1270,11 @@ static int imx335_probe(struct i2c_client *client) return -ENOMEM; imx335->dev = &client->dev; + imx335->cci = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx335->cci)) { + dev_err(imx335->dev, "Unable to initialize I2C\n"); + return -ENODEV; + } /* Initialize subdev */ v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops); diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 8c995c5874..7e9c2f65fa 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -56,7 +56,7 @@ #define IMX355_REG_ORIENTATION 0x0101 /* default link frequency and external clock */ -#define IMX355_LINK_FREQ_DEFAULT 360000000 +#define IMX355_LINK_FREQ_DEFAULT 360000000LL #define IMX355_EXT_CLK 19200000 #define IMX355_LINK_FREQ_INDEX 0 @@ -93,8 +93,7 @@ struct imx355_mode { struct imx355_hwcfg { u32 ext_clk; /* sensor external clk */ - s64 *link_freqs; /* CSI-2 link frequencies */ - unsigned int nr_of_link_freqs; + unsigned long link_freq_bitmap; }; struct imx355 { @@ -115,7 +114,6 @@ struct imx355 { const struct imx355_mode *cur_mode; struct imx355_hwcfg *hwcfg; - s64 link_def_freq; /* CSI-2 link default frequency */ /* * Mutex for serialized access: @@ -879,7 +877,10 @@ static const char * const imx355_test_pattern_menu[] = { "Pseudorandom Sequence (PN9)", }; -/* supported link frequencies */ +/* + * When adding more than the one below, make sure the disallowed ones will + * actually be disabled in the LINK_FREQ control. + */ static const s64 link_freq_menu_items[] = { IMX355_LINK_FREQ_DEFAULT, }; @@ -1356,7 +1357,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd, *framefmt = fmt->format; } else { imx355->cur_mode = mode; - pixel_rate = imx355->link_def_freq * 2 * 4; + pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ @@ -1543,7 +1544,7 @@ static int imx355_init_controls(struct imx355 *imx355) imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = imx355->link_def_freq * 2 * 4; + pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); /* By default, PIXEL_RATE is read only */ imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, @@ -1620,7 +1621,6 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); - unsigned int i; int ret; if (!fwnode) @@ -1652,24 +1652,14 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) goto out_err; } - dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); - if (!bus_cfg.nr_of_link_frequencies) { - dev_warn(dev, "no link frequencies defined"); - goto out_err; - } - - cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; - cfg->link_freqs = devm_kcalloc(dev, - bus_cfg.nr_of_link_frequencies + 1, - sizeof(*cfg->link_freqs), GFP_KERNEL); - if (!cfg->link_freqs) + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &cfg->link_freq_bitmap); + if (ret) goto out_err; - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); - } - v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); return cfg; @@ -1684,7 +1674,6 @@ static int imx355_probe(struct i2c_client *client) { struct imx355 *imx355; int ret; - u32 i; imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); if (!imx355) @@ -1709,20 +1698,6 @@ static int imx355_probe(struct i2c_client *client) goto error_probe; } - imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX]; - for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) { - if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) { - dev_dbg(&client->dev, "link freq index %d matched", i); - break; - } - } - - if (i == imx355->hwcfg->nr_of_link_freqs) { - dev_err(&client->dev, "no link frequency supported"); - ret = -EINVAL; - goto error_probe; - } - /* Set default mode to max resolution */ imx355->cur_mode = &supported_modes[0]; diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 0efce32952..7d1f7af0a9 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -542,14 +542,13 @@ static int imx412_update_controls(struct imx412 *imx412, */ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) { - u32 lpfr, shutter; + u32 lpfr; int ret; lpfr = imx412->vblank + imx412->cur_mode->height; - shutter = lpfr - exposure; - dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", - exposure, gain, shutter, lpfr); + dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u", + exposure, gain, lpfr); ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); if (ret) @@ -559,7 +558,7 @@ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) if (ret) goto error_release_group_hold; - ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter); + ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure); if (ret) goto error_release_group_hold; diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 1e5f20c3ed..a20b0db330 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> @@ -28,76 +29,65 @@ #define IMX415_NUM_CLK_PARAM_REGS 11 -#define IMX415_REG_8BIT(n) ((1 << 16) | (n)) -#define IMX415_REG_16BIT(n) ((2 << 16) | (n)) -#define IMX415_REG_24BIT(n) ((3 << 16) | (n)) -#define IMX415_REG_SIZE_SHIFT 16 -#define IMX415_REG_ADDR_MASK 0xffff - -#define IMX415_MODE IMX415_REG_8BIT(0x3000) +#define IMX415_MODE CCI_REG8(0x3000) #define IMX415_MODE_OPERATING (0) #define IMX415_MODE_STANDBY BIT(0) -#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001) +#define IMX415_REGHOLD CCI_REG8(0x3001) #define IMX415_REGHOLD_INVALID (0) #define IMX415_REGHOLD_VALID BIT(0) -#define IMX415_XMSTA IMX415_REG_8BIT(0x3002) +#define IMX415_XMSTA CCI_REG8(0x3002) #define IMX415_XMSTA_START (0) #define IMX415_XMSTA_STOP BIT(0) -#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008) -#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A) -#define IMX415_WINMODE IMX415_REG_8BIT(0x301C) -#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022) -#define IMX415_REVERSE IMX415_REG_8BIT(0x3030) +#define IMX415_BCWAIT_TIME CCI_REG16_LE(0x3008) +#define IMX415_CPWAIT_TIME CCI_REG16_LE(0x300a) +#define IMX415_WINMODE CCI_REG8(0x301c) +#define IMX415_ADDMODE CCI_REG8(0x3022) +#define IMX415_REVERSE CCI_REG8(0x3030) #define IMX415_HREVERSE_SHIFT (0) #define IMX415_VREVERSE_SHIFT BIT(0) -#define IMX415_ADBIT IMX415_REG_8BIT(0x3031) -#define IMX415_MDBIT IMX415_REG_8BIT(0x3032) -#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033) -#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0) -#define IMX415_DRV IMX415_REG_8BIT(0x30C1) -#define IMX415_VMAX IMX415_REG_24BIT(0x3024) -#define IMX415_HMAX IMX415_REG_16BIT(0x3028) -#define IMX415_SHR0 IMX415_REG_24BIT(0x3050) -#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) +#define IMX415_ADBIT CCI_REG8(0x3031) +#define IMX415_MDBIT CCI_REG8(0x3032) +#define IMX415_SYS_MODE CCI_REG8(0x3033) +#define IMX415_OUTSEL CCI_REG8(0x30c0) +#define IMX415_DRV CCI_REG8(0x30c1) +#define IMX415_VMAX CCI_REG24_LE(0x3024) +#define IMX415_HMAX CCI_REG16_LE(0x3028) +#define IMX415_SHR0 CCI_REG24_LE(0x3050) +#define IMX415_GAIN_PCG_0 CCI_REG16_LE(0x3090) #define IMX415_AGAIN_MIN 0 #define IMX415_AGAIN_MAX 100 #define IMX415_AGAIN_STEP 1 -#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2) +#define IMX415_BLKLEVEL CCI_REG16_LE(0x30e2) #define IMX415_BLKLEVEL_DEFAULT 50 -#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4) -#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6) -#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8) -#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110) -#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115) -#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116) -#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118) -#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A) -#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E) -#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8) -#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390) -#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12) -#define IMX415_SENSOR_INFO_MASK 0xFFF +#define IMX415_TPG_EN_DUOUT CCI_REG8(0x30e4) +#define IMX415_TPG_PATSEL_DUOUT CCI_REG8(0x30e6) +#define IMX415_TPG_COLORWIDTH CCI_REG8(0x30e8) +#define IMX415_TESTCLKEN_MIPI CCI_REG8(0x3110) +#define IMX415_INCKSEL1 CCI_REG8(0x3115) +#define IMX415_INCKSEL2 CCI_REG8(0x3116) +#define IMX415_INCKSEL3 CCI_REG16_LE(0x3118) +#define IMX415_INCKSEL4 CCI_REG16_LE(0x311a) +#define IMX415_INCKSEL5 CCI_REG8(0x311e) +#define IMX415_DIG_CLP_MODE CCI_REG8(0x32c8) +#define IMX415_WRJ_OPEN CCI_REG8(0x3390) +#define IMX415_SENSOR_INFO CCI_REG16_LE(0x3f12) +#define IMX415_SENSOR_INFO_MASK 0xfff #define IMX415_CHIP_ID 0x514 -#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001) +#define IMX415_LANEMODE CCI_REG16_LE(0x4001) #define IMX415_LANEMODE_2 1 #define IMX415_LANEMODE_4 3 -#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004) -#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C) -#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018) -#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A) -#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C) -#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E) -#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020) -#define IMX415_THSZERO IMX415_REG_16BIT(0x4022) -#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024) -#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026) -#define IMX415_TLPX IMX415_REG_16BIT(0x4028) -#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074) - -struct imx415_reg { - u32 address; - u32 val; -}; +#define IMX415_TXCLKESC_FREQ CCI_REG16_LE(0x4004) +#define IMX415_INCKSEL6 CCI_REG8(0x400c) +#define IMX415_TCLKPOST CCI_REG16_LE(0x4018) +#define IMX415_TCLKPREPARE CCI_REG16_LE(0x401a) +#define IMX415_TCLKTRAIL CCI_REG16_LE(0x401c) +#define IMX415_TCLKZERO CCI_REG16_LE(0x401e) +#define IMX415_THSPREPARE CCI_REG16_LE(0x4020) +#define IMX415_THSZERO CCI_REG16_LE(0x4022) +#define IMX415_THSTRAIL CCI_REG16_LE(0x4024) +#define IMX415_THSEXIT CCI_REG16_LE(0x4026) +#define IMX415_TLPX CCI_REG16_LE(0x4028) +#define IMX415_INCKSEL7 CCI_REG8(0x4074) static const char *const imx415_supply_names[] = { "dvdd", @@ -118,13 +108,13 @@ static const s64 link_freq_menu_items[] = { struct imx415_clk_params { u64 lane_rate; u64 inck; - struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS]; + struct cci_reg_sequence regs[IMX415_NUM_CLK_PARAM_REGS]; }; /* INCK Settings - includes all lane rate and INCK dependent registers */ static const struct imx415_clk_params imx415_clk_params[] = { { - .lane_rate = 594000000, + .lane_rate = 594000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -139,7 +129,37 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, { - .lane_rate = 720000000, + .lane_rate = 594000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x080 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0984 }, + }, + { + .lane_rate = 594000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x080 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 720000000UL, .inck = 24000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, @@ -154,7 +174,22 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, }, { - .lane_rate = 891000000, + .lane_rate = 720000000UL, + .inck = 72000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, + .regs[2] = { IMX415_SYS_MODE, 0x9 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, + }, + { + .lane_rate = 891000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -169,7 +204,37 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, { - .lane_rate = 1440000000, + .lane_rate = 891000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 891000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 1440000000UL, .inck = 24000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, @@ -184,7 +249,22 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, }, { - .lane_rate = 1485000000, + .lane_rate = 1440000000UL, + .inck = 72000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 }, + }, + { + .lane_rate = 1485000000UL, .inck = 27000000, .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, @@ -198,10 +278,175 @@ static const struct imx415_clk_params imx415_clk_params[] = { .regs[9] = { IMX415_INCKSEL7, 0x0 }, .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, }, + { + .lane_rate = 1485000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 1485000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C6 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 1782000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x4 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E7 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 2079000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x2 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x0E0 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x108 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 37125000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x07F }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x05B }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x24 }, + .regs[5] = { IMX415_INCKSEL3, 0x100 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x24 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 }, + }, + { + .lane_rate = 2376000000UL, + .inck = 74250000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 }, + .regs[2] = { IMX415_SYS_MODE, 0x0 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x28 }, + .regs[5] = { IMX415_INCKSEL3, 0x100 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E0 }, + .regs[7] = { IMX415_INCKSEL5, 0x28 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 }, + }, }; /* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ -static const struct imx415_reg imx415_mode_2_720[] = { +static const struct cci_reg_sequence imx415_mode_2_720[] = { { IMX415_VMAX, 0x08CA }, { IMX415_HMAX, 0x07F0 }, { IMX415_LANEMODE, IMX415_LANEMODE_2 }, @@ -217,7 +462,7 @@ static const struct imx415_reg imx415_mode_2_720[] = { }; /* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ -static const struct imx415_reg imx415_mode_2_1440[] = { +static const struct cci_reg_sequence imx415_mode_2_1440[] = { { IMX415_VMAX, 0x08CA }, { IMX415_HMAX, 0x042A }, { IMX415_LANEMODE, IMX415_LANEMODE_2 }, @@ -233,7 +478,7 @@ static const struct imx415_reg imx415_mode_2_1440[] = { }; /* all-pixel 4-lane 891 Mbps 30 Hz mode */ -static const struct imx415_reg imx415_mode_4_891[] = { +static const struct cci_reg_sequence imx415_mode_4_891[] = { { IMX415_VMAX, 0x08CA }, { IMX415_HMAX, 0x044C }, { IMX415_LANEMODE, IMX415_LANEMODE_4 }, @@ -250,7 +495,7 @@ static const struct imx415_reg imx415_mode_4_891[] = { struct imx415_mode_reg_list { u32 num_of_regs; - const struct imx415_reg *regs; + const struct cci_reg_sequence *regs; }; /* @@ -323,11 +568,6 @@ static const struct imx415_mode supported_modes[] = { }, }; -static const struct regmap_config imx415_regmap_config = { - .reg_bits = 16, - .val_bits = 8, -}; - static const char *const imx415_test_pattern_menu[] = { "disabled", "solid black", @@ -369,7 +609,7 @@ struct imx415 { * This table includes fixed register settings and a bunch of undocumented * registers that have to be set to another value than default. */ -static const struct imx415_reg imx415_init_table[] = { +static const struct cci_reg_sequence imx415_init_table[] = { /* use all-pixel readout mode, no flip */ { IMX415_WINMODE, 0x00 }, { IMX415_ADDMODE, 0x00 }, @@ -382,77 +622,77 @@ static const struct imx415_reg imx415_init_table[] = { { IMX415_DRV, 0x00 }, /* SONY magic registers */ - { IMX415_REG_8BIT(0x32D4), 0x21 }, - { IMX415_REG_8BIT(0x32EC), 0xA1 }, - { IMX415_REG_8BIT(0x3452), 0x7F }, - { IMX415_REG_8BIT(0x3453), 0x03 }, - { IMX415_REG_8BIT(0x358A), 0x04 }, - { IMX415_REG_8BIT(0x35A1), 0x02 }, - { IMX415_REG_8BIT(0x36BC), 0x0C }, - { IMX415_REG_8BIT(0x36CC), 0x53 }, - { IMX415_REG_8BIT(0x36CD), 0x00 }, - { IMX415_REG_8BIT(0x36CE), 0x3C }, - { IMX415_REG_8BIT(0x36D0), 0x8C }, - { IMX415_REG_8BIT(0x36D1), 0x00 }, - { IMX415_REG_8BIT(0x36D2), 0x71 }, - { IMX415_REG_8BIT(0x36D4), 0x3C }, - { IMX415_REG_8BIT(0x36D6), 0x53 }, - { IMX415_REG_8BIT(0x36D7), 0x00 }, - { IMX415_REG_8BIT(0x36D8), 0x71 }, - { IMX415_REG_8BIT(0x36DA), 0x8C }, - { IMX415_REG_8BIT(0x36DB), 0x00 }, - { IMX415_REG_8BIT(0x3724), 0x02 }, - { IMX415_REG_8BIT(0x3726), 0x02 }, - { IMX415_REG_8BIT(0x3732), 0x02 }, - { IMX415_REG_8BIT(0x3734), 0x03 }, - { IMX415_REG_8BIT(0x3736), 0x03 }, - { IMX415_REG_8BIT(0x3742), 0x03 }, - { IMX415_REG_8BIT(0x3862), 0xE0 }, - { IMX415_REG_8BIT(0x38CC), 0x30 }, - { IMX415_REG_8BIT(0x38CD), 0x2F }, - { IMX415_REG_8BIT(0x395C), 0x0C }, - { IMX415_REG_8BIT(0x3A42), 0xD1 }, - { IMX415_REG_8BIT(0x3A4C), 0x77 }, - { IMX415_REG_8BIT(0x3AE0), 0x02 }, - { IMX415_REG_8BIT(0x3AEC), 0x0C }, - { IMX415_REG_8BIT(0x3B00), 0x2E }, - { IMX415_REG_8BIT(0x3B06), 0x29 }, - { IMX415_REG_8BIT(0x3B98), 0x25 }, - { IMX415_REG_8BIT(0x3B99), 0x21 }, - { IMX415_REG_8BIT(0x3B9B), 0x13 }, - { IMX415_REG_8BIT(0x3B9C), 0x13 }, - { IMX415_REG_8BIT(0x3B9D), 0x13 }, - { IMX415_REG_8BIT(0x3B9E), 0x13 }, - { IMX415_REG_8BIT(0x3BA1), 0x00 }, - { IMX415_REG_8BIT(0x3BA2), 0x06 }, - { IMX415_REG_8BIT(0x3BA3), 0x0B }, - { IMX415_REG_8BIT(0x3BA4), 0x10 }, - { IMX415_REG_8BIT(0x3BA5), 0x14 }, - { IMX415_REG_8BIT(0x3BA6), 0x18 }, - { IMX415_REG_8BIT(0x3BA7), 0x1A }, - { IMX415_REG_8BIT(0x3BA8), 0x1A }, - { IMX415_REG_8BIT(0x3BA9), 0x1A }, - { IMX415_REG_8BIT(0x3BAC), 0xED }, - { IMX415_REG_8BIT(0x3BAD), 0x01 }, - { IMX415_REG_8BIT(0x3BAE), 0xF6 }, - { IMX415_REG_8BIT(0x3BAF), 0x02 }, - { IMX415_REG_8BIT(0x3BB0), 0xA2 }, - { IMX415_REG_8BIT(0x3BB1), 0x03 }, - { IMX415_REG_8BIT(0x3BB2), 0xE0 }, - { IMX415_REG_8BIT(0x3BB3), 0x03 }, - { IMX415_REG_8BIT(0x3BB4), 0xE0 }, - { IMX415_REG_8BIT(0x3BB5), 0x03 }, - { IMX415_REG_8BIT(0x3BB6), 0xE0 }, - { IMX415_REG_8BIT(0x3BB7), 0x03 }, - { IMX415_REG_8BIT(0x3BB8), 0xE0 }, - { IMX415_REG_8BIT(0x3BBA), 0xE0 }, - { IMX415_REG_8BIT(0x3BBC), 0xDA }, - { IMX415_REG_8BIT(0x3BBE), 0x88 }, - { IMX415_REG_8BIT(0x3BC0), 0x44 }, - { IMX415_REG_8BIT(0x3BC2), 0x7B }, - { IMX415_REG_8BIT(0x3BC4), 0xA2 }, - { IMX415_REG_8BIT(0x3BC8), 0xBD }, - { IMX415_REG_8BIT(0x3BCA), 0xBD }, + { CCI_REG8(0x32D4), 0x21 }, + { CCI_REG8(0x32EC), 0xA1 }, + { CCI_REG8(0x3452), 0x7F }, + { CCI_REG8(0x3453), 0x03 }, + { CCI_REG8(0x358A), 0x04 }, + { CCI_REG8(0x35A1), 0x02 }, + { CCI_REG8(0x36BC), 0x0C }, + { CCI_REG8(0x36CC), 0x53 }, + { CCI_REG8(0x36CD), 0x00 }, + { CCI_REG8(0x36CE), 0x3C }, + { CCI_REG8(0x36D0), 0x8C }, + { CCI_REG8(0x36D1), 0x00 }, + { CCI_REG8(0x36D2), 0x71 }, + { CCI_REG8(0x36D4), 0x3C }, + { CCI_REG8(0x36D6), 0x53 }, + { CCI_REG8(0x36D7), 0x00 }, + { CCI_REG8(0x36D8), 0x71 }, + { CCI_REG8(0x36DA), 0x8C }, + { CCI_REG8(0x36DB), 0x00 }, + { CCI_REG8(0x3724), 0x02 }, + { CCI_REG8(0x3726), 0x02 }, + { CCI_REG8(0x3732), 0x02 }, + { CCI_REG8(0x3734), 0x03 }, + { CCI_REG8(0x3736), 0x03 }, + { CCI_REG8(0x3742), 0x03 }, + { CCI_REG8(0x3862), 0xE0 }, + { CCI_REG8(0x38CC), 0x30 }, + { CCI_REG8(0x38CD), 0x2F }, + { CCI_REG8(0x395C), 0x0C }, + { CCI_REG8(0x3A42), 0xD1 }, + { CCI_REG8(0x3A4C), 0x77 }, + { CCI_REG8(0x3AE0), 0x02 }, + { CCI_REG8(0x3AEC), 0x0C }, + { CCI_REG8(0x3B00), 0x2E }, + { CCI_REG8(0x3B06), 0x29 }, + { CCI_REG8(0x3B98), 0x25 }, + { CCI_REG8(0x3B99), 0x21 }, + { CCI_REG8(0x3B9B), 0x13 }, + { CCI_REG8(0x3B9C), 0x13 }, + { CCI_REG8(0x3B9D), 0x13 }, + { CCI_REG8(0x3B9E), 0x13 }, + { CCI_REG8(0x3BA1), 0x00 }, + { CCI_REG8(0x3BA2), 0x06 }, + { CCI_REG8(0x3BA3), 0x0B }, + { CCI_REG8(0x3BA4), 0x10 }, + { CCI_REG8(0x3BA5), 0x14 }, + { CCI_REG8(0x3BA6), 0x18 }, + { CCI_REG8(0x3BA7), 0x1A }, + { CCI_REG8(0x3BA8), 0x1A }, + { CCI_REG8(0x3BA9), 0x1A }, + { CCI_REG8(0x3BAC), 0xED }, + { CCI_REG8(0x3BAD), 0x01 }, + { CCI_REG8(0x3BAE), 0xF6 }, + { CCI_REG8(0x3BAF), 0x02 }, + { CCI_REG8(0x3BB0), 0xA2 }, + { CCI_REG8(0x3BB1), 0x03 }, + { CCI_REG8(0x3BB2), 0xE0 }, + { CCI_REG8(0x3BB3), 0x03 }, + { CCI_REG8(0x3BB4), 0xE0 }, + { CCI_REG8(0x3BB5), 0x03 }, + { CCI_REG8(0x3BB6), 0xE0 }, + { CCI_REG8(0x3BB7), 0x03 }, + { CCI_REG8(0x3BB8), 0xE0 }, + { CCI_REG8(0x3BBA), 0xE0 }, + { CCI_REG8(0x3BBC), 0xDA }, + { CCI_REG8(0x3BBE), 0x88 }, + { CCI_REG8(0x3BC0), 0x44 }, + { CCI_REG8(0x3BC2), 0x7B }, + { CCI_REG8(0x3BC4), 0xA2 }, + { CCI_REG8(0x3BC8), 0xBD }, + { CCI_REG8(0x3BCA), 0xBD }, }; static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) @@ -460,74 +700,26 @@ static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) return container_of(sd, struct imx415, subdev); } -static int imx415_read(struct imx415 *sensor, u32 addr) -{ - u8 data[3] = { 0 }; - int ret; - - ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data, - (addr >> IMX415_REG_SIZE_SHIFT) & 3); - if (ret < 0) - return ret; - - return (data[2] << 16) | (data[1] << 8) | data[0]; -} - -static int imx415_write(struct imx415 *sensor, u32 addr, u32 value) -{ - u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; - int ret; - - ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK, - data, (addr >> IMX415_REG_SIZE_SHIFT) & 3); - if (ret < 0) - dev_err_ratelimited(sensor->dev, - "%u-bit write to 0x%04x failed: %d\n", - ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8, - addr & IMX415_REG_ADDR_MASK, ret); - - return 0; -} - static int imx415_set_testpattern(struct imx415 *sensor, int val) { - int ret; + int ret = 0; if (val) { - ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00); + cci_write(sensor->regmap, IMX415_BLKLEVEL, 0x00, &ret); + cci_write(sensor->regmap, IMX415_TPG_EN_DUOUT, 0x01, &ret); + cci_write(sensor->regmap, IMX415_TPG_PATSEL_DUOUT, + val - 1, &ret); + cci_write(sensor->regmap, IMX415_TPG_COLORWIDTH, 0x01, &ret); + cci_write(sensor->regmap, IMX415_TESTCLKEN_MIPI, 0x20, &ret); + cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x00, &ret); + cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x00, &ret); } else { - ret = imx415_write(sensor, IMX415_BLKLEVEL, - IMX415_BLKLEVEL_DEFAULT); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01); - if (ret) - return ret; - ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01); + cci_write(sensor->regmap, IMX415_BLKLEVEL, + IMX415_BLKLEVEL_DEFAULT, &ret); + cci_write(sensor->regmap, IMX415_TPG_EN_DUOUT, 0x00, &ret); + cci_write(sensor->regmap, IMX415_TESTCLKEN_MIPI, 0x00, &ret); + cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x01, &ret); + cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x01, &ret); } return 0; } @@ -553,19 +745,21 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) /* clamp the exposure value to VMAX. */ vmax = format->height + sensor->vblank->cur.val; ctrl->val = min_t(int, ctrl->val, vmax); - ret = imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + ret = cci_write(sensor->regmap, IMX415_SHR0, + vmax - ctrl->val, NULL); break; case V4L2_CID_ANALOGUE_GAIN: /* analogue gain in 0.3 dB step size */ - ret = imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + ret = cci_write(sensor->regmap, IMX415_GAIN_PCG_0, + ctrl->val, NULL); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | (sensor->vflip->val << IMX415_VREVERSE_SHIFT); - ret = imx415_write(sensor, IMX415_REVERSE, flip); + ret = cci_write(sensor->regmap, IMX415_REVERSE, flip, NULL); break; case V4L2_CID_TEST_PATTERN: @@ -679,8 +873,6 @@ static int imx415_ctrls_init(struct imx415 *sensor) static int imx415_set_mode(struct imx415 *sensor, int mode) { - const struct imx415_reg *reg; - unsigned int i; int ret = 0; if (mode >= ARRAY_SIZE(supported_modes)) { @@ -688,34 +880,29 @@ static int imx415_set_mode(struct imx415 *sensor, int mode) return -EINVAL; } - for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) { - reg = &supported_modes[mode].reg_list.regs[i]; - ret = imx415_write(sensor, reg->address, reg->val); - if (ret) - return ret; - } + cci_multi_reg_write(sensor->regmap, + supported_modes[mode].reg_list.regs, + supported_modes[mode].reg_list.num_of_regs, + &ret); - for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) { - reg = &sensor->clk_params->regs[i]; - ret = imx415_write(sensor, reg->address, reg->val); - if (ret) - return ret; - } + cci_multi_reg_write(sensor->regmap, + sensor->clk_params->regs, + IMX415_NUM_CLK_PARAM_REGS, + &ret); return 0; } static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) { - unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) { - ret = imx415_write(sensor, imx415_init_table[i].address, - imx415_init_table[i].val); - if (ret) - return ret; - } + ret = cci_multi_reg_write(sensor->regmap, + imx415_init_table, + ARRAY_SIZE(imx415_init_table), + NULL); + if (ret) + return ret; return imx415_set_mode(sensor, sensor->cur_mode); } @@ -724,7 +911,8 @@ static int imx415_wakeup(struct imx415 *sensor) { int ret; - ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING); + ret = cci_write(sensor->regmap, IMX415_MODE, + IMX415_MODE_OPERATING, NULL); if (ret) return ret; @@ -743,21 +931,18 @@ static int imx415_stream_on(struct imx415 *sensor) int ret; ret = imx415_wakeup(sensor); - if (ret) - return ret; - - return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START); + return cci_write(sensor->regmap, IMX415_XMSTA, + IMX415_XMSTA_START, &ret); } static int imx415_stream_off(struct imx415 *sensor) { int ret; - ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP); - if (ret) - return ret; - - return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + ret = cci_write(sensor->regmap, IMX415_XMSTA, + IMX415_XMSTA_STOP, NULL); + return cci_write(sensor->regmap, IMX415_MODE, + IMX415_MODE_STANDBY, &ret); } static int imx415_s_stream(struct v4l2_subdev *sd, int enable) @@ -992,6 +1177,7 @@ static void imx415_power_off(struct imx415 *sensor) static int imx415_identify_model(struct imx415 *sensor) { int model, ret; + u64 chip_id; /* * While most registers can be read when the sensor is in standby, this @@ -1002,14 +1188,14 @@ static int imx415_identify_model(struct imx415 *sensor) return dev_err_probe(sensor->dev, ret, "failed to get sensor out of standby\n"); - ret = imx415_read(sensor, IMX415_SENSOR_INFO); + ret = cci_read(sensor->regmap, IMX415_SENSOR_INFO, &chip_id, NULL); if (ret < 0) { dev_err_probe(sensor->dev, ret, "failed to read sensor information\n"); goto done; } - model = ret & IMX415_SENSOR_INFO_MASK; + model = chip_id & IMX415_SENSOR_INFO_MASK; switch (model) { case IMX415_CHIP_ID: @@ -1024,7 +1210,7 @@ static int imx415_identify_model(struct imx415 *sensor) ret = 0; done: - imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + cci_write(sensor->regmap, IMX415_MODE, IMX415_MODE_STANDBY, &ret); return ret; } @@ -1173,7 +1359,7 @@ static int imx415_probe(struct i2c_client *client) if (ret) return ret; - sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config); + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(sensor->regmap)) return PTR_ERR(sensor->regmap); diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c index 89e13ebbce..c7089035bb 100644 --- a/drivers/media/i2c/isl7998x.c +++ b/drivers/media/i2c/isl7998x.c @@ -1337,7 +1337,7 @@ static const struct regmap_config isl7998x_regmap = { .rd_table = &isl7998x_readable_table, .wr_table = &isl7998x_writeable_table, .volatile_table = &isl7998x_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int isl7998x_mc_init(struct isl7998x *isl7998x) diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 70c2a2948f..cd73d2096a 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -257,7 +257,7 @@ static const struct regmap_config max2175_regmap_config = { .reg_defaults = max2175_reg_defaults, .num_reg_defaults = ARRAY_SIZE(max2175_reg_defaults), .volatile_table = &max2175_volatile_regs, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; struct max2175 { diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271.h index dc5e4e70ba..0bf1d40811 100644 --- a/drivers/media/i2c/max9271.h +++ b/drivers/media/i2c/max9271.h @@ -8,6 +8,9 @@ * Copyright (C) 2015 Cogent Embedded, Inc. */ +#ifndef __MEDIA_I2C_MAX9271_H__ +#define __MEDIA_I2C_MAX9271_H__ + #include <linux/i2c.h> #define MAX9271_DEFAULT_ADDR 0x40 @@ -231,3 +234,5 @@ int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr); * Return 0 on success or a negative error code on failure */ int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest); + +#endif /* __MEDIA_I2C_MAX9271_H__ */ diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index d685d445cf..dfcb3fc033 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -383,7 +383,7 @@ static int max9286_i2c_mux_init(struct max9286_priv *priv) for_each_source(priv, source) { unsigned int index = to_index(priv, source); - ret = i2c_mux_add_adapter(priv->mux, 0, index, 0); + ret = i2c_mux_add_adapter(priv->mux, 0, index); if (ret < 0) goto error; } diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 0ed8561edf..599a5bc7cb 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -309,23 +309,15 @@ static void msp_wake_thread(struct i2c_client *client) wake_up_interruptible(&state->wq); } -int msp_sleep(struct msp_state *state, int timeout) +int msp_sleep(struct msp_state *state, int msec) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&state->wq, &wait); - if (!kthread_should_stop()) { - if (timeout < 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } else { - schedule_timeout_interruptible - (msecs_to_jiffies(timeout)); - } - } + long timeout; + + timeout = msec < 0 ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(msec); + + wait_event_freezable_timeout(state->wq, kthread_should_stop() || + state->restart, timeout); - remove_wait_queue(&state->wq, &wait); - try_to_freeze(); return state->restart; } diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h index 2bb9d5ff1b..7d391714ea 100644 --- a/drivers/media/i2c/msp3400-driver.h +++ b/drivers/media/i2c/msp3400-driver.h @@ -134,7 +134,7 @@ int msp_read_dsp(struct i2c_client *client, int addr); int msp_reset(struct i2c_client *client); void msp_set_scart(struct i2c_client *client, int in, int out); void msp_update_volume(struct msp_state *state); -int msp_sleep(struct msp_state *state, int timeout); +int msp_sleep(struct msp_state *state, int msec); /* msp3400-kthreads.c */ const char *msp_standard_std_name(int std); diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 596200d024..f4b4812123 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -1078,7 +1078,7 @@ mt9p031_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = of_graph_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!np) return NULL; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 3ca76eeae7..302120ff12 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -988,7 +988,7 @@ static const struct regmap_config mt9v032_regmap_config = { .reg_bits = 8, .val_bits = 16, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* ----------------------------------------------------------------------------- @@ -1006,7 +1006,7 @@ mt9v032_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = of_graph_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!np) return NULL; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index abbb0b774d..48df077522 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. +#include <asm-generic/unaligned.h> #include <linux/acpi.h> #include <linux/i2c.h> #include <linux/module.h> @@ -34,7 +35,7 @@ /* V_TIMING internal */ #define OV08X40_REG_VTS 0x380e -#define OV08X40_VTS_30FPS 0x1388 +#define OV08X40_VTS_30FPS 0x09c4 /* the VTS need to be half in normal mode */ #define OV08X40_VTS_BIN_30FPS 0x115c #define OV08X40_VTS_MAX 0x7fff @@ -44,8 +45,9 @@ /* Exposure control */ #define OV08X40_REG_EXPOSURE 0x3500 -#define OV08X40_EXPOSURE_MAX_MARGIN 31 -#define OV08X40_EXPOSURE_MIN 1 +#define OV08X40_EXPOSURE_MAX_MARGIN 8 +#define OV08X40_EXPOSURE_BIN_MAX_MARGIN 2 +#define OV08X40_EXPOSURE_MIN 4 #define OV08X40_EXPOSURE_STEP 1 #define OV08X40_EXPOSURE_DEFAULT 0x40 @@ -94,6 +96,12 @@ /* Vertical Window Offset */ #define OV08X40_REG_V_WIN_OFFSET 0x3813 +/* Burst Register */ +#define OV08X40_REG_XTALK_FIRST_A 0x5a80 +#define OV08X40_REG_XTALK_LAST_A 0x5b9f +#define OV08X40_REG_XTALK_FIRST_B 0x5bc0 +#define OV08X40_REG_XTALK_LAST_B 0x5f1f + enum { OV08X40_LINK_FREQ_400MHZ_INDEX, }; @@ -126,13 +134,17 @@ struct ov08x40_mode { u32 vts_def; u32 vts_min; - /* HTS */ - u32 hts; + /* Line Length Pixels */ + u32 llp; /* Index of Link frequency config to be used */ u32 link_freq_index; /* Default register values */ struct ov08x40_reg_list reg_list; + + /* Exposure calculation */ + u16 exposure_margin; + u16 exposure_shift; }; static const struct ov08x40_reg mipi_data_rate_800mbps[] = { @@ -665,1158 +677,6 @@ static const struct ov08x40_reg mode_3856x2416_regs[] = { {0x3502, 0x10}, {0x3508, 0x0f}, {0x3509, 0x80}, - {0x5a80, 0x75}, - {0x5a81, 0x75}, - {0x5a82, 0x75}, - {0x5a83, 0x75}, - {0x5a84, 0x75}, - {0x5a85, 0x75}, - {0x5a86, 0x75}, - {0x5a87, 0x75}, - {0x5a88, 0x75}, - {0x5a89, 0x75}, - {0x5a8a, 0x75}, - {0x5a8b, 0x75}, - {0x5a8c, 0x75}, - {0x5a8d, 0x75}, - {0x5a8e, 0x75}, - {0x5a8f, 0x75}, - {0x5a90, 0x75}, - {0x5a91, 0x75}, - {0x5a92, 0x75}, - {0x5a93, 0x75}, - {0x5a94, 0x75}, - {0x5a95, 0x75}, - {0x5a96, 0x75}, - {0x5a97, 0x75}, - {0x5a98, 0x75}, - {0x5a99, 0x75}, - {0x5a9a, 0x75}, - {0x5a9b, 0x75}, - {0x5a9c, 0x75}, - {0x5a9d, 0x75}, - {0x5a9e, 0x75}, - {0x5a9f, 0x75}, - {0x5aa0, 0x75}, - {0x5aa1, 0x75}, - {0x5aa2, 0x75}, - {0x5aa3, 0x75}, - {0x5aa4, 0x75}, - {0x5aa5, 0x75}, - {0x5aa6, 0x75}, - {0x5aa7, 0x75}, - {0x5aa8, 0x75}, - {0x5aa9, 0x75}, - {0x5aaa, 0x75}, - {0x5aab, 0x75}, - {0x5aac, 0x75}, - {0x5aad, 0x75}, - {0x5aae, 0x75}, - {0x5aaf, 0x75}, - {0x5ab0, 0x75}, - {0x5ab1, 0x75}, - {0x5ab2, 0x75}, - {0x5ab3, 0x75}, - {0x5ab4, 0x75}, - {0x5ab5, 0x75}, - {0x5ab6, 0x75}, - {0x5ab7, 0x75}, - {0x5ab8, 0x75}, - {0x5ab9, 0x75}, - {0x5aba, 0x75}, - {0x5abb, 0x75}, - {0x5abc, 0x75}, - {0x5abd, 0x75}, - {0x5abe, 0x75}, - {0x5abf, 0x75}, - {0x5ac0, 0x75}, - {0x5ac1, 0x75}, - {0x5ac2, 0x75}, - {0x5ac3, 0x75}, - {0x5ac4, 0x75}, - {0x5ac5, 0x75}, - {0x5ac6, 0x75}, - {0x5ac7, 0x75}, - {0x5ac8, 0x75}, - {0x5ac9, 0x75}, - {0x5aca, 0x75}, - {0x5acb, 0x75}, - {0x5acc, 0x75}, - {0x5acd, 0x75}, - {0x5ace, 0x75}, - {0x5acf, 0x75}, - {0x5ad0, 0x75}, - {0x5ad1, 0x75}, - {0x5ad2, 0x75}, - {0x5ad3, 0x75}, - {0x5ad4, 0x75}, - {0x5ad5, 0x75}, - {0x5ad6, 0x75}, - {0x5ad7, 0x75}, - {0x5ad8, 0x75}, - {0x5ad9, 0x75}, - {0x5ada, 0x75}, - {0x5adb, 0x75}, - {0x5adc, 0x75}, - {0x5add, 0x75}, - {0x5ade, 0x75}, - {0x5adf, 0x75}, - {0x5ae0, 0x75}, - {0x5ae1, 0x75}, - {0x5ae2, 0x75}, - {0x5ae3, 0x75}, - {0x5ae4, 0x75}, - {0x5ae5, 0x75}, - {0x5ae6, 0x75}, - {0x5ae7, 0x75}, - {0x5ae8, 0x75}, - {0x5ae9, 0x75}, - {0x5aea, 0x75}, - {0x5aeb, 0x75}, - {0x5aec, 0x75}, - {0x5aed, 0x75}, - {0x5aee, 0x75}, - {0x5aef, 0x75}, - {0x5af0, 0x75}, - {0x5af1, 0x75}, - {0x5af2, 0x75}, - {0x5af3, 0x75}, - {0x5af4, 0x75}, - {0x5af5, 0x75}, - {0x5af6, 0x75}, - {0x5af7, 0x75}, - {0x5af8, 0x75}, - {0x5af9, 0x75}, - {0x5afa, 0x75}, - {0x5afb, 0x75}, - {0x5afc, 0x75}, - {0x5afd, 0x75}, - {0x5afe, 0x75}, - {0x5aff, 0x75}, - {0x5b00, 0x75}, - {0x5b01, 0x75}, - {0x5b02, 0x75}, - {0x5b03, 0x75}, - {0x5b04, 0x75}, - {0x5b05, 0x75}, - {0x5b06, 0x75}, - {0x5b07, 0x75}, - {0x5b08, 0x75}, - {0x5b09, 0x75}, - {0x5b0a, 0x75}, - {0x5b0b, 0x75}, - {0x5b0c, 0x75}, - {0x5b0d, 0x75}, - {0x5b0e, 0x75}, - {0x5b0f, 0x75}, - {0x5b10, 0x75}, - {0x5b11, 0x75}, - {0x5b12, 0x75}, - {0x5b13, 0x75}, - {0x5b14, 0x75}, - {0x5b15, 0x75}, - {0x5b16, 0x75}, - {0x5b17, 0x75}, - {0x5b18, 0x75}, - {0x5b19, 0x75}, - {0x5b1a, 0x75}, - {0x5b1b, 0x75}, - {0x5b1c, 0x75}, - {0x5b1d, 0x75}, - {0x5b1e, 0x75}, - {0x5b1f, 0x75}, - {0x5b20, 0x75}, - {0x5b21, 0x75}, - {0x5b22, 0x75}, - {0x5b23, 0x75}, - {0x5b24, 0x75}, - {0x5b25, 0x75}, - {0x5b26, 0x75}, - {0x5b27, 0x75}, - {0x5b28, 0x75}, - {0x5b29, 0x75}, - {0x5b2a, 0x75}, - {0x5b2b, 0x75}, - {0x5b2c, 0x75}, - {0x5b2d, 0x75}, - {0x5b2e, 0x75}, - {0x5b2f, 0x75}, - {0x5b30, 0x75}, - {0x5b31, 0x75}, - {0x5b32, 0x75}, - {0x5b33, 0x75}, - {0x5b34, 0x75}, - {0x5b35, 0x75}, - {0x5b36, 0x75}, - {0x5b37, 0x75}, - {0x5b38, 0x75}, - {0x5b39, 0x75}, - {0x5b3a, 0x75}, - {0x5b3b, 0x75}, - {0x5b3c, 0x75}, - {0x5b3d, 0x75}, - {0x5b3e, 0x75}, - {0x5b3f, 0x75}, - {0x5b40, 0x75}, - {0x5b41, 0x75}, - {0x5b42, 0x75}, - {0x5b43, 0x75}, - {0x5b44, 0x75}, - {0x5b45, 0x75}, - {0x5b46, 0x75}, - {0x5b47, 0x75}, - {0x5b48, 0x75}, - {0x5b49, 0x75}, - {0x5b4a, 0x75}, - {0x5b4b, 0x75}, - {0x5b4c, 0x75}, - {0x5b4d, 0x75}, - {0x5b4e, 0x75}, - {0x5b4f, 0x75}, - {0x5b50, 0x75}, - {0x5b51, 0x75}, - {0x5b52, 0x75}, - {0x5b53, 0x75}, - {0x5b54, 0x75}, - {0x5b55, 0x75}, - {0x5b56, 0x75}, - {0x5b57, 0x75}, - {0x5b58, 0x75}, - {0x5b59, 0x75}, - {0x5b5a, 0x75}, - {0x5b5b, 0x75}, - {0x5b5c, 0x75}, - {0x5b5d, 0x75}, - {0x5b5e, 0x75}, - {0x5b5f, 0x75}, - {0x5b60, 0x75}, - {0x5b61, 0x75}, - {0x5b62, 0x75}, - {0x5b63, 0x75}, - {0x5b64, 0x75}, - {0x5b65, 0x75}, - {0x5b66, 0x75}, - {0x5b67, 0x75}, - {0x5b68, 0x75}, - {0x5b69, 0x75}, - {0x5b6a, 0x75}, - {0x5b6b, 0x75}, - {0x5b6c, 0x75}, - {0x5b6d, 0x75}, - {0x5b6e, 0x75}, - {0x5b6f, 0x75}, - {0x5b70, 0x75}, - {0x5b71, 0x75}, - {0x5b72, 0x75}, - {0x5b73, 0x75}, - {0x5b74, 0x75}, - {0x5b75, 0x75}, - {0x5b76, 0x75}, - {0x5b77, 0x75}, - {0x5b78, 0x75}, - {0x5b79, 0x75}, - {0x5b7a, 0x75}, - {0x5b7b, 0x75}, - {0x5b7c, 0x75}, - {0x5b7d, 0x75}, - {0x5b7e, 0x75}, - {0x5b7f, 0x75}, - {0x5b80, 0x75}, - {0x5b81, 0x75}, - {0x5b82, 0x75}, - {0x5b83, 0x75}, - {0x5b84, 0x75}, - {0x5b85, 0x75}, - {0x5b86, 0x75}, - {0x5b87, 0x75}, - {0x5b88, 0x75}, - {0x5b89, 0x75}, - {0x5b8a, 0x75}, - {0x5b8b, 0x75}, - {0x5b8c, 0x75}, - {0x5b8d, 0x75}, - {0x5b8e, 0x75}, - {0x5b8f, 0x75}, - {0x5b90, 0x75}, - {0x5b91, 0x75}, - {0x5b92, 0x75}, - {0x5b93, 0x75}, - {0x5b94, 0x75}, - {0x5b95, 0x75}, - {0x5b96, 0x75}, - {0x5b97, 0x75}, - {0x5b98, 0x75}, - {0x5b99, 0x75}, - {0x5b9a, 0x75}, - {0x5b9b, 0x75}, - {0x5b9c, 0x75}, - {0x5b9d, 0x75}, - {0x5b9e, 0x75}, - {0x5b9f, 0x75}, - {0x5bc0, 0x75}, - {0x5bc1, 0x75}, - {0x5bc2, 0x75}, - {0x5bc3, 0x75}, - {0x5bc4, 0x75}, - {0x5bc5, 0x75}, - {0x5bc6, 0x75}, - {0x5bc7, 0x75}, - {0x5bc8, 0x75}, - {0x5bc9, 0x75}, - {0x5bca, 0x75}, - {0x5bcb, 0x75}, - {0x5bcc, 0x75}, - {0x5bcd, 0x75}, - {0x5bce, 0x75}, - {0x5bcf, 0x75}, - {0x5bd0, 0x75}, - {0x5bd1, 0x75}, - {0x5bd2, 0x75}, - {0x5bd3, 0x75}, - {0x5bd4, 0x75}, - {0x5bd5, 0x75}, - {0x5bd6, 0x75}, - {0x5bd7, 0x75}, - {0x5bd8, 0x75}, - {0x5bd9, 0x75}, - {0x5bda, 0x75}, - {0x5bdb, 0x75}, - {0x5bdc, 0x75}, - {0x5bdd, 0x75}, - {0x5bde, 0x75}, - {0x5bdf, 0x75}, - {0x5be0, 0x75}, - {0x5be1, 0x75}, - {0x5be2, 0x75}, - {0x5be3, 0x75}, - {0x5be4, 0x75}, - {0x5be5, 0x75}, - {0x5be6, 0x75}, - {0x5be7, 0x75}, - {0x5be8, 0x75}, - {0x5be9, 0x75}, - {0x5bea, 0x75}, - {0x5beb, 0x75}, - {0x5bec, 0x75}, - {0x5bed, 0x75}, - {0x5bee, 0x75}, - {0x5bef, 0x75}, - {0x5bf0, 0x75}, - {0x5bf1, 0x75}, - {0x5bf2, 0x75}, - {0x5bf3, 0x75}, - {0x5bf4, 0x75}, - {0x5bf5, 0x75}, - {0x5bf6, 0x75}, - {0x5bf7, 0x75}, - {0x5bf8, 0x75}, - {0x5bf9, 0x75}, - {0x5bfa, 0x75}, - {0x5bfb, 0x75}, - {0x5bfc, 0x75}, - {0x5bfd, 0x75}, - {0x5bfe, 0x75}, - {0x5bff, 0x75}, - {0x5c00, 0x75}, - {0x5c01, 0x75}, - {0x5c02, 0x75}, - {0x5c03, 0x75}, - {0x5c04, 0x75}, - {0x5c05, 0x75}, - {0x5c06, 0x75}, - {0x5c07, 0x75}, - {0x5c08, 0x75}, - {0x5c09, 0x75}, - {0x5c0a, 0x75}, - {0x5c0b, 0x75}, - {0x5c0c, 0x75}, - {0x5c0d, 0x75}, - {0x5c0e, 0x75}, - {0x5c0f, 0x75}, - {0x5c10, 0x75}, - {0x5c11, 0x75}, - {0x5c12, 0x75}, - {0x5c13, 0x75}, - {0x5c14, 0x75}, - {0x5c15, 0x75}, - {0x5c16, 0x75}, - {0x5c17, 0x75}, - {0x5c18, 0x75}, - {0x5c19, 0x75}, - {0x5c1a, 0x75}, - {0x5c1b, 0x75}, - {0x5c1c, 0x75}, - {0x5c1d, 0x75}, - {0x5c1e, 0x75}, - {0x5c1f, 0x75}, - {0x5c20, 0x75}, - {0x5c21, 0x75}, - {0x5c22, 0x75}, - {0x5c23, 0x75}, - {0x5c24, 0x75}, - {0x5c25, 0x75}, - {0x5c26, 0x75}, - {0x5c27, 0x75}, - {0x5c28, 0x75}, - {0x5c29, 0x75}, - {0x5c2a, 0x75}, - {0x5c2b, 0x75}, - {0x5c2c, 0x75}, - {0x5c2d, 0x75}, - {0x5c2e, 0x75}, - {0x5c2f, 0x75}, - {0x5c30, 0x75}, - {0x5c31, 0x75}, - {0x5c32, 0x75}, - {0x5c33, 0x75}, - {0x5c34, 0x75}, - {0x5c35, 0x75}, - {0x5c36, 0x75}, - {0x5c37, 0x75}, - {0x5c38, 0x75}, - {0x5c39, 0x75}, - {0x5c3a, 0x75}, - {0x5c3b, 0x75}, - {0x5c3c, 0x75}, - {0x5c3d, 0x75}, - {0x5c3e, 0x75}, - {0x5c3f, 0x75}, - {0x5c40, 0x75}, - {0x5c41, 0x75}, - {0x5c42, 0x75}, - {0x5c43, 0x75}, - {0x5c44, 0x75}, - {0x5c45, 0x75}, - {0x5c46, 0x75}, - {0x5c47, 0x75}, - {0x5c48, 0x75}, - {0x5c49, 0x75}, - {0x5c4a, 0x75}, - {0x5c4b, 0x75}, - {0x5c4c, 0x75}, - {0x5c4d, 0x75}, - {0x5c4e, 0x75}, - {0x5c4f, 0x75}, - {0x5c50, 0x75}, - {0x5c51, 0x75}, - {0x5c52, 0x75}, - {0x5c53, 0x75}, - {0x5c54, 0x75}, - {0x5c55, 0x75}, - {0x5c56, 0x75}, - {0x5c57, 0x75}, - {0x5c58, 0x75}, - {0x5c59, 0x75}, - {0x5c5a, 0x75}, - {0x5c5b, 0x75}, - {0x5c5c, 0x75}, - {0x5c5d, 0x75}, - {0x5c5e, 0x75}, - {0x5c5f, 0x75}, - {0x5c60, 0x75}, - {0x5c61, 0x75}, - {0x5c62, 0x75}, - {0x5c63, 0x75}, - {0x5c64, 0x75}, - {0x5c65, 0x75}, - {0x5c66, 0x75}, - {0x5c67, 0x75}, - {0x5c68, 0x75}, - {0x5c69, 0x75}, - {0x5c6a, 0x75}, - {0x5c6b, 0x75}, - {0x5c6c, 0x75}, - {0x5c6d, 0x75}, - {0x5c6e, 0x75}, - {0x5c6f, 0x75}, - {0x5c70, 0x75}, - {0x5c71, 0x75}, - {0x5c72, 0x75}, - {0x5c73, 0x75}, - {0x5c74, 0x75}, - {0x5c75, 0x75}, - {0x5c76, 0x75}, - {0x5c77, 0x75}, - {0x5c78, 0x75}, - {0x5c79, 0x75}, - {0x5c7a, 0x75}, - {0x5c7b, 0x75}, - {0x5c7c, 0x75}, - {0x5c7d, 0x75}, - {0x5c7e, 0x75}, - {0x5c7f, 0x75}, - {0x5c80, 0x75}, - {0x5c81, 0x75}, - {0x5c82, 0x75}, - {0x5c83, 0x75}, - {0x5c84, 0x75}, - {0x5c85, 0x75}, - {0x5c86, 0x75}, - {0x5c87, 0x75}, - {0x5c88, 0x75}, - {0x5c89, 0x75}, - {0x5c8a, 0x75}, - {0x5c8b, 0x75}, - {0x5c8c, 0x75}, - {0x5c8d, 0x75}, - {0x5c8e, 0x75}, - {0x5c8f, 0x75}, - {0x5c90, 0x75}, - {0x5c91, 0x75}, - {0x5c92, 0x75}, - {0x5c93, 0x75}, - {0x5c94, 0x75}, - {0x5c95, 0x75}, - {0x5c96, 0x75}, - {0x5c97, 0x75}, - {0x5c98, 0x75}, - {0x5c99, 0x75}, - {0x5c9a, 0x75}, - {0x5c9b, 0x75}, - {0x5c9c, 0x75}, - {0x5c9d, 0x75}, - {0x5c9e, 0x75}, - {0x5c9f, 0x75}, - {0x5ca0, 0x75}, - {0x5ca1, 0x75}, - {0x5ca2, 0x75}, - {0x5ca3, 0x75}, - {0x5ca4, 0x75}, - {0x5ca5, 0x75}, - {0x5ca6, 0x75}, - {0x5ca7, 0x75}, - {0x5ca8, 0x75}, - {0x5ca9, 0x75}, - {0x5caa, 0x75}, - {0x5cab, 0x75}, - {0x5cac, 0x75}, - {0x5cad, 0x75}, - {0x5cae, 0x75}, - {0x5caf, 0x75}, - {0x5cb0, 0x75}, - {0x5cb1, 0x75}, - {0x5cb2, 0x75}, - {0x5cb3, 0x75}, - {0x5cb4, 0x75}, - {0x5cb5, 0x75}, - {0x5cb6, 0x75}, - {0x5cb7, 0x75}, - {0x5cb8, 0x75}, - {0x5cb9, 0x75}, - {0x5cba, 0x75}, - {0x5cbb, 0x75}, - {0x5cbc, 0x75}, - {0x5cbd, 0x75}, - {0x5cbe, 0x75}, - {0x5cbf, 0x75}, - {0x5cc0, 0x75}, - {0x5cc1, 0x75}, - {0x5cc2, 0x75}, - {0x5cc3, 0x75}, - {0x5cc4, 0x75}, - {0x5cc5, 0x75}, - {0x5cc6, 0x75}, - {0x5cc7, 0x75}, - {0x5cc8, 0x75}, - {0x5cc9, 0x75}, - {0x5cca, 0x75}, - {0x5ccb, 0x75}, - {0x5ccc, 0x75}, - {0x5ccd, 0x75}, - {0x5cce, 0x75}, - {0x5ccf, 0x75}, - {0x5cd0, 0x75}, - {0x5cd1, 0x75}, - {0x5cd2, 0x75}, - {0x5cd3, 0x75}, - {0x5cd4, 0x75}, - {0x5cd5, 0x75}, - {0x5cd6, 0x75}, - {0x5cd7, 0x75}, - {0x5cd8, 0x75}, - {0x5cd9, 0x75}, - {0x5cda, 0x75}, - {0x5cdb, 0x75}, - {0x5cdc, 0x75}, - {0x5cdd, 0x75}, - {0x5cde, 0x75}, - {0x5cdf, 0x75}, - {0x5ce0, 0x75}, - {0x5ce1, 0x75}, - {0x5ce2, 0x75}, - {0x5ce3, 0x75}, - {0x5ce4, 0x75}, - {0x5ce5, 0x75}, - {0x5ce6, 0x75}, - {0x5ce7, 0x75}, - {0x5ce8, 0x75}, - {0x5ce9, 0x75}, - {0x5cea, 0x75}, - {0x5ceb, 0x75}, - {0x5cec, 0x75}, - {0x5ced, 0x75}, - {0x5cee, 0x75}, - {0x5cef, 0x75}, - {0x5cf0, 0x75}, - {0x5cf1, 0x75}, - {0x5cf2, 0x75}, - {0x5cf3, 0x75}, - {0x5cf4, 0x75}, - {0x5cf5, 0x75}, - {0x5cf6, 0x75}, - {0x5cf7, 0x75}, - {0x5cf8, 0x75}, - {0x5cf9, 0x75}, - {0x5cfa, 0x75}, - {0x5cfb, 0x75}, - {0x5cfc, 0x75}, - {0x5cfd, 0x75}, - {0x5cfe, 0x75}, - {0x5cff, 0x75}, - {0x5d00, 0x75}, - {0x5d01, 0x75}, - {0x5d02, 0x75}, - {0x5d03, 0x75}, - {0x5d04, 0x75}, - {0x5d05, 0x75}, - {0x5d06, 0x75}, - {0x5d07, 0x75}, - {0x5d08, 0x75}, - {0x5d09, 0x75}, - {0x5d0a, 0x75}, - {0x5d0b, 0x75}, - {0x5d0c, 0x75}, - {0x5d0d, 0x75}, - {0x5d0e, 0x75}, - {0x5d0f, 0x75}, - {0x5d10, 0x75}, - {0x5d11, 0x75}, - {0x5d12, 0x75}, - {0x5d13, 0x75}, - {0x5d14, 0x75}, - {0x5d15, 0x75}, - {0x5d16, 0x75}, - {0x5d17, 0x75}, - {0x5d18, 0x75}, - {0x5d19, 0x75}, - {0x5d1a, 0x75}, - {0x5d1b, 0x75}, - {0x5d1c, 0x75}, - {0x5d1d, 0x75}, - {0x5d1e, 0x75}, - {0x5d1f, 0x75}, - {0x5d20, 0x75}, - {0x5d21, 0x75}, - {0x5d22, 0x75}, - {0x5d23, 0x75}, - {0x5d24, 0x75}, - {0x5d25, 0x75}, - {0x5d26, 0x75}, - {0x5d27, 0x75}, - {0x5d28, 0x75}, - {0x5d29, 0x75}, - {0x5d2a, 0x75}, - {0x5d2b, 0x75}, - {0x5d2c, 0x75}, - {0x5d2d, 0x75}, - {0x5d2e, 0x75}, - {0x5d2f, 0x75}, - {0x5d30, 0x75}, - {0x5d31, 0x75}, - {0x5d32, 0x75}, - {0x5d33, 0x75}, - {0x5d34, 0x75}, - {0x5d35, 0x75}, - {0x5d36, 0x75}, - {0x5d37, 0x75}, - {0x5d38, 0x75}, - {0x5d39, 0x75}, - {0x5d3a, 0x75}, - {0x5d3b, 0x75}, - {0x5d3c, 0x75}, - {0x5d3d, 0x75}, - {0x5d3e, 0x75}, - {0x5d3f, 0x75}, - {0x5d40, 0x75}, - {0x5d41, 0x75}, - {0x5d42, 0x75}, - {0x5d43, 0x75}, - {0x5d44, 0x75}, - {0x5d45, 0x75}, - {0x5d46, 0x75}, - {0x5d47, 0x75}, - {0x5d48, 0x75}, - {0x5d49, 0x75}, - {0x5d4a, 0x75}, - {0x5d4b, 0x75}, - {0x5d4c, 0x75}, - {0x5d4d, 0x75}, - {0x5d4e, 0x75}, - {0x5d4f, 0x75}, - {0x5d50, 0x75}, - {0x5d51, 0x75}, - {0x5d52, 0x75}, - {0x5d53, 0x75}, - {0x5d54, 0x75}, - {0x5d55, 0x75}, - {0x5d56, 0x75}, - {0x5d57, 0x75}, - {0x5d58, 0x75}, - {0x5d59, 0x75}, - {0x5d5a, 0x75}, - {0x5d5b, 0x75}, - {0x5d5c, 0x75}, - {0x5d5d, 0x75}, - {0x5d5e, 0x75}, - {0x5d5f, 0x75}, - {0x5d60, 0x75}, - {0x5d61, 0x75}, - {0x5d62, 0x75}, - {0x5d63, 0x75}, - {0x5d64, 0x75}, - {0x5d65, 0x75}, - {0x5d66, 0x75}, - {0x5d67, 0x75}, - {0x5d68, 0x75}, - {0x5d69, 0x75}, - {0x5d6a, 0x75}, - {0x5d6b, 0x75}, - {0x5d6c, 0x75}, - {0x5d6d, 0x75}, - {0x5d6e, 0x75}, - {0x5d6f, 0x75}, - {0x5d70, 0x75}, - {0x5d71, 0x75}, - {0x5d72, 0x75}, - {0x5d73, 0x75}, - {0x5d74, 0x75}, - {0x5d75, 0x75}, - {0x5d76, 0x75}, - {0x5d77, 0x75}, - {0x5d78, 0x75}, - {0x5d79, 0x75}, - {0x5d7a, 0x75}, - {0x5d7b, 0x75}, - {0x5d7c, 0x75}, - {0x5d7d, 0x75}, - {0x5d7e, 0x75}, - {0x5d7f, 0x75}, - {0x5d80, 0x75}, - {0x5d81, 0x75}, - {0x5d82, 0x75}, - {0x5d83, 0x75}, - {0x5d84, 0x75}, - {0x5d85, 0x75}, - {0x5d86, 0x75}, - {0x5d87, 0x75}, - {0x5d88, 0x75}, - {0x5d89, 0x75}, - {0x5d8a, 0x75}, - {0x5d8b, 0x75}, - {0x5d8c, 0x75}, - {0x5d8d, 0x75}, - {0x5d8e, 0x75}, - {0x5d8f, 0x75}, - {0x5d90, 0x75}, - {0x5d91, 0x75}, - {0x5d92, 0x75}, - {0x5d93, 0x75}, - {0x5d94, 0x75}, - {0x5d95, 0x75}, - {0x5d96, 0x75}, - {0x5d97, 0x75}, - {0x5d98, 0x75}, - {0x5d99, 0x75}, - {0x5d9a, 0x75}, - {0x5d9b, 0x75}, - {0x5d9c, 0x75}, - {0x5d9d, 0x75}, - {0x5d9e, 0x75}, - {0x5d9f, 0x75}, - {0x5da0, 0x75}, - {0x5da1, 0x75}, - {0x5da2, 0x75}, - {0x5da3, 0x75}, - {0x5da4, 0x75}, - {0x5da5, 0x75}, - {0x5da6, 0x75}, - {0x5da7, 0x75}, - {0x5da8, 0x75}, - {0x5da9, 0x75}, - {0x5daa, 0x75}, - {0x5dab, 0x75}, - {0x5dac, 0x75}, - {0x5dad, 0x75}, - {0x5dae, 0x75}, - {0x5daf, 0x75}, - {0x5db0, 0x75}, - {0x5db1, 0x75}, - {0x5db2, 0x75}, - {0x5db3, 0x75}, - {0x5db4, 0x75}, - {0x5db5, 0x75}, - {0x5db6, 0x75}, - {0x5db7, 0x75}, - {0x5db8, 0x75}, - {0x5db9, 0x75}, - {0x5dba, 0x75}, - {0x5dbb, 0x75}, - {0x5dbc, 0x75}, - {0x5dbd, 0x75}, - {0x5dbe, 0x75}, - {0x5dbf, 0x75}, - {0x5dc0, 0x75}, - {0x5dc1, 0x75}, - {0x5dc2, 0x75}, - {0x5dc3, 0x75}, - {0x5dc4, 0x75}, - {0x5dc5, 0x75}, - {0x5dc6, 0x75}, - {0x5dc7, 0x75}, - {0x5dc8, 0x75}, - {0x5dc9, 0x75}, - {0x5dca, 0x75}, - {0x5dcb, 0x75}, - {0x5dcc, 0x75}, - {0x5dcd, 0x75}, - {0x5dce, 0x75}, - {0x5dcf, 0x75}, - {0x5dd0, 0x75}, - {0x5dd1, 0x75}, - {0x5dd2, 0x75}, - {0x5dd3, 0x75}, - {0x5dd4, 0x75}, - {0x5dd5, 0x75}, - {0x5dd6, 0x75}, - {0x5dd7, 0x75}, - {0x5dd8, 0x75}, - {0x5dd9, 0x75}, - {0x5dda, 0x75}, - {0x5ddb, 0x75}, - {0x5ddc, 0x75}, - {0x5ddd, 0x75}, - {0x5dde, 0x75}, - {0x5ddf, 0x75}, - {0x5de0, 0x75}, - {0x5de1, 0x75}, - {0x5de2, 0x75}, - {0x5de3, 0x75}, - {0x5de4, 0x75}, - {0x5de5, 0x75}, - {0x5de6, 0x75}, - {0x5de7, 0x75}, - {0x5de8, 0x75}, - {0x5de9, 0x75}, - {0x5dea, 0x75}, - {0x5deb, 0x75}, - {0x5dec, 0x75}, - {0x5ded, 0x75}, - {0x5dee, 0x75}, - {0x5def, 0x75}, - {0x5df0, 0x75}, - {0x5df1, 0x75}, - {0x5df2, 0x75}, - {0x5df3, 0x75}, - {0x5df4, 0x75}, - {0x5df5, 0x75}, - {0x5df6, 0x75}, - {0x5df7, 0x75}, - {0x5df8, 0x75}, - {0x5df9, 0x75}, - {0x5dfa, 0x75}, - {0x5dfb, 0x75}, - {0x5dfc, 0x75}, - {0x5dfd, 0x75}, - {0x5dfe, 0x75}, - {0x5dff, 0x75}, - {0x5e00, 0x75}, - {0x5e01, 0x75}, - {0x5e02, 0x75}, - {0x5e03, 0x75}, - {0x5e04, 0x75}, - {0x5e05, 0x75}, - {0x5e06, 0x75}, - {0x5e07, 0x75}, - {0x5e08, 0x75}, - {0x5e09, 0x75}, - {0x5e0a, 0x75}, - {0x5e0b, 0x75}, - {0x5e0c, 0x75}, - {0x5e0d, 0x75}, - {0x5e0e, 0x75}, - {0x5e0f, 0x75}, - {0x5e10, 0x75}, - {0x5e11, 0x75}, - {0x5e12, 0x75}, - {0x5e13, 0x75}, - {0x5e14, 0x75}, - {0x5e15, 0x75}, - {0x5e16, 0x75}, - {0x5e17, 0x75}, - {0x5e18, 0x75}, - {0x5e19, 0x75}, - {0x5e1a, 0x75}, - {0x5e1b, 0x75}, - {0x5e1c, 0x75}, - {0x5e1d, 0x75}, - {0x5e1e, 0x75}, - {0x5e1f, 0x75}, - {0x5e20, 0x75}, - {0x5e21, 0x75}, - {0x5e22, 0x75}, - {0x5e23, 0x75}, - {0x5e24, 0x75}, - {0x5e25, 0x75}, - {0x5e26, 0x75}, - {0x5e27, 0x75}, - {0x5e28, 0x75}, - {0x5e29, 0x75}, - {0x5e2a, 0x75}, - {0x5e2b, 0x75}, - {0x5e2c, 0x75}, - {0x5e2d, 0x75}, - {0x5e2e, 0x75}, - {0x5e2f, 0x75}, - {0x5e30, 0x75}, - {0x5e31, 0x75}, - {0x5e32, 0x75}, - {0x5e33, 0x75}, - {0x5e34, 0x75}, - {0x5e35, 0x75}, - {0x5e36, 0x75}, - {0x5e37, 0x75}, - {0x5e38, 0x75}, - {0x5e39, 0x75}, - {0x5e3a, 0x75}, - {0x5e3b, 0x75}, - {0x5e3c, 0x75}, - {0x5e3d, 0x75}, - {0x5e3e, 0x75}, - {0x5e3f, 0x75}, - {0x5e40, 0x75}, - {0x5e41, 0x75}, - {0x5e42, 0x75}, - {0x5e43, 0x75}, - {0x5e44, 0x75}, - {0x5e45, 0x75}, - {0x5e46, 0x75}, - {0x5e47, 0x75}, - {0x5e48, 0x75}, - {0x5e49, 0x75}, - {0x5e4a, 0x75}, - {0x5e4b, 0x75}, - {0x5e4c, 0x75}, - {0x5e4d, 0x75}, - {0x5e4e, 0x75}, - {0x5e4f, 0x75}, - {0x5e50, 0x75}, - {0x5e51, 0x75}, - {0x5e52, 0x75}, - {0x5e53, 0x75}, - {0x5e54, 0x75}, - {0x5e55, 0x75}, - {0x5e56, 0x75}, - {0x5e57, 0x75}, - {0x5e58, 0x75}, - {0x5e59, 0x75}, - {0x5e5a, 0x75}, - {0x5e5b, 0x75}, - {0x5e5c, 0x75}, - {0x5e5d, 0x75}, - {0x5e5e, 0x75}, - {0x5e5f, 0x75}, - {0x5e60, 0x75}, - {0x5e61, 0x75}, - {0x5e62, 0x75}, - {0x5e63, 0x75}, - {0x5e64, 0x75}, - {0x5e65, 0x75}, - {0x5e66, 0x75}, - {0x5e67, 0x75}, - {0x5e68, 0x75}, - {0x5e69, 0x75}, - {0x5e6a, 0x75}, - {0x5e6b, 0x75}, - {0x5e6c, 0x75}, - {0x5e6d, 0x75}, - {0x5e6e, 0x75}, - {0x5e6f, 0x75}, - {0x5e70, 0x75}, - {0x5e71, 0x75}, - {0x5e72, 0x75}, - {0x5e73, 0x75}, - {0x5e74, 0x75}, - {0x5e75, 0x75}, - {0x5e76, 0x75}, - {0x5e77, 0x75}, - {0x5e78, 0x75}, - {0x5e79, 0x75}, - {0x5e7a, 0x75}, - {0x5e7b, 0x75}, - {0x5e7c, 0x75}, - {0x5e7d, 0x75}, - {0x5e7e, 0x75}, - {0x5e7f, 0x75}, - {0x5e80, 0x75}, - {0x5e81, 0x75}, - {0x5e82, 0x75}, - {0x5e83, 0x75}, - {0x5e84, 0x75}, - {0x5e85, 0x75}, - {0x5e86, 0x75}, - {0x5e87, 0x75}, - {0x5e88, 0x75}, - {0x5e89, 0x75}, - {0x5e8a, 0x75}, - {0x5e8b, 0x75}, - {0x5e8c, 0x75}, - {0x5e8d, 0x75}, - {0x5e8e, 0x75}, - {0x5e8f, 0x75}, - {0x5e90, 0x75}, - {0x5e91, 0x75}, - {0x5e92, 0x75}, - {0x5e93, 0x75}, - {0x5e94, 0x75}, - {0x5e95, 0x75}, - {0x5e96, 0x75}, - {0x5e97, 0x75}, - {0x5e98, 0x75}, - {0x5e99, 0x75}, - {0x5e9a, 0x75}, - {0x5e9b, 0x75}, - {0x5e9c, 0x75}, - {0x5e9d, 0x75}, - {0x5e9e, 0x75}, - {0x5e9f, 0x75}, - {0x5ea0, 0x75}, - {0x5ea1, 0x75}, - {0x5ea2, 0x75}, - {0x5ea3, 0x75}, - {0x5ea4, 0x75}, - {0x5ea5, 0x75}, - {0x5ea6, 0x75}, - {0x5ea7, 0x75}, - {0x5ea8, 0x75}, - {0x5ea9, 0x75}, - {0x5eaa, 0x75}, - {0x5eab, 0x75}, - {0x5eac, 0x75}, - {0x5ead, 0x75}, - {0x5eae, 0x75}, - {0x5eaf, 0x75}, - {0x5eb0, 0x75}, - {0x5eb1, 0x75}, - {0x5eb2, 0x75}, - {0x5eb3, 0x75}, - {0x5eb4, 0x75}, - {0x5eb5, 0x75}, - {0x5eb6, 0x75}, - {0x5eb7, 0x75}, - {0x5eb8, 0x75}, - {0x5eb9, 0x75}, - {0x5eba, 0x75}, - {0x5ebb, 0x75}, - {0x5ebc, 0x75}, - {0x5ebd, 0x75}, - {0x5ebe, 0x75}, - {0x5ebf, 0x75}, - {0x5ec0, 0x75}, - {0x5ec1, 0x75}, - {0x5ec2, 0x75}, - {0x5ec3, 0x75}, - {0x5ec4, 0x75}, - {0x5ec5, 0x75}, - {0x5ec6, 0x75}, - {0x5ec7, 0x75}, - {0x5ec8, 0x75}, - {0x5ec9, 0x75}, - {0x5eca, 0x75}, - {0x5ecb, 0x75}, - {0x5ecc, 0x75}, - {0x5ecd, 0x75}, - {0x5ece, 0x75}, - {0x5ecf, 0x75}, - {0x5ed0, 0x75}, - {0x5ed1, 0x75}, - {0x5ed2, 0x75}, - {0x5ed3, 0x75}, - {0x5ed4, 0x75}, - {0x5ed5, 0x75}, - {0x5ed6, 0x75}, - {0x5ed7, 0x75}, - {0x5ed8, 0x75}, - {0x5ed9, 0x75}, - {0x5eda, 0x75}, - {0x5edb, 0x75}, - {0x5edc, 0x75}, - {0x5edd, 0x75}, - {0x5ede, 0x75}, - {0x5edf, 0x75}, - {0x5ee0, 0x75}, - {0x5ee1, 0x75}, - {0x5ee2, 0x75}, - {0x5ee3, 0x75}, - {0x5ee4, 0x75}, - {0x5ee5, 0x75}, - {0x5ee6, 0x75}, - {0x5ee7, 0x75}, - {0x5ee8, 0x75}, - {0x5ee9, 0x75}, - {0x5eea, 0x75}, - {0x5eeb, 0x75}, - {0x5eec, 0x75}, - {0x5eed, 0x75}, - {0x5eee, 0x75}, - {0x5eef, 0x75}, - {0x5ef0, 0x75}, - {0x5ef1, 0x75}, - {0x5ef2, 0x75}, - {0x5ef3, 0x75}, - {0x5ef4, 0x75}, - {0x5ef5, 0x75}, - {0x5ef6, 0x75}, - {0x5ef7, 0x75}, - {0x5ef8, 0x75}, - {0x5ef9, 0x75}, - {0x5efa, 0x75}, - {0x5efb, 0x75}, - {0x5efc, 0x75}, - {0x5efd, 0x75}, - {0x5efe, 0x75}, - {0x5eff, 0x75}, - {0x5f00, 0x75}, - {0x5f01, 0x75}, - {0x5f02, 0x75}, - {0x5f03, 0x75}, - {0x5f04, 0x75}, - {0x5f05, 0x75}, - {0x5f06, 0x75}, - {0x5f07, 0x75}, - {0x5f08, 0x75}, - {0x5f09, 0x75}, - {0x5f0a, 0x75}, - {0x5f0b, 0x75}, - {0x5f0c, 0x75}, - {0x5f0d, 0x75}, - {0x5f0e, 0x75}, - {0x5f0f, 0x75}, - {0x5f10, 0x75}, - {0x5f11, 0x75}, - {0x5f12, 0x75}, - {0x5f13, 0x75}, - {0x5f14, 0x75}, - {0x5f15, 0x75}, - {0x5f16, 0x75}, - {0x5f17, 0x75}, - {0x5f18, 0x75}, - {0x5f19, 0x75}, - {0x5f1a, 0x75}, - {0x5f1b, 0x75}, - {0x5f1c, 0x75}, - {0x5f1d, 0x75}, - {0x5f1e, 0x75}, - {0x5f1f, 0x75}, }; static const struct ov08x40_reg mode_1928x1208_regs[] = { @@ -2354,7 +1214,7 @@ static const char * const ov08x40_test_pattern_menu[] = { /* Configurations for supported link frequencies */ #define OV08X40_LINK_FREQ_400MHZ 400000000ULL - +#define OV08X40_SCLK_96MHZ 96000000ULL #define OV08X40_EXT_CLK 19200000 #define OV08X40_DATA_LANES 4 @@ -2392,26 +1252,30 @@ static const struct ov08x40_mode supported_modes[] = { .height = 2416, .vts_def = OV08X40_VTS_30FPS, .vts_min = OV08X40_VTS_30FPS, - .hts = 640, + .llp = 0x10aa, /* in normal mode, tline time = 2 * HTS / SCLK */ .lanes = 4, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3856x2416_regs), .regs = mode_3856x2416_regs, }, .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX, + .exposure_shift = 1, + .exposure_margin = OV08X40_EXPOSURE_MAX_MARGIN, }, { .width = 1928, .height = 1208, .vts_def = OV08X40_VTS_BIN_30FPS, .vts_min = OV08X40_VTS_BIN_30FPS, - .hts = 720, + .llp = 0x960, .lanes = 4, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1928x1208_regs), .regs = mode_1928x1208_regs, }, .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX, + .exposure_shift = 0, + .exposure_margin = OV08X40_EXPOSURE_BIN_MAX_MARGIN, }, }; @@ -2432,6 +1296,9 @@ struct ov08x40 { /* Mutex for serialized access */ struct mutex mutex; + + /* True if the device has been identified */ + bool identified; }; #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) @@ -2472,6 +1339,40 @@ static int ov08x40_read_reg(struct ov08x40 *ov08x, return 0; } +static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, + u16 last_reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); + struct i2c_msg msgs; + size_t i, num_regs; + int ret; + + num_regs = last_reg - first_reg + 1; + msgs.addr = client->addr; + msgs.flags = 0; + msgs.len = 2 + num_regs; + msgs.buf = kmalloc(msgs.len, GFP_KERNEL); + + if (!msgs.buf) + return -ENOMEM; + + put_unaligned_be16(first_reg, msgs.buf); + + for (i = 0; i < num_regs; ++i) + msgs.buf[2 + i] = val; + + ret = i2c_transfer(client->adapter, &msgs, 1); + + kfree(msgs.buf); + + if (ret != 1) { + dev_err(&client->dev, "Failed regs transferred: %d\n", ret); + return -EIO; + } + + return 0; +} + /* Write registers up to 4 at a time */ static int ov08x40_write_reg(struct ov08x40 *ov08x, u16 reg, u32 len, u32 __val) @@ -2664,13 +1565,23 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) struct ov08x40, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); s64 max; + int exp; + int fll; int ret = 0; /* Propagate change of current control to all related controls */ switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = ov08x->cur_mode->height + ctrl->val - OV08X40_EXPOSURE_MAX_MARGIN; + /* + * because in normal mode, 1 HTS = 0.5 tline + * fps = sclk / hts / vts + * so the vts value needs to be double + */ + max = ((ov08x->cur_mode->height + ctrl->val) << + ov08x->cur_mode->exposure_shift) - + ov08x->cur_mode->exposure_margin; + __v4l2_ctrl_modify_range(ov08x->exposure, ov08x->exposure->minimum, max, ov08x->exposure->step, max); @@ -2694,15 +1605,20 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov08x40_update_digital_gain(ov08x, ctrl->val); break; case V4L2_CID_EXPOSURE: + exp = (ctrl->val << ov08x->cur_mode->exposure_shift) - + ov08x->cur_mode->exposure_margin; + ret = ov08x40_write_reg(ov08x, OV08X40_REG_EXPOSURE, OV08X40_REG_VALUE_24BIT, - ctrl->val); + exp); break; case V4L2_CID_VBLANK: + fll = ((ov08x->cur_mode->height + ctrl->val) << + ov08x->cur_mode->exposure_shift); + ret = ov08x40_write_reg(ov08x, OV08X40_REG_VTS, OV08X40_REG_VALUE_16BIT, - ov08x->cur_mode->height - + ctrl->val); + fll); break; case V4L2_CID_TEST_PATTERN: ret = ov08x40_enable_test_pattern(ov08x, ctrl->val); @@ -2812,6 +1728,7 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd, s64 h_blank; s64 pixel_rate; s64 link_freq; + u64 steps; mutex_lock(&ov08x->mutex); @@ -2839,13 +1756,22 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd, ov08x->cur_mode->height; vblank_min = ov08x->cur_mode->vts_min - ov08x->cur_mode->height; + + /* + * The frame length line should be aligned to a multiple of 4, + * as provided by the sensor vendor, in normal mode. + */ + steps = mode->exposure_shift == 1 ? 4 : 1; + __v4l2_ctrl_modify_range(ov08x->vblank, vblank_min, OV08X40_VTS_MAX - ov08x->cur_mode->height, - 1, + steps, vblank_def); __v4l2_ctrl_s_ctrl(ov08x->vblank, vblank_def); - h_blank = ov08x->cur_mode->hts; + + h_blank = ov08x->cur_mode->llp - ov08x->cur_mode->width; + __v4l2_ctrl_modify_range(ov08x->hblank, h_blank, h_blank, 1, h_blank); } @@ -2887,6 +1813,22 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) return ret; } + /* Use i2c burst to write register on full size registers */ + if (ov08x->cur_mode->exposure_shift == 1) { + ret = ov08x40_burst_fill_regs(ov08x, OV08X40_REG_XTALK_FIRST_A, + OV08X40_REG_XTALK_LAST_A, 0x75); + if (ret == 0) + ret = ov08x40_burst_fill_regs(ov08x, + OV08X40_REG_XTALK_FIRST_B, + OV08X40_REG_XTALK_LAST_B, + 0x75); + } + + if (ret) { + dev_err(&client->dev, "%s failed to set regs\n", __func__); + return ret; + } + /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(ov08x->sd.ctrl_handler); if (ret) @@ -2948,6 +1890,9 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) int ret; u32 val; + if (ov08x->identified) + return 0; + ret = ov08x40_read_reg(ov08x, OV08X40_REG_CHIP_ID, OV08X40_REG_VALUE_24BIT, &val); if (ret) @@ -2956,9 +1901,11 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) if (val != OV08X40_CHIP_ID) { dev_err(&client->dev, "chip id mismatch: %x!=%x\n", OV08X40_CHIP_ID, val); - return -EIO; + return -ENXIO; } + ov08x->identified = true; + return 0; } @@ -3035,7 +1982,8 @@ static int ov08x40_init_controls(struct ov08x40 *ov08x) OV08X40_VTS_MAX - mode->height, 1, vblank_def); - hblank = ov08x->cur_mode->hts; + hblank = ov08x->cur_mode->llp - ov08x->cur_mode->width; + ov08x->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov08x40_ctrl_ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); @@ -3175,6 +2123,7 @@ static int ov08x40_probe(struct i2c_client *client) { struct ov08x40 *ov08x; int ret; + bool full_power; /* Check HW config */ ret = ov08x40_check_hwcfg(&client->dev); @@ -3190,11 +2139,14 @@ static int ov08x40_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops); - /* Check module identity */ - ret = ov08x40_identify_module(ov08x); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); - return ret; + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + /* Check module identity */ + ret = ov08x40_identify_module(ov08x); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d\n", ret); + return ret; + } } /* Set default mode to max resolution */ @@ -3222,11 +2174,8 @@ static int ov08x40_probe(struct i2c_client *client) if (ret < 0) goto error_media_entity; - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - pm_runtime_set_active(&client->dev); + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -3270,11 +2219,13 @@ static struct i2c_driver ov08x40_i2c_driver = { }, .probe = ov08x40_probe, .remove = ov08x40_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov08x40_i2c_driver); MODULE_AUTHOR("Jason Chen <jason.z.chen@intel.com>"); +MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>"); MODULE_AUTHOR("Shawn Tu"); MODULE_DESCRIPTION("OmniVision OV08X40 sensor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 1d0ef72a64..d1653d7431 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1388,7 +1388,7 @@ ov2659_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!endpoint) return NULL; diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 39d321e2b7..3ae0ea5866 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -75,6 +75,8 @@ #define OV2680_ACTIVE_START_TOP 8 #define OV2680_MIN_CROP_WIDTH 2 #define OV2680_MIN_CROP_HEIGHT 2 +#define OV2680_MIN_VBLANK 4 +#define OV2680_MAX_VBLANK 0xffff /* Fixed pre-div of 1/2 */ #define OV2680_PLL_PREDIV0 2 @@ -84,10 +86,7 @@ /* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */ #define OV2680_PIXELS_PER_LINE 1704 -#define OV2680_LINES_PER_FRAME 1294 - -/* If possible send 16 extra rows / lines to the ISP as padding */ -#define OV2680_END_MARGIN 16 +#define OV2680_LINES_PER_FRAME_30FPS 1294 /* Max exposure time is VTS - 8 */ #define OV2680_INTEGRATION_TIME_MARGIN 8 @@ -130,6 +129,8 @@ struct ov2680_ctrls { struct v4l2_ctrl *test_pattern; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; }; struct ov2680_mode { @@ -143,8 +144,6 @@ struct ov2680_mode { u16 v_end; u16 h_output_size; u16 v_output_size; - u16 hts; - u16 vts; }; struct ov2680_dev { @@ -359,15 +358,11 @@ static void ov2680_calc_mode(struct ov2680_dev *sensor) sensor->mode.v_start = (sensor->mode.crop.top + (sensor->mode.crop.height - height) / 2) & ~1; sensor->mode.h_end = - min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1, - OV2680_NATIVE_WIDTH - 1); + min(sensor->mode.h_start + width - 1, OV2680_NATIVE_WIDTH - 1); sensor->mode.v_end = - min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1, - OV2680_NATIVE_HEIGHT - 1); + min(sensor->mode.v_start + height - 1, OV2680_NATIVE_HEIGHT - 1); sensor->mode.h_output_size = orig_width; sensor->mode.v_output_size = orig_height; - sensor->mode.hts = OV2680_PIXELS_PER_LINE; - sensor->mode.vts = OV2680_LINES_PER_FRAME; } static int ov2680_set_mode(struct ov2680_dev *sensor) @@ -402,9 +397,8 @@ static int ov2680_set_mode(struct ov2680_dev *sensor) cci_write(sensor->regmap, OV2680_REG_VERTICAL_OUTPUT_SIZE, sensor->mode.v_output_size, &ret); cci_write(sensor->regmap, OV2680_REG_TIMING_HTS, - sensor->mode.hts, &ret); - cci_write(sensor->regmap, OV2680_REG_TIMING_VTS, - sensor->mode.vts, &ret); + OV2680_PIXELS_PER_LINE, &ret); + /* VTS gets set by the vblank ctrl */ cci_write(sensor->regmap, OV2680_REG_ISP_X_WIN, 0, &ret); cci_write(sensor->regmap, OV2680_REG_ISP_Y_WIN, 0, &ret); cci_write(sensor->regmap, OV2680_REG_X_INC, inc, &ret); @@ -478,6 +472,15 @@ static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp) NULL); } +static int ov2680_exposure_update_range(struct ov2680_dev *sensor) +{ + int exp_max = sensor->mode.fmt.height + sensor->ctrls.vblank->val - + OV2680_INTEGRATION_TIME_MARGIN; + + return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max, + 1, exp_max); +} + static int ov2680_stream_enable(struct ov2680_dev *sensor) { int ret; @@ -644,7 +647,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *try_fmt; const struct v4l2_rect *crop; unsigned int width, height; - int ret = 0; + int def, max, ret = 0; crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad, format->which); @@ -673,6 +676,27 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, sensor->mode.fmt = format->format; ov2680_calc_mode(sensor); + /* vblank range is height dependent adjust and reset to default */ + max = OV2680_MAX_VBLANK - height; + def = OV2680_LINES_PER_FRAME_30FPS - height; + ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV2680_MIN_VBLANK, + max, 1, def); + if (ret) + goto unlock; + + ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, def); + if (ret) + goto unlock; + + /* exposure range depends on vts which may have changed */ + ret = ov2680_exposure_update_range(sensor); + if (ret) + goto unlock; + + /* adjust hblank value for new width */ + def = OV2680_PIXELS_PER_LINE - width; + ret = __v4l2_ctrl_modify_range(sensor->ctrls.hblank, def, def, 1, def); + unlock: mutex_unlock(&sensor->lock); @@ -842,6 +866,13 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) struct ov2680_dev *sensor = to_ov2680_dev(sd); int ret; + /* Update exposure range on vblank changes */ + if (ctrl->id == V4L2_CID_VBLANK) { + ret = ov2680_exposure_update_range(sensor); + if (ret) + return ret; + } + /* Only apply changes to the controls if the device is powered up */ if (!pm_runtime_get_if_in_use(sensor->sd.dev)) { ov2680_set_bayer_order(sensor, &sensor->mode.fmt); @@ -864,6 +895,10 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: ret = ov2680_test_pattern_set(sensor, ctrl->val); break; + case V4L2_CID_VBLANK: + ret = cci_write(sensor->regmap, OV2680_REG_TIMING_VTS, + sensor->mode.fmt.height + ctrl->val, NULL); + break; default: ret = -EINVAL; break; @@ -922,8 +957,8 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; struct ov2680_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; - int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN; - int ret = 0; + struct v4l2_fwnode_device_properties props; + int def, max, ret = 0; v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops); sensor->sd.internal_ops = &ov2680_internal_ops; @@ -948,8 +983,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, test_pattern_menu); + max = OV2680_LINES_PER_FRAME_30FPS - OV2680_INTEGRATION_TIME_MARGIN; ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, - 0, exp_max, 1, exp_max); + 0, max, 1, max); ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 1023, 1, 250); @@ -960,6 +996,21 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) 0, sensor->pixel_rate, 1, sensor->pixel_rate); + max = OV2680_MAX_VBLANK - OV2680_DEFAULT_HEIGHT; + def = OV2680_LINES_PER_FRAME_30FPS - OV2680_DEFAULT_HEIGHT; + ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + OV2680_MIN_VBLANK, max, 1, def); + + def = OV2680_PIXELS_PER_LINE - OV2680_DEFAULT_WIDTH; + ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, + def, def, 1, def); + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret) + goto cleanup_entity; + + v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); + if (hdl->error) { ret = hdl->error; goto cleanup_entity; @@ -968,6 +1019,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; sensor->sd.ctrl_handler = hdl; @@ -1116,25 +1168,24 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) sensor->pixel_rate = sensor->link_freq[0] * 2; do_div(sensor->pixel_rate, 10); - /* Verify bus cfg */ - if (bus_cfg.bus.mipi_csi2.num_data_lanes != 1) { - ret = dev_err_probe(dev, -EINVAL, - "only a 1-lane CSI2 config is supported"); - goto out_free_bus_cfg; + if (!bus_cfg.nr_of_link_frequencies) { + dev_warn(dev, "Consider passing 'link-frequencies' in DT\n"); + goto skip_link_freq_validation; } for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) if (bus_cfg.link_frequencies[i] == sensor->link_freq[0]) break; - if (bus_cfg.nr_of_link_frequencies == 0 || - bus_cfg.nr_of_link_frequencies == i) { + if (bus_cfg.nr_of_link_frequencies == i) { ret = dev_err_probe(dev, -EINVAL, "supported link freq %lld not found\n", sensor->link_freq[0]); goto out_free_bus_cfg; } +skip_link_freq_validation: + ret = 0; out_free_bus_cfg: v4l2_fwnode_endpoint_free(&bus_cfg); return ret; diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 552935ccb4..c48dbcde98 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -768,14 +768,15 @@ static int ov2740_init_controls(struct ov2740 *ov2740) cur_mode = ov2740->cur_mode; size = ARRAY_SIZE(link_freq_menu_items); - ov2740->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops, - V4L2_CID_LINK_FREQ, - size - 1, 0, - link_freq_menu_items); + ov2740->link_freq = + v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops, + V4L2_CID_LINK_FREQ, size - 1, + ov2740->supported_modes->link_freq_index, + link_freq_menu_items); if (ov2740->link_freq) ov2740->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - pixel_rate = to_pixel_rate(OV2740_LINK_FREQ_360MHZ_INDEX); + pixel_rate = to_pixel_rate(ov2740->supported_modes->link_freq_index); ov2740->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, pixel_rate); @@ -1332,9 +1333,16 @@ static int ov2740_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "failed to check HW configuration\n"); ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ov2740->reset_gpio)) + if (IS_ERR(ov2740->reset_gpio)) { return dev_err_probe(dev, PTR_ERR(ov2740->reset_gpio), "failed to get reset GPIO\n"); + } else if (ov2740->reset_gpio) { + /* + * Ensure reset is asserted for at least 20 ms before + * ov2740_resume() deasserts it. + */ + msleep(20); + } ov2740->clk = devm_clk_get_optional(dev, "clk"); if (IS_ERR(ov2740->clk)) diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index 4030916518..1c3a449f93 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -3,7 +3,7 @@ * ov4689 driver * * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. - * Copyright (C) 2022 Mikhail Rudenko + * Copyright (C) 2022, 2024 Mikhail Rudenko */ #include <linux/clk.h> @@ -15,45 +15,86 @@ #include <linux/regulator/consumer.h> #include <media/media-entity.h> #include <media/v4l2-async.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> #include <media/v4l2-fwnode.h> -#define CHIP_ID 0x004688 -#define OV4689_REG_CHIP_ID 0x300a - -#define OV4689_XVCLK_FREQ 24000000 - -#define OV4689_REG_CTRL_MODE 0x0100 +#define OV4689_REG_CTRL_MODE CCI_REG8(0x0100) #define OV4689_MODE_SW_STANDBY 0x0 #define OV4689_MODE_STREAMING BIT(0) -#define OV4689_REG_EXPOSURE 0x3500 +#define OV4689_REG_CHIP_ID CCI_REG16(0x300a) +#define CHIP_ID 0x004688 + +#define OV4689_REG_EXPOSURE CCI_REG24(0x3500) #define OV4689_EXPOSURE_MIN 4 #define OV4689_EXPOSURE_STEP 1 -#define OV4689_VTS_MAX 0x7fff -#define OV4689_REG_GAIN_H 0x3508 -#define OV4689_REG_GAIN_L 0x3509 -#define OV4689_GAIN_H_MASK 0x07 -#define OV4689_GAIN_H_SHIFT 8 -#define OV4689_GAIN_L_MASK 0xff +#define OV4689_REG_GAIN CCI_REG16(0x3508) #define OV4689_GAIN_STEP 1 #define OV4689_GAIN_DEFAULT 0x80 -#define OV4689_REG_TEST_PATTERN 0x5040 -#define OV4689_TEST_PATTERN_ENABLE 0x80 -#define OV4689_TEST_PATTERN_DISABLE 0x0 +#define OV4689_REG_DIG_GAIN CCI_REG16(0x352a) +#define OV4689_DIG_GAIN_MIN 1 +#define OV4689_DIG_GAIN_MAX 0x7fff +#define OV4689_DIG_GAIN_STEP 1 +#define OV4689_DIG_GAIN_DEFAULT 0x800 -#define OV4689_REG_VTS 0x380e +#define OV4689_REG_H_CROP_START CCI_REG16(0x3800) +#define OV4689_REG_V_CROP_START CCI_REG16(0x3802) +#define OV4689_REG_H_CROP_END CCI_REG16(0x3804) +#define OV4689_REG_V_CROP_END CCI_REG16(0x3806) +#define OV4689_REG_H_OUTPUT_SIZE CCI_REG16(0x3808) +#define OV4689_REG_V_OUTPUT_SIZE CCI_REG16(0x380a) -#define REG_NULL 0xFFFF +#define OV4689_REG_HTS CCI_REG16(0x380c) +#define OV4689_HTS_DIVIDER 4 +#define OV4689_HTS_MAX 0x7fff -#define OV4689_REG_VALUE_08BIT 1 -#define OV4689_REG_VALUE_16BIT 2 -#define OV4689_REG_VALUE_24BIT 3 +#define OV4689_REG_VTS CCI_REG16(0x380e) +#define OV4689_VTS_MAX 0x7fff + +#define OV4689_REG_H_WIN_OFF CCI_REG16(0x3810) +#define OV4689_REG_V_WIN_OFF CCI_REG16(0x3812) + +#define OV4689_REG_TIMING_FORMAT1 CCI_REG8(0x3820) /* Vertical */ +#define OV4689_REG_TIMING_FORMAT2 CCI_REG8(0x3821) /* Horizontal */ +#define OV4689_TIMING_FLIP_MASK GENMASK(2, 1) +#define OV4689_TIMING_FLIP_ARRAY BIT(1) +#define OV4689_TIMING_FLIP_DIGITAL BIT(2) +#define OV4689_TIMING_FLIP_BOTH (OV4689_TIMING_FLIP_ARRAY |\ + OV4689_TIMING_FLIP_DIGITAL) + +#define OV4689_REG_ANCHOR_LEFT_START CCI_REG16(0x4020) +#define OV4689_ANCHOR_LEFT_START_DEF 576 +#define OV4689_REG_ANCHOR_LEFT_END CCI_REG16(0x4022) +#define OV4689_ANCHOR_LEFT_END_DEF 831 +#define OV4689_REG_ANCHOR_RIGHT_START CCI_REG16(0x4024) +#define OV4689_ANCHOR_RIGHT_START_DEF 1984 +#define OV4689_REG_ANCHOR_RIGHT_END CCI_REG16(0x4026) +#define OV4689_ANCHOR_RIGHT_END_DEF 2239 + +#define OV4689_REG_VFIFO_CTRL_01 CCI_REG8(0x4601) + +#define OV4689_REG_WB_GAIN_RED CCI_REG16(0x500c) +#define OV4689_REG_WB_GAIN_BLUE CCI_REG16(0x5010) +#define OV4689_WB_GAIN_MIN 1 +#define OV4689_WB_GAIN_MAX 0xfff +#define OV4689_WB_GAIN_STEP 1 +#define OV4689_WB_GAIN_DEFAULT 0x400 + +#define OV4689_REG_TEST_PATTERN CCI_REG8(0x5040) +#define OV4689_TEST_PATTERN_ENABLE 0x80 +#define OV4689_TEST_PATTERN_DISABLE 0x0 #define OV4689_LANES 4 +#define OV4689_XVCLK_FREQ 24000000 + +#define OV4689_PIXEL_ARRAY_WIDTH 2720 +#define OV4689_PIXEL_ARRAY_HEIGHT 1536 +#define OV4689_DUMMY_ROWS 8 /* 8 dummy rows on each side */ +#define OV4689_DUMMY_COLUMNS 16 /* 16 dummy columns on each side */ static const char *const ov4689_supply_names[] = { "avdd", /* Analog power */ @@ -61,11 +102,6 @@ static const char *const ov4689_supply_names[] = { "dvdd", /* Digital core power */ }; -struct regval { - u16 addr; - u8 val; -}; - enum ov4689_mode_id { OV4689_MODE_2688_1520 = 0, OV4689_NUM_MODES, @@ -75,20 +111,18 @@ struct ov4689_mode { enum ov4689_mode_id id; u32 width; u32 height; - u32 max_fps; u32 hts_def; + u32 hts_min; u32 vts_def; u32 exp_def; u32 pixel_rate; - u32 sensor_width; - u32 sensor_height; - u32 crop_top; - u32 crop_left; - const struct regval *reg_list; + const struct cci_reg_sequence *reg_list; + unsigned int num_regs; }; struct ov4689 { - struct i2c_client *client; + struct device *dev; + struct regmap *regmap; struct clk *xvclk; struct gpio_desc *reset_gpio; struct gpio_desc *pwdn_gpio; @@ -99,7 +133,6 @@ struct ov4689 { u32 clock_rate; - struct mutex mutex; /* lock to protect ctrls and cur_mode */ struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *exposure; @@ -119,95 +152,108 @@ struct ov4689_gain_range { /* * Xclk 24Mhz - * max_framerate 30fps + * max_framerate 90fps * mipi_datarate per lane 1008Mbps */ -static const struct regval ov4689_2688x1520_regs[] = { - {0x0103, 0x01}, {0x3638, 0x00}, {0x0300, 0x00}, - {0x0302, 0x2a}, {0x0303, 0x00}, {0x0304, 0x03}, - {0x030b, 0x00}, {0x030d, 0x1e}, {0x030e, 0x04}, - {0x030f, 0x01}, {0x0312, 0x01}, {0x031e, 0x00}, - {0x3000, 0x20}, {0x3002, 0x00}, {0x3018, 0x72}, - {0x3020, 0x93}, {0x3021, 0x03}, {0x3022, 0x01}, - {0x3031, 0x0a}, {0x303f, 0x0c}, {0x3305, 0xf1}, - {0x3307, 0x04}, {0x3309, 0x29}, {0x3500, 0x00}, - {0x3501, 0x60}, {0x3502, 0x00}, {0x3503, 0x04}, - {0x3504, 0x00}, {0x3505, 0x00}, {0x3506, 0x00}, - {0x3507, 0x00}, {0x3508, 0x00}, {0x3509, 0x80}, - {0x350a, 0x00}, {0x350b, 0x00}, {0x350c, 0x00}, - {0x350d, 0x00}, {0x350e, 0x00}, {0x350f, 0x80}, - {0x3510, 0x00}, {0x3511, 0x00}, {0x3512, 0x00}, - {0x3513, 0x00}, {0x3514, 0x00}, {0x3515, 0x80}, - {0x3516, 0x00}, {0x3517, 0x00}, {0x3518, 0x00}, - {0x3519, 0x00}, {0x351a, 0x00}, {0x351b, 0x80}, - {0x351c, 0x00}, {0x351d, 0x00}, {0x351e, 0x00}, - {0x351f, 0x00}, {0x3520, 0x00}, {0x3521, 0x80}, - {0x3522, 0x08}, {0x3524, 0x08}, {0x3526, 0x08}, - {0x3528, 0x08}, {0x352a, 0x08}, {0x3602, 0x00}, - {0x3603, 0x40}, {0x3604, 0x02}, {0x3605, 0x00}, - {0x3606, 0x00}, {0x3607, 0x00}, {0x3609, 0x12}, - {0x360a, 0x40}, {0x360c, 0x08}, {0x360f, 0xe5}, - {0x3608, 0x8f}, {0x3611, 0x00}, {0x3613, 0xf7}, - {0x3616, 0x58}, {0x3619, 0x99}, {0x361b, 0x60}, - {0x361c, 0x7a}, {0x361e, 0x79}, {0x361f, 0x02}, - {0x3632, 0x00}, {0x3633, 0x10}, {0x3634, 0x10}, - {0x3635, 0x10}, {0x3636, 0x15}, {0x3646, 0x86}, - {0x364a, 0x0b}, {0x3700, 0x17}, {0x3701, 0x22}, - {0x3703, 0x10}, {0x370a, 0x37}, {0x3705, 0x00}, - {0x3706, 0x63}, {0x3709, 0x3c}, {0x370b, 0x01}, - {0x370c, 0x30}, {0x3710, 0x24}, {0x3711, 0x0c}, - {0x3716, 0x00}, {0x3720, 0x28}, {0x3729, 0x7b}, - {0x372a, 0x84}, {0x372b, 0xbd}, {0x372c, 0xbc}, - {0x372e, 0x52}, {0x373c, 0x0e}, {0x373e, 0x33}, - {0x3743, 0x10}, {0x3744, 0x88}, {0x3745, 0xc0}, - {0x374a, 0x43}, {0x374c, 0x00}, {0x374e, 0x23}, - {0x3751, 0x7b}, {0x3752, 0x84}, {0x3753, 0xbd}, - {0x3754, 0xbc}, {0x3756, 0x52}, {0x375c, 0x00}, - {0x3760, 0x00}, {0x3761, 0x00}, {0x3762, 0x00}, - {0x3763, 0x00}, {0x3764, 0x00}, {0x3767, 0x04}, - {0x3768, 0x04}, {0x3769, 0x08}, {0x376a, 0x08}, - {0x376b, 0x20}, {0x376c, 0x00}, {0x376d, 0x00}, - {0x376e, 0x00}, {0x3773, 0x00}, {0x3774, 0x51}, - {0x3776, 0xbd}, {0x3777, 0xbd}, {0x3781, 0x18}, - {0x3783, 0x25}, {0x3798, 0x1b}, {0x3800, 0x00}, - {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x04}, - {0x3804, 0x0a}, {0x3805, 0x97}, {0x3806, 0x05}, - {0x3807, 0xfb}, {0x3808, 0x0a}, {0x3809, 0x80}, - {0x380a, 0x05}, {0x380b, 0xf0}, {0x380c, 0x0a}, - {0x380d, 0x0e}, {0x380e, 0x06}, {0x380f, 0x12}, - {0x3810, 0x00}, {0x3811, 0x08}, {0x3812, 0x00}, - {0x3813, 0x04}, {0x3814, 0x01}, {0x3815, 0x01}, - {0x3819, 0x01}, {0x3820, 0x00}, {0x3821, 0x06}, - {0x3829, 0x00}, {0x382a, 0x01}, {0x382b, 0x01}, - {0x382d, 0x7f}, {0x3830, 0x04}, {0x3836, 0x01}, - {0x3837, 0x00}, {0x3841, 0x02}, {0x3846, 0x08}, - {0x3847, 0x07}, {0x3d85, 0x36}, {0x3d8c, 0x71}, - {0x3d8d, 0xcb}, {0x3f0a, 0x00}, {0x4000, 0xf1}, - {0x4001, 0x40}, {0x4002, 0x04}, {0x4003, 0x14}, - {0x400e, 0x00}, {0x4011, 0x00}, {0x401a, 0x00}, - {0x401b, 0x00}, {0x401c, 0x00}, {0x401d, 0x00}, - {0x401f, 0x00}, {0x4020, 0x00}, {0x4021, 0x10}, - {0x4022, 0x07}, {0x4023, 0xcf}, {0x4024, 0x09}, - {0x4025, 0x60}, {0x4026, 0x09}, {0x4027, 0x6f}, - {0x4028, 0x00}, {0x4029, 0x02}, {0x402a, 0x06}, - {0x402b, 0x04}, {0x402c, 0x02}, {0x402d, 0x02}, - {0x402e, 0x0e}, {0x402f, 0x04}, {0x4302, 0xff}, - {0x4303, 0xff}, {0x4304, 0x00}, {0x4305, 0x00}, - {0x4306, 0x00}, {0x4308, 0x02}, {0x4500, 0x6c}, - {0x4501, 0xc4}, {0x4502, 0x40}, {0x4503, 0x01}, - {0x4601, 0xa7}, {0x4800, 0x04}, {0x4813, 0x08}, - {0x481f, 0x40}, {0x4829, 0x78}, {0x4837, 0x10}, - {0x4b00, 0x2a}, {0x4b0d, 0x00}, {0x4d00, 0x04}, - {0x4d01, 0x42}, {0x4d02, 0xd1}, {0x4d03, 0x93}, - {0x4d04, 0xf5}, {0x4d05, 0xc1}, {0x5000, 0xf3}, - {0x5001, 0x11}, {0x5004, 0x00}, {0x500a, 0x00}, - {0x500b, 0x00}, {0x5032, 0x00}, {0x5040, 0x00}, - {0x5050, 0x0c}, {0x5500, 0x00}, {0x5501, 0x10}, - {0x5502, 0x01}, {0x5503, 0x0f}, {0x8000, 0x00}, - {0x8001, 0x00}, {0x8002, 0x00}, {0x8003, 0x00}, - {0x8004, 0x00}, {0x8005, 0x00}, {0x8006, 0x00}, - {0x8007, 0x00}, {0x8008, 0x00}, {0x3638, 0x00}, - {REG_NULL, 0x00}, +static const struct cci_reg_sequence ov4689_2688x1520_regs[] = { + /* System control*/ + { CCI_REG8(0x0103), 0x01 }, /* SC_CTRL0103 software_reset = 1 */ + { CCI_REG8(0x3000), 0x20 }, /* SC_CMMN_PAD_OEN0 FSIN_output_enable = 1 */ + { CCI_REG8(0x3021), 0x03 }, /* + * SC_CMMN_MISC_CTRL fst_stby_ctr = 0, + * sleep_no_latch_enable = 0 + */ + + /* AEC PK */ + { CCI_REG8(0x3503), 0x04 }, /* AEC_MANUAL gain_input_as_sensor_gain_format = 1 */ + + /* ADC and analog control*/ + { CCI_REG8(0x3603), 0x40 }, + { CCI_REG8(0x3604), 0x02 }, + { CCI_REG8(0x3609), 0x12 }, + { CCI_REG8(0x360c), 0x08 }, + { CCI_REG8(0x360f), 0xe5 }, + { CCI_REG8(0x3608), 0x8f }, + { CCI_REG8(0x3611), 0x00 }, + { CCI_REG8(0x3613), 0xf7 }, + { CCI_REG8(0x3616), 0x58 }, + { CCI_REG8(0x3619), 0x99 }, + { CCI_REG8(0x361b), 0x60 }, + { CCI_REG8(0x361e), 0x79 }, + { CCI_REG8(0x3634), 0x10 }, + { CCI_REG8(0x3635), 0x10 }, + { CCI_REG8(0x3636), 0x15 }, + { CCI_REG8(0x3646), 0x86 }, + { CCI_REG8(0x364a), 0x0b }, + + /* Sensor control */ + { CCI_REG8(0x3700), 0x17 }, + { CCI_REG8(0x3701), 0x22 }, + { CCI_REG8(0x3703), 0x10 }, + { CCI_REG8(0x370a), 0x37 }, + { CCI_REG8(0x3706), 0x63 }, + { CCI_REG8(0x3709), 0x3c }, + { CCI_REG8(0x370c), 0x30 }, + { CCI_REG8(0x3710), 0x24 }, + { CCI_REG8(0x3720), 0x28 }, + { CCI_REG8(0x3729), 0x7b }, + { CCI_REG8(0x372b), 0xbd }, + { CCI_REG8(0x372c), 0xbc }, + { CCI_REG8(0x372e), 0x52 }, + { CCI_REG8(0x373c), 0x0e }, + { CCI_REG8(0x373e), 0x33 }, + { CCI_REG8(0x3743), 0x10 }, + { CCI_REG8(0x3744), 0x88 }, + { CCI_REG8(0x3745), 0xc0 }, + { CCI_REG8(0x374c), 0x00 }, + { CCI_REG8(0x374e), 0x23 }, + { CCI_REG8(0x3751), 0x7b }, + { CCI_REG8(0x3753), 0xbd }, + { CCI_REG8(0x3754), 0xbc }, + { CCI_REG8(0x3756), 0x52 }, + { CCI_REG8(0x376b), 0x20 }, + { CCI_REG8(0x3774), 0x51 }, + { CCI_REG8(0x3776), 0xbd }, + { CCI_REG8(0x3777), 0xbd }, + { CCI_REG8(0x3781), 0x18 }, + { CCI_REG8(0x3783), 0x25 }, + { CCI_REG8(0x3798), 0x1b }, + + /* Timing control */ + { CCI_REG8(0x3819), 0x01 }, /* VSYNC_END_L vsync_end_point[7:0] = 0x01 */ + + /* OTP control */ + { CCI_REG8(0x3d85), 0x36 }, /* OTP_REG85 OTP_power_up_load_setting_enable = 1, + * OTP_power_up_load_data_enable = 1, + * OTP_bist_select = 1 (compare with zero) + */ + { CCI_REG8(0x3d8c), 0x71 }, /* OTP_SETTING_STT_ADDRESS_H */ + { CCI_REG8(0x3d8d), 0xcb }, /* OTP_SETTING_STT_ADDRESS_L */ + + /* BLC registers*/ + { CCI_REG8(0x4001), 0x40 }, /* DEBUG_MODE */ + { CCI_REG8(0x401b), 0x00 }, /* DEBUG_MODE */ + { CCI_REG8(0x401d), 0x00 }, /* DEBUG_MODE */ + { CCI_REG8(0x401f), 0x00 }, /* DEBUG_MODE */ + + /* ADC sync control */ + { CCI_REG8(0x4500), 0x6c }, /* ADC_SYNC_CTRL */ + { CCI_REG8(0x4503), 0x01 }, /* ADC_SYNC_CTRL */ + + /* Temperature monitor */ + { CCI_REG8(0x4d00), 0x04 }, /* TPM_CTRL_00 tmp_slope[15:8] = 0x04 */ + { CCI_REG8(0x4d01), 0x42 }, /* TPM_CTRL_01 tmp_slope[7:0] = 0x42 */ + { CCI_REG8(0x4d02), 0xd1 }, /* TPM_CTRL_02 tpm_offset[31:24] = 0xd1 */ + { CCI_REG8(0x4d03), 0x93 }, /* TPM_CTRL_03 tpm_offset[23:16] = 0x93 */ + { CCI_REG8(0x4d04), 0xf5 }, /* TPM_CTRL_04 tpm_offset[15:8] = 0xf5 */ + { CCI_REG8(0x4d05), 0xc1 }, /* TPM_CTRL_05 tpm_offset[7:0] = 0xc1 */ + + /* pre-ISP control */ + { CCI_REG8(0x5050), 0x0c }, /* DEBUG_MODE */ + + /* OTP-DPC control */ + { CCI_REG8(0x5501), 0x10 }, /* OTP_DPC_START_L otp_start_address[7:0] = 0x10 */ + { CCI_REG8(0x5503), 0x0f }, /* OTP_DPC_END_L otp_end_address[7:0] = 0x0f */ }; static const struct ov4689_mode supported_modes[] = { @@ -215,16 +261,13 @@ static const struct ov4689_mode supported_modes[] = { .id = OV4689_MODE_2688_1520, .width = 2688, .height = 1520, - .sensor_width = 2720, - .sensor_height = 1536, - .crop_top = 8, - .crop_left = 16, - .max_fps = 30, .exp_def = 1536, - .hts_def = 4 * 2574, + .hts_def = 10296, + .hts_min = 3432, .vts_def = 1554, .pixel_rate = 480000000, .reg_list = ov4689_2688x1520_regs, + .num_regs = ARRAY_SIZE(ov4689_2688x1520_regs), }, }; @@ -277,83 +320,6 @@ static const struct ov4689_gain_range ov4689_gain_ranges[] = { }, }; -/* Write registers up to 4 at a time */ -static int ov4689_write_reg(struct i2c_client *client, u16 reg, u32 len, - u32 val) -{ - u32 buf_i, val_i; - __be32 val_be; - u8 *val_p; - u8 buf[6]; - - if (len > 4) - return -EINVAL; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - - val_be = cpu_to_be32(val); - val_p = (u8 *)&val_be; - buf_i = 2; - val_i = 4 - len; - - while (val_i < 4) - buf[buf_i++] = val_p[val_i++]; - - if (i2c_master_send(client, buf, len + 2) != len + 2) - return -EIO; - - return 0; -} - -static int ov4689_write_array(struct i2c_client *client, - const struct regval *regs) -{ - int ret = 0; - u32 i; - - for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) - ret = ov4689_write_reg(client, regs[i].addr, - OV4689_REG_VALUE_08BIT, regs[i].val); - - return ret; -} - -/* Read registers up to 4 at a time */ -static int ov4689_read_reg(struct i2c_client *client, u16 reg, unsigned int len, - u32 *val) -{ - __be16 reg_addr_be = cpu_to_be16(reg); - struct i2c_msg msgs[2]; - __be32 data_be = 0; - u8 *data_be_p; - int ret; - - if (len > 4 || !len) - return -EINVAL; - - data_be_p = (u8 *)&data_be; - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = 2; - msgs[0].buf = (u8 *)®_addr_be; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_be_p[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *val = be32_to_cpu(data_be); - - return 0; -} - static void ov4689_fill_fmt(const struct ov4689_mode *mode, struct v4l2_mbus_framefmt *fmt) { @@ -376,19 +342,6 @@ static int ov4689_set_fmt(struct v4l2_subdev *sd, return 0; } -static int ov4689_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; - struct ov4689 *ov4689 = to_ov4689(sd); - - /* only one mode supported for now */ - ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt); - - return 0; -} - static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -427,16 +380,14 @@ static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern) else val = OV4689_TEST_PATTERN_DISABLE; - return ov4689_write_reg(ov4689->client, OV4689_REG_TEST_PATTERN, - OV4689_REG_VALUE_08BIT, val); + return cci_write(ov4689->regmap, OV4689_REG_TEST_PATTERN, + val, NULL); } static int ov4689_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_selection *sel) { - const struct ov4689_mode *mode = to_ov4689(sd)->cur_mode; - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; @@ -444,63 +395,114 @@ static int ov4689_get_selection(struct v4l2_subdev *sd, case V4L2_SEL_TGT_CROP_BOUNDS: sel->r.top = 0; sel->r.left = 0; - sel->r.width = mode->sensor_width; - sel->r.height = mode->sensor_height; + sel->r.width = OV4689_PIXEL_ARRAY_WIDTH; + sel->r.height = OV4689_PIXEL_ARRAY_HEIGHT; return 0; case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.top = mode->crop_top; - sel->r.left = mode->crop_left; - sel->r.width = mode->width; - sel->r.height = mode->height; + sel->r.top = OV4689_DUMMY_ROWS; + sel->r.left = OV4689_DUMMY_COLUMNS; + sel->r.width = + OV4689_PIXEL_ARRAY_WIDTH - 2 * OV4689_DUMMY_COLUMNS; + sel->r.height = + OV4689_PIXEL_ARRAY_HEIGHT - 2 * OV4689_DUMMY_ROWS; return 0; } return -EINVAL; } +static int ov4689_setup_timings(struct ov4689 *ov4689) +{ + const struct ov4689_mode *mode = ov4689->cur_mode; + struct regmap *rm = ov4689->regmap; + int ret = 0; + + cci_write(rm, OV4689_REG_H_CROP_START, 8, &ret); + cci_write(rm, OV4689_REG_V_CROP_START, 8, &ret); + cci_write(rm, OV4689_REG_H_CROP_END, 2711, &ret); + cci_write(rm, OV4689_REG_V_CROP_END, 1531, &ret); + + cci_write(rm, OV4689_REG_H_OUTPUT_SIZE, mode->width, &ret); + cci_write(rm, OV4689_REG_V_OUTPUT_SIZE, mode->height, &ret); + + cci_write(rm, OV4689_REG_H_WIN_OFF, 8, &ret); + cci_write(rm, OV4689_REG_V_WIN_OFF, 4, &ret); + + cci_write(rm, OV4689_REG_VFIFO_CTRL_01, 167, &ret); + + return ret; +} + +static int ov4689_setup_blc_anchors(struct ov4689 *ov4689) +{ + struct regmap *rm = ov4689->regmap; + int ret = 0; + + cci_write(rm, OV4689_REG_ANCHOR_LEFT_START, 16, &ret); + cci_write(rm, OV4689_REG_ANCHOR_LEFT_END, 1999, &ret); + cci_write(rm, OV4689_REG_ANCHOR_RIGHT_START, 2400, &ret); + cci_write(rm, OV4689_REG_ANCHOR_RIGHT_END, 2415, &ret); + + return ret; +} + static int ov4689_s_stream(struct v4l2_subdev *sd, int on) { struct ov4689 *ov4689 = to_ov4689(sd); - struct i2c_client *client = ov4689->client; + struct v4l2_subdev_state *sd_state; + struct device *dev = ov4689->dev; int ret = 0; - mutex_lock(&ov4689->mutex); + sd_state = v4l2_subdev_lock_and_get_active_state(&ov4689->subdev); if (on) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) goto unlock_and_return; - ret = ov4689_write_array(ov4689->client, - ov4689->cur_mode->reg_list); + ret = cci_multi_reg_write(ov4689->regmap, + ov4689->cur_mode->reg_list, + ov4689->cur_mode->num_regs, + NULL); + if (ret) { + pm_runtime_put(dev); + goto unlock_and_return; + } + + ret = ov4689_setup_timings(ov4689); if (ret) { - pm_runtime_put(&client->dev); + pm_runtime_put(dev); + goto unlock_and_return; + } + + ret = ov4689_setup_blc_anchors(ov4689); + if (ret) { + pm_runtime_put(dev); goto unlock_and_return; } ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler); if (ret) { - pm_runtime_put(&client->dev); + pm_runtime_put(dev); goto unlock_and_return; } - ret = ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE, - OV4689_REG_VALUE_08BIT, - OV4689_MODE_STREAMING); + ret = cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, + OV4689_MODE_STREAMING, NULL); if (ret) { - pm_runtime_put(&client->dev); + pm_runtime_put(dev); goto unlock_and_return; } } else { - ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE, - OV4689_REG_VALUE_08BIT, - OV4689_MODE_SW_STANDBY); - pm_runtime_put(&client->dev); + cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, + OV4689_MODE_SW_STANDBY, NULL); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } unlock_and_return: - mutex_unlock(&ov4689->mutex); + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -563,18 +565,13 @@ static int __maybe_unused ov4689_power_off(struct device *dev) return 0; } -static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int ov4689_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct ov4689 *ov4689 = to_ov4689(sd); - struct v4l2_mbus_framefmt *try_fmt; - - mutex_lock(&ov4689->mutex); - - try_fmt = v4l2_subdev_state_get_format(fh->state, 0); - /* Initialize try_fmt */ - ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt); + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_state_get_format(sd_state, 0); - mutex_unlock(&ov4689->mutex); + ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], fmt); return 0; } @@ -583,10 +580,6 @@ static const struct dev_pm_ops ov4689_pm_ops = { SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL) }; -static const struct v4l2_subdev_internal_ops ov4689_internal_ops = { - .open = ov4689_open, -}; - static const struct v4l2_subdev_video_ops ov4689_video_ops = { .s_stream = ov4689_s_stream, }; @@ -594,11 +587,15 @@ static const struct v4l2_subdev_video_ops ov4689_video_ops = { static const struct v4l2_subdev_pad_ops ov4689_pad_ops = { .enum_mbus_code = ov4689_enum_mbus_code, .enum_frame_size = ov4689_enum_frame_sizes, - .get_fmt = ov4689_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ov4689_set_fmt, .get_selection = ov4689_get_selection, }; +static const struct v4l2_subdev_internal_ops ov4689_internal_ops = { + .init_state = ov4689_init_state, +}; + static const struct v4l2_subdev_ops ov4689_subdev_ops = { .video = &ov4689_video_ops, .pad = &ov4689_pad_ops, @@ -610,7 +607,6 @@ static const struct v4l2_subdev_ops ov4689_subdev_ops = { */ static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result) { - const struct device *dev = &ov4689->client->dev; const struct ov4689_gain_range *range; unsigned int n; @@ -621,7 +617,8 @@ static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result) } if (n == ARRAY_SIZE(ov4689_gain_ranges)) { - dev_warn_ratelimited(dev, "no mapping found for gain %d\n", + dev_warn_ratelimited(ov4689->dev, + "no mapping found for gain %d\n", logical_gain); return -EINVAL; } @@ -637,10 +634,11 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov4689 *ov4689 = container_of(ctrl->handler, struct ov4689, ctrl_handler); - struct i2c_client *client = ov4689->client; - int sensor_gain; + struct regmap *regmap = ov4689->regmap; + struct device *dev = ov4689->dev; + int sensor_gain = 0; s64 max_expo; - int ret; + int ret = 0; /* Propagate change of current control to all related controls */ switch (ctrl->id) { @@ -654,44 +652,58 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(dev)) return 0; switch (ctrl->id) { case V4L2_CID_EXPOSURE: - /* 4 least significant bits of expsoure are fractional part */ - ret = ov4689_write_reg(ov4689->client, OV4689_REG_EXPOSURE, - OV4689_REG_VALUE_24BIT, ctrl->val << 4); + /* 4 least significant bits of exposure are fractional part */ + cci_write(regmap, OV4689_REG_EXPOSURE, ctrl->val << 4, &ret); break; case V4L2_CID_ANALOGUE_GAIN: ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain); - - ret = ret ?: - ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_H, - OV4689_REG_VALUE_08BIT, - (sensor_gain >> OV4689_GAIN_H_SHIFT) & - OV4689_GAIN_H_MASK); - ret = ret ?: - ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_L, - OV4689_REG_VALUE_08BIT, - sensor_gain & OV4689_GAIN_L_MASK); + cci_write(regmap, OV4689_REG_GAIN, sensor_gain, &ret); break; case V4L2_CID_VBLANK: - ret = ov4689_write_reg(ov4689->client, OV4689_REG_VTS, - OV4689_REG_VALUE_16BIT, - ctrl->val + ov4689->cur_mode->height); + cci_write(regmap, OV4689_REG_VTS, + ctrl->val + ov4689->cur_mode->height, &ret); break; case V4L2_CID_TEST_PATTERN: ret = ov4689_enable_test_pattern(ov4689, ctrl->val); break; + case V4L2_CID_HBLANK: + cci_write(regmap, OV4689_REG_HTS, + (ctrl->val + ov4689->cur_mode->width) / + OV4689_HTS_DIVIDER, &ret); + break; + case V4L2_CID_VFLIP: + cci_update_bits(regmap, OV4689_REG_TIMING_FORMAT1, + OV4689_TIMING_FLIP_MASK, + ctrl->val ? OV4689_TIMING_FLIP_BOTH : 0, &ret); + break; + case V4L2_CID_HFLIP: + cci_update_bits(regmap, OV4689_REG_TIMING_FORMAT2, + OV4689_TIMING_FLIP_MASK, + ctrl->val ? 0 : OV4689_TIMING_FLIP_BOTH, &ret); + break; + case V4L2_CID_DIGITAL_GAIN: + cci_write(regmap, OV4689_REG_DIG_GAIN, ctrl->val, &ret); + break; + case V4L2_CID_RED_BALANCE: + cci_write(regmap, OV4689_REG_WB_GAIN_RED, ctrl->val, &ret); + break; + case V4L2_CID_BLUE_BALANCE: + cci_write(regmap, OV4689_REG_WB_GAIN_BLUE, ctrl->val, &ret); + break; default: - dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + dev_warn(dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); ret = -EINVAL; break; } - pm_runtime_put(&client->dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return ret; } @@ -707,16 +719,15 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) struct v4l2_ctrl_handler *handler; const struct ov4689_mode *mode; s64 exposure_max, vblank_def; + s64 hblank_def, hblank_min; struct v4l2_ctrl *ctrl; - s64 h_blank_def; int ret; handler = &ov4689->ctrl_handler; mode = ov4689->cur_mode; - ret = v4l2_ctrl_handler_init(handler, 10); + ret = v4l2_ctrl_handler_init(handler, 15); if (ret) return ret; - handler->lock = &ov4689->mutex; ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, link_freq_menu_items); @@ -726,11 +737,11 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, mode->pixel_rate, 1, mode->pixel_rate); - h_blank_def = mode->hts_def - mode->width; - ctrl = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank_def, - h_blank_def, 1, h_blank_def); - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + hblank_def = mode->hts_def - mode->width; + hblank_min = mode->hts_min - mode->width; + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_HBLANK, + hblank_min, OV4689_HTS_MAX - mode->width, + OV4689_HTS_DIVIDER, hblank_def); vblank_def = mode->vts_def - mode->height; v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK, @@ -754,10 +765,24 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) ARRAY_SIZE(ov4689_test_pattern_menu) - 1, 0, 0, ov4689_test_pattern_menu); + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV4689_DIG_GAIN_MIN, OV4689_DIG_GAIN_MAX, + OV4689_DIG_GAIN_STEP, OV4689_DIG_GAIN_DEFAULT); + + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_RED_BALANCE, + OV4689_WB_GAIN_MIN, OV4689_WB_GAIN_MAX, + OV4689_WB_GAIN_STEP, OV4689_WB_GAIN_DEFAULT); + + v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_BLUE_BALANCE, + OV4689_WB_GAIN_MIN, OV4689_WB_GAIN_MAX, + OV4689_WB_GAIN_STEP, OV4689_WB_GAIN_DEFAULT); + if (handler->error) { ret = handler->error; - dev_err(&ov4689->client->dev, "Failed to init controls(%d)\n", - ret); + dev_err(ov4689->dev, "Failed to init controls(%d)\n", ret); goto err_free_handler; } @@ -783,19 +808,18 @@ err_free_handler: static int ov4689_check_sensor_id(struct ov4689 *ov4689, struct i2c_client *client) { - struct device *dev = &ov4689->client->dev; - u32 id = 0; + struct device *dev = ov4689->dev; + u64 id = 0; int ret; - ret = ov4689_read_reg(client, OV4689_REG_CHIP_ID, - OV4689_REG_VALUE_16BIT, &id); + ret = cci_read(ov4689->regmap, OV4689_REG_CHIP_ID, &id, NULL); if (ret) { dev_err(dev, "Cannot read sensor ID\n"); return ret; } if (id != CHIP_ID) { - dev_err(dev, "Unexpected sensor ID %06x, expected %06x\n", + dev_err(dev, "Unexpected sensor ID %06llx, expected %06x\n", id, CHIP_ID); return -ENODEV; } @@ -812,7 +836,7 @@ static int ov4689_configure_regulators(struct ov4689 *ov4689) for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++) ov4689->supplies[i].supply = ov4689_supply_names[i]; - return devm_regulator_bulk_get(&ov4689->client->dev, + return devm_regulator_bulk_get(ov4689->dev, ARRAY_SIZE(ov4689_supply_names), ov4689->supplies); } @@ -881,7 +905,8 @@ static int ov4689_probe(struct i2c_client *client) if (!ov4689) return -ENOMEM; - ov4689->client = client; + ov4689->dev = dev; + ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520]; ov4689->xvclk = devm_clk_get_optional(dev, NULL); @@ -905,6 +930,13 @@ static int ov4689_probe(struct i2c_client *client) return -EINVAL; } + ov4689->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(ov4689->regmap)) { + ret = PTR_ERR(ov4689->regmap); + dev_err(dev, "failed to initialize CCI: %d\n", ret); + return ret; + } + ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov4689->reset_gpio)) { @@ -923,13 +955,15 @@ static int ov4689_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "Failed to get power regulators\n"); - mutex_init(&ov4689->mutex); - sd = &ov4689->subdev; v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops); + sd->internal_ops = &ov4689_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ret = ov4689_initialize_controls(ov4689); - if (ret) - goto err_destroy_mutex; + if (ret) { + dev_err(dev, "Failed to initialize controls\n"); + return ret; + } ret = ov4689_power_on(dev); if (ret) @@ -939,35 +973,47 @@ static int ov4689_probe(struct i2c_client *client) if (ret) goto err_power_off; - sd->internal_ops = &ov4689_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ov4689->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov4689->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad); if (ret < 0) goto err_power_off; - ret = v4l2_async_register_subdev_sensor(sd); + sd->state_lock = ov4689->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(sd); if (ret) { - dev_err(dev, "v4l2 async register subdev failed\n"); + dev_err(dev, "Could not register v4l2 device\n"); goto err_clean_entity; } pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = v4l2_async_register_subdev_sensor(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_subdev_pm; + } + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; +err_clean_subdev_pm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + v4l2_subdev_cleanup(sd); err_clean_entity: media_entity_cleanup(&sd->entity); err_power_off: ov4689_power_off(dev); err_free_handler: v4l2_ctrl_handler_free(&ov4689->ctrl_handler); -err_destroy_mutex: - mutex_destroy(&ov4689->mutex); return ret; } @@ -979,9 +1025,8 @@ static void ov4689_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); - + v4l2_subdev_cleanup(sd); v4l2_ctrl_handler_free(&ov4689->ctrl_handler); - mutex_destroy(&ov4689->mutex); pm_runtime_disable(&client->dev); if (!pm_runtime_status_suspended(&client->dev)) diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index a26ac11c98..3b22b9e127 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -118,7 +118,6 @@ static inline struct ov5645 *to_ov5645(struct v4l2_subdev *sd) static const struct reg_value ov5645_global_init_setting[] = { { 0x3103, 0x11 }, - { 0x3008, 0x82 }, { 0x3008, 0x42 }, { 0x3103, 0x03 }, { 0x3503, 0x07 }, @@ -627,6 +626,10 @@ static int ov5645_set_register_array(struct ov5645 *ov5645, ret = ov5645_write_reg(ov5645, settings->reg, settings->val); if (ret < 0) return ret; + + if (settings->reg == OV5645_SYSTEM_CTRL0 && + settings->val == OV5645_SYSTEM_CTRL0_START) + usleep_range(1000, 2000); } return 0; @@ -1056,7 +1059,7 @@ static int ov5645_probe(struct i2c_client *client) ov5645->i2c_client = client; ov5645->dev = dev; - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); if (!endpoint) { dev_err(dev, "endpoint node not found\n"); return -EINVAL; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 96c0fd4ff5..0fb4d7bff9 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -1360,24 +1360,21 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY, }; - struct device_node *ep; + struct device_node *ep __free(device_node) = + of_graph_get_endpoint_by_regs(np, 0, -1); int ret; - ep = of_graph_get_next_endpoint(np, NULL); if (!ep) return -EINVAL; ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); if (ret) - goto out; + return ret; sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; -out: - of_node_put(ep); - - return ret; + return 0; } static int ov5647_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index 4fba4c2cb0..541bf74581 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -3287,7 +3287,7 @@ static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl) exp_max, 1, exp_val); } - pm_status = pm_runtime_get_if_active(ov64a40->dev, true); + pm_status = pm_runtime_get_if_active(ov64a40->dev); if (!pm_status) return 0; diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index b4647bda8c..b8bd8354d1 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -463,8 +463,8 @@ static int rdacm20_initialize(struct rdacm20_device *dev) return ret; /* - * Ensure that we have a good link configuration before attempting to - * identify the device. + * Ensure that we have a good link configuration before attempting to + * identify the device. */ ret = max9271_configure_i2c(&dev->serializer, MAX9271_I2CSLVSH_469NS_234NS | diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index af8d01f78c..cf6be509af 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1568,7 +1568,7 @@ static int s5c73m3_get_dt_data(struct s5c73m3 *state) "failed to request gpio S5C73M3_RST\n"); gpiod_set_consumer_name(state->reset, "S5C73M3_RST"); - node_ep = of_graph_get_next_endpoint(node, NULL); + node_ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!node_ep) { dev_warn(dev, "no endpoint defined for node: %pOF\n", node); return 0; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index de079d2c92..6b11039c35 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1849,7 +1849,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) state->mclk_frequency); } - node_ep = of_graph_get_next_endpoint(node, NULL); + node_ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!node_ep) { dev_err(dev, "no endpoint defined at node %pOF\n", node); return -EINVAL; diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f250640729..b947a55281 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -326,7 +326,7 @@ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge, } dev_dbg(&client->dev, "detect link_freq = %lld Hz", link_freq); - do_div(ui_4, link_freq); + ui_4 = div64_u64(ui_4, link_freq); bridge->r.clk_lane_reg1 |= ui_4 << 2; return 0; diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index e4d37a1977..b9e7c57027 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -12,6 +12,7 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/units.h> @@ -19,79 +20,74 @@ #include <media/mipi-csi2.h> #include <media/v4l2-async.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> -#define VGXY61_REG_8BIT(n) ((1 << 16) | (n)) -#define VGXY61_REG_16BIT(n) ((2 << 16) | (n)) -#define VGXY61_REG_32BIT(n) ((4 << 16) | (n)) -#define VGXY61_REG_SIZE_SHIFT 16 -#define VGXY61_REG_ADDR_MASK 0xffff - -#define VGXY61_REG_MODEL_ID VGXY61_REG_16BIT(0x0000) +#define VGXY61_REG_MODEL_ID CCI_REG16_LE(0x0000) #define VG5661_MODEL_ID 0x5661 #define VG5761_MODEL_ID 0x5761 -#define VGXY61_REG_REVISION VGXY61_REG_16BIT(0x0002) -#define VGXY61_REG_FWPATCH_REVISION VGXY61_REG_16BIT(0x0014) -#define VGXY61_REG_FWPATCH_START_ADDR VGXY61_REG_8BIT(0x2000) -#define VGXY61_REG_SYSTEM_FSM VGXY61_REG_8BIT(0x0020) +#define VGXY61_REG_REVISION CCI_REG16_LE(0x0002) +#define VGXY61_REG_FWPATCH_REVISION CCI_REG16_LE(0x0014) +#define VGXY61_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) +#define VGXY61_REG_SYSTEM_FSM CCI_REG8(0x0020) #define VGXY61_SYSTEM_FSM_SW_STBY 0x03 #define VGXY61_SYSTEM_FSM_STREAMING 0x04 -#define VGXY61_REG_NVM VGXY61_REG_8BIT(0x0023) +#define VGXY61_REG_NVM CCI_REG8(0x0023) #define VGXY61_NVM_OK 0x04 -#define VGXY61_REG_STBY VGXY61_REG_8BIT(0x0201) +#define VGXY61_REG_STBY CCI_REG8(0x0201) #define VGXY61_STBY_NO_REQ 0 #define VGXY61_STBY_REQ_TMP_READ BIT(2) -#define VGXY61_REG_STREAMING VGXY61_REG_8BIT(0x0202) +#define VGXY61_REG_STREAMING CCI_REG8(0x0202) #define VGXY61_STREAMING_NO_REQ 0 #define VGXY61_STREAMING_REQ_STOP BIT(0) #define VGXY61_STREAMING_REQ_START BIT(1) -#define VGXY61_REG_EXT_CLOCK VGXY61_REG_32BIT(0x0220) -#define VGXY61_REG_CLK_PLL_PREDIV VGXY61_REG_8BIT(0x0224) -#define VGXY61_REG_CLK_SYS_PLL_MULT VGXY61_REG_8BIT(0x0225) -#define VGXY61_REG_GPIO_0_CTRL VGXY61_REG_8BIT(0x0236) -#define VGXY61_REG_GPIO_1_CTRL VGXY61_REG_8BIT(0x0237) -#define VGXY61_REG_GPIO_2_CTRL VGXY61_REG_8BIT(0x0238) -#define VGXY61_REG_GPIO_3_CTRL VGXY61_REG_8BIT(0x0239) -#define VGXY61_REG_SIGNALS_POLARITY_CTRL VGXY61_REG_8BIT(0x023b) -#define VGXY61_REG_LINE_LENGTH VGXY61_REG_16BIT(0x0300) -#define VGXY61_REG_ORIENTATION VGXY61_REG_8BIT(0x0302) -#define VGXY61_REG_VT_CTRL VGXY61_REG_8BIT(0x0304) -#define VGXY61_REG_FORMAT_CTRL VGXY61_REG_8BIT(0x0305) -#define VGXY61_REG_OIF_CTRL VGXY61_REG_16BIT(0x0306) -#define VGXY61_REG_OIF_ROI0_CTRL VGXY61_REG_8BIT(0x030a) -#define VGXY61_REG_ROI0_START_H VGXY61_REG_16BIT(0x0400) -#define VGXY61_REG_ROI0_START_V VGXY61_REG_16BIT(0x0402) -#define VGXY61_REG_ROI0_END_H VGXY61_REG_16BIT(0x0404) -#define VGXY61_REG_ROI0_END_V VGXY61_REG_16BIT(0x0406) -#define VGXY61_REG_PATGEN_CTRL VGXY61_REG_32BIT(0x0440) +#define VGXY61_REG_EXT_CLOCK CCI_REG32_LE(0x0220) +#define VGXY61_REG_CLK_PLL_PREDIV CCI_REG8(0x0224) +#define VGXY61_REG_CLK_SYS_PLL_MULT CCI_REG8(0x0225) +#define VGXY61_REG_GPIO_0_CTRL CCI_REG8(0x0236) +#define VGXY61_REG_GPIO_1_CTRL CCI_REG8(0x0237) +#define VGXY61_REG_GPIO_2_CTRL CCI_REG8(0x0238) +#define VGXY61_REG_GPIO_3_CTRL CCI_REG8(0x0239) +#define VGXY61_REG_SIGNALS_POLARITY_CTRL CCI_REG8(0x023b) +#define VGXY61_REG_LINE_LENGTH CCI_REG16_LE(0x0300) +#define VGXY61_REG_ORIENTATION CCI_REG8(0x0302) +#define VGXY61_REG_VT_CTRL CCI_REG8(0x0304) +#define VGXY61_REG_FORMAT_CTRL CCI_REG8(0x0305) +#define VGXY61_REG_OIF_CTRL CCI_REG16_LE(0x0306) +#define VGXY61_REG_OIF_ROI0_CTRL CCI_REG8(0x030a) +#define VGXY61_REG_ROI0_START_H CCI_REG16_LE(0x0400) +#define VGXY61_REG_ROI0_START_V CCI_REG16_LE(0x0402) +#define VGXY61_REG_ROI0_END_H CCI_REG16_LE(0x0404) +#define VGXY61_REG_ROI0_END_V CCI_REG16_LE(0x0406) +#define VGXY61_REG_PATGEN_CTRL CCI_REG32_LE(0x0440) #define VGXY61_PATGEN_LONG_ENABLE BIT(16) #define VGXY61_PATGEN_SHORT_ENABLE BIT(0) #define VGXY61_PATGEN_LONG_TYPE_SHIFT 18 #define VGXY61_PATGEN_SHORT_TYPE_SHIFT 4 -#define VGXY61_REG_FRAME_CONTENT_CTRL VGXY61_REG_8BIT(0x0478) -#define VGXY61_REG_COARSE_EXPOSURE_LONG VGXY61_REG_16BIT(0x0500) -#define VGXY61_REG_COARSE_EXPOSURE_SHORT VGXY61_REG_16BIT(0x0504) -#define VGXY61_REG_ANALOG_GAIN VGXY61_REG_8BIT(0x0508) -#define VGXY61_REG_DIGITAL_GAIN_LONG VGXY61_REG_16BIT(0x050a) -#define VGXY61_REG_DIGITAL_GAIN_SHORT VGXY61_REG_16BIT(0x0512) -#define VGXY61_REG_FRAME_LENGTH VGXY61_REG_16BIT(0x051a) -#define VGXY61_REG_SIGNALS_CTRL VGXY61_REG_16BIT(0x0522) +#define VGXY61_REG_FRAME_CONTENT_CTRL CCI_REG8(0x0478) +#define VGXY61_REG_COARSE_EXPOSURE_LONG CCI_REG16_LE(0x0500) +#define VGXY61_REG_COARSE_EXPOSURE_SHORT CCI_REG16_LE(0x0504) +#define VGXY61_REG_ANALOG_GAIN CCI_REG8(0x0508) +#define VGXY61_REG_DIGITAL_GAIN_LONG CCI_REG16_LE(0x050a) +#define VGXY61_REG_DIGITAL_GAIN_SHORT CCI_REG16_LE(0x0512) +#define VGXY61_REG_FRAME_LENGTH CCI_REG16_LE(0x051a) +#define VGXY61_REG_SIGNALS_CTRL CCI_REG16_LE(0x0522) #define VGXY61_SIGNALS_GPIO_ID_SHIFT 4 -#define VGXY61_REG_READOUT_CTRL VGXY61_REG_8BIT(0x0530) -#define VGXY61_REG_HDR_CTRL VGXY61_REG_8BIT(0x0532) -#define VGXY61_REG_PATGEN_LONG_DATA_GR VGXY61_REG_16BIT(0x092c) -#define VGXY61_REG_PATGEN_LONG_DATA_R VGXY61_REG_16BIT(0x092e) -#define VGXY61_REG_PATGEN_LONG_DATA_B VGXY61_REG_16BIT(0x0930) -#define VGXY61_REG_PATGEN_LONG_DATA_GB VGXY61_REG_16BIT(0x0932) -#define VGXY61_REG_PATGEN_SHORT_DATA_GR VGXY61_REG_16BIT(0x0950) -#define VGXY61_REG_PATGEN_SHORT_DATA_R VGXY61_REG_16BIT(0x0952) -#define VGXY61_REG_PATGEN_SHORT_DATA_B VGXY61_REG_16BIT(0x0954) -#define VGXY61_REG_PATGEN_SHORT_DATA_GB VGXY61_REG_16BIT(0x0956) -#define VGXY61_REG_BYPASS_CTRL VGXY61_REG_8BIT(0x0a60) +#define VGXY61_REG_READOUT_CTRL CCI_REG8(0x0530) +#define VGXY61_REG_HDR_CTRL CCI_REG8(0x0532) +#define VGXY61_REG_PATGEN_LONG_DATA_GR CCI_REG16_LE(0x092c) +#define VGXY61_REG_PATGEN_LONG_DATA_R CCI_REG16_LE(0x092e) +#define VGXY61_REG_PATGEN_LONG_DATA_B CCI_REG16_LE(0x0930) +#define VGXY61_REG_PATGEN_LONG_DATA_GB CCI_REG16_LE(0x0932) +#define VGXY61_REG_PATGEN_SHORT_DATA_GR CCI_REG16_LE(0x0950) +#define VGXY61_REG_PATGEN_SHORT_DATA_R CCI_REG16_LE(0x0952) +#define VGXY61_REG_PATGEN_SHORT_DATA_B CCI_REG16_LE(0x0954) +#define VGXY61_REG_PATGEN_SHORT_DATA_GB CCI_REG16_LE(0x0956) +#define VGXY61_REG_BYPASS_CTRL CCI_REG8(0x0a60) #define VGX661_WIDTH 1464 #define VGX661_HEIGHT 1104 @@ -384,6 +380,7 @@ static const struct vgxy61_mode_info vgx761_mode_data[] = { struct vgxy61_dev { struct i2c_client *i2c_client; + struct regmap *regmap; struct v4l2_subdev sd; struct media_pad pad; struct regulator_bulk_data supplies[ARRAY_SIZE(vgxy61_supply_name)]; @@ -510,82 +507,6 @@ static unsigned int get_chunk_size(struct vgxy61_dev *sensor) return max(max_write_len, 1); } -static int vgxy61_read_multiple(struct vgxy61_dev *sensor, u32 reg, - unsigned int len) -{ - struct i2c_client *client = sensor->i2c_client; - struct i2c_msg msg[2]; - u8 buf[2]; - u8 val[sizeof(u32)] = {0}; - int ret; - - if (len > sizeof(u32)) - return -EINVAL; - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - - msg[0].addr = client->addr; - msg[0].flags = client->flags; - msg[0].buf = buf; - msg[0].len = sizeof(buf); - - msg[1].addr = client->addr; - msg[1].flags = client->flags | I2C_M_RD; - msg[1].buf = val; - msg[1].len = len; - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", - __func__, client->addr, reg, ret); - return ret; - } - - return get_unaligned_le32(val); -} - -static inline int vgxy61_read_reg(struct vgxy61_dev *sensor, u32 reg) -{ - return vgxy61_read_multiple(sensor, reg & VGXY61_REG_ADDR_MASK, - (reg >> VGXY61_REG_SIZE_SHIFT) & 7); -} - -static int vgxy61_write_multiple(struct vgxy61_dev *sensor, u32 reg, - const u8 *data, unsigned int len, int *err) -{ - struct i2c_client *client = sensor->i2c_client; - struct i2c_msg msg; - u8 buf[VGXY61_WRITE_MULTIPLE_CHUNK_MAX + 2]; - unsigned int i; - int ret; - - if (err && *err) - return *err; - - if (len > VGXY61_WRITE_MULTIPLE_CHUNK_MAX) - return -EINVAL; - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - for (i = 0; i < len; i++) - buf[i + 2] = data[i]; - - msg.addr = client->addr; - msg.flags = client->flags; - msg.buf = buf; - msg.len = len + 2; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", - __func__, reg, ret); - if (err) - *err = ret; - return ret; - } - - return 0; -} - static int vgxy61_write_array(struct vgxy61_dev *sensor, u32 reg, unsigned int nb, const u8 *array) { @@ -595,7 +516,8 @@ static int vgxy61_write_array(struct vgxy61_dev *sensor, u32 reg, while (nb) { sz = min(nb, chunk_size); - ret = vgxy61_write_multiple(sensor, reg, array, sz, NULL); + ret = regmap_bulk_write(sensor->regmap, CCI_REG_ADDR(reg), + array, sz); if (ret < 0) return ret; nb -= sz; @@ -606,24 +528,17 @@ static int vgxy61_write_array(struct vgxy61_dev *sensor, u32 reg, return 0; } -static inline int vgxy61_write_reg(struct vgxy61_dev *sensor, u32 reg, u32 val, - int *err) -{ - return vgxy61_write_multiple(sensor, reg & VGXY61_REG_ADDR_MASK, - (u8 *)&val, - (reg >> VGXY61_REG_SIZE_SHIFT) & 7, err); -} - static int vgxy61_poll_reg(struct vgxy61_dev *sensor, u32 reg, u8 poll_val, unsigned int timeout_ms) { const unsigned int loop_delay_ms = 10; + u64 val; int ret; - return read_poll_timeout(vgxy61_read_reg, ret, - ((ret < 0) || (ret == poll_val)), + return read_poll_timeout(cci_read, ret, + ((ret < 0) || (val == poll_val)), loop_delay_ms * 1000, timeout_ms * 1000, - false, sensor, reg); + false, sensor->regmap, reg, &val, NULL); } static int vgxy61_wait_state(struct vgxy61_dev *sensor, int state, @@ -662,11 +577,11 @@ static int vgxy61_apply_exposure(struct vgxy61_dev *sensor) int ret = 0; /* We first set expo to zero to avoid forbidden parameters couple */ - vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT, 0, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_LONG, - sensor->expo_long, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT, - sensor->expo_short, &ret); + cci_write(sensor->regmap, VGXY61_REG_COARSE_EXPOSURE_SHORT, 0, &ret); + cci_write(sensor->regmap, VGXY61_REG_COARSE_EXPOSURE_LONG, + sensor->expo_long, &ret); + cci_write(sensor->regmap, VGXY61_REG_COARSE_EXPOSURE_SHORT, + sensor->expo_short, &ret); return ret; } @@ -714,7 +629,7 @@ static int vgxy61_try_fmt_internal(struct v4l2_subdev *sd, const struct vgxy61_mode_info **new_mode) { struct vgxy61_dev *sensor = to_vgxy61_dev(sd); - const struct vgxy61_mode_info *mode = sensor->sensor_modes; + const struct vgxy61_mode_info *mode; unsigned int index; for (index = 0; index < ARRAY_SIZE(vgxy61_supported_codes); index++) { @@ -827,8 +742,8 @@ static int vgxy61_update_analog_gain(struct vgxy61_dev *sensor, u32 target) sensor->analog_gain = target; if (sensor->streaming) - return vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN, target, - NULL); + return cci_write(sensor->regmap, VGXY61_REG_ANALOG_GAIN, target, + NULL); return 0; } @@ -842,10 +757,10 @@ static int vgxy61_apply_digital_gain(struct vgxy61_dev *sensor, * DIGITAL_GAIN_SHORT_CH0 is enough to configure the gain of all * four sub pixels. */ - vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_LONG, digital_gain, - &ret); - vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_SHORT, digital_gain, - &ret); + cci_write(sensor->regmap, VGXY61_REG_DIGITAL_GAIN_LONG, digital_gain, + &ret); + cci_write(sensor->regmap, VGXY61_REG_DIGITAL_GAIN_SHORT, digital_gain, + &ret); return ret; } @@ -870,7 +785,7 @@ static int vgxy61_apply_patgen(struct vgxy61_dev *sensor, u32 index) if (pattern) reg |= VGXY61_PATGEN_LONG_ENABLE | VGXY61_PATGEN_SHORT_ENABLE; - return vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_CTRL, reg, NULL); + return cci_write(sensor->regmap, VGXY61_REG_PATGEN_CTRL, reg, NULL); } static int vgxy61_update_patgen(struct vgxy61_dev *sensor, u32 pattern) @@ -887,15 +802,13 @@ static int vgxy61_apply_gpiox_strobe_mode(struct vgxy61_dev *sensor, unsigned int idx) { static const u8 index2val[] = {0x0, 0x1, 0x3}; - int reg; + u16 mask, val; - reg = vgxy61_read_reg(sensor, VGXY61_REG_SIGNALS_CTRL); - if (reg < 0) - return reg; - reg &= ~(0xf << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT)); - reg |= index2val[mode] << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT); + mask = 0xf << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT); + val = index2val[mode] << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT); - return vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_CTRL, reg, NULL); + return cci_update_bits(sensor->regmap, VGXY61_REG_SIGNALS_CTRL, + mask, val, NULL); } static int vgxy61_update_gpios_strobe_mode(struct vgxy61_dev *sensor, @@ -940,12 +853,12 @@ static int vgxy61_update_gpios_strobe_polarity(struct vgxy61_dev *sensor, if (sensor->streaming) return -EBUSY; - vgxy61_write_reg(sensor, VGXY61_REG_GPIO_0_CTRL, polarity << 1, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_GPIO_1_CTRL, polarity << 1, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_GPIO_2_CTRL, polarity << 1, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_GPIO_3_CTRL, polarity << 1, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_POLARITY_CTRL, polarity, - &ret); + cci_write(sensor->regmap, VGXY61_REG_GPIO_0_CTRL, polarity << 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_GPIO_1_CTRL, polarity << 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_GPIO_2_CTRL, polarity << 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_GPIO_3_CTRL, polarity << 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_SIGNALS_POLARITY_CTRL, polarity, + &ret); return ret; } @@ -1057,8 +970,8 @@ static int vgxy61_update_exposure(struct vgxy61_dev *sensor, u16 new_expo_long, static int vgxy61_apply_framelength(struct vgxy61_dev *sensor) { - return vgxy61_write_reg(sensor, VGXY61_REG_FRAME_LENGTH, - sensor->frame_length, NULL); + return cci_write(sensor->regmap, VGXY61_REG_FRAME_LENGTH, + sensor->frame_length, NULL); } static int vgxy61_update_vblank(struct vgxy61_dev *sensor, u16 vblank, @@ -1086,8 +999,8 @@ static int vgxy61_apply_hdr(struct vgxy61_dev *sensor, { static const u8 index2val[] = {0x1, 0x4, 0xa}; - return vgxy61_write_reg(sensor, VGXY61_REG_HDR_CTRL, index2val[index], - NULL); + return cci_write(sensor->regmap, VGXY61_REG_HDR_CTRL, index2val[index], + NULL); } static int vgxy61_update_hdr(struct vgxy61_dev *sensor, @@ -1133,16 +1046,16 @@ static int vgxy61_apply_settings(struct vgxy61_dev *sensor) if (ret) return ret; - ret = vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN, - sensor->analog_gain, NULL); + ret = cci_write(sensor->regmap, VGXY61_REG_ANALOG_GAIN, + sensor->analog_gain, NULL); if (ret) return ret; ret = vgxy61_apply_digital_gain(sensor, sensor->digital_gain); if (ret) return ret; - ret = vgxy61_write_reg(sensor, VGXY61_REG_ORIENTATION, - sensor->hflip | (sensor->vflip << 1), NULL); + ret = cci_write(sensor->regmap, VGXY61_REG_ORIENTATION, + sensor->hflip | (sensor->vflip << 1), NULL); if (ret) return ret; @@ -1174,19 +1087,19 @@ static int vgxy61_stream_enable(struct vgxy61_dev *sensor) if (ret) return ret; - vgxy61_write_reg(sensor, VGXY61_REG_FORMAT_CTRL, - get_bpp_by_code(sensor->fmt.code), &ret); - vgxy61_write_reg(sensor, VGXY61_REG_OIF_ROI0_CTRL, - get_data_type_by_code(sensor->fmt.code), &ret); - - vgxy61_write_reg(sensor, VGXY61_REG_READOUT_CTRL, - sensor->current_mode->bin_mode, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_H, crop->left, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_H, - crop->left + crop->width - 1, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_V, crop->top, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_V, - crop->top + crop->height - 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_FORMAT_CTRL, + get_bpp_by_code(sensor->fmt.code), &ret); + cci_write(sensor->regmap, VGXY61_REG_OIF_ROI0_CTRL, + get_data_type_by_code(sensor->fmt.code), &ret); + + cci_write(sensor->regmap, VGXY61_REG_READOUT_CTRL, + sensor->current_mode->bin_mode, &ret); + cci_write(sensor->regmap, VGXY61_REG_ROI0_START_H, crop->left, &ret); + cci_write(sensor->regmap, VGXY61_REG_ROI0_END_H, + crop->left + crop->width - 1, &ret); + cci_write(sensor->regmap, VGXY61_REG_ROI0_START_V, crop->top, &ret); + cci_write(sensor->regmap, VGXY61_REG_ROI0_END_V, + crop->top + crop->height - 1, &ret); if (ret) goto err_rpm_put; @@ -1194,8 +1107,8 @@ static int vgxy61_stream_enable(struct vgxy61_dev *sensor) if (ret) goto err_rpm_put; - ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING, - VGXY61_STREAMING_REQ_START, NULL); + ret = cci_write(sensor->regmap, VGXY61_REG_STREAMING, + VGXY61_STREAMING_REQ_START, NULL); if (ret) goto err_rpm_put; @@ -1225,8 +1138,8 @@ static int vgxy61_stream_disable(struct vgxy61_dev *sensor) struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); int ret; - ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING, - VGXY61_STREAMING_REQ_STOP, NULL); + ret = cci_write(sensor->regmap, VGXY61_REG_STREAMING, + VGXY61_STREAMING_REQ_STOP, NULL); if (ret) goto err_str_dis; @@ -1582,7 +1495,7 @@ static int vgxy61_configure(struct vgxy61_dev *sensor) { u32 sensor_freq; u8 prediv, mult; - int line_length; + u64 line_length; int ret = 0; compute_pll_parameters_by_freq(sensor->clk_freq, &prediv, &mult); @@ -1592,28 +1505,28 @@ static int vgxy61_configure(struct vgxy61_dev *sensor) /* Video timing ISP path (pixel clock) requires 804/5 mhz = 160 mhz */ sensor->pclk = sensor_freq / 5; - line_length = vgxy61_read_reg(sensor, VGXY61_REG_LINE_LENGTH); - if (line_length < 0) - return line_length; - sensor->line_length = line_length; - vgxy61_write_reg(sensor, VGXY61_REG_EXT_CLOCK, sensor->clk_freq, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_CLK_PLL_PREDIV, prediv, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_CLK_SYS_PLL_MULT, mult, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_OIF_CTRL, sensor->oif_ctrl, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_FRAME_CONTENT_CTRL, 0, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_BYPASS_CTRL, 4, &ret); + cci_read(sensor->regmap, VGXY61_REG_LINE_LENGTH, &line_length, &ret); + if (ret < 0) + return ret; + sensor->line_length = (u16)line_length; + cci_write(sensor->regmap, VGXY61_REG_EXT_CLOCK, sensor->clk_freq, &ret); + cci_write(sensor->regmap, VGXY61_REG_CLK_PLL_PREDIV, prediv, &ret); + cci_write(sensor->regmap, VGXY61_REG_CLK_SYS_PLL_MULT, mult, &ret); + cci_write(sensor->regmap, VGXY61_REG_OIF_CTRL, sensor->oif_ctrl, &ret); + cci_write(sensor->regmap, VGXY61_REG_FRAME_CONTENT_CTRL, 0, &ret); + cci_write(sensor->regmap, VGXY61_REG_BYPASS_CTRL, 4, &ret); if (ret) return ret; vgxy61_update_gpios_strobe_polarity(sensor, sensor->gpios_polarity); /* Set pattern generator solid to middle value */ - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GR, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_R, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_B, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GB, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GR, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_R, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_B, 0x800, &ret); - vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GB, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_LONG_DATA_GR, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_LONG_DATA_R, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_LONG_DATA_B, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_LONG_DATA_GB, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_SHORT_DATA_GR, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_SHORT_DATA_R, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_SHORT_DATA_B, 0x800, &ret); + cci_write(sensor->regmap, VGXY61_REG_PATGEN_SHORT_DATA_GB, 0x800, &ret); if (ret) return ret; @@ -1623,37 +1536,33 @@ static int vgxy61_configure(struct vgxy61_dev *sensor) static int vgxy61_patch(struct vgxy61_dev *sensor) { struct i2c_client *client = sensor->i2c_client; - int patch, ret; + u64 patch; + int ret; ret = vgxy61_write_array(sensor, VGXY61_REG_FWPATCH_START_ADDR, sizeof(patch_array), patch_array); - if (ret) - return ret; - - ret = vgxy61_write_reg(sensor, VGXY61_REG_STBY, 0x10, NULL); + cci_write(sensor->regmap, VGXY61_REG_STBY, 0x10, &ret); if (ret) return ret; ret = vgxy61_poll_reg(sensor, VGXY61_REG_STBY, 0, VGXY61_TIMEOUT_MS); - if (ret) + cci_read(sensor->regmap, VGXY61_REG_FWPATCH_REVISION, &patch, &ret); + if (ret < 0) return ret; - patch = vgxy61_read_reg(sensor, VGXY61_REG_FWPATCH_REVISION); - if (patch < 0) - return patch; - if (patch != (VGXY61_FWPATCH_REVISION_MAJOR << 12) + (VGXY61_FWPATCH_REVISION_MINOR << 8) + VGXY61_FWPATCH_REVISION_MICRO) { - dev_err(&client->dev, "bad patch version expected %d.%d.%d got %d.%d.%d\n", + dev_err(&client->dev, + "bad patch version expected %d.%d.%d got %u.%u.%u\n", VGXY61_FWPATCH_REVISION_MAJOR, VGXY61_FWPATCH_REVISION_MINOR, VGXY61_FWPATCH_REVISION_MICRO, - patch >> 12, (patch >> 8) & 0x0f, patch & 0xff); + (u16)patch >> 12, ((u16)patch >> 8) & 0x0f, (u16)patch & 0xff); return -ENODEV; } - dev_dbg(&client->dev, "patch %d.%d.%d applied\n", - patch >> 12, (patch >> 8) & 0x0f, patch & 0xff); + dev_dbg(&client->dev, "patch %u.%u.%u applied\n", + (u16)patch >> 12, ((u16)patch >> 8) & 0x0f, (u16)patch & 0xff); return 0; } @@ -1661,11 +1570,12 @@ static int vgxy61_patch(struct vgxy61_dev *sensor) static int vgxy61_detect_cut_version(struct vgxy61_dev *sensor) { struct i2c_client *client = sensor->i2c_client; - int device_rev; + u64 device_rev; + int ret; - device_rev = vgxy61_read_reg(sensor, VGXY61_REG_REVISION); - if (device_rev < 0) - return device_rev; + ret = cci_read(sensor->regmap, VGXY61_REG_REVISION, &device_rev, NULL); + if (ret < 0) + return ret; switch (device_rev >> 8) { case 0xA: @@ -1687,17 +1597,17 @@ static int vgxy61_detect_cut_version(struct vgxy61_dev *sensor) static int vgxy61_detect(struct vgxy61_dev *sensor) { struct i2c_client *client = sensor->i2c_client; - int id = 0; - int ret, st; + u64 st, id = 0; + int ret; - id = vgxy61_read_reg(sensor, VGXY61_REG_MODEL_ID); - if (id < 0) - return id; + ret = cci_read(sensor->regmap, VGXY61_REG_MODEL_ID, &id, NULL); + if (ret < 0) + return ret; if (id != VG5661_MODEL_ID && id != VG5761_MODEL_ID) { - dev_warn(&client->dev, "Unsupported sensor id %x\n", id); + dev_warn(&client->dev, "Unsupported sensor id %x\n", (u16)id); return -ENODEV; } - dev_dbg(&client->dev, "detected sensor id = 0x%04x\n", id); + dev_dbg(&client->dev, "detected sensor id = 0x%04x\n", (u16)id); sensor->id = id; ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY, @@ -1705,11 +1615,11 @@ static int vgxy61_detect(struct vgxy61_dev *sensor) if (ret) return ret; - st = vgxy61_read_reg(sensor, VGXY61_REG_NVM); - if (st < 0) + ret = cci_read(sensor->regmap, VGXY61_REG_NVM, &st, NULL); + if (ret < 0) return st; if (st != VGXY61_NVM_OK) - dev_warn(&client->dev, "Bad nvm state got %d\n", st); + dev_warn(&client->dev, "Bad nvm state got %u\n", (u8)st); ret = vgxy61_detect_cut_version(sensor); if (ret) @@ -1832,6 +1742,12 @@ static int vgxy61_probe(struct i2c_client *client) sensor->analog_gain = 0; sensor->digital_gain = 256; + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) { + ret = PTR_ERR(sensor->regmap); + return dev_err_probe(dev, ret, "Failed to init regmap\n"); + } + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); if (!handle) { dev_err(dev, "handle node not found\n"); diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 558152575d..0307fee3cc 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1521,11 +1521,14 @@ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int tc358743_s_dv_timings(struct v4l2_subdev *sd, +static int tc358743_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tc358743_state *state = to_state(sd); + if (pad != 0) + return -EINVAL; + if (!timings) return -EINVAL; @@ -1553,11 +1556,14 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int tc358743_g_dv_timings(struct v4l2_subdev *sd, +static int tc358743_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tc358743_state *state = to_state(sd); + if (pad != 0) + return -EINVAL; + *timings = state->timings; return 0; @@ -1573,11 +1579,14 @@ static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, &tc358743_timings_cap, NULL, NULL); } -static int tc358743_query_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int tc358743_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { int ret; + if (pad != 0) + return -EINVAL; + ret = tc358743_get_detected_timings(sd, timings); if (ret) return ret; @@ -1822,9 +1831,6 @@ static const struct v4l2_subdev_core_ops tc358743_core_ops = { static const struct v4l2_subdev_video_ops tc358743_video_ops = { .g_input_status = tc358743_g_input_status, - .s_dv_timings = tc358743_s_dv_timings, - .g_dv_timings = tc358743_g_dv_timings, - .query_dv_timings = tc358743_query_dv_timings, .s_stream = tc358743_s_stream, }; @@ -1834,6 +1840,9 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { .get_fmt = tc358743_get_fmt, .get_edid = tc358743_g_edid, .set_edid = tc358743_s_edid, + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, .enum_dv_timings = tc358743_enum_dv_timings, .dv_timings_cap = tc358743_dv_timings_cap, .get_mbus_config = tc358743_get_mbus_config, @@ -1895,7 +1904,7 @@ static int tc358743_probe_of(struct tc358743_state *state) return dev_err_probe(dev, PTR_ERR(refclk), "failed to get refclk\n"); - ep = of_graph_get_next_endpoint(dev->of_node, NULL); + ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); if (!ep) { dev_err(dev, "missing endpoint node\n"); return -EINVAL; @@ -2110,7 +2119,7 @@ static int tc358743_probe(struct i2c_client *client) tc358743_initial_setup(sd); - tc358743_s_dv_timings(sd, &default_timing); + tc358743_s_dv_timings(sd, 0, &default_timing); tc358743_set_csi_color_space(sd); diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 106de4271d..edf79107ad 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -843,14 +843,13 @@ static unsigned long tc358746_find_pll_settings(struct tc358746 *tc358746, if (fin < 4 * HZ_PER_MHZ || fin > 40 * HZ_PER_MHZ) continue; - tmp = fout * p * postdiv; - do_div(tmp, fin); - mul = tmp; + tmp = fout * postdiv; + mul = div64_ul(tmp, fin); if (mul > 511) continue; tmp = mul * fin; - do_div(tmp, p * postdiv); + do_div(tmp, postdiv); delta = abs(fout - tmp); if (delta < min_delta) { diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 1ea703a990..58ce8fec30 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1669,8 +1669,8 @@ tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; }; -static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { struct tda1997x_state *state = to_state(sd); @@ -1694,7 +1694,7 @@ static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, +static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tda1997x_state *state = to_state(sd); @@ -1707,7 +1707,7 @@ static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, +static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct tda1997x_state *state = to_state(sd); @@ -1724,9 +1724,6 @@ static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops tda1997x_video_ops = { .g_input_status = tda1997x_g_input_status, - .s_dv_timings = tda1997x_s_dv_timings, - .g_dv_timings = tda1997x_g_dv_timings, - .query_dv_timings = tda1997x_query_dv_timings, }; @@ -1930,6 +1927,9 @@ static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = { .set_fmt = tda1997x_set_format, .get_edid = tda1997x_get_edid, .set_edid = tda1997x_set_edid, + .s_dv_timings = tda1997x_s_dv_timings, + .g_dv_timings = tda1997x_g_dv_timings, + .query_dv_timings = tda1997x_query_dv_timings, .dv_timings_cap = tda1997x_get_dv_timings_cap, .enum_dv_timings = tda1997x_enum_dv_timings, }; @@ -2310,7 +2310,7 @@ static int tda1997x_parse_dt(struct tda1997x_state *state) pdata->vidout_sel_de = DE_FREF_SEL_DE_VHREF; np = state->client->dev.of_node; - ep = of_graph_get_next_endpoint(np, NULL); + ep = of_graph_get_endpoint_by_regs(np, 0, -1); if (!ep) return -EINVAL; diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index 2806887514..19bd923a73 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -1052,7 +1052,7 @@ static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl) if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) return -EINVAL; - if (!pm_runtime_get_if_active(thp7312->dev, true)) + if (!pm_runtime_get_if_active(thp7312->dev)) return 0; switch (ctrl->id) { diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index ea70c1c138..49ed83a0ac 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -193,8 +193,8 @@ static int ths7303_s_stream(struct v4l2_subdev *sd, int enable) } /* for setting filter for HD output */ -static int ths7303_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *dv_timings) { struct ths7303_state *state = to_state(sd); @@ -210,7 +210,6 @@ static int ths7303_s_dv_timings(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ths7303_video_ops = { .s_stream = ths7303_s_stream, .s_std_output = ths7303_s_std_output, - .s_dv_timings = ths7303_s_dv_timings, }; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -317,9 +316,14 @@ static const struct v4l2_subdev_core_ops ths7303_core_ops = { #endif }; +static const struct v4l2_subdev_pad_ops ths7303_pad_ops = { + .s_dv_timings = ths7303_s_dv_timings, +}; + static const struct v4l2_subdev_ops ths7303_ops = { .core = &ths7303_core_ops, .video = &ths7303_video_ops, + .pad = &ths7303_pad_ops, }; static int ths7303_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 0e0f676cd2..ce0a7f809f 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -358,13 +358,16 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt) bt->hsync, bt->vsync); } -static int ths8200_s_dv_timings(struct v4l2_subdev *sd, +static int ths8200_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct ths8200_state *state = to_state(sd); v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap, NULL, NULL)) return -EINVAL; @@ -385,13 +388,16 @@ static int ths8200_s_dv_timings(struct v4l2_subdev *sd, return 0; } -static int ths8200_g_dv_timings(struct v4l2_subdev *sd, +static int ths8200_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_dv_timings *timings) { struct ths8200_state *state = to_state(sd); v4l2_dbg(1, debug, sd, "%s:\n", __func__); + if (pad != 0) + return -EINVAL; + *timings = state->dv_timings; return 0; @@ -420,11 +426,11 @@ static int ths8200_dv_timings_cap(struct v4l2_subdev *sd, /* Specific video subsystem operation handlers */ static const struct v4l2_subdev_video_ops ths8200_video_ops = { .s_stream = ths8200_s_stream, - .s_dv_timings = ths8200_s_dv_timings, - .g_dv_timings = ths8200_g_dv_timings, }; static const struct v4l2_subdev_pad_ops ths8200_pad_ops = { + .s_dv_timings = ths8200_s_dv_timings, + .g_dv_timings = ths8200_g_dv_timings, .enum_dv_timings = ths8200_enum_dv_timings, .dv_timings_cap = ths8200_dv_timings_cap, }; diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 5a561e5bf6..f9c9c80c33 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -987,7 +987,7 @@ tvp514x_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!endpoint) return NULL; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 9fc586cfdc..64b91aa3c8 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1817,7 +1817,7 @@ static struct regmap_config tvp5150_config = { .val_bits = 8, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .rd_table = &tvp5150_readable_table, .volatile_reg = tvp5150_volatile_reg, diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 30831b4b56..ea01bd8645 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -546,13 +546,16 @@ static int tvp7002_write_inittab(struct v4l2_subdev *sd, return error; } -static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) +static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *dv_timings) { struct tvp7002 *device = to_tvp7002(sd); const struct v4l2_bt_timings *bt = &dv_timings->bt; int i; + if (pad != 0) + return -EINVAL; + if (dv_timings->type != V4L2_DV_BT_656_1120) return -EINVAL; for (i = 0; i < NUM_TIMINGS; i++) { @@ -566,11 +569,14 @@ static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, return -EINVAL; } -static int tvp7002_g_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) +static int tvp7002_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *dv_timings) { struct tvp7002 *device = to_tvp7002(sd); + if (pad != 0) + return -EINVAL; + *dv_timings = device->current_timings->timings; return 0; } @@ -659,12 +665,16 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) return 0; } -static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) +static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_dv_timings *timings) { int index; - int err = tvp7002_query_dv(sd, &index); + int err; + + if (pad != 0) + return -EINVAL; + err = tvp7002_query_dv(sd, &index); if (err) return err; *timings = tvp7002_timings[index].timings; @@ -861,9 +871,6 @@ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { /* Specific video subsystem operation handlers */ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { - .g_dv_timings = tvp7002_g_dv_timings, - .s_dv_timings = tvp7002_s_dv_timings, - .query_dv_timings = tvp7002_query_dv_timings, .s_stream = tvp7002_s_stream, }; @@ -872,6 +879,9 @@ static const struct v4l2_subdev_pad_ops tvp7002_pad_ops = { .enum_mbus_code = tvp7002_enum_mbus_code, .get_fmt = tvp7002_get_pad_format, .set_fmt = tvp7002_set_pad_format, + .g_dv_timings = tvp7002_g_dv_timings, + .s_dv_timings = tvp7002_s_dv_timings, + .query_dv_timings = tvp7002_query_dv_timings, .enum_dv_timings = tvp7002_enum_dv_timings, }; @@ -893,7 +903,7 @@ tvp7002_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); if (!endpoint) return NULL; @@ -1001,7 +1011,7 @@ static int tvp7002_probe(struct i2c_client *c) /* Set registers according to default video mode */ timings = device->current_timings->timings; - error = tvp7002_s_dv_timings(sd, &timings); + error = tvp7002_s_dv_timings(sd, 0, &timings); #if defined(CONFIG_MEDIA_CONTROLLER) device->pad.flags = MEDIA_PAD_FL_SOURCE; |