mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 20:22:13 +08:00
media: i2c: imx258: Make HFLIP and VFLIP controls writable
The sensor supports H & V flips, but the controls were READ_ONLY. Note that the Bayer order changes with these flips, therefore they set the V4L2_CTRL_FLAG_MODIFY_LAYOUT property. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> Signed-off-by: Luis Garcia <git@luigi311.com> Reviewed-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
parent
799c46e849
commit
4c05213aee
@ -78,8 +78,8 @@
|
|||||||
|
|
||||||
/* Orientation */
|
/* Orientation */
|
||||||
#define REG_MIRROR_FLIP_CONTROL 0x0101
|
#define REG_MIRROR_FLIP_CONTROL 0x0101
|
||||||
#define REG_CONFIG_MIRROR_FLIP 0x03
|
#define REG_CONFIG_MIRROR_HFLIP 0x01
|
||||||
#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
|
#define REG_CONFIG_MIRROR_VFLIP 0x02
|
||||||
|
|
||||||
/* IMX258 native and active pixel array size. */
|
/* IMX258 native and active pixel array size. */
|
||||||
#define IMX258_NATIVE_WIDTH 4224U
|
#define IMX258_NATIVE_WIDTH 4224U
|
||||||
@ -484,6 +484,23 @@ static const struct imx258_variant_cfg imx258_pdaf_cfg = {
|
|||||||
.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
|
.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
static const u32 codes[] = {
|
||||||
|
/* 10-bit modes. */
|
||||||
|
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||||
|
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||||
|
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||||
|
MEDIA_BUS_FMT_SBGGR10_1X10
|
||||||
|
};
|
||||||
|
|
||||||
static const char * const imx258_test_pattern_menu[] = {
|
static const char * const imx258_test_pattern_menu[] = {
|
||||||
"Disabled",
|
"Disabled",
|
||||||
"Solid Colour",
|
"Solid Colour",
|
||||||
@ -670,6 +687,8 @@ struct imx258 {
|
|||||||
struct v4l2_ctrl *vblank;
|
struct v4l2_ctrl *vblank;
|
||||||
struct v4l2_ctrl *hblank;
|
struct v4l2_ctrl *hblank;
|
||||||
struct v4l2_ctrl *exposure;
|
struct v4l2_ctrl *exposure;
|
||||||
|
struct v4l2_ctrl *hflip;
|
||||||
|
struct v4l2_ctrl *vflip;
|
||||||
|
|
||||||
/* Current mode */
|
/* Current mode */
|
||||||
const struct imx258_mode *cur_mode;
|
const struct imx258_mode *cur_mode;
|
||||||
@ -768,9 +787,23 @@ static int imx258_write_regs(struct imx258 *imx258,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get bayer order based on flip setting. */
|
||||||
|
static u32 imx258_get_format_code(const struct imx258 *imx258)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
lockdep_assert_held(&imx258->mutex);
|
||||||
|
|
||||||
|
i = (imx258->vflip->val ? 2 : 0) |
|
||||||
|
(imx258->hflip->val ? 1 : 0);
|
||||||
|
|
||||||
|
return codes[i];
|
||||||
|
}
|
||||||
|
|
||||||
/* Open sub-device */
|
/* Open sub-device */
|
||||||
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||||
{
|
{
|
||||||
|
struct imx258 *imx258 = to_imx258(sd);
|
||||||
struct v4l2_mbus_framefmt *try_fmt =
|
struct v4l2_mbus_framefmt *try_fmt =
|
||||||
v4l2_subdev_state_get_format(fh->state, 0);
|
v4l2_subdev_state_get_format(fh->state, 0);
|
||||||
struct v4l2_rect *try_crop;
|
struct v4l2_rect *try_crop;
|
||||||
@ -778,7 +811,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||||||
/* Initialize try_fmt */
|
/* Initialize try_fmt */
|
||||||
try_fmt->width = supported_modes[0].width;
|
try_fmt->width = supported_modes[0].width;
|
||||||
try_fmt->height = supported_modes[0].height;
|
try_fmt->height = supported_modes[0].height;
|
||||||
try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
try_fmt->code = imx258_get_format_code(imx258);
|
||||||
try_fmt->field = V4L2_FIELD_NONE;
|
try_fmt->field = V4L2_FIELD_NONE;
|
||||||
|
|
||||||
/* Initialize try_crop */
|
/* Initialize try_crop */
|
||||||
@ -871,10 +904,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||||||
ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
|
ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
|
||||||
IMX258_REG_VALUE_16BIT,
|
IMX258_REG_VALUE_16BIT,
|
||||||
ctrl->val);
|
ctrl->val);
|
||||||
ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
|
|
||||||
IMX258_REG_VALUE_08BIT,
|
|
||||||
!ctrl->val ? REG_CONFIG_MIRROR_FLIP :
|
|
||||||
REG_CONFIG_FLIP_TEST_PATTERN);
|
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_WIDE_DYNAMIC_RANGE:
|
case V4L2_CID_WIDE_DYNAMIC_RANGE:
|
||||||
if (!ctrl->val) {
|
if (!ctrl->val) {
|
||||||
@ -897,6 +926,15 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||||||
IMX258_REG_VALUE_16BIT,
|
IMX258_REG_VALUE_16BIT,
|
||||||
imx258->cur_mode->height + ctrl->val);
|
imx258->cur_mode->height + ctrl->val);
|
||||||
break;
|
break;
|
||||||
|
case V4L2_CID_VFLIP:
|
||||||
|
case V4L2_CID_HFLIP:
|
||||||
|
ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
|
||||||
|
IMX258_REG_VALUE_08BIT,
|
||||||
|
(imx258->hflip->val ?
|
||||||
|
REG_CONFIG_MIRROR_HFLIP : 0) |
|
||||||
|
(imx258->vflip->val ?
|
||||||
|
REG_CONFIG_MIRROR_VFLIP : 0));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_info(&client->dev,
|
dev_info(&client->dev,
|
||||||
"ctrl(id:0x%x,val:0x%x) is not handled\n",
|
"ctrl(id:0x%x,val:0x%x) is not handled\n",
|
||||||
@ -918,11 +956,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
|
|||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_mbus_code_enum *code)
|
struct v4l2_subdev_mbus_code_enum *code)
|
||||||
{
|
{
|
||||||
/* Only one bayer order(GRBG) is supported */
|
struct imx258 *imx258 = to_imx258(sd);
|
||||||
|
|
||||||
|
/* Only one bayer format (10 bit) is supported */
|
||||||
if (code->index > 0)
|
if (code->index > 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
code->code = imx258_get_format_code(imx258);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -931,10 +971,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
|
|||||||
struct v4l2_subdev_state *sd_state,
|
struct v4l2_subdev_state *sd_state,
|
||||||
struct v4l2_subdev_frame_size_enum *fse)
|
struct v4l2_subdev_frame_size_enum *fse)
|
||||||
{
|
{
|
||||||
|
struct imx258 *imx258 = to_imx258(sd);
|
||||||
if (fse->index >= ARRAY_SIZE(supported_modes))
|
if (fse->index >= ARRAY_SIZE(supported_modes))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
|
if (fse->code != imx258_get_format_code(imx258))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fse->min_width = supported_modes[fse->index].width;
|
fse->min_width = supported_modes[fse->index].width;
|
||||||
@ -945,12 +986,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx258_update_pad_format(const struct imx258_mode *mode,
|
static void imx258_update_pad_format(struct imx258 *imx258,
|
||||||
|
const struct imx258_mode *mode,
|
||||||
struct v4l2_subdev_format *fmt)
|
struct v4l2_subdev_format *fmt)
|
||||||
{
|
{
|
||||||
fmt->format.width = mode->width;
|
fmt->format.width = mode->width;
|
||||||
fmt->format.height = mode->height;
|
fmt->format.height = mode->height;
|
||||||
fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
fmt->format.code = imx258_get_format_code(imx258);
|
||||||
fmt->format.field = V4L2_FIELD_NONE;
|
fmt->format.field = V4L2_FIELD_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,7 +1004,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
|
|||||||
fmt->format = *v4l2_subdev_state_get_format(sd_state,
|
fmt->format = *v4l2_subdev_state_get_format(sd_state,
|
||||||
fmt->pad);
|
fmt->pad);
|
||||||
else
|
else
|
||||||
imx258_update_pad_format(imx258->cur_mode, fmt);
|
imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -998,13 +1040,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
|
|||||||
|
|
||||||
mutex_lock(&imx258->mutex);
|
mutex_lock(&imx258->mutex);
|
||||||
|
|
||||||
/* Only one raw bayer(GBRG) order is supported */
|
fmt->format.code = imx258_get_format_code(imx258);
|
||||||
fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
|
||||||
|
|
||||||
mode = v4l2_find_nearest_size(supported_modes,
|
mode = v4l2_find_nearest_size(supported_modes,
|
||||||
ARRAY_SIZE(supported_modes), width, height,
|
ARRAY_SIZE(supported_modes), width, height,
|
||||||
fmt->format.width, fmt->format.height);
|
fmt->format.width, fmt->format.height);
|
||||||
imx258_update_pad_format(mode, fmt);
|
imx258_update_pad_format(imx258, mode, fmt);
|
||||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||||
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
|
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
|
||||||
*framefmt = fmt->format;
|
*framefmt = fmt->format;
|
||||||
@ -1154,15 +1195,6 @@ static int imx258_start_streaming(struct imx258 *imx258)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Orientation be 180 degree */
|
|
||||||
ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
|
|
||||||
IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&client->dev, "%s failed to set orientation\n",
|
|
||||||
__func__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply customized values from user */
|
/* Apply customized values from user */
|
||||||
ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
|
ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1315,7 +1347,6 @@ static int imx258_init_controls(struct imx258 *imx258)
|
|||||||
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
|
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
|
||||||
const struct imx258_link_freq_config *link_freq_cfgs;
|
const struct imx258_link_freq_config *link_freq_cfgs;
|
||||||
struct v4l2_fwnode_device_properties props;
|
struct v4l2_fwnode_device_properties props;
|
||||||
struct v4l2_ctrl *vflip, *hflip;
|
|
||||||
struct v4l2_ctrl_handler *ctrl_hdlr;
|
struct v4l2_ctrl_handler *ctrl_hdlr;
|
||||||
const struct imx258_link_cfg *link_cfg;
|
const struct imx258_link_cfg *link_cfg;
|
||||||
s64 vblank_def;
|
s64 vblank_def;
|
||||||
@ -1340,16 +1371,15 @@ static int imx258_init_controls(struct imx258 *imx258)
|
|||||||
if (imx258->link_freq)
|
if (imx258->link_freq)
|
||||||
imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||||
|
|
||||||
/* The driver only supports one bayer order and flips by default. */
|
imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
|
||||||
hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
|
V4L2_CID_HFLIP, 0, 1, 1, 1);
|
||||||
V4L2_CID_HFLIP, 1, 1, 1, 1);
|
if (imx258->hflip)
|
||||||
if (hflip)
|
imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
|
||||||
hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
|
||||||
|
|
||||||
vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
|
imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
|
||||||
V4L2_CID_VFLIP, 1, 1, 1, 1);
|
V4L2_CID_VFLIP, 0, 1, 1, 1);
|
||||||
if (vflip)
|
if (imx258->vflip)
|
||||||
vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
|
||||||
|
|
||||||
link_freq_cfgs = &imx258->link_freq_configs[0];
|
link_freq_cfgs = &imx258->link_freq_configs[0];
|
||||||
link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
|
link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
|
||||||
|
Loading…
Reference in New Issue
Block a user