Commit d03dfb7d authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Hans Verkuil

media: i2c: imx219: Group functions by purpose

Move functions around to group them by purpose, in order to improve
readability. No functional change is intended.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent 5ebbdd7a
......@@ -385,6 +385,10 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
return imx219_mbus_formats[i];
}
/* -----------------------------------------------------------------------------
* Controls
*/
static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx219 *imx219 =
......@@ -476,130 +480,135 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
.s_ctrl = imx219_set_ctrl,
};
static void imx219_update_pad_format(struct imx219 *imx219,
const struct imx219_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
{
/* Bayer order varies with flips */
fmt->code = imx219_get_format_code(imx219, code);
fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_RAW;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
}
static int imx219_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
/* Initialize control handlers */
static int imx219_init_controls(struct imx219 *imx219)
{
struct imx219 *imx219 = to_imx219(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
/* Initialize the format. */
format = v4l2_subdev_get_pad_format(sd, state, 0);
imx219_update_pad_format(imx219, &supported_modes[0], format,
MEDIA_BUS_FMT_SRGGB10_1X10);
/* Initialize the crop rectangle. */
crop = v4l2_subdev_get_pad_crop(sd, state, 0);
crop->top = IMX219_PIXEL_ARRAY_TOP;
crop->left = IMX219_PIXEL_ARRAY_LEFT;
crop->width = IMX219_PIXEL_ARRAY_WIDTH;
crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
const struct imx219_mode *mode = &supported_modes[0];
struct v4l2_ctrl_handler *ctrl_hdlr;
struct v4l2_fwnode_device_properties props;
int exposure_max, exposure_def, hblank;
int i, ret;
return 0;
}
ctrl_hdlr = &imx219->ctrl_handler;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
if (ret)
return ret;
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx219 *imx219 = to_imx219(sd);
/* By default, PIXEL_RATE is read only */
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_PIXEL_RATE,
imx219_get_pixel_rate(imx219),
imx219_get_pixel_rate(imx219), 1,
imx219_get_pixel_rate(imx219));
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
return -EINVAL;
imx219->link_freq =
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
(imx219->lanes == 2) ? imx219_link_freq_menu :
imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
/* Initial vblank/hblank/exposure parameters based on current mode */
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
hblank = IMX219_PPL_DEFAULT - mode->width;
imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HBLANK, hblank, hblank,
1, hblank);
if (imx219->hblank)
imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_EXPOSURE,
IMX219_EXPOSURE_MIN, exposure_max,
IMX219_EXPOSURE_STEP,
exposure_def);
return 0;
}
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
static int imx219_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct imx219 *imx219 = to_imx219(sd);
u32 code;
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
if (imx219->hflip)
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
code = imx219_get_format_code(imx219, fse->code);
if (fse->code != code)
return -EINVAL;
imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
if (imx219->vflip)
imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
fse->min_width = supported_modes[fse->index].width;
fse->max_width = fse->min_width;
fse->min_height = supported_modes[fse->index].height;
fse->max_height = fse->min_height;
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx219_test_pattern_menu) - 1,
0, 0, imx219_test_pattern_menu);
for (i = 0; i < 4; i++) {
/*
* The assumption is that
* V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
* V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
* V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
*/
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN_RED + i,
IMX219_TESTP_COLOUR_MIN,
IMX219_TESTP_COLOUR_MAX,
IMX219_TESTP_COLOUR_STEP,
IMX219_TESTP_COLOUR_MAX);
/* The "Solid color" pattern is white by default */
}
return 0;
}
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(&client->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
static int imx219_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx219 *imx219 = to_imx219(sd);
const struct imx219_mode *mode;
int exposure_max, exposure_def, hblank;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
ret = v4l2_fwnode_device_parse(&client->dev, &props);
if (ret)
goto error;
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
width, height,
fmt->format.width, fmt->format.height);
ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops,
&props);
if (ret)
goto error;
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
imx219->sd.ctrl_handler = ctrl_hdlr;
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
*format = fmt->format;
*crop = mode->crop;
error:
v4l2_ctrl_handler_free(ctrl_hdlr);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
__v4l2_ctrl_s_ctrl(imx219->vblank,
mode->vts_def - mode->height);
/* Update max exposure while meeting expected vblanking */
exposure_max = mode->vts_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);
/*
* Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
* depends on mode->width only, and is not changeble in any
* way other than changing the mode.
*/
hblank = IMX219_PPL_DEFAULT - mode->width;
__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
hblank);
}
return ret;
}
return 0;
static void imx219_free_controls(struct imx219 *imx219)
{
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
}
/* -----------------------------------------------------------------------------
* Subdev operations
*/
static int imx219_set_framefmt(struct imx219 *imx219,
struct v4l2_subdev_state *state)
{
......@@ -664,37 +673,6 @@ static int imx219_set_framefmt(struct imx219 *imx219,
return ret;
}
static int imx219_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
}
case V4L2_SEL_TGT_NATIVE_SIZE:
sel->r.top = 0;
sel->r.left = 0;
sel->r.width = IMX219_NATIVE_WIDTH;
sel->r.height = IMX219_NATIVE_HEIGHT;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r.top = IMX219_PIXEL_ARRAY_TOP;
sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0;
}
return -EINVAL;
}
static int imx219_configure_lanes(struct imx219 *imx219)
{
return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE,
......@@ -799,86 +777,159 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
/* Power/clock management functions */
static int imx219_power_on(struct device *dev)
static void imx219_update_pad_format(struct imx219 *imx219,
const struct imx219_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd);
int ret;
/* Bayer order varies with flips */
fmt->code = imx219_get_format_code(imx219, code);
fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_RAW;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
}
ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
imx219->supplies);
if (ret) {
dev_err(dev, "%s: failed to enable regulators\n",
__func__);
return ret;
}
static int imx219_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
struct imx219 *imx219 = to_imx219(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
ret = clk_prepare_enable(imx219->xclk);
if (ret) {
dev_err(dev, "%s: failed to enable clock\n",
__func__);
goto reg_off;
}
/* Initialize the format. */
format = v4l2_subdev_get_pad_format(sd, state, 0);
imx219_update_pad_format(imx219, &supported_modes[0], format,
MEDIA_BUS_FMT_SRGGB10_1X10);
gpiod_set_value_cansleep(imx219->reset_gpio, 1);
usleep_range(IMX219_XCLR_MIN_DELAY_US,
IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
/* Initialize the crop rectangle. */
crop = v4l2_subdev_get_pad_crop(sd, state, 0);
crop->top = IMX219_PIXEL_ARRAY_TOP;
crop->left = IMX219_PIXEL_ARRAY_LEFT;
crop->width = IMX219_PIXEL_ARRAY_WIDTH;
crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0;
}
reg_off:
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx219 *imx219 = to_imx219(sd);
return ret;
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
return -EINVAL;
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
return 0;
}
static int imx219_power_off(struct device *dev)
static int imx219_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd);
u32 code;
gpiod_set_value_cansleep(imx219->reset_gpio, 0);
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
clk_disable_unprepare(imx219->xclk);
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
code = imx219_get_format_code(imx219, fse->code);
if (fse->code != code)
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
fse->max_width = fse->min_width;
fse->min_height = supported_modes[fse->index].height;
fse->max_height = fse->min_height;
return 0;
}
static int imx219_get_regulators(struct imx219 *imx219)
static int imx219_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
unsigned int i;
struct imx219 *imx219 = to_imx219(sd);
const struct imx219_mode *mode;
int exposure_max, exposure_def, hblank;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
imx219->supplies[i].supply = imx219_supply_name[i];
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
width, height,
fmt->format.width, fmt->format.height);
return devm_regulator_bulk_get(&client->dev,
IMX219_NUM_SUPPLIES,
imx219->supplies);
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0);
*format = fmt->format;
*crop = mode->crop;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
__v4l2_ctrl_s_ctrl(imx219->vblank,
mode->vts_def - mode->height);
/* Update max exposure while meeting expected vblanking */
exposure_max = mode->vts_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);
/*
* Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
* depends on mode->width only, and is not changeble in any
* way other than changing the mode.
*/
hblank = IMX219_PPL_DEFAULT - mode->width;
__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
hblank);
}
return 0;
}
/* Verify chip ID */
static int imx219_identify_module(struct imx219 *imx219)
static int imx219_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
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) {
dev_err(&client->dev, "failed to read chip id %x\n",
IMX219_CHIP_ID);
return ret;
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
}
if (val != IMX219_CHIP_ID) {
dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
IMX219_CHIP_ID, val);
return -EIO;
case V4L2_SEL_TGT_NATIVE_SIZE:
sel->r.top = 0;
sel->r.left = 0;
sel->r.width = IMX219_NATIVE_WIDTH;
sel->r.height = IMX219_NATIVE_HEIGHT;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r.top = IMX219_PIXEL_ARRAY_TOP;
sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0;
}
return 0;
return -EINVAL;
}
static const struct v4l2_subdev_core_ops imx219_core_ops = {
......@@ -906,129 +957,93 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = {
};
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
{
return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
}
/* -----------------------------------------------------------------------------
* Power management
*/
/* Initialize control handlers */
static int imx219_init_controls(struct imx219 *imx219)
static int imx219_power_on(struct device *dev)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
const struct imx219_mode *mode = &supported_modes[0];
struct v4l2_ctrl_handler *ctrl_hdlr;
struct v4l2_fwnode_device_properties props;
int exposure_max, exposure_def, hblank;
int i, ret;
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd);
int ret;
ctrl_hdlr = &imx219->ctrl_handler;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
if (ret)
ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
imx219->supplies);
if (ret) {
dev_err(dev, "%s: failed to enable regulators\n",
__func__);
return ret;
}
/* By default, PIXEL_RATE is read only */
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_PIXEL_RATE,
imx219_get_pixel_rate(imx219),
imx219_get_pixel_rate(imx219), 1,
imx219_get_pixel_rate(imx219));
ret = clk_prepare_enable(imx219->xclk);
if (ret) {
dev_err(dev, "%s: failed to enable clock\n",
__func__);
goto reg_off;
}
imx219->link_freq =
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
(imx219->lanes == 2) ? imx219_link_freq_menu :
imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
gpiod_set_value_cansleep(imx219->reset_gpio, 1);
usleep_range(IMX219_XCLR_MIN_DELAY_US,
IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
/* Initial vblank/hblank/exposure parameters based on current mode */
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
hblank = IMX219_PPL_DEFAULT - mode->width;
imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HBLANK, hblank, hblank,
1, hblank);
if (imx219->hblank)
imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_EXPOSURE,
IMX219_EXPOSURE_MIN, exposure_max,
IMX219_EXPOSURE_STEP,
exposure_def);
return 0;
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
reg_off:
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
return ret;
}
imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
if (imx219->hflip)
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
static int imx219_power_off(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd);
imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
if (imx219->vflip)
imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
gpiod_set_value_cansleep(imx219->reset_gpio, 0);
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
clk_disable_unprepare(imx219->xclk);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx219_test_pattern_menu) - 1,
0, 0, imx219_test_pattern_menu);
for (i = 0; i < 4; i++) {
/*
* The assumption is that
* V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
* V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
* V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
*/
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN_RED + i,
IMX219_TESTP_COLOUR_MIN,
IMX219_TESTP_COLOUR_MAX,
IMX219_TESTP_COLOUR_STEP,
IMX219_TESTP_COLOUR_MAX);
/* The "Solid color" pattern is white by default */
}
return 0;
}
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(&client->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
/* -----------------------------------------------------------------------------
* Probe & remove
*/
ret = v4l2_fwnode_device_parse(&client->dev, &props);
if (ret)
goto error;
static int imx219_get_regulators(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
unsigned int i;
ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops,
&props);
if (ret)
goto error;
for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
imx219->supplies[i].supply = imx219_supply_name[i];
imx219->sd.ctrl_handler = ctrl_hdlr;
return devm_regulator_bulk_get(&client->dev,
IMX219_NUM_SUPPLIES,
imx219->supplies);
}
return 0;
/* Verify chip ID */
static int imx219_identify_module(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
int ret;
u64 val;
error:
v4l2_ctrl_handler_free(ctrl_hdlr);
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;
}
return ret;
}
if (val != IMX219_CHIP_ID) {
dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
IMX219_CHIP_ID, val);
return -EIO;
}
static void imx219_free_controls(struct imx219 *imx219)
{
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
return 0;
}
static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment