mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
drivers: media: imx500: Add device id readback control
Add a new custom control V4L2_CID_USER_GET_IMX500_DEVICE_ID to allow userland to query the device id from the IMX500 sensor eeprom. Note that this device id can only be accessed when a network firmware has been upoloaded to the device, so cannot be cached on probe. Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
This commit is contained in:
committed by
Phil Elwell
parent
7f0e46a5e4
commit
5c1d35bb54
@@ -239,6 +239,7 @@ enum pad_types { IMAGE_PAD, METADATA_PAD, NUM_PADS };
|
||||
|
||||
#define V4L2_CID_USER_IMX500_INFERENCE_WINDOW (V4L2_CID_USER_IMX500_BASE + 0)
|
||||
#define V4L2_CID_USER_IMX500_NETWORK_FW_FD (V4L2_CID_USER_IMX500_BASE + 1)
|
||||
#define V4L2_CID_USER_GET_IMX500_DEVICE_ID (V4L2_CID_USER_IMX500_BASE + 2)
|
||||
|
||||
#define ONE_MIB (1024 * 1024)
|
||||
|
||||
@@ -1365,6 +1366,7 @@ struct imx500 {
|
||||
struct v4l2_ctrl *vblank;
|
||||
struct v4l2_ctrl *hblank;
|
||||
struct v4l2_ctrl *network_fw_ctrl;
|
||||
struct v4l2_ctrl *device_id;
|
||||
|
||||
struct v4l2_rect inference_window;
|
||||
|
||||
@@ -1579,6 +1581,25 @@ static int imx500_set_inference_window(struct imx500 *imx500)
|
||||
ARRAY_SIZE(window_regs), NULL);
|
||||
}
|
||||
|
||||
static int imx500_get_device_id(struct imx500 *imx500, u32 *device_id)
|
||||
{
|
||||
const u32 addr = 0xd040;
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
u64 tmp, data;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = cci_read(imx500->regmap, CCI_REG32(addr + i * 4), &tmp,
|
||||
NULL);
|
||||
if (ret)
|
||||
return -EREMOTEIO;
|
||||
data = tmp & 0xffffffff;
|
||||
device_id[i] = data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx500_reg_val_write_cbk(void *arg,
|
||||
const struct cci_reg_sequence *reg)
|
||||
{
|
||||
@@ -1619,6 +1640,7 @@ static int imx500_validate_fw_block(const char *data, size_t maxlen)
|
||||
static const char footer_id[] = { '3', '6', '9', '5' };
|
||||
|
||||
u32 data_size;
|
||||
u32 extra_bytes_size = 0;
|
||||
|
||||
const char *end = data + maxlen;
|
||||
|
||||
@@ -1635,13 +1657,16 @@ static int imx500_validate_fw_block(const char *data, size_t maxlen)
|
||||
memcpy(&data_size, data + sizeof(header_id), sizeof(data_size));
|
||||
data_size = ___constant_swab32(data_size);
|
||||
|
||||
if (end - data_size - footer_size < data)
|
||||
/* check the device_lock flag */
|
||||
extra_bytes_size = *((u8 *)(data + 0x0e)) & 0x01 ? 32 : 0;
|
||||
|
||||
if (end - data_size - footer_size - extra_bytes_size < data)
|
||||
return -1;
|
||||
if (memcmp(data + data_size + footer_size - sizeof(footer_id),
|
||||
&footer_id, sizeof(footer_id)))
|
||||
return -1;
|
||||
|
||||
return data_size + footer_size;
|
||||
return data_size + footer_size + extra_bytes_size;
|
||||
}
|
||||
|
||||
/* Parse fw block by block, returning total valid fw size */
|
||||
@@ -1875,6 +1900,7 @@ static void imx500_clear_fw_network(struct imx500 *imx500)
|
||||
imx500->fw_network = NULL;
|
||||
imx500->network_written = false;
|
||||
imx500->fw_progress = 0;
|
||||
v4l2_ctrl_activate(imx500->device_id, false);
|
||||
}
|
||||
|
||||
static int imx500_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
@@ -1997,7 +2023,31 @@ static int imx500_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx500_get_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct imx500 *imx500 = container_of(ctrl->handler, struct imx500,
|
||||
ctrl_handler);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&imx500->sd);
|
||||
u32 device_id[4] = {0};
|
||||
int ret;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_USER_GET_IMX500_DEVICE_ID:
|
||||
ret = imx500_get_device_id(imx500, device_id);
|
||||
memcpy(ctrl->p_new.p_u32, device_id, sizeof(device_id));
|
||||
break;
|
||||
default:
|
||||
dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n",
|
||||
ctrl->id, ctrl->val);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops imx500_ctrl_ops = {
|
||||
.g_volatile_ctrl = imx500_get_ctrl,
|
||||
.s_ctrl = imx500_set_ctrl,
|
||||
};
|
||||
|
||||
@@ -2592,6 +2642,8 @@ static int imx500_start_streaming(struct imx500 *imx500)
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
v4l2_ctrl_activate(imx500->device_id, true);
|
||||
}
|
||||
|
||||
/* Apply default values of current mode */
|
||||
@@ -2846,6 +2898,22 @@ static const struct v4l2_ctrl_config network_fw_fd = {
|
||||
.def = -1,
|
||||
};
|
||||
|
||||
/* Custom control to get camera device id */
|
||||
static const struct v4l2_ctrl_config cam_get_device_id = {
|
||||
.name = "Get IMX500 Device ID",
|
||||
.id = V4L2_CID_USER_GET_IMX500_DEVICE_ID,
|
||||
.dims[0] = 4,
|
||||
.ops = &imx500_ctrl_ops,
|
||||
.type = V4L2_CTRL_TYPE_U32,
|
||||
.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE |
|
||||
V4L2_CTRL_FLAG_INACTIVE,
|
||||
.elem_size = sizeof(u32),
|
||||
.min = 0x00,
|
||||
.max = U32_MAX,
|
||||
.step = 1,
|
||||
.def = 0,
|
||||
};
|
||||
|
||||
/* Initialize control handlers */
|
||||
static int imx500_init_controls(struct imx500 *imx500)
|
||||
{
|
||||
@@ -2909,6 +2977,8 @@ static int imx500_init_controls(struct imx500 *imx500)
|
||||
v4l2_ctrl_new_custom(ctrl_hdlr, &inf_window_ctrl, NULL);
|
||||
imx500->network_fw_ctrl =
|
||||
v4l2_ctrl_new_custom(ctrl_hdlr, &network_fw_fd, NULL);
|
||||
imx500->device_id =
|
||||
v4l2_ctrl_new_custom(ctrl_hdlr, &cam_get_device_id, NULL);
|
||||
|
||||
if (ctrl_hdlr->error) {
|
||||
ret = ctrl_hdlr->error;
|
||||
|
||||
Reference in New Issue
Block a user