Skip to content

Commit ceddfd4

Browse files
aford173mchehab
authored andcommitted
media: i2c: imx219: Support four-lane operation
The imx219 camera is capable of either two-lane or four-lane operation. When operating in four-lane, both the pixel rate and link frequency change. Regardless of the mode, however, both frequencies remain fixed. Helper functions are needed to read and set pixel and link frequencies which also reduces the number of fixed registers in the table of modes. Signed-off-by: Adam Ford <aford173@gmail.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
1 parent 8508455 commit ceddfd4

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

drivers/media/i2c/imx219.c

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,16 @@
4242
/* External clock frequency is 24.0M */
4343
#define IMX219_XCLK_FREQ 24000000
4444

45-
/* Pixel rate is fixed at 182.4M for all the modes */
45+
/* Pixel rate is fixed for all the modes */
4646
#define IMX219_PIXEL_RATE 182400000
47+
#define IMX219_PIXEL_RATE_4LANE 280800000
4748

4849
#define IMX219_DEFAULT_LINK_FREQ 456000000
50+
#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000
51+
52+
#define IMX219_REG_CSI_LANE_MODE 0x0114
53+
#define IMX219_CSI_2_LANE_MODE 0x01
54+
#define IMX219_CSI_4_LANE_MODE 0x03
4955

5056
/* V_TIMING internal */
5157
#define IMX219_REG_VTS 0x0160
@@ -299,6 +305,10 @@ static const s64 imx219_link_freq_menu[] = {
299305
IMX219_DEFAULT_LINK_FREQ,
300306
};
301307

308+
static const s64 imx219_link_freq_4lane_menu[] = {
309+
IMX219_DEFAULT_LINK_FREQ_4LANE,
310+
};
311+
302312
static const char * const imx219_test_pattern_menu[] = {
303313
"Disabled",
304314
"Color Bars",
@@ -474,6 +484,9 @@ struct imx219 {
474484

475485
/* Streaming on/off */
476486
bool streaming;
487+
488+
/* Two or Four lanes */
489+
u8 lanes;
477490
};
478491

479492
static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
@@ -936,6 +949,13 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
936949
return -EINVAL;
937950
}
938951

952+
static int imx219_configure_lanes(struct imx219 *imx219)
953+
{
954+
return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE,
955+
IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ?
956+
IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
957+
};
958+
939959
static int imx219_start_streaming(struct imx219 *imx219)
940960
{
941961
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -953,6 +973,13 @@ static int imx219_start_streaming(struct imx219 *imx219)
953973
goto err_rpm_put;
954974
}
955975

976+
/* Configure two or four Lane mode */
977+
ret = imx219_configure_lanes(imx219);
978+
if (ret) {
979+
dev_err(&client->dev, "%s failed to configure lanes\n", __func__);
980+
goto err_rpm_put;
981+
}
982+
956983
/* Apply default values of current mode */
957984
reg_list = &imx219->mode->reg_list;
958985
ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
@@ -1184,6 +1211,11 @@ static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
11841211
.open = imx219_open,
11851212
};
11861213

1214+
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
1215+
{
1216+
return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
1217+
}
1218+
11871219
/* Initialize control handlers */
11881220
static int imx219_init_controls(struct imx219 *imx219)
11891221
{
@@ -1205,15 +1237,16 @@ static int imx219_init_controls(struct imx219 *imx219)
12051237
/* By default, PIXEL_RATE is read only */
12061238
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
12071239
V4L2_CID_PIXEL_RATE,
1208-
IMX219_PIXEL_RATE,
1209-
IMX219_PIXEL_RATE, 1,
1210-
IMX219_PIXEL_RATE);
1240+
imx219_get_pixel_rate(imx219),
1241+
imx219_get_pixel_rate(imx219), 1,
1242+
imx219_get_pixel_rate(imx219));
12111243

12121244
imx219->link_freq =
12131245
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
12141246
V4L2_CID_LINK_FREQ,
12151247
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
1216-
imx219_link_freq_menu);
1248+
(imx219->lanes == 2) ? imx219_link_freq_menu :
1249+
imx219_link_freq_4lane_menu);
12171250
if (imx219->link_freq)
12181251
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
12191252

@@ -1308,7 +1341,7 @@ static void imx219_free_controls(struct imx219 *imx219)
13081341
mutex_destroy(&imx219->mutex);
13091342
}
13101343

1311-
static int imx219_check_hwcfg(struct device *dev)
1344+
static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
13121345
{
13131346
struct fwnode_handle *endpoint;
13141347
struct v4l2_fwnode_endpoint ep_cfg = {
@@ -1328,10 +1361,12 @@ static int imx219_check_hwcfg(struct device *dev)
13281361
}
13291362

13301363
/* Check the number of MIPI CSI2 data lanes */
1331-
if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
1332-
dev_err(dev, "only 2 data lanes are currently supported\n");
1364+
if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
1365+
ep_cfg.bus.mipi_csi2.num_data_lanes != 4) {
1366+
dev_err(dev, "only 2 or 4 data lanes are currently supported\n");
13331367
goto error_out;
13341368
}
1369+
imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;
13351370

13361371
/* Check the link frequency set in device tree */
13371372
if (!ep_cfg.nr_of_link_frequencies) {
@@ -1340,7 +1375,8 @@ static int imx219_check_hwcfg(struct device *dev)
13401375
}
13411376

13421377
if (ep_cfg.nr_of_link_frequencies != 1 ||
1343-
ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
1378+
(ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
1379+
IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
13441380
dev_err(dev, "Link frequency not supported: %lld\n",
13451381
ep_cfg.link_frequencies[0]);
13461382
goto error_out;
@@ -1368,7 +1404,7 @@ static int imx219_probe(struct i2c_client *client)
13681404
v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
13691405

13701406
/* Check the hardware configuration in device tree */
1371-
if (imx219_check_hwcfg(dev))
1407+
if (imx219_check_hwcfg(dev, imx219))
13721408
return -EINVAL;
13731409

13741410
/* Get system clock (xclk) */

0 commit comments

Comments
 (0)