diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 18:50:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 18:50:03 +0000 |
commit | 01a69402cf9d38ff180345d55c2ee51c7e89fbc7 (patch) | |
tree | b406c5242a088c4f59c6e4b719b783f43aca6ae9 /drivers/media/i2c/imx335.c | |
parent | Adding upstream version 6.7.12. (diff) | |
download | linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.tar.xz linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.zip |
Adding upstream version 6.8.9.upstream/6.8.9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/media/i2c/imx335.c')
-rw-r--r-- | drivers/media/i2c/imx335.c | 223 |
1 files changed, 186 insertions, 37 deletions
diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 964a81bec5..7a37eb327f 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -55,6 +55,14 @@ #define IMX335_REG_MIN 0x00 #define IMX335_REG_MAX 0xfffff +/* IMX335 native and active pixel array size. */ +#define IMX335_NATIVE_WIDTH 2616U +#define IMX335_NATIVE_HEIGHT 1964U +#define IMX335_PIXEL_ARRAY_LEFT 12U +#define IMX335_PIXEL_ARRAY_TOP 12U +#define IMX335_PIXEL_ARRAY_WIDTH 2592U +#define IMX335_PIXEL_ARRAY_HEIGHT 1944U + /** * struct imx335_reg - imx335 sensor register * @address: Register address @@ -75,6 +83,12 @@ struct imx335_reg_list { const struct imx335_reg *regs; }; +static const char * const imx335_supply_name[] = { + "avdd", /* Analog (2.9V) supply */ + "ovdd", /* Digital I/O (1.8V) supply */ + "dvdd", /* Digital Core (1.2V) supply */ +}; + /** * struct imx335_mode - imx335 sensor mode structure * @width: Frame width @@ -108,6 +122,7 @@ struct imx335_mode { * @sd: V4L2 sub-device * @pad: Media pad. Only one pad supported * @reset_gpio: Sensor reset gpio + * @supplies: Regulator supplies to handle power control * @inclk: Sensor input clock * @ctrl_handler: V4L2 control handler * @link_freq_ctrl: Pointer to link frequency control @@ -119,6 +134,7 @@ struct imx335_mode { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls + * @cur_mbus_code: Currently selected media bus format code */ struct imx335 { struct device *dev; @@ -126,6 +142,8 @@ struct imx335 { struct v4l2_subdev sd; struct media_pad pad; struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx335_supply_name)]; + struct clk *inclk; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *link_freq_ctrl; @@ -139,6 +157,7 @@ struct imx335 { u32 vblank; const struct imx335_mode *cur_mode; struct mutex mutex; + u32 cur_mbus_code; }; static const s64 link_freq[] = { @@ -233,6 +252,25 @@ static const struct imx335_reg mode_2592x1940_regs[] = { {0x3a00, 0x01}, }; +static const struct imx335_reg raw10_framefmt_regs[] = { + {0x3050, 0x00}, + {0x319d, 0x00}, + {0x341c, 0xff}, + {0x341d, 0x01}, +}; + +static const struct imx335_reg raw12_framefmt_regs[] = { + {0x3050, 0x01}, + {0x319d, 0x01}, + {0x341c, 0x47}, + {0x341d, 0x00}, +}; + +static const u32 imx335_mbus_codes[] = { + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SRGGB10_1X10, +}; + /* Supported sensor mode configurations */ static const struct imx335_mode supported_mode = { .width = 2592, @@ -243,7 +281,6 @@ static const struct imx335_mode supported_mode = { .vblank_max = 133060, .pclk = 396000000, .link_freq_idx = 0, - .code = MEDIA_BUS_FMT_SRGGB12_1X12, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), .regs = mode_2592x1940_regs, @@ -396,7 +433,7 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) lpfr = imx335->vblank + imx335->cur_mode->height; shutter = lpfr - exposure; - dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", + 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); @@ -443,7 +480,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VBLANK: imx335->vblank = imx335->vblank_ctrl->val; - dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u", + dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n", imx335->vblank, imx335->vblank + imx335->cur_mode->height); @@ -462,7 +499,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) exposure = ctrl->val; analog_gain = imx335->again_ctrl->val; - dev_dbg(imx335->dev, "Received exp %u, analog gain %u", + dev_dbg(imx335->dev, "Received exp %u, analog gain %u\n", exposure, analog_gain); ret = imx335_update_exp_gain(imx335, exposure, analog_gain); @@ -471,7 +508,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) break; default: - dev_err(imx335->dev, "Invalid control %d", ctrl->id); + dev_err(imx335->dev, "Invalid control %d\n", ctrl->id); ret = -EINVAL; } @@ -483,6 +520,18 @@ static const struct v4l2_ctrl_ops imx335_ctrl_ops = { .s_ctrl = imx335_set_ctrl, }; +static int imx335_get_format_code(struct imx335 *imx335, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) { + if (imx335_mbus_codes[i] == code) + return imx335_mbus_codes[i]; + } + + return imx335_mbus_codes[0]; +} + /** * imx335_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes * @sd: pointer to imx335 V4L2 sub-device structure @@ -495,10 +544,10 @@ static int imx335_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index > 0) + if (code->index >= ARRAY_SIZE(imx335_mbus_codes)) return -EINVAL; - code->code = supported_mode.code; + code->code = imx335_mbus_codes[code->index]; return 0; } @@ -515,10 +564,14 @@ static int imx335_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fsize) { - if (fsize->index > 0) + struct imx335 *imx335 = to_imx335(sd); + u32 code; + + if (fsize->index > ARRAY_SIZE(imx335_mbus_codes)) return -EINVAL; - if (fsize->code != supported_mode.code) + code = imx335_get_format_code(imx335, fsize->code); + if (fsize->code != code) return -EINVAL; fsize->min_width = supported_mode.width; @@ -542,7 +595,7 @@ static void imx335_fill_pad_format(struct imx335 *imx335, { fmt->format.width = mode->width; fmt->format.height = mode->height; - fmt->format.code = mode->code; + fmt->format.code = imx335->cur_mbus_code; fmt->format.field = V4L2_FIELD_NONE; fmt->format.colorspace = V4L2_COLORSPACE_RAW; fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; @@ -569,7 +622,7 @@ static int imx335_get_pad_format(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx335_fill_pad_format(imx335, imx335->cur_mode, fmt); @@ -594,17 +647,22 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, { struct imx335 *imx335 = to_imx335(sd); const struct imx335_mode *mode; - int ret = 0; + int i, ret = 0; mutex_lock(&imx335->mutex); mode = &supported_mode; + for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) { + if (imx335_mbus_codes[i] == fmt->format.code) + imx335->cur_mbus_code = imx335_mbus_codes[i]; + } + imx335_fill_pad_format(imx335, mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { ret = imx335_update_controls(imx335, mode); @@ -618,14 +676,14 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, } /** - * imx335_init_pad_cfg() - Initialize sub-device pad configuration + * imx335_init_state() - Initialize sub-device state * @sd: pointer to imx335 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration * * Return: 0 if successful, error code otherwise. */ -static int imx335_init_pad_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int imx335_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct imx335 *imx335 = to_imx335(sd); struct v4l2_subdev_format fmt = { 0 }; @@ -637,6 +695,56 @@ static int imx335_init_pad_cfg(struct v4l2_subdev *sd, } /** + * imx335_get_selection() - Selection API + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @sel: V4L2 selection info + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = IMX335_NATIVE_WIDTH; + sel->r.height = IMX335_NATIVE_HEIGHT; + + return 0; + + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX335_PIXEL_ARRAY_TOP; + sel->r.left = IMX335_PIXEL_ARRAY_LEFT; + sel->r.width = IMX335_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX335_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +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)); + + case MEDIA_BUS_FMT_SRGGB12_1X12: + return imx335_write_regs(imx335, raw12_framefmt_regs, + ARRAY_SIZE(raw12_framefmt_regs)); + } + + return -EINVAL; +} + +/** * imx335_start_streaming() - Start sensor stream * @imx335: pointer to imx335 device * @@ -652,14 +760,21 @@ static int imx335_start_streaming(struct imx335 *imx335) ret = imx335_write_regs(imx335, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(imx335->dev, "fail to write initial registers"); + dev_err(imx335->dev, "fail to write initial registers\n"); + return ret; + } + + ret = imx335_set_framefmt(imx335); + if (ret) { + dev_err(imx335->dev, "%s failed to set frame format: %d\n", + __func__, ret); return ret; } /* Setup handler will write actual exposure and gain */ ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler); if (ret) { - dev_err(imx335->dev, "fail to setup handler"); + dev_err(imx335->dev, "fail to setup handler\n"); return ret; } @@ -667,7 +782,7 @@ static int imx335_start_streaming(struct imx335 *imx335) ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, 1, IMX335_MODE_STREAMING); if (ret) { - dev_err(imx335->dev, "fail to start streaming"); + dev_err(imx335->dev, "fail to start streaming\n"); return ret; } @@ -744,7 +859,7 @@ static int imx335_detect(struct imx335 *imx335) return ret; if (val != IMX335_ID) { - dev_err(imx335->dev, "chip id mismatch: %x!=%x", + dev_err(imx335->dev, "chip id mismatch: %x!=%x\n", IMX335_ID, val); return -ENXIO; } @@ -776,27 +891,40 @@ static int imx335_parse_hw_config(struct imx335 *imx335) imx335->reset_gpio = devm_gpiod_get_optional(imx335->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(imx335->reset_gpio)) { - dev_err(imx335->dev, "failed to get reset gpio %ld", + dev_err(imx335->dev, "failed to get reset gpio %ld\n", PTR_ERR(imx335->reset_gpio)); return PTR_ERR(imx335->reset_gpio); } + for (i = 0; i < ARRAY_SIZE(imx335_supply_name); i++) + imx335->supplies[i].supply = imx335_supply_name[i]; + + ret = devm_regulator_bulk_get(imx335->dev, + ARRAY_SIZE(imx335_supply_name), + imx335->supplies); + if (ret) { + dev_err(imx335->dev, "Failed to get regulators\n"); + return ret; + } + /* Get sensor input clock */ imx335->inclk = devm_clk_get(imx335->dev, NULL); if (IS_ERR(imx335->inclk)) { - dev_err(imx335->dev, "could not get inclk"); + dev_err(imx335->dev, "could not get inclk\n"); return PTR_ERR(imx335->inclk); } rate = clk_get_rate(imx335->inclk); if (rate != IMX335_INCLK_RATE) { - dev_err(imx335->dev, "inclk frequency mismatch"); + dev_err(imx335->dev, "inclk frequency mismatch\n"); return -EINVAL; } ep = fwnode_graph_get_next_endpoint(fwnode, NULL); - if (!ep) + if (!ep) { + dev_err(imx335->dev, "Failed to get next endpoint\n"); return -ENXIO; + } ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); @@ -805,14 +933,14 @@ static int imx335_parse_hw_config(struct imx335 *imx335) if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) { dev_err(imx335->dev, - "number of CSI2 data lanes %d is not supported", + "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); ret = -EINVAL; goto done_endpoint_free; } if (!bus_cfg.nr_of_link_frequencies) { - dev_err(imx335->dev, "no link frequencies defined"); + dev_err(imx335->dev, "no link frequencies defined\n"); ret = -EINVAL; goto done_endpoint_free; } @@ -821,6 +949,8 @@ static int imx335_parse_hw_config(struct imx335 *imx335) 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; done_endpoint_free: @@ -835,9 +965,10 @@ static const struct v4l2_subdev_video_ops imx335_video_ops = { }; static const struct v4l2_subdev_pad_ops imx335_pad_ops = { - .init_cfg = imx335_init_pad_cfg, .enum_mbus_code = imx335_enum_mbus_code, .enum_frame_size = imx335_enum_frame_size, + .get_selection = imx335_get_selection, + .set_selection = imx335_get_selection, .get_fmt = imx335_get_pad_format, .set_fmt = imx335_set_pad_format, }; @@ -847,6 +978,10 @@ static const struct v4l2_subdev_ops imx335_subdev_ops = { .pad = &imx335_pad_ops, }; +static const struct v4l2_subdev_internal_ops imx335_internal_ops = { + .init_state = imx335_init_state, +}; + /** * imx335_power_on() - Sensor power on sequence * @dev: pointer to i2c device @@ -859,20 +994,32 @@ static int imx335_power_on(struct device *dev) struct imx335 *imx335 = to_imx335(sd); int ret; + ret = regulator_bulk_enable(ARRAY_SIZE(imx335_supply_name), + imx335->supplies); + if (ret) { + dev_err(dev, "%s: failed to enable regulators\n", + __func__); + return ret; + } + + usleep_range(500, 550); /* Tlow */ + + /* Set XCLR */ gpiod_set_value_cansleep(imx335->reset_gpio, 1); ret = clk_prepare_enable(imx335->inclk); if (ret) { - dev_err(imx335->dev, "fail to enable inclk"); + dev_err(imx335->dev, "fail to enable inclk\n"); goto error_reset; } - usleep_range(20, 22); + usleep_range(20, 22); /* T4 */ return 0; error_reset: gpiod_set_value_cansleep(imx335->reset_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(imx335_supply_name), imx335->supplies); return ret; } @@ -889,8 +1036,8 @@ static int imx335_power_off(struct device *dev) struct imx335 *imx335 = to_imx335(sd); gpiod_set_value_cansleep(imx335->reset_gpio, 0); - clk_disable_unprepare(imx335->inclk); + regulator_bulk_disable(ARRAY_SIZE(imx335_supply_name), imx335->supplies); return 0; } @@ -969,7 +1116,7 @@ static int imx335_init_controls(struct imx335 *imx335) imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; if (ctrl_hdlr->error) { - dev_err(imx335->dev, "control init failed: %d", + dev_err(imx335->dev, "control init failed: %d\n", ctrl_hdlr->error); v4l2_ctrl_handler_free(ctrl_hdlr); return ctrl_hdlr->error; @@ -999,10 +1146,11 @@ static int imx335_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops); + imx335->sd.internal_ops = &imx335_internal_ops; ret = imx335_parse_hw_config(imx335); if (ret) { - dev_err(imx335->dev, "HW configuration is not supported"); + dev_err(imx335->dev, "HW configuration is not supported\n"); return ret; } @@ -1010,24 +1158,25 @@ static int imx335_probe(struct i2c_client *client) ret = imx335_power_on(imx335->dev); if (ret) { - dev_err(imx335->dev, "failed to power-on the sensor"); + dev_err(imx335->dev, "failed to power-on the sensor\n"); goto error_mutex_destroy; } /* Check module identity */ ret = imx335_detect(imx335); if (ret) { - dev_err(imx335->dev, "failed to find sensor: %d", ret); + dev_err(imx335->dev, "failed to find sensor: %d\n", ret); goto error_power_off; } /* Set default mode to max resolution */ imx335->cur_mode = &supported_mode; + imx335->cur_mbus_code = imx335_mbus_codes[0]; imx335->vblank = imx335->cur_mode->vblank; ret = imx335_init_controls(imx335); if (ret) { - dev_err(imx335->dev, "failed to init controls: %d", ret); + dev_err(imx335->dev, "failed to init controls: %d\n", ret); goto error_power_off; } @@ -1039,14 +1188,14 @@ static int imx335_probe(struct i2c_client *client) imx335->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx335->sd.entity, 1, &imx335->pad); if (ret) { - dev_err(imx335->dev, "failed to init entity pads: %d", ret); + dev_err(imx335->dev, "failed to init entity pads: %d\n", ret); goto error_handler_free; } ret = v4l2_async_register_subdev_sensor(&imx335->sd); if (ret < 0) { dev_err(imx335->dev, - "failed to register async subdev: %d", ret); + "failed to register async subdev: %d\n", ret); goto error_media_entity; } |