// SPDX-License-Identifier: GPL-2.0 /* * A V4L2 driver for Sony IMX219 cameras. * Copyright (C) 2019, Raspberry Pi (Trading) Ltd * * Based on Sony imx258 camera driver * Copyright (C) 2018 Intel Corporation * * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver * Copyright 2018 Qtechnology A/S * * Flip handling taken from the Sony IMX319 driver. * Copyright (C) 2018 Intel Corporation *
*/
staticconst s64 imx219_link_freq_4lane_menu[] = {
IMX219_DEFAULT_LINK_FREQ_4LANE, /* * This will never be advertised to userspace, but will be used for * v4l2_link_freq_to_bitmap
*/
IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED,
};
/* regulator supplies */ staticconstchar * const imx219_supply_name[] = { /* Supplies can be enabled in any order */ "VANA", /* Analog (2.8V) supply */ "VDIG", /* Digital Core (1.8V) supply */ "VDDL", /* IF (1.2V) supply */
};
/* * The supported formats. * This table MUST contain 4 entries per format, to cover the various flip * combinations in the order * - no flip * - h flip * - v flip * - h&v flips
*/ staticconst u32 imx219_mbus_formats[] = {
MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SGRBG10_1X10,
MEDIA_BUS_FMT_SGBRG10_1X10,
MEDIA_BUS_FMT_SBGGR10_1X10,
/* * Initialisation delay between XCLR low->high and the moment when the sensor * can start capture (i.e. can leave software stanby) must be not less than: * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>) * where * t4 is fixed, and is max 200uS, * t5 is fixed, and is 6000uS, * t6 depends on the sensor external clock, and is max 32000 clock periods. * As per sensor datasheet, the external clock must be from 6MHz to 27MHz. * So for any acceptable external clock t6 is always within the range of * 1185 to 5333 uS, and is always less than t5. * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then * initialize the sensor over I2C, and then exit the software standby. * * This start-up time can be optimized a bit more, if we start the writes * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor * initialization over I2C may complete before (t4+t5) expires, and we must * ensure that capture is not started before (t4+t5). * * This delay doesn't account for the power supply startup time. If needed, * this should be taken care of via the regulator framework. E.g. in the * case of DT for regulator-fixed one should define the startup-delay-us * property.
*/ #define IMX219_XCLR_MIN_DELAY_US 6200 #define IMX219_XCLR_DELAY_RANGE_US 1000
/* Get bayer order based on flip setting. */ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
{ unsignedint i;
for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++) if (imx219_mbus_formats[i] == code) break;
if (i >= ARRAY_SIZE(imx219_mbus_formats))
i = 0;
i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
(imx219->hflip->val ? 1 : 0);
return imx219_mbus_formats[i];
}
static u32 imx219_get_format_bpp(conststruct v4l2_mbus_framefmt *format)
{ switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: return 8;
case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: default: return 10;
}
}
/* * Use analog binning only if both dimensions are binned, as it crops * the other dimension.
*/ if (hbin == 2 && vbin == 2) {
*bin_h = IMX219_BINNING_X2_ANALOG;
*bin_v = IMX219_BINNING_X2_ANALOG;
return;
}
if (hbin == 2)
*bin_h = IMX219_BINNING_X2; if (vbin == 2)
*bin_v = IMX219_BINNING_X2;
}
state = v4l2_subdev_get_locked_active_state(&imx219->sd);
format = v4l2_subdev_state_get_format(state, 0);
rate_factor = imx219_get_rate_factor(state);
if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max, exposure_def;
ret = pm_runtime_resume_and_get(&client->dev); if (ret < 0) return ret;
/* Send all registers that are common to all modes */
ret = cci_multi_reg_write(imx219->regmap, imx219_common_regs,
ARRAY_SIZE(imx219_common_regs), NULL); if (ret) {
dev_err(&client->dev, "%s failed to send mfg header\n", __func__); goto err_rpm_put;
}
/* Configure two or four Lane mode */
ret = imx219_configure_lanes(imx219); if (ret) {
dev_err(&client->dev, "%s failed to configure lanes\n", __func__); goto err_rpm_put;
}
/* Apply format and crop settings. */
ret = imx219_set_framefmt(imx219, state); if (ret) {
dev_err(&client->dev, "%s failed to set frame format: %d\n",
__func__, ret); goto err_rpm_put;
}
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) goto err_rpm_put;
/* set stream on register */
ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT,
IMX219_MODE_STREAMING, NULL); if (ret) goto err_rpm_put;
/* vflip and hflip cannot change during streaming */
__v4l2_ctrl_grab(imx219->vflip, true);
__v4l2_ctrl_grab(imx219->hflip, true);
/* set stream off register */
ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT,
IMX219_MODE_STANDBY, NULL); if (ret)
dev_err(&client->dev, "%s failed to set stream\n", __func__);
/* * Use binning to maximize the crop rectangle size, and centre it in the * sensor.
*/
bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U);
bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { int exposure_max; int exposure_def; int hblank, llp_min; int pixel_rate;
/* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
IMX219_FLL_MAX - mode->height, 1,
mode->fll_def - mode->height);
__v4l2_ctrl_s_ctrl(imx219->vblank,
mode->fll_def - mode->height); /* Update max exposure while meeting expected vblanking */
exposure_max = mode->fll_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
__v4l2_ctrl_modify_range(imx219->exposure,
imx219->exposure->minimum,
exposure_max, imx219->exposure->step,
exposure_def);
/* * With analog binning the default minimum line length of 3448 * can cause artefacts with RAW10 formats, because the ADC * operates on two lines together. So we switch to a higher * minimum of 3560.
*/
imx219_get_binning(state, &bin_h, &bin_v);
llp_min = (bin_h & bin_v) == IMX219_BINNING_X2_ANALOG ?
IMX219_BINNED_LLP_MIN : IMX219_LLP_MIN;
__v4l2_ctrl_modify_range(imx219->hblank, llp_min - mode->width,
IMX219_LLP_MAX - mode->width, 1,
llp_min - mode->width); /* * Retain PPL setting from previous mode so that the * line time does not change on a mode change. * Limits have to be recomputed as the controls define * the blanking only, so PPL values need to have the * mode width subtracted.
*/
hblank = prev_line_len - mode->width;
__v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
/* Scale the pixel rate based on the mode specific factor */
pixel_rate = imx219_get_pixel_rate(imx219) *
imx219_get_rate_factor(state);
__v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate,
pixel_rate, 1, pixel_rate);
}
/* Verify chip ID */ staticint imx219_identify_module(struct imx219 *imx219)
{ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); int ret;
u64 val;
ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); if (ret) return dev_err_probe(&client->dev, ret, "failed to read chip id %x\n",
IMX219_CHIP_ID);
if (val != IMX219_CHIP_ID) return dev_err_probe(&client->dev, -EIO, "chip id mismatch: %x!=%llx\n",
IMX219_CHIP_ID, val);
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); if (!endpoint) return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
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_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 */ switch (imx219->lanes) { case 2:
ret = v4l2_link_freq_to_bitmap(dev,
ep_cfg.link_frequencies,
ep_cfg.nr_of_link_frequencies,
imx219_link_freq_menu,
ARRAY_SIZE(imx219_link_freq_menu),
&link_freq_bitmap); break; case 4:
ret = v4l2_link_freq_to_bitmap(dev,
ep_cfg.link_frequencies,
ep_cfg.nr_of_link_frequencies,
imx219_link_freq_4lane_menu,
ARRAY_SIZE(imx219_link_freq_4lane_menu),
&link_freq_bitmap);
if (!ret && (link_freq_bitmap & BIT(1))) {
dev_warn(dev, "Link frequency of %d not supported, but has been incorrectly advertised previously\n",
IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED);
dev_warn(dev, "Using link frequency of %d\n",
IMX219_DEFAULT_LINK_FREQ_4LANE);
link_freq_bitmap |= BIT(0);
} break;
}
if (ret || !(link_freq_bitmap & BIT(0))) {
ret = -EINVAL;
dev_err_probe(dev, -EINVAL, "Link frequency not supported: %lld\n",
ep_cfg.link_frequencies[0]);
}
/* Check the hardware configuration in device tree */ if (imx219_check_hwcfg(dev, imx219)) return -EINVAL;
imx219->regmap = devm_cci_regmap_init_i2c(client, 16); 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)) 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) return dev_err_probe(dev, -EINVAL, "xclk frequency not supported: %d Hz\n",
imx219->xclk_freq);
ret = imx219_get_regulators(imx219); if (ret) return dev_err_probe(dev, ret, "failed to get regulators\n");
/* * The sensor must be powered for imx219_identify_module() * to be able to read the CHIP_ID register
*/
ret = imx219_power_on(dev); if (ret) return ret;
ret = imx219_identify_module(imx219); if (ret) goto error_power_off;
/* * Sensor doesn't enter LP-11 state upon power up until and unless * streaming is started, so upon power up switch the modes to: * streaming -> standby
*/
ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT,
IMX219_MODE_STREAMING, NULL); if (ret < 0) goto error_power_off;
usleep_range(100, 110);
/* put sensor back to standby mode */
ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT,
IMX219_MODE_STANDBY, NULL); if (ret < 0) goto error_power_off;
usleep_range(100, 110);
ret = imx219_init_controls(imx219); if (ret) goto error_power_off;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.