diff options
Diffstat (limited to 'drivers/media/i2c/ccs/ccs-core.c')
| -rw-r--r-- | drivers/media/i2c/ccs/ccs-core.c | 858 |
1 files changed, 459 insertions, 399 deletions
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index f8523140784c..aa4dd7e7cf5a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -13,6 +13,7 @@ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.com> */ +#include <linux/bits.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> @@ -25,6 +26,7 @@ #include <linux/slab.h> #include <linux/smiapp.h> #include <linux/v4l2-mediabus.h> +#include <media/mipi-csi2.h> #include <media/v4l2-cci.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -245,6 +247,33 @@ out_err: return ret; } +static u8 ccs_mipi_csi2_data_type(unsigned int bpp) +{ + switch (bpp) { + case 6: + return MIPI_CSI2_DT_RAW6; + case 7: + return MIPI_CSI2_DT_RAW7; + case 8: + return MIPI_CSI2_DT_RAW8; + case 10: + return MIPI_CSI2_DT_RAW10; + case 12: + return MIPI_CSI2_DT_RAW12; + case 14: + return MIPI_CSI2_DT_RAW14; + case 16: + return MIPI_CSI2_DT_RAW16; + case 20: + return MIPI_CSI2_DT_RAW20; + case 24: + return MIPI_CSI2_DT_RAW24; + default: + WARN_ON(1); + return 0; + } +} + static int ccs_read_frame_fmt(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -483,16 +512,71 @@ static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll) return ccs_pll_calculate(&client->dev, &lim, pll); } +static void +ccs_get_binning(struct ccs_sensor *sensor, u8 *binning_mode, u8 *binh, u8 *binv) +{ + struct v4l2_subdev_state *state = + v4l2_subdev_get_locked_active_state(&sensor->binner->sd); + const struct v4l2_rect *sink_crop = + v4l2_subdev_state_get_crop(state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + const struct v4l2_rect *sink_comp = + v4l2_subdev_state_get_compose(state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + + if (binning_mode) + *binning_mode = sink_crop->width == sink_comp->width && + sink_crop->height == sink_comp->height ? 0 : 1; + + *binh = sink_crop->width / sink_comp->width; + *binv = sink_crop->height / sink_comp->height; +} + +static void ccs_get_scaling(struct ccs_sensor *sensor, u8 *scaling_mode, + u8 *scale_m) +{ + struct v4l2_subdev_state *state = + v4l2_subdev_get_locked_active_state(&sensor->scaler->sd); + const struct v4l2_rect *sink_crop = + v4l2_subdev_state_get_crop(state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + const struct v4l2_rect *sink_comp = + v4l2_subdev_state_get_compose(state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + + *scale_m = sink_crop->width * CCS_LIM(sensor, SCALER_N_MIN) / + sink_comp->width; + + if (!scaling_mode) + return; + + if (sink_crop->width == sink_comp->width) + *scaling_mode = CCS_SCALING_MODE_NO_SCALING; + else if (sink_crop->height == sink_comp->height) + *scaling_mode = CCS_SCALING_MODE_HORIZONTAL; + else + *scaling_mode = SMIAPP_SCALING_MODE_BOTH; +} + static int ccs_pll_update(struct ccs_sensor *sensor) { struct ccs_pll *pll = &sensor->pll; + u8 binh, binv; + u8 scale_m; int rval; - pll->binning_horizontal = sensor->binning_horizontal; - pll->binning_vertical = sensor->binning_vertical; + ccs_get_binning(sensor, NULL, &binh, &binv); + + if (sensor->scaler) + ccs_get_scaling(sensor, NULL, &scale_m); + else + scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + pll->binning_horizontal = binh; + pll->binning_vertical = binv; pll->link_freq = sensor->link_freq->qmenu_int[sensor->link_freq->val]; - pll->scale_m = sensor->scale_m; + pll->scale_m = scale_m; pll->bits_per_pixel = sensor->csi_format->compressed; rval = ccs_pll_try(sensor, pll); @@ -513,12 +597,13 @@ static int ccs_pll_update(struct ccs_sensor *sensor) * */ -static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) +static void __ccs_update_exposure_limits(struct ccs_sensor *sensor, + const struct v4l2_rect *pa_src) { struct v4l2_ctrl *ctrl = sensor->exposure; int max; - max = sensor->pa_src.height + sensor->vblank->val - + max = pa_src->height + sensor->vblank->val - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); @@ -621,12 +706,20 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) container_of(ctrl->handler, struct ccs_subdev, ctrl_handler) ->sensor; struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct v4l2_subdev_state *state; + const struct v4l2_rect *pa_src = NULL; int pm_status; u32 orient = 0; unsigned int i; int exposure; int rval; + if (ctrl->id == V4L2_CID_VBLANK || ctrl->id == V4L2_CID_HBLANK) { + state = v4l2_subdev_get_locked_active_state(&sensor->pixel_array->sd); + pa_src = v4l2_subdev_state_get_crop(state, CCS_PA_PAD_SRC, + CCS_STREAM_PIXEL); + } + switch (ctrl->id) { case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: @@ -645,7 +738,7 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VBLANK: exposure = sensor->exposure->val; - __ccs_update_exposure_limits(sensor); + __ccs_update_exposure_limits(sensor, pa_src); if (exposure > sensor->exposure->maximum) { sensor->exposure->val = sensor->exposure->maximum; @@ -737,12 +830,12 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: rval = ccs_write(sensor, FRAME_LENGTH_LINES, - sensor->pa_src.height + ctrl->val); + pa_src->height + ctrl->val); break; case V4L2_CID_HBLANK: rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pa_src.width + ctrl->val); + pa_src->width + ctrl->val); break; case V4L2_CID_TEST_PATTERN: @@ -1117,14 +1210,14 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) dev_dbg(&client->dev, "jolly good! %u\n", j); - sensor->default_mbus_frame_fmts |= 1 << j; + sensor->default_mbus_frame_fmts |= BIT_U64(j); } } /* Figure out which BPP values can be used with which formats. */ pll->binning_horizontal = 1; pll->binning_vertical = 1; - pll->scale_m = sensor->scale_m; + pll->scale_m = CCS_LIM(sensor, SCALER_N_MIN); for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { sensor->compressed_min_bpp = @@ -1150,7 +1243,7 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) f->compressed - sensor->compressed_min_bpp]; unsigned int j; - if (!(sensor->default_mbus_frame_fmts & 1 << i)) + if (!(sensor->default_mbus_frame_fmts & BIT_U64(i))) continue; pll->bits_per_pixel = f->compressed; @@ -1195,14 +1288,18 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) return 0; } -static void ccs_update_blanking(struct ccs_sensor *sensor) +static void ccs_update_blanking(struct ccs_sensor *sensor, + const struct v4l2_rect *pa_src) { struct v4l2_ctrl *vblank = sensor->vblank; struct v4l2_ctrl *hblank = sensor->hblank; u16 min_fll, max_fll, min_llp, max_llp, min_lbp; int min, max; + u8 binh, binv; + + ccs_get_binning(sensor, NULL, &binh, &binv); - if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { + if (binv > 1 || binh > 1) { min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); @@ -1218,21 +1315,26 @@ static void ccs_update_blanking(struct ccs_sensor *sensor) min = max_t(int, CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - sensor->pa_src.height); - max = max_fll - sensor->pa_src.height; + min_fll - pa_src->height); + max = max_fll - pa_src->height; __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); - min = max_t(int, min_llp - sensor->pa_src.width, min_lbp); - max = max_llp - sensor->pa_src.width; + min = max_t(int, min_llp - pa_src->width, min_lbp); + max = max_llp - pa_src->width; __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); - __ccs_update_exposure_limits(sensor); + __ccs_update_exposure_limits(sensor, pa_src); } static int ccs_pll_blanking_update(struct ccs_sensor *sensor) { + struct v4l2_subdev_state *state = + v4l2_subdev_get_locked_active_state(&sensor->pixel_array->sd); + const struct v4l2_rect *pa_src = + v4l2_subdev_state_get_crop(state, CCS_PA_PAD_SRC, + CCS_STREAM_PIXEL); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; @@ -1241,15 +1343,15 @@ static int ccs_pll_blanking_update(struct ccs_sensor *sensor) return rval; /* Output from pixel array, including blanking */ - ccs_update_blanking(sensor); + ccs_update_blanking(sensor, pa_src); dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); dev_dbg(&client->dev, "real timeperframe\t100/%d\n", sensor->pll.pixel_rate_pixel_array / - ((sensor->pa_src.width + sensor->hblank->val) * - (sensor->pa_src.height + sensor->vblank->val) / 100)); + ((pa_src->width + sensor->hblank->val) * + (pa_src->height + sensor->vblank->val) / 100)); return 0; } @@ -1704,72 +1806,122 @@ static int ccs_power_off(struct device *dev) usleep_range(5000, 5000); regulator_bulk_disable(ARRAY_SIZE(ccs_regulators), sensor->regulators); - sensor->streaming = false; return 0; } /* ----------------------------------------------------------------------------- - * Video stream management + * V4L2 subdev video operations */ -static int ccs_start_streaming(struct ccs_sensor *sensor) +static int ccs_pm_get_init(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int binning_mode; int rval; - mutex_lock(&sensor->mutex); + /* + * It can't use pm_runtime_resume_and_get() here, as the driver + * relies at the returned value to detect if the device was already + * active or not. + */ + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) + goto error; + + /* Device was already active, so don't set controls */ + if (rval == 1 && !sensor->handler_setup_needed) + return 0; + + sensor->handler_setup_needed = false; + + /* Restore V4L2 controls to the previously suspended device */ + rval = __v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); + if (rval) + goto error; + + rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + if (rval) + goto error; + + /* Keep PM runtime usage_count incremented on success */ + return 0; + +error: + pm_runtime_put(&client->dev); + return rval; +} + +static int ccs_enable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct v4l2_subdev_state *pa_state = + v4l2_subdev_get_locked_active_state(&sensor->pixel_array->sd); + struct v4l2_subdev_state *src_state = + v4l2_subdev_get_locked_active_state(&sensor->src->sd); + const struct v4l2_rect *pa_src = + v4l2_subdev_state_get_crop(pa_state, CCS_PA_PAD_SRC, + CCS_STREAM_PIXEL); + const struct v4l2_rect *src_src = + v4l2_subdev_state_get_crop(src_state, CCS_PAD_SRC, + CCS_STREAM_PIXEL); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + u8 binning_mode, binh, binv; + int rval; + + if (pad != CCS_PAD_SRC) + return -EINVAL; + + if (sensor->streaming) { + sensor->streaming |= streams_mask; + return 0; + } + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; rval = ccs_write(sensor, CSI_DATA_FORMAT, (sensor->csi_format->width << 8) | sensor->csi_format->compressed); if (rval) - goto out; + goto err_pm_put; /* Binning configuration */ - if (sensor->binning_horizontal == 1 && - sensor->binning_vertical == 1) { - binning_mode = 0; - } else { - u8 binning_type = - (sensor->binning_horizontal << 4) - | sensor->binning_vertical; + ccs_get_binning(sensor, &binning_mode, &binh, &binv); - rval = ccs_write(sensor, BINNING_TYPE, binning_type); + if (binning_mode) { + rval = ccs_write(sensor, BINNING_TYPE, (binh << 4) | binv); if (rval < 0) - goto out; - - binning_mode = 1; + goto err_pm_put; } rval = ccs_write(sensor, BINNING_MODE, binning_mode); if (rval < 0) - goto out; + goto err_pm_put; /* Set up PLL */ rval = ccs_pll_configure(sensor); if (rval) - goto out; + goto err_pm_put; /* Analog crop start coordinates */ - rval = ccs_write(sensor, X_ADDR_START, sensor->pa_src.left); + rval = ccs_write(sensor, X_ADDR_START, pa_src->left); if (rval < 0) - goto out; + goto err_pm_put; - rval = ccs_write(sensor, Y_ADDR_START, sensor->pa_src.top); + rval = ccs_write(sensor, Y_ADDR_START, pa_src->top); if (rval < 0) - goto out; + goto err_pm_put; /* Analog crop end coordinates */ - rval = ccs_write(sensor, X_ADDR_END, - sensor->pa_src.left + sensor->pa_src.width - 1); + rval = ccs_write(sensor, X_ADDR_END, pa_src->left + pa_src->width - 1); if (rval < 0) - goto out; + goto err_pm_put; - rval = ccs_write(sensor, Y_ADDR_END, - sensor->pa_src.top + sensor->pa_src.height - 1); + rval = ccs_write(sensor, Y_ADDR_END, pa_src->top + pa_src->height - 1); if (rval < 0) - goto out; + goto err_pm_put; /* * Output from pixel array, including blanking, is set using @@ -1779,46 +1931,57 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) /* Digital crop */ if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + struct v4l2_subdev_state *scaler_state = + v4l2_subdev_get_locked_active_state(&sensor->scaler->sd); + const struct v4l2_rect *scaler_sink = + v4l2_subdev_state_get_crop(scaler_state, + sensor->scaler->sink_pad, + CCS_STREAM_PIXEL); + rval = ccs_write(sensor, DIGITAL_CROP_X_OFFSET, - sensor->scaler_sink.left); + scaler_sink->left); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_Y_OFFSET, - sensor->scaler_sink.top); + scaler_sink->top); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_WIDTH, - sensor->scaler_sink.width); + scaler_sink->width); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_HEIGHT, - sensor->scaler_sink.height); + scaler_sink->height); if (rval < 0) - goto out; + goto err_pm_put; } /* Scaling */ if (CCS_LIM(sensor, SCALING_CAPABILITY) != CCS_SCALING_CAPABILITY_NONE) { - rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); + u8 scaling_mode, scale_m; + + ccs_get_scaling(sensor, &scaling_mode, &scale_m); + + rval = ccs_write(sensor, SCALING_MODE, scaling_mode); if (rval < 0) - goto out; + goto err_pm_put; - rval = ccs_write(sensor, SCALE_M, sensor->scale_m); + rval = ccs_write(sensor, SCALE_M, scale_m); if (rval < 0) - goto out; + goto err_pm_put; } /* Output size from sensor */ - rval = ccs_write(sensor, X_OUTPUT_SIZE, sensor->src_src.width); + rval = ccs_write(sensor, X_OUTPUT_SIZE, src_src->width); if (rval < 0) - goto out; - rval = ccs_write(sensor, Y_OUTPUT_SIZE, sensor->src_src.height); + goto err_pm_put; + rval = ccs_write(sensor, Y_OUTPUT_SIZE, src_src->height); if (rval < 0) - goto out; + goto err_pm_put; if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | @@ -1827,109 +1990,53 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) sensor->hwcfg.strobe_setup->trigger != 0) { rval = ccs_setup_flash_strobe(sensor); if (rval) - goto out; + goto err_pm_put; } rval = ccs_call_quirk(sensor, pre_streamon); if (rval) { dev_err(&client->dev, "pre_streamon quirks failed\n"); - goto out; + goto err_pm_put; } rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static int ccs_stop_streaming(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - mutex_lock(&sensor->mutex); - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); - if (rval) - goto out; - - rval = ccs_call_quirk(sensor, post_streamoff); - if (rval) - dev_err(&client->dev, "post_streamoff quirks failed\n"); - -out: - mutex_unlock(&sensor->mutex); - return rval; -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev video operations - */ - -static int ccs_pm_get_init(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - /* - * It can't use pm_runtime_resume_and_get() here, as the driver - * relies at the returned value to detect if the device was already - * active or not. - */ - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) - goto error; + sensor->streaming |= streams_mask; - /* Device was already active, so don't set controls */ - if (rval == 1 && !sensor->handler_setup_needed) - return 0; - - sensor->handler_setup_needed = false; - - /* Restore V4L2 controls to the previously suspended device */ - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); - if (rval) - goto error; + return 0; - rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - if (rval) - goto error; +err_pm_put: + pm_runtime_put_autosuspend(&client->dev); - /* Keep PM runtime usage_count incremented on success */ - return 0; -error: - pm_runtime_put(&client->dev); return rval; } -static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) +static int ccs_disable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; - if (!enable) { - ccs_stop_streaming(sensor); - sensor->streaming = false; - pm_runtime_put_autosuspend(&client->dev); + if (pad != CCS_PAD_SRC) + return -EINVAL; + sensor->streaming &= ~streams_mask; + if (sensor->streaming) return 0; - } - rval = ccs_pm_get_init(sensor); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); if (rval) return rval; - sensor->streaming = true; + rval = ccs_call_quirk(sensor, post_streamoff); + if (rval) + dev_err(&client->dev, "post_streamoff quirks failed\n"); - rval = ccs_start_streaming(sensor); - if (rval < 0) { - sensor->streaming = false; - pm_runtime_put_autosuspend(&client->dev); - } + pm_runtime_put_autosuspend(&client->dev); - return rval; + return 0; } static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) @@ -1955,7 +2062,8 @@ static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) } } - rval = ccs_pm_get_init(sensor); + scoped_guard(mutex, &sensor->mutex) + rval = ccs_pm_get_init(sensor); if (rval) return rval; @@ -1974,7 +2082,23 @@ static int ccs_post_streamoff(struct v4l2_subdev *subdev) struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - return pm_runtime_put(&client->dev); + pm_runtime_put(&client->dev); + + return 0; +} + +static const struct ccs_csi_data_format +*ccs_validate_csi_data_format(struct ccs_sensor *sensor, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + if (sensor->mbus_frame_fmts & BIT_U64(i) && + ccs_csi_data_formats[i].code == code) + return &ccs_csi_data_formats[i]; + } + + return sensor->csi_format; } static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, @@ -1985,42 +2109,35 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, struct ccs_sensor *sensor = to_ccs_sensor(subdev); unsigned int i; int idx = -1; - int rval = -EINVAL; - - mutex_lock(&sensor->mutex); dev_err(&client->dev, "subdev %s, pad %u, index %u\n", subdev->name, code->pad, code->index); if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) { if (code->index) - goto out; + return -EINVAL; code->code = sensor->internal_csi_format->code; - rval = 0; - goto out; + + return 0; } for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i)) + if (sensor->mbus_frame_fmts & BIT_U64(i)) idx++; if (idx == code->index) { code->code = ccs_csi_data_formats[i].code; dev_err(&client->dev, "found index %u, i %u, code %x\n", code->index, i, code->code); - rval = 0; - break; + return 0; } } -out: - mutex_unlock(&sensor->mutex); - - return rval; + return -EINVAL; } -static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) +static u32 ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); @@ -2030,102 +2147,47 @@ static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) return sensor->internal_csi_format->code; } -static int __ccs_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad); - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); - - return 0; -} - static int ccs_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __ccs_get_format(subdev, sd_state, fmt); - mutex_unlock(&sensor->mutex); - - return rval; -} - -static void ccs_get_crop_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_rect **crops, - struct v4l2_rect **comps) -{ - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - unsigned int i; + fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad); + fmt->format.code = ccs_get_mbus_code(subdev, fmt->pad); - if (crops) - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = - v4l2_subdev_state_get_crop(sd_state, i); - if (comps) - *comps = v4l2_subdev_state_get_compose(sd_state, - ssd->sink_pad); + return 0; } /* Changes require propagation only on sink pad. */ static void ccs_propagate(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, int which, - int target) + struct v4l2_subdev_state *sd_state, int target) { - struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; + struct v4l2_rect *comp, *crop; struct v4l2_mbus_framefmt *fmt; - ccs_get_crop_compose(subdev, sd_state, crops, &comp); - + comp = v4l2_subdev_state_get_compose(sd_state, ssd->sink_pad, + CCS_STREAM_PIXEL); switch (target) { case V4L2_SEL_TGT_CROP: - comp->width = crops[CCS_PAD_SINK]->width; - comp->height = crops[CCS_PAD_SINK]->height; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (ssd == sensor->scaler) { - sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); - sensor->scaling_mode = - CCS_SCALING_MODE_NO_SCALING; - sensor->scaler_sink = *comp; - } else if (ssd == sensor->binner) { - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - } - } + crop = v4l2_subdev_state_get_crop(sd_state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + comp->width = crop->width; + comp->height = crop->height; fallthrough; case V4L2_SEL_TGT_COMPOSE: - *crops[CCS_PAD_SRC] = *comp; - fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC); + crop = v4l2_subdev_state_get_crop(sd_state, CCS_PAD_SRC, + CCS_STREAM_PIXEL); + *crop = *comp; + fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC, + CCS_STREAM_PIXEL); fmt->width = comp->width; fmt->height = comp->height; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src) - sensor->src_src = *crops[CCS_PAD_SRC]; break; default: WARN_ON_ONCE(1); } } -static const struct ccs_csi_data_format -*ccs_validate_csi_data_format(struct ccs_sensor *sensor, u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i) && - ccs_csi_data_formats[i].code == code) - return &ccs_csi_data_formats[i]; - } - - return sensor->csi_format; -} - static int ccs_set_format_source(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -2138,7 +2200,7 @@ static int ccs_set_format_source(struct v4l2_subdev *subdev, unsigned int i; int rval; - rval = __ccs_get_format(subdev, sd_state, fmt); + rval = ccs_get_format(subdev, sd_state, fmt); if (rval) return rval; @@ -2185,22 +2247,19 @@ static int ccs_set_format(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *crops[CCS_PADS]; - - mutex_lock(&sensor->mutex); + struct v4l2_rect *crop; if (fmt->pad == ssd->source_pad) { int rval; rval = ccs_set_format_source(subdev, sd_state, fmt); - mutex_unlock(&sensor->mutex); - return rval; } /* Sink pad. Width and height are changeable here. */ - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.code = ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.width &= ~1; fmt->format.height &= ~1; fmt->format.field = V4L2_FIELD_NONE; @@ -2214,15 +2273,14 @@ static int ccs_set_format(struct v4l2_subdev *subdev, CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); - ccs_get_crop_compose(subdev, sd_state, crops, NULL); - - crops[ssd->sink_pad]->left = 0; - crops[ssd->sink_pad]->top = 0; - crops[ssd->sink_pad]->width = fmt->format.width; - crops[ssd->sink_pad]->height = fmt->format.height; - ccs_propagate(subdev, sd_state, fmt->which, V4L2_SEL_TGT_CROP); + crop = v4l2_subdev_state_get_crop(sd_state, ssd->sink_pad, + CCS_STREAM_PIXEL); - mutex_unlock(&sensor->mutex); + crop->left = 0; + crop->top = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + ccs_propagate(subdev, sd_state, V4L2_SEL_TGT_CROP); return 0; } @@ -2274,26 +2332,23 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, static void ccs_set_compose_binner(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) + const struct v4l2_rect *sink_crop) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); unsigned int i; unsigned int binh = 1, binv = 1; - int best = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width, sel->r.width, - crops[CCS_PAD_SINK]->height, sel->r.height, sel->flags); + int best = scaling_goodness(subdev, sink_crop->width, sel->r.width, + sink_crop->height, sel->r.height, + sel->flags); for (i = 0; i < sensor->nbinning_subtypes; i++) { - int this = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width - / sensor->binning_subtypes[i].horizontal, - sel->r.width, - crops[CCS_PAD_SINK]->height - / sensor->binning_subtypes[i].vertical, - sel->r.height, sel->flags); + int this = scaling_goodness(subdev, + sink_crop->width + / sensor->binning_subtypes[i].horizontal, + sel->r.width, + sink_crop->height + / sensor->binning_subtypes[i].vertical, + sel->r.height, sel->flags); if (this > best) { binh = sensor->binning_subtypes[i].horizontal; @@ -2301,13 +2356,9 @@ static void ccs_set_compose_binner(struct v4l2_subdev *subdev, best = this; } } - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->binning_vertical = binv; - sensor->binning_horizontal = binh; - } - sel->r.width = (crops[CCS_PAD_SINK]->width / binh) & ~1; - sel->r.height = (crops[CCS_PAD_SINK]->height / binv) & ~1; + sel->r.width = (sink_crop->width / binh) & ~1; + sel->r.height = (sink_crop->height / binv) & ~1; } /* @@ -2322,8 +2373,7 @@ static void ccs_set_compose_binner(struct v4l2_subdev *subdev, static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) + const struct v4l2_rect *sink_crop) { struct i2c_client *client = v4l2_get_subdevdata(subdev); struct ccs_sensor *sensor = to_ccs_sensor(subdev); @@ -2335,18 +2385,14 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, unsigned int i; int best = INT_MIN; - sel->r.width = min_t(unsigned int, sel->r.width, - crops[CCS_PAD_SINK]->width); - sel->r.height = min_t(unsigned int, sel->r.height, - crops[CCS_PAD_SINK]->height); + sel->r.width = min_t(unsigned int, sel->r.width, sink_crop->width); + sel->r.height = min_t(unsigned int, sel->r.height, sink_crop->height); - a = crops[CCS_PAD_SINK]->width - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; - b = crops[CCS_PAD_SINK]->height - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; - max_m = crops[CCS_PAD_SINK]->width + a = sink_crop->width * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; + b = sink_crop->height * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; + max_m = sink_crop->width * CCS_LIM(sensor, SCALER_N_MIN) - / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); + / (CCS_LIM(sensor, MIN_X_OUTPUT_SIZE) ?: 1); a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), CCS_LIM(sensor, SCALER_M_MAX)); @@ -2376,14 +2422,12 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, } for (i = 0; i < ntry; i++) { - int this = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width - / try[i] * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.width, - crops[CCS_PAD_SINK]->height, - sel->r.height, - sel->flags); + int this = scaling_goodness(subdev, + sink_crop->width + / try[i] + * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.width, sink_crop->height, + sel->r.height, sel->flags); dev_dbg(&client->dev, "trying factor %u (%u)\n", try[i], i); @@ -2398,12 +2442,10 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, continue; this = scaling_goodness( - subdev, crops[CCS_PAD_SINK]->width - / try[i] + subdev, sink_crop->width / try[i] * CCS_LIM(sensor, SCALER_N_MIN), sel->r.width, - crops[CCS_PAD_SINK]->height - / try[i] + sink_crop->height / try[i] * CCS_LIM(sensor, SCALER_N_MIN), sel->r.height, sel->flags); @@ -2415,23 +2457,13 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, } } - sel->r.width = - (crops[CCS_PAD_SINK]->width - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; + sel->r.width = (sink_crop->width / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; if (mode == SMIAPP_SCALING_MODE_BOTH) - sel->r.height = - (crops[CCS_PAD_SINK]->height - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) - & ~1; + sel->r.height = (sink_crop->height / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; else - sel->r.height = crops[CCS_PAD_SINK]->height; - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->scale_m = scale_m; - sensor->scaling_mode = mode; - } + sel->r.height = sink_crop->height; } /* We're only called on source pads. This function sets scaling. */ static int ccs_set_compose(struct v4l2_subdev *subdev, @@ -2440,20 +2472,24 @@ static int ccs_set_compose(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; + const struct v4l2_rect *sink_crop; + struct v4l2_rect *comp; - ccs_get_crop_compose(subdev, sd_state, crops, &comp); + sink_crop = v4l2_subdev_state_get_crop(sd_state, CCS_PAD_SINK, + CCS_STREAM_PIXEL); + comp = v4l2_subdev_state_get_compose(sd_state, ssd->sink_pad, + CCS_STREAM_PIXEL); sel->r.top = 0; sel->r.left = 0; if (ssd == sensor->binner) - ccs_set_compose_binner(subdev, sd_state, sel, crops, comp); + ccs_set_compose_binner(subdev, sd_state, sel, sink_crop); else - ccs_set_compose_scaler(subdev, sd_state, sel, crops, comp); + ccs_set_compose_scaler(subdev, sd_state, sel, sink_crop); *comp = sel->r; - ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_COMPOSE); + ccs_propagate(subdev, sd_state, V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) return ccs_pll_blanking_update(sensor); @@ -2505,9 +2541,13 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect src_size = { 0 }, *crops[CCS_PADS], *comp; + struct v4l2_rect src_size = { 0 }, *crop; + const struct v4l2_rect *comp; - ccs_get_crop_compose(subdev, sd_state, crops, &comp); + crop = v4l2_subdev_state_get_crop(sd_state, sel->pad, + CCS_STREAM_PIXEL); + comp = v4l2_subdev_state_get_compose(sd_state, ssd->sink_pad, + CCS_STREAM_PIXEL); if (sel->pad == ssd->sink_pad) { struct v4l2_mbus_framefmt *mfmt = @@ -2530,13 +2570,10 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, sel->r.left = min_t(int, sel->r.left, src_size.width - sel->r.width); sel->r.top = min_t(int, sel->r.top, src_size.height - sel->r.height); - *crops[sel->pad] = sel->r; + *crop = sel->r; if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) - ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_CROP); - else if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && - ssd == sensor->pixel_array) - sensor->pa_src = sel->r; + ccs_propagate(subdev, sd_state, V4L2_SEL_TGT_CROP); return 0; } @@ -2555,14 +2592,17 @@ static int ccs_get_selection(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; + const struct v4l2_rect *crop, *comp; int ret; ret = ccs_sel_supported(subdev, sel); if (ret) return ret; - ccs_get_crop_compose(subdev, sd_state, crops, &comp); + crop = v4l2_subdev_state_get_crop(sd_state, sel->pad, + CCS_STREAM_PIXEL); + comp = v4l2_subdev_state_get_compose(sd_state, ssd->sink_pad, + CCS_STREAM_PIXEL); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: @@ -2582,7 +2622,7 @@ static int ccs_get_selection(struct v4l2_subdev *subdev, break; case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_COMPOSE_BOUNDS: - sel->r = *crops[sel->pad]; + sel->r = *crop; break; case V4L2_SEL_TGT_COMPOSE: sel->r = *comp; @@ -2603,8 +2643,6 @@ static int ccs_set_selection(struct v4l2_subdev *subdev, if (ret) return ret; - mutex_lock(&sensor->mutex); - sel->r.left = max(0, sel->r.left & ~1); sel->r.top = max(0, sel->r.top & ~1); sel->r.width = CCS_ALIGN_DIM(sel->r.width, sel->flags); @@ -2626,10 +2664,44 @@ static int ccs_set_selection(struct v4l2_subdev *subdev, ret = -EINVAL; } - mutex_unlock(&sensor->mutex); return ret; } +static int ccs_get_frame_desc(struct v4l2_subdev *subdev, unsigned int pad, + struct v4l2_mbus_frame_desc *desc) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct v4l2_mbus_frame_desc_entry *entry = desc->entry; + struct v4l2_subdev_state *sd_state; + + switch (sensor->hwcfg.csi_signalling_mode) { + case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: + case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: + desc->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + break; + default: + /* FIXME: CCP2 support */ + return -EINVAL; + } + + sd_state = v4l2_subdev_lock_and_get_active_state(subdev); + if (!sd_state) + return -EINVAL; + + entry->pixelcode = sensor->csi_format->code; + entry->stream = CCS_STREAM_PIXEL; + entry->bus.csi2.dt = + sensor->csi_format->width == sensor->csi_format->compressed ? + ccs_mipi_csi2_data_type(sensor->csi_format->width) : + CCS_DEFAULT_COMPRESSED_DT; + entry++; + desc->num_entries++; + + v4l2_subdev_unlock_state(sd_state); + + return 0; +} + static int ccs_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); @@ -2940,6 +3012,8 @@ static void ccs_cleanup(struct ccs_sensor *sensor) ccs_free_controls(sensor); } +static const struct v4l2_subdev_internal_ops ccs_internal_ops; + static int ccs_init_subdev(struct ccs_sensor *sensor, struct ccs_subdev *ssd, const char *name, unsigned short num_pads, u32 function, @@ -2952,11 +3026,14 @@ static int ccs_init_subdev(struct ccs_sensor *sensor, if (!ssd) return 0; - if (ssd != sensor->src) + if (ssd != sensor->src) { v4l2_subdev_init(&ssd->sd, &ccs_ops); + ssd->sd.internal_ops = &ccs_internal_ops; + } ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ssd->sd.entity.function = function; + ssd->sd.state_lock = &sensor->mutex; ssd->sensor = sensor; ssd->npads = num_pads; @@ -3002,9 +3079,8 @@ static int ccs_init_state(struct v4l2_subdev *sd, v4l2_subdev_state_get_format(sd_state, pad); struct v4l2_rect *crop = v4l2_subdev_state_get_crop(sd_state, pad); - bool is_active = !sd->active_state || sd->active_state == sd_state; - mutex_lock(&sensor->mutex); + guard(mutex)(&sensor->mutex); ccs_get_native_size(ssd, crop); @@ -3013,28 +3089,21 @@ static int ccs_init_state(struct v4l2_subdev *sd, fmt->code = sensor->internal_csi_format->code; fmt->field = V4L2_FIELD_NONE; - if (ssd == sensor->pixel_array) { - if (is_active) - sensor->pa_src = *crop; - - mutex_unlock(&sensor->mutex); + if (ssd == sensor->pixel_array) return 0; - } fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC); fmt->code = ssd == sensor->src ? sensor->csi_format->code : sensor->internal_csi_format->code; fmt->field = V4L2_FIELD_NONE; - ccs_propagate(sd, sd_state, is_active, V4L2_SEL_TGT_CROP); - - mutex_unlock(&sensor->mutex); + ccs_propagate(sd, sd_state, V4L2_SEL_TGT_CROP); return 0; } static const struct v4l2_subdev_video_ops ccs_video_ops = { - .s_stream = ccs_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, .pre_streamon = ccs_pre_streamon, .post_streamoff = ccs_post_streamoff, }; @@ -3045,6 +3114,9 @@ static const struct v4l2_subdev_pad_ops ccs_pad_ops = { .set_fmt = ccs_set_format, .get_selection = ccs_get_selection, .set_selection = ccs_set_selection, + .enable_streams = ccs_enable_streams, + .disable_streams = ccs_disable_streams, + .get_frame_desc = ccs_get_frame_desc, }; static const struct v4l2_subdev_sensor_ops ccs_sensor_ops = { @@ -3062,6 +3134,10 @@ static const struct media_entity_operations ccs_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; +static const struct v4l2_subdev_internal_ops ccs_internal_ops = { + .init_state = ccs_init_state, +}; + static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { .init_state = ccs_init_state, .registered = ccs_registered, @@ -3074,11 +3150,9 @@ static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) { - struct ccs_hwconfig *hwcfg = &sensor->hwcfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_UNKNOWN }; - struct fwnode_handle *ep; - struct fwnode_handle *fwnode = dev_fwnode(dev); - unsigned int i; + struct fwnode_handle *fwnode = dev_fwnode(dev), *ep; + struct ccs_hwconfig *hwcfg = &sensor->hwcfg; int rval; ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, @@ -3105,9 +3179,9 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) break; case V4L2_MBUS_CSI1: case V4L2_MBUS_CCP2: - hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; + hwcfg->csi_signalling_mode = bus_cfg.bus.mipi_csi1.strobe ? + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; hwcfg->lanes = 1; break; default: @@ -3116,11 +3190,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) goto out_err; } - rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &hwcfg->ext_clk); - - dev_dbg(dev, "clk %u, mode %u\n", hwcfg->ext_clk, - hwcfg->csi_signalling_mode); + dev_dbg(dev, "signalling mode: %u\n", hwcfg->csi_signalling_mode); if (!bus_cfg.nr_of_link_frequencies) { dev_warn(dev, "no link frequencies defined\n"); @@ -3128,23 +3198,22 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) goto out_err; } - hwcfg->op_sys_clock = devm_kcalloc( - dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, - sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); + hwcfg->op_sys_clock = + devm_kcalloc(dev, + bus_cfg.nr_of_link_frequencies + 1 /* guardian */, + sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); if (!hwcfg->op_sys_clock) { rval = -ENOMEM; goto out_err; } - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + for (unsigned int i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; dev_dbg(dev, "freq %u: %lld\n", i, hwcfg->op_sys_clock[i]); } - v4l2_fwnode_endpoint_free(&bus_cfg); - fwnode_handle_put(ep); - - return 0; + fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &hwcfg->ext_clk); out_err: v4l2_fwnode_endpoint_free(&bus_cfg); @@ -3232,47 +3301,30 @@ static int ccs_probe(struct i2c_client *client) return rval; } - sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (PTR_ERR(sensor->ext_clk) == -ENOENT) { - dev_info(&client->dev, "no clock defined, continuing...\n"); - sensor->ext_clk = NULL; - } else if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock (%pe)\n", - sensor->ext_clk); - return -EPROBE_DEFER; - } + sensor->ext_clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(sensor->ext_clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->ext_clk), + "could not get clock\n"); - if (sensor->ext_clk) { - if (sensor->hwcfg.ext_clk) { - unsigned long rate; + if (sensor->hwcfg.ext_clk) { + unsigned long rate; - rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg.ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", - sensor->hwcfg.ext_clk); - return rval; - } - - rate = clk_get_rate(sensor->ext_clk); - if (rate != sensor->hwcfg.ext_clk) { - dev_err(&client->dev, - "can't set clock freq, asked for %u but got %lu\n", - sensor->hwcfg.ext_clk, rate); - return -EINVAL; - } - } else { - sensor->hwcfg.ext_clk = clk_get_rate(sensor->ext_clk); - dev_dbg(&client->dev, "obtained clock freq %u\n", - sensor->hwcfg.ext_clk); + rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg.ext_clk); + if (rval < 0) + return dev_err_probe(&client->dev, rval, + "unable to set clock freq to %u\n", + sensor->hwcfg.ext_clk); + + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg.ext_clk) { + return dev_err_probe(&client->dev, -EINVAL, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg.ext_clk, rate); } - } else if (sensor->hwcfg.ext_clk) { - dev_dbg(&client->dev, "assuming clock freq %u\n", - sensor->hwcfg.ext_clk); } else { - dev_err(&client->dev, "unable to obtain clock freq\n"); - return -EINVAL; + sensor->hwcfg.ext_clk = clk_get_rate(sensor->ext_clk); + dev_dbg(&client->dev, "obtained clock freq %u\n", + sensor->hwcfg.ext_clk); } if (!sensor->hwcfg.ext_clk) { @@ -3384,8 +3436,6 @@ static int ccs_probe(struct i2c_client *client) sensor->binning_subtypes[i].vertical); } } - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; if (device_create_file(&client->dev, &dev_attr_ident) != 0) { dev_err(&client->dev, "sysfs ident entry creation failed\n"); @@ -3422,10 +3472,22 @@ static int ccs_probe(struct i2c_client *client) sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; sensor->ssds_used++; - sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); - /* prepare PLL configuration input values */ - sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; + switch (sensor->hwcfg.csi_signalling_mode) { + case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: + sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY; + break; + case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: + case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK: + case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE: + sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; + break; + default: + dev_err(&client->dev, "unsupported signalling mode %u\n", + sensor->hwcfg.csi_signalling_mode); + rval = -EINVAL; + goto out_cleanup; + } sensor->pll.csi2.lanes = sensor->hwcfg.lanes; if (CCS_LIM(sensor, CLOCK_CALCULATION) & CCS_CLOCK_CALCULATION_LANE_SPEED) { @@ -3517,15 +3579,13 @@ static int ccs_probe(struct i2c_client *client) goto out_cleanup; } - mutex_lock(&sensor->mutex); - rval = ccs_pll_blanking_update(sensor); - mutex_unlock(&sensor->mutex); + scoped_guard(mutex, &sensor->mutex) + rval = ccs_pll_blanking_update(sensor); if (rval) { dev_err(&client->dev, "update mode failed\n"); goto out_cleanup; } - sensor->streaming = false; sensor->dev_init_done = true; sensor->handler_setup_needed = true; |
