From 8636c5fc7658c7c6299fb8b352d24ea4b9ba99e2 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Tue, 6 Dec 2022 14:05:55 +0100 Subject: [PATCH 001/216] media: max9286: Fix memleak in max9286_v4l2_register() There is a kmemleak when testing the media/i2c/max9286.c with bpf mock device: kmemleak: 5 new suspected memory leaks (see /sys/kernel/debug/kmemleak) unreferenced object 0xffff88810defc400 (size 256): comm "python3", pid 278, jiffies 4294737563 (age 31.978s) hex dump (first 32 bytes): 28 06 a7 0a 81 88 ff ff 00 fe 22 12 81 88 ff ff (........."..... 10 c4 ef 0d 81 88 ff ff 10 c4 ef 0d 81 88 ff ff ................ backtrace: [<00000000191de6a7>] __kmalloc_node+0x44/0x1b0 [<000000002f4912b7>] kvmalloc_node+0x34/0x180 [<0000000057dc4cae>] v4l2_ctrl_new+0x325/0x10f0 [videodev] [<0000000026030272>] v4l2_ctrl_new_std+0x16f/0x210 [videodev] [<00000000f0d9ea2f>] max9286_probe+0x76e/0xbff [max9286] [<00000000ea8f6455>] i2c_device_probe+0x28d/0x680 [<0000000087529af3>] really_probe+0x17c/0x3f0 [<00000000b08be526>] __driver_probe_device+0xe3/0x170 [<000000004382edea>] driver_probe_device+0x49/0x120 [<000000007bde528a>] __device_attach_driver+0xf7/0x150 [<000000009f9c6ab4>] bus_for_each_drv+0x114/0x180 [<00000000c8aaf588>] __device_attach+0x1e5/0x2d0 [<0000000041cc06b9>] bus_probe_device+0x126/0x140 [<000000002309860d>] device_add+0x810/0x1130 [<000000002827bf98>] i2c_new_client_device+0x359/0x4f0 [<00000000593bdc85>] of_i2c_register_device+0xf1/0x110 max9286_v4l2_register() calls v4l2_ctrl_new_std(), but won't free the created v412_ctrl when fwnode_graph_get_endpoint_by_id() failed, which causes the memleak. Call v4l2_ctrl_handler_free() to free the v412_ctrl. Fixes: 66d8c9d2422d ("media: i2c: Add MAX9286 driver") Signed-off-by: Shang XiaoJing Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/max9286.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index dd6477548f29..701038d6d19b 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1113,6 +1113,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv) err_put_node: fwnode_handle_put(ep); err_async: + v4l2_ctrl_handler_free(&priv->ctrls); max9286_v4l2_notifier_unregister(priv); return ret; From 2d899592ed7829d0d5140853bac4d58742a6b8af Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Thu, 8 Dec 2022 08:59:37 +0100 Subject: [PATCH 002/216] media: ov2740: Fix memleak in ov2740_init_controls() There is a kmemleak when testing the media/i2c/ov2740.c with bpf mock device: unreferenced object 0xffff8881090e19e0 (size 16): comm "51-i2c-ov2740", pid 278, jiffies 4294781584 (age 23.613s) hex dump (first 16 bytes): 00 f3 7c 0b 81 88 ff ff 80 75 6a 09 81 88 ff ff ..|......uj..... backtrace: [<000000004e9fad8f>] __kmalloc_node+0x44/0x1b0 [<0000000039c802f4>] kvmalloc_node+0x34/0x180 [<000000009b8b5c63>] v4l2_ctrl_handler_init_class+0x11d/0x180 [videodev] [<0000000038644056>] ov2740_probe+0x37d/0x84f [ov2740] [<0000000092489f59>] i2c_device_probe+0x28d/0x680 [<000000001038babe>] really_probe+0x17c/0x3f0 [<0000000098c7af1c>] __driver_probe_device+0xe3/0x170 [<00000000e1b3dc24>] device_driver_attach+0x34/0x80 [<000000005a04a34d>] bind_store+0x10b/0x1a0 [<00000000ce25d4f2>] drv_attr_store+0x49/0x70 [<000000007d9f4e9a>] sysfs_kf_write+0x8c/0xb0 [<00000000be6cff0f>] kernfs_fop_write_iter+0x216/0x2e0 [<0000000031ddb40a>] vfs_write+0x658/0x810 [<0000000041beecdd>] ksys_write+0xd6/0x1b0 [<0000000023755840>] do_syscall_64+0x38/0x90 [<00000000b2cc2da2>] entry_SYSCALL_64_after_hwframe+0x63/0xcd ov2740_init_controls() won't clean all the allocated resources in fail path, which may causes the memleaks. Add v4l2_ctrl_handler_free() to prevent memleak. Fixes: 866edc895171 ("media: i2c: Add ov2740 image sensor driver") Signed-off-by: Shang XiaoJing Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index f3731f932a94..89d126240c34 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -629,8 +629,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740) V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov2740_test_pattern_menu) - 1, 0, 0, ov2740_test_pattern_menu); - if (ctrl_hdlr->error) + if (ctrl_hdlr->error) { + v4l2_ctrl_handler_free(ctrl_hdlr); return ctrl_hdlr->error; + } ov2740->sd.ctrl_handler = ctrl_hdlr; From dd74ed6c213003533e3abf4c204374ef01d86978 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Thu, 8 Dec 2022 08:59:38 +0100 Subject: [PATCH 003/216] media: ov5675: Fix memleak in ov5675_init_controls() There is a kmemleak when testing the media/i2c/ov5675.c with bpf mock device: AssertionError: unreferenced object 0xffff888107362160 (size 16): comm "python3", pid 277, jiffies 4294832798 (age 20.722s) hex dump (first 16 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000abe7d67c>] __kmalloc_node+0x44/0x1b0 [<000000008a725aac>] kvmalloc_node+0x34/0x180 [<000000009a53cd11>] v4l2_ctrl_handler_init_class+0x11d/0x180 [videodev] [<0000000055b46db0>] ov5675_probe+0x38b/0x897 [ov5675] [<00000000153d886c>] i2c_device_probe+0x28d/0x680 [<000000004afb7e8f>] really_probe+0x17c/0x3f0 [<00000000ff2f18e4>] __driver_probe_device+0xe3/0x170 [<000000000a001029>] driver_probe_device+0x49/0x120 [<00000000e39743c7>] __device_attach_driver+0xf7/0x150 [<00000000d32fd070>] bus_for_each_drv+0x114/0x180 [<000000009083ac41>] __device_attach+0x1e5/0x2d0 [<0000000015b4a830>] bus_probe_device+0x126/0x140 [<000000007813deaf>] device_add+0x810/0x1130 [<000000007becb867>] i2c_new_client_device+0x386/0x540 [<000000007f9cf4b4>] of_i2c_register_device+0xf1/0x110 [<00000000ebfdd032>] of_i2c_notify+0xfc/0x1f0 ov5675_init_controls() won't clean all the allocated resources in fail path, which may causes the memleaks. Add v4l2_ctrl_handler_free() to prevent memleak. Fixes: bf27502b1f3b ("media: ov5675: Add support for OV5675 sensor") Signed-off-by: Shang XiaoJing Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5675.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 94dc8cb7a7c0..a6e6b367d128 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -820,8 +820,10 @@ static int ov5675_init_controls(struct ov5675 *ov5675) v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - if (ctrl_hdlr->error) + if (ctrl_hdlr->error) { + v4l2_ctrl_handler_free(ctrl_hdlr); return ctrl_hdlr->error; + } ov5675->sd.ctrl_handler = ctrl_hdlr; From 0605081142070a41de8f1deb8fdaeb8677e97741 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 16 Dec 2022 11:35:43 +0100 Subject: [PATCH 004/216] media: i2c: tc358746: fix missing return assignment It was intended to return an error if tc358746_update_bits() call fail. Fix this by storing the return code. Addresses-Coverity-ID: 1527252 ("Control flow issues") Reported-by: coverity-bot Fixes: 80a21da36051 ("media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver") Signed-off-by: Marco Felsch Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358746.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index d1f552bd81d4..e7f27cbb5790 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -406,7 +406,7 @@ tc358746_apply_pll_config(struct tc358746 *tc358746) val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN; mask = PLL_FRS_MASK | RESETB | PLL_EN; - tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val); + err = tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val); if (err) return err; From 9d33802c8bcf96c4099ffea4f392afa52897e556 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 16 Dec 2022 11:35:44 +0100 Subject: [PATCH 005/216] media: i2c: tc358746: fix ignoring read error in g_register callback Currently we ignore the return value of tc358746_read() and return alawys return 0 which is wrong. Fix this by returning the actual return value of the read operation which is either 0 on success or an error value. Addresses-Coverity-ID: 1527254 ("Error handling issues") Reported-by: coverity-bot Fixes: 80a21da36051 ("media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver") Signed-off-by: Marco Felsch Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358746.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index e7f27cbb5790..c5a0df300a06 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -988,6 +988,7 @@ static int __maybe_unused tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { struct tc358746 *tc358746 = to_tc358746(sd); + int err; /* 32-bit registers starting from CLW_DPHYCONTTX */ reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4; @@ -995,12 +996,12 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) if (!pm_runtime_get_if_in_use(sd->dev)) return 0; - tc358746_read(tc358746, reg->reg, (u32 *)®->val); + err = tc358746_read(tc358746, reg->reg, (u32 *)®->val); pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); - return 0; + return err; } static int __maybe_unused From 5ad2e46030ad97de7fdbdaf63bb1af45c7caf3dd Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 16 Dec 2022 11:35:45 +0100 Subject: [PATCH 006/216] media: i2c: tc358746: fix possible endianness issue Using the u64 v4l2_dbg_register.val directly can lead to unexpected results depending on machine endianness. Fix this by using a local variable which is assigned afterwards. Since tc358746_read() will init the val variable to 0 we can assing it without checking the return value first. Addresses-Coverity-ID: 1527256 ("Integer handling issues") Reported-by: coverity-bot Fixes: 80a21da36051 ("media: tc358746: add Toshiba TC358746 Parallel to CSI-2 bridge driver") Signed-off-by: Marco Felsch Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358746.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index c5a0df300a06..4063754a6732 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -988,6 +988,7 @@ static int __maybe_unused tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { struct tc358746 *tc358746 = to_tc358746(sd); + u32 val; int err; /* 32-bit registers starting from CLW_DPHYCONTTX */ @@ -996,7 +997,8 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) if (!pm_runtime_get_if_in_use(sd->dev)) return 0; - err = tc358746_read(tc358746, reg->reg, (u32 *)®->val); + err = tc358746_read(tc358746, reg->reg, &val); + reg->val = val; pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); From 8508455961d5a9e8907bcfd8dcd58f19d9b6ce47 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 20 Dec 2022 13:07:53 +0100 Subject: [PATCH 007/216] media: i2c: imx219: Split common registers from mode tables There are four modes, and each mode has a table of registers. Some of the registers are common to all modes, so create new tables for these common registers to reduce duplicate code. Signed-off-by: Adam Ford Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 206 +++++++++++-------------------------- 1 file changed, 59 insertions(+), 147 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 77bd79a5954e..7f44d62047b6 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -145,23 +145,61 @@ struct imx219_mode { struct imx219_reg_list reg_list; }; -/* - * Register sets lifted off the i2C interface from the Raspberry Pi firmware - * driver. - * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. - */ -static const struct imx219_reg mode_3280x2464_regs[] = { - {0x0100, 0x00}, +static const struct imx219_reg imx219_common_regs[] = { + {0x0100, 0x00}, /* Mode Select */ + + /* To Access Addresses 3000-5fff, send the following commands */ {0x30eb, 0x0c}, {0x30eb, 0x05}, {0x300a, 0xff}, {0x300b, 0xff}, {0x30eb, 0x05}, {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, + + /* PLL Clock Table */ + {0x0301, 0x05}, /* VTPXCK_DIV */ + {0x0303, 0x01}, /* VTSYSCK_DIV */ + {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ + {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ + {0x0306, 0x00}, /* PLL_VT_MPY */ + {0x0307, 0x39}, + {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ + {0x030c, 0x00}, /* PLL_OP_MPY */ + {0x030d, 0x72}, + + /* Undocumented registers */ + {0x455e, 0x00}, + {0x471e, 0x4b}, + {0x4767, 0x0f}, + {0x4750, 0x14}, + {0x4540, 0x00}, + {0x47b4, 0x14}, + {0x4713, 0x30}, + {0x478b, 0x10}, + {0x478f, 0x10}, + {0x4793, 0x10}, + {0x4797, 0x0e}, + {0x479b, 0x0e}, + + /* Frame Bank Register Group "A" */ + {0x0162, 0x0d}, /* Line_Length_A */ + {0x0163, 0x78}, + {0x0170, 0x01}, /* X_ODD_INC_A */ + {0x0171, 0x01}, /* Y_ODD_INC_A */ + + /* Output setup registers */ + {0x0114, 0x01}, /* CSI 2-Lane Mode */ + {0x0128, 0x00}, /* DPHY Auto Mode */ + {0x012a, 0x18}, /* EXCK_Freq */ {0x012b, 0x00}, +}; + +/* + * Register sets lifted off the i2C interface from the Raspberry Pi firmware + * driver. + * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. + */ +static const struct imx219_reg mode_3280x2464_regs[] = { {0x0164, 0x00}, {0x0165, 0x00}, {0x0166, 0x0c}, @@ -174,53 +212,15 @@ static const struct imx219_reg mode_3280x2464_regs[] = { {0x016d, 0xd0}, {0x016e, 0x09}, {0x016f, 0xa0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x00}, + {0x0174, 0x00}, /* No-Binning */ {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x0c}, {0x0625, 0xd0}, {0x0626, 0x09}, {0x0627, 0xa0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, - {0x0162, 0x0d}, - {0x0163, 0x78}, }; static const struct imx219_reg mode_1920_1080_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, - {0x0162, 0x0d}, - {0x0163, 0x78}, {0x0164, 0x02}, {0x0165, 0xa8}, {0x0166, 0x0a}, @@ -233,49 +233,15 @@ static const struct imx219_reg mode_1920_1080_regs[] = { {0x016d, 0x80}, {0x016e, 0x04}, {0x016f, 0x38}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x00}, + {0x0174, 0x00}, /* No-Binning */ {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x07}, {0x0625, 0x80}, {0x0626, 0x04}, {0x0627, 0x38}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, }; static const struct imx219_reg mode_1640_1232_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x0c}, - {0x30eb, 0x05}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, {0x0164, 0x00}, {0x0165, 0x00}, {0x0166, 0x0c}, @@ -288,53 +254,15 @@ static const struct imx219_reg mode_1640_1232_regs[] = { {0x016d, 0x68}, {0x016e, 0x04}, {0x016f, 0xd0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x01}, + {0x0174, 0x01}, /* x2-Binning */ {0x0175, 0x01}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, {0x0627, 0xd0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, - {0x0162, 0x0d}, - {0x0163, 0x78}, }; static const struct imx219_reg mode_640_480_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, - {0x0162, 0x0d}, - {0x0163, 0x78}, {0x0164, 0x03}, {0x0165, 0xe8}, {0x0166, 0x08}, @@ -347,35 +275,12 @@ static const struct imx219_reg mode_640_480_regs[] = { {0x016d, 0x80}, {0x016e, 0x01}, {0x016f, 0xe0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x03}, + {0x0174, 0x03}, /* x2-analog binning */ {0x0175, 0x03}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, {0x0627, 0xd0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, }; static const struct imx219_reg raw8_framefmt_regs[] = { @@ -1041,6 +946,13 @@ static int imx219_start_streaming(struct imx219 *imx219) if (ret < 0) return ret; + /* Send all registers that are common to all modes */ + ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs)); + if (ret) { + dev_err(&client->dev, "%s failed to send mfg header\n", __func__); + goto err_rpm_put; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); From ceddfd4493b3341bc69b278bbecfb19ea0773a69 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 20 Dec 2022 13:07:54 +0100 Subject: [PATCH 008/216] 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 Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 56 +++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 7f44d62047b6..b5fa4986470a 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -42,10 +42,16 @@ /* External clock frequency is 24.0M */ #define IMX219_XCLK_FREQ 24000000 -/* Pixel rate is fixed at 182.4M for all the modes */ +/* Pixel rate is fixed for all the modes */ #define IMX219_PIXEL_RATE 182400000 +#define IMX219_PIXEL_RATE_4LANE 280800000 #define IMX219_DEFAULT_LINK_FREQ 456000000 +#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000 + +#define IMX219_REG_CSI_LANE_MODE 0x0114 +#define IMX219_CSI_2_LANE_MODE 0x01 +#define IMX219_CSI_4_LANE_MODE 0x03 /* V_TIMING internal */ #define IMX219_REG_VTS 0x0160 @@ -299,6 +305,10 @@ static const s64 imx219_link_freq_menu[] = { IMX219_DEFAULT_LINK_FREQ, }; +static const s64 imx219_link_freq_4lane_menu[] = { + IMX219_DEFAULT_LINK_FREQ_4LANE, +}; + static const char * const imx219_test_pattern_menu[] = { "Disabled", "Color Bars", @@ -474,6 +484,9 @@ struct imx219 { /* Streaming on/off */ bool streaming; + + /* Two or Four lanes */ + u8 lanes; }; static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) @@ -936,6 +949,13 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return -EINVAL; } +static int imx219_configure_lanes(struct imx219 *imx219) +{ + return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE, + IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ? + IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE); +}; + static int imx219_start_streaming(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); @@ -953,6 +973,13 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + /* Configure two or four Lane mode */ + ret = imx219_configure_lanes(imx219); + if (ret) { + dev_err(&client->dev, "%s failed to configure lanes\n", __func__); + goto err_rpm_put; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; 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 = { .open = imx219_open, }; +static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) +{ + return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; +} + /* Initialize control handlers */ static int imx219_init_controls(struct imx219 *imx219) { @@ -1205,15 +1237,16 @@ static int imx219_init_controls(struct imx219 *imx219) /* By default, PIXEL_RATE is read only */ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_PIXEL_RATE, - IMX219_PIXEL_RATE, - IMX219_PIXEL_RATE, 1, - IMX219_PIXEL_RATE); + imx219_get_pixel_rate(imx219), + imx219_get_pixel_rate(imx219), 1, + imx219_get_pixel_rate(imx219)); 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_link_freq_menu); + (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; @@ -1308,7 +1341,7 @@ static void imx219_free_controls(struct imx219 *imx219) mutex_destroy(&imx219->mutex); } -static int imx219_check_hwcfg(struct device *dev) +static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) { struct fwnode_handle *endpoint; struct v4l2_fwnode_endpoint ep_cfg = { @@ -1328,10 +1361,12 @@ static int imx219_check_hwcfg(struct device *dev) } /* Check the number of MIPI CSI2 data lanes */ - if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { - dev_err(dev, "only 2 data lanes are currently supported\n"); + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 && + ep_cfg.bus.mipi_csi2.num_data_lanes != 4) { + dev_err(dev, "only 2 or 4 data lanes are currently supported\n"); goto error_out; } + imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; /* Check the link frequency set in device tree */ if (!ep_cfg.nr_of_link_frequencies) { @@ -1340,7 +1375,8 @@ static int imx219_check_hwcfg(struct device *dev) } if (ep_cfg.nr_of_link_frequencies != 1 || - ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) { + (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ? + IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) { dev_err(dev, "Link frequency not supported: %lld\n", ep_cfg.link_frequencies[0]); goto error_out; @@ -1368,7 +1404,7 @@ static int imx219_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); /* Check the hardware configuration in device tree */ - if (imx219_check_hwcfg(dev)) + if (imx219_check_hwcfg(dev, imx219)) return -EINVAL; /* Get system clock (xclk) */ From 68453b02e422ff42fc73a9469979ff301661dcdd Mon Sep 17 00:00:00 2001 From: "Guoniu.zhou" Date: Mon, 12 Dec 2022 05:05:26 +0100 Subject: [PATCH 009/216] media: ov5640: set correct default format for CSI-2 mode In commit a89f14bbcfa5 ("media: ov5640: Split DVP and CSI-2 formats"), it splits format list for DVP and CSI-2 mode, but the default format defined in commit 90b0f355c5a3 ("media: ov5640: Implement init_cfg") is only supported by DVP mode, so define a new default format for CSI-2 mode. Signed-off-by: Guoniu.zhou Reviewed-by: Jai Luthra Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index e0f908af581b..2c37ed7b75d3 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -520,7 +520,18 @@ static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) */ /* YUV422 UYVY VGA@30fps */ -static const struct v4l2_mbus_framefmt ov5640_default_fmt = { +static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .width = 640, + .height = 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), + .field = V4L2_FIELD_NONE, +}; + +static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = { .code = MEDIA_BUS_FMT_UYVY8_2X8, .width = 640, .height = 480, @@ -3719,11 +3730,13 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) static int ov5640_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { + struct ov5640_dev *sensor = to_ov5640_dev(sd); struct v4l2_mbus_framefmt *fmt = v4l2_subdev_get_try_format(sd, state, 0); struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); - *fmt = ov5640_default_fmt; + *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : + ov5640_dvp_default_fmt; crop->left = OV5640_PIXEL_ARRAY_LEFT; crop->top = OV5640_PIXEL_ARRAY_TOP; @@ -3812,7 +3825,6 @@ static int ov5640_probe(struct i2c_client *client) * default init sequence initialize sensor to * YUV422 UYVY VGA@30fps */ - sensor->fmt = ov5640_default_fmt; sensor->frame_interval.numerator = 1; sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; sensor->current_fr = OV5640_30_FPS; @@ -3845,6 +3857,9 @@ static int ov5640_probe(struct i2c_client *client) return -EINVAL; } + sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : + ov5640_dvp_default_fmt; + /* get system clock (xclk) */ sensor->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(sensor->xclk)) { From cb7e1c8dbe60ef8e76518a39ad6ea133ab8532ae Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:38 +0100 Subject: [PATCH 010/216] media: i2c: imx290: Group functions in sections Move functions around to group them in logical sections, in order to improve readability. As a result, the IMX290_NUM_SUPPLIES macro has to be changed. No other code change is included, only moves. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 620 +++++++++++++++++++------------------ 1 file changed, 322 insertions(+), 298 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 218ded13fd80..ca2fa57c28fe 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -152,13 +152,7 @@ #define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920 #define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080 -static const char * const imx290_supply_name[] = { - "vdda", - "vddd", - "vdddo", -}; - -#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name) +#define IMX290_NUM_SUPPLIES 3 struct imx290_regval { u32 reg; @@ -199,31 +193,14 @@ struct imx290 { struct mutex lock; }; -struct imx290_pixfmt { - u32 code; - u8 bpp; -}; +static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx290, sd); +} -static const struct imx290_pixfmt imx290_formats[] = { - { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, -}; - -static const struct regmap_config imx290_regmap_config = { - .reg_bits = 16, - .val_bits = 8, -}; - -static const char * const imx290_test_pattern_menu[] = { - "Disabled", - "Sequence Pattern 1", - "Horizontal Color-bar Chart", - "Vertical Color-bar Chart", - "Sequence Pattern 2", - "Gradation Pattern 1", - "Gradation Pattern 2", - "000/555h Toggle Pattern", -}; +/* ----------------------------------------------------------------------------- + * Modes and formats + */ static const struct imx290_regval imx290_global_init_settings[] = { { IMX290_CTRL_07, IMX290_WINMODE_1080P }, @@ -438,10 +415,19 @@ static inline int imx290_modes_num(const struct imx290 *imx290) return ARRAY_SIZE(imx290_modes_4lanes); } -static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) -{ - return container_of(_sd, struct imx290, sd); -} +struct imx290_pixfmt { + u32 code; + u8 bpp; +}; + +static const struct imx290_pixfmt imx290_formats[] = { + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, +}; + +/* ----------------------------------------------------------------------------- + * Register access + */ static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value) { @@ -501,18 +487,94 @@ static int imx290_set_register_array(struct imx290 *imx290, return 0; } -/* Stop streaming */ -static int imx290_stop_streaming(struct imx290 *imx290) +static int imx290_set_data_lanes(struct imx290 *imx290) { - int ret = 0; + int ret = 0, laneval, frsel; - imx290_write(imx290, IMX290_STANDBY, 0x01, &ret); + switch (imx290->nlanes) { + case 2: + laneval = 0x01; + frsel = 0x02; + break; + case 4: + laneval = 0x03; + frsel = 0x01; + break; + default: + /* + * We should never hit this since the data lane count is + * validated in probe itself + */ + dev_err(imx290->dev, "Lane configuration not supported\n"); + return -EINVAL; + } - msleep(30); + imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret); + imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret); + imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); - return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret); + return ret; } +static int imx290_write_current_format(struct imx290 *imx290) +{ + int ret; + + switch (imx290->current_format.code) { + case MEDIA_BUS_FMT_SRGGB10_1X10: + ret = imx290_set_register_array(imx290, imx290_10bit_settings, + ARRAY_SIZE( + imx290_10bit_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set format registers\n"); + return ret; + } + break; + case MEDIA_BUS_FMT_SRGGB12_1X12: + ret = imx290_set_register_array(imx290, imx290_12bit_settings, + ARRAY_SIZE( + imx290_12bit_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set format registers\n"); + return ret; + } + break; + default: + dev_err(imx290->dev, "Unknown pixel format\n"); + return -EINVAL; + } + + return 0; +} + +static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) +{ + return imx290->current_mode->link_freq_index; +} + +static s64 imx290_get_link_freq(struct imx290 *imx290) +{ + u8 index = imx290_get_link_freq_index(imx290); + + return *(imx290_link_freqs_ptr(imx290) + index); +} + +static u64 imx290_calc_pixel_rate(struct imx290 *imx290) +{ + s64 link_freq = imx290_get_link_freq(imx290); + u8 nlanes = imx290->nlanes; + u64 pixel_rate; + + /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = link_freq * 2 * nlanes; + do_div(pixel_rate, imx290->bpp); + return pixel_rate; +} + +/* ---------------------------------------------------------------------------- + * Controls + */ + static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx290 *imx290 = container_of(ctrl->handler, @@ -566,6 +628,187 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = { .s_ctrl = imx290_set_ctrl, }; +static const char * const imx290_test_pattern_menu[] = { + "Disabled", + "Sequence Pattern 1", + "Horizontal Color-bar Chart", + "Vertical Color-bar Chart", + "Sequence Pattern 2", + "Gradation Pattern 1", + "Gradation Pattern 2", + "000/555h Toggle Pattern", +}; + +static int imx290_ctrl_init(struct imx290 *imx290) +{ + struct v4l2_fwnode_device_properties props; + unsigned int blank; + int ret; + + ret = v4l2_fwnode_device_parse(imx290->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&imx290->ctrls, 9); + imx290->ctrls.lock = &imx290->lock; + + /* + * The sensor has an analog gain and a digital gain, both controlled + * through a single gain value, expressed in 0.3dB increments. Values + * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values + * up to 72.0dB (240) add further digital gain. Limit the range to + * analog gain only, support for digital gain can be added separately + * if needed. + * + * The IMX327 and IMX462 are largely compatible with the IMX290, but + * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital + * gain. When support for those sensors gets added to the driver, the + * gain control should be adjusted accordingly. + */ + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); + + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, + IMX290_VMAX_DEFAULT - 2); + + imx290->link_freq = + v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_LINK_FREQ, + imx290_link_freqs_num(imx290) - 1, 0, + imx290_link_freqs_ptr(imx290)); + if (imx290->link_freq) + imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_PIXEL_RATE, + 1, INT_MAX, 1, + imx290_calc_pixel_rate(imx290)); + + v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx290_test_pattern_menu) - 1, + 0, 0, imx290_test_pattern_menu); + + blank = imx290->current_mode->hmax - imx290->current_mode->width; + imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_HBLANK, blank, blank, 1, + blank); + if (imx290->hblank) + imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height; + imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_VBLANK, blank, blank, 1, + blank); + if (imx290->vblank) + imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, + &props); + + imx290->sd.ctrl_handler = &imx290->ctrls; + + if (imx290->ctrls.error) { + ret = imx290->ctrls.error; + v4l2_ctrl_handler_free(&imx290->ctrls); + return ret; + } + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Subdev operations + */ + +/* Start streaming */ +static int imx290_start_streaming(struct imx290 *imx290) +{ + int ret; + + /* Set init register settings */ + ret = imx290_set_register_array(imx290, imx290_global_init_settings, + ARRAY_SIZE( + imx290_global_init_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set init registers\n"); + return ret; + } + + /* Apply the register values related to current frame format */ + ret = imx290_write_current_format(imx290); + if (ret < 0) { + dev_err(imx290->dev, "Could not set frame format\n"); + return ret; + } + + /* Apply default values of current mode */ + ret = imx290_set_register_array(imx290, imx290->current_mode->data, + imx290->current_mode->data_size); + if (ret < 0) { + dev_err(imx290->dev, "Could not set current mode\n"); + return ret; + } + + ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax, + NULL); + if (ret) + return ret; + + /* Apply customized values from user */ + ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); + if (ret) { + dev_err(imx290->dev, "Could not sync v4l2 controls\n"); + return ret; + } + + imx290_write(imx290, IMX290_STANDBY, 0x00, &ret); + + msleep(30); + + /* Start streaming */ + return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret); +} + +/* Stop streaming */ +static int imx290_stop_streaming(struct imx290 *imx290) +{ + int ret = 0; + + imx290_write(imx290, IMX290_STANDBY, 0x01, &ret); + + msleep(30); + + return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret); +} + +static int imx290_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx290 *imx290 = to_imx290(sd); + int ret = 0; + + if (enable) { + ret = pm_runtime_resume_and_get(imx290->dev); + if (ret < 0) + goto unlock_and_return; + + ret = imx290_start_streaming(imx290); + if (ret) { + dev_err(imx290->dev, "Start stream failed\n"); + pm_runtime_put(imx290->dev); + goto unlock_and_return; + } + } else { + imx290_stop_streaming(imx290); + pm_runtime_put(imx290->dev); + } + +unlock_and_return: + + return ret; +} + static struct v4l2_mbus_framefmt * imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state, u32 which) @@ -627,30 +870,6 @@ static int imx290_get_fmt(struct v4l2_subdev *sd, return 0; } -static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) -{ - return imx290->current_mode->link_freq_index; -} - -static s64 imx290_get_link_freq(struct imx290 *imx290) -{ - u8 index = imx290_get_link_freq_index(imx290); - - return *(imx290_link_freqs_ptr(imx290) + index); -} - -static u64 imx290_calc_pixel_rate(struct imx290 *imx290) -{ - s64 link_freq = imx290_get_link_freq(imx290); - u8 nlanes = imx290->nlanes; - u64 pixel_rate; - - /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = link_freq * 2 * nlanes; - do_div(pixel_rate, imx290->bpp); - return pixel_rate; -} - static int imx290_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -774,151 +993,31 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, return 0; } -static int imx290_write_current_format(struct imx290 *imx290) -{ - int ret; +static const struct v4l2_subdev_video_ops imx290_video_ops = { + .s_stream = imx290_set_stream, +}; - switch (imx290->current_format.code) { - case MEDIA_BUS_FMT_SRGGB10_1X10: - ret = imx290_set_register_array(imx290, imx290_10bit_settings, - ARRAY_SIZE( - imx290_10bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } - break; - case MEDIA_BUS_FMT_SRGGB12_1X12: - ret = imx290_set_register_array(imx290, imx290_12bit_settings, - ARRAY_SIZE( - imx290_12bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } - break; - default: - dev_err(imx290->dev, "Unknown pixel format\n"); - return -EINVAL; - } +static const struct v4l2_subdev_pad_ops imx290_pad_ops = { + .init_cfg = imx290_entity_init_cfg, + .enum_mbus_code = imx290_enum_mbus_code, + .enum_frame_size = imx290_enum_frame_size, + .get_fmt = imx290_get_fmt, + .set_fmt = imx290_set_fmt, + .get_selection = imx290_get_selection, +}; - return 0; -} +static const struct v4l2_subdev_ops imx290_subdev_ops = { + .video = &imx290_video_ops, + .pad = &imx290_pad_ops, +}; -/* Start streaming */ -static int imx290_start_streaming(struct imx290 *imx290) -{ - int ret; +static const struct media_entity_operations imx290_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; - /* Set init register settings */ - ret = imx290_set_register_array(imx290, imx290_global_init_settings, - ARRAY_SIZE( - imx290_global_init_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set init registers\n"); - return ret; - } - - /* Apply the register values related to current frame format */ - ret = imx290_write_current_format(imx290); - if (ret < 0) { - dev_err(imx290->dev, "Could not set frame format\n"); - return ret; - } - - /* Apply default values of current mode */ - ret = imx290_set_register_array(imx290, imx290->current_mode->data, - imx290->current_mode->data_size); - if (ret < 0) { - dev_err(imx290->dev, "Could not set current mode\n"); - return ret; - } - - ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax, - NULL); - if (ret) - return ret; - - /* Apply customized values from user */ - ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); - if (ret) { - dev_err(imx290->dev, "Could not sync v4l2 controls\n"); - return ret; - } - - imx290_write(imx290, IMX290_STANDBY, 0x00, &ret); - - msleep(30); - - /* Start streaming */ - return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret); -} - -static int imx290_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct imx290 *imx290 = to_imx290(sd); - int ret = 0; - - if (enable) { - ret = pm_runtime_resume_and_get(imx290->dev); - if (ret < 0) - goto unlock_and_return; - - ret = imx290_start_streaming(imx290); - if (ret) { - dev_err(imx290->dev, "Start stream failed\n"); - pm_runtime_put(imx290->dev); - goto unlock_and_return; - } - } else { - imx290_stop_streaming(imx290); - pm_runtime_put(imx290->dev); - } - -unlock_and_return: - - return ret; -} - -static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++) - imx290->supplies[i].supply = imx290_supply_name[i]; - - return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies), - imx290->supplies); -} - -static int imx290_set_data_lanes(struct imx290 *imx290) -{ - int ret = 0, laneval, frsel; - - switch (imx290->nlanes) { - case 2: - laneval = 0x01; - frsel = 0x02; - break; - case 4: - laneval = 0x03; - frsel = 0x01; - break; - default: - /* - * We should never hit this since the data lane count is - * validated in probe itself - */ - dev_err(imx290->dev, "Lane configuration not supported\n"); - return -EINVAL; - } - - imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret); - imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret); - imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); - - return ret; -} +/* ---------------------------------------------------------------------------- + * Power management + */ static int imx290_power_on(struct device *dev) { @@ -966,105 +1065,30 @@ static const struct dev_pm_ops imx290_pm_ops = { SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) }; -static const struct v4l2_subdev_video_ops imx290_video_ops = { - .s_stream = imx290_set_stream, +/* ---------------------------------------------------------------------------- + * Probe & remove + */ + +static const struct regmap_config imx290_regmap_config = { + .reg_bits = 16, + .val_bits = 8, }; -static const struct v4l2_subdev_pad_ops imx290_pad_ops = { - .init_cfg = imx290_entity_init_cfg, - .enum_mbus_code = imx290_enum_mbus_code, - .enum_frame_size = imx290_enum_frame_size, - .get_fmt = imx290_get_fmt, - .set_fmt = imx290_set_fmt, - .get_selection = imx290_get_selection, +static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = { + "vdda", + "vddd", + "vdddo", }; -static const struct v4l2_subdev_ops imx290_subdev_ops = { - .video = &imx290_video_ops, - .pad = &imx290_pad_ops, -}; - -static const struct media_entity_operations imx290_subdev_entity_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - -static int imx290_ctrl_init(struct imx290 *imx290) +static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) { - struct v4l2_fwnode_device_properties props; - unsigned int blank; - int ret; + unsigned int i; - ret = v4l2_fwnode_device_parse(imx290->dev, &props); - if (ret < 0) - return ret; + for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++) + imx290->supplies[i].supply = imx290_supply_name[i]; - v4l2_ctrl_handler_init(&imx290->ctrls, 9); - imx290->ctrls.lock = &imx290->lock; - - /* - * The sensor has an analog gain and a digital gain, both controlled - * through a single gain value, expressed in 0.3dB increments. Values - * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values - * up to 72.0dB (240) add further digital gain. Limit the range to - * analog gain only, support for digital gain can be added separately - * if needed. - * - * The IMX327 and IMX462 are largely compatible with the IMX290, but - * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital - * gain. When support for those sensors gets added to the driver, the - * gain control should be adjusted accordingly. - */ - v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); - - v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, - IMX290_VMAX_DEFAULT - 2); - - imx290->link_freq = - v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_LINK_FREQ, - imx290_link_freqs_num(imx290) - 1, 0, - imx290_link_freqs_ptr(imx290)); - if (imx290->link_freq) - imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, - imx290_calc_pixel_rate(imx290)); - - v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(imx290_test_pattern_menu) - 1, - 0, 0, imx290_test_pattern_menu); - - blank = imx290->current_mode->hmax - imx290->current_mode->width; - imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_HBLANK, blank, blank, 1, - blank); - if (imx290->hblank) - imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height; - imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_VBLANK, blank, blank, 1, - blank); - if (imx290->vblank) - imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, - &props); - - imx290->sd.ctrl_handler = &imx290->ctrls; - - if (imx290->ctrls.error) { - ret = imx290->ctrls.error; - v4l2_ctrl_handler_free(&imx290->ctrls); - return ret; - } - - return 0; + return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies), + imx290->supplies); } /* From dfb704da83003c8f00156b020aaa6fa34b22e600 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:39 +0100 Subject: [PATCH 011/216] media: i2c: imx290: Factor out subdev init and cleanup to functions The probe() function is large. Make it more readable by factoring the subdev initialization code out. While at it, rename the error labels as the "free_" prefix isn't accurate. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 108 +++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index ca2fa57c28fe..5529bd39238f 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1015,6 +1015,47 @@ static const struct media_entity_operations imx290_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; +static int imx290_subdev_init(struct imx290 *imx290) +{ + struct i2c_client *client = to_i2c_client(imx290->dev); + int ret; + + /* + * Initialize the frame format. In particular, imx290->current_mode + * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call + * below relies on these fields. + */ + imx290_entity_init_cfg(&imx290->sd, NULL); + + ret = imx290_ctrl_init(imx290); + if (ret < 0) { + dev_err(imx290->dev, "Control initialization error %d\n", ret); + return ret; + } + + v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx290->sd.dev = imx290->dev; + imx290->sd.entity.ops = &imx290_subdev_entity_ops; + imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx290->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); + if (ret < 0) { + dev_err(imx290->dev, "Could not register media entity\n"); + v4l2_ctrl_handler_free(&imx290->ctrls); + return ret; + } + + return 0; +} + +static void imx290_subdev_cleanup(struct imx290 *imx290) +{ + media_entity_cleanup(&imx290->sd.entity); + v4l2_ctrl_handler_free(&imx290->ctrls); +} + /* ---------------------------------------------------------------------------- * Power management */ @@ -1147,10 +1188,10 @@ static int imx290_probe(struct i2c_client *client) fwnode_handle_put(endpoint); if (ret == -ENXIO) { dev_err(dev, "Unsupported bus type, should be CSI2\n"); - goto free_err; + goto err_endpoint; } else if (ret) { dev_err(dev, "Parsing endpoint node failed\n"); - goto free_err; + goto err_endpoint; } /* Get number of data lanes */ @@ -1158,7 +1199,7 @@ static int imx290_probe(struct i2c_client *client) if (imx290->nlanes != 2 && imx290->nlanes != 4) { dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); ret = -EINVAL; - goto free_err; + goto err_endpoint; } dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); @@ -1166,7 +1207,7 @@ static int imx290_probe(struct i2c_client *client) if (!ep.nr_of_link_frequencies) { dev_err(dev, "link-frequency property not found in DT\n"); ret = -EINVAL; - goto free_err; + goto err_endpoint; } /* Check that link frequences for all the modes are in device tree */ @@ -1174,7 +1215,7 @@ static int imx290_probe(struct i2c_client *client) if (fq) { dev_err(dev, "Link frequency of %lld is not supported\n", fq); ret = -EINVAL; - goto free_err; + goto err_endpoint; } /* get system clock (xclk) */ @@ -1182,14 +1223,14 @@ static int imx290_probe(struct i2c_client *client) if (IS_ERR(imx290->xclk)) { dev_err(dev, "Could not get xclk"); ret = PTR_ERR(imx290->xclk); - goto free_err; + goto err_endpoint; } ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &xclk_freq); if (ret) { dev_err(dev, "Could not get xclk frequency\n"); - goto free_err; + goto err_endpoint; } /* external clock must be 37.125 MHz */ @@ -1197,19 +1238,19 @@ static int imx290_probe(struct i2c_client *client) dev_err(dev, "External clock frequency %u is not supported\n", xclk_freq); ret = -EINVAL; - goto free_err; + goto err_endpoint; } ret = clk_set_rate(imx290->xclk, xclk_freq); if (ret) { dev_err(dev, "Could not set xclk frequency\n"); - goto free_err; + goto err_endpoint; } ret = imx290_get_regulators(dev, imx290); if (ret < 0) { dev_err(dev, "Cannot get regulators\n"); - goto free_err; + goto err_endpoint; } imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", @@ -1217,48 +1258,26 @@ static int imx290_probe(struct i2c_client *client) if (IS_ERR(imx290->rst_gpio)) { dev_err(dev, "Cannot get reset gpio\n"); ret = PTR_ERR(imx290->rst_gpio); - goto free_err; + goto err_endpoint; } mutex_init(&imx290->lock); - /* - * Initialize the frame format. In particular, imx290->current_mode - * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call - * below relies on these fields. - */ - imx290_entity_init_cfg(&imx290->sd, NULL); - - ret = imx290_ctrl_init(imx290); - if (ret < 0) { - dev_err(dev, "Control initialization error %d\n", ret); - goto free_mutex; - } - - v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - imx290->sd.dev = &client->dev; - imx290->sd.entity.ops = &imx290_subdev_entity_ops; - imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - imx290->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); - if (ret < 0) { - dev_err(dev, "Could not register media entity\n"); - goto free_ctrl; - } + ret = imx290_subdev_init(imx290); + if (ret) + goto err_mutex; ret = v4l2_async_register_subdev(&imx290->sd); if (ret < 0) { dev_err(dev, "Could not register v4l2 device\n"); - goto free_entity; + goto err_subdev; } /* Power on the device to match runtime PM state below */ ret = imx290_power_on(dev); if (ret < 0) { dev_err(dev, "Could not power on the device\n"); - goto free_entity; + goto err_subdev; } pm_runtime_set_active(dev); @@ -1269,13 +1288,11 @@ static int imx290_probe(struct i2c_client *client) return 0; -free_entity: - media_entity_cleanup(&imx290->sd.entity); -free_ctrl: - v4l2_ctrl_handler_free(&imx290->ctrls); -free_mutex: +err_subdev: + imx290_subdev_cleanup(imx290); +err_mutex: mutex_destroy(&imx290->lock); -free_err: +err_endpoint: v4l2_fwnode_endpoint_free(&ep); return ret; @@ -1287,8 +1304,7 @@ static void imx290_remove(struct i2c_client *client) struct imx290 *imx290 = to_imx290(sd); v4l2_async_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); - v4l2_ctrl_handler_free(sd->ctrl_handler); + imx290_subdev_cleanup(imx290); mutex_destroy(&imx290->lock); From a7941da37c43d60c99843265e8535d47c7dd93a3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:40 +0100 Subject: [PATCH 012/216] media: i2c: imx290: Factor out control update code to a function Move the control update code to a separate function to group it with all the control-related code and make imx290_set_fmt() more readable. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 43 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 5529bd39238f..991e7285c40c 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -639,6 +639,28 @@ static const char * const imx290_test_pattern_menu[] = { "000/555h Toggle Pattern", }; +static void imx290_ctrl_update(struct imx290 *imx290, + const struct imx290_mode *mode) +{ + unsigned int hblank = mode->hmax - mode->width; + unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; + + /* + * This function may be called from imx290_set_fmt() before controls + * get created by imx290_ctrl_init(). Return immediately in that case. + */ + if (!imx290->ctrls.lock) + return; + + __v4l2_ctrl_s_ctrl(imx290->link_freq, + imx290_get_link_freq_index(imx290)); + __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, + imx290_calc_pixel_rate(imx290)); + + __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank); + __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank); +} + static int imx290_ctrl_init(struct imx290 *imx290) { struct v4l2_fwnode_device_properties props; @@ -904,26 +926,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, imx290->current_mode = mode; imx290->bpp = imx290_formats[i].bpp; - if (imx290->link_freq) - __v4l2_ctrl_s_ctrl(imx290->link_freq, - imx290_get_link_freq_index(imx290)); - if (imx290->pixel_rate) - __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, - imx290_calc_pixel_rate(imx290)); - - if (imx290->hblank) { - unsigned int hblank = mode->hmax - mode->width; - - __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, - 1, hblank); - } - - if (imx290->vblank) { - unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; - - __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, - 1, vblank); - } + imx290_ctrl_update(imx290, mode); } *format = fmt->format; From 70bbf56aa82ca972be424ec110f9a7f4ab9ee732 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:41 +0100 Subject: [PATCH 013/216] media: i2c: imx290: Access link_freq_index directly The imx290_get_link_freq_index() function hides the fact that it relies on the imx290 current_mode field, which obfuscates the code instead of making it more readable. Inline it in the callers, and use the mode pointer we already have in imx290_ctrl_update() instead of using the current_mode field. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 991e7285c40c..4ad6eab4f2e2 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -547,14 +547,9 @@ static int imx290_write_current_format(struct imx290 *imx290) return 0; } -static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) -{ - return imx290->current_mode->link_freq_index; -} - static s64 imx290_get_link_freq(struct imx290 *imx290) { - u8 index = imx290_get_link_freq_index(imx290); + u8 index = imx290->current_mode->link_freq_index; return *(imx290_link_freqs_ptr(imx290) + index); } @@ -652,8 +647,7 @@ static void imx290_ctrl_update(struct imx290 *imx290, if (!imx290->ctrls.lock) return; - __v4l2_ctrl_s_ctrl(imx290->link_freq, - imx290_get_link_freq_index(imx290)); + __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, imx290_calc_pixel_rate(imx290)); From 31b54a422b3f66f715a0963d1d3ce0c7678fb333 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:42 +0100 Subject: [PATCH 014/216] media: i2c: imx290: Pass format and mode to imx290_calc_pixel_rate() Avoid accessing the imx290 current_format and current_mode fields in imx290_calc_pixel_rate() to prepare for the removal of those fields. Among the two callers of the function, imx290_ctrl_update() has an explicit mode pointer already, and we can also give it a format pointer. Use those explicitly. While at it, inline the imx290_get_link_freq() function in imx290_calc_pixel_rate() as it is only called there. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4ad6eab4f2e2..25671ded7c2a 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -547,21 +547,14 @@ static int imx290_write_current_format(struct imx290 *imx290) return 0; } -static s64 imx290_get_link_freq(struct imx290 *imx290) +static u64 imx290_calc_pixel_rate(struct imx290 *imx290, + const struct imx290_mode *mode) { - u8 index = imx290->current_mode->link_freq_index; - - return *(imx290_link_freqs_ptr(imx290) + index); -} - -static u64 imx290_calc_pixel_rate(struct imx290 *imx290) -{ - s64 link_freq = imx290_get_link_freq(imx290); - u8 nlanes = imx290->nlanes; + s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; u64 pixel_rate; /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = link_freq * 2 * nlanes; + pixel_rate = link_freq * 2 * imx290->nlanes; do_div(pixel_rate, imx290->bpp); return pixel_rate; } @@ -649,7 +642,7 @@ static void imx290_ctrl_update(struct imx290 *imx290, __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, - imx290_calc_pixel_rate(imx290)); + imx290_calc_pixel_rate(imx290, mode)); __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank); __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank); @@ -659,6 +652,7 @@ static int imx290_ctrl_init(struct imx290 *imx290) { struct v4l2_fwnode_device_properties props; unsigned int blank; + u64 pixel_rate; int ret; ret = v4l2_fwnode_device_parse(imx290->dev, &props); @@ -696,10 +690,10 @@ static int imx290_ctrl_init(struct imx290 *imx290) if (imx290->link_freq) imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + pixel_rate = imx290_calc_pixel_rate(imx290, imx290->current_mode); imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, - imx290_calc_pixel_rate(imx290)); + 1, INT_MAX, 1, pixel_rate); v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_TEST_PATTERN, From 693b5cb598cc787dd61b8b626bfd45c26b5b1290 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:43 +0100 Subject: [PATCH 015/216] media: i2c: imx290: Compute pixel rate and blanking in one place The hblank, vblank, pixel rate and link frequency values and limits are currently computed when creating controls, in imx290_ctrl_init(), and updated in imx290_ctrl_update(). This duplicates the logic in different places. Simplify the code by setting the control values and limits to hardcoded values when creating the controls, and call imx290_ctrl_update() to then update them. Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 43 +++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 25671ded7c2a..d3279d88f253 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -547,18 +547,6 @@ static int imx290_write_current_format(struct imx290 *imx290) return 0; } -static u64 imx290_calc_pixel_rate(struct imx290 *imx290, - const struct imx290_mode *mode) -{ - s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; - u64 pixel_rate; - - /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = link_freq * 2 * imx290->nlanes; - do_div(pixel_rate, imx290->bpp); - return pixel_rate; -} - /* ---------------------------------------------------------------------------- * Controls */ @@ -632,6 +620,8 @@ static void imx290_ctrl_update(struct imx290 *imx290, { unsigned int hblank = mode->hmax - mode->width; unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; + s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; + u64 pixel_rate; /* * This function may be called from imx290_set_fmt() before controls @@ -640,9 +630,12 @@ static void imx290_ctrl_update(struct imx290 *imx290, if (!imx290->ctrls.lock) return; + /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = link_freq * 2 * imx290->nlanes; + do_div(pixel_rate, imx290->bpp); + __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); - __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, - imx290_calc_pixel_rate(imx290, mode)); + __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate); __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank); __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank); @@ -651,8 +644,6 @@ static void imx290_ctrl_update(struct imx290 *imx290, static int imx290_ctrl_init(struct imx290 *imx290) { struct v4l2_fwnode_device_properties props; - unsigned int blank; - u64 pixel_rate; int ret; ret = v4l2_fwnode_device_parse(imx290->dev, &props); @@ -682,6 +673,11 @@ static int imx290_ctrl_init(struct imx290 *imx290) V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, IMX290_VMAX_DEFAULT - 2); + /* + * Set the link frequency, pixel rate, horizontal blanking and vertical + * blanking to hardcoded values, they will be updated by + * imx290_ctrl_update(). + */ imx290->link_freq = v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_LINK_FREQ, @@ -690,27 +686,22 @@ static int imx290_ctrl_init(struct imx290 *imx290) if (imx290->link_freq) imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - pixel_rate = imx290_calc_pixel_rate(imx290, imx290->current_mode); imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, pixel_rate); + 1, INT_MAX, 1, 1); v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(imx290_test_pattern_menu) - 1, 0, 0, imx290_test_pattern_menu); - blank = imx290->current_mode->hmax - imx290->current_mode->width; imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_HBLANK, blank, blank, 1, - blank); + V4L2_CID_HBLANK, 1, 1, 1, 1); if (imx290->hblank) imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height; imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_VBLANK, blank, blank, 1, - blank); + V4L2_CID_VBLANK, 1, 1, 1, 1); if (imx290->vblank) imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -725,6 +716,10 @@ static int imx290_ctrl_init(struct imx290 *imx290) return ret; } + mutex_lock(imx290->ctrls.lock); + imx290_ctrl_update(imx290, imx290->current_mode); + mutex_unlock(imx290->ctrls.lock); + return 0; } From ee4ce89366935da1c044d0417bf09f9f0e4a3457 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:44 +0100 Subject: [PATCH 016/216] media: i2c: imx290: Factor out black level setting to a function The black level programmed in the BLKLEVEL register depends on the output format. The black level value computation is currently performed in imx290_set_ctrl(), in addition to having different black level values in the output-specific register value tables. Move it to a separate function to simplify the imx290_set_ctrl() code. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 50 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index d3279d88f253..e7043e9a8fd5 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -152,6 +152,9 @@ #define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920 #define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080 +/* Equivalent value for 16bpp */ +#define IMX290_BLACK_LEVEL_DEFAULT 3840 + #define IMX290_NUM_SUPPLIES 3 struct imx290_regval { @@ -315,7 +318,6 @@ static const struct imx290_regval imx290_10bit_settings[] = { { IMX290_ADBIT2, IMX290_ADBIT2_10BIT }, { IMX290_ADBIT3, IMX290_ADBIT3_10BIT }, { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 }, - { IMX290_BLKLEVEL, 60 }, }; static const struct imx290_regval imx290_12bit_settings[] = { @@ -325,7 +327,6 @@ static const struct imx290_regval imx290_12bit_settings[] = { { IMX290_ADBIT2, IMX290_ADBIT2_12BIT }, { IMX290_ADBIT3, IMX290_ADBIT3_12BIT }, { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 }, - { IMX290_BLKLEVEL, 240 }, }; /* supported link frequencies */ @@ -516,35 +517,40 @@ static int imx290_set_data_lanes(struct imx290 *imx290) return ret; } +static int imx290_set_black_level(struct imx290 *imx290, + unsigned int black_level, int *err) +{ + return imx290_write(imx290, IMX290_BLKLEVEL, + black_level >> (16 - imx290->bpp), err); +} + static int imx290_write_current_format(struct imx290 *imx290) { + const struct imx290_regval *regs; + unsigned int num_regs; int ret; switch (imx290->current_format.code) { case MEDIA_BUS_FMT_SRGGB10_1X10: - ret = imx290_set_register_array(imx290, imx290_10bit_settings, - ARRAY_SIZE( - imx290_10bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } + regs = imx290_10bit_settings; + num_regs = ARRAY_SIZE(imx290_10bit_settings); break; case MEDIA_BUS_FMT_SRGGB12_1X12: - ret = imx290_set_register_array(imx290, imx290_12bit_settings, - ARRAY_SIZE( - imx290_12bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } + regs = imx290_12bit_settings; + num_regs = ARRAY_SIZE(imx290_12bit_settings); break; default: dev_err(imx290->dev, "Unknown pixel format\n"); return -EINVAL; } - return 0; + ret = imx290_set_register_array(imx290, regs, num_regs); + if (ret < 0) { + dev_err(imx290->dev, "Could not set format registers\n"); + return ret; + } + + return imx290_set_black_level(imx290, IMX290_BLACK_LEVEL_DEFAULT, &ret); } /* ---------------------------------------------------------------------------- @@ -573,7 +579,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: if (ctrl->val) { - imx290_write(imx290, IMX290_BLKLEVEL, 0, &ret); + imx290_set_black_level(imx290, 0, &ret); usleep_range(10000, 11000); imx290_write(imx290, IMX290_PGCTRL, (u8)(IMX290_PGCTRL_REGEN | @@ -582,12 +588,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) } else { imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret); usleep_range(10000, 11000); - if (imx290->bpp == 10) - imx290_write(imx290, IMX290_BLKLEVEL, 0x3c, - &ret); - else /* 12 bits per pixel */ - imx290_write(imx290, IMX290_BLKLEVEL, 0xf0, - &ret); + imx290_set_black_level(imx290, IMX290_BLACK_LEVEL_DEFAULT, + &ret); } break; default: From 6b69c52277ed113b8d005674dd3d67a542ec0edf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:45 +0100 Subject: [PATCH 017/216] media: i2c: imx290: Factor out DT parsing to separate function Make the probe() function more readable by factoring out the DT parsing code to a separate function. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 121 ++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index e7043e9a8fd5..530da5b03e61 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1142,17 +1142,69 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290, return 0; } -static int imx290_probe(struct i2c_client *client) +static int imx290_parse_dt(struct imx290 *imx290) { - struct device *dev = &client->dev; - struct fwnode_handle *endpoint; /* Only CSI2 is supported for now: */ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct fwnode_handle *endpoint; + int ret; + s64 fq; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL); + if (!endpoint) { + dev_err(imx290->dev, "Endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); + fwnode_handle_put(endpoint); + if (ret == -ENXIO) { + dev_err(imx290->dev, "Unsupported bus type, should be CSI2\n"); + goto done; + } else if (ret) { + dev_err(imx290->dev, "Parsing endpoint node failed\n"); + goto done; + } + + /* Get number of data lanes */ + imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes; + if (imx290->nlanes != 2 && imx290->nlanes != 4) { + dev_err(imx290->dev, "Invalid data lanes: %d\n", imx290->nlanes); + ret = -EINVAL; + goto done; + } + + dev_dbg(imx290->dev, "Using %u data lanes\n", imx290->nlanes); + + if (!ep.nr_of_link_frequencies) { + dev_err(imx290->dev, "link-frequency property not found in DT\n"); + ret = -EINVAL; + goto done; + } + + /* Check that link frequences for all the modes are in device tree */ + fq = imx290_check_link_freqs(imx290, &ep); + if (fq) { + dev_err(imx290->dev, "Link frequency of %lld is not supported\n", + fq); + ret = -EINVAL; + goto done; + } + + ret = 0; + +done: + v4l2_fwnode_endpoint_free(&ep); + return ret; +} + +static int imx290_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; struct imx290 *imx290; u32 xclk_freq; - s64 fq; int ret; imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); @@ -1166,87 +1218,48 @@ static int imx290_probe(struct i2c_client *client) return -ENODEV; } - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); - if (!endpoint) { - dev_err(dev, "Endpoint node not found\n"); - return -EINVAL; - } - - ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); - fwnode_handle_put(endpoint); - if (ret == -ENXIO) { - dev_err(dev, "Unsupported bus type, should be CSI2\n"); - goto err_endpoint; - } else if (ret) { - dev_err(dev, "Parsing endpoint node failed\n"); - goto err_endpoint; - } - - /* Get number of data lanes */ - imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes; - if (imx290->nlanes != 2 && imx290->nlanes != 4) { - dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); - ret = -EINVAL; - goto err_endpoint; - } - - dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); - - if (!ep.nr_of_link_frequencies) { - dev_err(dev, "link-frequency property not found in DT\n"); - ret = -EINVAL; - goto err_endpoint; - } - - /* Check that link frequences for all the modes are in device tree */ - fq = imx290_check_link_freqs(imx290, &ep); - if (fq) { - dev_err(dev, "Link frequency of %lld is not supported\n", fq); - ret = -EINVAL; - goto err_endpoint; - } + ret = imx290_parse_dt(imx290); + if (ret) + return ret; /* get system clock (xclk) */ imx290->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(imx290->xclk)) { dev_err(dev, "Could not get xclk"); - ret = PTR_ERR(imx290->xclk); - goto err_endpoint; + return PTR_ERR(imx290->xclk); } ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &xclk_freq); if (ret) { dev_err(dev, "Could not get xclk frequency\n"); - goto err_endpoint; + return ret; } /* external clock must be 37.125 MHz */ if (xclk_freq != 37125000) { dev_err(dev, "External clock frequency %u is not supported\n", xclk_freq); - ret = -EINVAL; - goto err_endpoint; + return -EINVAL; } ret = clk_set_rate(imx290->xclk, xclk_freq); if (ret) { dev_err(dev, "Could not set xclk frequency\n"); - goto err_endpoint; + return ret; } ret = imx290_get_regulators(dev, imx290); if (ret < 0) { dev_err(dev, "Cannot get regulators\n"); - goto err_endpoint; + return ret; } imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(imx290->rst_gpio)) { dev_err(dev, "Cannot get reset gpio\n"); - ret = PTR_ERR(imx290->rst_gpio); - goto err_endpoint; + return PTR_ERR(imx290->rst_gpio); } mutex_init(&imx290->lock); @@ -1272,16 +1285,12 @@ static int imx290_probe(struct i2c_client *client) pm_runtime_enable(dev); pm_runtime_idle(dev); - v4l2_fwnode_endpoint_free(&ep); - return 0; err_subdev: imx290_subdev_cleanup(imx290); err_mutex: mutex_destroy(&imx290->lock); -err_endpoint: - v4l2_fwnode_endpoint_free(&ep); return ret; } From 63127235bebdd112bf17cbd2339c9daf63c51970 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:46 +0100 Subject: [PATCH 018/216] media: i2c: imx290: Use dev_err_probe() Improve error handling in the probe() function with dev_err_probe(). Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 530da5b03e61..51f430ca3652 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1224,10 +1224,9 @@ static int imx290_probe(struct i2c_client *client) /* get system clock (xclk) */ imx290->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(imx290->xclk)) { - dev_err(dev, "Could not get xclk"); - return PTR_ERR(imx290->xclk); - } + if (IS_ERR(imx290->xclk)) + return dev_err_probe(dev, PTR_ERR(imx290->xclk), + "Could not get xclk"); ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &xclk_freq); @@ -1250,17 +1249,14 @@ static int imx290_probe(struct i2c_client *client) } ret = imx290_get_regulators(dev, imx290); - if (ret < 0) { - dev_err(dev, "Cannot get regulators\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot get regulators\n"); imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(imx290->rst_gpio)) { - dev_err(dev, "Cannot get reset gpio\n"); - return PTR_ERR(imx290->rst_gpio); - } + if (IS_ERR(imx290->rst_gpio)) + return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio), + "Cannot get reset gpio\n"); mutex_init(&imx290->lock); From e5d363ca82b94b26d85043c26e865824f947a80b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:47 +0100 Subject: [PATCH 019/216] media: i2c: imx290: Factor out clock initialization to separate function Move the external clock initialization code from probe() to a separate function to improve readability. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 57 +++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 51f430ca3652..c1d18ec51e41 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1120,6 +1120,34 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) imx290->supplies); } +static int imx290_init_clk(struct imx290 *imx290) +{ + u32 xclk_freq; + int ret; + + ret = fwnode_property_read_u32(dev_fwnode(imx290->dev), + "clock-frequency", &xclk_freq); + if (ret) { + dev_err(imx290->dev, "Could not get xclk frequency\n"); + return ret; + } + + /* external clock must be 37.125 MHz */ + if (xclk_freq != 37125000) { + dev_err(imx290->dev, "External clock frequency %u is not supported\n", + xclk_freq); + return -EINVAL; + } + + ret = clk_set_rate(imx290->xclk, xclk_freq); + if (ret) { + dev_err(imx290->dev, "Could not set xclk frequency\n"); + return ret; + } + + return 0; +} + /* * Returns 0 if all link frequencies used by the driver for the given number * of MIPI data lanes are mentioned in the device tree, or the value of the @@ -1204,7 +1232,6 @@ static int imx290_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct imx290 *imx290; - u32 xclk_freq; int ret; imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); @@ -1222,32 +1249,12 @@ static int imx290_probe(struct i2c_client *client) if (ret) return ret; - /* get system clock (xclk) */ + /* Acquire resources. */ imx290->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(imx290->xclk)) return dev_err_probe(dev, PTR_ERR(imx290->xclk), "Could not get xclk"); - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &xclk_freq); - if (ret) { - dev_err(dev, "Could not get xclk frequency\n"); - return ret; - } - - /* external clock must be 37.125 MHz */ - if (xclk_freq != 37125000) { - dev_err(dev, "External clock frequency %u is not supported\n", - xclk_freq); - return -EINVAL; - } - - ret = clk_set_rate(imx290->xclk, xclk_freq); - if (ret) { - dev_err(dev, "Could not set xclk frequency\n"); - return ret; - } - ret = imx290_get_regulators(dev, imx290); if (ret < 0) return dev_err_probe(dev, ret, "Cannot get regulators\n"); @@ -1258,8 +1265,14 @@ static int imx290_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio), "Cannot get reset gpio\n"); + /* Initialize external clock frequency. */ + ret = imx290_init_clk(imx290); + if (ret) + return ret; + mutex_init(&imx290->lock); + /* Initialize and register subdev. */ ret = imx290_subdev_init(imx290); if (ret) goto err_mutex; From a2514b9a634ac0a2cfbc329822b8fb58ffe23a80 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 17 Oct 2022 12:44:27 +0200 Subject: [PATCH 020/216] media: i2c: imx290: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format. This simplifies the driver not only by dropping the imx290 current_format field, but it also allows dropping the imx290 lock, replaced with the state lock. The lock check in imx290_ctrl_update() can be dropped as imx290_set_fmt() can't be called anywmore with which set to ACTIVE before controls are initialized. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 154 ++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 89 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index c1d18ec51e41..1aa5ab0c57ce 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -177,12 +177,12 @@ struct imx290 { struct clk *xclk; struct regmap *regmap; u8 nlanes; - u8 bpp; struct v4l2_subdev sd; struct media_pad pad; - struct v4l2_mbus_framefmt current_format; + const struct imx290_mode *current_mode; + u8 bpp; struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES]; struct gpio_desc *rst_gpio; @@ -192,8 +192,6 @@ struct imx290 { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; - - struct mutex lock; }; static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) @@ -524,13 +522,14 @@ static int imx290_set_black_level(struct imx290 *imx290, black_level >> (16 - imx290->bpp), err); } -static int imx290_write_current_format(struct imx290 *imx290) +static int imx290_setup_format(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format) { const struct imx290_regval *regs; unsigned int num_regs; int ret; - switch (imx290->current_format.code) { + switch (format->code) { case MEDIA_BUS_FMT_SRGGB10_1X10: regs = imx290_10bit_settings; num_regs = ARRAY_SIZE(imx290_10bit_settings); @@ -563,6 +562,15 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) struct imx290, ctrls); int ret = 0; + /* + * Return immediately for controls that don't need to be applied to the + * device. Those controls are modified in imx290_ctrl_update(), which + * is called at probe time before runtime PM is initialized, so we + * can't proceed to the pm_runtime_get_if_in_use() call below. + */ + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) + return 0; + /* V4L2 controls values will be applied only when power is already up */ if (!pm_runtime_get_if_in_use(imx290->dev)) return 0; @@ -592,6 +600,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) &ret); } break; + default: ret = -EINVAL; break; @@ -625,13 +634,6 @@ static void imx290_ctrl_update(struct imx290 *imx290, s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; u64 pixel_rate; - /* - * This function may be called from imx290_set_fmt() before controls - * get created by imx290_ctrl_init(). Return immediately in that case. - */ - if (!imx290->ctrls.lock) - return; - /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ pixel_rate = link_freq * 2 * imx290->nlanes; do_div(pixel_rate, imx290->bpp); @@ -653,7 +655,6 @@ static int imx290_ctrl_init(struct imx290 *imx290) return ret; v4l2_ctrl_handler_init(&imx290->ctrls, 9); - imx290->ctrls.lock = &imx290->lock; /* * The sensor has an analog gain and a digital gain, both controlled @@ -718,10 +719,6 @@ static int imx290_ctrl_init(struct imx290 *imx290) return ret; } - mutex_lock(imx290->ctrls.lock); - imx290_ctrl_update(imx290, imx290->current_mode); - mutex_unlock(imx290->ctrls.lock); - return 0; } @@ -730,8 +727,10 @@ static int imx290_ctrl_init(struct imx290 *imx290) */ /* Start streaming */ -static int imx290_start_streaming(struct imx290 *imx290) +static int imx290_start_streaming(struct imx290 *imx290, + struct v4l2_subdev_state *state) { + const struct v4l2_mbus_framefmt *format; int ret; /* Set init register settings */ @@ -744,7 +743,8 @@ static int imx290_start_streaming(struct imx290 *imx290) } /* Apply the register values related to current frame format */ - ret = imx290_write_current_format(imx290); + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + ret = imx290_setup_format(imx290, format); if (ret < 0) { dev_err(imx290->dev, "Could not set frame format\n"); return ret; @@ -764,7 +764,7 @@ static int imx290_start_streaming(struct imx290 *imx290) return ret; /* Apply customized values from user */ - ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); + ret = __v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); if (ret) { dev_err(imx290->dev, "Could not sync v4l2 controls\n"); return ret; @@ -793,39 +793,32 @@ static int imx290_stop_streaming(struct imx290 *imx290) static int imx290_set_stream(struct v4l2_subdev *sd, int enable) { struct imx290 *imx290 = to_imx290(sd); + struct v4l2_subdev_state *state; int ret = 0; + state = v4l2_subdev_lock_and_get_active_state(sd); + if (enable) { ret = pm_runtime_resume_and_get(imx290->dev); if (ret < 0) - goto unlock_and_return; + goto unlock; - ret = imx290_start_streaming(imx290); + ret = imx290_start_streaming(imx290, state); if (ret) { dev_err(imx290->dev, "Start stream failed\n"); pm_runtime_put(imx290->dev); - goto unlock_and_return; + goto unlock; } } else { imx290_stop_streaming(imx290); pm_runtime_put(imx290->dev); } -unlock_and_return: - +unlock: + v4l2_subdev_unlock_state(state); return ret; } -static struct v4l2_mbus_framefmt * -imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state, - u32 which) -{ - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - return &imx290->current_format; - else - return v4l2_subdev_get_try_format(&imx290->sd, state, 0); -} - static int imx290_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -860,23 +853,6 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int imx290_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx290 *imx290 = to_imx290(sd); - struct v4l2_mbus_framefmt *framefmt; - - mutex_lock(&imx290->lock); - - framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which); - fmt->format = *framefmt; - - mutex_unlock(&imx290->lock); - - return 0; -} - static int imx290_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -886,8 +862,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; unsigned int i; - mutex_lock(&imx290->lock); - mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), imx290_modes_num(imx290), width, height, fmt->format.width, fmt->format.height); @@ -905,7 +879,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, fmt->format.code = imx290_formats[i].code; fmt->format.field = V4L2_FIELD_NONE; - format = imx290_get_pad_format(imx290, sd_state, fmt->which); + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx290->current_mode = mode; @@ -916,8 +890,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, *format = fmt->format; - mutex_unlock(&imx290->lock); - return 0; } @@ -925,14 +897,11 @@ static int imx290_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct imx290 *imx290 = to_imx290(sd); struct v4l2_mbus_framefmt *format; switch (sel->target) { case V4L2_SEL_TGT_CROP: { - format = imx290_get_pad_format(imx290, sd_state, sel->which); - - mutex_lock(&imx290->lock); + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2; @@ -941,7 +910,6 @@ static int imx290_get_selection(struct v4l2_subdev *sd, sel->r.width = format->width; sel->r.height = format->height; - mutex_unlock(&imx290->lock); return 0; } @@ -970,11 +938,13 @@ static int imx290_get_selection(struct v4l2_subdev *sd, static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - struct v4l2_subdev_format fmt = { 0 }; - - fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = 1920; - fmt.format.height = 1080; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .width = 1920, + .height = 1080, + }, + }; imx290_set_fmt(subdev, sd_state, &fmt); @@ -989,7 +959,7 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = { .init_cfg = imx290_entity_init_cfg, .enum_mbus_code = imx290_enum_mbus_code, .enum_frame_size = imx290_enum_frame_size, - .get_fmt = imx290_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx290_set_fmt, .get_selection = imx290_get_selection, }; @@ -1008,18 +978,8 @@ static int imx290_subdev_init(struct imx290 *imx290) struct i2c_client *client = to_i2c_client(imx290->dev); int ret; - /* - * Initialize the frame format. In particular, imx290->current_mode - * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call - * below relies on these fields. - */ - imx290_entity_init_cfg(&imx290->sd, NULL); - - ret = imx290_ctrl_init(imx290); - if (ret < 0) { - dev_err(imx290->dev, "Control initialization error %d\n", ret); - return ret; - } + imx290->current_mode = &imx290_modes_ptr(imx290)[0]; + imx290->bpp = imx290_formats[0].bpp; v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -1031,15 +991,37 @@ static int imx290_subdev_init(struct imx290 *imx290) ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); if (ret < 0) { dev_err(imx290->dev, "Could not register media entity\n"); - v4l2_ctrl_handler_free(&imx290->ctrls); return ret; } + ret = imx290_ctrl_init(imx290); + if (ret < 0) { + dev_err(imx290->dev, "Control initialization error %d\n", ret); + goto err_media; + } + + imx290->sd.state_lock = imx290->ctrls.lock; + + ret = v4l2_subdev_init_finalize(&imx290->sd); + if (ret < 0) { + dev_err(imx290->dev, "subdev initialization error %d\n", ret); + goto err_ctrls; + } + + imx290_ctrl_update(imx290, imx290->current_mode); + return 0; + +err_ctrls: + v4l2_ctrl_handler_free(&imx290->ctrls); +err_media: + media_entity_cleanup(&imx290->sd.entity); + return ret; } static void imx290_subdev_cleanup(struct imx290 *imx290) { + v4l2_subdev_cleanup(&imx290->sd); media_entity_cleanup(&imx290->sd.entity); v4l2_ctrl_handler_free(&imx290->ctrls); } @@ -1270,12 +1252,10 @@ static int imx290_probe(struct i2c_client *client) if (ret) return ret; - mutex_init(&imx290->lock); - /* Initialize and register subdev. */ ret = imx290_subdev_init(imx290); if (ret) - goto err_mutex; + return ret; ret = v4l2_async_register_subdev(&imx290->sd); if (ret < 0) { @@ -1298,8 +1278,6 @@ static int imx290_probe(struct i2c_client *client) err_subdev: imx290_subdev_cleanup(imx290); -err_mutex: - mutex_destroy(&imx290->lock); return ret; } @@ -1312,8 +1290,6 @@ static void imx290_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); imx290_subdev_cleanup(imx290); - mutex_destroy(&imx290->lock); - pm_runtime_disable(imx290->dev); if (!pm_runtime_status_suspended(imx290->dev)) imx290_power_off(imx290->dev); From 10591fe63691bd8199d5e7244029cc065959ffc9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 17 Oct 2022 12:44:27 +0200 Subject: [PATCH 021/216] media: i2c: imx290: Rename, extend and expand usage of imx290_pixfmt The imx290_pixfmt structure contains information about formats, currently limited to the bpp value. Extend it with the register settings for each format, and rename it to imx290_format_info to make its purpose clearer. Add a function named imx290_format_info() to look up format info for a media bus code, and use it through the code. This allows dropping the imx290 bpp field as the value is now looked up dynamically. The error handling in imx290_setup_format() can also be dropped, as the format is guaranteed by imx290_set_fmt() to be valid. Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 99 ++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 1aa5ab0c57ce..7356279822e8 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -182,7 +182,6 @@ struct imx290 { struct media_pad pad; const struct imx290_mode *current_mode; - u8 bpp; struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES]; struct gpio_desc *rst_gpio; @@ -414,16 +413,41 @@ static inline int imx290_modes_num(const struct imx290 *imx290) return ARRAY_SIZE(imx290_modes_4lanes); } -struct imx290_pixfmt { +struct imx290_format_info { u32 code; u8 bpp; + const struct imx290_regval *regs; + unsigned int num_regs; }; -static const struct imx290_pixfmt imx290_formats[] = { - { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, +static const struct imx290_format_info imx290_formats[] = { + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bpp = 10, + .regs = imx290_10bit_settings, + .num_regs = ARRAY_SIZE(imx290_10bit_settings), + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bpp = 12, + .regs = imx290_12bit_settings, + .num_regs = ARRAY_SIZE(imx290_12bit_settings), + } }; +static const struct imx290_format_info *imx290_format_info(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) { + const struct imx290_format_info *info = &imx290_formats[i]; + + if (info->code == code) + return info; + } + + return NULL; +} + /* ----------------------------------------------------------------------------- * Register access */ @@ -516,40 +540,31 @@ static int imx290_set_data_lanes(struct imx290 *imx290) } static int imx290_set_black_level(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format, unsigned int black_level, int *err) { + unsigned int bpp = imx290_format_info(format->code)->bpp; + return imx290_write(imx290, IMX290_BLKLEVEL, - black_level >> (16 - imx290->bpp), err); + black_level >> (16 - bpp), err); } static int imx290_setup_format(struct imx290 *imx290, const struct v4l2_mbus_framefmt *format) { - const struct imx290_regval *regs; - unsigned int num_regs; + const struct imx290_format_info *info; int ret; - switch (format->code) { - case MEDIA_BUS_FMT_SRGGB10_1X10: - regs = imx290_10bit_settings; - num_regs = ARRAY_SIZE(imx290_10bit_settings); - break; - case MEDIA_BUS_FMT_SRGGB12_1X12: - regs = imx290_12bit_settings; - num_regs = ARRAY_SIZE(imx290_12bit_settings); - break; - default: - dev_err(imx290->dev, "Unknown pixel format\n"); - return -EINVAL; - } + info = imx290_format_info(format->code); - ret = imx290_set_register_array(imx290, regs, num_regs); + ret = imx290_set_register_array(imx290, info->regs, info->num_regs); if (ret < 0) { dev_err(imx290->dev, "Could not set format registers\n"); return ret; } - return imx290_set_black_level(imx290, IMX290_BLACK_LEVEL_DEFAULT, &ret); + return imx290_set_black_level(imx290, format, + IMX290_BLACK_LEVEL_DEFAULT, &ret); } /* ---------------------------------------------------------------------------- @@ -560,6 +575,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx290 *imx290 = container_of(ctrl->handler, struct imx290, ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret = 0; /* @@ -575,6 +592,9 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) if (!pm_runtime_get_if_in_use(imx290->dev)) return 0; + state = v4l2_subdev_get_locked_active_state(&imx290->sd); + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL); @@ -587,7 +607,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: if (ctrl->val) { - imx290_set_black_level(imx290, 0, &ret); + imx290_set_black_level(imx290, format, 0, &ret); usleep_range(10000, 11000); imx290_write(imx290, IMX290_PGCTRL, (u8)(IMX290_PGCTRL_REGEN | @@ -596,8 +616,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) } else { imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret); usleep_range(10000, 11000); - imx290_set_black_level(imx290, IMX290_BLACK_LEVEL_DEFAULT, - &ret); + imx290_set_black_level(imx290, format, + IMX290_BLACK_LEVEL_DEFAULT, &ret); } break; @@ -627,6 +647,7 @@ static const char * const imx290_test_pattern_menu[] = { }; static void imx290_ctrl_update(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format, const struct imx290_mode *mode) { unsigned int hblank = mode->hmax - mode->width; @@ -636,7 +657,7 @@ static void imx290_ctrl_update(struct imx290 *imx290, /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ pixel_rate = link_freq * 2 * imx290->nlanes; - do_div(pixel_rate, imx290->bpp); + do_div(pixel_rate, imx290_format_info(format->code)->bpp); __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate); @@ -838,8 +859,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, const struct imx290 *imx290 = to_imx290(sd); const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); - if ((fse->code != imx290_formats[0].code) && - (fse->code != imx290_formats[1].code)) + if (!imx290_format_info(fse->code)) return -EINVAL; if (fse->index >= imx290_modes_num(imx290)) @@ -860,7 +880,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, struct imx290 *imx290 = to_imx290(sd); const struct imx290_mode *mode; struct v4l2_mbus_framefmt *format; - unsigned int i; mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), imx290_modes_num(imx290), width, height, @@ -869,23 +888,17 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, fmt->format.width = mode->width; fmt->format.height = mode->height; - for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) - if (imx290_formats[i].code == fmt->format.code) - break; + if (!imx290_format_info(fmt->format.code)) + fmt->format.code = imx290_formats[0].code; - if (i >= ARRAY_SIZE(imx290_formats)) - i = 0; - - fmt->format.code = imx290_formats[i].code; fmt->format.field = V4L2_FIELD_NONE; format = v4l2_subdev_get_pad_format(sd, sd_state, 0); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx290->current_mode = mode; - imx290->bpp = imx290_formats[i].bpp; - imx290_ctrl_update(imx290, mode); + imx290_ctrl_update(imx290, &fmt->format, mode); } *format = fmt->format; @@ -976,10 +989,11 @@ static const struct media_entity_operations imx290_subdev_entity_ops = { static int imx290_subdev_init(struct imx290 *imx290) { struct i2c_client *client = to_i2c_client(imx290->dev); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret; imx290->current_mode = &imx290_modes_ptr(imx290)[0]; - imx290->bpp = imx290_formats[0].bpp; v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -1008,7 +1022,10 @@ static int imx290_subdev_init(struct imx290 *imx290) goto err_ctrls; } - imx290_ctrl_update(imx290, imx290->current_mode); + state = v4l2_subdev_lock_and_get_active_state(&imx290->sd); + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + imx290_ctrl_update(imx290, format, imx290->current_mode); + v4l2_subdev_unlock_state(state); return 0; From a8c3e0c1bf1e97b5ee094951ed0f1e57e3b378c7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:50 +0100 Subject: [PATCH 022/216] media: i2c: imx290: Use runtime PM autosuspend Use runtime PM autosuspend to avoid powering off the sensor during fast stop-reconfigure-restart cycles. This also fixes runtime PM handling in the probe function that didn't suspend the device, effectively leaving it resumed forever. While at it, improve documentation of power management in probe() and remove(). Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 58 +++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 7356279822e8..324d30ed5617 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -626,7 +626,8 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(imx290->dev); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); return ret; } @@ -827,12 +828,13 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) ret = imx290_start_streaming(imx290, state); if (ret) { dev_err(imx290->dev, "Start stream failed\n"); - pm_runtime_put(imx290->dev); + pm_runtime_put_sync(imx290->dev); goto unlock; } } else { imx290_stop_streaming(imx290); - pm_runtime_put(imx290->dev); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); } unlock: @@ -1269,33 +1271,59 @@ static int imx290_probe(struct i2c_client *client) if (ret) return ret; - /* Initialize and register subdev. */ + /* Initialize the V4L2 subdev. */ ret = imx290_subdev_init(imx290); if (ret) return ret; - ret = v4l2_async_register_subdev(&imx290->sd); - if (ret < 0) { - dev_err(dev, "Could not register v4l2 device\n"); - goto err_subdev; - } - - /* Power on the device to match runtime PM state below */ + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here. + */ ret = imx290_power_on(dev); if (ret < 0) { dev_err(dev, "Could not power on the device\n"); goto err_subdev; } + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + /* + * Finally, register the V4L2 subdev. This must be done after + * initializing everything as the subdev can be used immediately after + * being registered. + */ + ret = v4l2_async_register_subdev(&imx290->sd); + if (ret < 0) { + dev_err(dev, "Could not register v4l2 device\n"); + goto err_pm; + } + + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; +err_pm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + imx290_power_off(dev); err_subdev: imx290_subdev_cleanup(imx290); - return ret; } @@ -1307,6 +1335,10 @@ static void imx290_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); imx290_subdev_cleanup(imx290); + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ pm_runtime_disable(imx290->dev); if (!pm_runtime_status_suspended(imx290->dev)) imx290_power_off(imx290->dev); From 02852c01f65402e2fe4a8a5fe5a0b641f245b529 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:51 +0100 Subject: [PATCH 023/216] media: i2c: imx290: Initialize runtime PM before subdev Initializing the subdev before runtime PM means that no subdev initialization can interact with the runtime PM framework. This can be problematic when modifying controls, as the .s_ctrl() handler commonly calls pm_runtime_get_if_in_use(). These code paths are not trivial, making the driver fragile and possibly causing subtle bugs. To make the subdev initialization more robust, initialize runtime PM first. Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 324d30ed5617..4185835f065d 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -581,9 +581,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) /* * Return immediately for controls that don't need to be applied to the - * device. Those controls are modified in imx290_ctrl_update(), which - * is called at probe time before runtime PM is initialized, so we - * can't proceed to the pm_runtime_get_if_in_use() call below. + * device. */ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) return 0; @@ -1049,22 +1047,20 @@ static void imx290_subdev_cleanup(struct imx290 *imx290) * Power management */ -static int imx290_power_on(struct device *dev) +static int imx290_power_on(struct imx290 *imx290) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx290 *imx290 = to_imx290(sd); int ret; ret = clk_prepare_enable(imx290->xclk); if (ret) { - dev_err(dev, "Failed to enable clock\n"); + dev_err(imx290->dev, "Failed to enable clock\n"); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies), imx290->supplies); if (ret) { - dev_err(dev, "Failed to enable regulators\n"); + dev_err(imx290->dev, "Failed to enable regulators\n"); clk_disable_unprepare(imx290->xclk); return ret; } @@ -1079,20 +1075,33 @@ static int imx290_power_on(struct device *dev) return 0; } -static int imx290_power_off(struct device *dev) +static void imx290_power_off(struct imx290 *imx290) +{ + clk_disable_unprepare(imx290->xclk); + gpiod_set_value_cansleep(imx290->rst_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies); +} + +static int imx290_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx290 *imx290 = to_imx290(sd); - clk_disable_unprepare(imx290->xclk); - gpiod_set_value_cansleep(imx290->rst_gpio, 1); - regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies); + return imx290_power_on(imx290); +} + +static int imx290_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx290 *imx290 = to_imx290(sd); + + imx290_power_off(imx290); return 0; } static const struct dev_pm_ops imx290_pm_ops = { - SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) + SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL) }; /* ---------------------------------------------------------------------------- @@ -1271,20 +1280,15 @@ static int imx290_probe(struct i2c_client *client) if (ret) return ret; - /* Initialize the V4L2 subdev. */ - ret = imx290_subdev_init(imx290); - if (ret) - return ret; - /* * Enable power management. The driver supports runtime PM, but needs to * work when runtime PM is disabled in the kernel. To that end, power * the sensor on manually here. */ - ret = imx290_power_on(dev); + ret = imx290_power_on(imx290); if (ret < 0) { dev_err(dev, "Could not power on the device\n"); - goto err_subdev; + return ret; } /* @@ -1298,6 +1302,11 @@ static int imx290_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); + /* Initialize the V4L2 subdev. */ + ret = imx290_subdev_init(imx290); + if (ret) + goto err_pm; + /* * Finally, register the V4L2 subdev. This must be done after * initializing everything as the subdev can be used immediately after @@ -1306,7 +1315,7 @@ static int imx290_probe(struct i2c_client *client) ret = v4l2_async_register_subdev(&imx290->sd); if (ret < 0) { dev_err(dev, "Could not register v4l2 device\n"); - goto err_pm; + goto err_subdev; } /* @@ -1318,12 +1327,12 @@ static int imx290_probe(struct i2c_client *client) return 0; +err_subdev: + imx290_subdev_cleanup(imx290); err_pm: pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - imx290_power_off(dev); -err_subdev: - imx290_subdev_cleanup(imx290); + imx290_power_off(imx290); return ret; } @@ -1341,7 +1350,7 @@ static void imx290_remove(struct i2c_client *client) */ pm_runtime_disable(imx290->dev); if (!pm_runtime_status_suspended(imx290->dev)) - imx290_power_off(imx290->dev); + imx290_power_off(imx290); pm_runtime_set_suspended(imx290->dev); } From 7d399658f7c666ead4bc3dbe88944bb8ea7746ca Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:52 +0100 Subject: [PATCH 024/216] media: i2c: imx290: Configure data lanes at start time There's no need to configure the data lanes in the runtime PM resume handler. Do so in imx290_start_streaming() instead. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4185835f065d..34278d098218 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -762,6 +762,9 @@ static int imx290_start_streaming(struct imx290 *imx290, return ret; } + /* Set data lane count */ + imx290_set_data_lanes(imx290); + /* Apply the register values related to current frame format */ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); ret = imx290_setup_format(imx290, format); @@ -1069,9 +1072,6 @@ static int imx290_power_on(struct imx290 *imx290) gpiod_set_value_cansleep(imx290->rst_gpio, 0); usleep_range(30000, 31000); - /* Set data lane count */ - imx290_set_data_lanes(imx290); - return 0; } From 76c001287f6a56f37a5d48682086c334d81ec9f2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:53 +0100 Subject: [PATCH 025/216] media: i2c: imx290: Simplify imx290_set_data_lanes() There's no need to check for an incorrect number of data lanes in imx290_set_data_lanes() as the value is validated at probe() time. Drop the check. The PHY_LANE_NUM and CSI_LANE_MODE registers are programmed with a value equal to the number of lanes minus one. Compute it instead of handling it in the switch/case. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 34278d098218..bb8713813e29 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -512,28 +512,21 @@ static int imx290_set_register_array(struct imx290 *imx290, static int imx290_set_data_lanes(struct imx290 *imx290) { - int ret = 0, laneval, frsel; + int ret = 0; + u32 frsel; switch (imx290->nlanes) { case 2: - laneval = 0x01; + default: frsel = 0x02; break; case 4: - laneval = 0x03; frsel = 0x01; break; - default: - /* - * We should never hit this since the data lane count is - * validated in probe itself - */ - dev_err(imx290->dev, "Lane configuration not supported\n"); - return -EINVAL; } - imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret); - imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret); + imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret); + imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret); imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); return ret; From 05ef7ec49d6b7ed364ad68cf348f952ffcc22605 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:54 +0100 Subject: [PATCH 026/216] media: i2c: imx290: Handle error from imx290_set_data_lanes() Check the error status returned by imx290_set_data_lanes() in its caller and propagate it. Signed-off-by: Laurent Pinchart Reviewed-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index bb8713813e29..49d6c8bdec41 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -756,7 +756,11 @@ static int imx290_start_streaming(struct imx290 *imx290, } /* Set data lane count */ - imx290_set_data_lanes(imx290); + ret = imx290_set_data_lanes(imx290); + if (ret < 0) { + dev_err(imx290->dev, "Could not set data lanes\n"); + return ret; + } /* Apply the register values related to current frame format */ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); From 3216e828b919675f7bc511f7aa575ee93090b5b1 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 16 Jan 2023 16:44:47 +0100 Subject: [PATCH 027/216] media: dt-bindings: media: Add OmniVision OV8858 Add binding schema for the OmniVision OV8858 8 Megapixels camera sensor. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/ovti,ov8858.yaml | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml new file mode 100644 index 000000000000..a65f921ec0fd --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov8858.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV8858 Image Sensor + +maintainers: + - Jacopo Mondi + - Nicholas Roth + +description: | + The OmniVision OV8858 is a color CMOS 8 Megapixels (3264x2448) image sensor + controlled through an I2C-compatible SCCB bus. The sensor transmits images + on a MIPI CSI-2 output interface with up to 4 data lanes. + +properties: + compatible: + const: ovti,ov8858 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: XVCLK external clock + + clock-names: + const: xvclk + + dvdd-supply: + description: Digital Domain Power Supply + + avdd-supply: + description: Analog Domain Power Supply + + dovdd-supply: + description: I/O Domain Power Supply + + powerdown-gpios: + description: PWDNB powerdown GPIO (active low) + + reset-gpios: + maxItems: 1 + description: XSHUTDN reset GPIO (active low) + + port: + description: MIPI CSI-2 transmitter port + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + #include + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov8858: camera@36 { + compatible = "ovti,ov8858"; + reg = <0x36>; + + clocks = <&cru SCLK_CIF_OUT>; + clock-names = "xvclk"; + assigned-clocks = <&cru SCLK_CIF_OUT>; + assigned-clock-rates = <24000000>; + + dovdd-supply = <&vcc1v8_dvp>; + + reset-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; +... From e14d3ac81bd2264edc76bf5796305b2dfea44487 Mon Sep 17 00:00:00 2001 From: Nicholas Roth Date: Mon, 16 Jan 2023 16:44:48 +0100 Subject: [PATCH 028/216] media: i2c: Add driver for OmniVision OV8858 Add a driver for OmniVision OV8858 image sensor. The driver currently supports operations with 2 and 4 data lanes, in full resolution and half-binned resolution modes. The driver has been upported from the PinephonePro BSP available at https://gitlab.com/pine64-org/linux.git at commit 8c4a90c12dc2 ("media: i2c: ov8858: Use default subdev name"). Signed-off-by: Nicholas Roth Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 9 + drivers/media/i2c/Kconfig | 13 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov8858.c | 2008 ++++++++++++++++++++++++++++++++++++ 4 files changed, 2031 insertions(+) create mode 100644 drivers/media/i2c/ov8858.c diff --git a/MAINTAINERS b/MAINTAINERS index ba5254cd1002..d435a4dd5971 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15516,6 +15516,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml F: drivers/media/i2c/ov8856.c +OMNIVISION OV8858 SENSOR DRIVER +M: Jacopo Mondi +M: Nicholas Roth +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml +F: drivers/media/i2c/ov8858.c + OMNIVISION OV9282 SENSOR DRIVER M: Paul J. Murphy M: Daniele Alessandrelli diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 833241897d63..12ba8542778f 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -645,6 +645,19 @@ config VIDEO_OV8856 To compile this driver as a module, choose M here: the module will be called ov8856. +config VIDEO_OV8858 + tristate "OmniVision OV8858 sensor support" + depends on I2C && PM && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for OmniVision + OV8858 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called ov8858. + config VIDEO_OV8865 tristate "OmniVision OV8865 sensor support" depends on I2C && PM && VIDEO_DEV diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 4d6c052bb5a7..b611a8277d57 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV8856) += ov8856.o +obj-$(CONFIG_VIDEO_OV8858) += ov8858.o obj-$(CONFIG_VIDEO_OV8865) += ov8865.o obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c new file mode 100644 index 000000000000..9ca8a17bfbb9 --- /dev/null +++ b/drivers/media/i2c/ov8858.c @@ -0,0 +1,2008 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Jacopo Mondi + * Copyright (C) 2022 Nicholas Roth + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV8858_LINK_FREQ 360000000U +#define OV8858_XVCLK_FREQ 24000000 + +#define OV8858_REG_SIZE_SHIFT 16 +#define OV8858_REG_ADDR_MASK 0xffff +#define OV8858_REG_8BIT(n) ((1U << OV8858_REG_SIZE_SHIFT) | (n)) +#define OV8858_REG_16BIT(n) ((2U << OV8858_REG_SIZE_SHIFT) | (n)) +#define OV8858_REG_24BIT(n) ((3U << OV8858_REG_SIZE_SHIFT) | (n)) + +#define OV8858_REG_SC_CTRL0100 OV8858_REG_8BIT(0x0100) +#define OV8858_MODE_SW_STANDBY 0x0 +#define OV8858_MODE_STREAMING 0x1 + +#define OV8858_REG_CHIP_ID OV8858_REG_24BIT(0x300a) +#define OV8858_CHIP_ID 0x008858 + +#define OV8858_REG_SUB_ID OV8858_REG_8BIT(0x302a) +#define OV8858_R1A 0xb0 +#define OV8858_R2A 0xb2 + +#define OV8858_REG_LONG_EXPO OV8858_REG_24BIT(0x3500) +#define OV8858_EXPOSURE_MIN 4 +#define OV8858_EXPOSURE_STEP 1 +#define OV8858_EXPOSURE_MARGIN 4 + +#define OV8858_REG_LONG_GAIN OV8858_REG_16BIT(0x3508) +#define OV8858_LONG_GAIN_MIN 0x0 +#define OV8858_LONG_GAIN_MAX 0x7ff +#define OV8858_LONG_GAIN_STEP 1 +#define OV8858_LONG_GAIN_DEFAULT 0x80 + +#define OV8858_REG_LONG_DIGIGAIN OV8858_REG_16BIT(0x350a) +#define OV8858_LONG_DIGIGAIN_H_MASK 0x3fc0 +#define OV8858_LONG_DIGIGAIN_L_MASK 0x3f +#define OV8858_LONG_DIGIGAIN_H_SHIFT 2 +#define OV8858_LONG_DIGIGAIN_MIN 0x0 +#define OV8858_LONG_DIGIGAIN_MAX 0x3fff +#define OV8858_LONG_DIGIGAIN_STEP 1 +#define OV8858_LONG_DIGIGAIN_DEFAULT 0x200 + +#define OV8858_REG_VTS OV8858_REG_16BIT(0x380e) +#define OV8858_VTS_MAX 0x7fff + +#define OV8858_REG_TEST_PATTERN OV8858_REG_8BIT(0x5e00) +#define OV8858_TEST_PATTERN_ENABLE 0x80 +#define OV8858_TEST_PATTERN_DISABLE 0x0 + +#define REG_NULL 0xffff + +static const char * const ov8858_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +struct regval { + u16 addr; + u8 val; +}; + +struct regval_modes { + const struct regval *mode_2lanes; + const struct regval *mode_4lanes; +}; + +struct ov8858_mode { + u32 width; + u32 height; + u32 hts_def; + u32 vts_def; + u32 exp_def; + const struct regval_modes reg_modes; +}; + +struct ov8858 { + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct gpio_desc *pwdn_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov8858_supply_names)]; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + + const struct regval *global_regs; + + unsigned int num_lanes; +}; + +static inline struct ov8858 *sd_to_ov8858(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov8858, subdev); +} + +static const struct regval ov8858_global_regs_r1a[] = { + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0302, 0x1e}, + {0x0303, 0x00}, + {0x0304, 0x03}, + {0x030e, 0x00}, + {0x030f, 0x09}, + {0x0312, 0x01}, + {0x031e, 0x0c}, + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x30}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x06}, + {0x360c, 0xdc}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0xb0}, + {0x3618, 0x56}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x00}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x01}, + {0x3018, 0x32}, + {0x3020, 0x93}, + {0x3022, 0x01}, + {0x3031, 0x0a}, + {0x3034, 0x00}, + {0x3106, 0x01}, + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, + {0x3501, 0x4d}, + {0x3502, 0x40}, + {0x3503, 0x00}, + {0x3505, 0x80}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3700, 0x18}, + {0x3701, 0x0c}, + {0x3702, 0x28}, + {0x3703, 0x19}, + {0x3704, 0x14}, + {0x3705, 0x00}, + {0x3706, 0x35}, + {0x3707, 0x04}, + {0x3708, 0x24}, + {0x3709, 0x33}, + {0x370a, 0x00}, + {0x370b, 0xb5}, + {0x370c, 0x04}, + {0x3718, 0x12}, + {0x3719, 0x31}, + {0x3712, 0x42}, + {0x3714, 0x24}, + {0x371e, 0x19}, + {0x371f, 0x40}, + {0x3720, 0x05}, + {0x3721, 0x05}, + {0x3724, 0x06}, + {0x3725, 0x01}, + {0x3726, 0x06}, + {0x3728, 0x05}, + {0x3729, 0x02}, + {0x372a, 0x03}, + {0x372b, 0x53}, + {0x372c, 0xa3}, + {0x372d, 0x53}, + {0x372e, 0x06}, + {0x372f, 0x10}, + {0x3730, 0x01}, + {0x3731, 0x06}, + {0x3732, 0x14}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x20}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373e, 0x03}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x06}, + {0x375b, 0x13}, + {0x375c, 0x20}, + {0x375d, 0x02}, + {0x375e, 0x00}, + {0x375f, 0x14}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x23}, + {0x3773, 0x02}, + {0x3774, 0x16}, + {0x3775, 0x12}, + {0x3776, 0x04}, + {0x3777, 0x00}, + {0x3778, 0x1b}, + {0x37a0, 0x44}, + {0x37a1, 0x3d}, + {0x37a2, 0x3d}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x44}, + {0x37a8, 0x4c}, + {0x37a9, 0x4c}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x44}, + {0x37ab, 0x2e}, + {0x37ac, 0x2e}, + {0x37ad, 0x33}, + {0x37ae, 0x0d}, + {0x37af, 0x0d}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x42}, + {0x37b4, 0x42}, + {0x37b5, 0x33}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x0c}, + {0x3804, 0x0c}, + {0x3805, 0xd3}, + {0x3806, 0x09}, + {0x3807, 0xa3}, + {0x3808, 0x06}, + {0x3809, 0x60}, + {0x380a, 0x04}, + {0x380b, 0xc8}, + {0x380c, 0x07}, + {0x380d, 0x88}, + {0x380e, 0x04}, + {0x380f, 0xdc}, + {0x3810, 0x00}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3820, 0x00}, + {0x3821, 0x67}, + {0x382a, 0x03}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3d85, 0x14}, + {0x3f08, 0x08}, + {0x3f0a, 0x80}, + {0x4000, 0xf1}, + {0x4001, 0x10}, + {0x4005, 0x10}, + {0x4002, 0x27}, + {0x4009, 0x81}, + {0x400b, 0x0c}, + {0x401b, 0x00}, + {0x401d, 0x00}, + {0x4020, 0x00}, + {0x4021, 0x04}, + {0x4022, 0x04}, + {0x4023, 0xb9}, + {0x4024, 0x05}, + {0x4025, 0x2a}, + {0x4026, 0x05}, + {0x4027, 0x2b}, + {0x4028, 0x00}, + {0x4029, 0x02}, + {0x402a, 0x04}, + {0x402b, 0x04}, + {0x402c, 0x02}, + {0x402d, 0x02}, + {0x402e, 0x08}, + {0x402f, 0x02}, + {0x401f, 0x00}, + {0x4034, 0x3f}, + {0x403d, 0x04}, + {0x4300, 0xff}, + {0x4301, 0x00}, + {0x4302, 0x0f}, + {0x4316, 0x00}, + {0x4500, 0x38}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, + {0x4837, 0x16}, + {0x4850, 0x10}, + {0x4851, 0x32}, + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, + {0x5000, 0x7e}, + {0x5001, 0x01}, + {0x5002, 0x08}, + {0x5003, 0x20}, + {0x5046, 0x12}, + {0x5901, 0x00}, + {0x5e00, 0x00}, + {0x5e01, 0x41}, + {0x382d, 0x7f}, + {0x4825, 0x3a}, + {0x4826, 0x40}, + {0x4808, 0x25}, + {REG_NULL, 0x00}, +}; + +static const struct regval ov8858_global_regs_r2a_2lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0103, 0x01}, /* software reset */ + {0x0100, 0x00}, /* software standby */ + {0x0302, 0x1e}, /* pll1_multi */ + {0x0303, 0x00}, /* pll1_divm */ + {0x0304, 0x03}, /* pll1_div_mipi */ + {0x030e, 0x02}, /* pll2_rdiv */ + {0x030f, 0x04}, /* pll2_divsp */ + {0x0312, 0x03}, /* pll2_pre_div0, pll2_r_divdac */ + {0x031e, 0x0c}, /* pll1_no_lat */ + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x20}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x05}, + {0x360c, 0xd4}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0x90}, + {0x3618, 0x5a}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x0a}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0f}, + {0x3634, 0x0f}, + {0x3635, 0x0f}, + {0x3636, 0x12}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x00}, + {0x3018, 0x32}, /* MIPI 2 lane */ + {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */ + {0x3022, 0x01}, /* pd_mipi enable when rst_sync */ + {0x3031, 0x0a}, /* MIPI 10-bit mode */ + {0x3034, 0x00}, + {0x3106, 0x01}, /* sclk_div, sclk_pre_div */ + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, /* exposure H */ + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */ + {0x3505, 0x80}, /* gain option */ + {0x3508, 0x02}, /* gain H */ + {0x3509, 0x00}, /* gain L */ + {0x350c, 0x00}, /* short gain H */ + {0x350d, 0x80}, /* short gain L */ + {0x3510, 0x00}, /* short exposure H */ + {0x3511, 0x02}, /* short exposure M */ + {0x3512, 0x00}, /* short exposure L */ + {0x3700, 0x18}, + {0x3701, 0x0c}, + {0x3702, 0x28}, + {0x3703, 0x19}, + {0x3704, 0x14}, + {0x3705, 0x00}, + {0x3706, 0x82}, + {0x3707, 0x04}, + {0x3708, 0x24}, + {0x3709, 0x33}, + {0x370a, 0x01}, + {0x370b, 0x82}, + {0x370c, 0x04}, + {0x3718, 0x12}, + {0x3719, 0x31}, + {0x3712, 0x42}, + {0x3714, 0x24}, + {0x371e, 0x19}, + {0x371f, 0x40}, + {0x3720, 0x05}, + {0x3721, 0x05}, + {0x3724, 0x06}, + {0x3725, 0x01}, + {0x3726, 0x06}, + {0x3728, 0x05}, + {0x3729, 0x02}, + {0x372a, 0x03}, + {0x372b, 0x53}, + {0x372c, 0xa3}, + {0x372d, 0x53}, + {0x372e, 0x06}, + {0x372f, 0x10}, + {0x3730, 0x01}, + {0x3731, 0x06}, + {0x3732, 0x14}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x20}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373e, 0x03}, + {0x3750, 0x0a}, + {0x3751, 0x0e}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x06}, + {0x375b, 0x13}, + {0x375c, 0x20}, + {0x375d, 0x02}, + {0x375e, 0x00}, + {0x375f, 0x14}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x23}, + {0x3773, 0x02}, + {0x3774, 0x16}, + {0x3775, 0x12}, + {0x3776, 0x04}, + {0x3777, 0x00}, + {0x3778, 0x17}, + {0x37a0, 0x44}, + {0x37a1, 0x3d}, + {0x37a2, 0x3d}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x44}, + {0x37a8, 0x4c}, + {0x37a9, 0x4c}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x44}, + {0x37ab, 0x2e}, + {0x37ac, 0x2e}, + {0x37ad, 0x33}, + {0x37ae, 0x0d}, + {0x37af, 0x0d}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x42}, + {0x37b4, 0x42}, + {0x37b5, 0x31}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, /* x start H */ + {0x3801, 0x0c}, /* x start L */ + {0x3802, 0x00}, /* y start H */ + {0x3803, 0x0c}, /* y start L */ + {0x3804, 0x0c}, /* x end H */ + {0x3805, 0xd3}, /* x end L */ + {0x3806, 0x09}, /* y end H */ + {0x3807, 0xa3}, /* y end L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3810, 0x00}, /* ISP x win H */ + {0x3811, 0x04}, /* ISP x win L */ + {0x3813, 0x02}, /* ISP y win L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3815, 0x01}, /* x even inc */ + {0x3820, 0x00}, /* vflip off */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x382b, 0x01}, /* y even inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, /* window auto size enable */ + {0x3846, 0x48}, + {0x3d85, 0x16}, /* OTP power up load data enable with BIST */ + {0x3d8c, 0x73}, /* OTP setting start High */ + {0x3d8d, 0xde}, /* OTP setting start Low */ + {0x3f08, 0x08}, + {0x3f0a, 0x00}, + {0x4000, 0xf1}, /* out_range_trig, format_chg_trig */ + {0x4001, 0x10}, /* total 128 black column */ + {0x4005, 0x10}, /* BLC target L */ + {0x4002, 0x27}, /* value used to limit BLC offset */ + {0x4009, 0x81}, /* final BLC offset limitation enable */ + {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */ + {0x401b, 0x00}, /* zero line R coefficient */ + {0x401d, 0x00}, /* zoro line T coefficient */ + {0x4020, 0x00}, /* Anchor left start H */ + {0x4021, 0x04}, /* Anchor left start L */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4024, 0x0f}, /* Anchor right start H */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4026, 0x0f}, /* Anchor right end H */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x4028, 0x00}, /* top zero line start */ + {0x4029, 0x02}, /* top zero line number */ + {0x402a, 0x04}, /* top black line start */ + {0x402b, 0x04}, /* top black line number */ + {0x402c, 0x00}, /* bottom zero line start */ + {0x402d, 0x02}, /* bottom zoro line number */ + {0x402e, 0x04}, /* bottom black line start */ + {0x402f, 0x04}, /* bottom black line number */ + {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */ + {0x4034, 0x3f}, + {0x403d, 0x04}, /* md_precision_en */ + {0x4300, 0xff}, /* clip max H */ + {0x4301, 0x00}, /* clip min H */ + {0x4302, 0x0f}, /* clip min L, clip max L */ + {0x4316, 0x00}, + {0x4500, 0x58}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, /* clk prepare min */ + {0x4837, 0x16}, /* global timing */ + {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */ + {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */ + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, /* temperature sensor */ + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, /* temperature sensor */ + {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */ + {0x5001, 0x01}, /* BLC on */ + {0x5002, 0x08}, /* H scale off, WBMATCH off, OTP_DPC */ + {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */ + {0x501e, 0x93}, /* enable digital gain */ + {0x5046, 0x12}, + {0x5780, 0x3e}, /* DPC */ + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x00}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, /* DPC */ + {0x5871, 0x0d}, /* Lenc */ + {0x5870, 0x18}, + {0x586e, 0x10}, + {0x586f, 0x08}, + {0x58f7, 0x01}, + {0x58f8, 0x3d}, /* Lenc */ + {0x5901, 0x00}, /* H skip off, V skip off */ + {0x5b00, 0x02}, /* OTP DPC start address */ + {0x5b01, 0x10}, /* OTP DPC start address */ + {0x5b02, 0x03}, /* OTP DPC end address */ + {0x5b03, 0xcf}, /* OTP DPC end address */ + {0x5b05, 0x6c}, /* recover method = 2b11, */ + {0x5e00, 0x00}, /* use 0x3ff to test pattern off */ + {0x5e01, 0x41}, /* window cut enable */ + {0x382d, 0x7f}, + {0x4825, 0x3a}, /* lpx_p_min */ + {0x4826, 0x40}, /* hs_prepare_min */ + {0x4808, 0x25}, /* wake up delay in 1/1024 s */ + {0x3763, 0x18}, + {0x3768, 0xcc}, + {0x470b, 0x28}, + {0x4202, 0x00}, + {0x400d, 0x10}, /* BLC offset trigger L */ + {0x4040, 0x04}, /* BLC gain th2 */ + {0x403e, 0x04}, /* BLC gain th1 */ + {0x4041, 0xc6}, /* BLC */ + {0x3007, 0x80}, + {0x400a, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 30fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_1632x1224_regs_2lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0100, 0x00}, + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3778, 0x17}, + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3f0a, 0x00}, + {0x4001, 0x10}, /* total 128 black column */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x402b, 0x04}, /* top black line number */ + {0x402f, 0x04}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x382d, 0x7f}, + {0x0100, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 15fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_3264x2448_regs_2lane[] = { + {0x0100, 0x00}, + {0x3501, 0x9a}, /* exposure M */ + {0x3502, 0x20}, /* exposure L */ + {0x3778, 0x1a}, + {0x3808, 0x0c}, /* x output size H */ + {0x3809, 0xc0}, /* x output size L */ + {0x380a, 0x09}, /* y output size H */ + {0x380b, 0x90}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x94}, /* HTS L */ + {0x380e, 0x09}, /* VTS H */ + {0x380f, 0xaa}, /* VTS L */ + {0x3814, 0x01}, /* x odd inc */ + {0x3821, 0x46}, /* mirror on, bin off */ + {0x382a, 0x01}, /* y odd inc */ + {0x3830, 0x06}, + {0x3836, 0x01}, + {0x3f0a, 0x00}, + {0x4001, 0x00}, /* total 256 black column */ + {0x4022, 0x0c}, /* Anchor left end H */ + {0x4023, 0x60}, /* Anchor left end L */ + {0x4025, 0x36}, /* Anchor right start L */ + {0x4027, 0x37}, /* Anchor right end L */ + {0x402b, 0x08}, /* top black line number */ + {0x402f, 0x08}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x01}, + {0x4601, 0x97}, + {0x382d, 0xff}, + {REG_NULL, 0x00}, +}; + +static const struct regval ov8858_global_regs_r2a_4lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0103, 0x01}, /* software reset for OVTATool only */ + {0x0103, 0x01}, /* software reset */ + {0x0100, 0x00}, /* software standby */ + {0x0302, 0x1e}, /* pll1_multi */ + {0x0303, 0x00}, /* pll1_divm */ + {0x0304, 0x03}, /* pll1_div_mipi */ + {0x030e, 0x00}, /* pll2_rdiv */ + {0x030f, 0x04}, /* pll2_divsp */ + {0x0312, 0x01}, /* pll2_pre_div0, pll2_r_divdac */ + {0x031e, 0x0c}, /* pll1_no_lat */ + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x20}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x05}, + {0x360c, 0xd4}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0x90}, + {0x3618, 0x5a}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x0a}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0f}, + {0x3634, 0x0f}, + {0x3635, 0x0f}, + {0x3636, 0x12}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x01}, + {0x3018, 0x72}, /* MIPI 4 lane */ + {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */ + {0x3022, 0x01}, /* pd_mipi enable when rst_sync */ + {0x3031, 0x0a}, /* MIPI 10-bit mode */ + {0x3034, 0x00}, + {0x3106, 0x01}, /* sclk_div, sclk_pre_div */ + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, /* exposure H */ + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */ + {0x3505, 0x80}, /* gain option */ + {0x3508, 0x02}, /* gain H */ + {0x3509, 0x00}, /* gain L */ + {0x350c, 0x00}, /* short gain H */ + {0x350d, 0x80}, /* short gain L */ + {0x3510, 0x00}, /* short exposure H */ + {0x3511, 0x02}, /* short exposure M */ + {0x3512, 0x00}, /* short exposure L */ + {0x3700, 0x30}, + {0x3701, 0x18}, + {0x3702, 0x50}, + {0x3703, 0x32}, + {0x3704, 0x28}, + {0x3705, 0x00}, + {0x3706, 0x82}, + {0x3707, 0x08}, + {0x3708, 0x48}, + {0x3709, 0x66}, + {0x370a, 0x01}, + {0x370b, 0x82}, + {0x370c, 0x07}, + {0x3718, 0x14}, + {0x3719, 0x31}, + {0x3712, 0x44}, + {0x3714, 0x24}, + {0x371e, 0x31}, + {0x371f, 0x7f}, + {0x3720, 0x0a}, + {0x3721, 0x0a}, + {0x3724, 0x0c}, + {0x3725, 0x02}, + {0x3726, 0x0c}, + {0x3728, 0x0a}, + {0x3729, 0x03}, + {0x372a, 0x06}, + {0x372b, 0xa6}, + {0x372c, 0xa6}, + {0x372d, 0xa6}, + {0x372e, 0x0c}, + {0x372f, 0x20}, + {0x3730, 0x02}, + {0x3731, 0x0c}, + {0x3732, 0x28}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x30}, + {0x373a, 0x0a}, + {0x373b, 0x0b}, + {0x373c, 0x14}, + {0x373e, 0x06}, + {0x3750, 0x0a}, + {0x3751, 0x0e}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x0c}, + {0x375b, 0x26}, + {0x375c, 0x20}, + {0x375d, 0x04}, + {0x375e, 0x00}, + {0x375f, 0x28}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x46}, + {0x3773, 0x04}, + {0x3774, 0x2c}, + {0x3775, 0x13}, + {0x3776, 0x08}, + {0x3777, 0x00}, + {0x3778, 0x17}, + {0x37a0, 0x88}, + {0x37a1, 0x7a}, + {0x37a2, 0x7a}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x88}, + {0x37a8, 0x98}, + {0x37a9, 0x98}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x88}, + {0x37ab, 0x5c}, + {0x37ac, 0x5c}, + {0x37ad, 0x55}, + {0x37ae, 0x19}, + {0x37af, 0x19}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x84}, + {0x37b4, 0x84}, + {0x37b5, 0x60}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, /* x start H */ + {0x3801, 0x0c}, /* x start L */ + {0x3802, 0x00}, /* y start H */ + {0x3803, 0x0c}, /* y start L */ + {0x3804, 0x0c}, /* x end H */ + {0x3805, 0xd3}, /* x end L */ + {0x3806, 0x09}, /* y end H */ + {0x3807, 0xa3}, /* y end L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3810, 0x00}, /* ISP x win H */ + {0x3811, 0x04}, /* ISP x win L */ + {0x3813, 0x02}, /* ISP y win L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3815, 0x01}, /* x even inc */ + {0x3820, 0x00}, /* vflip off */ + {0x3821, 0x67}, /* mirror on, bin o */ + {0x382a, 0x03}, /* y odd inc */ + {0x382b, 0x01}, /* y even inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, /* window auto size enable */ + {0x3846, 0x48}, + {0x3d85, 0x16}, /* OTP power up load data/setting enable */ + {0x3d8c, 0x73}, /* OTP setting start High */ + {0x3d8d, 0xde}, /* OTP setting start Low */ + {0x3f08, 0x10}, + {0x3f0a, 0x00}, + {0x4000, 0xf1}, /* out_range/format_chg/gain/exp_chg trig enable */ + {0x4001, 0x10}, /* total 128 black column */ + {0x4005, 0x10}, /* BLC target L */ + {0x4002, 0x27}, /* value used to limit BLC offset */ + {0x4009, 0x81}, /* final BLC offset limitation enable */ + {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */ + {0x401b, 0x00}, /* zero line R coefficient */ + {0x401d, 0x00}, /* zoro line T coefficient */ + {0x4020, 0x00}, /* Anchor left start H */ + {0x4021, 0x04}, /* Anchor left start L */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4024, 0x0f}, /* Anchor right start H */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4026, 0x0f}, /* Anchor right end H */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x4028, 0x00}, /* top zero line start */ + {0x4029, 0x02}, /* top zero line number */ + {0x402a, 0x04}, /* top black line start */ + {0x402b, 0x04}, /* top black line number */ + {0x402c, 0x00}, /* bottom zero line start */ + {0x402d, 0x02}, /* bottom zoro line number */ + {0x402e, 0x04}, /* bottom black line start */ + {0x402f, 0x04}, /* bottom black line number */ + {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */ + {0x4034, 0x3f}, + {0x403d, 0x04}, /* md_precision_en */ + {0x4300, 0xff}, /* clip max H */ + {0x4301, 0x00}, /* clip min H */ + {0x4302, 0x0f}, /* clip min L, clip max L */ + {0x4316, 0x00}, + {0x4500, 0x58}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, /* clk prepare min */ + {0x4837, 0x16}, /* global timing */ + {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */ + {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */ + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, /* temperature sensor */ + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, /* temperature sensor */ + {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */ + {0x5001, 0x01}, /* BLC on */ + {0x5002, 0x08}, /* WBMATCH sensor's gain, H scale/WBMATCH/OTP_DPC off */ + {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */ + {0x501e, 0x93}, /* enable digital gain */ + {0x5046, 0x12}, + {0x5780, 0x3e}, /* DPC */ + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x00}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, /* DPC */ + {0x5871, 0x0d}, /* Lenc */ + {0x5870, 0x18}, + {0x586e, 0x10}, + {0x586f, 0x08}, + {0x58f7, 0x01}, + {0x58f8, 0x3d}, /* Lenc */ + {0x5901, 0x00}, /* H skip off, V skip off */ + {0x5b00, 0x02}, /* OTP DPC start address */ + {0x5b01, 0x10}, /* OTP DPC start address */ + {0x5b02, 0x03}, /* OTP DPC end address */ + {0x5b03, 0xcf}, /* OTP DPC end address */ + {0x5b05, 0x6c}, /* recover method = 2b11 */ + {0x5e00, 0x00}, /* use 0x3ff to test pattern off */ + {0x5e01, 0x41}, /* window cut enable */ + {0x382d, 0x7f}, + {0x4825, 0x3a}, /* lpx_p_min */ + {0x4826, 0x40}, /* hs_prepare_min */ + {0x4808, 0x25}, /* wake up delay in 1/1024 s */ + {0x3763, 0x18}, + {0x3768, 0xcc}, + {0x470b, 0x28}, + {0x4202, 0x00}, + {0x400d, 0x10}, /* BLC offset trigger L */ + {0x4040, 0x04}, /* BLC gain th2 */ + {0x403e, 0x04}, /* BLC gain th1 */ + {0x4041, 0xc6}, /* BLC */ + {0x3007, 0x80}, + {0x400a, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 60fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_1632x1224_regs_4lane[] = { + {0x0100, 0x00}, + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3f0a, 0x00}, + {0x4001, 0x10}, /* total 128 black column */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x402b, 0x04}, /* top black line number */ + {0x402f, 0x04}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x382d, 0x7f}, + {0x0100, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 30fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_3264x2448_regs_4lane[] = { + {0x0100, 0x00}, + {0x3501, 0x9a}, /* exposure M */ + {0x3502, 0x20}, /* exposure L */ + {0x3808, 0x0c}, /* x output size H */ + {0x3809, 0xc0}, /* x output size L */ + {0x380a, 0x09}, /* y output size H */ + {0x380b, 0x90}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x94}, /* HTS L */ + {0x380e, 0x09}, /* VTS H */ + {0x380f, 0xaa}, /* VTS L */ + {0x3814, 0x01}, /* x odd inc */ + {0x3821, 0x46}, /* mirror on, bin off */ + {0x382a, 0x01}, /* y odd inc */ + {0x3830, 0x06}, + {0x3836, 0x01}, + {0x3f0a, 0x00}, + {0x4001, 0x00}, /* total 256 black column */ + {0x4022, 0x0c}, /* Anchor left end H */ + {0x4023, 0x60}, /* Anchor left end L */ + {0x4025, 0x36}, /* Anchor right start L */ + {0x4027, 0x37}, /* Anchor right end L */ + {0x402b, 0x08}, /* top black line number */ + {0x402f, 0x08}, /* interpolation x/y disable, Anchor one disable */ + {0x4500, 0x58}, + {0x4600, 0x01}, + {0x4601, 0x97}, + {0x382d, 0xff}, + {REG_NULL, 0x00}, +}; + +static const struct ov8858_mode ov8858_modes[] = { + { + .width = 3264, + .height = 2448, + .exp_def = 2464, + .hts_def = 1940 * 2, + .vts_def = 2472, + .reg_modes = { + .mode_2lanes = ov8858_3264x2448_regs_2lane, + .mode_4lanes = ov8858_3264x2448_regs_4lane, + }, + }, + { + .width = 1632, + .height = 1224, + .exp_def = 1232, + .hts_def = 1928 * 2, + .vts_def = 1244, + .reg_modes = { + .mode_2lanes = ov8858_1632x1224_regs_2lane, + .mode_4lanes = ov8858_1632x1224_regs_4lane, + }, + }, +}; + +static const s64 link_freq_menu_items[] = { + OV8858_LINK_FREQ +}; + +static const char * const ov8858_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +/* ---------------------------------------------------------------------------- + * HW access + */ + +static int ov8858_write(struct ov8858 *ov8858, u32 reg, u32 val, int *err) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3; + u16 addr = reg & OV8858_REG_ADDR_MASK; + u8 buf[6]; + int ret; + + if (err && *err) + return *err; + + put_unaligned_be16(addr, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) { + ret = ret < 0 ? ret : -EIO; + if (err) + *err = ret; + + dev_err(&client->dev, + "Failed to write reg %u: %d\n", addr, ret); + return ret; + } + + return 0; +} + +static int ov8858_write_array(struct ov8858 *ov8858, const struct regval *regs) +{ + unsigned int i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; ++i) { + ov8858_write(ov8858, OV8858_REG_8BIT(regs[i].addr), + regs[i].val, &ret); + } + + return ret; +} + +static int ov8858_read(struct ov8858 *ov8858, u32 reg, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + __be16 reg_addr_be = cpu_to_be16(reg & OV8858_REG_ADDR_MASK); + unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3; + struct i2c_msg msgs[2]; + __be32 data_be = 0; + u8 *data_be_p; + int ret; + + data_be_p = (u8 *)&data_be; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + ret = ret < 0 ? ret : -EIO; + dev_err(&client->dev, + "Failed to read reg %u: %d\n", reg, ret); + return ret; + } + + *val = be32_to_cpu(data_be); + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Streaming + */ + +static int ov8858_start_stream(struct ov8858 *ov8858, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + const struct ov8858_mode *mode; + const struct regval *reg_list; + int ret; + + ret = ov8858_write_array(ov8858, ov8858->global_regs); + if (ret) + return ret; + + format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes), + width, height, format->width, + format->height); + + reg_list = ov8858->num_lanes == 4 + ? mode->reg_modes.mode_4lanes + : mode->reg_modes.mode_2lanes; + + ret = ov8858_write_array(ov8858, reg_list); + if (ret) + return ret; + + /* 200 usec max to let PLL stabilize. */ + fsleep(200); + + ret = __v4l2_ctrl_handler_setup(&ov8858->ctrl_handler); + if (ret) + return ret; + + ret = ov8858_write(ov8858, OV8858_REG_SC_CTRL0100, + OV8858_MODE_STREAMING, NULL); + if (ret) + return ret; + + /* t5 (fixed) = 10msec before entering streaming state */ + fsleep(10000); + + return 0; +} + +static int ov8858_stop_stream(struct ov8858 *ov8858) +{ + return ov8858_write(ov8858, OV8858_REG_SC_CTRL0100, + OV8858_MODE_SW_STANDBY, NULL); +} + +static int ov8858_s_stream(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (on) { + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + goto unlock_and_return; + + ret = ov8858_start_stream(ov8858, state); + if (ret) { + dev_err(&client->dev, "Failed to start streaming\n"); + pm_runtime_put_sync(&client->dev); + goto unlock_and_return; + } + } else { + ov8858_stop_stream(ov8858); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + +unlock_and_return: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static const struct v4l2_subdev_video_ops ov8858_video_ops = { + .s_stream = ov8858_s_stream, +}; + +/* ---------------------------------------------------------------------------- + * Pad ops + */ + +static int ov8858_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ov8858 *ov8858 = sd_to_ov8858(sd); + const struct ov8858_mode *mode; + s64 h_blank, vblank_def; + + mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes), + width, height, fmt->format.width, + fmt->format.height); + + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + + /* Store the format in the current subdev state. */ + *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + /* Adjust control limits when a new mode is applied. */ + h_blank = mode->hts_def - mode->width; + __v4l2_ctrl_modify_range(ov8858->hblank, h_blank, h_blank, 1, + h_blank); + + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov8858->vblank, vblank_def, + OV8858_VTS_MAX - mode->height, 1, + vblank_def); + + return 0; +} + +static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(ov8858_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) + return -EINVAL; + + fse->min_width = ov8858_modes[fse->index].width; + fse->max_width = ov8858_modes[fse->index].width; + fse->max_height = ov8858_modes[fse->index].height; + fse->min_height = ov8858_modes[fse->index].height; + + return 0; +} + +static int ov8858_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov8858_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + const struct ov8858_mode *def_mode = &ov8858_modes[0]; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .width = def_mode->width, + .height = def_mode->height, + }, + }; + + ov8858_set_fmt(sd, sd_state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { + .init_cfg = ov8858_init_cfg, + .enum_mbus_code = ov8858_enum_mbus_code, + .enum_frame_size = ov8858_enum_frame_sizes, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov8858_set_fmt, +}; + +static const struct v4l2_subdev_core_ops ov8858_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops ov8858_subdev_ops = { + .core = &ov8858_core_ops, + .video = &ov8858_video_ops, + .pad = &ov8858_pad_ops, +}; + +/* ---------------------------------------------------------------------------- + * Controls handling + */ + +static int ov8858_enable_test_pattern(struct ov8858 *ov8858, u32 pattern) +{ + u32 val; + + if (pattern) + val = (pattern - 1) | OV8858_TEST_PATTERN_ENABLE; + else + val = OV8858_TEST_PATTERN_DISABLE; + + return ov8858_write(ov8858, OV8858_REG_TEST_PATTERN, val, NULL); +} + +static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov8858 *ov8858 = container_of(ctrl->handler, + struct ov8858, ctrl_handler); + + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + u16 digi_gain; + s64 max_exp; + int ret; + + /* + * The control handler and the subdev state use the same mutex and the + * mutex is guaranteed to be locked: + * - by the core when s_ctrl is called int the VIDIOC_S_CTRL call path + * - by the driver when s_ctrl is called in the s_stream(1) call path + */ + state = v4l2_subdev_get_locked_active_state(&ov8858->subdev); + format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max_exp = format->height + ctrl->val - OV8858_EXPOSURE_MARGIN; + __v4l2_ctrl_modify_range(ov8858->exposure, + ov8858->exposure->minimum, max_exp, + ov8858->exposure->step, + ov8858->exposure->default_value); + break; + } + + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of exposure are fractional part */ + ret = ov8858_write(ov8858, OV8858_REG_LONG_EXPO, + ctrl->val << 4, NULL); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov8858_write(ov8858, OV8858_REG_LONG_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_DIGITAL_GAIN: + /* + * Digital gain is assembled as: + * 0x350a[7:0] = dgain[13:6] + * 0x350b[5:0] = dgain[5:0] + * Reassemble the control value to write it in one go. + */ + digi_gain = (ctrl->val & OV8858_LONG_DIGIGAIN_L_MASK) + | ((ctrl->val & OV8858_LONG_DIGIGAIN_H_MASK) << + OV8858_LONG_DIGIGAIN_H_SHIFT); + ret = ov8858_write(ov8858, OV8858_REG_LONG_DIGIGAIN, + digi_gain, NULL); + break; + case V4L2_CID_VBLANK: + ret = ov8858_write(ov8858, OV8858_REG_VTS, + ctrl->val + format->height, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov8858_enable_test_pattern(ov8858, ctrl->val); + break; + default: + ret = -EINVAL; + dev_warn(&client->dev, "%s Unhandled id: 0x%x\n", + __func__, ctrl->id); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov8858_ctrl_ops = { + .s_ctrl = ov8858_set_ctrl, +}; + +/* ---------------------------------------------------------------------------- + * Power Management + */ + +static int ov8858_power_on(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct device *dev = &client->dev; + unsigned long delay_us; + int ret; + + if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ret = clk_prepare_enable(ov8858->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + /* + * The chip manual only suggests 8192 cycles prior to first SCCB + * transaction, but a double sleep between the release of gpios + * helps with sporadic failures observed at probe time. + */ + delay_us = DIV_ROUND_UP(8192, OV8858_XVCLK_FREQ / 1000 / 1000); + + gpiod_set_value_cansleep(ov8858->reset_gpio, 0); + fsleep(delay_us); + gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0); + fsleep(delay_us); + + return 0; + +disable_clk: + clk_disable_unprepare(ov8858->xvclk); + + return ret; +} + +static void ov8858_power_off(struct ov8858 *ov8858) +{ + gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1); + clk_disable_unprepare(ov8858->xvclk); + gpiod_set_value_cansleep(ov8858->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); +} + +static int ov8858_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + return ov8858_power_on(ov8858); +} + +static int ov8858_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + ov8858_power_off(ov8858); + + return 0; +} + +static const struct dev_pm_ops ov8858_pm_ops = { + SET_RUNTIME_PM_OPS(ov8858_runtime_suspend, + ov8858_runtime_resume, NULL) +}; + +/* ---------------------------------------------------------------------------- + * Probe and initialization + */ + +static int ov8858_init_ctrls(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct v4l2_ctrl_handler *handler = &ov8858->ctrl_handler; + const struct ov8858_mode *mode = &ov8858_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, vblank_def; + unsigned int pixel_rate; + struct v4l2_ctrl *ctrl; + u32 h_blank; + int ret; + + ret = v4l2_ctrl_handler_init(handler, 10); + if (ret) + return ret; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* pixel rate = link frequency * 2 * lanes / bpp */ + pixel_rate = OV8858_LINK_FREQ * 2 * ov8858->num_lanes / 10; + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts_def - mode->width; + ov8858->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov8858->hblank) + ov8858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_def = mode->vts_def - mode->height; + ov8858->vblank = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV8858_VTS_MAX - mode->height, + 1, vblank_def); + + exposure_max = mode->vts_def - OV8858_EXPOSURE_MARGIN; + ov8858->exposure = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, + V4L2_CID_EXPOSURE, + OV8858_EXPOSURE_MIN, + exposure_max, OV8858_EXPOSURE_STEP, + mode->exp_def); + + v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV8858_LONG_GAIN_MIN, OV8858_LONG_GAIN_MAX, + OV8858_LONG_GAIN_STEP, OV8858_LONG_GAIN_DEFAULT); + + v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV8858_LONG_DIGIGAIN_MIN, OV8858_LONG_DIGIGAIN_MAX, + OV8858_LONG_DIGIGAIN_STEP, + OV8858_LONG_DIGIGAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(handler, &ov8858_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov8858_test_pattern_menu) - 1, + 0, 0, ov8858_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + goto err_free_handler; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto err_free_handler; + + ret = v4l2_ctrl_new_fwnode_properties(handler, &ov8858_ctrl_ops, + &props); + if (ret) + goto err_free_handler; + + ov8858->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + dev_err(&client->dev, "Failed to init controls: %d\n", ret); + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov8858_check_sensor_id(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + u32 id = 0; + int ret; + + ret = ov8858_read(ov8858, OV8858_REG_CHIP_ID, &id); + if (ret) + return ret; + + if (id != OV8858_CHIP_ID) { + dev_err(&client->dev, "Unexpected sensor id 0x%x\n", id); + return -ENODEV; + } + + ret = ov8858_read(ov8858, OV8858_REG_SUB_ID, &id); + if (ret) + return ret; + + dev_info(&client->dev, "Detected OV8858 sensor, revision 0x%x\n", id); + + if (id == OV8858_R2A) { + /* R2A supports 2 and 4 lanes modes. */ + ov8858->global_regs = ov8858->num_lanes == 4 + ? ov8858_global_regs_r2a_4lane + : ov8858_global_regs_r2a_2lane; + } else if (ov8858->num_lanes == 2) { + /* + * R1A only supports 2 lanes mode and it's only partially + * supported. + */ + ov8858->global_regs = ov8858_global_regs_r1a; + dev_warn(&client->dev, "R1A may not work well!\n"); + } else { + dev_err(&client->dev, + "Unsupported number of data lanes for R1A revision.\n"); + return -EINVAL; + } + + return 0; +} + +static int ov8858_configure_regulators(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov8858_supply_names); i++) + ov8858->supplies[i].supply = ov8858_supply_names[i]; + + return devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); +} + +static int ov8858_parse_of(struct ov8858 *ov8858) +{ + struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct device *dev = &client->dev; + struct fwnode_handle *endpoint; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { + dev_err(dev, "Failed to get endpoint\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(endpoint, &vep); + if (ret) { + dev_err(dev, "Failed to parse endpoint: %d\n", ret); + fwnode_handle_put(endpoint); + return ret; + } + + ov8858->num_lanes = vep.bus.mipi_csi2.num_data_lanes; + switch (ov8858->num_lanes) { + case 4: + case 2: + break; + default: + dev_err(dev, "Unsupported number of data lanes %u\n", + ov8858->num_lanes); + fwnode_handle_put(endpoint); + return -EINVAL; + } + + ov8858->subdev.fwnode = endpoint; + + return 0; +} + +static int ov8858_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct v4l2_subdev *sd; + struct ov8858 *ov8858; + int ret; + + ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL); + if (!ov8858) + return -ENOMEM; + + ov8858->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov8858->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov8858->xvclk), + "Failed to get xvclk\n"); + + ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov8858->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio), + "Failed to get reset gpio\n"); + + ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov8858->pwdn_gpio)) + return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio), + "Failed to get powerdown gpio\n"); + + v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops); + + ret = ov8858_configure_regulators(ov8858); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = ov8858_parse_of(ov8858); + if (ret) + return ret; + + ret = ov8858_init_ctrls(ov8858); + if (ret) + goto err_put_fwnode; + + sd = &ov8858->subdev; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + ov8858->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad); + if (ret < 0) + goto err_free_handler; + + sd->state_lock = ov8858->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) { + dev_err(&client->dev, "Subdev initialization error %d\n", ret); + goto err_clean_entity; + } + + ret = ov8858_power_on(ov8858); + if (ret) + goto err_clean_entity; + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + + ret = ov8858_check_sensor_id(ov8858); + if (ret) + goto err_power_off; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = v4l2_async_register_subdev_sensor(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_power_off; + } + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +err_power_off: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + ov8858_power_off(ov8858); +err_clean_entity: + media_entity_cleanup(&sd->entity); +err_free_handler: + v4l2_ctrl_handler_free(&ov8858->ctrl_handler); +err_put_fwnode: + fwnode_handle_put(ov8858->subdev.fwnode); + + return ret; +} + +static void ov8858_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&ov8858->ctrl_handler); + fwnode_handle_put(ov8858->subdev.fwnode); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov8858_power_off(ov8858); + pm_runtime_set_suspended(&client->dev); +} + +static const struct of_device_id ov8858_of_match[] = { + { .compatible = "ovti,ov8858" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov8858_of_match); + +static struct i2c_driver ov8858_i2c_driver = { + .driver = { + .name = "ov8858", + .pm = &ov8858_pm_ops, + .of_match_table = ov8858_of_match, + }, + .probe_new = &ov8858_probe, + .remove = &ov8858_remove, +}; + +module_i2c_driver(ov8858_i2c_driver); + +MODULE_DESCRIPTION("OmniVision OV8858 sensor driver"); +MODULE_LICENSE("GPL"); From e13064a32db56a7dad5a3539b7bd2482284f103a Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Sun, 15 Jan 2023 18:30:10 +0100 Subject: [PATCH 029/216] media: ov5640: Update last busy timestamp to reset autosuspend timer Otherwise autosuspend delay doesn't work and power is cut off immediately as device is freed. Signed-off-by: Andrey Skvortsov Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 2c37ed7b75d3..34687ab23d77 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3327,6 +3327,7 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return 0; @@ -3402,6 +3403,7 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return ret; @@ -3721,8 +3723,10 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) out: mutex_unlock(&sensor->lock); - if (!enable || ret) + if (!enable || ret) { + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); + } return ret; } @@ -3927,6 +3931,7 @@ static int ov5640_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; From 51c2bf13a42d82d519660dbfd6ea8f3bf0d962b8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jan 2023 15:52:19 +0100 Subject: [PATCH 030/216] media: i2c: st-vgxy61: Use asm intead of asm-generic There is no point to specify asm-generic for the unaligned.h. Drop the 'generic' suffix and move the inclusion to be after the non-media linux/* ones. Signed-off-by: Andy Shevchenko Reviewed-by: Benjamin Mugnier Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/st-vgxy61.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 826baf4e064d..5dcabee6677d 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -5,7 +5,6 @@ * Copyright (C) 2022 STMicroelectronics SA */ -#include #include #include #include @@ -15,6 +14,9 @@ #include #include #include + +#include + #include #include #include From decea0a98b7ac04536c7d659f74783e8d67a06c0 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Tue, 3 Jan 2023 13:27:35 +0100 Subject: [PATCH 031/216] media: ov5640: Fix soft reset sequence and timings Move the register-based reset out of the init_setting[] and into the powerup_sequence function. The sensor is power cycled and reset using the gpio pins so the soft reset is not always necessary. This also ensures that soft reset honors the timing sequence from the datasheet [1]. [1] https://cdn.sparkfun.com/datasheets/Sensors/LightImaging/OV5640_datasheet.pdf Fixes: 19a81c1426c1 ("[media] add Omnivision OV5640 sensor driver") Reported-by: Nishanth Menon Suggested-by: Jacopo Mondi Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 34687ab23d77..d82f250355ed 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -50,6 +50,7 @@ #define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 +#define OV5640_REG_SYS_CTRL0_SW_RST 0x82 #define OV5640_REG_CHIP_ID 0x300a #define OV5640_REG_IO_MIPI_CTRL00 0x300e #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 @@ -543,7 +544,7 @@ static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = { }; static const struct reg_value ov5640_init_setting[] = { - {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, + {0x3103, 0x11, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, @@ -2440,19 +2441,32 @@ static void ov5640_reset(struct ov5640_dev *sensor) if (!sensor->reset_gpio) return; - gpiod_set_value_cansleep(sensor->reset_gpio, 0); + if (sensor->pwdn_gpio) { + gpiod_set_value_cansleep(sensor->reset_gpio, 0); - /* camera power cycle */ - ov5640_power(sensor, false); - usleep_range(5000, 10000); - ov5640_power(sensor, true); - usleep_range(5000, 10000); + /* camera power cycle */ + ov5640_power(sensor, false); + usleep_range(5000, 10000); + ov5640_power(sensor, true); + usleep_range(5000, 10000); - gpiod_set_value_cansleep(sensor->reset_gpio, 1); - usleep_range(1000, 2000); + gpiod_set_value_cansleep(sensor->reset_gpio, 1); + usleep_range(1000, 2000); - gpiod_set_value_cansleep(sensor->reset_gpio, 0); + gpiod_set_value_cansleep(sensor->reset_gpio, 0); + } else { + /* software reset */ + ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, + OV5640_REG_SYS_CTRL0_SW_RST); + } usleep_range(20000, 25000); + + /* + * software standby: allows registers programming; + * exit at restore_mode() for CSI, s_stream(1) for DVP + */ + ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, + OV5640_REG_SYS_CTRL0_SW_PWDN); } static int ov5640_set_power_on(struct ov5640_dev *sensor) From d7ff69139908842adf824be4f50c7e9ac5886c04 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Tue, 3 Jan 2023 13:27:36 +0100 Subject: [PATCH 032/216] media: ov5640: Handle delays when no reset_gpio set Some module manufacturers [1][2] don't expose the RESETB and PWDN pins of the sensor directly through the 15-pin FFC connector. Instead wiring ~PWDN gpio to the sensor pins with appropriate delays. In such cases, reset_gpio will not be available to the driver, but it will still be toggled when the sensor is powered on, and thus we should still honor the wait time of >= 5ms + 1ms + 20ms (see figure 2-3 in [3]) before attempting any i/o operations over SCCB. Also, rename the function to ov5640_powerup_sequence to better match the datasheet (section 2.7). [1] https://digilent.com/reference/_media/reference/add-ons/pcam-5c/pcam_5c_sch.pdf [2] https://www.alinx.com/public/upload/file/AN5641_User_Manual.pdf [3] https://cdn.sparkfun.com/datasheets/Sensors/LightImaging/OV5640_datasheet.pdf Fixes: 19a81c1426c1 ("[media] add Omnivision OV5640 sensor driver") Reported-by: Nishanth Menon Signed-off-by: Jai Luthra Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index d82f250355ed..e1b8365fef58 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2436,11 +2436,22 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable) gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); } -static void ov5640_reset(struct ov5640_dev *sensor) +/* + * From section 2.7 power up sequence: + * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down + * t3 >= 1ms Delay from PWDN pull down to RESETB pull up + * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable + * + * Some modules don't expose RESETB/PWDN pins directly, instead providing a + * "PWUP" GPIO which is wired through appropriate delays and inverters to the + * pins. + * + * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we + * should still toggle the pwdn_gpio below with the appropriate delays, while + * the calls to reset_gpio will be ignored. + */ +static void ov5640_powerup_sequence(struct ov5640_dev *sensor) { - if (!sensor->reset_gpio) - return; - if (sensor->pwdn_gpio) { gpiod_set_value_cansleep(sensor->reset_gpio, 0); @@ -2489,8 +2500,7 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor) goto xclk_off; } - ov5640_reset(sensor); - ov5640_power(sensor, true); + ov5640_powerup_sequence(sensor); ret = ov5640_init_slave_id(sensor); if (ret) From d10ac51e8a047e613bee8309739d122e48e00bcb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Dec 2022 10:33:37 +0100 Subject: [PATCH 033/216] media: mc: entity: Add pad iterator for media_pipeline Add a media_pipeline_for_each_pad() macro to iterate over pads in a pipeline. This should be used by driver as a replacement of the media_graph_walk API, as iterating over the media_pipeline uses the cached list of pads and is thus more efficient. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-entity.c | 18 ++++++++++++++++++ include/media/media-entity.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 6ec2092d7f80..83797d6b1753 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -945,6 +945,24 @@ __must_check int media_pipeline_alloc_start(struct media_pad *pad) } EXPORT_SYMBOL_GPL(media_pipeline_alloc_start); +struct media_pad * +__media_pipeline_pad_iter_next(struct media_pipeline *pipe, + struct media_pipeline_pad_iter *iter, + struct media_pad *pad) +{ + if (!pad) + iter->cursor = pipe->pads.next; + + if (iter->cursor == &pipe->pads) + return NULL; + + pad = list_entry(iter->cursor, struct media_pipeline_pad, list)->pad; + iter->cursor = iter->cursor->next; + + return pad; +} +EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next); + /* ----------------------------------------------------------------------------- * Links management */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 47863e8fde7b..11351579a4d2 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -130,6 +130,15 @@ struct media_pipeline_pad { struct media_pad *pad; }; +/** + * struct media_pipeline_pad_iter - Iterator for media_pipeline_for_each_pad + * + * @cursor: The current element + */ +struct media_pipeline_pad_iter { + struct list_head *cursor; +}; + /** * struct media_link - A link object part of a media graph. * @@ -1165,6 +1174,26 @@ void media_pipeline_stop(struct media_pad *pad); */ void __media_pipeline_stop(struct media_pad *pad); +struct media_pad * +__media_pipeline_pad_iter_next(struct media_pipeline *pipe, + struct media_pipeline_pad_iter *iter, + struct media_pad *pad); + +/** + * media_pipeline_for_each_pad - Iterate on all pads in a media pipeline + * @pipe: The pipeline + * @iter: The iterator (struct media_pipeline_pad_iter) + * @pad: The iterator pad + * + * Iterate on all pads in a media pipeline. This is only valid after the + * pipeline has been built with media_pipeline_start() and before it gets + * destroyed with media_pipeline_stop(). + */ +#define media_pipeline_for_each_pad(pipe, iter, pad) \ + for (pad = __media_pipeline_pad_iter_next((pipe), iter, NULL); \ + pad != NULL; \ + pad = __media_pipeline_pad_iter_next((pipe), iter, pad)) + /** * media_pipeline_alloc_start - Mark a pipeline as streaming * @pad: Starting pad From eac564de0915433716b83fad800d00675ccc6972 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Dec 2022 10:33:38 +0100 Subject: [PATCH 034/216] media: mc: entity: Add entity iterator for media_pipeline Add a media_pipeline_for_each_entity() macro to iterate over entities in a pipeline. This should be used by driver as a replacement of the media_graph_walk API, as iterating over the media_pipeline uses the cached list of pads and is thus more efficient. Deprecate the media_graph_walk API to indicate it shouldn't be used in new drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-entity.c | 37 +++++++++++++++++++ include/media/media-entity.h | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 83797d6b1753..0b7fb0cc641c 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -963,6 +963,43 @@ __media_pipeline_pad_iter_next(struct media_pipeline *pipe, } EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next); +int media_pipeline_entity_iter_init(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter) +{ + return media_entity_enum_init(&iter->ent_enum, pipe->mdev); +} +EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_init); + +void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter) +{ + media_entity_enum_cleanup(&iter->ent_enum); +} +EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_cleanup); + +struct media_entity * +__media_pipeline_entity_iter_next(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter, + struct media_entity *entity) +{ + if (!entity) + iter->cursor = pipe->pads.next; + + while (iter->cursor != &pipe->pads) { + struct media_pipeline_pad *ppad; + struct media_entity *entity; + + ppad = list_entry(iter->cursor, struct media_pipeline_pad, list); + entity = ppad->pad->entity; + iter->cursor = iter->cursor->next; + + if (!media_entity_enum_test_and_set(&iter->ent_enum, entity)) + return entity; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__media_pipeline_entity_iter_next); + /* ----------------------------------------------------------------------------- * Links management */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 11351579a4d2..741f9c629c6f 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -139,6 +139,17 @@ struct media_pipeline_pad_iter { struct list_head *cursor; }; +/** + * struct media_pipeline_entity_iter - Iterator for media_pipeline_for_each_entity + * + * @ent_enum: The entity enumeration tracker + * @cursor: The current element + */ +struct media_pipeline_entity_iter { + struct media_entity_enum ent_enum; + struct list_head *cursor; +}; + /** * struct media_link - A link object part of a media graph. * @@ -1077,6 +1088,8 @@ int media_entity_get_fwnode_pad(struct media_entity *entity, * @graph: Media graph structure that will be used to walk the graph * @mdev: Pointer to the &media_device that contains the object * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * The caller is required to hold the media_device graph_mutex during the graph * walk until the graph state is released. * @@ -1089,6 +1102,8 @@ __must_check int media_graph_walk_init( * media_graph_walk_cleanup - Release resources used by graph walk. * * @graph: Media graph structure that will be used to walk the graph + * + * This function is deprecated, use media_pipeline_for_each_pad() instead. */ void media_graph_walk_cleanup(struct media_graph *graph); @@ -1099,6 +1114,8 @@ void media_graph_walk_cleanup(struct media_graph *graph); * @graph: Media graph structure that will be used to walk the graph * @entity: Starting entity * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * Before using this function, media_graph_walk_init() must be * used to allocate resources used for walking the graph. This * function initializes the graph traversal structure to walk the @@ -1114,6 +1131,8 @@ void media_graph_walk_start(struct media_graph *graph, * media_graph_walk_next - Get the next entity in the graph * @graph: Media graph structure * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * Perform a depth-first traversal of the given media entities graph. * * The graph structure must have been previously initialized with a call to @@ -1194,6 +1213,56 @@ __media_pipeline_pad_iter_next(struct media_pipeline *pipe, pad != NULL; \ pad = __media_pipeline_pad_iter_next((pipe), iter, pad)) +/** + * media_pipeline_entity_iter_init - Initialize a pipeline entity iterator + * @pipe: The pipeline + * @iter: The iterator + * + * This function must be called to initialize the iterator before using it in a + * media_pipeline_for_each_entity() loop. The iterator must be destroyed by a + * call to media_pipeline_entity_iter_cleanup after the loop (including in code + * paths that break from the loop). + * + * The same iterator can be used in multiple consecutive loops without being + * destroyed and reinitialized. + * + * Return: 0 on success or a negative error code otherwise. + */ +int media_pipeline_entity_iter_init(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter); + +/** + * media_pipeline_entity_iter_cleanup - Destroy a pipeline entity iterator + * @iter: The iterator + * + * This function must be called to destroy iterators initialized with + * media_pipeline_entity_iter_init(). + */ +void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter); + +struct media_entity * +__media_pipeline_entity_iter_next(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter, + struct media_entity *entity); + +/** + * media_pipeline_for_each_entity - Iterate on all entities in a media pipeline + * @pipe: The pipeline + * @iter: The iterator (struct media_pipeline_entity_iter) + * @entity: The iterator entity + * + * Iterate on all entities in a media pipeline. This is only valid after the + * pipeline has been built with media_pipeline_start() and before it gets + * destroyed with media_pipeline_stop(). The iterator must be initialized with + * media_pipeline_entity_iter_init() before iteration, and destroyed with + * media_pipeline_entity_iter_cleanup() after (including in code paths that + * break from the loop). + */ +#define media_pipeline_for_each_entity(pipe, iter, entity) \ + for (entity = __media_pipeline_entity_iter_next((pipe), iter, NULL); \ + entity != NULL; \ + entity = __media_pipeline_entity_iter_next((pipe), iter, entity)) + /** * media_pipeline_alloc_start - Mark a pipeline as streaming * @pad: Starting pad From 3e8537b4c15172bfe1b285c3155ed5c37d523cd3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Dec 2022 10:33:39 +0100 Subject: [PATCH 035/216] media: ti: omap3isp: Use media_pipeline_for_each_entity() Replace usage of the deprecated media graph walk API with the new media_pipeline_for_each_entity() macro. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/omap3isp/ispvideo.c | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 3e5348c63773..ddc7d08d4f96 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -221,22 +221,16 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad) static int isp_video_get_graph_data(struct isp_video *video, struct isp_pipeline *pipe) { - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_entity_iter iter; + struct media_entity *entity; struct isp_video *far_end = NULL; int ret; - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); + ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter); + if (ret) return ret; - } - media_graph_walk_start(&graph, entity); - - while ((entity = media_graph_walk_next(&graph))) { + media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) { struct isp_video *__video; media_entity_enum_set(&pipe->ent_enum, entity); @@ -255,9 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video, far_end = __video; } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); + media_pipeline_entity_iter_cleanup(&iter); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { pipe->input = far_end; From 27e45f2e59c9db2c83ed67775e911c8a3c776db2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Dec 2022 10:33:40 +0100 Subject: [PATCH 036/216] media: ti: omap4iss: Use media_pipeline_for_each_entity() Replace usage of the deprecated media graph walk API with the new media_pipeline_for_each_entity() and media_pipeline_for_each_pad() macros. Even though the entity iterator may seem a better match when build the entity bitmap in iss_video_stream(), it would not be more efficient as it would still iterate internally over all pads. As the entity iterator requires explicit iterator initialization and cleanup calls, the code would be more complex. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss_video.c | 66 +++++++++------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 0ad70faa9ba0..05548eab7daa 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -201,39 +201,34 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad) /* Return a pointer to the ISS video instance at the far end of the pipeline. */ static struct iss_video * -iss_video_far_end(struct iss_video *video) +iss_video_far_end(struct iss_video *video, struct iss_pipeline *pipe) { - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_entity_iter iter; + struct media_entity *entity; struct iss_video *far_end = NULL; + int ret; - mutex_lock(&mdev->graph_mutex); + ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter); + if (ret) + return ERR_PTR(-ENOMEM); - if (media_graph_walk_init(&graph, mdev)) { - mutex_unlock(&mdev->graph_mutex); - return NULL; - } + media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) { + struct iss_video *other; - media_graph_walk_start(&graph, entity); - - while ((entity = media_graph_walk_next(&graph))) { if (entity == &video->video.entity) continue; if (!is_media_entity_v4l2_video_device(entity)) continue; - far_end = to_iss_video(media_entity_to_video_device(entity)); - if (far_end->type != video->type) + other = to_iss_video(media_entity_to_video_device(entity)); + if (other->type != video->type) { + far_end = other; break; - - far_end = NULL; + } } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); + media_pipeline_entity_iter_cleanup(&iter); return far_end; } @@ -850,12 +845,12 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { struct iss_video_fh *vfh = to_iss_video_fh(fh); struct iss_video *video = video_drvdata(file); - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_device *mdev = video->video.entity.graph_obj.mdev; + struct media_pipeline_pad_iter iter; enum iss_pipeline_state state; struct iss_pipeline *pipe; struct iss_video *far_end; + struct media_pad *pad; unsigned long flags; int ret; @@ -873,13 +868,9 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->external_rate = 0; pipe->external_bpp = 0; - ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev); + ret = media_entity_enum_init(&pipe->ent_enum, mdev); if (ret) - goto err_graph_walk_init; - - ret = media_graph_walk_init(&graph, entity->graph_obj.mdev); - if (ret) - goto err_graph_walk_init; + goto err_entity_enum_init; if (video->iss->pdata->set_constraints) video->iss->pdata->set_constraints(video->iss, true); @@ -888,11 +879,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (ret < 0) goto err_media_pipeline_start; - mutex_lock(&mdev->graph_mutex); - media_graph_walk_start(&graph, entity); - while ((entity = media_graph_walk_next(&graph))) - media_entity_enum_set(&pipe->ent_enum, entity); - mutex_unlock(&mdev->graph_mutex); + media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) + media_entity_enum_set(&pipe->ent_enum, pad->entity); /* * Verify that the currently configured format matches the output of @@ -909,7 +897,11 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) * Find the ISS video node connected at the far end of the pipeline and * update the pipeline. */ - far_end = iss_video_far_end(video); + far_end = iss_video_far_end(video, pipe); + if (IS_ERR(far_end)) { + ret = PTR_ERR(far_end); + goto err_iss_video_check_format; + } if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT; @@ -966,8 +958,6 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) spin_unlock_irqrestore(&video->qlock, flags); } - media_graph_walk_cleanup(&graph); - mutex_unlock(&video->stream_lock); return 0; @@ -981,9 +971,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) video->iss->pdata->set_constraints(video->iss, false); video->queue = NULL; - media_graph_walk_cleanup(&graph); - -err_graph_walk_init: +err_entity_enum_init: media_entity_enum_cleanup(&pipe->ent_enum); mutex_unlock(&video->stream_lock); From 36c9b753a186a4ea5c18fee0d903c3891c401049 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Dec 2022 10:33:41 +0100 Subject: [PATCH 037/216] media: xilinx: dma: Use media_pipeline_for_each_pad() Replace usage of the deprecated media graph walk API with the new media_pipeline_for_each_pad() macro. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/xilinx/xilinx-dma.c | 28 +++++----------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 0a7fd8642a65..fee02c8c85fd 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -173,31 +173,19 @@ static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on) static int xvip_pipeline_validate(struct xvip_pipeline *pipe, struct xvip_dma *start) { - struct media_graph graph; - struct media_entity *entity = &start->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_pad_iter iter; unsigned int num_inputs = 0; unsigned int num_outputs = 0; - int ret; + struct media_pad *pad; - mutex_lock(&mdev->graph_mutex); - - /* Walk the graph to locate the video nodes. */ - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return ret; - } - - media_graph_walk_start(&graph, entity); - - while ((entity = media_graph_walk_next(&graph))) { + /* Locate the video nodes in the pipeline. */ + media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) { struct xvip_dma *dma; - if (entity->function != MEDIA_ENT_F_IO_V4L) + if (pad->entity->function != MEDIA_ENT_F_IO_V4L) continue; - dma = to_xvip_dma(media_entity_to_video_device(entity)); + dma = to_xvip_dma(media_entity_to_video_device(pad->entity)); if (dma->pad.flags & MEDIA_PAD_FL_SINK) { pipe->output = dma; @@ -207,10 +195,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe, } } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); - /* We need exactly one output and zero or one input. */ if (num_outputs != 1 || num_inputs > 1) return -EPIPE; From ea5930a4dcb0d33db9fc018a753f383394409ed8 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 13 Dec 2022 15:07:26 +0100 Subject: [PATCH 038/216] media: i2c: ov9282: remove unused and unset i2c_client member This is not need anyway as the i2c_client is stored in v4l2_subdev. Signed-off-by: Alexander Stein Acked-by: Daniele Alessandrelli Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9282.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 37a55d53af56..8216644494bb 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -148,7 +148,6 @@ struct ov9282_mode { /** * struct ov9282 - ov9282 sensor device structure * @dev: Pointer to generic device - * @client: Pointer to i2c client * @sd: V4L2 sub-device * @pad: Media pad. Only one pad supported * @reset_gpio: Sensor reset gpio @@ -170,7 +169,6 @@ struct ov9282_mode { */ struct ov9282 { struct device *dev; - struct i2c_client *client; struct v4l2_subdev sd; struct media_pad pad; struct gpio_desc *reset_gpio; From e1610209a8879e7bc6a4910f93b071cf6d91cbef Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 13 Dec 2022 15:07:27 +0100 Subject: [PATCH 039/216] media: i2c: ov9282: Switch to use dev_err_probe helper In the probe path, dev_err() can be replaced with dev_err_probe() which will check if error code is -EPROBE_DEFER and prints the error name. It also sets the defer probe reason which can be checked later through debugfs. It's more simple in error path. Signed-off-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9282.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 8216644494bb..7f46cac38aab 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -1142,10 +1142,9 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282) } ret = ov9282_configure_regulators(ov9282); - if (ret) { - dev_err(ov9282->dev, "Failed to get power regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(ov9282->dev, ret, + "Failed to get power regulators\n"); rate = clk_get_rate(ov9282->inclk); if (rate != OV9282_INCLK_RATE) { From a967a3a788028f541e4db54beabcebc3648997db Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 12 Dec 2022 14:25:04 +0100 Subject: [PATCH 040/216] media: mc: Get media_device directly from pad Various functions access the media_device from a pad by going through the entity the pad belongs to. Remove the level of indirection and get the media_device from the pad directly. Fixes: 9e3576a1ae2b ("media: mc: convert pipeline funcs to take media_pad") Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-entity.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 0b7fb0cc641c..7c62d26d9797 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -716,7 +716,7 @@ static int media_pipeline_populate(struct media_pipeline *pipe, __must_check int __media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; struct media_pipeline_pad *err_ppad; struct media_pipeline_pad *ppad; int ret; @@ -864,7 +864,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_start); __must_check int media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; int ret; mutex_lock(&mdev->graph_mutex); @@ -901,7 +901,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_stop); void media_pipeline_stop(struct media_pad *pad) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; mutex_lock(&mdev->graph_mutex); __media_pipeline_stop(pad); @@ -911,7 +911,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_stop); __must_check int media_pipeline_alloc_start(struct media_pad *pad) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; struct media_pipeline *new_pipe = NULL; struct media_pipeline *pipe; int ret; From b516354542b71632438d33920f6ce7478ecab0ce Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 12 Dec 2022 14:25:05 +0100 Subject: [PATCH 041/216] media: mc: entity: Fix minor issues in comments and documentation Commit ae219872834a ("media: mc: entity: Rewrite media_pipeline_start()") incorrectly referred to entity instead of pad in a comment, and forgot to update a second comment accordingly when moving the pipe from entity to pad. Furthermore, it didn't properly reflow the documentation text it updated. Fix those small issues. Fixes: ae219872834a ("media: mc: entity: Rewrite media_pipeline_start()") Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/mc-core.rst | 10 ++++------ drivers/media/mc/mc-entity.c | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst index 400b8ca29367..2456950ce8ff 100644 --- a/Documentation/driver-api/media/mc-core.rst +++ b/Documentation/driver-api/media/mc-core.rst @@ -232,12 +232,10 @@ prevent link states from being modified during streaming by calling The function will mark all the pads which are part of the pipeline as streaming. -The struct media_pipeline instance pointed to by -the pipe argument will be stored in every pad in the pipeline. -Drivers should embed the struct media_pipeline -in higher-level pipeline structures and can then access the -pipeline through the struct media_pad -pipe field. +The struct media_pipeline instance pointed to by the pipe argument will be +stored in every pad in the pipeline. Drivers should embed the struct +media_pipeline in higher-level pipeline structures and can then access the +pipeline through the struct media_pad pipe field. Calls to :c:func:`media_pipeline_start()` can be nested. The pipeline pointer must be identical for all nested calls to the function. diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 7c62d26d9797..e7216a985ba6 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -724,8 +724,8 @@ __must_check int __media_pipeline_start(struct media_pad *pad, lockdep_assert_held(&mdev->graph_mutex); /* - * If the entity is already part of a pipeline, that pipeline must - * be the same as the pipe given to media_pipeline_start(). + * If the pad is already part of a pipeline, that pipeline must be the + * same as the pipe given to media_pipeline_start(). */ if (WARN_ON(pad->pipe && pad->pipe != pipe)) return -EINVAL; @@ -919,7 +919,7 @@ __must_check int media_pipeline_alloc_start(struct media_pad *pad) mutex_lock(&mdev->graph_mutex); /* - * Is the entity already part of a pipeline? If not, we need to allocate + * Is the pad already part of a pipeline? If not, we need to allocate * a pipe. */ pipe = media_pad_pipeline(pad); From 6d801f89ad7c485bbb14c0138d991beebd307aa6 Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Fri, 9 Dec 2022 15:37:39 +0100 Subject: [PATCH 042/216] media: dt-bindings: ak7375: Convert to DT schema Convert DT bindings document for AKM AK7375 VCM to DT schema format and add an example. Signed-off-by: Yassine Oudjana Reviewed-by: Krzysztof Kozlowski Tested-by: Umang Jain Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ak7375.txt | 8 ---- .../media/i2c/asahi-kasei,ak7375.yaml | 41 +++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 42 insertions(+), 9 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/ak7375.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ak7375.txt b/Documentation/devicetree/bindings/media/i2c/ak7375.txt deleted file mode 100644 index aa3e24b41241..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/ak7375.txt +++ /dev/null @@ -1,8 +0,0 @@ -Asahi Kasei Microdevices AK7375 voice coil lens driver - -AK7375 is a camera voice coil lens. - -Mandatory properties: - -- compatible: "asahi-kasei,ak7375" -- reg: I2C slave address diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml new file mode 100644 index 000000000000..22b1251b16ee --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/asahi-kasei,ak7375.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Asahi Kasei Microdevices AK7375 voice coil lens actuator + +maintainers: + - Tianshu Qiu + +description: + AK7375 is a voice coil motor (VCM) camera lens actuator that + is controlled over I2C. + +properties: + compatible: + const: asahi-kasei,ak7375 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ak7375: camera-lens@c { + compatible = "asahi-kasei,ak7375"; + reg = <0x0c>; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index d435a4dd5971..217e4e1179de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3224,7 +3224,7 @@ M: Tianshu Qiu L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/ak7375.txt +F: Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml F: drivers/media/i2c/ak7375.c ASAHI KASEI AK8974 DRIVER From 04a79f078329b14f260db15250e84c97022f42cd Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Fri, 9 Dec 2022 15:37:40 +0100 Subject: [PATCH 043/216] media: dt-bindings: ak7375: Add supplies Add supply properties to describe regulators needed to power the AK7375 VCM. Signed-off-by: Yassine Oudjana Acked-by: Krzysztof Kozlowski Tested-by: Umang Jain Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/asahi-kasei,ak7375.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml index 22b1251b16ee..22a810fc7222 100644 --- a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml +++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml @@ -20,9 +20,17 @@ properties: reg: maxItems: 1 + vdd-supply: + description: VDD supply + + vio-supply: + description: I/O pull-up supply + required: - compatible - reg + - vdd-supply + - vio-supply additionalProperties: false @@ -35,6 +43,9 @@ examples: ak7375: camera-lens@c { compatible = "asahi-kasei,ak7375"; reg = <0x0c>; + + vdd-supply = <&vreg_l23a_2p8>; + vio-supply = <&vreg_lvs1a_1p8>; }; }; From 90f7e76eac50c1ae54a445abc6a286837ade46cf Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Fri, 9 Dec 2022 15:37:41 +0100 Subject: [PATCH 044/216] media: i2c: ak7375: Add regulator management Make the driver get needed regulators on probe and enable/disable them on runtime PM callbacks. Signed-off-by: Yassine Oudjana Tested-by: Umang Jain Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ak7375.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c index 1af9f698eecf..e7cec45bc271 100644 --- a/drivers/media/i2c/ak7375.c +++ b/drivers/media/i2c/ak7375.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -23,17 +24,29 @@ */ #define AK7375_CTRL_STEPS 64 #define AK7375_CTRL_DELAY_US 1000 +/* + * The vcm may take up 10 ms (tDELAY) to power on and start taking + * I2C messages. Based on AK7371 datasheet. + */ +#define AK7375_POWER_DELAY_US 10000 #define AK7375_REG_POSITION 0x0 #define AK7375_REG_CONT 0x2 #define AK7375_MODE_ACTIVE 0x0 #define AK7375_MODE_STANDBY 0x40 +static const char * const ak7375_supply_names[] = { + "vdd", + "vio", +}; + /* ak7375 device structure */ struct ak7375_device { struct v4l2_ctrl_handler ctrls_vcm; struct v4l2_subdev sd; struct v4l2_ctrl *focus; + struct regulator_bulk_data supplies[ARRAY_SIZE(ak7375_supply_names)]; + /* active or standby mode */ bool active; }; @@ -133,12 +146,24 @@ static int ak7375_probe(struct i2c_client *client) { struct ak7375_device *ak7375_dev; int ret; + unsigned int i; ak7375_dev = devm_kzalloc(&client->dev, sizeof(*ak7375_dev), GFP_KERNEL); if (!ak7375_dev) return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++) + ak7375_dev->supplies[i].supply = ak7375_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) { + dev_err_probe(&client->dev, ret, "Failed to get regulators\n"); + return ret; + } + v4l2_i2c_subdev_init(&ak7375_dev->sd, client, &ak7375_ops); ak7375_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ak7375_dev->sd.internal_ops = &ak7375_int_ops; @@ -208,6 +233,11 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev) if (ret) dev_err(dev, "%s I2C failure: %d\n", __func__, ret); + ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) + return ret; + ak7375_dev->active = false; return 0; @@ -228,6 +258,14 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev) if (ak7375_dev->active) return 0; + ret = regulator_bulk_enable(ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) + return ret; + + /* Wait for vcm to become ready */ + usleep_range(AK7375_POWER_DELAY_US, AK7375_POWER_DELAY_US + 500); + ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT, AK7375_MODE_ACTIVE, 1); if (ret) { From 7485edb2b6ca5960205c0a49bedfd09bba30e521 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Thu, 8 Dec 2022 09:06:25 +0100 Subject: [PATCH 045/216] media: i2c: ov772x: Fix memleak in ov772x_probe() A memory leak was reported when testing ov772x with bpf mock device: AssertionError: unreferenced object 0xffff888109afa7a8 (size 8): comm "python3", pid 279, jiffies 4294805921 (age 20.681s) hex dump (first 8 bytes): 80 22 88 15 81 88 ff ff ."...... backtrace: [<000000009990b438>] __kmalloc_node+0x44/0x1b0 [<000000009e32f7d7>] kvmalloc_node+0x34/0x180 [<00000000faf48134>] v4l2_ctrl_handler_init_class+0x11d/0x180 [videodev] [<00000000da376937>] ov772x_probe+0x1c3/0x68c [ov772x] [<000000003f0d225e>] i2c_device_probe+0x28d/0x680 [<00000000e0b6db89>] really_probe+0x17c/0x3f0 [<000000001b19fcee>] __driver_probe_device+0xe3/0x170 [<0000000048370519>] driver_probe_device+0x49/0x120 [<000000005ead07a0>] __device_attach_driver+0xf7/0x150 [<0000000043f452b8>] bus_for_each_drv+0x114/0x180 [<00000000358e5596>] __device_attach+0x1e5/0x2d0 [<0000000043f83c5d>] bus_probe_device+0x126/0x140 [<00000000ee0f3046>] device_add+0x810/0x1130 [<00000000e0278184>] i2c_new_client_device+0x359/0x4f0 [<0000000070baf34f>] of_i2c_register_device+0xf1/0x110 [<00000000a9f2159d>] of_i2c_notify+0x100/0x160 unreferenced object 0xffff888119825c00 (size 256): comm "python3", pid 279, jiffies 4294805921 (age 20.681s) hex dump (first 32 bytes): 00 b4 a5 17 81 88 ff ff 00 5e 82 19 81 88 ff ff .........^...... 10 5c 82 19 81 88 ff ff 10 5c 82 19 81 88 ff ff .\.......\...... backtrace: [<000000009990b438>] __kmalloc_node+0x44/0x1b0 [<000000009e32f7d7>] kvmalloc_node+0x34/0x180 [<0000000073d88e0b>] v4l2_ctrl_new.cold+0x19b/0x86f [videodev] [<00000000b1f576fb>] v4l2_ctrl_new_std+0x16f/0x210 [videodev] [<00000000caf7ac99>] ov772x_probe+0x1fa/0x68c [ov772x] [<000000003f0d225e>] i2c_device_probe+0x28d/0x680 [<00000000e0b6db89>] really_probe+0x17c/0x3f0 [<000000001b19fcee>] __driver_probe_device+0xe3/0x170 [<0000000048370519>] driver_probe_device+0x49/0x120 [<000000005ead07a0>] __device_attach_driver+0xf7/0x150 [<0000000043f452b8>] bus_for_each_drv+0x114/0x180 [<00000000358e5596>] __device_attach+0x1e5/0x2d0 [<0000000043f83c5d>] bus_probe_device+0x126/0x140 [<00000000ee0f3046>] device_add+0x810/0x1130 [<00000000e0278184>] i2c_new_client_device+0x359/0x4f0 [<0000000070baf34f>] of_i2c_register_device+0xf1/0x110 The reason is that if priv->hdl.error is set, ov772x_probe() jumps to the error_mutex_destroy without doing v4l2_ctrl_handler_free(), and all resources allocated in v4l2_ctrl_handler_init() and v4l2_ctrl_new_std() are leaked. Fixes: 1112babde214 ("media: i2c: Copy ov772x soc_camera sensor driver") Signed-off-by: Yuan Can Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 4189e3fc3d53..a238e63425f8 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1462,7 +1462,7 @@ static int ov772x_probe(struct i2c_client *client) priv->subdev.ctrl_handler = &priv->hdl; if (priv->hdl.error) { ret = priv->hdl.error; - goto error_mutex_destroy; + goto error_ctrl_free; } priv->clk = clk_get(&client->dev, NULL); @@ -1515,7 +1515,6 @@ static int ov772x_probe(struct i2c_client *client) clk_put(priv->clk); error_ctrl_free: v4l2_ctrl_handler_free(&priv->hdl); -error_mutex_destroy: mutex_destroy(&priv->lock); return ret; From afa4805799c1d332980ad23339fdb07b5e0cf7e0 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Mon, 28 Nov 2022 09:02:01 +0100 Subject: [PATCH 046/216] media: ov5640: Fix analogue gain control Gain control is badly documented in publicly available (including leaked) documentation. There is an AGC pre-gain in register 0x3a13, expressed as a 6-bit value (plus an enable bit in bit 6). The driver hardcodes it to 0x43, which one application note states is equal to x1.047. The documentation also states that 0x40 is equel to x1.000. The pre-gain thus seems to be expressed as in 1/64 increments, and thus ranges from x1.00 to x1.984. What the pre-gain does is however unspecified. There is then an AGC gain limit, in registers 0x3a18 and 0x3a19, expressed as a 10-bit "real gain format" value. One application note sets it to 0x00f8 and states it is equal to x15.5, so it appears to be expressed in 1/16 increments, up to x63.9375. The manual gain is stored in registers 0x350a and 0x350b, also as a 10-bit "real gain format" value. It is documented in the application note as a Q6.4 values, up to x63.9375. One version of the datasheet indicates that the sensor supports a digital gain: The OV5640 supports 1/2/4 digital gain. Normally, the gain is controlled automatically by the automatic gain control (AGC) block. It isn't clear how that would be controlled manually. There appears to be no indication regarding whether the gain controlled through registers 0x350a and 0x350b is an analogue gain only or also includes digital gain. The words "real gain" don't necessarily mean "combined analogue and digital gains". Some OmniVision sensors (such as the OV8858) are documented as supoprting different formats for the gain values, selectable through a register bit, and they are called "real gain format" and "sensor gain format". For that sensor, we have (one of) the gain registers documented as 0x3503[2]=0, gain[7:0] is real gain format, where low 4 bits are fraction bits, for example, 0x10 is 1x gain, 0x28 is 2.5x gain If 0x3503[2]=1, gain[7:0] is sensor gain format, gain[7:4] is coarse gain, 00000: 1x, 00001: 2x, 00011: 4x, 00111: 8x, gain[7] is 1, gain[3:0] is fine gain. For example, 0x10 is 1x gain, 0x30 is 2x gain, 0x70 is 4x gain (The second part of the text makes little sense) "Real gain" may thus refer to the combination of the coarse and fine analogue gains as a single value. The OV5640 0x350a and 0x350b registers thus appear to control analogue gain. The driver incorrectly uses V4L2_CID_GAIN as V4L2 has a specific control for analogue gain, V4L2_CID_ANALOGUE_GAIN. Use it. If registers 0x350a and 0x350b are later found to control digital gain as well, the driver could then restrict the range of the analogue gain control value to lower than x64 and add a separate digital gain control. Signed-off-by: Paul Elder Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index e1b8365fef58..1536649b9e90 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3495,7 +3495,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) /* Auto/manual gain */ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 1023, 1, 0); ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, From d680dc5805745e68e3c8d769f40685707ca7fe4f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 23 Aug 2022 02:58:21 +0200 Subject: [PATCH 047/216] media: dt-bindings: media: i2c: Add IMX296 CMOS sensor binding Add YAML devicetree binding for IMX296 CMOS image sensor. Let's also add MAINTAINERS entry for the binding and driver. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/sony,imx296.yaml | 106 ++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 114 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml new file mode 100644 index 000000000000..65ad9c100e45 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx296.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX296 1/2.8-Inch CMOS Image Sensor + +maintainers: + - Manivannan Sadhasivam + - Laurent Pinchart + +description: |- + The Sony IMX296 is a 1/2.9-Inch active pixel type CMOS Solid-state image + sensor with square pixel array and 1.58 M effective pixels. This chip + features a global shutter with variable charge-integration time. It is + programmable through I2C and 4-wire interfaces. The sensor output is + available via CSI-2 serial data output (1 Lane). + +properties: + compatible: + enum: + - sony,imx296 + - sony,imx296ll + - sony,imx296lq + description: + The IMX296 sensor exists in two different models, a colour variant + (IMX296LQ) and a monochrome variant (IMX296LL). The device exposes the + model through registers, allowing for auto-detection with a common + "sony,imx296" compatible string. However, some camera modules disable the + ability to read the sensor model register, which disables this feature. + In those cases, the exact model needs to be specified as "sony,imx296ll" + or "sony,imx296lq". + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + description: Input clock (37.125 MHz, 54 MHz or 74.25 MHz) + items: + - const: inck + + avdd-supply: + description: Analog power supply (3.3V) + + dvdd-supply: + description: Digital power supply (1.2V) + + ovdd-supply: + description: Interface power supply (1.8V) + + reset-gpios: + description: Sensor reset (XCLR) GPIO + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - clocks + - clock-names + - avdd-supply + - dvdd-supply + - ovdd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imx296: camera-sensor@1a { + compatible = "sony,imx296"; + reg = <0x1a>; + + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_default>; + + clocks = <&gcc 90>; + clock-names = "inck"; + + avdd-supply = <&camera_vdda_3v3>; + dvdd-supply = <&camera_vddd_1v2>; + ovdd-supply = <&camera_vddo_1v8>; + + reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>; + + port { + imx296_ep: endpoint { + remote-endpoint = <&csiphy0_ep>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 217e4e1179de..8a2f019d1239 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19453,6 +19453,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml F: drivers/media/i2c/imx290.c +SONY IMX296 SENSOR DRIVER +M: Laurent Pinchart +M: Manivannan Sadhasivam +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml + SONY IMX319 SENSOR DRIVER M: Bingbu Cao L: linux-media@vger.kernel.org From cb33db2b6ccfe3ccc13347755ab3ef38691d59c3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 23 Aug 2022 02:58:22 +0200 Subject: [PATCH 048/216] media: i2c: IMX296 camera sensor driver The IMX296LLR is a monochrome 1.60MP CMOS sensor from Sony. The driver supports cropping and binning (but not both at the same time due to hardware limitations) and exposure, gain, vertical blanking and test pattern controls. Preliminary support is also included for the color IMX296LQR sensor. [Sakari Ailus: Make driver's remove function return void] Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 13 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/imx296.c | 1172 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1187 insertions(+) create mode 100644 drivers/media/i2c/imx296.c diff --git a/MAINTAINERS b/MAINTAINERS index 8a2f019d1239..f1c9aa89f6a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19460,6 +19460,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml +F: drivers/media/i2c/imx296.c SONY IMX319 SENSOR DRIVER M: Bingbu Cao diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 12ba8542778f..438bb506017f 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -162,6 +162,19 @@ config VIDEO_IMX290 To compile this driver as a module, choose M here: the module will be called imx290. +config VIDEO_IMX296 + tristate "Sony IMX296 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the Sony + IMX296 camera. + + To compile this driver as a module, choose M here: the + module will be called imx296. + config VIDEO_IMX319 tristate "Sony IMX319 sensor support" depends on I2C && VIDEO_DEV diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index b611a8277d57..28178d4c512a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_VIDEO_IMX219) += imx219.o obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX290) += imx290.o +obj-$(CONFIG_VIDEO_IMX296) += imx296.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX334) += imx334.o obj-$(CONFIG_VIDEO_IMX335) += imx335.o diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c new file mode 100644 index 000000000000..3c12b6edeac9 --- /dev/null +++ b/drivers/media/i2c/imx296.c @@ -0,0 +1,1172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for IMX296 CMOS Image Sensor from Sony + * + * Copyright 2019 Laurent Pinchart + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define IMX296_PIXEL_ARRAY_WIDTH 1456 +#define IMX296_PIXEL_ARRAY_HEIGHT 1088 + +#define IMX296_REG_8BIT(n) ((1 << 16) | (n)) +#define IMX296_REG_16BIT(n) ((2 << 16) | (n)) +#define IMX296_REG_24BIT(n) ((3 << 16) | (n)) +#define IMX296_REG_SIZE_SHIFT 16 +#define IMX296_REG_ADDR_MASK 0xffff + +#define IMX296_CTRL00 IMX296_REG_8BIT(0x3000) +#define IMX296_CTRL00_STANDBY BIT(0) +#define IMX296_CTRL08 IMX296_REG_8BIT(0x3008) +#define IMX296_CTRL08_REGHOLD BIT(0) +#define IMX296_CTRL0A IMX296_REG_8BIT(0x300a) +#define IMX296_CTRL0A_XMSTA BIT(0) +#define IMX296_CTRL0B IMX296_REG_8BIT(0x300b) +#define IMX296_CTRL0B_TRIGEN BIT(0) +#define IMX296_CTRL0D IMX296_REG_8BIT(0x300d) +#define IMX296_CTRL0D_WINMODE_ALL (0 << 0) +#define IMX296_CTRL0D_WINMODE_FD_BINNING (2 << 0) +#define IMX296_CTRL0D_HADD_ON_BINNING BIT(5) +#define IMX296_CTRL0D_SAT_CNT BIT(6) +#define IMX296_CTRL0E IMX296_REG_8BIT(0x300e) +#define IMX296_CTRL0E_VREVERSE BIT(0) +#define IMX296_CTRL0E_HREVERSE BIT(1) +#define IMX296_VMAX IMX296_REG_24BIT(0x3010) +#define IMX296_HMAX IMX296_REG_16BIT(0x3014) +#define IMX296_TMDCTRL IMX296_REG_8BIT(0x301d) +#define IMX296_TMDCTRL_LATCH BIT(0) +#define IMX296_TMDOUT IMX296_REG_16BIT(0x301e) +#define IMX296_TMDOUT_MASK 0x3ff +#define IMX296_WDSEL IMX296_REG_8BIT(0x3021) +#define IMX296_WDSEL_NORMAL (0 << 0) +#define IMX296_WDSEL_MULTI_2 (1 << 0) +#define IMX296_WDSEL_MULTI_4 (3 << 0) +#define IMX296_BLKLEVELAUTO IMX296_REG_8BIT(0x3022) +#define IMX296_BLKLEVELAUTO_ON 0x01 +#define IMX296_BLKLEVELAUTO_OFF 0xf0 +#define IMX296_SST IMX296_REG_8BIT(0x3024) +#define IMX296_SST_EN BIT(0) +#define IMX296_CTRLTOUT IMX296_REG_8BIT(0x3026) +#define IMX296_CTRLTOUT_TOUT1SEL_LOW (0 << 0) +#define IMX296_CTRLTOUT_TOUT1SEL_PULSE (3 << 0) +#define IMX296_CTRLTOUT_TOUT2SEL_LOW (0 << 2) +#define IMX296_CTRLTOUT_TOUT2SEL_PULSE (3 << 2) +#define IMX296_CTRLTRIG IMX296_REG_8BIT(0x3029) +#define IMX296_CTRLTRIG_TOUT1_SEL_LOW (0 << 0) +#define IMX296_CTRLTRIG_TOUT1_SEL_PULSE1 (1 << 0) +#define IMX296_CTRLTRIG_TOUT2_SEL_LOW (0 << 4) +#define IMX296_CTRLTRIG_TOUT2_SEL_PULSE2 (2 << 4) +#define IMX296_SYNCSEL IMX296_REG_8BIT(0x3036) +#define IMX296_SYNCSEL_NORMAL 0xc0 +#define IMX296_SYNCSEL_HIZ 0xf0 +#define IMX296_PULSE1 IMX296_REG_8BIT(0x306d) +#define IMX296_PULSE1_EN_NOR BIT(0) +#define IMX296_PULSE1_EN_TRIG BIT(1) +#define IMX296_PULSE1_POL_HIGH (0 << 2) +#define IMX296_PULSE1_POL_LOW (1 << 2) +#define IMX296_PULSE1_UP IMX296_REG_24BIT(0x3070) +#define IMX296_PULSE1_DN IMX296_REG_24BIT(0x3074) +#define IMX296_PULSE2 IMX296_REG_8BIT(0x3079) +#define IMX296_PULSE2_EN_NOR BIT(0) +#define IMX296_PULSE2_EN_TRIG BIT(1) +#define IMX296_PULSE2_POL_HIGH (0 << 2) +#define IMX296_PULSE2_POL_LOW (1 << 2) +#define IMX296_PULSE2_UP IMX296_REG_24BIT(0x307c) +#define IMX296_PULSE2_DN IMX296_REG_24BIT(0x3080) +#define IMX296_INCKSEL(n) IMX296_REG_8BIT(0x3089 + (n)) +#define IMX296_SHS1 IMX296_REG_24BIT(0x308d) +#define IMX296_SHS2 IMX296_REG_24BIT(0x3090) +#define IMX296_SHS3 IMX296_REG_24BIT(0x3094) +#define IMX296_SHS4 IMX296_REG_24BIT(0x3098) +#define IMX296_VBLANKLP IMX296_REG_8BIT(0x309c) +#define IMX296_VBLANKLP_NORMAL 0x04 +#define IMX296_VBLANKLP_LOW_POWER 0x2c +#define IMX296_EXP_CNT IMX296_REG_8BIT(0x30a3) +#define IMX296_EXP_CNT_RESET BIT(0) +#define IMX296_EXP_MAX IMX296_REG_16BIT(0x30a6) +#define IMX296_VINT IMX296_REG_8BIT(0x30aa) +#define IMX296_VINT_EN BIT(0) +#define IMX296_LOWLAGTRG IMX296_REG_8BIT(0x30ae) +#define IMX296_LOWLAGTRG_FAST BIT(0) +#define IMX296_I2CCTRL IMX296_REG_8BIT(0x30ef) +#define IMX296_I2CCTRL_I2CACKEN BIT(0) + +#define IMX296_SENSOR_INFO IMX296_REG_16BIT(0x3148) +#define IMX296_SENSOR_INFO_MONO BIT(15) +#define IMX296_SENSOR_INFO_IMX296LQ 0x4a00 +#define IMX296_SENSOR_INFO_IMX296LL 0xca00 +#define IMX296_S_SHSA IMX296_REG_16BIT(0x31ca) +#define IMX296_S_SHSB IMX296_REG_16BIT(0x31d2) +/* + * Registers 0x31c8 to 0x31cd, 0x31d0 to 0x31d5, 0x31e2, 0x31e3, 0x31ea and + * 0x31eb are related to exposure mode but otherwise not documented. + */ + +#define IMX296_GAINCTRL IMX296_REG_8BIT(0x3200) +#define IMX296_GAINCTRL_WD_GAIN_MODE_NORMAL 0x01 +#define IMX296_GAINCTRL_WD_GAIN_MODE_MULTI 0x41 +#define IMX296_GAIN IMX296_REG_16BIT(0x3204) +#define IMX296_GAIN_MIN 0 +#define IMX296_GAIN_MAX 480 +#define IMX296_GAIN1 IMX296_REG_16BIT(0x3208) +#define IMX296_GAIN2 IMX296_REG_16BIT(0x320c) +#define IMX296_GAIN3 IMX296_REG_16BIT(0x3210) +#define IMX296_GAINDLY IMX296_REG_8BIT(0x3212) +#define IMX296_GAINDLY_NONE 0x08 +#define IMX296_GAINDLY_1FRAME 0x09 +#define IMX296_PGCTRL IMX296_REG_8BIT(0x3238) +#define IMX296_PGCTRL_REGEN BIT(0) +#define IMX296_PGCTRL_THRU BIT(1) +#define IMX296_PGCTRL_CLKEN BIT(2) +#define IMX296_PGCTRL_MODE(n) ((n) << 3) +#define IMX296_PGHPOS IMX296_REG_16BIT(0x3239) +#define IMX296_PGVPOS IMX296_REG_16BIT(0x323c) +#define IMX296_PGHPSTEP IMX296_REG_8BIT(0x323e) +#define IMX296_PGVPSTEP IMX296_REG_8BIT(0x323f) +#define IMX296_PGHPNUM IMX296_REG_8BIT(0x3240) +#define IMX296_PGVPNUM IMX296_REG_8BIT(0x3241) +#define IMX296_PGDATA1 IMX296_REG_16BIT(0x3244) +#define IMX296_PGDATA2 IMX296_REG_16BIT(0x3246) +#define IMX296_PGHGSTEP IMX296_REG_8BIT(0x3249) +#define IMX296_BLKLEVEL IMX296_REG_16BIT(0x3254) + +#define IMX296_FID0_ROI IMX296_REG_8BIT(0x3300) +#define IMX296_FID0_ROIH1ON BIT(0) +#define IMX296_FID0_ROIV1ON BIT(1) +#define IMX296_FID0_ROIPH1 IMX296_REG_16BIT(0x3310) +#define IMX296_FID0_ROIPV1 IMX296_REG_16BIT(0x3312) +#define IMX296_FID0_ROIWH1 IMX296_REG_16BIT(0x3314) +#define IMX296_FID0_ROIWH1_MIN 80 +#define IMX296_FID0_ROIWV1 IMX296_REG_16BIT(0x3316) +#define IMX296_FID0_ROIWV1_MIN 4 + +#define IMX296_CM_HSST_STARTTMG IMX296_REG_16BIT(0x4018) +#define IMX296_CM_HSST_ENDTMG IMX296_REG_16BIT(0x401a) +#define IMX296_DA_HSST_STARTTMG IMX296_REG_16BIT(0x404d) +#define IMX296_DA_HSST_ENDTMG IMX296_REG_16BIT(0x4050) +#define IMX296_LM_HSST_STARTTMG IMX296_REG_16BIT(0x4094) +#define IMX296_LM_HSST_ENDTMG IMX296_REG_16BIT(0x4096) +#define IMX296_SST_SIEASTA1_SET IMX296_REG_8BIT(0x40c9) +#define IMX296_SST_SIEASTA1PRE_1U IMX296_REG_16BIT(0x40cc) +#define IMX296_SST_SIEASTA1PRE_1D IMX296_REG_16BIT(0x40ce) +#define IMX296_SST_SIEASTA1PRE_2U IMX296_REG_16BIT(0x40d0) +#define IMX296_SST_SIEASTA1PRE_2D IMX296_REG_16BIT(0x40d2) +#define IMX296_HSST IMX296_REG_8BIT(0x40dc) +#define IMX296_HSST_EN BIT(2) + +#define IMX296_CKREQSEL IMX296_REG_8BIT(0x4101) +#define IMX296_CKREQSEL_HS BIT(2) +#define IMX296_GTTABLENUM IMX296_REG_8BIT(0x4114) +#define IMX296_CTRL418C IMX296_REG_8BIT(0x418c) + +struct imx296_clk_params { + unsigned int freq; + u8 incksel[4]; + u8 ctrl418c; +}; + +static const struct imx296_clk_params imx296_clk_params[] = { + { 37125000, { 0x80, 0x0b, 0x80, 0x08 }, 116 }, + { 54000000, { 0xb0, 0x0f, 0xb0, 0x0c }, 168 }, + { 74250000, { 0x80, 0x0f, 0x80, 0x0c }, 232 }, +}; + +static const char * const imx296_supply_names[] = { + "dvdd", + "ovdd", + "avdd", +}; + +struct imx296 { + struct device *dev; + struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)]; + struct gpio_desc *reset; + struct regmap *regmap; + + const struct imx296_clk_params *clk_params; + bool mono; + + bool streaming; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; +}; + +static inline struct imx296 *to_imx296(struct v4l2_subdev *sd) +{ + return container_of(sd, struct imx296, subdev); +} + +static int imx296_read(struct imx296 *sensor, u32 addr) +{ + u8 data[3] = { 0, 0, 0 }; + int ret; + + ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data, + (addr >> IMX296_REG_SIZE_SHIFT) & 3); + if (ret < 0) + return ret; + + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err) +{ + u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; + int ret; + + if (err && *err) + return *err; + + ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK, + data, (addr >> IMX296_REG_SIZE_SHIFT) & 3); + if (ret < 0) { + dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n", + ((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8, + addr & IMX296_REG_ADDR_MASK, ret); + if (err) + *err = ret; + } + + return ret; +} + +static int imx296_power_on(struct imx296 *sensor) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + udelay(1); + + ret = gpiod_direction_output(sensor->reset, 0); + if (ret < 0) + goto err_supply; + + udelay(1); + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto err_reset; + + /* + * The documentation doesn't explicitly say how much time is required + * after providing a clock and before starting I2C communication. It + * mentions a delay of 20µs in 4-wire mode, but tests showed that a + * delay of 100µs resulted in I2C communication failures, while 500µs + * seems to be enough. Be conservative. + */ + usleep_range(1000, 2000); + + return 0; + +err_reset: + gpiod_direction_output(sensor->reset, 1); +err_supply: + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void imx296_power_off(struct imx296 *sensor) +{ + clk_disable_unprepare(sensor->clk); + gpiod_direction_output(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +/* ----------------------------------------------------------------------------- + * Controls + */ + +static const char * const imx296_test_pattern_menu[] = { + "Disabled", + "Multiple Pixels", + "Sequence 1", + "Sequence 2", + "Gradient", + "Row", + "Column", + "Cross", + "Stripe", + "Checks", +}; + +static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx296 *sensor = container_of(ctrl->handler, struct imx296, ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int vmax; + int ret = 0; + + if (!sensor->streaming) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->subdev); + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* Clamp the exposure value to VMAX. */ + vmax = format->height + sensor->vblank->cur.val; + ctrl->val = min_t(int, ctrl->val, vmax); + imx296_write(sensor, IMX296_SHS1, vmax - ctrl->val, &ret); + break; + + case V4L2_CID_ANALOGUE_GAIN: + imx296_write(sensor, IMX296_GAIN, ctrl->val, &ret); + break; + + case V4L2_CID_VBLANK: + imx296_write(sensor, IMX296_VMAX, format->height + ctrl->val, + &ret); + break; + + case V4L2_CID_TEST_PATTERN: + if (ctrl->val) { + imx296_write(sensor, IMX296_PGHPOS, 8, &ret); + imx296_write(sensor, IMX296_PGVPOS, 8, &ret); + imx296_write(sensor, IMX296_PGHPSTEP, 8, &ret); + imx296_write(sensor, IMX296_PGVPSTEP, 8, &ret); + imx296_write(sensor, IMX296_PGHPNUM, 100, &ret); + imx296_write(sensor, IMX296_PGVPNUM, 100, &ret); + imx296_write(sensor, IMX296_PGDATA1, 0x300, &ret); + imx296_write(sensor, IMX296_PGDATA2, 0x100, &ret); + imx296_write(sensor, IMX296_PGHGSTEP, 0, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0, &ret); + imx296_write(sensor, IMX296_BLKLEVELAUTO, + IMX296_BLKLEVELAUTO_OFF, &ret); + imx296_write(sensor, IMX296_PGCTRL, + IMX296_PGCTRL_REGEN | + IMX296_PGCTRL_CLKEN | + IMX296_PGCTRL_MODE(ctrl->val - 1), &ret); + } else { + imx296_write(sensor, IMX296_PGCTRL, + IMX296_PGCTRL_CLKEN, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0x3c, &ret); + imx296_write(sensor, IMX296_BLKLEVELAUTO, + IMX296_BLKLEVELAUTO_ON, &ret); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static const struct v4l2_ctrl_ops imx296_ctrl_ops = { + .s_ctrl = imx296_s_ctrl, +}; + +static int imx296_ctrls_init(struct imx296 *sensor) +{ + struct v4l2_fwnode_device_properties props; + unsigned int hblank; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&sensor->ctrls, 9); + + v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 1048575, 1, 1104); + v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN, + IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN); + + /* + * Horizontal blanking is controlled through the HMAX register, which + * contains a line length in INCK clock units. The INCK frequency is + * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100, + * convert it to a number of pixels based on the nominal pixel rate. + */ + hblank = 1100 * 1188000000ULL / 10 / 74250000 + - IMX296_PIXEL_ARRAY_WIDTH; + sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, 1, + hblank); + if (sensor->hblank) + sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_VBLANK, 30, + 1048575 - IMX296_PIXEL_ARRAY_HEIGHT, + 1, 30); + /* + * The sensor calculates the MIPI timings internally to achieve a bit + * rate between 1122 and 1198 Mbps. The exact value is unfortunately not + * reported, at least according to the documentation. Report a nominal + * rate of 1188 Mbps as that is used by the datasheet in multiple + * examples. + */ + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, + 1122000000 / 10, 1198000000 / 10, 1, 1188000000 / 10); + v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx296_test_pattern_menu) - 1, + 0, 0, imx296_test_pattern_menu); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx296_ctrl_ops, + &props); + + if (sensor->ctrls.error) { + dev_err(sensor->dev, "failed to add controls (%d)\n", + sensor->ctrls.error); + v4l2_ctrl_handler_free(&sensor->ctrls); + return sensor->ctrls.error; + } + + sensor->subdev.ctrl_handler = &sensor->ctrls; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdev Operations + */ + +/* + * This table is extracted from vendor data that is entirely undocumented. The + * first register write is required to activate the CSI-2 output. The other + * entries may or may not be optional? + */ +static const struct { + unsigned int reg; + unsigned int value; +} imx296_init_table[] = { + { IMX296_REG_8BIT(0x3005), 0xf0 }, + { IMX296_REG_8BIT(0x309e), 0x04 }, + { IMX296_REG_8BIT(0x30a0), 0x04 }, + { IMX296_REG_8BIT(0x30a1), 0x3c }, + { IMX296_REG_8BIT(0x30a4), 0x5f }, + { IMX296_REG_8BIT(0x30a8), 0x91 }, + { IMX296_REG_8BIT(0x30ac), 0x28 }, + { IMX296_REG_8BIT(0x30af), 0x09 }, + { IMX296_REG_8BIT(0x30df), 0x00 }, + { IMX296_REG_8BIT(0x3165), 0x00 }, + { IMX296_REG_8BIT(0x3169), 0x10 }, + { IMX296_REG_8BIT(0x316a), 0x02 }, + { IMX296_REG_8BIT(0x31c8), 0xf3 }, /* Exposure-related */ + { IMX296_REG_8BIT(0x31d0), 0xf4 }, /* Exposure-related */ + { IMX296_REG_8BIT(0x321a), 0x00 }, + { IMX296_REG_8BIT(0x3226), 0x02 }, + { IMX296_REG_8BIT(0x3256), 0x01 }, + { IMX296_REG_8BIT(0x3541), 0x72 }, + { IMX296_REG_8BIT(0x3516), 0x77 }, + { IMX296_REG_8BIT(0x350b), 0x7f }, + { IMX296_REG_8BIT(0x3758), 0xa3 }, + { IMX296_REG_8BIT(0x3759), 0x00 }, + { IMX296_REG_8BIT(0x375a), 0x85 }, + { IMX296_REG_8BIT(0x375b), 0x00 }, + { IMX296_REG_8BIT(0x3832), 0xf5 }, + { IMX296_REG_8BIT(0x3833), 0x00 }, + { IMX296_REG_8BIT(0x38a2), 0xf6 }, + { IMX296_REG_8BIT(0x38a3), 0x00 }, + { IMX296_REG_8BIT(0x3a00), 0x80 }, + { IMX296_REG_8BIT(0x3d48), 0xa3 }, + { IMX296_REG_8BIT(0x3d49), 0x00 }, + { IMX296_REG_8BIT(0x3d4a), 0x85 }, + { IMX296_REG_8BIT(0x3d4b), 0x00 }, + { IMX296_REG_8BIT(0x400e), 0x58 }, + { IMX296_REG_8BIT(0x4014), 0x1c }, + { IMX296_REG_8BIT(0x4041), 0x2a }, + { IMX296_REG_8BIT(0x40a2), 0x06 }, + { IMX296_REG_8BIT(0x40c1), 0xf6 }, + { IMX296_REG_8BIT(0x40c7), 0x0f }, + { IMX296_REG_8BIT(0x40c8), 0x00 }, + { IMX296_REG_8BIT(0x4174), 0x00 }, +}; + +static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + unsigned int i; + int ret = 0; + + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0); + + for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i) + imx296_write(sensor, imx296_init_table[i].reg, + imx296_init_table[i].value, &ret); + + if (crop->width != IMX296_PIXEL_ARRAY_WIDTH || + crop->height != IMX296_PIXEL_ARRAY_HEIGHT) { + imx296_write(sensor, IMX296_FID0_ROI, + IMX296_FID0_ROIH1ON | IMX296_FID0_ROIV1ON, &ret); + imx296_write(sensor, IMX296_FID0_ROIPH1, crop->left, &ret); + imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret); + imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret); + imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret); + } else { + imx296_write(sensor, IMX296_FID0_ROI, 0, &ret); + } + + imx296_write(sensor, IMX296_CTRL0D, + (crop->width != format->width ? + IMX296_CTRL0D_HADD_ON_BINNING : 0) | + (crop->height != format->height ? + IMX296_CTRL0D_WINMODE_FD_BINNING : 0), + &ret); + + /* + * HMAX and VMAX configure horizontal and vertical blanking by + * specifying the total line time and frame time respectively. The line + * time is specified in operational clock units (which appears to be the + * output of an internal PLL, fixed at 74.25 MHz regardless of the + * exernal clock frequency), while the frame time is specified as a + * number of lines. + * + * In the vertical direction the sensor outputs the following: + * + * - one line for the FS packet + * - two lines of embedded data (DT 0x12) + * - six null lines (DT 0x10) + * - four lines of vertical effective optical black (DT 0x37) + * - 8 to 1088 lines of active image data (RAW10, DT 0x2b) + * - one line for the FE packet + * - 16 or more lines of vertical blanking + */ + imx296_write(sensor, IMX296_HMAX, 1100, &ret); + imx296_write(sensor, IMX296_VMAX, + format->height + sensor->vblank->cur.val, &ret); + + for (i = 0; i < ARRAY_SIZE(sensor->clk_params->incksel); ++i) + imx296_write(sensor, IMX296_INCKSEL(i), + sensor->clk_params->incksel[i], &ret); + imx296_write(sensor, IMX296_GTTABLENUM, 0xc5, &ret); + imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c, + &ret); + + imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret); + + return ret; +} + +static int imx296_stream_on(struct imx296 *sensor) +{ + int ret = 0; + + imx296_write(sensor, IMX296_CTRL00, 0, &ret); + usleep_range(2000, 5000); + imx296_write(sensor, IMX296_CTRL0A, 0, &ret); + + return ret; +} + +static int imx296_stream_off(struct imx296 *sensor) +{ + int ret = 0; + + imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret); + imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret); + + return ret; +} + +static int imx296_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx296 *sensor = to_imx296(sd); + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (!enable) { + ret = imx296_stream_off(sensor); + + pm_runtime_mark_last_busy(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + sensor->streaming = false; + + goto unlock; + } + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret < 0) + goto unlock; + + ret = imx296_setup(sensor, state); + if (ret < 0) + goto err_pm; + + /* + * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set + * the controls. The flag is reset to false further down if an error + * occurs. + */ + sensor->streaming = true; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); + if (ret < 0) + goto err_pm; + + ret = imx296_stream_on(sensor); + if (ret) + goto err_pm; + +unlock: + v4l2_subdev_unlock_state(state); + + return ret; + +err_pm: + /* + * In case of error, turn the power off synchronously as the device + * likely has no other chance to recover. + */ + pm_runtime_put_sync(sensor->dev); + sensor->streaming = false; + + goto unlock; +} + +static int imx296_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx296 *sensor = to_imx296(sd); + + if (code->index != 0) + return -EINVAL; + + code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 + : MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int imx296_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + + if (fse->index >= 2 || fse->code != format->code) + return -EINVAL; + + fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->max_width = fse->min_width; + fse->min_height = IMX296_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + fse->max_height = fse->min_height; + + return 0; +} + +static int imx296_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + return 0; +} + +static int imx296_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct imx296 *sensor = to_imx296(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + /* + * Binning is only allowed when cropping is disabled according to the + * documentation. This should be double-checked. + */ + if (crop->width == IMX296_PIXEL_ARRAY_WIDTH && + crop->height == IMX296_PIXEL_ARRAY_HEIGHT) { + unsigned int width; + unsigned int height; + unsigned int hratio; + unsigned int vratio; + + /* Clamp the width and height to avoid dividing by zero. */ + width = clamp_t(unsigned int, fmt->format.width, + crop->width / 2, crop->width); + height = clamp_t(unsigned int, fmt->format.height, + crop->height / 2, crop->height); + + hratio = DIV_ROUND_CLOSEST(crop->width, width); + vratio = DIV_ROUND_CLOSEST(crop->height, height); + + format->width = crop->width / hratio; + format->height = crop->height / vratio; + } else { + format->width = crop->width; + format->height = crop->height; + } + + format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 + : MEDIA_BUS_FMT_SBGGR10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + fmt->format = *format; + + return 0; +} + +static int imx296_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + break; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = IMX296_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX296_PIXEL_ARRAY_HEIGHT; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int imx296_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect rect; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + /* + * Clamp the crop rectangle boundaries and align them to a multiple of 4 + * pixels to satisfy hardware requirements. + */ + rect.left = clamp(ALIGN(sel->r.left, 4), 0, + IMX296_PIXEL_ARRAY_WIDTH - IMX296_FID0_ROIWH1_MIN); + rect.top = clamp(ALIGN(sel->r.top, 4), 0, + IMX296_PIXEL_ARRAY_HEIGHT - IMX296_FID0_ROIWV1_MIN); + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + IMX296_FID0_ROIWH1_MIN, IMX296_PIXEL_ARRAY_WIDTH); + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 4), + IMX296_FID0_ROIWV1_MIN, IMX296_PIXEL_ARRAY_HEIGHT); + + rect.width = min_t(unsigned int, rect.width, + IMX296_PIXEL_ARRAY_WIDTH - rect.left); + rect.height = min_t(unsigned int, rect.height, + IMX296_PIXEL_ARRAY_HEIGHT - rect.top); + + crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + + if (rect.width != crop->width || rect.height != crop->height) { + /* + * Reset the output image size if the crop rectangle size has + * been modified. + */ + format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + format->width = rect.width; + format->height = rect.height; + } + + *crop = rect; + sel->r = rect; + + return 0; +} + +static int imx296_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_selection sel = { + .target = V4L2_SEL_TGT_CROP, + .r.width = IMX296_PIXEL_ARRAY_WIDTH, + .r.height = IMX296_PIXEL_ARRAY_HEIGHT, + }; + struct v4l2_subdev_format format = { + .format = { + .width = IMX296_PIXEL_ARRAY_WIDTH, + .height = IMX296_PIXEL_ARRAY_HEIGHT, + }, + }; + + imx296_set_selection(sd, state, &sel); + imx296_set_format(sd, state, &format); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = { + .s_stream = imx296_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = { + .enum_mbus_code = imx296_enum_mbus_code, + .enum_frame_size = imx296_enum_frame_size, + .get_fmt = imx296_get_format, + .set_fmt = imx296_set_format, + .get_selection = imx296_get_selection, + .set_selection = imx296_set_selection, + .init_cfg = imx296_init_cfg, +}; + +static const struct v4l2_subdev_ops imx296_subdev_ops = { + .video = &imx296_subdev_video_ops, + .pad = &imx296_subdev_pad_ops, +}; + +static int imx296_subdev_init(struct imx296 *sensor) +{ + struct i2c_client *client = to_i2c_client(sensor->dev); + int ret; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops); + + ret = imx296_ctrls_init(sensor); + if (ret < 0) + return ret; + + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); + if (ret < 0) { + v4l2_ctrl_handler_free(&sensor->ctrls); + return ret; + } + + sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock; + + v4l2_subdev_init_finalize(&sensor->subdev); + + return ret; +} + +static void imx296_subdev_cleanup(struct imx296 *sensor) +{ + media_entity_cleanup(&sensor->subdev.entity); + v4l2_ctrl_handler_free(&sensor->ctrls); +} + +/* ----------------------------------------------------------------------------- + * Power management + */ + +static int __maybe_unused imx296_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + return imx296_power_on(sensor); +} + +static int __maybe_unused imx296_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + imx296_power_off(sensor); + + return 0; +} + +static const struct dev_pm_ops imx296_pm_ops = { + SET_RUNTIME_PM_OPS(imx296_runtime_suspend, imx296_runtime_resume, NULL) +}; + +/* ----------------------------------------------------------------------------- + * Probe & Remove + */ + +static int imx296_read_temperature(struct imx296 *sensor, int *temp) +{ + int tmdout; + int ret; + + ret = imx296_write(sensor, IMX296_TMDCTRL, IMX296_TMDCTRL_LATCH, NULL); + if (ret < 0) + return ret; + + tmdout = imx296_read(sensor, IMX296_TMDOUT) & IMX296_TMDOUT_MASK; + if (tmdout < 0) + return tmdout; + + /* T(°C) = 246.312 - 0.304 * TMDOUT */; + *temp = 246312 - 304 * tmdout; + + return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL); +} + +static int imx296_identify_model(struct imx296 *sensor) +{ + unsigned int model; + int temp = 0; + int ret; + + model = (uintptr_t)of_device_get_match_data(sensor->dev); + if (model) { + dev_dbg(sensor->dev, + "sensor model auto-detection disabled, forcing 0x%04x\n", + model); + sensor->mono = model & IMX296_SENSOR_INFO_MONO; + return 0; + } + + /* + * While most registers can be read when the sensor is in standby, this + * is not the case of the sensor info register :-( + */ + ret = imx296_write(sensor, IMX296_CTRL00, 0, NULL); + if (ret < 0) { + dev_err(sensor->dev, + "failed to get sensor out of standby (%d)\n", ret); + return ret; + } + + ret = imx296_read(sensor, IMX296_SENSOR_INFO); + if (ret < 0) { + dev_err(sensor->dev, "failed to read sensor information (%d)\n", + ret); + goto done; + } + + model = (ret >> 6) & 0x1ff; + + switch (model) { + case 296: + sensor->mono = ret & IMX296_SENSOR_INFO_MONO; + break; + /* + * The IMX297 seems to share features with the IMX296, it may be + * possible to support it in the same driver. + */ + case 297: + default: + dev_err(sensor->dev, "invalid device model 0x%04x\n", ret); + ret = -ENODEV; + goto done; + } + + ret = imx296_read_temperature(sensor, &temp); + if (ret < 0) + goto done; + + dev_info(sensor->dev, "found IMX%u%s (%u.%uC)\n", model, + sensor->mono ? "LL" : "LQ", temp / 1000, (temp / 100) % 10); + +done: + imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, NULL); + return ret; +} + +static const struct regmap_config imx296_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + + .wr_table = &(const struct regmap_access_table) { + .no_ranges = (const struct regmap_range[]) { + { + .range_min = IMX296_SENSOR_INFO & 0xffff, + .range_max = (IMX296_SENSOR_INFO & 0xffff) + 1, + }, + }, + .n_no_ranges = 1, + }, +}; + +static int imx296_probe(struct i2c_client *client) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + unsigned long clk_rate; + struct imx296 *sensor; + unsigned int i; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->dev = &client->dev; + + /* Acquire resources. */ + for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i) + sensor->supplies[i].supply = imx296_supply_names[i]; + + ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to get supplies\n"); + return ret; + } + + sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), + "failed to get reset GPIO\n"); + + sensor->clk = devm_clk_get(sensor->dev, "inck"); + if (IS_ERR(sensor->clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + clk_rate = clk_get_rate(sensor->clk); + for (i = 0; i < ARRAY_SIZE(imx296_clk_params); ++i) { + if (clk_rate == imx296_clk_params[i].freq) { + sensor->clk_params = &imx296_clk_params[i]; + break; + } + } + + if (!sensor->clk_params) { + dev_err(sensor->dev, "unsupported clock rate %lu\n", clk_rate); + return -EINVAL; + } + + sensor->regmap = devm_regmap_init_i2c(client, &imx296_regmap_config); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, identify it, and fully initialize it. + */ + ret = imx296_power_on(sensor); + if (ret < 0) + return ret; + + ret = imx296_identify_model(sensor); + if (ret < 0) + goto err_power; + + /* Initialize the V4L2 subdev. */ + ret = imx296_subdev_init(sensor); + if (ret < 0) + goto err_power; + + /* + * Enable runtime PM. As the device has been powered manually, mark it + * as active, and increase the usage count without resuming the device. + */ + pm_runtime_set_active(sensor->dev); + pm_runtime_get_noresume(sensor->dev); + pm_runtime_enable(sensor->dev); + + /* Register the V4L2 subdev. */ + ret = v4l2_async_register_subdev(&sensor->subdev); + if (ret < 0) + goto err_pm; + + /* + * Finally, enable autosuspend and decrease the usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. + */ + pm_runtime_set_autosuspend_delay(sensor->dev, 1000); + pm_runtime_use_autosuspend(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + return 0; + +err_pm: + pm_runtime_disable(sensor->dev); + pm_runtime_put_noidle(sensor->dev); + imx296_subdev_cleanup(sensor); +err_power: + imx296_power_off(sensor); + return ret; +} + +static void imx296_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + v4l2_async_unregister_subdev(subdev); + + imx296_subdev_cleanup(sensor); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(sensor->dev); + if (!pm_runtime_status_suspended(sensor->dev)) + imx296_power_off(sensor); + pm_runtime_set_suspended(sensor->dev); +} + +static const struct of_device_id imx296_of_match[] = { + { .compatible = "sony,imx296", .data = NULL }, + { .compatible = "sony,imx296ll", .data = (void *)IMX296_SENSOR_INFO_IMX296LL }, + { .compatible = "sony,imx296lq", .data = (void *)IMX296_SENSOR_INFO_IMX296LQ }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx296_of_match); + +static struct i2c_driver imx296_i2c_driver = { + .driver = { + .of_match_table = imx296_of_match, + .name = "imx296", + .pm = &imx296_pm_ops + }, + .probe_new = imx296_probe, + .remove = imx296_remove, +}; + +module_i2c_driver(imx296_i2c_driver); + +MODULE_DESCRIPTION("Sony IMX296 Camera driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); From c699ce1a3838465fb87ecd951f0819404e70030a Mon Sep 17 00:00:00 2001 From: Oleg Verych Date: Tue, 17 Jan 2023 00:03:23 +0100 Subject: [PATCH 049/216] media: sun4i-csi: Use CSI_INT_STA_REG name, fix typo in a comment Fix interrupt status register offset usage to be a defined name CSI_INT_STA_REG (= 0x34) instead of a plain number. Additionally fix a typo in a comment of the same file. Signed-off-by: Oleg Verych Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index a3e826a755fc..95b5633b7914 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -245,7 +245,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) * We need a scratch buffer in case where we'll not have any * more buffer queued so that we don't error out. One of those * cases is when you end up at the last frame to capture, you - * don't havea any buffer queued any more, and yet it doesn't + * don't have any buffer queued any more, and yet it doesn't * really matter since you'll never reach the next buffer. * * Since we support the multi-planar API, we need to have a @@ -311,7 +311,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG); /* Clear the pending interrupts */ - writel(CSI_INT_FRM_DONE, csi->regs + 0x34); + writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_STA_REG); /* Enable frame done interrupt */ writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG); From ef86447e775fb1f2ced00d4c7fff2c0a1c63f165 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Tue, 17 Jan 2023 09:16:23 +0100 Subject: [PATCH 050/216] media: i2c: imx219: Fix binning for RAW8 capture 2x2 binning works fine for RAW10 capture, but for RAW8 1232p mode it leads to corrupted frames [1][2]. Using the special 2x2 analog binning mode fixes the issue, but causes artefacts for RAW10 1232p capture. So here we choose the binning mode depending upon the frame format selected. As both binning modes work fine for 480p RAW8 and RAW10 capture, it can share the same code path as 1232p for selecting binning mode. [1] https://forums.raspberrypi.com/viewtopic.php?t=332103 [2] https://github.com/raspberrypi/libcamera-apps/issues/281 Fixes: 22da1d56e982 ("media: i2c: imx219: Add support for RAW8 bit bayer format") Signed-off-by: Jai Luthra Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 57 ++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index b5fa4986470a..f9471c9e3a74 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -95,6 +95,12 @@ #define IMX219_REG_ORIENTATION 0x0172 +/* Binning Mode */ +#define IMX219_REG_BINNING_MODE 0x0174 +#define IMX219_BINNING_NONE 0x0000 +#define IMX219_BINNING_2X2 0x0101 +#define IMX219_BINNING_2X2_ANALOG 0x0303 + /* Test Pattern Control */ #define IMX219_REG_TEST_PATTERN 0x0600 #define IMX219_TEST_PATTERN_DISABLE 0 @@ -149,6 +155,9 @@ struct imx219_mode { /* Default register values */ struct imx219_reg_list reg_list; + + /* 2x2 binning is used */ + bool binning; }; static const struct imx219_reg imx219_common_regs[] = { @@ -218,8 +227,6 @@ static const struct imx219_reg mode_3280x2464_regs[] = { {0x016d, 0xd0}, {0x016e, 0x09}, {0x016f, 0xa0}, - {0x0174, 0x00}, /* No-Binning */ - {0x0175, 0x00}, {0x0624, 0x0c}, {0x0625, 0xd0}, {0x0626, 0x09}, @@ -239,8 +246,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { {0x016d, 0x80}, {0x016e, 0x04}, {0x016f, 0x38}, - {0x0174, 0x00}, /* No-Binning */ - {0x0175, 0x00}, {0x0624, 0x07}, {0x0625, 0x80}, {0x0626, 0x04}, @@ -260,8 +265,6 @@ static const struct imx219_reg mode_1640_1232_regs[] = { {0x016d, 0x68}, {0x016e, 0x04}, {0x016f, 0xd0}, - {0x0174, 0x01}, /* x2-Binning */ - {0x0175, 0x01}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, @@ -281,8 +284,6 @@ static const struct imx219_reg mode_640_480_regs[] = { {0x016d, 0x80}, {0x016e, 0x01}, {0x016f, 0xe0}, - {0x0174, 0x03}, /* x2-analog binning */ - {0x0175, 0x03}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, @@ -400,6 +401,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), .regs = mode_3280x2464_regs, }, + .binning = false, }, { /* 1080P 30fps cropped */ @@ -416,6 +418,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), .regs = mode_1920_1080_regs, }, + .binning = false, }, { /* 2x2 binned 30fps mode */ @@ -432,6 +435,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), .regs = mode_1640_1232_regs, }, + .binning = true, }, { /* 640x480 30fps mode */ @@ -448,6 +452,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_640_480_regs), .regs = mode_640_480_regs, }, + .binning = true, }, }; @@ -897,6 +902,35 @@ static int imx219_set_framefmt(struct imx219 *imx219) return -EINVAL; } +static int imx219_set_binning(struct imx219 *imx219) +{ + if (!imx219->mode->binning) { + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_NONE); + } + + switch (imx219->fmt.code) { + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_2X2_ANALOG); + + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_2X2); + } + + return -EINVAL; +} + static const struct v4l2_rect * __imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_state *sd_state, @@ -995,6 +1029,13 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + ret = imx219_set_binning(imx219); + if (ret) { + dev_err(&client->dev, "%s failed to set binning: %d\n", + __func__, ret); + goto err_rpm_put; + } + /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) From c9dd57143e70d9ad164d0047393a02c74bd0fa1f Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 8 Jun 2022 15:44:17 +0200 Subject: [PATCH 051/216] media: dt-bindings: ov5675: document YAML binding This patch adds documentation of device tree in YAML schema for the OV5675 CMOS image sensor from Omnivision. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Quentin Schulz Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/ovti,ov5675.yaml | 122 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 123 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml new file mode 100644 index 000000000000..ad07204057f9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2022 Theobroma Systems Design und Consulting GmbH +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov5675.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV5675 CMOS Sensor + +maintainers: + - Quentin Schulz + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +description: | + The Omnivision OV5675 is a high performance, 1/5-inch, 5 megapixel, CMOS + image sensor that delivers 2592x1944 at 30fps. It provides full-frame, + sub-sampled, and windowed 10-bit MIPI images in various formats via the + Serial Camera Control Bus (SCCB) interface. + + This chip is programmable through I2C and two-wire SCCB. The sensor output + is available via CSI-2 serial data output (up to 2-lane). + +properties: + compatible: + const: ovti,ov5675 + + reg: + maxItems: 1 + + clocks: + description: + System input clock (aka XVCLK). From 6 to 27 MHz. + maxItems: 1 + + dovdd-supply: + description: + Digital I/O voltage supply, 1.8 volts. + + avdd-supply: + description: + Analog voltage supply, 2.8 volts. + + dvdd-supply: + description: + Digital core voltage supply, 1.2 volts. + + reset-gpios: + description: + The phandle and specifier for the GPIO that controls sensor reset. + This corresponds to the hardware pin XSHUTDN which is physically + active low. + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 2 + + # Supports max data transfer of 900 Mbps per lane + link-frequencies: true + +required: + - compatible + - reg + - clocks + - dovdd-supply + - avdd-supply + - dvdd-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5675: camera@36 { + compatible = "ovti,ov5675"; + reg = <0x36>; + + reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&cif_clkout_m0>; + + clocks = <&cru SCLK_CIF_OUT>; + assigned-clocks = <&cru SCLK_CIF_OUT>; + assigned-clock-rates = <19200000>; + + avdd-supply = <&vcc_1v8>; + dvdd-supply = <&vcc_1v2>; + dovdd-supply = <&vcc_2v8>; + + rotation = <90>; + orientation = <0>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <450000000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index f1c9aa89f6a4..48da17fa9525 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15467,6 +15467,7 @@ M: Shawn Tu L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml F: drivers/media/i2c/ov5675.c OMNIVISION OV5693 SENSOR DRIVER From 49d9ad719e8934fcd0de4a8317fd1a735e587f47 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 8 Jun 2022 15:44:18 +0200 Subject: [PATCH 052/216] media: ov5675: add device-tree support and support runtime PM Until now, this driver only supported ACPI. This adds support for Device Tree too while enabling clock and regulators in runtime PM. Signed-off-by: Quentin Schulz Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5675.c | 154 +++++++++++++++++++++++++++++++------ 1 file changed, 131 insertions(+), 23 deletions(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index a6e6b367d128..6fb849db1af7 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -3,10 +3,14 @@ #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include @@ -17,7 +21,7 @@ #define OV5675_LINK_FREQ_450MHZ 450000000ULL #define OV5675_SCLK 90000000LL -#define OV5675_MCLK 19200000 +#define OV5675_XVCLK_19_2 19200000 #define OV5675_DATA_LANES 2 #define OV5675_RGB_DEPTH 10 @@ -76,6 +80,14 @@ #define to_ov5675(_sd) container_of(_sd, struct ov5675, sd) +static const char * const ov5675_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV5675_NUM_SUPPLIES ARRAY_SIZE(ov5675_supply_names) + enum { OV5675_LINK_FREQ_900MBPS, }; @@ -484,6 +496,9 @@ struct ov5675 { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV5675_NUM_SUPPLIES]; /* V4L2 Controls */ struct v4l2_ctrl *link_freq; @@ -946,6 +961,56 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) return ret; } +static int ov5675_power_off(struct device *dev) +{ + /* 512 xvclk cycles after the last SCCB transation or MIPI frame end */ + u32 delay_us = DIV_ROUND_UP(512, OV5675_XVCLK_19_2 / 1000 / 1000); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5675 *ov5675 = to_ov5675(sd); + + usleep_range(delay_us, delay_us * 2); + + clk_disable_unprepare(ov5675->xvclk); + gpiod_set_value_cansleep(ov5675->reset_gpio, 1); + regulator_bulk_disable(OV5675_NUM_SUPPLIES, ov5675->supplies); + + return 0; +} + +static int ov5675_power_on(struct device *dev) +{ + u32 delay_us = DIV_ROUND_UP(8192, OV5675_XVCLK_19_2 / 1000 / 1000); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5675 *ov5675 = to_ov5675(sd); + int ret; + + ret = clk_prepare_enable(ov5675->xvclk); + if (ret < 0) { + dev_err(dev, "failed to enable xvclk: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ov5675->reset_gpio, 1); + + ret = regulator_bulk_enable(OV5675_NUM_SUPPLIES, ov5675->supplies); + if (ret) { + clk_disable_unprepare(ov5675->xvclk); + return ret; + } + + /* Reset pulse should be at least 2ms and reset gpio released only once + * regulators are stable. + */ + usleep_range(2000, 2200); + + gpiod_set_value_cansleep(ov5675->reset_gpio, 0); + + /* 8192 xvclk cycles prior to the first SCCB transation */ + usleep_range(delay_us, delay_us * 2); + + return 0; +} + static int __maybe_unused ov5675_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); @@ -1108,31 +1173,59 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { .open = ov5675_open, }; -static int ov5675_check_hwcfg(struct device *dev) +static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) { struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; + u32 xvclk_rate; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + ov5675->xvclk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ov5675->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov5675->xvclk), + "failed to get xvclk: %ld\n", + PTR_ERR(ov5675->xvclk)); - if (ret) { - dev_err(dev, "can't get clock frequency"); + if (ov5675->xvclk) { + xvclk_rate = clk_get_rate(ov5675->xvclk); + } else { + ret = fwnode_property_read_u32(fwnode, "clock-frequency", + &xvclk_rate); + + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } + } + + if (xvclk_rate != OV5675_XVCLK_19_2) { + dev_err(dev, "external clock rate %u is unsupported", + xvclk_rate); + return -EINVAL; + } + + ov5675->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5675->reset_gpio)) { + ret = PTR_ERR(ov5675->reset_gpio); + dev_err(dev, "failed to get reset-gpios: %d\n", ret); return ret; } - if (mclk != OV5675_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } + for (i = 0; i < OV5675_NUM_SUPPLIES; i++) + ov5675->supplies[i].supply = ov5675_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, OV5675_NUM_SUPPLIES, + ov5675->supplies); + if (ret) + return ret; ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) @@ -1187,6 +1280,10 @@ static void ov5675_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); mutex_destroy(&ov5675->mutex); + + if (!pm_runtime_status_suspended(&client->dev)) + ov5675_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); } static int ov5675_probe(struct i2c_client *client) @@ -1195,25 +1292,31 @@ static int ov5675_probe(struct i2c_client *client) bool full_power; int ret; - ret = ov5675_check_hwcfg(&client->dev); - if (ret) { - dev_err(&client->dev, "failed to check HW configuration: %d", - ret); - return ret; - } - ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL); if (!ov5675) return -ENOMEM; + ret = ov5675_get_hwcfg(ov5675, &client->dev); + if (ret) { + dev_err(&client->dev, "failed to get HW configuration: %d", + ret); + return ret; + } + v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); + ret = ov5675_power_on(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to power on: %d\n", ret); + return ret; + } + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { ret = ov5675_identify_module(ov5675); if (ret) { dev_err(&client->dev, "failed to find sensor: %d", ret); - return ret; + goto probe_power_off; } } @@ -1243,11 +1346,6 @@ static int ov5675_probe(struct i2c_client *client) goto probe_error_media_entity_cleanup; } - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); @@ -1262,12 +1360,15 @@ static int ov5675_probe(struct i2c_client *client) probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); mutex_destroy(&ov5675->mutex); +probe_power_off: + ov5675_power_off(&client->dev); return ret; } static const struct dev_pm_ops ov5675_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) + SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL) }; #ifdef CONFIG_ACPI @@ -1279,11 +1380,18 @@ static const struct acpi_device_id ov5675_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids); #endif +static const struct of_device_id ov5675_of_match[] = { + { .compatible = "ovti,ov5675", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov5675_of_match); + static struct i2c_driver ov5675_i2c_driver = { .driver = { .name = "ov5675", .pm = &ov5675_pm_ops, .acpi_match_table = ACPI_PTR(ov5675_acpi_ids), + .of_match_table = ov5675_of_match, }, .probe_new = ov5675_probe, .remove = ov5675_remove, From c8aa2111e17ae8bd624ddc578a7b4cd43a9d469c Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 8 Jun 2022 15:44:19 +0200 Subject: [PATCH 053/216] media: i2c: ov5675: parse and register V4L2 device tree properties Parse V4L2 device tree properties and register controls for them. Reviewed-by: Jacopo Mondi Signed-off-by: Quentin Schulz Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5675.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 6fb849db1af7..b1ed437b8842 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -779,12 +779,14 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { static int ov5675_init_controls(struct ov5675 *ov5675) { + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank; int ret; ctrl_hdlr = &ov5675->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); if (ret) return ret; @@ -840,9 +842,23 @@ static int ov5675_init_controls(struct ov5675 *ov5675) return ctrl_hdlr->error; } + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov5675_ctrl_ops, + &props); + if (ret) + goto error; + ov5675->sd.ctrl_handler = ctrl_hdlr; return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; } static void ov5675_update_pad_format(const struct ov5675_mode *mode, From 221827ee2da4e61ba0d16b14ad40c6446ca3294f Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 8 Jun 2022 15:44:20 +0200 Subject: [PATCH 054/216] media: i2c: ov5675: add .get_selection support The sensor has 2592*1944 active pixels, surrounded by 16 active dummy pixels and there are an additional 24 black rows "at the bottom". [2624] +-----+------------------+-----+ | | 16 dummy | | +-----+------------------+-----+ | | | | | | [2592] | | | | | | |16 | valid | 16 |[2000] |dummy| |dummy| | | [1944]| | | | | | +-----+------------------+-----+ | | 16 dummy | | +-----+------------------+-----+ | | 24 black lines | | +-----+------------------+-----+ The top-left coordinate is gotten from the registers specified in the modes which are identical for both currently supported modes. There are currently two modes supported by this driver: 2592*1944 and 1296*972. The second mode is obtained thanks to subsampling while keeping the same field of view (FoV). No cropping involved, hence the harcoded values. Signed-off-by: Quentin Schulz Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5675.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index b1ed437b8842..d55180b3b7aa 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -1123,6 +1123,31 @@ static int ov5675_get_format(struct v4l2_subdev *sd, return 0; } +static int ov5675_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = 2624; + sel->r.height = 2000; + return 0; + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = 16; + sel->r.left = 16; + sel->r.width = 2592; + sel->r.height = 1944; + return 0; + } + return -EINVAL; +} + static int ov5675_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -1172,6 +1197,7 @@ static const struct v4l2_subdev_video_ops ov5675_video_ops = { static const struct v4l2_subdev_pad_ops ov5675_pad_ops = { .set_fmt = ov5675_set_format, .get_fmt = ov5675_get_format, + .get_selection = ov5675_get_selection, .enum_mbus_code = ov5675_enum_mbus_code, .enum_frame_size = ov5675_enum_frame_size, }; From 3e4ab2342fc26800e8d40a82a6ad5dcedb419924 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sat, 28 Jan 2023 12:27:36 +0100 Subject: [PATCH 055/216] media: dt-bindings: Add OV5670 Add the bindings documentation for Omnivision OV5670 image sensor. Signed-off-by: Jacopo Mondi Reviewed-by: Krzysztof Kozlowski Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/ovti,ov5670.yaml | 93 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 94 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml new file mode 100644 index 000000000000..6e089fe1d613 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov5670.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV5670 5 Megapixels raw image sensor + +maintainers: + - Jacopo Mondi + +description: |- + The OV5670 is a 5 Megapixels raw image sensor which provides images in 10-bits + RAW BGGR Bayer format on a 2 data lanes MIPI CSI-2 serial interface and is + controlled through an I2C compatible control bus. + +properties: + compatible: + const: ovti,ov5670 + + reg: + maxItems: 1 + + clocks: + description: System clock. From 6 to 27 MHz. + maxItems: 1 + + powerdown-gpios: + description: Reference to the GPIO connected to the PWDNB pin. Active low. + + reset-gpios: + description: Reference to the GPIO connected to the XSHUTDOWN pin. Active low. + maxItems: 1 + + avdd-supply: + description: Analog circuit power. Typically 2.8V. + + dvdd-supply: + description: Digital circuit power. Typically 1.2V. + + dovdd-supply: + description: Digital I/O circuit power. Typically 2.8V or 1.8V. + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + additionalProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 2 + items: + enum: [1, 2] + + clock-noncontinuous: true + remote-endpoint: true + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5670: sensor@36 { + compatible = "ovti,ov5670"; + reg = <0x36>; + + clocks = <&sensor_xclk>; + + port { + ov5670_ep: endpoint { + remote-endpoint = <&csi_ep>; + data-lanes = <1 2>; + clock-noncontinuous; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 48da17fa9525..6406e23772da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15460,6 +15460,7 @@ M: Chiranjeevi Rapolu L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml F: drivers/media/i2c/ov5670.c OMNIVISION OV5675 SENSOR DRIVER From 5635500ae516fb834d59077e16e2e4db85538e0d Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:02 +0100 Subject: [PATCH 056/216] media: i2c: ov5670: Allow probing with OF The ov5670 driver currently only supports probing using ACPI matching. Add support for OF and add a missing header inclusion. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index bc9fc3bc90c2..07a396c8ab68 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include #include #include @@ -2583,11 +2585,18 @@ static const struct acpi_device_id ov5670_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov5670_acpi_ids); #endif +static const struct of_device_id ov5670_of_ids[] = { + { .compatible = "ovti,ov5670" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov5670_of_ids); + static struct i2c_driver ov5670_i2c_driver = { .driver = { .name = "ov5670", .pm = &ov5670_pm_ops, .acpi_match_table = ACPI_PTR(ov5670_acpi_ids), + .of_match_table = ov5670_of_ids, }, .probe_new = ov5670_probe, .remove = ov5670_remove, From 8004c91e20959c241fcc7c87f6f7bc880dc25a27 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:03 +0100 Subject: [PATCH 057/216] media: i2c: ov5670: Use common clock framework Add support for probing the main system clock using the common clock framework and its OF bindings. Maintain ACPI compatibility by falling back to parse 'clock-frequency'. Signed-off-by: Jacopo Mondi Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 07a396c8ab68..52b799a7491c 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2,6 +2,7 @@ // Copyright (c) 2017 Intel Corporation. #include +#include #include #include #include @@ -12,6 +13,8 @@ #include #include +#define OV5670_XVCLK_FREQ 19200000 + #define OV5670_REG_CHIP_ID 0x300a #define OV5670_CHIP_ID 0x005670 @@ -1830,6 +1833,9 @@ struct ov5670 { /* Current mode */ const struct ov5670_mode *cur_mode; + /* xvclk input clock */ + struct clk *xvclk; + /* To serialize asynchronus callbacks */ struct mutex mutex; @@ -2478,10 +2484,6 @@ static int ov5670_probe(struct i2c_client *client) bool full_power; int ret; - device_property_read_u32(&client->dev, "clock-frequency", &input_clk); - if (input_clk != 19200000) - return -EINVAL; - ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL); if (!ov5670) { ret = -ENOMEM; @@ -2489,6 +2491,22 @@ static int ov5670_probe(struct i2c_client *client) goto error_print; } + ov5670->xvclk = devm_clk_get(&client->dev, NULL); + if (!IS_ERR_OR_NULL(ov5670->xvclk)) + input_clk = clk_get_rate(ov5670->xvclk); + else if (PTR_ERR(ov5670->xvclk) == -ENOENT) + device_property_read_u32(&client->dev, "clock-frequency", + &input_clk); + else + return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk), + "error getting clock\n"); + + if (input_clk != OV5670_XVCLK_FREQ) { + dev_err(&client->dev, + "Unsupported clock frequency %u\n", input_clk); + return -EINVAL; + } + /* Initialize subdev */ v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); From cf9ab879910f620fca10562ce9223b54463dff70 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:04 +0100 Subject: [PATCH 058/216] media: i2c: ov5670: Probe regulators The OV5670 has three power supplies (AVDD, DOVDD and DVDD). Probe them in the driver to prepare controlling with runtime_pm operations. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 52b799a7491c..e71f13360480 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,14 @@ struct ov5670_link_freq_config { const struct ov5670_reg_list reg_list; }; +static const char * const ov5670_supply_names[] = { + "avdd", /* Analog power */ + "dvdd", /* Digital power */ + "dovdd", /* Digital output power */ +}; + +#define OV5670_NUM_SUPPLIES ARRAY_SIZE(ov5670_supply_names) + struct ov5670_mode { /* Frame width in pixels */ u32 width; @@ -1836,6 +1845,9 @@ struct ov5670 { /* xvclk input clock */ struct clk *xvclk; + /* Regulators */ + struct regulator_bulk_data supplies[OV5670_NUM_SUPPLIES]; + /* To serialize asynchronus callbacks */ struct mutex mutex; @@ -2476,6 +2488,18 @@ static const struct v4l2_subdev_internal_ops ov5670_internal_ops = { .open = ov5670_open, }; +static int ov5670_regulators_probe(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + unsigned int i; + + for (i = 0; i < OV5670_NUM_SUPPLIES; i++) + ov5670->supplies[i].supply = ov5670_supply_names[i]; + + return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES, + ov5670->supplies); +} + static int ov5670_probe(struct i2c_client *client) { struct ov5670 *ov5670; @@ -2510,6 +2534,12 @@ static int ov5670_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); + ret = ov5670_regulators_probe(ov5670); + if (ret) { + err_msg = "Regulators probe failed"; + goto error_print; + } + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { /* Check module identity */ From 0a844ab77bd1ee9349e34c2beac049dc4b50bf58 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:05 +0100 Subject: [PATCH 059/216] media: i2c: ov5670: Probe GPIOs The OV5670 has a powerdown and reset pin, named respectively "PWDN" and "XSHUTDOWN". Optionally probe the gpios connected to the pins during the driver probe routine. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index e71f13360480..0290f33f619d 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -1848,6 +1849,10 @@ struct ov5670 { /* Regulators */ struct regulator_bulk_data supplies[OV5670_NUM_SUPPLIES]; + /* Power-down and reset gpios. */ + struct gpio_desc *pwdn_gpio; /* PWDNB pin. */ + struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */ + /* To serialize asynchronus callbacks */ struct mutex mutex; @@ -2500,6 +2505,23 @@ static int ov5670_regulators_probe(struct ov5670 *ov5670) ov5670->supplies); } +static int ov5670_gpio_probe(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + + ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(ov5670->pwdn_gpio)) + return PTR_ERR(ov5670->pwdn_gpio); + + ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov5670->reset_gpio)) + return PTR_ERR(ov5670->reset_gpio); + + return 0; +} + static int ov5670_probe(struct i2c_client *client) { struct ov5670 *ov5670; @@ -2540,6 +2562,12 @@ static int ov5670_probe(struct i2c_client *client) goto error_print; } + ret = ov5670_gpio_probe(ov5670); + if (ret) { + err_msg = "GPIO probe failed"; + goto error_print; + } + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { /* Check module identity */ From 62ab1e32597851450c9d42aab6aaf96f397d0d15 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:06 +0100 Subject: [PATCH 060/216] media: i2c: ov5670: Add runtime_pm operations Implement the runtime resume and suspend routines and install them as runtime_pm handlers. While at it rework the probe() sequence in order to enable runtime_pm before registering the async subdevice. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 78 +++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 0290f33f619d..47fedbe37ced 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017 Intel Corporation. +#include #include #include +#include #include #include #include @@ -2429,6 +2431,49 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) return ret; } +static int __maybe_unused ov5670_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5670 *ov5670 = to_ov5670(sd); + unsigned long delay_us; + int ret; + + ret = clk_prepare_enable(ov5670->xvclk); + if (ret) + return ret; + + ret = regulator_bulk_enable(OV5670_NUM_SUPPLIES, ov5670->supplies); + if (ret) { + clk_disable_unprepare(ov5670->xvclk); + return ret; + } + + gpiod_set_value_cansleep(ov5670->pwdn_gpio, 0); + gpiod_set_value_cansleep(ov5670->reset_gpio, 0); + + /* 8192 * 2 clock pulses before the first SCCB transaction. */ + delay_us = DIV_ROUND_UP(8192 * 2 * 1000, + DIV_ROUND_UP(OV5670_XVCLK_FREQ, 1000)); + fsleep(delay_us); + + return 0; +} + +static int __maybe_unused ov5670_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5670 *ov5670 = to_ov5670(sd); + + gpiod_set_value_cansleep(ov5670->reset_gpio, 1); + gpiod_set_value_cansleep(ov5670->pwdn_gpio, 1); + regulator_bulk_disable(OV5670_NUM_SUPPLIES, ov5670->supplies); + clk_disable_unprepare(ov5670->xvclk); + + return 0; +} + static int __maybe_unused ov5670_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); @@ -2570,11 +2615,17 @@ static int ov5670_probe(struct i2c_client *client) full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + ret = ov5670_runtime_resume(&client->dev); + if (ret) { + err_msg = "Power up failed"; + goto error_print; + } + /* Check module identity */ ret = ov5670_identify_module(ov5670); if (ret) { err_msg = "ov5670_identify_module() error"; - goto error_print; + goto error_power_off; } } @@ -2603,24 +2654,27 @@ static int ov5670_probe(struct i2c_client *client) goto error_handler_free; } - /* Async register for subdev */ - ret = v4l2_async_register_subdev_sensor(&ov5670->sd); - if (ret < 0) { - err_msg = "v4l2_async_register_subdev() error"; - goto error_entity_cleanup; - } - ov5670->streaming = false; /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); + + /* Async register for subdev */ + ret = v4l2_async_register_subdev_sensor(&ov5670->sd); + if (ret < 0) { + err_msg = "v4l2_async_register_subdev() error"; + goto error_pm_disable; + } + pm_runtime_idle(&client->dev); return 0; -error_entity_cleanup: +error_pm_disable: + pm_runtime_disable(&client->dev); + media_entity_cleanup(&ov5670->sd.entity); error_handler_free: @@ -2629,6 +2683,10 @@ static int ov5670_probe(struct i2c_client *client) error_mutex_destroy: mutex_destroy(&ov5670->mutex); +error_power_off: + if (full_power) + ov5670_runtime_suspend(&client->dev); + error_print: dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret); @@ -2646,10 +2704,12 @@ static void ov5670_remove(struct i2c_client *client) mutex_destroy(&ov5670->mutex); pm_runtime_disable(&client->dev); + ov5670_runtime_suspend(&client->dev); } static const struct dev_pm_ops ov5670_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume) + SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL) }; #ifdef CONFIG_ACPI From bbc6071c4c65f8850dce05c54700afbf56e763a9 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:07 +0100 Subject: [PATCH 061/216] media: i2c: ov5670: Implement init_cfg Implement the .init_cfg() pad operation and initialize the default format with the default full resolution mode 2592x1944. With .init_cfg() pad operation implemented the deprecated .open() internal operation can now be dropped. Signed-off-by: Jacopo Mondi Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 46 +++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 47fedbe37ced..898f564e0c3e 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1962,27 +1962,6 @@ static int ov5670_write_reg_list(struct ov5670 *ov5670, return ov5670_write_regs(ov5670, r_list->regs, r_list->num_of_regs); } -/* Open sub-device */ -static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct ov5670 *ov5670 = to_ov5670(sd); - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); - - mutex_lock(&ov5670->mutex); - - /* Initialize try_fmt */ - try_fmt->width = ov5670->cur_mode->width; - try_fmt->height = ov5670->cur_mode->height; - try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - try_fmt->field = V4L2_FIELD_NONE; - - /* No crop or compose */ - mutex_unlock(&ov5670->mutex); - - return 0; -} - static int ov5670_update_digital_gain(struct ov5670 *ov5670, u32 d_gain) { int ret; @@ -2182,6 +2161,25 @@ static int ov5670_init_controls(struct ov5670 *ov5670) return ret; } +static int ov5670_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_try_format(sd, state, 0); + const struct ov5670_mode *default_mode = &supported_modes[0]; + + fmt->width = default_mode->width; + fmt->height = default_mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); + + return 0; +} + static int ov5670_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -2513,6 +2511,7 @@ static const struct v4l2_subdev_video_ops ov5670_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5670_pad_ops = { + .init_cfg = ov5670_init_cfg, .enum_mbus_code = ov5670_enum_mbus_code, .get_fmt = ov5670_get_pad_format, .set_fmt = ov5670_set_pad_format, @@ -2534,10 +2533,6 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static const struct v4l2_subdev_internal_ops ov5670_internal_ops = { - .open = ov5670_open, -}; - static int ov5670_regulators_probe(struct ov5670 *ov5670) { struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); @@ -2640,7 +2635,6 @@ static int ov5670_probe(struct i2c_client *client) goto error_mutex_destroy; } - ov5670->sd.internal_ops = &ov5670_internal_ops; ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ov5670->sd.entity.ops = &ov5670_subdev_entity_ops; From 2eadd98dd4de7f983f0fc96586a4a914329fc811 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Thu, 26 Jan 2023 17:59:08 +0100 Subject: [PATCH 062/216] media: i2c: ov5670: Add .get_selection() support Add support for the .get_selection() pad operation to the ov5670 sensor driver. Report the native sensor size (pixel array), the crop bounds (readable pixel array area) and the current and default analog crop rectangles. Currently all driver's modes use an analog crop rectangle of size [12, 4, 2600, 1952]. Instead of hardcoding the value in the operation implementation, ad an .analog_crop field to the sensor's modes definitions, to make sure that if any mode gets added, its crop rectangle will be defined as well. While at it re-sort the modes' field definition order to match the declaration order and initialize the crop rectangle in init_cfg(). [Sakari Ailus: Fix a typo on comments (03800 -> 0x3800)] Signed-off-by: Jean-Michel Hautbois Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 89 +++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 898f564e0c3e..c26ca6200c27 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -74,6 +74,10 @@ #define OV5670_REG_VALUE_16BIT 2 #define OV5670_REG_VALUE_24BIT 3 +/* Pixel Array */ +#define OV5670_NATIVE_WIDTH 2624 +#define OV5670_NATIVE_HEIGHT 1980 + /* Initial number of frames to skip to avoid possible garbage */ #define OV5670_NUM_OF_SKIP_FRAMES 2 @@ -116,10 +120,25 @@ struct ov5670_mode { /* Link frequency needed for this resolution */ u32 link_freq_index; + /* Analog crop rectangle */ + const struct v4l2_rect *analog_crop; + /* Sensor register settings for this resolution */ const struct ov5670_reg_list reg_list; }; +/* + * All the modes supported by the driver are obtained by subsampling the + * full pixel array. The below values are reflected in registers from + * 0x3800-0x3807 in the modes register-value tables. + */ +static const struct v4l2_rect ov5670_analog_crop = { + .left = 12, + .top = 4, + .width = 2600, + .height = 1952, +}; + static const struct ov5670_reg mipi_data_rate_840mbps[] = { {0x0300, 0x04}, {0x0301, 0x00}, @@ -1767,66 +1786,73 @@ static const struct ov5670_mode supported_modes[] = { .height = 1944, .vts_def = OV5670_VTS_30FPS, .vts_min = OV5670_VTS_30FPS, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), .regs = mode_2592x1944_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 1296, .height = 972, .vts_def = OV5670_VTS_30FPS, .vts_min = 996, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), .regs = mode_1296x972_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 648, .height = 486, .vts_def = OV5670_VTS_30FPS, .vts_min = 516, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_648x486_regs), .regs = mode_648x486_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 2560, .height = 1440, .vts_def = OV5670_VTS_30FPS, .vts_min = OV5670_VTS_30FPS, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2560x1440_regs), .regs = mode_2560x1440_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 1280, .height = 720, .vts_def = OV5670_VTS_30FPS, .vts_min = 1020, + + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), .regs = mode_1280x720_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 640, .height = 360, .vts_def = OV5670_VTS_30FPS, .vts_min = 510, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_640x360_regs), .regs = mode_640x360_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, } }; @@ -2167,6 +2193,7 @@ static int ov5670_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt = v4l2_subdev_get_try_format(sd, state, 0); const struct ov5670_mode *default_mode = &supported_modes[0]; + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); fmt->width = default_mode->width; fmt->height = default_mode->height; @@ -2177,6 +2204,8 @@ static int ov5670_init_cfg(struct v4l2_subdev *sd, fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); + *crop = *default_mode->analog_crop; + return 0; } @@ -2506,6 +2535,52 @@ static const struct v4l2_subdev_core_ops ov5670_core_ops = { .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; +static const struct v4l2_rect * +__ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + const struct ov5670_mode *mode = sensor->cur_mode; + + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(&sensor->sd, state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return mode->analog_crop; + } + + return NULL; +} + +static int ov5670_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ov5670 *sensor = to_ov5670(subdev); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + mutex_lock(&sensor->mutex); + sel->r = *__ov5670_get_pad_crop(sensor, state, sel->pad, + sel->which); + mutex_unlock(&sensor->mutex); + break; + case V4L2_SEL_TGT_NATIVE_SIZE: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV5670_NATIVE_WIDTH; + sel->r.height = OV5670_NATIVE_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r = ov5670_analog_crop; + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct v4l2_subdev_video_ops ov5670_video_ops = { .s_stream = ov5670_set_stream, }; @@ -2516,6 +2591,8 @@ static const struct v4l2_subdev_pad_ops ov5670_pad_ops = { .get_fmt = ov5670_get_pad_format, .set_fmt = ov5670_set_pad_format, .enum_frame_size = ov5670_enum_frame_size, + .get_selection = ov5670_get_selection, + .set_selection = ov5670_get_selection, }; static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = { From c5b6f99c91a24c09cc8048b74d40477caad9690c Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Jan 2023 17:59:09 +0100 Subject: [PATCH 063/216] media: i2c: ov5670: Handle RO controls in set_ctrl The ov5670 driver registers three controls as read-only: - V4L2_CID_PIXEL_RATE - V4L2_CID_LINK_FREQ - V4L2_CID_HBLANK The driver updates the range of HBLANK with __v4l2_ctrl_modify_range() and updates the values of PIXEL_RATE and LINK_FREQ with an explicit call to __v4l2_ctrl_s_ctrl() in ov5670_set_pad_format() time. This causes the .set_ctrl handler to be called on these controls causing a non-fatal warning to be emitted: ov5670_set_ctrl Unhandled id:0x9e0902, val:0x824 This is currently only critical for HBLANK, as LINK_FREQ and PIXEL_RATE currently only support a single value, and the v4l2-ctrl framework skips calling .set_ctrl() if the current control value is not changed. Expand the ov5670_set_ctrl() callback to handle the above controls to remove the above warning and defend against future expansions of the supported pixel rates and link frequencies. Also be stricter and return an error value if a control is actually not handled. Reported-by: Luca Weiss Signed-off-by: Jacopo Mondi Tested-by: Luca Weiss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index c26ca6200c27..f79d908f4531 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2038,7 +2038,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) struct ov5670, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); s64 max; - int ret = 0; + int ret; /* Propagate change of current control to all related controls */ switch (ctrl->id) { @@ -2077,7 +2077,13 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: ret = ov5670_enable_test_pattern(ov5670, ctrl->val); break; + case V4L2_CID_HBLANK: + case V4L2_CID_LINK_FREQ: + case V4L2_CID_PIXEL_RATE: + ret = 0; + break; default: + ret = -EINVAL; dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; From 909d3096ac99fa2289f9b8945a3eab2269947a0a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 21 Dec 2022 09:30:11 +0100 Subject: [PATCH 064/216] media: ipu3-cio2: Fix PM runtime usage_count in driver unbind Get the PM runtime usage_count and forbid PM runtime at driver unbind. The opposite is being done in probe() already. Fixes: commit c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Cc: stable@vger.kernel.org # for >= 4.16 Signed-off-by: Sakari Ailus Reviewed-by: Bingbu Cao Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 390bd5ea3472..3b76a9d0383a 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1843,6 +1843,9 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) v4l2_device_unregister(&cio2->v4l2_dev); media_device_cleanup(&cio2->media_dev); mutex_destroy(&cio2->lock); + + pm_runtime_forbid(&pci_dev->dev); + pm_runtime_get_noresume(&pci_dev->dev); } static int __maybe_unused cio2_runtime_suspend(struct device *dev) From 7993dc12d6f2a49b03868e5ada895ad69c52bd23 Mon Sep 17 00:00:00 2001 From: Michael Riesch Date: Mon, 30 Jan 2023 09:47:09 +0100 Subject: [PATCH 065/216] media: dt-bindings: media: i2c: add imx415 cmos image sensor Add devicetree binding for the Sony IMX415 CMOS image sensor. Signed-off-by: Michael Riesch Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/sony,imx415.yaml | 122 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 129 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml new file mode 100644 index 000000000000..ffccf5f3c9e3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx415.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX415 CMOS Image Sensor + +maintainers: + - Michael Riesch + +description: |- + The Sony IMX415 is a diagonal 6.4 mm (Type 1/2.8) CMOS active pixel type + solid-state image sensor with a square pixel array and 8.46 M effective + pixels. This chip operates with analog 2.9 V, digital 1.1 V, and interface + 1.8 V triple power supply, and has low power consumption. + The IMX415 is programmable through I2C interface. The sensor output is + available via CSI-2 serial data output (two or four lanes). + +allOf: + - $ref: ../video-interface-devices.yaml# + +properties: + compatible: + const: sony,imx415 + + reg: + maxItems: 1 + + clocks: + description: Input clock (24 MHz, 27 MHz, 37.125 MHz, 72 MHz or 74.25 MHz) + maxItems: 1 + + avdd-supply: + description: Analog power supply (2.9 V) + + dvdd-supply: + description: Digital power supply (1.1 V) + + ovdd-supply: + description: Interface power supply (1.8 V) + + reset-gpios: + description: Sensor reset (XCLR) GPIO + maxItems: 1 + + flash-leds: true + + lens-focus: true + + orientation: true + + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + oneOf: + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - avdd-supply + - dvdd-supply + - ovdd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imx415: camera-sensor@1a { + compatible = "sony,imx415"; + reg = <0x1a>; + avdd-supply = <&vcc2v9_cam>; + clocks = <&clock_cam>; + dvdd-supply = <&vcc1v1_cam>; + lens-focus = <&vcm>; + orientation = <2>; + ovdd-supply = <&vcc1v8_cam>; + reset-gpios = <&gpio_expander 14 GPIO_ACTIVE_LOW>; + rotation = <180>; + + port { + imx415_ep: endpoint { + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <445500000>; + remote-endpoint = <&mipi_in>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 6406e23772da..4777678ca000 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19505,6 +19505,13 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c +SONY IMX415 SENSOR DRIVER +M: Michael Riesch +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky M: Alex Dubov From 14cd15e7a1e2a321f6184124bee95560035db4ef Mon Sep 17 00:00:00 2001 From: Gerald Loacker Date: Mon, 30 Jan 2023 09:47:10 +0100 Subject: [PATCH 066/216] media: i2c: add imx415 cmos image sensor driver Add driver for the Sony IMX415 CMOS image sensor. Signed-off-by: Gerald Loacker Co-developed-by: Michael Riesch Signed-off-by: Michael Riesch Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 14 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/imx415.c | 1300 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1316 insertions(+) create mode 100644 drivers/media/i2c/imx415.c diff --git a/MAINTAINERS b/MAINTAINERS index 4777678ca000..759ba6205117 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19511,6 +19511,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml +F: drivers/media/i2c/imx415.c SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 438bb506017f..c3d5952ca27e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -241,6 +241,20 @@ config VIDEO_IMX412 To compile this driver as a module, choose M here: the module will be called imx412. +config VIDEO_IMX415 + tristate "Sony IMX415 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_DEV + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX415 camera. + + To compile this driver as a module, choose M here: the + module will be called imx415. + config VIDEO_MAX9271_LIB tristate diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 28178d4c512a..4f5e9d9cee85 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_VIDEO_IMX334) += imx334.o obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o +obj-$(CONFIG_VIDEO_IMX415) += imx415.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c new file mode 100644 index 000000000000..d90392df98c7 --- /dev/null +++ b/drivers/media/i2c/imx415.c @@ -0,0 +1,1300 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the Sony IMX415 CMOS Image Sensor. + * + * Copyright (C) 2023 WolfVision GmbH. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define IMX415_PIXEL_ARRAY_TOP 0 +#define IMX415_PIXEL_ARRAY_LEFT 0 +#define IMX415_PIXEL_ARRAY_WIDTH 3864 +#define IMX415_PIXEL_ARRAY_HEIGHT 2192 +#define IMX415_PIXEL_ARRAY_VBLANK 58 + +#define IMX415_NUM_CLK_PARAM_REGS 11 + +#define IMX415_REG_8BIT(n) ((1 << 16) | (n)) +#define IMX415_REG_16BIT(n) ((2 << 16) | (n)) +#define IMX415_REG_24BIT(n) ((3 << 16) | (n)) +#define IMX415_REG_SIZE_SHIFT 16 +#define IMX415_REG_ADDR_MASK 0xffff + +#define IMX415_MODE IMX415_REG_8BIT(0x3000) +#define IMX415_MODE_OPERATING (0) +#define IMX415_MODE_STANDBY BIT(0) +#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001) +#define IMX415_REGHOLD_INVALID (0) +#define IMX415_REGHOLD_VALID BIT(0) +#define IMX415_XMSTA IMX415_REG_8BIT(0x3002) +#define IMX415_XMSTA_START (0) +#define IMX415_XMSTA_STOP BIT(0) +#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008) +#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A) +#define IMX415_WINMODE IMX415_REG_8BIT(0x301C) +#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022) +#define IMX415_REVERSE IMX415_REG_8BIT(0x3030) +#define IMX415_HREVERSE_SHIFT (0) +#define IMX415_VREVERSE_SHIFT BIT(0) +#define IMX415_ADBIT IMX415_REG_8BIT(0x3031) +#define IMX415_MDBIT IMX415_REG_8BIT(0x3032) +#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033) +#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0) +#define IMX415_DRV IMX415_REG_8BIT(0x30C1) +#define IMX415_VMAX IMX415_REG_24BIT(0x3024) +#define IMX415_HMAX IMX415_REG_16BIT(0x3028) +#define IMX415_SHR0 IMX415_REG_24BIT(0x3050) +#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) +#define IMX415_AGAIN_MIN 0 +#define IMX415_AGAIN_MAX 100 +#define IMX415_AGAIN_STEP 1 +#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2) +#define IMX415_BLKLEVEL_DEFAULT 50 +#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4) +#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6) +#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8) +#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110) +#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115) +#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116) +#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118) +#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A) +#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E) +#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8) +#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390) +#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12) +#define IMX415_SENSOR_INFO_MASK 0xFFF +#define IMX415_CHIP_ID 0x514 +#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001) +#define IMX415_LANEMODE_2 1 +#define IMX415_LANEMODE_4 3 +#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004) +#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C) +#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018) +#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A) +#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C) +#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E) +#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020) +#define IMX415_THSZERO IMX415_REG_16BIT(0x4022) +#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024) +#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026) +#define IMX415_TLPX IMX415_REG_16BIT(0x4028) +#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074) + +struct imx415_reg { + u32 address; + u32 val; +}; + +static const char *const imx415_supply_names[] = { + "dvdd", + "ovdd", + "avdd", +}; + +/* + * The IMX415 data sheet uses lane rates but v4l2 uses link frequency to + * describe MIPI CSI-2 speed. This driver uses lane rates wherever possible + * and converts them to link frequencies by a factor of two when needed. + */ +static const s64 link_freq_menu_items[] = { + 594000000 / 2, 720000000 / 2, 891000000 / 2, + 1440000000 / 2, 1485000000 / 2, +}; + +struct imx415_clk_params { + u64 lane_rate; + u64 inck; + struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS]; +}; + +/* INCK Settings - includes all lane rate and INCK dependent registers */ +static const struct imx415_clk_params imx415_clk_params[] = { + { + .lane_rate = 594000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x084 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 720000000, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, + .regs[2] = { IMX415_SYS_MODE, 0x9 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0B4 }, + .regs[6] = { IMX415_INCKSEL4, 0x0FC }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { + .lane_rate = 891000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C6 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 1440000000, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0B4 }, + .regs[6] = { IMX415_INCKSEL4, 0x0FC }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { + .lane_rate = 1485000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A5 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, +}; + +/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ +static const struct imx415_reg imx415_mode_2_720[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x07F0 }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x006F }, + { IMX415_TCLKPREPARE, 0x002F }, + { IMX415_TCLKTRAIL, 0x002F }, + { IMX415_TCLKZERO, 0x00BF }, + { IMX415_THSPREPARE, 0x002F }, + { IMX415_THSZERO, 0x0057 }, + { IMX415_THSTRAIL, 0x002F }, + { IMX415_THSEXIT, 0x004F }, + { IMX415_TLPX, 0x0027 }, +}; + +/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ +static const struct imx415_reg imx415_mode_2_1440[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x042A }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x009F }, + { IMX415_TCLKPREPARE, 0x0057 }, + { IMX415_TCLKTRAIL, 0x0057 }, + { IMX415_TCLKZERO, 0x0187 }, + { IMX415_THSPREPARE, 0x005F }, + { IMX415_THSZERO, 0x00A7 }, + { IMX415_THSTRAIL, 0x005F }, + { IMX415_THSEXIT, 0x0097 }, + { IMX415_TLPX, 0x004F }, +}; + +/* all-pixel 4-lane 891 Mbps 30 Hz mode */ +static const struct imx415_reg imx415_mode_4_891[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x044C }, + { IMX415_LANEMODE, IMX415_LANEMODE_4 }, + { IMX415_TCLKPOST, 0x007F }, + { IMX415_TCLKPREPARE, 0x0037 }, + { IMX415_TCLKTRAIL, 0x0037 }, + { IMX415_TCLKZERO, 0x00F7 }, + { IMX415_THSPREPARE, 0x003F }, + { IMX415_THSZERO, 0x006F }, + { IMX415_THSTRAIL, 0x003F }, + { IMX415_THSEXIT, 0x005F }, + { IMX415_TLPX, 0x002F }, +}; + +struct imx415_mode_reg_list { + u32 num_of_regs; + const struct imx415_reg *regs; +}; + +/* + * Mode : number of lanes, lane rate and frame rate dependent settings + * + * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl + * interface. These values can not be found in the data sheet and should be + * treated as virtual values. Use following table when adding new modes. + * + * lane_rate lanes fps hmax_pix pixel_rate + * + * 594 2 10.000 4400 99000000 + * 891 2 15.000 4400 148500000 + * 720 2 15.748 4064 144000000 + * 1782 2 30.000 4400 297000000 + * 2079 2 30.000 4400 297000000 + * 1440 2 30.019 4510 304615385 + * + * 594 4 20.000 5500 247500000 + * 594 4 25.000 4400 247500000 + * 720 4 25.000 4400 247500000 + * 720 4 30.019 4510 304615385 + * 891 4 30.000 4400 297000000 + * 1440 4 30.019 4510 304615385 + * 1440 4 60.038 4510 609230769 + * 1485 4 60.000 4400 594000000 + * 1782 4 60.000 4400 594000000 + * 2079 4 60.000 4400 594000000 + * 2376 4 90.164 4392 891000000 + */ +struct imx415_mode { + u64 lane_rate; + u32 lanes; + u32 hmax_pix; + u64 pixel_rate; + struct imx415_mode_reg_list reg_list; +}; + +/* mode configs */ +static const struct imx415_mode supported_modes[] = { + { + .lane_rate = 720000000, + .lanes = 2, + .hmax_pix = 4064, + .pixel_rate = 144000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_720), + .regs = imx415_mode_2_720, + }, + }, + { + .lane_rate = 1440000000, + .lanes = 2, + .hmax_pix = 4510, + .pixel_rate = 304615385, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440), + .regs = imx415_mode_2_1440, + }, + }, + { + .lane_rate = 891000000, + .lanes = 4, + .hmax_pix = 4400, + .pixel_rate = 297000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_4_891), + .regs = imx415_mode_4_891, + }, + }, +}; + +static const struct regmap_config imx415_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const char *const imx415_test_pattern_menu[] = { + "disabled", + "solid black", + "solid white", + "solid dark gray", + "solid light gray", + "stripes light/dark grey", + "stripes dark/light grey", + "stripes black/dark grey", + "stripes dark grey/black", + "stripes black/white", + "stripes white/black", + "horizontal color bar", + "vertical color bar", +}; + +struct imx415 { + struct device *dev; + struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)]; + struct gpio_desc *reset; + struct regmap *regmap; + + const struct imx415_clk_params *clk_params; + + bool streaming; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + + unsigned int cur_mode; + unsigned int num_data_lanes; +}; + +/* + * This table includes fixed register settings and a bunch of undocumented + * registers that have to be set to another value than default. + */ +static const struct imx415_reg imx415_init_table[] = { + /* use all-pixel readout mode, no flip */ + { IMX415_WINMODE, 0x00 }, + { IMX415_ADDMODE, 0x00 }, + { IMX415_REVERSE, 0x00 }, + /* use RAW 10-bit mode */ + { IMX415_ADBIT, 0x00 }, + { IMX415_MDBIT, 0x00 }, + /* output VSYNC on XVS and low on XHS */ + { IMX415_OUTSEL, 0x22 }, + { IMX415_DRV, 0x00 }, + + /* SONY magic registers */ + { IMX415_REG_8BIT(0x32D4), 0x21 }, + { IMX415_REG_8BIT(0x32EC), 0xA1 }, + { IMX415_REG_8BIT(0x3452), 0x7F }, + { IMX415_REG_8BIT(0x3453), 0x03 }, + { IMX415_REG_8BIT(0x358A), 0x04 }, + { IMX415_REG_8BIT(0x35A1), 0x02 }, + { IMX415_REG_8BIT(0x36BC), 0x0C }, + { IMX415_REG_8BIT(0x36CC), 0x53 }, + { IMX415_REG_8BIT(0x36CD), 0x00 }, + { IMX415_REG_8BIT(0x36CE), 0x3C }, + { IMX415_REG_8BIT(0x36D0), 0x8C }, + { IMX415_REG_8BIT(0x36D1), 0x00 }, + { IMX415_REG_8BIT(0x36D2), 0x71 }, + { IMX415_REG_8BIT(0x36D4), 0x3C }, + { IMX415_REG_8BIT(0x36D6), 0x53 }, + { IMX415_REG_8BIT(0x36D7), 0x00 }, + { IMX415_REG_8BIT(0x36D8), 0x71 }, + { IMX415_REG_8BIT(0x36DA), 0x8C }, + { IMX415_REG_8BIT(0x36DB), 0x00 }, + { IMX415_REG_8BIT(0x3724), 0x02 }, + { IMX415_REG_8BIT(0x3726), 0x02 }, + { IMX415_REG_8BIT(0x3732), 0x02 }, + { IMX415_REG_8BIT(0x3734), 0x03 }, + { IMX415_REG_8BIT(0x3736), 0x03 }, + { IMX415_REG_8BIT(0x3742), 0x03 }, + { IMX415_REG_8BIT(0x3862), 0xE0 }, + { IMX415_REG_8BIT(0x38CC), 0x30 }, + { IMX415_REG_8BIT(0x38CD), 0x2F }, + { IMX415_REG_8BIT(0x395C), 0x0C }, + { IMX415_REG_8BIT(0x3A42), 0xD1 }, + { IMX415_REG_8BIT(0x3A4C), 0x77 }, + { IMX415_REG_8BIT(0x3AE0), 0x02 }, + { IMX415_REG_8BIT(0x3AEC), 0x0C }, + { IMX415_REG_8BIT(0x3B00), 0x2E }, + { IMX415_REG_8BIT(0x3B06), 0x29 }, + { IMX415_REG_8BIT(0x3B98), 0x25 }, + { IMX415_REG_8BIT(0x3B99), 0x21 }, + { IMX415_REG_8BIT(0x3B9B), 0x13 }, + { IMX415_REG_8BIT(0x3B9C), 0x13 }, + { IMX415_REG_8BIT(0x3B9D), 0x13 }, + { IMX415_REG_8BIT(0x3B9E), 0x13 }, + { IMX415_REG_8BIT(0x3BA1), 0x00 }, + { IMX415_REG_8BIT(0x3BA2), 0x06 }, + { IMX415_REG_8BIT(0x3BA3), 0x0B }, + { IMX415_REG_8BIT(0x3BA4), 0x10 }, + { IMX415_REG_8BIT(0x3BA5), 0x14 }, + { IMX415_REG_8BIT(0x3BA6), 0x18 }, + { IMX415_REG_8BIT(0x3BA7), 0x1A }, + { IMX415_REG_8BIT(0x3BA8), 0x1A }, + { IMX415_REG_8BIT(0x3BA9), 0x1A }, + { IMX415_REG_8BIT(0x3BAC), 0xED }, + { IMX415_REG_8BIT(0x3BAD), 0x01 }, + { IMX415_REG_8BIT(0x3BAE), 0xF6 }, + { IMX415_REG_8BIT(0x3BAF), 0x02 }, + { IMX415_REG_8BIT(0x3BB0), 0xA2 }, + { IMX415_REG_8BIT(0x3BB1), 0x03 }, + { IMX415_REG_8BIT(0x3BB2), 0xE0 }, + { IMX415_REG_8BIT(0x3BB3), 0x03 }, + { IMX415_REG_8BIT(0x3BB4), 0xE0 }, + { IMX415_REG_8BIT(0x3BB5), 0x03 }, + { IMX415_REG_8BIT(0x3BB6), 0xE0 }, + { IMX415_REG_8BIT(0x3BB7), 0x03 }, + { IMX415_REG_8BIT(0x3BB8), 0xE0 }, + { IMX415_REG_8BIT(0x3BBA), 0xE0 }, + { IMX415_REG_8BIT(0x3BBC), 0xDA }, + { IMX415_REG_8BIT(0x3BBE), 0x88 }, + { IMX415_REG_8BIT(0x3BC0), 0x44 }, + { IMX415_REG_8BIT(0x3BC2), 0x7B }, + { IMX415_REG_8BIT(0x3BC4), 0xA2 }, + { IMX415_REG_8BIT(0x3BC8), 0xBD }, + { IMX415_REG_8BIT(0x3BCA), 0xBD }, +}; + +static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) +{ + return container_of(sd, struct imx415, subdev); +} + +static int imx415_read(struct imx415 *sensor, u32 addr) +{ + u8 data[3] = { 0 }; + int ret; + + ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data, + (addr >> IMX415_REG_SIZE_SHIFT) & 3); + if (ret < 0) + return ret; + + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static int imx415_write(struct imx415 *sensor, u32 addr, u32 value) +{ + u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; + int ret; + + ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK, + data, (addr >> IMX415_REG_SIZE_SHIFT) & 3); + if (ret < 0) + dev_err_ratelimited(sensor->dev, + "%u-bit write to 0x%04x failed: %d\n", + ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8, + addr & IMX415_REG_ADDR_MASK, ret); + + return 0; +} + +static int imx415_set_testpattern(struct imx415 *sensor, int val) +{ + int ret; + + if (val) { + ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00); + } else { + ret = imx415_write(sensor, IMX415_BLKLEVEL, + IMX415_BLKLEVEL_DEFAULT); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01); + } + return 0; +} + +static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx415 *sensor = container_of(ctrl->handler, struct imx415, + ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int vmax; + unsigned int flip; + + if (!sensor->streaming) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->subdev); + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* clamp the exposure value to VMAX. */ + vmax = format->height + sensor->vblank->cur.val; + ctrl->val = min_t(int, ctrl->val, vmax); + return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + + case V4L2_CID_ANALOGUE_GAIN: + /* analogue gain in 0.3 dB step size */ + return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | + (sensor->vflip->val << IMX415_VREVERSE_SHIFT); + return imx415_write(sensor, IMX415_REVERSE, flip); + + case V4L2_CID_TEST_PATTERN: + return imx415_set_testpattern(sensor, ctrl->val); + + default: + return -EINVAL; + } +} + +static const struct v4l2_ctrl_ops imx415_ctrl_ops = { + .s_ctrl = imx415_s_ctrl, +}; + +static int imx415_ctrls_init(struct imx415 *sensor) +{ + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *ctrl; + u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate; + u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate; + u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT + + IMX415_PIXEL_ARRAY_VBLANK - 8; + u32 hblank; + unsigned int i; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&sensor->ctrls, 10); + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); ++i) { + if (lane_rate == link_freq_menu_items[i] * 2) + break; + } + if (i == ARRAY_SIZE(link_freq_menu_items)) { + return dev_err_probe(sensor->dev, -EINVAL, + "lane rate %llu not supported\n", + lane_rate); + } + + ctrl = v4l2_ctrl_new_int_menu(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, i, + link_freq_menu_items); + + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE, + 4, exposure_max, 1, exposure_max); + + v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN, + IMX415_AGAIN_MAX, IMX415_AGAIN_STEP, + IMX415_AGAIN_MIN); + + hblank = supported_modes[sensor->cur_mode].hmax_pix - + IMX415_PIXEL_ARRAY_WIDTH; + ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, 1, hblank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VBLANK, + IMX415_PIXEL_ARRAY_VBLANK, + IMX415_PIXEL_ARRAY_VBLANK, 1, + IMX415_PIXEL_ARRAY_VBLANK); + if (sensor->vblank) + sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* + * The pixel rate used here is a virtual value and can be used for + * calculating the frame rate together with hblank. It may not + * necessarily be the physically correct pixel clock. + */ + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx415_test_pattern_menu) - 1, + 0, 0, imx415_test_pattern_menu); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx415_ctrl_ops, + &props); + + if (sensor->ctrls.error) { + dev_err_probe(sensor->dev, sensor->ctrls.error, + "failed to add controls\n"); + v4l2_ctrl_handler_free(&sensor->ctrls); + return sensor->ctrls.error; + } + sensor->subdev.ctrl_handler = &sensor->ctrls; + + return 0; +} + +static int imx415_set_mode(struct imx415 *sensor, int mode) +{ + const struct imx415_reg *reg; + unsigned int i; + int ret = 0; + + if (mode >= ARRAY_SIZE(supported_modes)) { + dev_err(sensor->dev, "Mode %d not supported\n", mode); + return -EINVAL; + } + + for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) { + reg = &supported_modes[mode].reg_list.regs[i]; + ret = imx415_write(sensor, reg->address, reg->val); + if (ret) + return ret; + } + + for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) { + reg = &sensor->clk_params->regs[i]; + ret = imx415_write(sensor, reg->address, reg->val); + if (ret) + return ret; + } + + return 0; +} + +static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) { + ret = imx415_write(sensor, imx415_init_table[i].address, + imx415_init_table[i].val); + if (ret) + return ret; + } + + return imx415_set_mode(sensor, sensor->cur_mode); +} + +static int imx415_wakeup(struct imx415 *sensor) +{ + int ret; + + ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING); + if (ret) + return ret; + + /* + * According to the datasheet we have to wait at least 63 us after + * leaving standby mode. But this doesn't work even after 30 ms. + * So probably this should be 63 ms and therefore we wait for 80 ms. + */ + msleep(80); + + return 0; +} + +static int imx415_stream_on(struct imx415 *sensor) +{ + int ret; + + ret = imx415_wakeup(sensor); + if (ret) + return ret; + + return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START); +} + +static int imx415_stream_off(struct imx415 *sensor) +{ + int ret; + + ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP); + if (ret) + return ret; + + return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); +} + +static int imx415_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx415 *sensor = to_imx415(sd); + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (!enable) { + ret = imx415_stream_off(sensor); + + pm_runtime_mark_last_busy(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + sensor->streaming = false; + + goto unlock; + } + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret < 0) + goto unlock; + + ret = imx415_setup(sensor, state); + if (ret) + goto err_pm; + + /* + * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set + * the controls. The flag is reset to false further down if an error + * occurs. + */ + sensor->streaming = true; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); + if (ret < 0) + goto err_pm; + + ret = imx415_stream_on(sensor); + if (ret) + goto err_pm; + + ret = 0; + +unlock: + v4l2_subdev_unlock_state(state); + + return ret; + +err_pm: + /* + * In case of error, turn the power off synchronously as the device + * likely has no other chance to recover. + */ + pm_runtime_put_sync(sensor->dev); + sensor->streaming = false; + + goto unlock; +} + +static int imx415_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGBRG10_1X10; + + return 0; +} + +static int imx415_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + + if (fse->index > 0 || fse->code != format->code) + return -EINVAL; + + fse->min_width = IMX415_PIXEL_ARRAY_WIDTH; + fse->max_width = fse->min_width; + fse->min_height = IMX415_PIXEL_ARRAY_HEIGHT; + fse->max_height = fse->min_height; + return 0; +} + +static int imx415_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + return 0; +} + +static int imx415_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + format->width = fmt->format.width; + format->height = fmt->format.height; + format->code = MEDIA_BUS_FMT_SGBRG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_DEFAULT; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + fmt->format = *format; + return 0; +} + +static int imx415_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: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX415_PIXEL_ARRAY_TOP; + sel->r.left = IMX415_PIXEL_ARRAY_LEFT; + sel->r.width = IMX415_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX415_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +static int imx415_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format format = { + .format = { + .width = IMX415_PIXEL_ARRAY_WIDTH, + .height = IMX415_PIXEL_ARRAY_HEIGHT, + }, + }; + + imx415_set_format(sd, state, &format); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = { + .s_stream = imx415_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = { + .enum_mbus_code = imx415_enum_mbus_code, + .enum_frame_size = imx415_enum_frame_size, + .get_fmt = imx415_get_format, + .set_fmt = imx415_set_format, + .get_selection = imx415_get_selection, + .init_cfg = imx415_init_cfg, +}; + +static const struct v4l2_subdev_ops imx415_subdev_ops = { + .video = &imx415_subdev_video_ops, + .pad = &imx415_subdev_pad_ops, +}; + +static int imx415_subdev_init(struct imx415 *sensor) +{ + struct i2c_client *client = to_i2c_client(sensor->dev); + int ret; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops); + + ret = imx415_ctrls_init(sensor); + if (ret) + return ret; + + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); + if (ret < 0) { + v4l2_ctrl_handler_free(&sensor->ctrls); + return ret; + } + + sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock; + v4l2_subdev_init_finalize(&sensor->subdev); + + return 0; +} + +static void imx415_subdev_cleanup(struct imx415 *sensor) +{ + media_entity_cleanup(&sensor->subdev.entity); + v4l2_ctrl_handler_free(&sensor->ctrls); +} + +static int imx415_power_on(struct imx415 *sensor) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + gpiod_set_value_cansleep(sensor->reset, 0); + + udelay(1); + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto err_reset; + + /* + * Data sheet states that 20 us are required before communication start, + * but this doesn't work in all cases. Use 100 us to be on the safe + * side. + */ + usleep_range(100, 200); + + return 0; + +err_reset: + gpiod_set_value_cansleep(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void imx415_power_off(struct imx415 *sensor) +{ + clk_disable_unprepare(sensor->clk); + gpiod_set_value_cansleep(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +static int imx415_identify_model(struct imx415 *sensor) +{ + int model, ret; + + /* + * While most registers can be read when the sensor is in standby, this + * is not the case of the sensor info register :-( + */ + ret = imx415_wakeup(sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get sensor out of standby\n"); + + ret = imx415_read(sensor, IMX415_SENSOR_INFO); + if (ret < 0) { + dev_err_probe(sensor->dev, ret, + "failed to read sensor information\n"); + goto done; + } + + model = ret & IMX415_SENSOR_INFO_MASK; + + switch (model) { + case IMX415_CHIP_ID: + dev_info(sensor->dev, "Detected IMX415 image sensor\n"); + break; + default: + ret = dev_err_probe(sensor->dev, -ENODEV, + "invalid device model 0x%04x\n", model); + goto done; + } + + ret = 0; + +done: + imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + return ret; +} + +static int imx415_check_inck(unsigned long inck, u64 link_frequency) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { + if ((imx415_clk_params[i].lane_rate == link_frequency * 2) && + imx415_clk_params[i].inck == inck) + break; + } + + if (i == ARRAY_SIZE(imx415_clk_params)) + return -EINVAL; + else + return 0; +} + +static int imx415_parse_hw_config(struct imx415 *sensor) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep; + u64 lane_rate; + unsigned long inck; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i) + sensor->supplies[i].supply = imx415_supply_names[i]; + + ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get supplies\n"); + + sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), + "failed to get reset GPIO\n"); + + sensor->clk = devm_clk_get(sensor->dev, "inck"); + if (IS_ERR(sensor->clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + ep = fwnode_graph_get_next_endpoint(dev_fwnode(sensor->dev), NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + switch (bus_cfg.bus.mipi_csi2.num_data_lanes) { + case 2: + case 4: + sensor->num_data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + break; + default: + ret = dev_err_probe(sensor->dev, -EINVAL, + "invalid number of CSI2 data lanes %d\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "no link frequencies defined"); + goto done_endpoint_free; + } + + /* + * Check if there exists a sensor mode defined for current INCK, + * number of lanes and given lane rates. + */ + inck = clk_get_rate(sensor->clk); + for (i = 0; i < bus_cfg.nr_of_link_frequencies; ++i) { + if (imx415_check_inck(inck, bus_cfg.link_frequencies[i])) { + dev_dbg(sensor->dev, + "INCK %lu Hz not supported for this link freq", + inck); + continue; + } + + for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) { + if (sensor->num_data_lanes != supported_modes[j].lanes) + continue; + if (bus_cfg.link_frequencies[i] * 2 != + supported_modes[j].lane_rate) + continue; + sensor->cur_mode = j; + break; + } + if (j < ARRAY_SIZE(supported_modes)) + break; + } + if (i == bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "no valid sensor mode defined\n"); + goto done_endpoint_free; + } + + lane_rate = supported_modes[sensor->cur_mode].lane_rate; + for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { + if (lane_rate == imx415_clk_params[i].lane_rate && + inck == imx415_clk_params[i].inck) { + sensor->clk_params = &imx415_clk_params[i]; + break; + } + } + if (i == ARRAY_SIZE(imx415_clk_params)) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "Mode %d not supported\n", + sensor->cur_mode); + goto done_endpoint_free; + } + + ret = 0; + dev_dbg(sensor->dev, "clock: %lu Hz, lane_rate: %llu bps, lanes: %d\n", + inck, lane_rate, sensor->num_data_lanes); + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int imx415_probe(struct i2c_client *client) +{ + struct imx415 *sensor; + int ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->dev = &client->dev; + + ret = imx415_parse_hw_config(sensor); + if (ret) + return ret; + + sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, identify it, and fully initialize it. + */ + ret = imx415_power_on(sensor); + if (ret) + return ret; + + ret = imx415_identify_model(sensor); + if (ret) + goto err_power; + + ret = imx415_subdev_init(sensor); + if (ret) + goto err_power; + + /* + * Enable runtime PM. As the device has been powered manually, mark it + * as active, and increase the usage count without resuming the device. + */ + pm_runtime_set_active(sensor->dev); + pm_runtime_get_noresume(sensor->dev); + pm_runtime_enable(sensor->dev); + + ret = v4l2_async_register_subdev_sensor(&sensor->subdev); + if (ret < 0) + goto err_pm; + + /* + * Finally, enable autosuspend and decrease the usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. + */ + pm_runtime_set_autosuspend_delay(sensor->dev, 1000); + pm_runtime_use_autosuspend(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + return 0; + +err_pm: + pm_runtime_disable(sensor->dev); + pm_runtime_put_noidle(sensor->dev); + imx415_subdev_cleanup(sensor); +err_power: + imx415_power_off(sensor); + return ret; +} + +static void imx415_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + v4l2_async_unregister_subdev(subdev); + + imx415_subdev_cleanup(sensor); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(sensor->dev); + if (!pm_runtime_status_suspended(sensor->dev)) + imx415_power_off(sensor); + pm_runtime_set_suspended(sensor->dev); +} + +static int imx415_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + return imx415_power_on(sensor); +} + +static int imx415_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + imx415_power_off(sensor); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx415_pm_ops, imx415_runtime_suspend, + imx415_runtime_resume, NULL); + +static const struct of_device_id imx415_of_match[] = { + { .compatible = "sony,imx415" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, imx415_of_match); + +static struct i2c_driver imx415_driver = { + .probe_new = imx415_probe, + .remove = imx415_remove, + .driver = { + .name = "imx415", + .of_match_table = imx415_of_match, + .pm = pm_ptr(&imx415_pm_ops), + }, +}; + +module_i2c_driver(imx415_driver); + +MODULE_DESCRIPTION("Sony IMX415 image sensor driver"); +MODULE_AUTHOR("Gerald Loacker "); +MODULE_AUTHOR("Michael Riesch "); +MODULE_LICENSE("GPL"); From 8d46c5cdadeb64206d2dd7d00f00dd26020ceb3c Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 28 Nov 2022 15:07:17 +0100 Subject: [PATCH 067/216] media: microchip: microchip-isc: replace v4l2_{dbg|info|err} with dev-* v4l2_dbg and friends are legacy and should be removed. Replaced all the calls with dev_dbg equivalent. This also removes the 'debug' module parameter which has become obsolete. Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../platform/microchip/microchip-isc-base.c | 109 ++++++++---------- 1 file changed, 48 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index e2994d48f10c..71758ee8474b 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -32,10 +32,6 @@ #include "microchip-isc-regs.h" #include "microchip-isc.h" -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - #define ISC_IS_FORMAT_RAW(mbus_code) \ (((mbus_code) & 0xf000) == 0x3000) @@ -114,8 +110,8 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) unsigned long size = isc->fmt.fmt.pix.sizeimage; if (vb2_plane_size(vb, 0) < size) { - v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); + dev_err(isc->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); return -EINVAL; } @@ -346,15 +342,14 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) /* Enable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", - ret); + dev_err(isc->dev, "stream on failed in subdev %d\n", ret); goto err_start_stream; } ret = pm_runtime_resume_and_get(isc->dev); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n", - ret); + dev_err(isc->dev, "RPM resume failed in subdev %d\n", + ret); goto err_pm_get; } @@ -423,8 +418,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) /* Wait until the end of the current frame */ if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) - v4l2_err(&isc->v4l2_dev, - "Timeout waiting for end of the capture\n"); + dev_err(isc->dev, "Timeout waiting for end of the capture\n"); mutex_unlock(&isc->awb_mutex); @@ -436,7 +430,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) /* Disable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); if (ret && ret != -ENOIOCTLCMD) - v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); + dev_err(isc->dev, "stream off failed in subdev\n"); /* Release all active buffers */ spin_lock_irqsave(&isc->dma_queue_lock, flags); @@ -620,28 +614,28 @@ static int isc_try_validate_formats(struct isc_device *isc) break; default: /* any other different formats are not supported */ - v4l2_err(&isc->v4l2_dev, "Requested unsupported format.\n"); + dev_err(isc->dev, "Requested unsupported format.\n"); ret = -EINVAL; } - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", - rgb, yuv, grey, bayer); + dev_dbg(isc->dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); if (bayer && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot output RAW if we do not receive RAW.\n"); + dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n"); return -EINVAL; } if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) && !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot output GREY if we do not receive RAW/GREY.\n"); + dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n"); return -EINVAL; } if ((rgb || bayer || yuv) && ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot convert GREY to another format.\n"); + dev_err(isc->dev, "Cannot convert GREY to another format.\n"); return -EINVAL; } @@ -936,9 +930,9 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) isc->config = isc->try_config; isc->fmt = isc->try_fmt; - v4l2_dbg(1, debug, &isc->v4l2_dev, "ISC set_fmt to %.4s @%dx%d\n", - (char *)&f->fmt.pix.pixelformat, - f->fmt.pix.width, f->fmt.pix.height); + dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n", + (char *)&f->fmt.pix.pixelformat, + f->fmt.pix.width, f->fmt.pix.height); return 0; } @@ -973,9 +967,9 @@ static int isc_validate(struct isc_device *isc) /* Check if the format is not supported */ if (!sd_fmt) { - v4l2_err(&isc->v4l2_dev, - "Current subdevice is streaming a media bus code that is not supported 0x%x\n", - format.format.code); + dev_err(isc->dev, + "Current subdevice is streaming a media bus code that is not supported 0x%x\n", + format.format.code); return -EPIPE; } @@ -993,16 +987,16 @@ static int isc_validate(struct isc_device *isc) /* Check if the frame size is the same. Otherwise we may overflow */ if (pixfmt->height != format.format.height || pixfmt->width != format.format.width) { - v4l2_err(&isc->v4l2_dev, - "ISC not configured with the proper frame size: %dx%d\n", - format.format.width, format.format.height); + dev_err(isc->dev, + "ISC not configured with the proper frame size: %dx%d\n", + format.format.width, format.format.height); return -EPIPE; } - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Identified subdev using format %.4s with %dx%d %d bpp\n", - (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height, - isc->try_config.bpp); + dev_dbg(isc->dev, + "Identified subdev using format %.4s with %dx%d %d bpp\n", + (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height, + isc->try_config.bpp); /* Reset and restart AWB if the subdevice changed the format */ if (isc->try_config.sd_format && isc->config.sd_format && @@ -1027,7 +1021,7 @@ static int isc_validate(struct isc_device *isc) isc->config = isc->try_config; - v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); + dev_dbg(isc->dev, "New ISC configuration in place\n"); return 0; } @@ -1294,9 +1288,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) if (!*min) *min = 1; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: hist_id %u, hist_count %u", - ctrls->hist_id, *hist_count); + dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u", + ctrls->hist_id, *hist_count); } static void isc_wb_update(struct isc_ctrls *ctrls) @@ -1318,8 +1311,7 @@ static void isc_wb_update(struct isc_ctrls *ctrls) (u64)hist_count[ISC_HIS_CFG_MODE_GB]; avg >>= 1; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: green components average %llu\n", avg); + dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg); /* Green histogram is null, nothing to do */ if (!avg) @@ -1373,9 +1365,9 @@ static void isc_wb_update(struct isc_ctrls *ctrls) else gw_gain[c] = 1 << 9; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: component %d, s_gain %u, gw_gain %u\n", - c, s_gain[c], gw_gain[c]); + dev_dbg(isc->dev, + "isc wb: component %d, s_gain %u, gw_gain %u\n", + c, s_gain[c], gw_gain[c]); /* multiply both gains and adjust for decimals */ ctrls->gain[c] = s_gain[c] * gw_gain[c]; ctrls->gain[c] >>= 9; @@ -1383,9 +1375,8 @@ static void isc_wb_update(struct isc_ctrls *ctrls) /* make sure we are not out of range */ ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0)); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: component %d, final gain %u\n", - c, ctrls->gain[c]); + dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n", + c, ctrls->gain[c]); } } @@ -1406,8 +1397,8 @@ static void isc_awb_work(struct work_struct *w) isc_hist_count(isc, &min, &max); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max); + dev_dbg(isc->dev, + "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max); ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; @@ -1446,8 +1437,8 @@ static void isc_awb_work(struct work_struct *w) * we are basically done. */ if (ctrls->awb == ISC_WB_ONETIME) { - v4l2_info(&isc->v4l2_dev, - "Completed one time white-balance adjustment.\n"); + dev_info(isc->dev, + "Completed one time white-balance adjustment.\n"); /* update the v4l2 controls values */ isc_update_v4l2_ctrls(isc); ctrls->awb = ISC_WB_NONE; @@ -1580,8 +1571,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) V4L2_CTRL_FLAG_INACTIVE)) { ctrls->awb = ISC_WB_ONETIME; isc_set_histogram(isc, true); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "One time white-balance started.\n"); + dev_dbg(isc->dev, "One time white-balance started.\n"); } return 0; } @@ -1730,7 +1720,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier, int pad; if (video_is_registered(&isc->video_dev)) { - v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); + dev_err(isc->dev, "only supports one sub-device.\n"); return -EBUSY; } @@ -1739,8 +1729,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier, pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, MEDIA_PAD_FL_SOURCE); if (pad < 0) { - v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n", - subdev->name); + dev_err(isc->dev, "failed to find pad for %s\n", subdev->name); return pad; } @@ -1813,7 +1802,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); + dev_err(isc->dev, "Failed to register subdev nodes\n"); return ret; } @@ -1838,8 +1827,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = vb2_queue_init(q); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "vb2_queue_init() failed: %d\n", ret); + dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret); goto isc_async_complete_err; } @@ -1850,13 +1838,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = isc_set_default_fmt(isc); if (ret) { - v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); + dev_err(isc->dev, "Could not set default format\n"); goto isc_async_complete_err; } ret = isc_ctrl_init(isc); if (ret) { - v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); + dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret); goto isc_async_complete_err; } @@ -1876,8 +1864,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "video_register_device failed: %d\n", ret); + dev_err(isc->dev, "video_register_device failed: %d\n", ret); goto isc_async_complete_err; } From b755063ec0394bca5c688c6ad88315cbb1b23e7b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Nov 2022 20:49:45 +0100 Subject: [PATCH 068/216] media: i2c: s5c73m3: remove support for platform data There are no existing users of s5c73m3_platform_data in the tree, and new users should either be using device tree, ACPI, or static device properties, so let's remove it from the driver. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 20 +++-------- drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c | 1 - drivers/media/i2c/s5c73m3/s5c73m3.h | 1 - include/media/i2c/s5c73m3.h | 41 ----------------------- 4 files changed, 5 insertions(+), 58 deletions(-) delete mode 100644 include/media/i2c/s5c73m3.h diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 59b03b0860d5..318a4ec2d8a5 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "s5c73m3.h" @@ -1522,25 +1521,16 @@ static const struct v4l2_subdev_ops oif_subdev_ops = { .video = &s5c73m3_oif_video_ops, }; -static int s5c73m3_get_platform_data(struct s5c73m3 *state) +static int s5c73m3_get_dt_data(struct s5c73m3 *state) { - struct i2c_client *c = state->i2c_client; - struct device *dev = &c->dev; - const struct s5c73m3_platform_data *pdata = dev->platform_data; + struct device *dev = &state->i2c_client->dev; struct device_node *node = dev->of_node; struct device_node *node_ep; struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; int ret; - if (!node) { - if (!pdata) { - dev_err(dev, "Platform data not specified\n"); - return -EINVAL; - } - - state->mclk_frequency = pdata->mclk_frequency; - return 0; - } + if (!node) + return -EINVAL; state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); if (IS_ERR(state->clock)) @@ -1603,7 +1593,7 @@ static int s5c73m3_probe(struct i2c_client *client) return -ENOMEM; state->i2c_client = client; - ret = s5c73m3_get_platform_data(state); + ret = s5c73m3_get_dt_data(state); if (ret < 0) return ret; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c index e3543ae384ed..1c8103670fa2 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "s5c73m3.h" diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 1fc7df41c5ee..627e80cf5b72 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -16,7 +16,6 @@ #include #include #include -#include #define DRIVER_NAME "S5C73M3" diff --git a/include/media/i2c/s5c73m3.h b/include/media/i2c/s5c73m3.h deleted file mode 100644 index df0769d64523..000000000000 --- a/include/media/i2c/s5c73m3.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Samsung LSI S5C73M3 8M pixel camera driver - * - * Copyright (C) 2012, Samsung Electronics, Co., Ltd. - * Sylwester Nawrocki - * Andrzej Hajda - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef MEDIA_S5C73M3__ -#define MEDIA_S5C73M3__ - -#include -#include - -/** - * struct s5c73m3_platform_data - s5c73m3 driver platform data - * @mclk_frequency: sensor's master clock frequency in Hz - * @bus_type: bus type - * @nlanes: maximum number of MIPI-CSI lanes used - * @horiz_flip: default horizontal image flip value, non zero to enable - * @vert_flip: default vertical image flip value, non zero to enable - */ - -struct s5c73m3_platform_data { - unsigned long mclk_frequency; - - enum v4l2_mbus_type bus_type; - u8 nlanes; - u8 horiz_flip; - u8 vert_flip; -}; - -#endif /* MEDIA_S5C73M3__ */ From 7206fcc59399729667260d58c63e3db4503ac511 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 29 Nov 2022 08:53:22 +0100 Subject: [PATCH 069/216] media: rzg2l-cru: Remove unneeded semicolon ./drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c:409:2-3: Unneeded semicolon ./drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c:407:2-3: Unneeded semicolon Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3273 Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 2 +- drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index 33e08efa3039..384fb54e219a 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -406,7 +406,7 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS)) break; usleep_range(100, 200); - }; + } if (!timeout) dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n"); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index 91b57c7c2e56..e6eedd65b71d 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -404,7 +404,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru) break; usleep_range(10, 20); - }; + } /* Notify that AXI bus can not stop here */ if (!retries) From 1925665ef403c5f5e605d10148870d1cb505b5ab Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 29 Nov 2022 11:22:17 +0100 Subject: [PATCH 070/216] media: amphion: remove redundant check of colorspace in venc_s_fmt record the colorspace set by user. if it's not supported by h264 vui, then zero will be written to vui, but don't modify the user setting. Fixes: 0401e659c1f9 ("media: amphion: add v4l2 m2m vpu encoder stateful driver") Signed-off-by: Ming Qian Acked-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/venc.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 3cbe8ce637e5..e6e8fe45fc7c 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -250,19 +250,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) } if (V4L2_TYPE_IS_OUTPUT(f->type)) { - if (!vpu_color_check_primaries(pix_mp->colorspace)) { - venc->params.color.primaries = pix_mp->colorspace; - vpu_color_get_default(venc->params.color.primaries, - &venc->params.color.transfer, - &venc->params.color.matrix, - &venc->params.color.full_range); - } - if (!vpu_color_check_transfers(pix_mp->xfer_func)) - venc->params.color.transfer = pix_mp->xfer_func; - if (!vpu_color_check_matrix(pix_mp->ycbcr_enc)) - venc->params.color.matrix = pix_mp->ycbcr_enc; - if (!vpu_color_check_full_range(pix_mp->quantization)) - venc->params.color.full_range = pix_mp->quantization; + venc->params.color.primaries = pix_mp->colorspace; + venc->params.color.transfer = pix_mp->xfer_func; + venc->params.color.matrix = pix_mp->ycbcr_enc; + venc->params.color.full_range = pix_mp->quantization; } pix_mp->colorspace = venc->params.color.primaries; @@ -1281,7 +1272,6 @@ static void venc_init(struct file *file) f.fmt.pix_mp.width = 1280; f.fmt.pix_mp.height = 720; f.fmt.pix_mp.field = V4L2_FIELD_NONE; - f.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; venc_s_fmt(file, &inst->fh, &f); memset(&f, 0, sizeof(f)); From 01cb370ff6c5abf2d64985832ff165f353ac04bb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Nov 2022 12:15:13 +0100 Subject: [PATCH 071/216] media: videobuf2-core: drop obsolete sanity check in __vb2_queue_free() The sanity check in __vb2_queue_free() is obsolete ever since commit f035eb4e976e ("[media] videobuf2: fix lockdep warning"). Remove it and let __vb2_queue_free() return void. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/common/videobuf2/videobuf2-core.c | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index fc3758a5bc1c..cab07e3a3c6f 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -502,27 +502,11 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) * related information, if no buffers are left return the queue to an * uninitialized state. Might be called even if the queue has already been freed. */ -static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) +static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; - /* - * Sanity check: when preparing a buffer the queue lock is released for - * a short while (see __buf_prepare for the details), which would allow - * a race with a reqbufs which can call this function. Removing the - * buffers from underneath __buf_prepare is obviously a bad idea, so we - * check if any of the buffers is in the state PREPARING, and if so we - * just return -EAGAIN. - */ - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; - ++buffer) { - if (q->bufs[buffer] == NULL) - continue; - if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { - dprintk(q, 1, "preparing buffers, cannot free\n"); - return -EAGAIN; - } - } + lockdep_assert_held(&q->mmap_lock); /* Call driver-provided cleanup function for each buffer, if provided */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; @@ -616,7 +600,6 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->memory = VB2_MEMORY_UNKNOWN; INIT_LIST_HEAD(&q->queued_list); } - return 0; } bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) @@ -798,10 +781,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * queued without ever calling STREAMON. */ __vb2_queue_cancel(q); - ret = __vb2_queue_free(q, q->num_buffers); + __vb2_queue_free(q, q->num_buffers); mutex_unlock(&q->mmap_lock); - if (ret) - return ret; /* * In case of REQBUFS(0) return immediately without calling From 1963689bed4d500236938d90c91cdd5e63c1eb28 Mon Sep 17 00:00:00 2001 From: Qiheng Lin Date: Fri, 2 Dec 2022 11:18:36 +0100 Subject: [PATCH 072/216] media: platform: mtk-mdp3: Fix return value check in mdp_probe() In case of error, the function mtk_mutex_get() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). And also fix the err_free_mutex case. Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Signed-off-by: Qiheng Lin Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 2d1f6ae9f080..97edcd9d1c81 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -207,8 +207,8 @@ static int mdp_probe(struct platform_device *pdev) } for (i = 0; i < MDP_PIPE_MAX; i++) { mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev); - if (!mdp->mdp_mutex[i]) { - ret = -ENODEV; + if (IS_ERR(mdp->mdp_mutex[i])) { + ret = PTR_ERR(mdp->mdp_mutex[i]); goto err_free_mutex; } } @@ -289,7 +289,8 @@ static int mdp_probe(struct platform_device *pdev) mdp_comp_destroy(mdp); err_free_mutex: for (i = 0; i < MDP_PIPE_MAX; i++) - mtk_mutex_put(mdp->mdp_mutex[i]); + if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i])) + mtk_mutex_put(mdp->mdp_mutex[i]); err_destroy_device: kfree(mdp); err_return: From c360945ea4c61262b3062a3a02037dae180f0311 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 4 Dec 2022 19:33:26 +0100 Subject: [PATCH 073/216] media: docs: admin-guide: media: align HDMI CEC node names with dtschema The bindings expect "cec" for HDMI CEC node. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/cec.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/media/cec.rst b/Documentation/admin-guide/media/cec.rst index 5c7259371494..14ec3ff317c2 100644 --- a/Documentation/admin-guide/media/cec.rst +++ b/Documentation/admin-guide/media/cec.rst @@ -340,14 +340,14 @@ and IO24. Monitoring the HPD an 5V lines is not necessary, but it is helpful. This kernel patch will hook up the cec-gpio driver correctly to e.g. ``arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts``:: - cec-gpio@7 { + cec@7 { compatible = "cec-gpio"; cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; }; - cec-gpio@8 { + cec@8 { compatible = "cec-gpio"; cec-gpios = <&gpio 8 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; hpd-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; From 4be362d8449fa124c3437c86f278f4b063428c97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 4 Dec 2022 19:34:55 +0100 Subject: [PATCH 074/216] media: exynos4-is: drop unused pctrl field and headers The field 'pctrl' in 'struct fimc_is' is not used, just like linux/pinctrl/consumer.h headers in the headers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/samsung/exynos4-is/fimc-is.h | 3 --- drivers/media/platform/samsung/exynos4-is/media-dev.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.h b/drivers/media/platform/samsung/exynos4-is/fimc-is.h index 06586e455b1d..c126b779aafc 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -231,7 +230,6 @@ struct chain_config { /** * struct fimc_is - fimc-is data structure * @pdev: pointer to FIMC-IS platform device - * @pctrl: pointer to pinctrl structure for this device * @v4l2_dev: pointer to the top level v4l2_device * @fw: data structure describing the FIMC-IS firmware binary * @memory: memory region assigned for the FIMC-IS (firmware) @@ -262,7 +260,6 @@ struct chain_config { */ struct fimc_is { struct platform_device *pdev; - struct pinctrl *pctrl; struct v4l2_device *v4l2_dev; struct fimc_is_firmware fw; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h index 62ad5d7e035a..079105d88bab 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.h +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include From c3fc806763b285c668e8a916bd7dfe8692caadce Mon Sep 17 00:00:00 2001 From: Jammy Huang Date: Thu, 8 Dec 2022 02:24:23 +0100 Subject: [PATCH 075/216] media: docs: aspeed-video: Update reference Use URL rather than plain text. Signed-off-by: Jammy Huang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/drivers/aspeed-video.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/drivers/aspeed-video.rst b/Documentation/userspace-api/media/drivers/aspeed-video.rst index 1b0cb1e3eba8..567387aca6b0 100644 --- a/Documentation/userspace-api/media/drivers/aspeed-video.rst +++ b/Documentation/userspace-api/media/drivers/aspeed-video.rst @@ -23,7 +23,7 @@ proprietary mode. More details on the ASPEED video hardware operations can be found in *chapter 6.2.16 KVM Video Driver* of SDK_User_Guide which available on -AspeedTech-BMC/openbmc/releases. +`github `__. The ASPEED video driver implements the following driver-specific control: From ac270a6fa5517c551aacd57210c42f2eccb1707e Mon Sep 17 00:00:00 2001 From: Jammy Huang Date: Thu, 8 Dec 2022 02:26:31 +0100 Subject: [PATCH 076/216] media: docs: pixfmt-reserved: Update reference Use URL rather than plain text. Signed-off-by: Jammy Huang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index 73cd99828010..58f6ae25b2e7 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -271,7 +271,7 @@ please make a proposal on the linux-media mailing list. The implementation is based on AST2600 A3 datasheet, revision 0.9, which is not publicly available. Or you can reference Video stream data format – ASPEED mode compression of SDK_User_Guide which available on - AspeedTech-BMC/openbmc/releases. + `github `__. Decoder's implementation can be found here, `aspeed_codec `__ From a0799442716c090d8cf4404deec41b96aff03502 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Dec 2022 08:51:19 +0100 Subject: [PATCH 077/216] media: s5p-mfc: use vb2_is_streaming() Don't touch q->streaming directly, use the vb2_is_streaming() function instead. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index f3e4cdac1ef3..9d2cce124a34 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -1021,8 +1021,8 @@ static __poll_t s5p_mfc_poll(struct file *file, * means either in driver already or waiting for driver to claim it * and start processing. */ - if ((!src_q->streaming || list_empty(&src_q->queued_list)) - && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { + if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) && + (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) { rc = EPOLLERR; goto end; } From c43784c856483dded7956175b5786e27af6d87f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Dec 2022 08:51:32 +0100 Subject: [PATCH 078/216] media: v4l2-mem2mem: use vb2_is_streaming() Don't touch q->streaming directly, use the vb2_is_streaming() function instead. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index be7fde1ed3ea..0cc30397fbad 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -922,9 +922,9 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, * means either in driver already or waiting for driver to claim it * and start processing. */ - if ((!src_q->streaming || src_q->error || + if ((!vb2_is_streaming(src_q) || src_q->error || list_empty(&src_q->queued_list)) && - (!dst_q->streaming || dst_q->error || + (!vb2_is_streaming(dst_q) || dst_q->error || (list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued))) return EPOLLERR; From 25e7b6c00dbf5cd319bc8bee1588f67880e45ee0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Dec 2022 08:52:06 +0100 Subject: [PATCH 079/216] media: go7007: don't modify q->streaming The streaming state is maintained by the vb2 core, so drivers must never change it themselves. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/go7007/go7007-v4l2.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index b2edc4deaca3..13256565b034 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -404,16 +404,13 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) go->next_seq = 0; go->active_buf = NULL; go->modet_event_status = 0; - q->streaming = 1; if (go7007_start_encoder(go) < 0) ret = -EIO; else ret = 0; mutex_unlock(&go->hw_lock); - if (ret) { - q->streaming = 0; + if (ret) return ret; - } call_all(&go->v4l2_dev, video, s_stream, 1); v4l2_ctrl_grab(go->mpeg_video_gop_size, true); v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); @@ -430,7 +427,6 @@ static void go7007_stop_streaming(struct vb2_queue *q) struct go7007 *go = vb2_get_drv_priv(q); unsigned long flags; - q->streaming = 0; go7007_stream_stop(go); mutex_lock(&go->hw_lock); go7007_reset_encoder(go); From eb78ca6a0496795f3abf16fe64b8450ef0639195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 16:35:50 +0100 Subject: [PATCH 080/216] media: ti/davinci: vpbe_osd: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Reviewed-by: Lad Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/davinci/vpbe_osd.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/ti/davinci/vpbe_osd.c b/drivers/media/platform/ti/davinci/vpbe_osd.c index 32f7ef547c82..f6ea71c081d4 100644 --- a/drivers/media/platform/ti/davinci/vpbe_osd.c +++ b/drivers/media/platform/ti/davinci/vpbe_osd.c @@ -1561,14 +1561,8 @@ static int osd_probe(struct platform_device *pdev) return 0; } -static int osd_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver osd_driver = { .probe = osd_probe, - .remove = osd_remove, .driver = { .name = MODULE_NAME, }, From 5204a5dce04b382a9131637c613f619afa64f873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 16:35:51 +0100 Subject: [PATCH 081/216] media: ti/davinci: vpbe_venc: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Reviewed-by: Lad Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/davinci/vpbe_venc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/ti/davinci/vpbe_venc.c b/drivers/media/platform/ti/davinci/vpbe_venc.c index 4c8e31de12b1..6bde6517cba5 100644 --- a/drivers/media/platform/ti/davinci/vpbe_venc.c +++ b/drivers/media/platform/ti/davinci/vpbe_venc.c @@ -655,14 +655,8 @@ static int venc_probe(struct platform_device *pdev) return 0; } -static int venc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver venc_driver = { .probe = venc_probe, - .remove = venc_remove, .driver = { .name = MODULE_NAME, }, From c58bddb1d743e8b25aedd5f67d0bf391ecf79ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 16:35:53 +0100 Subject: [PATCH 082/216] media: chips-media/imx-vdoa: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/chips-media/imx-vdoa.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/imx-vdoa.c index c70871bae193..c3561fcecb98 100644 --- a/drivers/media/platform/chips-media/imx-vdoa.c +++ b/drivers/media/platform/chips-media/imx-vdoa.c @@ -324,11 +324,6 @@ static int vdoa_probe(struct platform_device *pdev) return 0; } -static int vdoa_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct of_device_id vdoa_dt_ids[] = { { .compatible = "fsl,imx6q-vdoa" }, {} @@ -337,7 +332,6 @@ MODULE_DEVICE_TABLE(of, vdoa_dt_ids); static struct platform_driver vdoa_driver = { .probe = vdoa_probe, - .remove = vdoa_remove, .driver = { .name = VDOA_NAME, .of_match_table = vdoa_dt_ids, From 05fb9ace34b8645cb76f7e3a21b5c7b754329cae Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Dec 2022 17:28:46 +0100 Subject: [PATCH 083/216] media: camss: csiphy-3ph: avoid undefined behavior Marking a case of the switch statement as unreachable means the compiler treats it as undefined behavior, which is then caught by an objtool warning: drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.o: warning: objtool: csiphy_lanes_enable() falls through to next function csiphy_lanes_disable() Instead of simply continuing execution at a random place of the driver, print a warning and return from to the caller, which makes it possible to understand what happens and avoids the warning. Fixes: 53655d2a0ff2 ("media: camss: csiphy-3ph: add support for SM8250 CSI DPHY") Signed-off-by: Arnd Bergmann Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 451a4c9b3d30..04baa80494c6 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -429,7 +429,8 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, array_size = ARRAY_SIZE(lane_regs_sm8250[0]); break; default: - unreachable(); + WARN(1, "unknown cspi version\n"); + return; } for (l = 0; l < 5; l++) { From e3f7feb6d89311f369dd4ad903ea62e45328cdbe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Dec 2022 17:40:08 +0100 Subject: [PATCH 084/216] media: platform: mtk-mdp3: fix Kconfig dependencies The new mdp3 driver uses 'select' to force-enable a couple of drivers it depends on. This is error-prone and likely to cause dependency loops as well as warnings like: WARNING: unmet direct dependencies detected for VIDEO_MEDIATEK_VPU Depends on [n]: MEDIA_SUPPORT [=m] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && V4L_MEM2MEM_DRIVERS [=n] && VIDEO_DEV [=m] && (ARCH_MEDIATEK [=y] || COMPILE_TEST [=y]) Selected by [m]: - VIDEO_MEDIATEK_MDP3 [=m] && MEDIA_SUPPORT [=m] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && (MTK_IOMMU [=m] || COMPILE_TEST [=y]) && VIDEO_DEV [=m] && (ARCH_MEDIATEK [=y] || COMPILE_TEST [=y]) && HAS_DMA [=y] && REMOTEPROC [=y] This specific warning was already addressed in a previous patch, but there are similar unnecessary 'select' statements, so turn those into 'depends on'. This also means the dependency on ARCH_MEDIATEK is redundant and can be dropped. Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Fixes: 9195a860ef0a ("media: platform: mtk-mdp3: remove unused VIDEO_MEDIATEK_VPU config") Signed-off-by: Arnd Bergmann Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig index 846e759a8f6a..602329c44750 100644 --- a/drivers/media/platform/mediatek/mdp3/Kconfig +++ b/drivers/media/platform/mediatek/mdp3/Kconfig @@ -3,14 +3,13 @@ config VIDEO_MEDIATEK_MDP3 tristate "MediaTek MDP v3 driver" depends on MTK_IOMMU || COMPILE_TEST depends on VIDEO_DEV - depends on ARCH_MEDIATEK || COMPILE_TEST depends on HAS_DMA depends on REMOTEPROC + depends on MTK_MMSYS + depends on MTK_CMDQ + depends on MTK_SCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - select MTK_MMSYS - select MTK_CMDQ - select MTK_SCP default n help It is a v4l2 driver and present in MediaTek MT8183 SoC. From 41959c4f973b837a12061b84d3a436fc64c73a30 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Fri, 16 Dec 2022 09:30:33 +0100 Subject: [PATCH 085/216] media: v4l2-jpeg: correct the skip count in jpeg_parse_app14_data The curr pointer has advanced 14 bytes in jpeg_parse_app14_data. 1. jpeg_get_word_be(stream), it goes forward 2 bytes. 2. jpeg_skip(stream, 11), it goes forward 11 bytes. 3. jpeg_get_byte(stream), it goes forward 1 bytes. so the remain bytes of this segment should be (lp - 2 - 11 - 1), but not (lp - 2 - 11). if driver skip 1 extra bytes, the following parsing may go wrong. Fixes: b8035f7988a8 ("media: Add parsing for APP14 data segment in jpeg helpers") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-jpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c index c2513b775f6a..75c2af763d55 100644 --- a/drivers/media/v4l2-core/v4l2-jpeg.c +++ b/drivers/media/v4l2-core/v4l2-jpeg.c @@ -474,7 +474,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream, *tf = ret; /* skip the rest of the segment, this ensures at least it is complete */ - skip = lp - 2 - 11; + skip = lp - 2 - 11 - 1; return jpeg_skip(stream, skip); } From 251c0ea6efd3c3ea0f8a55fdd96c749a98639bd3 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Fri, 16 Dec 2022 10:08:44 +0100 Subject: [PATCH 086/216] media: v4l2-jpeg: ignore the unknown APP14 marker The legal identifier of APP14 is "Adobe\0", but sometimes it may be "This is an unknown APP marker . Compliant decoders must ignore it." In this case, just ignore it. It won't affect the decode result. Fixes: b8035f7988a8 ("media: Add parsing for APP14 data segment in jpeg helpers") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-jpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c index 75c2af763d55..94435a7b6816 100644 --- a/drivers/media/v4l2-core/v4l2-jpeg.c +++ b/drivers/media/v4l2-core/v4l2-jpeg.c @@ -460,7 +460,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream, /* Check for "Adobe\0" in Ap1..6 */ if (stream->curr + 6 > stream->end || strncmp(stream->curr, "Adobe\0", 6)) - return -EINVAL; + return jpeg_skip(stream, lp - 2); /* get to Ap12 */ ret = jpeg_skip(stream, 11); From 637046bb5ac9487e3f059a490f7b3045f1d1077a Mon Sep 17 00:00:00 2001 From: Zhou jie Date: Fri, 23 Dec 2022 10:08:58 +0100 Subject: [PATCH 087/216] media: radio/wl128x: remove unnecessary (void*) conversions The void * type pointer does not need to be cast. Signed-off-by: Zhou jie Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 8a316de70e6c..cbd49dff6d74 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -1442,7 +1442,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb) { struct fmdev *fmdev; - fmdev = (struct fmdev *)arg; + fmdev = arg; if (skb == NULL) { fmerr("Invalid SKB received from ST\n"); From 29bd426764dee14a09e37700406f4a5920825fcc Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 23 Dec 2022 19:16:47 +0100 Subject: [PATCH 088/216] media: hantro: Fix JPEG encoder ENUM_FRMSIZE on RK3399 Since 79c987de8b354, enumerating framesize on format set with "MODE_NONE" (any raw formats) is reporting an invalid frmsize. Size: Stepwise 0x0 - 0x0 with step 0/0 Before this change, the driver would return EINVAL, which is also invalid but worked in GStreamer. The original intent was not to implement it, hence the -ENOTTY return in this change. While drivers should implement ENUM_FRMSIZE for all formats and queues, this change is limited in scope to fix the regression. This fixes taking picture in Gnome Cheese software, or any software using GSteamer to encode JPEG with hardware acceleration. Fixes: 79c987de8b35 ("media: hantro: Use post processor scaling capacities") Reported-by: Robert Mader Signed-off-by: Nicolas Dufresne Reviewed-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Tested-by: Robert Mader Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_v4l2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 2c7a805289e7..30e650edaea8 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -161,8 +161,11 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, } /* For non-coded formats check if postprocessing scaling is possible */ - if (fmt->codec_mode == HANTRO_MODE_NONE && hantro_needs_postproc(ctx, fmt)) { - return hanto_postproc_enum_framesizes(ctx, fsize); + if (fmt->codec_mode == HANTRO_MODE_NONE) { + if (hantro_needs_postproc(ctx, fmt)) + return hanto_postproc_enum_framesizes(ctx, fsize); + else + return -ENOTTY; } else if (fsize->index != 0) { vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", fsize->index); From ee56fa0116e13f39e6d025dbc4f4138878f67a12 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Tue, 3 Jan 2023 18:38:20 +0100 Subject: [PATCH 089/216] media: staging: media: imx: change imx_media_fim_set_stream() to return void At present, the function imx_media_fim_set_stream() always returns 0. So, convert it to be a function returning void instead. Issue identified using the returnvar.cocci Coccinelle semantic patch. Signed-off-by: Deepak R Varma Reviewed-by: Marco Felsch Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 7 ++----- drivers/staging/media/imx/imx-media-fim.c | 8 +++----- drivers/staging/media/imx/imx-media.h | 6 +++--- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 5c3cc7de209d..44d87fe30d52 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -779,11 +779,8 @@ static int csi_start(struct csi_priv *priv) goto idmac_stop; /* start the frame interval monitor */ - if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) { - ret = imx_media_fim_set_stream(priv->fim, output_fi, true); - if (ret) - goto idmac_stop; - } + if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) + imx_media_fim_set_stream(priv->fim, output_fi, true); ret = ipu_csi_enable(priv->csi); if (ret) { diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c index fb6590dcfc36..f456751f100a 100644 --- a/drivers/staging/media/imx/imx-media-fim.c +++ b/drivers/staging/media/imx/imx-media-fim.c @@ -368,12 +368,11 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp) } /* Called by the subdev in its s_stream callback */ -int imx_media_fim_set_stream(struct imx_media_fim *fim, - const struct v4l2_fract *fi, - bool on) +void imx_media_fim_set_stream(struct imx_media_fim *fim, + const struct v4l2_fract *fi, + bool on) { unsigned long flags; - int ret = 0; v4l2_ctrl_lock(fim->ctrl[FIM_CL_ENABLE]); @@ -393,7 +392,6 @@ int imx_media_fim_set_stream(struct imx_media_fim *fim, fim->stream_on = on; out: v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]); - return ret; } int imx_media_fim_add_controls(struct imx_media_fim *fim) diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index f679249d82e4..6f9a46573edd 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -246,9 +246,9 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd, /* imx-media-fim.c */ struct imx_media_fim; void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp); -int imx_media_fim_set_stream(struct imx_media_fim *fim, - const struct v4l2_fract *frame_interval, - bool on); +void imx_media_fim_set_stream(struct imx_media_fim *fim, + const struct v4l2_fract *frame_interval, + bool on); int imx_media_fim_add_controls(struct imx_media_fim *fim); struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd); void imx_media_fim_free(struct imx_media_fim *fim); From 3ef5750989a2b028ce84a0feadd819202de2a66e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Jan 2023 19:33:14 +0100 Subject: [PATCH 090/216] media: vidtv: make const array DURATION static Don't populate the read-only const array DURATION on the stack but instead make it static. Also makes the object code a little smaller. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vidtv/vidtv_psi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index a5875380ef40..ce0b7a6e92dc 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -1940,7 +1940,7 @@ u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args) struct vidtv_psi_table_eit_event *vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id) { - const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */ + static const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */ struct vidtv_psi_table_eit_event *e; struct timespec64 ts; struct tm time; From 4ee8191c7c9f2dc62bd007dd4ac79b7799785c36 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Jan 2023 19:44:03 +0100 Subject: [PATCH 091/216] media: rkisp1: make a few const arrays static Don't populate the const arrays on the stack, instead make them static. Also makes the object code smaller. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-capture.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index d4540684ea9a..d1d1fdce03e3 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1131,10 +1131,12 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap, const struct rkisp1_capture_config *config = cap->config; const struct rkisp1_capture_fmt_cfg *fmt; const struct v4l2_format_info *info; - const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH, - RKISP1_RSZ_SP_SRC_MAX_WIDTH }; - const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT, - RKISP1_RSZ_SP_SRC_MAX_HEIGHT}; + static const unsigned int max_widths[] = { + RKISP1_RSZ_MP_SRC_MAX_WIDTH, RKISP1_RSZ_SP_SRC_MAX_WIDTH + }; + static const unsigned int max_heights[] = { + RKISP1_RSZ_MP_SRC_MAX_HEIGHT, RKISP1_RSZ_SP_SRC_MAX_HEIGHT + }; fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat); if (!fmt) { @@ -1336,8 +1338,9 @@ void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) static int rkisp1_register_capture(struct rkisp1_capture *cap) { - const char * const dev_names[] = {RKISP1_MP_DEV_NAME, - RKISP1_SP_DEV_NAME}; + static const char * const dev_names[] = { + RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME + }; struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev; struct video_device *vdev = &cap->vnode.vdev; struct rkisp1_vdev_node *node; From c07e734b7a65c7706319e24f9b14ec9d262fa50c Mon Sep 17 00:00:00 2001 From: Oleg Verych Date: Sat, 7 Jan 2023 09:37:49 +0100 Subject: [PATCH 092/216] media: sun4i-csi: Fix 'Unbalanced pm_runtime_enable!' When removing the module, balance PM runtime enable with the corresponding disable call. Signed-off-by: Oleg Verych Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 18e6c65f4737..86c5235a0c7a 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -264,6 +264,7 @@ static int sun4i_csi_remove(struct platform_device *pdev) { struct sun4i_csi *csi = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); v4l2_async_nf_unregister(&csi->notifier); v4l2_async_nf_cleanup(&csi->notifier); vb2_video_unregister_device(&csi->vdev); From 61fe43dc9f454bc3caa99dbdd8f5fa3ba813981a Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Thu, 12 Jan 2023 10:47:02 +0100 Subject: [PATCH 093/216] media: imx-jpeg: Apply clk_bulk api instead of operating specific clk using the api of clk_bulk can simplify the code. and the clock of the jpeg codec may be changed, the clk_bulk api can be compatible with the future change. Fixes: 4c2e5156d9fa ("media: imx-jpeg: Add pm-runtime support for imx-jpeg") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 35 +++++-------------- .../media/platform/nxp/imx-jpeg/mxc-jpeg.h | 4 +-- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 6cd015a35f7c..f085f14d676a 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2472,19 +2472,12 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->mode = mode; /* Get clocks */ - jpeg->clk_ipg = devm_clk_get(dev, "ipg"); - if (IS_ERR(jpeg->clk_ipg)) { - dev_err(dev, "failed to get clock: ipg\n"); - ret = PTR_ERR(jpeg->clk_ipg); - goto err_clk; - } - - jpeg->clk_per = devm_clk_get(dev, "per"); - if (IS_ERR(jpeg->clk_per)) { - dev_err(dev, "failed to get clock: per\n"); - ret = PTR_ERR(jpeg->clk_per); + ret = devm_clk_bulk_get_all(&pdev->dev, &jpeg->clks); + if (ret < 0) { + dev_err(dev, "failed to get clock\n"); goto err_clk; } + jpeg->num_clks = ret; ret = mxc_jpeg_attach_pm_domains(jpeg); if (ret < 0) { @@ -2581,32 +2574,20 @@ static int mxc_jpeg_runtime_resume(struct device *dev) struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(jpeg->clk_ipg); + ret = clk_bulk_prepare_enable(jpeg->num_clks, jpeg->clks); if (ret < 0) { - dev_err(dev, "failed to enable clock: ipg\n"); - goto err_ipg; - } - - ret = clk_prepare_enable(jpeg->clk_per); - if (ret < 0) { - dev_err(dev, "failed to enable clock: per\n"); - goto err_per; + dev_err(dev, "failed to enable clock\n"); + return ret; } return 0; - -err_per: - clk_disable_unprepare(jpeg->clk_ipg); -err_ipg: - return ret; } static int mxc_jpeg_runtime_suspend(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); - clk_disable_unprepare(jpeg->clk_ipg); - clk_disable_unprepare(jpeg->clk_per); + clk_bulk_disable_unprepare(jpeg->num_clks, jpeg->clks); return 0; } diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index 8fa8c0aec5a2..87157db78082 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -120,8 +120,8 @@ struct mxc_jpeg_dev { spinlock_t hw_lock; /* hardware access lock */ unsigned int mode; struct mutex lock; /* v4l2 ioctls serialization */ - struct clk *clk_ipg; - struct clk *clk_per; + struct clk_bulk_data *clks; + int num_clks; struct platform_device *pdev; struct device *dev; void __iomem *base_reg; From 809060c8a357e020010dd8f797a5efd3c5432b13 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Fri, 13 Jan 2023 06:25:51 +0100 Subject: [PATCH 094/216] media: amphion: correct the unspecified color space in the E.2.1 of Rec. ITU-T H.264 (06/2019), 0 of colour primaries is reserved, and 2 is unspecified. driver can map V4L2_COLORSPACE_LAST to 0, and map V4L2_COLORSPACE_DEFAULT to 2. v4l2_xfer_func and v4l2_ycbcr_encoding are similar case. Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/vpu_color.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_color.c b/drivers/media/platform/amphion/vpu_color.c index 80b9a53fd1c1..4ae435cbc5cd 100644 --- a/drivers/media/platform/amphion/vpu_color.c +++ b/drivers/media/platform/amphion/vpu_color.c @@ -17,7 +17,7 @@ #include "vpu_helpers.h" static const u8 colorprimaries[] = { - 0, + V4L2_COLORSPACE_LAST, V4L2_COLORSPACE_REC709, /*Rec. ITU-R BT.709-6*/ 0, 0, @@ -31,7 +31,7 @@ static const u8 colorprimaries[] = { }; static const u8 colortransfers[] = { - 0, + V4L2_XFER_FUNC_LAST, V4L2_XFER_FUNC_709, /*Rec. ITU-R BT.709-6*/ 0, 0, @@ -53,7 +53,7 @@ static const u8 colortransfers[] = { }; static const u8 colormatrixcoefs[] = { - 0, + V4L2_YCBCR_ENC_LAST, V4L2_YCBCR_ENC_709, /*Rec. ITU-R BT.709-6*/ 0, 0, From 255a4a5f1d2bc70f95ac03defab39f2a7c1fff42 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Sat, 14 Jan 2023 10:41:12 +0100 Subject: [PATCH 095/216] media: mediatek: vcodec: Using pm_runtime_put instead of pm_runtime_put_sync pm_runtime_put will set RPM_ASYNC flag then queue an idle-notification request again, won't return error immediately until current request is scheduled. But pm_runtime_put_sync run the ->runtime_idle() callback directly, return error immediately no matter whether current request is scheduled. Signed-off-by: Yunfei Dong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 4305e4eb9900..777d445999e9 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -72,9 +72,9 @@ static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { int ret; - ret = pm_runtime_put_sync(pm->dev); - if (ret) - mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); + ret = pm_runtime_put(pm->dev); + if (ret && ret != -EAGAIN) + mtk_v4l2_err("pm_runtime_put fail %d", ret); } static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) From c9ca3b53ee31046a9f72cf3ced8dad6582edebfe Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 26 Dec 2022 06:26:06 +0100 Subject: [PATCH 096/216] media: hantro: Use core-generated bus_info value The Hantro driver uses a hardcoded value for the bus_info field in the media device and |struct v4l2_capability|. This worked well when there was just one device. However with the iMX.8 series we are now seeing two Hantro blocks on the same chip. The static bus_info is no longer sufficient for differentiating devices. Since commit f2d8b6917f3b ("media: v4l: ioctl: Set bus_info in v4l_querycap()"), the V4L2 core provides a default value for the bus_info field for platform and PCI devices. This value will match the default value for media devices added by commit cef699749f37 ("media: mc: Set bus_info in media_device_init()"). These defaults are stable and device-specific. Drop the static bus_info values from the hantro driver and use the defaults. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_drv.c | 2 -- drivers/media/platform/verisilicon/hantro_v4l2.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 8cb4a68c9119..b0aeedae7b65 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -1050,8 +1050,6 @@ static int hantro_probe(struct platform_device *pdev) vpu->mdev.dev = vpu->dev; strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); - strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, - sizeof(vpu->mdev.bus_info)); media_device_init(&vpu->mdev); vpu->mdev.ops = &hantro_m2m_media_ops; vpu->v4l2_dev.mdev = &vpu->mdev; diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 30e650edaea8..c0d427956210 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -142,8 +142,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", - vpu->dev->driver->name); return 0; } From be3ae7cf4326e95bb1d5413b63baabc26f4a1324 Mon Sep 17 00:00:00 2001 From: Dong Chuanjian Date: Tue, 27 Dec 2022 03:36:25 +0100 Subject: [PATCH 097/216] media: drivers/media/v4l2-core/v4l2-h264 : add detection of null pointers When the pointer variable is judged to be null, null is returned directly. [hverkuil: fix two checkpatch warnings] Signed-off-by: Dong Chuanjian Acked-by: Nicolas Dufresne Fixes: d3f756ad629b ("media: v4l2: Trace calculated p/b0/b1 initial reflist") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-h264.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c index 72bd64f65198..c00197d095e7 100644 --- a/drivers/media/v4l2-core/v4l2-h264.c +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -305,6 +305,8 @@ static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *bui int n = 0, i; *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + if (!(*out_str)) + return NULL; n += snprintf(*out_str + n, tmp_str_size - n, "|"); @@ -343,6 +345,8 @@ static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *bui int n = 0, i; *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + if (!(*out_str)) + return NULL; n += snprintf(*out_str + n, tmp_str_size - n, "|"); From da727f82b7356a2b28c3393cec888cf3409349cf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:07 +0100 Subject: [PATCH 098/216] media: dt-bindings: amlogic,meson-gx-ao-cec: move to cec subfolder Move amlogic,meson-gx-ao-cec.yaml bindings to cec subfolder and drop unneeded quotes. Signed-off-by: Krzysztof Kozlowski Acked-by: Neil Armstrong Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/{ => cec}/amlogic,meson-gx-ao-cec.yaml | 4 ++-- MAINTAINERS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename Documentation/devicetree/bindings/media/{ => cec}/amlogic,meson-gx-ao-cec.yaml (93%) diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml similarity index 93% rename from Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml rename to Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml index 8d844f4312d1..f65c9681a9f7 100644 --- a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml +++ b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/media/amlogic,meson-gx-ao-cec.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/media/cec/amlogic,meson-gx-ao-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson AO-CEC Controller diff --git a/MAINTAINERS b/MAINTAINERS index 759ba6205117..4182beadef4b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13565,7 +13565,7 @@ L: linux-amlogic@lists.infradead.org S: Supported W: http://linux-meson.com/ T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml +F: Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml F: drivers/media/cec/platform/meson/ao-cec-g12a.c F: drivers/media/cec/platform/meson/ao-cec.c From 8f43766211afaabe019b0252a805e5afe5331962 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:08 +0100 Subject: [PATCH 099/216] media: dt-bindings: st,stm32-cec: move to cec subfolder Move st,stm32-cec.yaml bindings to cec subfolder and drop unneeded "bindings" in the title. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/cec/st,stm32-cec.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml diff --git a/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml new file mode 100644 index 000000000000..2314a9a14650 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/st,stm32-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 CEC + +maintainers: + - Yannick Fertre + +properties: + compatible: + const: st,stm32-cec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Module Clock + - description: Bus Clock + + clock-names: + items: + - const: cec + - const: hdmi-cec + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + cec: cec@40006c00 { + compatible = "st,stm32-cec"; + reg = <0x40006c00 0x400>; + interrupts = ; + clocks = <&rcc CEC_K>, <&clk_lse>; + clock-names = "cec", "hdmi-cec"; + }; + +... From f4b0b85e171b2a1f99126b8feb93fd1fcc98fdac Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:09 +0100 Subject: [PATCH 100/216] media: dt-bindings: cec: convert common CEC properties to DT schema Convert common HDMI CEC adapter bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/cec.txt | 8 ------ .../bindings/media/cec/cec-common.yaml | 28 +++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/cec.txt create mode 100644 Documentation/devicetree/bindings/media/cec/cec-common.yaml diff --git a/Documentation/devicetree/bindings/media/cec.txt b/Documentation/devicetree/bindings/media/cec.txt deleted file mode 100644 index 22d7aae3d3d7..000000000000 --- a/Documentation/devicetree/bindings/media/cec.txt +++ /dev/null @@ -1,8 +0,0 @@ -Common bindings for HDMI CEC adapters - -- hdmi-phandle: phandle to the HDMI controller. - -- needs-hpd: if present the CEC support is only available when the HPD - is high. Some boards only let the CEC pin through if the HPD is high, - for example if there is a level converter that uses the HPD to power - up or down. diff --git a/Documentation/devicetree/bindings/media/cec/cec-common.yaml b/Documentation/devicetree/bindings/media/cec/cec-common.yaml new file mode 100644 index 000000000000..af6ee5f1c73f --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/cec-common.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/cec-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HDMI CEC Adapters Common Properties + +maintainers: + - Hans Verkuil + +properties: + $nodename: + pattern: "^cec(@[0-9a-f]+|-[0-9]+)?$" + + hdmi-phandle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the HDMI controller. + + needs-hpd: + type: boolean + description: + The CEC support is only available when the HPD is high. Some boards only + let the CEC pin through if the HPD is high, for example if there is a + level converter that uses the HPD to power up or down. + +additionalProperties: true diff --git a/MAINTAINERS b/MAINTAINERS index 4182beadef4b..8ee07964b515 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4834,7 +4834,7 @@ S: Supported W: http://linuxtv.org T: git git://linuxtv.org/media_tree.git F: Documentation/ABI/testing/debugfs-cec-error-inj -F: Documentation/devicetree/bindings/media/cec.txt +F: Documentation/devicetree/bindings/media/cec/cec-common.yaml F: Documentation/driver-api/media/cec-core.rst F: Documentation/userspace-api/media/cec F: drivers/media/cec/ From 4498e7ba22ddac18e7f37518fff17b2eb6a77d35 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:10 +0100 Subject: [PATCH 101/216] media: dt-bindings: amlogic,meson-gx-ao-cec: reference common CEC properties Reference common HDMI CEC adapter properties to simplify the binding and have only one place of definition for common properties. Signed-off-by: Krzysztof Kozlowski Acked-by: Neil Armstrong Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/cec/amlogic,meson-gx-ao-cec.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml index f65c9681a9f7..b1fab53418f9 100644 --- a/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml +++ b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml @@ -33,11 +33,8 @@ properties: interrupts: maxItems: 1 - hdmi-phandle: - description: phandle to the HDMI controller - $ref: /schemas/types.yaml#/definitions/phandle - allOf: + - $ref: cec-common.yaml# - if: properties: compatible: @@ -81,7 +78,7 @@ required: - clocks - clock-names -additionalProperties: false +unevaluatedProperties: false examples: - | From d358c05bf33e39e392ba1aefce749d565a3fdd2a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:11 +0100 Subject: [PATCH 102/216] media: dt-bindings: chrontel,ch7322: reference common CEC properties Reference common HDMI CEC adapter properties to simplify the binding and have only one place of definition for common properties. The common CEC binding expects also node name to be 'cec'. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/chrontel,ch7322.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml index 63e5b89d2e0b..af8ada55b3f2 100644 --- a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml +++ b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml @@ -13,6 +13,9 @@ description: The Chrontel CH7322 is a discrete HDMI-CEC controller. It is programmable through I2C and drives a single CEC line. +allOf: + - $ref: /schemas/media/cec/cec-common.yaml# + properties: compatible: const: chrontel,ch7322 @@ -40,16 +43,12 @@ properties: if in auto mode. maxItems: 1 - # see ../cec.txt - hdmi-phandle: - description: phandle to the HDMI controller - required: - compatible - reg - interrupts -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -58,7 +57,7 @@ examples: i2c { #address-cells = <1>; #size-cells = <0>; - ch7322@75 { + cec@75 { compatible = "chrontel,ch7322"; reg = <0x75>; interrupts = <47 IRQ_TYPE_EDGE_RISING>; From 91b40d445d266591ffa38773438156bc270c9e7f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:12 +0100 Subject: [PATCH 103/216] media: dt-bindings: samsung,s5p-cec: convert to DT schema Convert Samsung S5P HDMI CEC adapter bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/cec/samsung,s5p-cec.yaml | 66 +++++++++++++++++++ .../devicetree/bindings/media/s5p-cec.txt | 36 ---------- MAINTAINERS | 2 +- 3 files changed, 67 insertions(+), 37 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml delete mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt diff --git a/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml new file mode 100644 index 000000000000..016c8a77c1a6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/samsung,s5p-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S5PV210 and Exynos HDMI CEC + +maintainers: + - Krzysztof Kozlowski + - Marek Szyprowski + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + const: samsung,s5p-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: hdmicec + + interrupts: + maxItems: 1 + + samsung,syscon-phandle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to PMU system controller interface + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - hdmi-phandle + - interrupts + - samsung,syscon-phandle + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + + cec@101b0000 { + compatible = "samsung,s5p-cec"; + reg = <0x101B0000 0x200>; + + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + interrupts = ; + hdmi-phandle = <&hdmi>; + needs-hpd; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + samsung,syscon-phandle = <&pmu_system_controller>; + }; diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt deleted file mode 100644 index e847291d4aff..000000000000 --- a/Documentation/devicetree/bindings/media/s5p-cec.txt +++ /dev/null @@ -1,36 +0,0 @@ -* Samsung HDMI CEC driver - -The HDMI CEC module is present is Samsung SoCs and its purpose is to -handle communication between HDMI connected devices over the CEC bus. - -Required properties: - - compatible : value should be following - "samsung,s5p-cec" - - - reg : Physical base address of the IP registers and length of memory - mapped region. - - - interrupts : HDMI CEC interrupt number to the CPU. - - clocks : from common clock binding: handle to HDMI CEC clock. - - clock-names : from common clock binding: must contain "hdmicec", - corresponding to entry in the clocks property. - - samsung,syscon-phandle - phandle to the PMU system controller - - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. - -Optional: - - needs-hpd : if present the CEC support is only available when the HPD - is high. See cec.txt for more details. - -Example: - -hdmicec: cec@100b0000 { - compatible = "samsung,s5p-cec"; - reg = <0x100B0000 0x200>; - interrupts = <0 114 0>; - clocks = <&clock CLK_HDMI_CEC>; - clock-names = "hdmicec"; - samsung,syscon-phandle = <&pmu_system_controller>; - hdmi-phandle = <&hdmi>; - pinctrl-names = "default"; - pinctrl-0 = <&hdmi_cec>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 8ee07964b515..a31eb7c0ac6f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2868,7 +2868,7 @@ M: Marek Szyprowski L: linux-samsung-soc@vger.kernel.org L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/s5p-cec.txt +F: Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml F: drivers/media/cec/platform/s5p/ ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT From 343e1eb45d88762f3be46c5396b6ca2d27f5fc67 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:13 +0100 Subject: [PATCH 104/216] media: dt-bindings: cec-gpio: convert to DT schema Convert HDMI CEC GPIO bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/cec-gpio.txt | 42 ----------- .../bindings/media/cec/cec-gpio.yaml | 74 +++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 75 insertions(+), 43 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/cec-gpio.txt create mode 100644 Documentation/devicetree/bindings/media/cec/cec-gpio.yaml diff --git a/Documentation/devicetree/bindings/media/cec-gpio.txt b/Documentation/devicetree/bindings/media/cec-gpio.txt deleted file mode 100644 index 47e8d73d32a3..000000000000 --- a/Documentation/devicetree/bindings/media/cec-gpio.txt +++ /dev/null @@ -1,42 +0,0 @@ -* HDMI CEC GPIO driver - -The HDMI CEC GPIO module supports CEC implementations where the CEC line -is hooked up to a pull-up GPIO line and - optionally - the HPD line is -hooked up to another GPIO line. - -Please note: the maximum voltage for the CEC line is 3.63V, for the HPD and -5V lines it is 5.3V. So you may need some sort of level conversion circuitry -when connecting them to a GPIO line. - -Required properties: - - compatible: value must be "cec-gpio". - - cec-gpios: gpio that the CEC line is connected to. The line should be - tagged as open drain. - -If the CEC line is associated with an HDMI receiver/transmitter, then the -following property is also required: - - - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. - -If the CEC line is not associated with an HDMI receiver/transmitter, then -the following property is optional and can be used for debugging HPD changes: - - - hpd-gpios: gpio that the HPD line is connected to. - -This property is optional and can be used for debugging changes on the 5V line: - - - v5-gpios: gpio that the 5V line is connected to. - -Example for the Raspberry Pi 3 where the CEC line is connected to -pin 26 aka BCM7 aka CE1 on the GPIO pin header, the HPD line is -connected to pin 11 aka BCM17 and the 5V line is connected to pin -15 aka BCM22 (some level shifter is needed for the HPD and 5V lines!): - -#include - -cec-gpio { - compatible = "cec-gpio"; - cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; - hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml new file mode 100644 index 000000000000..64d7ec057672 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/cec-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HDMI CEC GPIO + +maintainers: + - Hans Verkuil + +description: | + The HDMI CEC GPIO module supports CEC implementations where the CEC line is + hooked up to a pull-up GPIO line and - optionally - the HPD line is hooked up + to another GPIO line. + + Please note:: the maximum voltage for the CEC line is 3.63V, for the HPD and + 5V lines it is 5.3V. So you may need some sort of level conversion + circuitry when connecting them to a GPIO line. + +properties: + compatible: + const: cec-gpio + + cec-gpios: + maxItems: 1 + description: + GPIO that the CEC line is connected to. The line should be tagged as open + drain. + + hpd-gpios: + maxItems: 1 + description: + GPIO that the HPD line is connected to. Used for debugging HPD changes + when the CEC line is not associated with an HDMI receiver/transmitter. + + v5-gpios: + maxItems: 1 + description: + GPIO that the 5V line is connected to. Used for debugging changes on the + 5V line. + +required: + - compatible + - cec-gpios + +allOf: + - $ref: cec-common.yaml# + - if: + required: + - hdmi-phandle + then: + properties: + hpd-gpios: false + + - if: + required: + - hpd-gpios + then: + properties: + hdmi-phandle: false + +unevaluatedProperties: false + +examples: + - | + #include + + cec { + compatible = "cec-gpio"; + cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a31eb7c0ac6f..356e22bda662 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4850,7 +4850,7 @@ L: linux-media@vger.kernel.org S: Supported W: http://linuxtv.org T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/cec-gpio.txt +F: Documentation/devicetree/bindings/media/cec/cec-gpio.yaml F: drivers/media/cec/platform/cec-gpio/ CELL BROADBAND ENGINE ARCHITECTURE From c69dff4fa348a44f4bdffbddec72c259b04a4e2a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:14 +0100 Subject: [PATCH 105/216] media: dt-bindings: nvidia,tegra114-cec: convert to DT schema Convert NVIDIA Tegra HDMI CEC bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Acked-by: Thierry Reding Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/cec/nvidia,tegra114-cec.yaml | 58 +++++++++++++++++++ .../devicetree/bindings/media/tegra-cec.txt | 27 --------- MAINTAINERS | 2 +- 3 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml delete mode 100644 Documentation/devicetree/bindings/media/tegra-cec.txt diff --git a/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml new file mode 100644 index 000000000000..369c48fd9bf9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/nvidia,tegra114-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra HDMI CEC + +maintainers: + - Hans Verkuil + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + enum: + - nvidia,tegra114-cec + - nvidia,tegra124-cec + - nvidia,tegra210-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: cec + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - hdmi-phandle + - interrupts + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + + cec@70015000 { + compatible = "nvidia,tegra124-cec"; + reg = <0x70015000 0x00001000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_CEC>; + clock-names = "cec"; + status = "disabled"; + hdmi-phandle = <&hdmi>; + }; diff --git a/Documentation/devicetree/bindings/media/tegra-cec.txt b/Documentation/devicetree/bindings/media/tegra-cec.txt deleted file mode 100644 index c503f06f3b84..000000000000 --- a/Documentation/devicetree/bindings/media/tegra-cec.txt +++ /dev/null @@ -1,27 +0,0 @@ -* Tegra HDMI CEC hardware - -The HDMI CEC module is present in Tegra SoCs and its purpose is to -handle communication between HDMI connected devices over the CEC bus. - -Required properties: - - compatible : value should be one of the following: - "nvidia,tegra114-cec" - "nvidia,tegra124-cec" - "nvidia,tegra210-cec" - - reg : Physical base address of the IP registers and length of memory - mapped region. - - interrupts : HDMI CEC interrupt number to the CPU. - - clocks : from common clock binding: handle to HDMI CEC clock. - - clock-names : from common clock binding: must contain "cec", - corresponding to the entry in the clocks property. - - hdmi-phandle : phandle to the HDMI controller, see also cec.txt. - -Example: - -cec@70015000 { - compatible = "nvidia,tegra124-cec"; - reg = <0x0 0x70015000 0x0 0x00001000>; - interrupts = ; - clocks = <&tegra_car TEGRA124_CLK_CEC>; - clock-names = "cec"; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 356e22bda662..7765944ecca9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3001,7 +3001,7 @@ M: Hans Verkuil L: linux-tegra@vger.kernel.org L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/tegra-cec.txt +F: Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml F: drivers/media/cec/platform/tegra/ ARM/TESLA FSD SoC SUPPORT From aefcc80b7547f921c99701aaabf4217de03f7c92 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 8 Dec 2022 11:31:15 +0100 Subject: [PATCH 106/216] media: dt-bindings: st,stih-cec: convert to DT schema Convert ST STIH4xx HDMI CEC bindings to DT schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/cec/st,stih-cec.yaml | 66 +++++++++++++++++++ .../devicetree/bindings/media/stih-cec.txt | 27 -------- MAINTAINERS | 2 +- 3 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml delete mode 100644 Documentation/devicetree/bindings/media/stih-cec.txt diff --git a/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml new file mode 100644 index 000000000000..aeddf16ed339 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/st,stih-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STIH4xx HDMI CEC + +maintainers: + - Alain Volmat + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + const: st,stih-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: cec-clk + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: cec-irq + + resets: + maxItems: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - hdmi-phandle + - interrupts + - resets + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + + cec@94a087c { + compatible = "st,stih-cec"; + reg = <0x94a087c 0x64>; + + clocks = <&clk_sysin>; + clock-names = "cec-clk"; + hdmi-phandle = <&sti_hdmi>; + interrupts = ; + interrupt-names = "cec-irq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cec0_default>; + resets = <&softreset STIH407_LPM_SOFTRESET>; + }; diff --git a/Documentation/devicetree/bindings/media/stih-cec.txt b/Documentation/devicetree/bindings/media/stih-cec.txt deleted file mode 100644 index ece0832fdeaf..000000000000 --- a/Documentation/devicetree/bindings/media/stih-cec.txt +++ /dev/null @@ -1,27 +0,0 @@ -STMicroelectronics STIH4xx HDMI CEC driver - -Required properties: - - compatible : value should be "st,stih-cec" - - reg : Physical base address of the IP registers and length of memory - mapped region. - - clocks : from common clock binding: handle to HDMI CEC clock - - interrupts : HDMI CEC interrupt number to the CPU. - - pinctrl-names: Contains only one value - "default" - - pinctrl-0: Specifies the pin control groups used for CEC hardware. - - resets: Reference to a reset controller - - hdmi-phandle: Phandle to the HDMI controller, see also cec.txt. - -Example for STIH407: - -sti-cec@94a087c { - compatible = "st,stih-cec"; - reg = <0x94a087c 0x64>; - clocks = <&clk_sysin>; - clock-names = "cec-clk"; - interrupts = ; - interrupt-names = "cec-irq"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cec0_default>; - resets = <&softreset STIH407_LPM_SOFTRESET>; - hdmi-phandle = <&hdmi>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 7765944ecca9..b8a4b52db8ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19951,7 +19951,7 @@ F: sound/soc/sti/ STI CEC DRIVER M: Alain Volmat S: Maintained -F: Documentation/devicetree/bindings/media/stih-cec.txt +F: Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml F: drivers/media/cec/platform/sti/ STK1160 USB VIDEO CAPTURE DRIVER From 30040818b338b8ebc956ce0ebd198f8d593586a6 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 11 Jan 2023 10:39:21 +0100 Subject: [PATCH 107/216] media: rc: gpio-ir-recv: add remove function In case runtime PM is enabled, do runtime PM clean up to remove cpu latency qos request, otherwise driver removal may have below kernel dump: [ 19.463299] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000048 [ 19.472161] Mem abort info: [ 19.474985] ESR = 0x0000000096000004 [ 19.478754] EC = 0x25: DABT (current EL), IL = 32 bits [ 19.484081] SET = 0, FnV = 0 [ 19.487149] EA = 0, S1PTW = 0 [ 19.490361] FSC = 0x04: level 0 translation fault [ 19.495256] Data abort info: [ 19.498149] ISV = 0, ISS = 0x00000004 [ 19.501997] CM = 0, WnR = 0 [ 19.504977] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000049f81000 [ 19.511432] [0000000000000048] pgd=0000000000000000, p4d=0000000000000000 [ 19.518245] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP [ 19.524520] Modules linked in: gpio_ir_recv(+) rc_core [last unloaded: rc_core] [ 19.531845] CPU: 0 PID: 445 Comm: insmod Not tainted 6.2.0-rc1-00028-g2c397a46d47c #72 [ 19.531854] Hardware name: FSL i.MX8MM EVK board (DT) [ 19.531859] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 19.551777] pc : cpu_latency_qos_remove_request+0x20/0x110 [ 19.557277] lr : gpio_ir_recv_runtime_suspend+0x18/0x30 [gpio_ir_recv] [ 19.557294] sp : ffff800008ce3740 [ 19.557297] x29: ffff800008ce3740 x28: 0000000000000000 x27: ffff800008ce3d50 [ 19.574270] x26: ffffc7e3e9cea100 x25: 00000000000f4240 x24: ffffc7e3f9ef0e30 [ 19.574284] x23: 0000000000000000 x22: ffff0061803820f4 x21: 0000000000000008 [ 19.574296] x20: ffffc7e3fa75df30 x19: 0000000000000020 x18: ffffffffffffffff [ 19.588570] x17: 0000000000000000 x16: ffffc7e3f9efab70 x15: ffffffffffffffff [ 19.595712] x14: ffff800008ce37b8 x13: ffff800008ce37aa x12: 0000000000000001 [ 19.602853] x11: 0000000000000001 x10: ffffcbe3ec0dff87 x9 : 0000000000000008 [ 19.609991] x8 : 0101010101010101 x7 : 0000000000000000 x6 : 000000000f0bfe9f [ 19.624261] x5 : 00ffffffffffffff x4 : 0025ab8e00000000 x3 : ffff006180382010 [ 19.631405] x2 : ffffc7e3e9ce8030 x1 : ffffc7e3fc3eb810 x0 : 0000000000000020 [ 19.638548] Call trace: [ 19.640995] cpu_latency_qos_remove_request+0x20/0x110 [ 19.646142] gpio_ir_recv_runtime_suspend+0x18/0x30 [gpio_ir_recv] [ 19.652339] pm_generic_runtime_suspend+0x2c/0x44 [ 19.657055] __rpm_callback+0x48/0x1dc [ 19.660807] rpm_callback+0x6c/0x80 [ 19.664301] rpm_suspend+0x10c/0x640 [ 19.667880] rpm_idle+0x250/0x2d0 [ 19.671198] update_autosuspend+0x38/0xe0 [ 19.675213] pm_runtime_set_autosuspend_delay+0x40/0x60 [ 19.680442] gpio_ir_recv_probe+0x1b4/0x21c [gpio_ir_recv] [ 19.685941] platform_probe+0x68/0xc0 [ 19.689610] really_probe+0xc0/0x3dc [ 19.693189] __driver_probe_device+0x7c/0x190 [ 19.697550] driver_probe_device+0x3c/0x110 [ 19.701739] __driver_attach+0xf4/0x200 [ 19.705578] bus_for_each_dev+0x70/0xd0 [ 19.709417] driver_attach+0x24/0x30 [ 19.712998] bus_add_driver+0x17c/0x240 [ 19.716834] driver_register+0x78/0x130 [ 19.720676] __platform_driver_register+0x28/0x34 [ 19.725386] gpio_ir_recv_driver_init+0x20/0x1000 [gpio_ir_recv] [ 19.731404] do_one_initcall+0x44/0x2ac [ 19.735243] do_init_module+0x48/0x1d0 [ 19.739003] load_module+0x19fc/0x2034 [ 19.742759] __do_sys_finit_module+0xac/0x12c [ 19.747124] __arm64_sys_finit_module+0x20/0x30 [ 19.751664] invoke_syscall+0x48/0x114 [ 19.755420] el0_svc_common.constprop.0+0xcc/0xec [ 19.760132] do_el0_svc+0x38/0xb0 [ 19.763456] el0_svc+0x2c/0x84 [ 19.766516] el0t_64_sync_handler+0xf4/0x120 [ 19.770789] el0t_64_sync+0x190/0x194 [ 19.774460] Code: 910003fd a90153f3 aa0003f3 91204021 (f9401400) [ 19.780556] ---[ end trace 0000000000000000 ]--- Signed-off-by: Li Jun Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 8f1fff7af6c9..8dbe780dae4e 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -126,6 +126,23 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) "gpio-ir-recv-irq", gpio_dev); } +static int gpio_ir_recv_remove(struct platform_device *pdev) +{ + struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); + struct device *pmdev = gpio_dev->pmdev; + + if (pmdev) { + pm_runtime_get_sync(pmdev); + cpu_latency_qos_remove_request(&gpio_dev->qos); + + pm_runtime_disable(pmdev); + pm_runtime_put_noidle(pmdev); + pm_runtime_set_suspended(pmdev); + } + + return 0; +} + #ifdef CONFIG_PM static int gpio_ir_recv_suspend(struct device *dev) { @@ -185,6 +202,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, + .remove = gpio_ir_recv_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(gpio_ir_recv_of_match), From 29b0589a865b6f66d141d79b2dd1373e4e50fe17 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 24 Jan 2023 08:55:33 +0100 Subject: [PATCH 108/216] media: rc: Fix use-after-free bugs caused by ene_tx_irqsim() When the ene device is detaching, function ene_remove() will be called. But there is no function to cancel tx_sim_timer in ene_remove(), the timer handler ene_tx_irqsim() could race with ene_remove(). As a result, the UAF bugs could happen, the process is shown below. (cleanup routine) | (timer routine) | mod_timer(&dev->tx_sim_timer, ..) ene_remove() | (wait a time) | ene_tx_irqsim() | dev->hw_lock //USE | ene_tx_sample(dev) //USE Fix by adding del_timer_sync(&dev->tx_sim_timer) in ene_remove(), The tx_sim_timer could stop before ene device is deallocated. What's more, The rc_unregister_device() and del_timer_sync() should be called first in ene_remove() and the deallocated functions such as free_irq(), release_region() and so on should be called behind them. Because the rc_unregister_device() is well synchronized. Otherwise, race conditions may happen. The situations that may lead to race conditions are shown below. Firstly, the rx receiver is disabled with ene_rx_disable() before rc_unregister_device() in ene_remove(), which means it can be enabled again if a process opens /dev/lirc0 between ene_rx_disable() and rc_unregister_device(). Secondly, the irqaction descriptor is freed by free_irq() before the rc device is unregistered, which means irqaction descriptor may be accessed again after it is deallocated. Thirdly, the timer can call ene_tx_sample() that can write to the io ports, which means the io ports could be accessed again after they are deallocated by release_region(). Therefore, the rc_unregister_device() and del_timer_sync() should be called first in ene_remove(). Suggested by: Sean Young Fixes: 9ea53b74df9c ("V4L/DVB: STAGING: remove lirc_ene0100 driver") Signed-off-by: Duoming Zhou Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index e09270916fbc..11ee21a7db8f 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1106,6 +1106,8 @@ static void ene_remove(struct pnp_dev *pnp_dev) struct ene_device *dev = pnp_get_drvdata(pnp_dev); unsigned long flags; + rc_unregister_device(dev->rdev); + del_timer_sync(&dev->tx_sim_timer); spin_lock_irqsave(&dev->hw_lock, flags); ene_rx_disable(dev); ene_rx_restore_hw_buffer(dev); @@ -1113,7 +1115,6 @@ static void ene_remove(struct pnp_dev *pnp_dev) free_irq(dev->irq, dev); release_region(dev->hw_io, ENE_IO_SIZE); - rc_unregister_device(dev->rdev); kfree(dev); } From be94be1b7fc7e51f9ccef20a0ef76583587275f3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2023 09:21:36 +0100 Subject: [PATCH 109/216] media: atomisp: fix videobuf2 Kconfig depenendency The recent conversion missed the Kconfig bit, so it can now end up in a link error on randconfig builds: ld.lld: error: undefined symbol: vb2_vmalloc_memops >>> referenced by atomisp_fops.c >>> drivers/staging/media/atomisp/pci/atomisp_fops.o:(atomisp_open) in archive vmlinux.a Link: https://lore.kernel.org/r/20230104082212.3770415-1-arnd@kernel.org Fixes: cb48ae89be3b ("media: atomisp: Convert to videobuf2") Signed-off-by: Arnd Bergmann Tested-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 2c8d7fdcc5f7..c9bff98e5309 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -14,7 +14,7 @@ config VIDEO_ATOMISP depends on VIDEO_DEV && INTEL_ATOMISP depends on PMIC_OPREGION select IOSF_MBI - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC select VIDEO_V4L2_SUBDEV_API help Say Y here if your platform supports Intel Atom SoC From 5b8c1d30dc358c07aa0ef7676c2ddc3787abcf86 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Dec 2022 09:12:00 +0100 Subject: [PATCH 110/216] media: atomisp: use vb2_start_streaming_called() Don't touch q->start_streaming_called directly, use the vb2_start_streaming_called() function instead. Link: https://lore.kernel.org/r/bc6c24ec-72ea-64a1-9061-311cc7339827@xs4all.nl Signed-off-by: Hans Verkuil Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index cb01ba65c88f..4f35e8f8250a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -636,10 +636,10 @@ static int atomisp_enum_input(struct file *file, void *fh, static unsigned int atomisp_subdev_streaming_count(struct atomisp_sub_device *asd) { - return asd->video_out_preview.vb_queue.start_streaming_called - + asd->video_out_capture.vb_queue.start_streaming_called - + asd->video_out_video_capture.vb_queue.start_streaming_called - + asd->video_out_vf.vb_queue.start_streaming_called; + return vb2_start_streaming_called(&asd->video_out_preview.vb_queue) + + vb2_start_streaming_called(&asd->video_out_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_video_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_vf.vb_queue); } unsigned int atomisp_streaming_count(struct atomisp_device *isp) From 3376f06932f85eda824597f6ef93fccbbb92b64f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 22 Dec 2022 23:00:48 +0100 Subject: [PATCH 111/216] media: atomisp: Propagate set_fmt() errors in queue_setup() If set_fmt() fails make queue_setup() actually return the error instead of returning 0. This fixes the following oops on set_fmt() failures: [ 1060.378662] ------------[ cut here ]------------ [ 1060.378805] WARNING: CPU: 0 PID: 2080 at drivers/media/common/videobuf2/videobuf2-core.c:840 vb2_core_reqbufs+0x3f7/0x430 [videobuf2_common] ... [ 1060.381414] RIP: 0010:vb2_core_reqbufs+0x3f7/0x430 [videobuf2_common] ... [ 1060.382066] vb2_ioctl_reqbufs+0x9d/0xe0 [videobuf2_v4l2] [ 1060.382181] __video_do_ioctl+0x18e/0x3c0 [videodev] Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index acea7492847d..d953240cc908 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -80,7 +80,7 @@ static int atomisp_queue_setup(struct vb2_queue *vq, out: mutex_unlock(&pipe->asd->isp->mutex); - return 0; + return ret; } static int atomisp_buf_init(struct vb2_buffer *vb) From 60ec70a71a9f9975a5d2dd4a7d97c20da0e41976 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Dec 2022 23:11:47 +0100 Subject: [PATCH 112/216] media: atomisp: Only set default_run_mode on first open of a stream/asd Calling v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode) when the stream is already active (through another /dev/video# node) causes the stream to stop. Move the call to set the default run-mode so that it is only done on the first open of one of the 4 /dev/video# nodes of one of the 2 streams (atomisp-sub-devices / asd-s). Fixes: 2c45e343c581 ("media: atomisp: set per-device's default mode") Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index d953240cc908..ccdd780234a7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -821,13 +821,13 @@ static int atomisp_open(struct file *file) goto done; atomisp_subdev_init_struct(asd); + /* Ensure that a mode is set */ + v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); done: pipe->users++; mutex_unlock(&isp->mutex); - /* Ensure that a mode is set */ - v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); return 0; From 2e18e118c22594cced8121e6ab7ca27a60bcfc29 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 21 Jan 2023 16:54:03 +0100 Subject: [PATCH 113/216] media: atomisp: Fix WARN() when the vb2 start_streaming callback fails The videobuf2-core expects buffers to be put back in the queued state when the vb2 start_streaming callback fails. But the atomisp atomisp_flush_video_pipe() would unconditionally return them to the core in an error state. This triggers the following warning in the videobuf2-core: drivers/media/common/videobuf2/videobuf2-core.c:1652: /* * If done_list is not empty, then start_streaming() didn't call * vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED) but STATE_ERROR or * STATE_DONE. */ WARN_ON(!list_empty(&q->done_list)); Fix this by adding a state argument to atomisp_flush_video_pipe() and use VB2_BUF_STATE_QUEUED as state when atomisp_start_streaming() fails. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_cmd.c | 17 +++++++++-------- drivers/staging/media/atomisp/pci/atomisp_cmd.h | 3 ++- .../staging/media/atomisp/pci/atomisp_ioctl.c | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index d8c7e7367386..e798fa7de5a1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -679,7 +679,8 @@ void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state vb2_buffer_done(&frame->vb.vb2_buf, state); } -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames) +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames) { struct ia_css_frame *frame, *_frame; unsigned long irqflags; @@ -689,15 +690,15 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) { if (warn_on_css_frames) dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n"); - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue) - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) { pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0; - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } spin_unlock_irqrestore(&pipe->irq_lock, irqflags); @@ -706,10 +707,10 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ /* Returns queued buffers back to video-core */ void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd) { - atomisp_flush_video_pipe(&asd->video_out_capture, false); - atomisp_flush_video_pipe(&asd->video_out_vf, false); - atomisp_flush_video_pipe(&asd->video_out_preview, false); - atomisp_flush_video_pipe(&asd->video_out_video_capture, false); + atomisp_flush_video_pipe(&asd->video_out_capture, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_vf, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_preview, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_video_capture, VB2_BUF_STATE_ERROR, false); } /* clean out the parameters that did not apply */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index b8911491581a..e31ba24ec6d5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -57,7 +57,8 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); int atomisp_reset(struct atomisp_device *isp); int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe); void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state); -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames); +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames); void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd); void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd); diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 4f35e8f8250a..e534e1f67572 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -1354,7 +1354,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) ret = atomisp_css_start(asd, css_pipe_id, false); if (ret) { - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); goto out_unlock; } @@ -1530,7 +1530,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq) css_pipe_id = atomisp_get_css_pipe_id(asd); atomisp_css_stop(asd, css_pipe_id, false); - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true); atomisp_subdev_cleanup_pending_events(asd); stopsensor: From bcc5997250a4e4d44056fb49367ed46fb97bc300 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Dec 2022 20:31:43 +0100 Subject: [PATCH 114/216] media: atomisp: Check buffer index is in range inside atomisp_qbuf_wrapper() Check buffer index is in range inside atomisp_qbuf_wrapper() before using it do index pipe->frame_request_config_id[]. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index e534e1f67572..ef6eaad9b634 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -1067,13 +1067,23 @@ int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, return -ENOMEM; } +/* + * FIXME the abuse of buf->reserved2 in the qbuf and dqbuf wrappers comes from + * the original atomisp buffer handling and should be replaced with proper V4L2 + * per frame parameters use. + * + * Once this is fixed these wrappers can be removed, replacing them with direct + * calls to vb2_ioctl_[d]qbuf(). + */ static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */ + if (buf->index >= vdev->queue->num_buffers) + return -EINVAL; + if (!atomisp_is_vf_pipe(pipe) && (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) { /* this buffer will have a per-frame parameter */ @@ -1106,7 +1116,6 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer vb = pipe->vb_queue.bufs[buf->index]; frame = vb_to_frame(vb); - /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */ buf->reserved = asd->frame_status[buf->index]; /* From 0c144c9308a66b4a8d7eb9a0f58d251999870fd1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Dec 2022 22:59:40 +0100 Subject: [PATCH 115/216] media: atomisp: Fix regulator registers on BYT devices with CRC PMIC The Crystal Cove PMIC used on some BYT/CHT devices has different revisions when paired with Bay Trail (BYT) vs Cherry Trail (CHT) SoCs. The current hardcoded values are only valid for CHT devices, change the code so that it uses the correct register values on both BYT and CHT. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_gmin_platform.c | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 3d41fab661cf..f7106ddf5c45 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -57,8 +57,12 @@ enum clock_rate { #define LDO_1P8V_OFF 0x58 /* ... bottom bit is "enabled" */ /* CRYSTAL COVE PMIC register set */ -#define CRYSTAL_1P8V_REG 0x57 -#define CRYSTAL_2P8V_REG 0x5d +#define CRYSTAL_BYT_1P8V_REG 0x5d +#define CRYSTAL_BYT_2P8V_REG 0x66 + +#define CRYSTAL_CHT_1P8V_REG 0x57 +#define CRYSTAL_CHT_2P8V_REG 0x5d + #define CRYSTAL_ON 0x63 #define CRYSTAL_OFF 0x62 @@ -843,6 +847,7 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (!gs || gs->v1p8_on == on) return 0; @@ -898,10 +903,15 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) LDO10_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_1P8V_REG; + else + reg = CRYSTAL_BYT_1P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_1P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v1p8\n"); @@ -918,6 +928,7 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (WARN_ON(!gs)) return -ENODEV; @@ -974,10 +985,15 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) LDO9_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_2P8V_REG; + else + reg = CRYSTAL_BYT_2P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_2P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v2p8\n"); From 21b86873711be1aa019ee8991c293efd09c022fd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Nov 2022 15:06:09 +0100 Subject: [PATCH 116/216] media: atomisp: Remove atomisp_sw_contex struct Remove the atomisp_sw_contex struct, it has only 1 member: running_freq, instead store running_freq directly. While at it also change running_freq from an int to an unsigned int, all values stored in it are unsigned and it is compared to the also unsigned new_freq variable. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_cmd.c | 4 ++-- drivers/staging/media/atomisp/pci/atomisp_fops.c | 2 +- drivers/staging/media/atomisp/pci/atomisp_internal.h | 6 +----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index e798fa7de5a1..33accdf8f3b4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -280,14 +280,14 @@ int atomisp_freq_scaling(struct atomisp_device *isp, done: dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq); - if ((new_freq == isp->sw_contex.running_freq) && !force) + if ((new_freq == isp->running_freq) && !force) return 0; dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq); ret = write_target_freq_to_hw(isp, new_freq); if (!ret) { - isp->sw_contex.running_freq = new_freq; + isp->running_freq = new_freq; trace_ipu_pstate(new_freq, -1); } return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index ccdd780234a7..8d5522bff578 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -681,7 +681,7 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp) * For Merrifield, frequency is scalable. * After boot-up, the default frequency is 200MHz. */ - isp->sw_contex.running_freq = ISP_FREQ_200MHZ; + isp->running_freq = ISP_FREQ_200MHZ; } static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index 653e6d74a966..675007d7d9af 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -194,10 +194,6 @@ struct atomisp_regs { u32 csi_access_viol; }; -struct atomisp_sw_contex { - int running_freq; -}; - #define ATOMISP_DEVICE_STREAMING_DISABLED 0 #define ATOMISP_DEVICE_STREAMING_ENABLED 1 #define ATOMISP_DEVICE_STREAMING_STOPPING 2 @@ -242,7 +238,6 @@ struct atomisp_device { struct v4l2_subdev *motor; struct atomisp_regs saved_regs; - struct atomisp_sw_contex sw_contex; struct atomisp_css_env css_env; /* isp timeout status flag */ @@ -257,6 +252,7 @@ struct atomisp_device { unsigned int mipi_frame_size; const struct atomisp_dfs_config *dfs; unsigned int hpll_freq; + unsigned int running_freq; bool css_initialized; }; From 553a64b7e7cef7690203bb07bd0280dd142c1015 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 26 Nov 2022 23:02:49 +0100 Subject: [PATCH 117/216] media: atomisp: Move power-management over to a custom pm-domain The atomisp does not use standard PCI power-management through the PCI config space. Instead this driver directly tells the P-Unit to disable the ISP over the IOSF. The standard PCI subsystem pm_ops will try to access the config space before (resume) / after (suspend) this driver has turned the ISP on / off, resulting in the following errors: Unable to change power state from D0 to D3hot, device inaccessible Unable to change power state from D3cold to D0, device inaccessible Getting logged into dmesg a whole bunch of time during boot as well as every time the camera is used. To avoid these errors use a custom pm_domain instead of standard driver pm-callbacks so that all the PCI subsys suspend / resume handling is skipped and call pci_save_state() / pci_restore_state() ourselves. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_internal.h | 1 + .../staging/media/atomisp/pci/atomisp_v4l2.c | 44 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index 675007d7d9af..fa38d91420cf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -210,6 +210,7 @@ struct atomisp_device { void __iomem *base; const struct firmware *firmware; + struct dev_pm_domain pm_domain; struct pm_qos_request pm_qos; s32 max_isr_latency; diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index e786b81921da..e994a4a5284e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -524,7 +525,7 @@ static int atomisp_save_iunit_reg(struct atomisp_device *isp) return 0; } -static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp) +static int atomisp_restore_iunit_reg(struct atomisp_device *isp) { struct pci_dev *pdev = to_pci_dev(isp->dev); @@ -662,6 +663,7 @@ static void punit_ddr_dvfs_enable(bool enable) static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) { + struct pci_dev *pdev = to_pci_dev(isp->dev); unsigned long timeout; u32 val = enable ? MRFLD_ISPSSPM0_IUNIT_POWER_ON : MRFLD_ISPSSPM0_IUNIT_POWER_OFF; @@ -703,6 +705,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) tmp = (tmp >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) & MRFLD_ISPSSPM0_ISPSSC_MASK; if (tmp == val) { trace_ipu_cstate(enable); + pdev->current_state = enable ? PCI_D0 : PCI_D3cold; return 0; } @@ -743,6 +746,7 @@ int atomisp_power_off(struct device *dev) pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg); cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE); + pci_save_state(pdev); return atomisp_mrfld_power(isp, false); } @@ -756,6 +760,7 @@ int atomisp_power_on(struct device *dev) if (ret) return ret; + pci_restore_state(to_pci_dev(dev)); cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency); /*restore register values for iUnit and iUnitPHY registers*/ @@ -767,7 +772,7 @@ int atomisp_power_on(struct device *dev) return atomisp_css_init(isp); } -static int __maybe_unused atomisp_suspend(struct device *dev) +static int atomisp_suspend(struct device *dev) { struct atomisp_device *isp = (struct atomisp_device *) dev_get_drvdata(dev); @@ -790,10 +795,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev) } spin_unlock_irqrestore(&isp->lock, flags); + pm_runtime_resume(dev); + return atomisp_power_off(dev); } -static int __maybe_unused atomisp_resume(struct device *dev) +static int atomisp_resume(struct device *dev) { return atomisp_power_on(dev); } @@ -1603,6 +1610,26 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i /* save the iunit context only once after all the values are init'ed. */ atomisp_save_iunit_reg(isp); + /* + * The atomisp does not use standard PCI power-management through the + * PCI config space. Instead this driver directly tells the P-Unit to + * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will + * try to access the config space before (resume) / after (suspend) this + * driver has turned the ISP on / off, resulting in the following errors: + * + * "Unable to change power state from D0 to D3hot, device inaccessible" + * "Unable to change power state from D3cold to D0, device inaccessible" + * + * To avoid these errors override the pm_domain so that all the PCI + * subsys suspend / resume handling is skipped. + */ + isp->pm_domain.ops.runtime_suspend = atomisp_power_off; + isp->pm_domain.ops.runtime_resume = atomisp_power_on; + isp->pm_domain.ops.suspend = atomisp_suspend; + isp->pm_domain.ops.resume = atomisp_resume; + + dev_pm_domain_set(&pdev->dev, &isp->pm_domain); + pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); @@ -1645,6 +1672,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i request_irq_fail: hmm_cleanup(); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); atomisp_unregister_entities(isp); register_entities_fail: atomisp_uninitialize_modules(isp); @@ -1697,6 +1725,7 @@ static void atomisp_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); cpu_latency_qos_remove_request(&isp->pm_qos); atomisp_msi_irq_uninit(isp); @@ -1721,17 +1750,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); -static const struct dev_pm_ops atomisp_pm_ops = { - .runtime_suspend = atomisp_power_off, - .runtime_resume = atomisp_power_on, - .suspend = atomisp_suspend, - .resume = atomisp_resume, -}; static struct pci_driver atomisp_pci_driver = { - .driver = { - .pm = &atomisp_pm_ops, - }, .name = "atomisp-isp2", .id_table = atomisp_pci_tbl, .probe = atomisp_pci_probe, From d8ba8ba6d5d1a559b882b2ebd0d35e9d517924ff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 26 Nov 2022 23:08:25 +0100 Subject: [PATCH 118/216] media: atomisp: Silence "isys dma store at addr, val" debug messages These are clearly debug messages, printing these all the time is not useful. Silence these by simply removing them altogether. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/css_2401_system/host/isys_dma_private.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h index a313e1dc7c71..d65fe9ec9049 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h @@ -34,8 +34,6 @@ void isys2401_dma_reg_store(const isys2401_dma_ID_t dma_id, reg_loc = ISYS2401_DMA_BASE[dma_id] + (reg * sizeof(hrt_data)); - ia_css_print("isys dma store at addr(0x%x) val(%u)\n", reg_loc, - (unsigned int)value); ia_css_device_store_uint32(reg_loc, value); } From e6548795bb10af1e7aa6668224a47fb294ff24d8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 15:27:39 +0100 Subject: [PATCH 119/216] media: atomisp: Remove non working doorbell check from punit_ddr_dvfs_enable() punit_ddr_dvfs_enable() is only used on CHT devices and there dmesg gets filled with: "DDR DVFS, door bell is not cleared within 3ms" messages, so clearly the doorbell checking is not working. This check was added by: https://github.com/intel/ProductionKernelQuilts/blob/master/uefi/cht-m1stable/patches/cam-0340-atomisp-add-door-bell-for-ddr-dvfs-on-cht.patch Which commit message says: "PUNIT interface added to check Req_ACK of freq status". This suggests that the doorbell mechanism may only be available with certain PUNIT fw versions and it seems that many CHT devices do not have this fw version; that or the doorbell mechanism is not working for other reasons. Revert cam-0340-atomisp-add-door-bell-for-ddr-dvfs-on-cht.patch, replacing the doorbell check with a msleep(20) this fixes dmesg getting filled with error messages. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_v4l2.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index e994a4a5284e..9eea8ffbc3d6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -638,27 +638,16 @@ static int atomisp_mrfld_pre_power_down(struct atomisp_device *isp) */ static void punit_ddr_dvfs_enable(bool enable) { - int door_bell = 1 << 8; - int max_wait = 30; int reg; iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); if (enable) { reg &= ~(MRFLD_BIT0 | MRFLD_BIT1); } else { - reg |= (MRFLD_BIT1 | door_bell); + reg |= MRFLD_BIT1; reg &= ~(MRFLD_BIT0); } iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg); - - /* Check Req_ACK to see freq status, wait until door_bell is cleared */ - while ((reg & door_bell) && max_wait--) { - iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); - usleep_range(100, 500); - } - - if (max_wait == -1) - pr_info("DDR DVFS, door bell is not cleared within 3ms\n"); } static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) @@ -671,8 +660,10 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off"); /* WA for P-Unit, if DVFS enabled, ISP timeout observed */ - if (IS_CHT && enable) + if (IS_CHT && enable) { punit_ddr_dvfs_enable(false); + msleep(20); + } /* * FIXME:WA for ECS28A, with this sleep, CTS From 94afce19ff62a89e4c161b0ca7cee2cd4a6454e7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 15:37:41 +0100 Subject: [PATCH 120/216] media: atomisp: Remove useless msleep(10) before power-on on BYT On BYT on poweron/runtime-resume the code is doing: 1. Do nothing 2. msleep(10) 3. Start actual poweron sequence Since the runtime resume can happen at any moment, waiting 10ms after it does not really make any sense. According to both the comment and to: https://github.com/intel/ProductionKernelQuilts/blob/master/uefi/cht-m1stable/patches/cam-0341-atomisp-WA-sleep-10ms-when-power-up-ISP-on-byt.patch Which is the patch which originally added this this was added as a workaround for a single test failing on a single model tablet/laptop. So lets just drop this. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 9eea8ffbc3d6..aa05c69a5c6b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -665,14 +665,6 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) msleep(20); } - /* - * FIXME:WA for ECS28A, with this sleep, CTS - * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort - * PASS, no impact on other platforms - */ - if (IS_BYT && enable) - msleep(10); - /* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */ iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, val, MRFLD_ISPSSPM0_ISPSSC_MASK); From 8b3332b278756f1f40ed74275da9bd2762986363 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Dec 2022 00:21:54 +0100 Subject: [PATCH 121/216] media: atomisp: Remove custom ATOMISP_IOC_ISP_MAKERNOTE ioctl This ioctl simply returns a couple of fixed sensor parameters. With libcamera these fixed parameters are instead stored in a table with sensor-name to parameters mappings (camera_sensor_properties.cpp), so this custom ioctl is not necessary; and it currently has no users. Remove the ioctl and also remove the custom v4l2-ctrls underpinning the ioctl. This is part of a patch-series which tries to remove atomisp specific / custom code from the sensor drivers, with as end goal to make the atomisp drivers regular camera sensor drivers. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-gc0310.c | 63 ------------------ .../media/atomisp/i2c/atomisp-gc2235.c | 63 ------------------ .../media/atomisp/i2c/atomisp-mt9m114.c | 64 ------------------- .../media/atomisp/i2c/atomisp-ov2680.c | 64 ------------------- .../media/atomisp/i2c/atomisp-ov2722.c | 63 ------------------ drivers/staging/media/atomisp/i2c/gc0310.h | 3 - drivers/staging/media/atomisp/i2c/gc2235.h | 3 - drivers/staging/media/atomisp/i2c/mt9m114.h | 3 - drivers/staging/media/atomisp/i2c/ov2680.h | 3 - drivers/staging/media/atomisp/i2c/ov2722.h | 3 - .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 63 ------------------ .../media/atomisp/include/linux/atomisp.h | 20 ------ .../staging/media/atomisp/pci/atomisp_cmd.c | 36 ----------- .../staging/media/atomisp/pci/atomisp_cmd.h | 3 - .../staging/media/atomisp/pci/atomisp_ioctl.c | 7 -- 15 files changed, 461 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 87a634bf9ff5..a9c4724a9358 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -241,27 +241,6 @@ static int gc0310_write_reg_array(struct i2c_client *client, return __gc0310_flush_reg_array(client, &ctrl); } -static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | - (GC0310_F_NUMBER_DEM << 16) | - (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; - return 0; -} - static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) { struct gc0310_device *dev = to_gc0310_sensor(sd); @@ -596,15 +575,6 @@ static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = gc0310_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc0310_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_BIN_FACTOR_HORZ: ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); break; @@ -655,39 +625,6 @@ static const struct v4l2_ctrl_config gc0310_controls[] = { .step = 1, .def = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC0310_FOCAL_LENGTH_DEFAULT, - .max = GC0310_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC0310_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC0310_F_NUMBER_DEFAULT, - .max = GC0310_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC0310_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC0310_F_NUMBER_RANGE, - .max = GC0310_F_NUMBER_RANGE, - .step = 0x01, - .def = GC0310_F_NUMBER_RANGE, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_BIN_FACTOR_HORZ, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 4d5a7e335f85..e6df10bcab8c 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -220,27 +220,6 @@ static int gc2235_write_reg_array(struct i2c_client *client, return __gc2235_flush_reg_array(client, &ctrl); } -static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /* const f number for imx */ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; - return 0; -} - -static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | - (GC2235_F_NUMBER_DEM << 16) | - (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; - return 0; -} - static int gc2235_get_intg_factor(struct i2c_client *client, struct camera_mipi_info *info, const struct gc2235_resolution *res) @@ -467,15 +446,6 @@ static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = gc2235_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc2235_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -499,39 +469,6 @@ static struct v4l2_ctrl_config gc2235_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC2235_FOCAL_LENGTH_DEFAULT, - .max = GC2235_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC2235_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC2235_F_NUMBER_DEFAULT, - .max = GC2235_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC2235_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC2235_F_NUMBER_RANGE, - .max = GC2235_F_NUMBER_RANGE, - .step = 0x01, - .def = GC2235_F_NUMBER_RANGE, - .flags = 0, - }, }; static int __gc2235_init(struct v4l2_subdev *sd) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index a0e8e94b2412..eb34b5cadb33 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -841,28 +841,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, return 0; } -/* TODO: Update to SOC functions, remove exposure and gain */ -static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; - return 0; -} - -static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /* const f number for mt9m114 */ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; - return 0; -} - -static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | - (MT9M114_F_NUMBER_DEM << 16) | - (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; - return 0; -} - /* Horizontal flip the image. */ static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) { @@ -1271,15 +1249,6 @@ static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_HFLIP: ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = mt9m114_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_EXPOSURE_ABSOLUTE: ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); break; @@ -1331,39 +1300,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { .step = 1, .def = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .name = "focal length", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_FOCAL_LENGTH_DEFAULT, - .max = MT9M114_FOCAL_LENGTH_DEFAULT, - .step = 1, - .def = MT9M114_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .name = "f-number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_DEFAULT, - .max = MT9M114_F_NUMBER_DEFAULT, - .step = 1, - .def = MT9M114_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .name = "f-number range", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_RANGE, - .max = MT9M114_F_NUMBER_RANGE, - .step = 1, - .def = MT9M114_F_NUMBER_RANGE, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE_ABSOLUTE, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index fa1de45b7a2d..39f86c7fd12e 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -119,28 +119,6 @@ static int ov2680_write_reg_array(struct i2c_client *client, return 0; } -static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /* const f number for ov2680 */ - - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; - return 0; -} - -static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | - (OV2680_F_NUMBER_DEM << 16) | - (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; - return 0; -} - static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) { struct ov2680_device *dev = to_ov2680_sensor(sd); @@ -517,15 +495,6 @@ static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov2680_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2680_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_BIN_FACTOR_HORZ: ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); break; @@ -556,39 +525,6 @@ static const struct v4l2_ctrl_config ov2680_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2680_FOCAL_LENGTH_DEFAULT, - .max = OV2680_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2680_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2680_F_NUMBER_DEFAULT, - .max = OV2680_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2680_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2680_F_NUMBER_RANGE, - .max = OV2680_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2680_F_NUMBER_RANGE, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_BIN_FACTOR_HORZ, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 887b6f99f6ca..47eefaccbe0b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -261,27 +261,6 @@ static int ov2722_write_reg_array(struct i2c_client *client, return __ov2722_flush_reg_array(client, &ctrl); } -static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | - (OV2722_F_NUMBER_DEM << 16) | - (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; - return 0; -} - static int ov2722_get_intg_factor(struct i2c_client *client, struct camera_mipi_info *info, const struct ov2722_resolution *res) @@ -547,15 +526,6 @@ static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov2722_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2722_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_LINK_FREQ: val = dev->res->mipi_freq; if (val == 0) @@ -586,39 +556,6 @@ static const struct v4l2_ctrl_config ov2722_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2722_FOCAL_LENGTH_DEFAULT, - .max = OV2722_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2722_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2722_F_NUMBER_DEFAULT, - .max = OV2722_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2722_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2722_F_NUMBER_RANGE, - .max = OV2722_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2722_F_NUMBER_RANGE, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_LINK_FREQ, diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 4b9ce681bd93..52b4c07e5cf0 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -38,9 +38,6 @@ #define I2C_RETRY_COUNT 5 #define GC0310_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define GC0310_FOCAL_LENGTH_DEM 100 -#define GC0310_F_NUMBER_DEFAULT_NUM 26 -#define GC0310_F_NUMBER_DEM 10 #define MAX_FMTS 1 diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 806be5dff7a5..dd2d44b40e22 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -44,9 +44,6 @@ #define I2C_RETRY_COUNT 5 #define GC2235_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define GC2235_FOCAL_LENGTH_DEM 100 -#define GC2235_F_NUMBER_DEFAULT_NUM 26 -#define GC2235_F_NUMBER_DEM 10 #define MAX_FMTS 1 diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index bcce18b65fa6..831875071cbb 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -136,9 +136,6 @@ #define MT9M114_BPAT_BGBGGRGR BIT(3) #define MT9M114_FOCAL_LENGTH_NUM 208 /*2.08mm*/ -#define MT9M114_FOCAL_LENGTH_DEM 100 -#define MT9M114_F_NUMBER_DEFAULT_NUM 24 -#define MT9M114_F_NUMBER_DEM 10 #define MT9M114_WAIT_STAT_TIMEOUT 100 #define MT9M114_FLICKER_MODE_50HZ 1 #define MT9M114_FLICKER_MODE_60HZ 2 diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 7ab337b859ad..2bc350c67711 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -37,9 +37,6 @@ #define I2C_RETRY_COUNT 5 #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define OV2680_FOCAL_LENGTH_DEM 100 -#define OV2680_F_NUMBER_DEFAULT_NUM 24 -#define OV2680_F_NUMBER_DEM 10 #define OV2680_BIN_FACTOR_MAX 4 diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index d6e2510bc01c..d4cd6f27ee8d 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -39,9 +39,6 @@ #define I2C_RETRY_COUNT 5 #define OV2722_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define OV2722_FOCAL_LENGTH_DEM 100 -#define OV2722_F_NUMBER_DEFAULT_NUM 26 -#define OV2722_F_NUMBER_DEM 10 #define MAX_FMTS 1 diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index c1cd631455e6..9adaf2fc940a 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -415,27 +415,6 @@ static int ov5693_write_reg_array(struct i2c_client *client, return __ov5693_flush_reg_array(client, &ctrl); } -static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | - (OV5693_F_NUMBER_DEM << 16) | - (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; - return 0; -} - static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) { struct ov5693_device *dev = to_ov5693_sensor(sd); @@ -1107,15 +1086,6 @@ static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov5693_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov5693_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_FOCUS_ABSOLUTE: ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); break; @@ -1152,39 +1122,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV5693_FOCAL_LENGTH_DEFAULT, - .max = OV5693_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV5693_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV5693_F_NUMBER_DEFAULT, - .max = OV5693_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV5693_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV5693_F_NUMBER_RANGE, - .max = OV5693_F_NUMBER_RANGE, - .step = 0x01, - .def = OV5693_F_NUMBER_RANGE, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_FOCUS_ABSOLUTE, diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 3f602b5aaff9..e70e57695300 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -586,20 +586,6 @@ struct atomisp_shading_table { __u16 *data[ATOMISP_NUM_SC_COLORS]; }; -struct atomisp_makernote_info { - /* bits 31-16: numerator, bits 15-0: denominator */ - unsigned int focal_length; - /* bits 31-16: numerator, bits 15-0: denominator*/ - unsigned int f_number_curr; - /* - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ - unsigned int f_number_range; -}; - /* parameter for MACC */ #define ATOMISP_NUM_MACC_AXES 16 struct atomisp_macc_table { @@ -914,8 +900,6 @@ struct atomisp_sensor_ae_bracketing_lut { _IOR('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table) #define ATOMISP_IOC_S_ISP_GDC_TAB \ _IOW('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table) -#define ATOMISP_IOC_ISP_MAKERNOTE \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 11, struct atomisp_makernote_info) /* macc parameter control*/ #define ATOMISP_IOC_G_ISP_MACC \ @@ -1093,10 +1077,6 @@ struct atomisp_sensor_ae_bracketing_lut { * Exposure, Flash and privacy (indicator) light controls, to be upstreamed */ #define V4L2_CID_CAMERA_LASTP1 (V4L2_CID_CAMERA_CLASS_BASE + 1024) -#define V4L2_CID_FOCAL_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 0) -#define V4L2_CID_FNUMBER_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 1) -#define V4L2_CID_FNUMBER_RANGE (V4L2_CID_CAMERA_LASTP1 + 2) - /* Flash related CIDs, see also: * http://linuxtv.org/downloads/v4l-dvb-apis/extended-controls.html\ * #flash-controls */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 33accdf8f3b4..6ee845375a94 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -5493,42 +5493,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd, return ret; } -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config) -{ - struct v4l2_control ctrl; - struct atomisp_device *isp = asd->isp; - - ctrl.id = V4L2_CID_FOCAL_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for focal length\n"); - return -EINVAL; - } else { - config->focal_length = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f-number\n"); - return -EINVAL; - } else { - config->f_number_curr = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_RANGE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f number range\n"); - return -EINVAL; - } else { - config->f_number_range = ctrl.value; - } - - return 0; -} - int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index e31ba24ec6d5..2dfb4abfe463 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -274,9 +274,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd, int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config); -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config); - void atomisp_free_internal_buffers(struct atomisp_sub_device *asd); int atomisp_s_ae_window(struct atomisp_sub_device *asd, diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index ef6eaad9b634..13fc6074dfde 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -1640,7 +1640,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, switch (control->id) { case V4L2_CID_IRIS_ABSOLUTE: case V4L2_CID_EXPOSURE_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_2A_STATUS: case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: case V4L2_CID_EXPOSURE: @@ -1837,7 +1836,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_ABSOLUTE: case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_BIN_FACTOR_HORZ: case V4L2_CID_BIN_FACTOR_VERT: case V4L2_CID_3A_LOCK: @@ -1949,7 +1947,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_EXPOSURE_METERING: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_VCM_TIMING: case V4L2_CID_VCM_SLEW: case V4L2_CID_3A_LOCK: @@ -2285,10 +2282,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, err = atomisp_fixed_pattern_table(asd, arg); break; - case ATOMISP_IOC_ISP_MAKERNOTE: - err = atomisp_exif_makernote(asd, arg); - break; - case ATOMISP_IOC_G_SENSOR_MODE_DATA: err = atomisp_get_sensor_mode_data(asd, arg); break; From 7f04875057eb68e6b371f05ff055134dba1e27d5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Dec 2022 22:19:07 +0100 Subject: [PATCH 122/216] media: atomisp: Remove custom ATOMISP_IOC_G_SENSOR_MODE_DATA ioctl This ioctl returns a number of fixed sensor parameters + a number of mode-specific parameters. With libcamera these fixed parameters are instead stored in a table with sensor-name to parameters mappings (camera_sensor_properties.cpp); and the variable parameters can be derived from the set fmt. So this custom ioctl is not necessary; and it currently has no users. Remove the ioctl and all the sensor drivers xxxx_get_intg_factor() helpers which return this info. This is part of a patch-series which tries to remove atomisp specific / custom code from the sensor drivers, with as end goal to make the atomisp drivers regular camera sensor drivers. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-gc0310.c | 140 ------------------ .../media/atomisp/i2c/atomisp-gc2235.c | 113 -------------- .../media/atomisp/i2c/atomisp-mt9m114.c | 96 ------------ .../media/atomisp/i2c/atomisp-ov2680.c | 82 ---------- .../media/atomisp/i2c/atomisp-ov2722.c | 111 -------------- drivers/staging/media/atomisp/i2c/gc0310.h | 1 - drivers/staging/media/atomisp/i2c/gc2235.h | 1 - drivers/staging/media/atomisp/i2c/ov2722.h | 1 - .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 86 ----------- .../staging/media/atomisp/i2c/ov5693/ov5693.h | 1 - .../media/atomisp/include/linux/atomisp.h | 26 ---- .../atomisp/include/linux/atomisp_platform.h | 1 - drivers/staging/media/atomisp/notes.txt | 6 - .../staging/media/atomisp/pci/atomisp_cmd.c | 19 --- .../staging/media/atomisp/pci/atomisp_cmd.h | 3 - .../staging/media/atomisp/pci/atomisp_ioctl.c | 4 - 16 files changed, 691 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index a9c4724a9358..4968ec51ff1b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -259,140 +259,6 @@ static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) return 0; } -static int gc0310_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc0310_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 val; - u8 reg_val; - int ret; - unsigned int hori_blanking; - unsigned int vert_blanking; - unsigned int sh_delay; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; - dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); - - /* get integration time */ - buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC0310_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC0310_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - /* Getting crop_horizontal_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start); - - /* Getting crop_vertical_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start); - - /* Getting output_width */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "output_width=%d\n", buf->output_width); - - /* Getting output_height */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "output_height=%d\n", buf->output_height); - - buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; - dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end); - dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end); - - /* Getting line_length_pck */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_L, ®_val); - if (ret) - return ret; - hori_blanking = val | (reg_val & 0xFF); - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SH_DELAY, ®_val); - if (ret) - return ret; - sh_delay = reg_val; - buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; - dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, - sh_delay, buf->line_length_pck); - - /* Getting frame_length_lines */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_L, ®_val); - if (ret) - return ret; - vert_blanking = val | (reg_val & 0xFF); - buf->frame_length_lines = buf->output_height + vert_blanking; - dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking, - buf->frame_length_lines); - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) { @@ -889,12 +755,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, goto err; } - ret = gc0310_get_intg_factor(client, gc0310_info, dev->res); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index e6df10bcab8c..cb4c79b483ca 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -220,114 +220,6 @@ static int gc2235_write_reg_array(struct i2c_client *client, return __gc2235_flush_reg_array(client, &ctrl); } -static int gc2235_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc2235_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 reg_val, reg_val_h; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; - - /* get integration time */ - buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC2235_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC2235_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_vertical_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = (reg_val_h << 8) | reg_val; - - buf->crop_horizontal_end = buf->crop_horizontal_start + - buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + - buf->output_height - 1; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_L, ®_val); - if (ret) - return ret; - -#if 0 - u16 dummy = (reg_val_h << 8) | reg_val; -#endif - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_L, ®_val); - -#if 0 - buf->line_length_pck = buf->output_width + 16 + dummy + - (((u16)reg_val_h << 8) | (u16)reg_val) + 4; -#endif - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_L, ®_val); - if (ret) - return ret; - -#if 0 - buf->frame_length_lines = buf->output_height + 32 + - (((u16)reg_val_h << 8) | (u16)reg_val); -#endif - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -680,11 +572,6 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd, goto err; } - ret = gc2235_get_intg_factor(client, gc2235_info, - dev->res); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index eb34b5cadb33..1df38f5fe1f4 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -612,96 +612,6 @@ static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) return 0; } -static int mt9m114_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct mt9m114_res_struct *res) -{ - struct atomisp_sensor_mode_data *buf; - u32 reg_val; - int ret; - - if (!info) - return -EINVAL; - - buf = &info->data; - - ret = mt9m114_read_reg(client, MISENSOR_32BIT, - REG_PIXEL_CLK, ®_val); - if (ret) - return ret; - buf->vt_pix_clk_freq_mhz = reg_val; - - /* get integration time */ - buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - MT9M114_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - MT9M114_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; - - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_START, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_START, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_END, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_END, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_WIDTH, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_HEIGHT, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_HTS, ®_val); - if (ret) - return ret; - buf->line_length_pck = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_VTS, ®_val); - if (ret) - return ret; - buf->frame_length_lines = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static int mt9m114_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -823,12 +733,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, mt9m114_res[index].used = false; } } - ret = mt9m114_get_intg_factor(c, mt9m114_info, - &mt9m114_res[res->res]); - if (ret) { - dev_err(&c->dev, "failed to get integration_factor\n"); - return -EINVAL; - } /* * mt9m114 - we don't poll for context switch * because it does not happen with streaming disabled. diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 39f86c7fd12e..9379c25205b4 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -140,82 +140,6 @@ static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) return 0; } -static int ov2680_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2680_resolution *res) -{ - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u32 reg_val; - int ret; - - dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2680_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2680_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - (res->bin_factor_x * 2) : 1; - buf->binning_factor_y = res->bin_factor_y ? - (res->bin_factor_y * 2) : 1; - return 0; -} - static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -818,12 +742,6 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, goto err; } - ret = ov2680_get_intg_factor(client, ov2680_info, res); - if (ret) { - dev_err(&client->dev, "failed to get integration factor\n"); - goto err; - } - /* * recall flip functions to avoid flip registers * were overridden by default setting diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 47eefaccbe0b..d819ab5de28a 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -261,113 +261,6 @@ static int ov2722_write_reg_array(struct i2c_client *client, return __ov2722_flush_reg_array(client, &ctrl); } -static int ov2722_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2722_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = NULL; - struct atomisp_sensor_mode_data *buf = &info->data; - const unsigned int ext_clk_freq_hz = 19200000; - const unsigned int pll_invariant_div = 10; - unsigned int pix_clk_freq_hz; - u16 pre_pll_clk_div; - u16 pll_multiplier; - u16 op_pix_clk_div; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - dev = to_ov2722_sensor(sd); - - /* pixel clock calculattion */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); - if (ret) - return ret; - - pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; - if (!pre_pll_clk_div) - return -EINVAL; - - pll_multiplier = pll_multiplier & 0x7f; - op_pix_clk_div = op_pix_clk_div & 0x03; - pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier - * op_pix_clk_div / pll_invariant_div; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2722_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -812,10 +705,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, } } - ret = ov2722_get_intg_factor(client, ov2722_info, dev->res); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 52b4c07e5cf0..2a559b0d474d 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -146,7 +146,6 @@ struct gc0310_device { struct v4l2_ctrl_handler ctrl_handler; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; struct gc0310_resolution *res; u8 type; bool power_on; diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index dd2d44b40e22..8e33eb166bed 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -158,7 +158,6 @@ struct gc2235_device { struct gc2235_resolution *res; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; u8 type; }; diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index d4cd6f27ee8d..5802cdb0e90c 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -201,7 +201,6 @@ struct ov2722_device { struct ov2722_resolution *res; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; int run_mode; u16 pixels_per_line; u16 lines_per_frame; diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 9adaf2fc940a..e65759499d81 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -433,84 +433,6 @@ static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) return 0; } -static int ov5693_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov5693_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV5693_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV5693_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -1596,18 +1518,10 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd, if (ret) dev_warn(&client->dev, "ov5693 stream off err\n"); - ret = ov5693_get_intg_factor(client, ov5693_info, - &ov5693_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - ov5693_info->metadata_width = fmt->width * 10 / 8; ov5693_info->metadata_height = 1; ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; -err: mutex_unlock(&dev->input_lock); return ret; } diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index a1366666f49c..c9b9dc780f96 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -228,7 +228,6 @@ struct ov5693_device { struct camera_sensor_platform_data *platform_data; ktime_t timestamp_t_focus_abs; - int vt_pix_clk_freq_mhz; int fmt_idx; int run_mode; int otp_size; diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index e70e57695300..d6da776e9bf4 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -636,28 +636,6 @@ struct atomisp_overlay { unsigned int overlay_start_y; }; -/* Sensor resolution specific data for AE calculation.*/ -struct atomisp_sensor_mode_data { - unsigned int coarse_integration_time_min; - unsigned int coarse_integration_time_max_margin; - unsigned int fine_integration_time_min; - unsigned int fine_integration_time_max_margin; - unsigned int fine_integration_time_def; - unsigned int frame_length_lines; - unsigned int line_length_pck; - unsigned int read_mode; - unsigned int vt_pix_clk_freq_mhz; - unsigned int crop_horizontal_start; /* Sensor crop start cord. (x0,y0)*/ - unsigned int crop_vertical_start; - unsigned int crop_horizontal_end; /* Sensor crop end cord. (x1,y1)*/ - unsigned int crop_vertical_end; - unsigned int output_width; /* input size to ISP after binning/scaling */ - unsigned int output_height; - u8 binning_factor_x; /* horizontal binning factor used */ - u8 binning_factor_y; /* vertical binning factor used */ - u16 hts; -}; - struct atomisp_exposure { unsigned int integration_time[8]; unsigned int shutter_speed[8]; @@ -945,10 +923,6 @@ struct atomisp_sensor_ae_bracketing_lut { #define ATOMISP_IOC_CAMERA_BRIDGE \ _IOWR('v', BASE_VIDIOC_PRIVATE + 19, struct atomisp_bc_video_package) -/* Sensor resolution specific info for AE */ -#define ATOMISP_IOC_G_SENSOR_MODE_DATA \ - _IOR('v', BASE_VIDIOC_PRIVATE + 20, struct atomisp_sensor_mode_data) - #define ATOMISP_IOC_S_EXPOSURE \ _IOW('v', BASE_VIDIOC_PRIVATE + 21, struct atomisp_exposure) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 0253661d4332..559a497975c5 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -210,7 +210,6 @@ struct camera_mipi_info { unsigned int num_lanes; enum atomisp_input_format input_format; enum atomisp_bayer_order raw_bayer_order; - struct atomisp_sensor_mode_data data; enum atomisp_input_format metadata_format; u32 metadata_width; u32 metadata_height; diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt index d3cf6ed547ae..c04c283ff438 100644 --- a/drivers/staging/media/atomisp/notes.txt +++ b/drivers/staging/media/atomisp/notes.txt @@ -36,12 +36,6 @@ a camera_mipi_info struct. This struct is allocated/managed by the core atomisp code. The most important parts of the struct are filled by the atomisp core itself, like e.g. the port number. -The sensor drivers on a set_fmt call do fill in camera_mipi_info.data -which is a atomisp_sensor_mode_data struct. This gets filled from -a function called _get_intg_factor(). This struct is not -used by the atomisp code at all. It is returned to userspace by -a ATOMISP_IOC_G_SENSOR_MODE_DATA and the Android userspace does use this. - Other members of camera_mipi_info which are set by some drivers are: -metadata_width, metadata_height, metadata_effective_width, set by the ov5693 driver (and used by the atomisp core) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 6ee845375a94..b9e7ad57040e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -4212,25 +4212,6 @@ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, return 0; } -/* - * Function to get sensor specific info for current resolution, - * which will be used for auto exposure conversion. - */ -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config) -{ - struct camera_mipi_info *mipi_info; - struct atomisp_device *isp = asd->isp; - - mipi_info = atomisp_to_sensor_mipi_info( - isp->inputs[asd->input_curr].camera); - if (!mipi_info) - return -EINVAL; - - memcpy(config, &mipi_info->data, sizeof(*config)); - return 0; -} - static void __atomisp_update_stream_env(struct atomisp_sub_device *asd, u16 stream_index, struct atomisp_input_stream_info *stream_info) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index 2dfb4abfe463..733b9f8cd06f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -259,9 +259,6 @@ int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd, int atomisp_compare_grid(struct atomisp_sub_device *asd, struct atomisp_grid_info *atomgrid); -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config); - /* This function looks up the closest available resolution. */ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, bool *res_overflow); diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 13fc6074dfde..1e1464abf32b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -2282,10 +2282,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, err = atomisp_fixed_pattern_table(asd, arg); break; - case ATOMISP_IOC_G_SENSOR_MODE_DATA: - err = atomisp_get_sensor_mode_data(asd, arg); - break; - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: if (motor) err = v4l2_subdev_call(motor, core, ioctl, cmd, arg); From 159a61da965a3f099b35c98e9f635e6d14d87d7a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Dec 2022 22:32:22 +0100 Subject: [PATCH 123/216] media: atomisp: Remove V4L2_CID_BIN_FACTOR_HORZ/_VERT The bin-factor-x and bin-factor-y ctrls are only used internally to get a single value to pass to atomisp_css_input_set_binning_factor(), which is supposed to tune the lens-shading correction for the binning factor. But all sensor drivers return either 0 or 1 for this, with 0 meaning unset and 1 meaning no-binning. Even though some modes do actually do binning ... Also note that the removed atomisp_get_sensor_bin_factor() would fall back to 0 if either the x and y factor differ or if the ctrls are not implemented (not all sensor drivers implement them). Simply always pass 0 to atomisp_css_input_set_binning_factor(). This is part of a patch-series which tries to remove atomisp specific / custom code from the sensor drivers, with as end goal to make the atomisp drivers regular camera sensor drivers. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-gc0310.c | 46 ----------------- .../media/atomisp/i2c/atomisp-mt9m114.c | 46 ----------------- .../media/atomisp/i2c/atomisp-ov2680.c | 49 ------------------- .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 46 ----------------- .../media/atomisp/include/linux/atomisp.h | 4 -- .../staging/media/atomisp/pci/atomisp_ioctl.c | 20 -------- .../media/atomisp/pci/atomisp_subdev.c | 36 +------------- 7 files changed, 1 insertion(+), 246 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 4968ec51ff1b..0d90683ed227 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -241,24 +241,6 @@ static int gc0310_write_reg_array(struct i2c_client *client, return __gc0310_flush_reg_array(client, &ctrl); } -static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = dev->res->bin_factor_x; - - return 0; -} - -static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = dev->res->bin_factor_y; - - return 0; -} - static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) { @@ -441,12 +423,6 @@ static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = gc0310_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -491,28 +467,6 @@ static const struct v4l2_ctrl_config gc0310_controls[] = { .step = 1, .def = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, }; static int gc0310_init(struct v4l2_subdev *sd) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 1df38f5fe1f4..0e5a981dd331 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1016,24 +1016,6 @@ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, return 0; } -static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_x; - - return 0; -} - -static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_y; - - return 0; -} - static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) { struct i2c_client *c = v4l2_get_subdevdata(sd); @@ -1159,12 +1141,6 @@ static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ZONE_NUM: ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); - break; case V4L2_CID_EXPOSURE: ret = mt9m114_g_ev(&dev->sd, &ctrl->val); break; @@ -1237,28 +1213,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { .def = 1, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .name = "horizontal binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .name = "vertical binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 9379c25205b4..88fdeb828c6c 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -119,27 +119,6 @@ static int ov2680_write_reg_array(struct i2c_client *client, return 0; } -static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); - *val = dev->res->bin_factor_x; - - return 0; -} - -static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - *val = dev->res->bin_factor_y; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); - return 0; -} - static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -419,12 +398,6 @@ static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov2680_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -449,28 +422,6 @@ static const struct v4l2_ctrl_config ov2680_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, { .ops = &ctrl_ops, .id = V4L2_CID_VFLIP, diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index e65759499d81..da8c3b1d3bcd 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -415,24 +415,6 @@ static int ov5693_write_reg_array(struct i2c_client *client, return __ov5693_flush_reg_array(client, &ctrl); } -static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -1014,12 +996,6 @@ static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_FOCUS_STATUS: ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -1099,28 +1075,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = { .def = 0, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, }; static int ov5693_init(struct v4l2_subdev *sd) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index d6da776e9bf4..63b1bcd35399 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -1071,10 +1071,6 @@ struct atomisp_sensor_ae_bracketing_lut { /* Query Focus Status */ #define V4L2_CID_FOCUS_STATUS (V4L2_CID_CAMERA_LASTP1 + 14) -/* Query sensor's binning factor */ -#define V4L2_CID_BIN_FACTOR_HORZ (V4L2_CID_CAMERA_LASTP1 + 15) -#define V4L2_CID_BIN_FACTOR_VERT (V4L2_CID_CAMERA_LASTP1 + 16) - /* number of frames to skip at stream start */ #define V4L2_CID_G_SKIP_FRAMES (V4L2_CID_CAMERA_LASTP1 + 17) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 1e1464abf32b..b7872d7ac0c3 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -172,24 +172,6 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = { .step = 1, .default_value = 1, }, - { - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Horizontal binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, { .id = V4L2_CID_2A_STATUS, .type = V4L2_CTRL_TYPE_BITMASK, @@ -1836,8 +1818,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_ABSOLUTE: case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_BIN_FACTOR_HORZ: - case V4L2_CID_BIN_FACTOR_VERT: case V4L2_CID_3A_LOCK: case V4L2_CID_TEST_PATTERN: case V4L2_CID_TEST_PATTERN_COLOR_R: diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index cadc468b4c2f..fc9e07bf63ae 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -574,40 +574,6 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd, sel->target, sel->flags, &sel->r); } -static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd) -{ - struct v4l2_control ctrl = {0}; - struct atomisp_device *isp = asd->isp; - int hbin, vbin; - int ret; - - if (isp->inputs[asd->input_curr].type == FILE_INPUT || - isp->inputs[asd->input_curr].type == TEST_PATTERN) - return 0; - - ctrl.id = V4L2_CID_BIN_FACTOR_HORZ; - ret = - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - hbin = ctrl.value; - ctrl.id = V4L2_CID_BIN_FACTOR_VERT; - ret |= - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - vbin = ctrl.value; - - /* - * ISP needs to know binning factor from sensor. - * In case horizontal and vertical sensor's binning factors - * are different or sensor does not support binning factor CID, - * ISP will apply default 0 value. - */ - if (ret || hbin != vbin) - hbin = 0; - - return hbin; -} - void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, uint32_t which, @@ -645,7 +611,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, ATOMISP_INPUT_STREAM_GENERAL, ffmt); atomisp_css_input_set_binning_factor(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, - atomisp_get_sensor_bin_factor(isp_sd)); + 0); atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, fc->bayer_order); atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, From ebfa8f5e8d66a2406427f5836c603c9b4693321b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Dec 2022 22:42:11 +0100 Subject: [PATCH 124/216] media: atomisp: Remove no longer used binning info from sensor resolution info Remove the no longer used bin_factor_x, bin_factor_y and bin_mode members from the resolution info inside various atomisp camera sensor drivers. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/gc0310.h | 6 -- drivers/staging/media/atomisp/i2c/gc2235.h | 27 --------- drivers/staging/media/atomisp/i2c/mt9m114.h | 12 ---- drivers/staging/media/atomisp/i2c/ov2680.h | 39 ------------ drivers/staging/media/atomisp/i2c/ov2722.h | 30 ---------- .../staging/media/atomisp/i2c/ov5693/ov5693.h | 60 ------------------- 6 files changed, 174 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 2a559b0d474d..cae480ae6fba 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -123,9 +123,6 @@ struct gc0310_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -386,9 +383,6 @@ static struct gc0310_resolution gc0310_res_preview[] = { .pixels_per_line = 0x0314, .lines_per_frame = 0x0213, #endif - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 2, .regs = gc0310_VGA_30fps, }, diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 8e33eb166bed..55ea422291ba 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -134,9 +134,6 @@ struct gc2235_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -536,9 +533,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1068, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1600_900_30fps, }, @@ -552,9 +546,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1082_30fps, }, @@ -567,9 +558,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1216_30fps, }, @@ -593,9 +581,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1068, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1600_900_30fps, }, @@ -608,9 +593,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1082_30fps, }, @@ -623,9 +605,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1216_30fps, }, @@ -644,9 +623,6 @@ static struct gc2235_resolution gc2235_res_video[] = { .used = 0, .pixels_per_line = 1828, .lines_per_frame = 888, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1296_736_30fps, }, @@ -659,9 +635,6 @@ static struct gc2235_resolution gc2235_res_video[] = { .used = 0, .pixels_per_line = 1492, .lines_per_frame = 792, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_960_640_30fps, }, diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index 831875071cbb..b0cd1b724394 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -316,9 +316,6 @@ struct mt9m114_res_struct { struct regval_list *regs; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; }; /* 2 bytes used for address: 256 bytes total */ @@ -350,9 +347,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0640, .lines_per_frame = 0x0307, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, { .desc = "848P", @@ -366,9 +360,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0640, .lines_per_frame = 0x03E8, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, { .desc = "960P", @@ -382,9 +373,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0644, /* consistent with regs arrays */ .lines_per_frame = 0x03E5, /* consistent with regs arrays */ - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, }; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 2bc350c67711..596e14453fb3 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -147,9 +147,6 @@ struct ov2680_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; }; struct ov2680_format { @@ -758,9 +755,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .fps = 30, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_1616x1216_30fps, }, @@ -771,9 +765,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .fps = 30, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_1616x1082_30fps, }, @@ -784,9 +775,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_1616x916_30fps, }, @@ -797,9 +785,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_1456x1096_30fps, }, @@ -810,9 +795,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_1296x976_30fps, }, @@ -823,9 +805,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_720p_30fps, }, @@ -836,9 +815,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_800x600_30fps, }, @@ -849,9 +825,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_720x592_30fps, }, @@ -862,9 +835,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_656x496_30fps, }, @@ -875,9 +845,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_QVGA_30fps, }, @@ -888,9 +855,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_CIF_30fps, }, @@ -901,9 +865,6 @@ static struct ov2680_resolution ov2680_res_preview[] = { .pix_clk_freq = 66, .pixels_per_line = 1698,//1704, .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = ov2680_QCIF_30fps, }, diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index 5802cdb0e90c..020743a944c4 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -177,9 +177,6 @@ struct ov2722_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; int mipi_freq; }; @@ -1109,9 +1106,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1632_1092_30fps, .mipi_freq = 422400, @@ -1125,9 +1119,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1452_1092_30fps, .mipi_freq = 422400, @@ -1141,9 +1132,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, @@ -1167,9 +1155,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1632_1092_30fps, .mipi_freq = 422400, @@ -1183,9 +1168,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1452_1092_30fps, .mipi_freq = 422400, @@ -1199,9 +1181,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, @@ -1220,9 +1199,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2048, .lines_per_frame = 1184, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_QVGA_30fps, .mipi_freq = 364800, @@ -1236,9 +1212,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2048, .lines_per_frame = 1184, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_480P_30fps, }, @@ -1251,9 +1224,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index c9b9dc780f96..5e17eaf8fd6e 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -198,9 +198,6 @@ struct ov5693_resolution { int pix_clk_freq; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -1109,9 +1106,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_736x496_30fps, }, { @@ -1123,9 +1117,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1616x1216_30fps, }, { @@ -1137,9 +1128,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2576x1456_30fps, }, { @@ -1151,9 +1139,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2576x1936_30fps, }, }; @@ -1175,9 +1160,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_736x496_30fps, }, { @@ -1189,9 +1171,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1424x1168_30fps, }, { @@ -1203,9 +1182,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1616x1216_30fps, }, { @@ -1217,9 +1193,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1456_30fps, }, { @@ -1231,9 +1204,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1944_30fps, }, }; @@ -1250,9 +1220,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_736x496, }, { @@ -1264,9 +1231,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_336x256, }, { @@ -1278,9 +1242,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_368x304, }, { @@ -1292,9 +1253,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_192x160, }, { @@ -1306,9 +1264,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, .regs = ov5693_1296x736, }, { @@ -1320,9 +1275,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, .regs = ov5693_1296x976, }, { @@ -1334,9 +1286,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1636p_30fps, }, { @@ -1348,9 +1297,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1940x1096, }, { @@ -1362,9 +1308,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1456_30fps, }, { @@ -1376,9 +1319,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1944_30fps, }, }; From 8972ed6ea7a00a39eab8f652e6f2f16a40ed2c3b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Dec 2022 20:14:00 +0100 Subject: [PATCH 125/216] media: atomisp: Remove deferred firmware loading support Make atomisp behave like any other drivers and have it load the firmware at probe time (as it was already doing by default). The deferred firmware loading support needlessly complicates the v4l2_file_operations.open callback (atomisp_open()), getting in the way of allowing multiple opens like a normal v4l2 device would. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_fops.c | 25 ----------- .../staging/media/atomisp/pci/atomisp_fops.h | 2 - .../staging/media/atomisp/pci/atomisp_v4l2.c | 42 +++++++------------ 3 files changed, 14 insertions(+), 55 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 8d5522bff578..c99d115d196f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -757,25 +757,6 @@ static int atomisp_open(struct file *file) mutex_lock(&isp->mutex); asd->subdev.devnode = vdev; - /* Deferred firmware loading case. */ - if (isp->css_env.isp_css_fw.bytes == 0) { - dev_err(isp->dev, "Deferred firmware load.\n"); - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - dev_err(isp->dev, "Failed to load ISP firmware.\n"); - ret = -ENOENT; - goto error; - } - ret = atomisp_css_load_firmware(isp); - if (ret) { - dev_err(isp->dev, "Failed to init css.\n"); - goto error; - } - /* No need to keep FW in memory anymore. */ - release_firmware(isp->firmware); - isp->firmware = NULL; - isp->css_env.isp_css_fw.data = NULL; - } if (!isp->input_cnt) { dev_err(isp->dev, "no camera attached\n"); @@ -901,12 +882,6 @@ static int atomisp_release(struct file *file) atomisp_destroy_pipes_stream_force(asd); - if (defer_fw_load) { - ia_css_unload_firmware(); - isp->css_env.isp_css_fw.data = NULL; - isp->css_env.isp_css_fw.bytes = 0; - } - ret = v4l2_subdev_call(isp->flash, core, s_power, 0); if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off flash\n"); diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h index 10e43126b693..2efc5245e571 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h @@ -33,6 +33,4 @@ int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd); extern const struct v4l2_file_operations atomisp_fops; -extern bool defer_fw_load; - #endif /* __ATOMISP_FOPS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index aa05c69a5c6b..2a949d3dc5d1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -58,12 +58,6 @@ static uint skip_fwload; module_param(skip_fwload, uint, 0644); MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load"); -/* memory optimization: deferred firmware loading */ -bool defer_fw_load; -module_param(defer_fw_load, bool, 0644); -MODULE_PARM_DESC(defer_fw_load, - "Defer FW loading until device is opened (default:disable)"); - /* cross componnet debug message flag */ int dbg_level; module_param(dbg_level, int, 0644); @@ -1514,21 +1508,17 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY; /* Load isp firmware from user space */ - if (!defer_fw_load) { - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - err = -ENOENT; - dev_dbg(&pdev->dev, "Firmware load failed\n"); - goto load_fw_fail; - } + isp->firmware = atomisp_load_firmware(isp); + if (!isp->firmware) { + err = -ENOENT; + dev_dbg(&pdev->dev, "Firmware load failed\n"); + goto load_fw_fail; + } - err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); - if (err) { - dev_dbg(&pdev->dev, "Firmware version check failed\n"); - goto fw_validation_fail; - } - } else { - dev_info(&pdev->dev, "Firmware load will be deferred\n"); + err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); + if (err) { + dev_dbg(&pdev->dev, "Firmware version check failed\n"); + goto fw_validation_fail; } pci_set_master(pdev); @@ -1628,14 +1618,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i } /* Load firmware into ISP memory */ - if (!defer_fw_load) { - err = atomisp_css_load_firmware(isp); - if (err) { - dev_err(&pdev->dev, "Failed to init css.\n"); - goto css_init_fail; - } - } else { - dev_dbg(&pdev->dev, "Skip css init.\n"); + err = atomisp_css_load_firmware(isp); + if (err) { + dev_err(&pdev->dev, "Failed to init css.\n"); + goto css_init_fail; } /* Clear FW image from memory */ release_firmware(isp->firmware); From 20734fcae96c8e5fd164e7afe40088ffe4e71803 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Dec 2022 22:48:15 +0100 Subject: [PATCH 126/216] media: atomisp: Drop atomisp_init_pipe() atomisp_init_pipe() does 3 things: 1. Init a bunch of list-heads / locks 2. Init the vb_queue for the videodev (aka pipe) 3. zero the per-frame parameters related variables of the pipe 1. and 2. really should not be done at file-open time, but once at probe. Currently the code is getting away with doing this on every videodev-open because only 1 open is allowed at a time. 1. is already done at probe time by atomisp_init_subdev_pipe(), move 2. to atomisp_init_subdev_pipe() so that it is also done once at probe. As for 3. The per-frame parameters can only be set from a qbuf ioctl, which can only happen after a reqbufs ioctl and atomisp_buf_cleanup already zeros the per-frame parameters when the buffers are released, so 3. is not necessary at all. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_fops.c | 40 +-------------- .../staging/media/atomisp/pci/atomisp_fops.h | 1 + .../media/atomisp/pci/atomisp_subdev.c | 49 +++++++++++++++---- 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index c99d115d196f..78af97a64362 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -624,7 +624,7 @@ static void atomisp_buf_cleanup(struct vb2_buffer *vb) hmm_free(frame->data); } -static const struct vb2_ops atomisp_vb2_ops = { +const struct vb2_ops atomisp_vb2_ops = { .queue_setup = atomisp_queue_setup, .buf_init = atomisp_buf_init, .buf_cleanup = atomisp_buf_cleanup, @@ -633,40 +633,6 @@ static const struct vb2_ops atomisp_vb2_ops = { .stop_streaming = atomisp_stop_streaming, }; -static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) -{ - int ret; - - /* init locks */ - spin_lock_init(&pipe->irq_lock); - mutex_init(&pipe->vb_queue_mutex); - - /* Init videobuf2 queue structure */ - pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; - pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); - pipe->vb_queue.ops = &atomisp_vb2_ops; - pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; - pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - ret = vb2_queue_init(&pipe->vb_queue); - if (ret) - return ret; - - pipe->vdev.queue = &pipe->vb_queue; - pipe->vdev.queue->lock = &pipe->vb_queue_mutex; - - INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); - INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, 0, - VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, 0, - VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); - - return 0; -} - static void atomisp_dev_init_struct(struct atomisp_device *isp) { unsigned int i; @@ -773,10 +739,6 @@ static int atomisp_open(struct file *file) return -EBUSY; } - ret = atomisp_init_pipe(pipe); - if (ret) - goto error; - if (atomisp_dev_users(isp)) { dev_dbg(isp->dev, "skip init isp in open\n"); goto init_subdev; diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h index 2efc5245e571..883c1851c1c9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h @@ -31,6 +31,7 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd); int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd); +extern const struct vb2_ops atomisp_vb2_ops; extern const struct v4l2_file_operations atomisp_fops; #endif /* __ATOMISP_FOPS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index fc9e07bf63ae..c32db4ffb778 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -25,9 +25,11 @@ #include #include +#include #include "atomisp_cmd.h" #include "atomisp_common.h" #include "atomisp_compat.h" +#include "atomisp_fops.h" #include "atomisp_internal.h" const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = { @@ -1023,14 +1025,31 @@ static const struct v4l2_ctrl_config ctrl_depth_mode = { .def = 0, }; -static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, - struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) +static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, + struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) { + int ret; + pipe->type = buf_type; pipe->asd = asd; pipe->isp = asd->isp; spin_lock_init(&pipe->irq_lock); mutex_init(&pipe->vb_queue_mutex); + + /* Init videobuf2 queue structure */ + pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; + pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); + pipe->vb_queue.ops = &atomisp_vb2_ops; + pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; + pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&pipe->vb_queue); + if (ret) + return ret; + + pipe->vdev.queue = &pipe->vb_queue; + pipe->vdev.queue->lock = &pipe->vb_queue_mutex; + INIT_LIST_HEAD(&pipe->buffers_in_css); INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); @@ -1040,6 +1059,8 @@ static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, memset(pipe->frame_params, 0, VIDEO_MAX_FRAME * sizeof(struct atomisp_css_params_with_list *)); + + return 0; } /* @@ -1085,17 +1106,25 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) if (ret < 0) return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_preview, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_vf, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE", ATOMISP_RUN_MODE_STILL_CAPTURE); From d24a42b9a643c4999a1710c3a30387208a1b60f6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Dec 2022 22:56:03 +0100 Subject: [PATCH 127/216] media: atomisp: Remove unnecessary memset(foo, 0, sizeof(foo)) calls The memory for all of struct atomisp_video_pipe is kzalloc()-ed in atomisp_subdev_init() so there is no need to memset parts of struct atomisp_video_pipe to 0. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_subdev.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index c32db4ffb778..eb8f319fca5c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -1054,11 +1054,6 @@ static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, - 0, VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, - 0, VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); return 0; } From 5141562bf46935cb6b41c0e871283b06690f6c52 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 30 Dec 2022 19:17:13 +0100 Subject: [PATCH 128/216] media: atomisp: Do not turn off sensor when the atomisp-sub-dev does not own it The atomisp driver creates 8 /dev/video# device nodes. 4 nodes (preview / video / viewfinder / capture) for each of 2 possible streams aka atomisp-sub-device-s (asd-s). Both streams start with asd->input_curr set to 0 (to the first sensor), opening + releasing a file-handle on one of the nodes of an asd, while streaming from the other asd causes the sensor to get turned off, leading to the stream failing. The atomisp-code already tracks which asd "owns" a specific sensor, use this to only turn the sensor off if it is owned by the asd. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 78af97a64362..833c7aac8f0a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -828,13 +828,17 @@ static int atomisp_release(struct file *file) atomisp_css_free_stat_buffers(asd); atomisp_free_internal_buffers(asd); - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - core, s_power, 0); - if (ret) - dev_warn(isp->dev, "Failed to power-off sensor\n"); - /* clear the asd field to show this camera is not used */ - isp->inputs[asd->input_curr].asd = NULL; + if (isp->inputs[asd->input_curr].asd == asd) { + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, + core, s_power, 0); + if (ret) + dev_warn(isp->dev, "Failed to power-off sensor\n"); + + /* clear the asd field to show this camera is not used */ + isp->inputs[asd->input_curr].asd = NULL; + } + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; spin_unlock_irqrestore(&isp->lock, flags); From 3f1125db16a5358ac59fd09fab87aa7b7ea622ce Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 18:06:06 +0100 Subject: [PATCH 129/216] media: atomisp: Allow sensor drivers without a s_power callback The s_power callback for v4l2-subdevs has been deprecated, allow sensor drivers without a s_power callback to work by ignoring the -ENOIOCTLCMD return value. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 2 +- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 833c7aac8f0a..ce01479bdd68 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -832,7 +832,7 @@ static int atomisp_release(struct file *file) if (isp->inputs[asd->input_curr].asd == asd) { ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, core, s_power, 0); - if (ret) + if (ret && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off sensor\n"); /* clear the asd field to show this camera is not used */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index b7872d7ac0c3..d1314bdbf7d5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -700,7 +700,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) asd->input_curr != input) { ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, core, s_power, 0); - if (ret) + if (ret && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off sensor\n"); /* clear the asd field to show this camera is not used */ @@ -709,7 +709,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) /* powe on the new sensor */ ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1); - if (ret) { + if (ret && ret != -ENOIOCTLCMD) { dev_err(isp->dev, "Failed to power-on sensor\n"); return ret; } From ba49e91e01876be72186faac75eafd2c0944e581 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 14 Jan 2023 19:10:39 +0100 Subject: [PATCH 130/216] media: atomisp: Remove atomisp_gmin_find_subdev() atomisp_gmin_find_subdev() can be used to lookup a subdev given its i2c-adapter + i2c-client-address. But the only caller of it reads this from the intel_v4l2_subdev_table struct and that same struct already contains a pointer to the v4l2_subdev. So this function is not necessary, drop it and modify its only caller to directly take the subdev from the intel_v4l2_subdev_table struct. Also drop struct intel_v4l2_subdev_i2c_board_info since that now no longer is used. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../include/linux/atomisp_gmin_platform.h | 2 - .../atomisp/include/linux/atomisp_platform.h | 6 --- .../media/atomisp/pci/atomisp_gmin_platform.c | 27 ---------- .../staging/media/atomisp/pci/atomisp_v4l2.c | 54 +++---------------- 4 files changed, 7 insertions(+), 82 deletions(-) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h index 5463d11d4295..64bd54835c32 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h @@ -21,8 +21,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, struct camera_sensor_platform_data *plat_data, enum intel_v4l2_subdev_type type); -struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, - struct i2c_board_info *board_info); int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd); int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def); diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 559a497975c5..82973aa0e1eb 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -125,13 +125,7 @@ struct intel_v4l2_subdev_id { enum atomisp_camera_port port; }; -struct intel_v4l2_subdev_i2c_board_info { - struct i2c_board_info board_info; - int i2c_adapter_id; -}; - struct intel_v4l2_subdev_table { - struct intel_v4l2_subdev_i2c_board_info v4l2_subdev; enum intel_v4l2_subdev_type type; enum atomisp_camera_port port; struct v4l2_subdev *subdev; diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index f7106ddf5c45..ea363f25196c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -149,7 +149,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, enum intel_v4l2_subdev_type type) { int i; - struct i2c_board_info *bi; struct gmin_subdev *gs; struct i2c_client *client = v4l2_get_subdevdata(subdev); struct acpi_device *adev = ACPI_COMPANION(&client->dev); @@ -183,36 +182,10 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, pdata.subdevs[i].type = type; pdata.subdevs[i].port = gs->csi_port; pdata.subdevs[i].subdev = subdev; - pdata.subdevs[i].v4l2_subdev.i2c_adapter_id = client->adapter->nr; - - /* Convert i2c_client to i2c_board_info */ - bi = &pdata.subdevs[i].v4l2_subdev.board_info; - memcpy(bi->type, client->name, I2C_NAME_SIZE); - bi->flags = client->flags; - bi->addr = client->addr; - bi->irq = client->irq; - bi->platform_data = plat_data; - return 0; } EXPORT_SYMBOL_GPL(atomisp_register_i2c_module); -struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, - struct i2c_board_info *board_info) -{ - int i; - - for (i = 0; i < MAX_SUBDEVS && pdata.subdevs[i].type; i++) { - struct intel_v4l2_subdev_table *sd = &pdata.subdevs[i]; - - if (sd->v4l2_subdev.i2c_adapter_id == adapter->nr && - sd->v4l2_subdev.board_info.addr == board_info->addr) - return sd->subdev; - } - return NULL; -} -EXPORT_SYMBOL_GPL(atomisp_gmin_find_subdev); - int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd) { int i, j; diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 2a949d3dc5d1..ba628f7cf385 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -937,45 +937,9 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) /* FIXME: should, instead, use I2C probe */ for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) { - struct v4l2_subdev *subdev; - struct i2c_board_info *board_info = - &subdevs->v4l2_subdev.board_info; - struct i2c_adapter *adapter = - i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); - - dev_info(isp->dev, "Probing Subdev %s\n", board_info->type); - - if (!adapter) { - dev_err(isp->dev, - "Failed to find i2c adapter for subdev %s\n", - board_info->type); - break; - } - - /* In G-Min, the sensor devices will already be probed - * (via ACPI) and registered, do not create new - * ones */ - subdev = atomisp_gmin_find_subdev(adapter, board_info); - if (!subdev) { - dev_warn(isp->dev, "Subdev %s not found\n", - board_info->type); + ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev); + if (ret) continue; - } - ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev); - if (ret) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - if (!subdev) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - dev_info(isp->dev, "Subdev %s successfully register\n", - board_info->type); switch (subdevs->type) { case RAW_CAMERA: @@ -992,7 +956,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) isp->inputs[isp->input_cnt].type = subdevs->type; isp->inputs[isp->input_cnt].port = subdevs->port; - isp->inputs[isp->input_cnt].camera = subdev; + isp->inputs[isp->input_cnt].camera = subdevs->subdev; isp->inputs[isp->input_cnt].sensor_index = 0; /* * initialize the subdev frame size, then next we can @@ -1004,22 +968,18 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) break; case CAMERA_MOTOR: if (isp->motor) { - dev_warn(isp->dev, - "too many atomisp motors, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp motors\n"); continue; } - isp->motor = subdev; + isp->motor = subdevs->subdev; break; case LED_FLASH: case XENON_FLASH: if (isp->flash) { - dev_warn(isp->dev, - "too many atomisp flash devices, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp flash devices\n"); continue; } - isp->flash = subdev; + isp->flash = subdevs->subdev; break; default: dev_dbg(isp->dev, "unknown subdev probed\n"); From f05cf2545ba86156d6acc024b26f35f21636bb83 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 22:09:57 +0100 Subject: [PATCH 131/216] media: atomisp: Add atomisp_register_sensor_no_gmin() helper The DSDT of all Windows BYT / CHT devices which I have seen has proper ACPI powermagement for the clk and regulators used by the sensors. So there is no need for the whole custom atomisp_gmin custom code to disable the ACPI pm and directly poke at the PMIC for this. Add new atomisp_register_sensor_no_gmin() + atomisp_unregister_subdev() helpers which allow registering a sensor with the atomisp code without using any of the atomisp_gmin power-management code. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/include/linux/atomisp_platform.h | 4 ++ .../media/atomisp/pci/atomisp_gmin_platform.c | 61 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 82973aa0e1eb..539b21d39d3b 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -211,6 +211,10 @@ struct camera_mipi_info { }; const struct atomisp_platform_data *atomisp_get_platform_data(void); +int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes, + enum atomisp_input_format format, + enum atomisp_bayer_order bayer_order); +void atomisp_unregister_subdev(struct v4l2_subdev *subdev); /* API from old platform_camera.h, new CPUID implementation */ #define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \ diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index ea363f25196c..34497b4b91d2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1084,6 +1084,67 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) return 0; } +int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes, + enum atomisp_input_format format, + enum atomisp_bayer_order bayer_order) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct acpi_device *adev = ACPI_COMPANION(&client->dev); + int i, ret, clock_num, port = 0; + + if (adev) { + /* Get ACPI _PR0 derived clock to determine the csi_port default */ + if (acpi_device_power_manageable(adev)) { + clock_num = atomisp_get_acpi_power(&client->dev); + + /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */ + if (IS_ISP2401) + port = clock_num == 4 ? 1 : 0; + else + port = clock_num == 0 ? 1 : 0; + } + + port = gmin_get_var_int(&client->dev, false, "CsiPort", port); + lanes = gmin_get_var_int(&client->dev, false, "CsiLanes", lanes); + } + + for (i = 0; i < MAX_SUBDEVS; i++) + if (!pdata.subdevs[i].type) + break; + + if (i >= MAX_SUBDEVS) { + dev_err(&client->dev, "Error too many subdevs already registered\n"); + return -ENOMEM; + } + + ret = camera_sensor_csi_alloc(subdev, port, lanes, format, bayer_order); + if (ret) + return ret; + + pdata.subdevs[i].type = RAW_CAMERA; + pdata.subdevs[i].port = port; + pdata.subdevs[i].subdev = subdev; + return 0; +} +EXPORT_SYMBOL_GPL(atomisp_register_sensor_no_gmin); + +void atomisp_unregister_subdev(struct v4l2_subdev *subdev) +{ + int i; + + for (i = 0; i < MAX_SUBDEVS; i++) { + if (pdata.subdevs[i].subdev != subdev) + continue; + + camera_sensor_csi_free(subdev); + pdata.subdevs[i].subdev = NULL; + pdata.subdevs[i].type = 0; + pdata.subdevs[i].port = 0; + break; + } +} +EXPORT_SYMBOL_GPL(atomisp_unregister_subdev); + static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev, char *camera_module) { From f629e3865701a666f7881fc009d0f0a446421fab Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 22 Jan 2023 16:51:57 +0100 Subject: [PATCH 132/216] media: atomisp: Drop ffmt local var from atomisp_set_fmt() ffmt is a local variable pointing to a substruct of another local variable which really just makes the code harder to read / follow, so drop it. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_cmd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index b9e7ad57040e..eb05288d8fb1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -4992,7 +4992,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) struct v4l2_subdev_format vformat = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct v4l2_mbus_framefmt *ffmt = &vformat.format; struct v4l2_rect isp_sink_crop; u16 source_pad = atomisp_subdev_source_pad(vdev); struct v4l2_subdev_fh fh; @@ -5031,17 +5030,17 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) /* Ensure that the resolution is equal or below the maximum supported */ vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; - v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code); - ffmt->height += padding_h; - ffmt->width += padding_w; + v4l2_fill_mbus_format(&vformat.format, &f->fmt.pix, format_bridge->mbus_code); + vformat.format.height += padding_h; + vformat.format.width += padding_w; ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad, set_fmt, NULL, &vformat); if (ret) return ret; - f->fmt.pix.width = ffmt->width - padding_w; - f->fmt.pix.height = ffmt->height - padding_h; + f->fmt.pix.width = vformat.format.width - padding_w; + f->fmt.pix.height = vformat.format.height - padding_h; snr_fmt = f->fmt.pix; backup_fmt = snr_fmt; From edcb14e5139b09d2e2dc9e9bcf4c1bbdd4ad2e7c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 22 Jan 2023 16:47:26 +0100 Subject: [PATCH 133/216] media: atomisp: Stop overriding padding w/h to 12 on BYT atomisp_set_fmt() first does: v4l2_fill_mbus_format(&vformat.format, ...); vformat.format.height += padding_h; vformat.format.width += padding_w; ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad, set_fmt, NULL, &vformat); if (ret) return ret; f->fmt.pix.width = vformat.format.width - padding_w; f->fmt.pix.height = vformat.format.height - padding_h; this happens with the original padding w/h = 16 values and then later on it calls: ret = atomisp_set_fmt_to_snr(vdev, &s_fmt, f->fmt.pix.pixelformat, padding_w, padding_h, dvs_env_w, dvs_env_h); Which repeats the above structure. If at that point padding w/h are changed to 12 then it will now request a different output-size of the sensor driver. The sensor drivers so far have actually been ignoring this since they use v4l2_find_nearest_size() on a fixed resolution list and the nearest resolution will be the one from the earlier calls where padding w/h was 16. But there really is no reason for sensor drivers to use a fixed resolution list. They make lower resolutions using cropping so they can make any resolution as long as width/height are even numbers. Dropping the fixed-resolution list limit from sensors on BYT results in trying to start streaming failing because the resolution set to the sensor now no longer matches with the resolution used during the initial part of the configuration done by atomisp_set_fmt(). Drop the BYT specific overriding of the padding_w/h to 12, so that the padding in the first and second s_fmt calls made to the sensor matches, to fix stream start failing when the fixed resolution list is dropped. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_cmd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index eb05288d8fb1..47f18ac5e40e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -5163,9 +5163,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) if (!atomisp_subdev_format_conversion(asd, source_pad)) { padding_w = 0; padding_h = 0; - } else if (IS_BYT) { - padding_w = 12; - padding_h = 12; } /* construct resolution supported by isp */ From cb90b196647282fc197804d680ad9d86889e27e4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 22 Jan 2023 20:48:13 +0100 Subject: [PATCH 134/216] media: atomisp: Put sensor ACPI devices in D3 before disable ACPI power-resources The device core will call ACPI to turn the device (i2c_client) for a sensor on / put it in D0 before calling its probe() method. This takes a reference on all of the ACPI power-resources belonging to the device. Since the atomisp_gmin_platform code disables ACPI power-resource management and does its own pm, this reference never gets released. This is a problem for ACPI power-resources which are shared with other devices since those now never get turned off again (nor back on again). Explicitly put the device in D3 before disabling the ACPI power-resource management. Note that atomisp_register_i2c_module() runs near the end of the sensor driver's probe() function, after the driver is done with probing the hw. So the power-resouces (the same resources as directly controlled by the atomisp platform code) getting turned off (a second time, as they are already off) is not a problem. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 34497b4b91d2..7fc7dfa56172 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -161,6 +161,14 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, * tickled during suspend/resume. This has caused power and * performance issues on multiple devices. */ + + /* + * Turn off the device before disabling ACPI power resources + * (the sensor driver has already probed it at this point). + * This avoids leaking the reference count of the (possibly shared) + * ACPI power resources which were enabled/referenced before probe(). + */ + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->power.flags.power_resources = 0; for (i = 0; i < MAX_SUBDEVS; i++) From 15b5128cafd5760c777945ec24cfadf45b6c1206 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 22 Jan 2023 20:59:23 +0100 Subject: [PATCH 135/216] media: atomisp: Remove isp_subdev_link_setup() Looking at isp_subdev_link_setup(), this function can never work, it does a switch-case like this: switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) with cases like this: case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN where ATOMISP_SUBDEV_PAD_SINK matches an index (0-4) and MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN is 0x00020000, but is_media_entity_v4l2_subdev(remote->entity) does not return MEDIA_ENT_F_* values, it return a bool, so 0 or 1 which means that non of the cases can ever match the input value. Looking at the rest of the function all it ever does (if it would actually hit one of the cases) is set the atomisp_sub_device struct's input member. And checking the rest of the atomisp code that member is never read. Also userspace does not actually setup media-controller links when using the atomisp /dev/video$ nodes since all the links are fixed. So isp_subdev_link_setup() never runs. Remove the unnecessary and broken isp_subdev_link_setup() function and also remove the unused atomisp_sub_device struct's input member. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_subdev.c | 79 ------------------- .../media/atomisp/pci/atomisp_subdev.h | 13 --- 2 files changed, 92 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index eb8f319fca5c..52d1936b8c87 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -714,85 +714,8 @@ static void isp_subdev_init_params(struct atomisp_sub_device *asd) } } -/* -* isp_subdev_link_setup - Setup isp subdev connections -* @entity: ispsubdev media entity -* @local: Pad at the local end of the link -* @remote: Pad at the remote end of the link -* @flags: Link flags -* -* return -EINVAL or zero on success -*/ -static int isp_subdev_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); - struct atomisp_device *isp = isp_sd->isp; - unsigned int i; - - switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) { - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - /* Read from the sensor CSI2-ports. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - break; - } - - if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE) - return -EBUSY; - - for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { - if (remote->entity != &isp->csi2_port[i].subdev.entity) - continue; - - isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i; - return 0; - } - - return -EINVAL; - - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 && - isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1 - + ATOMISP_CAMERA_NR_PORTS)) - return -EBUSY; - isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY; - } else { - if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY) - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - } - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - default: - return -EINVAL; - } - - return 0; -} - /* media operations */ static const struct media_entity_operations isp_subdev_media_ops = { - .link_setup = isp_subdev_link_setup, .link_validate = v4l2_subdev_link_validate, /* .set_power = v4l2_subdev_set_power, */ }; @@ -1071,8 +994,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) struct media_entity *me = &sd->entity; int ret; - asd->input = ATOMISP_SUBDEV_INPUT_NONE; - v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index); v4l2_set_subdevdata(sd, asd); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index bd2872cbb50c..daa6077a83bd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -30,18 +30,6 @@ /* EXP_ID's ranger is 1 ~ 250 */ #define ATOMISP_MAX_EXP_ID (250) -enum atomisp_subdev_input_entity { - ATOMISP_SUBDEV_INPUT_NONE, - ATOMISP_SUBDEV_INPUT_MEMORY, - ATOMISP_SUBDEV_INPUT_CSI2, - /* - * The following enum for CSI2 port must go together in one row. - * Otherwise it breaks the code logic. - */ - ATOMISP_SUBDEV_INPUT_CSI2_PORT1, - ATOMISP_SUBDEV_INPUT_CSI2_PORT2, - ATOMISP_SUBDEV_INPUT_CSI2_PORT3, -}; #define ATOMISP_SUBDEV_PAD_SINK 0 /* capture output for still frames */ @@ -267,7 +255,6 @@ struct atomisp_sub_device { struct atomisp_pad_format fmt[ATOMISP_SUBDEV_PADS_NUM]; u16 capture_pad; /* main capture pad; defines much of isp config */ - enum atomisp_subdev_input_entity input; unsigned int output; struct atomisp_video_pipe video_out_capture; /* capture output */ struct atomisp_video_pipe video_out_vf; /* viewfinder output */ From c7c49ac854d0d3ef8ff8ab7e667482faa813e757 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Jan 2023 21:49:10 +0100 Subject: [PATCH 136/216] media: atomisp: Remove csi2_link_setup() Looking at csi2_link_setup(), this function can never work, it does a switch-case like this: switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) with cases like this: case ATOMISP_SUBDEV_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN where ATOMISP_SUBDEV_PAD_SOURCE matches an index (0-1) and MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN is 0x00020000, but is_media_entity_v4l2_subdev(remote->entity) does not return MEDIA_ENT_F_* values, it return a bool, so 0 or 1 which means that non of the cases can ever match the input value. Looking at the rest of the function all it ever does (if it would actually hit one of the cases) is set the atomisp_mipi_csi2_device struct's output member. And checking the rest of the atomisp code that member is never read. Also userspace does not actually setup media-controller links when using the atomisp /dev/video$ nodes since all the links are fixed. So csi2_link_setup() never runs. Remove the unnecessary and broken csi2_link_setup() function and also remove the unused atomisp_mipi_csi2_device struct's output member. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_csi2.c | 39 ------------------- .../staging/media/atomisp/pci/atomisp_csi2.h | 5 --- 2 files changed, 44 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 4a9268bac8a9..7853a23b9f53 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -175,47 +175,8 @@ static const struct v4l2_subdev_ops csi2_ops = { .pad = &csi2_pad_ops, }; -/* - * csi2_link_setup - Setup CSI2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int csi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); - u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity); - - switch (result) { - case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE: - /* not supported yet */ - return -EINVAL; - - case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_ISP_SUBDEV; - } else { - csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV; - } - break; - - default: - /* Link from camera to CSI2 is fixed... */ - return -EINVAL; - } - return 0; -} - /* media operations */ static const struct media_entity_operations csi2_media_ops = { - .link_setup = csi2_link_setup, .link_validate = v4l2_subdev_link_validate, }; diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index e35711be8a37..b245b2f5ce99 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -25,9 +25,6 @@ #define CSI2_PAD_SOURCE 1 #define CSI2_PADS_NUM 2 -#define CSI2_OUTPUT_ISP_SUBDEV BIT(0) -#define CSI2_OUTPUT_MEMORY BIT(1) - struct atomisp_device; struct v4l2_device; struct atomisp_sub_device; @@ -39,8 +36,6 @@ struct atomisp_mipi_csi2_device { struct v4l2_ctrl_handler ctrls; struct atomisp_device *isp; - - u32 output; /* output direction */ }; int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, From c47060369f9cf6724af70945aef4ee3907a4a5ce Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Jan 2023 22:01:20 +0100 Subject: [PATCH 137/216] media: atomisp: Properly initialize function field of media-entity links Don't use MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN to initialize the function field of various media-entity links. This fixes the following warnings showing up in dmesg: atomisp-isp2 0000:00:03.0: Entity type for entity ATOM ISP CSI2-port0 was not initialized! atomisp-isp2 0000:00:03.0: Entity type for entity ATOM ISP CSI2-port1 was not initialized! atomisp-isp2 0000:00:03.0: Entity type for entity ATOM ISP CSI2-port2 was not initialized! atomisp-isp2 0000:00:03.0: Entity type for entity tpg_subdev was not initialized! atomisp-isp2 0000:00:03.0: Entity type for entity ATOMISP_SUBDEV_0 was not initialized! atomisp-isp2 0000:00:03.0: Entity type for entity ATOMISP_SUBDEV_1 was not initialized! Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_csi2.c | 2 +- drivers/staging/media/atomisp/pci/atomisp_subdev.c | 2 +- drivers/staging/media/atomisp/pci/atomisp_tpg.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 7853a23b9f53..b00bc0b7aaad 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -203,7 +203,7 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; me->ops = &csi2_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_VID_IF_BRIDGE; ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); if (ret < 0) return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 52d1936b8c87..9cfb85c61db6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -1017,7 +1017,7 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) MEDIA_BUS_FMT_SBGGR10_1X10; me->ops = &isp_subdev_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads); if (ret < 0) return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index e29a96da5f98..074826a5b706 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -152,7 +152,7 @@ int atomisp_tpg_init(struct atomisp_device *isp) v4l2_set_subdevdata(sd, tpg); pads[0].flags = MEDIA_PAD_FL_SINK; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, 1, pads); if (ret < 0) From 65b3974173a7ffede971456de064cec3e9368135 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Dec 2022 16:48:49 +0100 Subject: [PATCH 138/216] media: core: add ov_16bit_addr_reg_helpers.h The following drivers under drivers/media/i2c: ov08x40.c, ov13858.c, ov13b10.c, ov2680.c, ov2685.c, ov2740.c, ov4689.c, ov5670.c, ov5675.c, ov5695.c, ov8856.c, ov9282.c and ov9734.c, as well as various "atomisp" sensor drivers in drivers/staging, *all* use register access helpers with the following function prototypes: int ovxxxx_read_reg(struct ovxxxx_dev *sensor, u16 reg, unsigned int len, u32 *val); int ovxxxx_write_reg(struct ovxxxx_dev *sensor, u16 reg, unsigned int len, u32 val); To read/write registers on Omnivision OVxxxx image sensors wich expect a 16 bit register address in big-endian format and which have 1-3 byte wide registers, in big-endian format (for the higher width registers). Add a new ov_16bit_addr_reg_helpers.h header file with static inline versions of these register access helpers, so that this code duplication can be removed. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- include/media/ov_16bit_addr_reg_helpers.h | 92 +++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 include/media/ov_16bit_addr_reg_helpers.h diff --git a/include/media/ov_16bit_addr_reg_helpers.h b/include/media/ov_16bit_addr_reg_helpers.h new file mode 100644 index 000000000000..1c60a50bd795 --- /dev/null +++ b/include/media/ov_16bit_addr_reg_helpers.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * I2C register access helpers for Omnivision OVxxxx image sensors which expect + * a 16 bit register address in big-endian format and which have 1-3 byte + * wide registers, in big-endian format (for the higher width registers). + * + * Based on the register helpers from drivers/media/i2c/ov2680.c which is: + * Copyright (C) 2018 Linaro Ltd + */ +#ifndef __OV_16BIT_ADDR_REG_HELPERS_H +#define __OV_16BIT_ADDR_REG_HELPERS_H + +#include +#include +#include + +static inline int ov_read_reg(struct i2c_client *client, u16 reg, + unsigned int len, u32 *val) +{ + u8 addr_buf[2], data_buf[4] = { }; + struct i2c_msg msgs[2]; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret); + return -EIO; + } + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +#define ov_read_reg8(s, r, v) ov_read_reg(s, r, 1, v) +#define ov_read_reg16(s, r, v) ov_read_reg(s, r, 2, v) +#define ov_read_reg24(s, r, v) ov_read_reg(s, r, 3, v) + +static inline int ov_write_reg(struct i2c_client *client, u16 reg, + unsigned int len, u32 val) +{ + u8 buf[6]; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) { + dev_err(&client->dev, "write error: reg=0x%4x: %d\n", reg, ret); + return -EIO; + } + + return 0; +} + +#define ov_write_reg8(s, r, v) ov_write_reg(s, r, 1, v) +#define ov_write_reg16(s, r, v) ov_write_reg(s, r, 2, v) +#define ov_write_reg24(s, r, v) ov_write_reg(s, r, 3, v) + +static inline int ov_update_reg(struct i2c_client *client, u16 reg, u8 mask, u8 val) +{ + u32 readval; + int ret; + + ret = ov_read_reg8(client, reg, &readval); + if (ret < 0) + return ret; + + val = (readval & ~mask) | (val & mask); + + return ov_write_reg8(client, reg, val); +} + +#endif From f76855ef2f561c3787e22194b5d51c45e7d994d2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Dec 2022 17:21:02 +0100 Subject: [PATCH 139/216] media: atomisp: ov2680: Use the new ov_16bit_addr_reg_helpers.h Use the new ov_16bit_addr_reg_helpers.h instead of duplicating the ovxxxx sensor I2C register access helpers found in many different sensor drivers. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 122 ++++-------------- drivers/staging/media/atomisp/i2c/ov2680.h | 4 - 2 files changed, 25 insertions(+), 101 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 88fdeb828c6c..fe1ee09b2a60 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -46,64 +47,6 @@ static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_rggb, }; -/* i2c read/write stuff */ -static int ov2680_read_reg(struct i2c_client *client, - int len, u16 reg, u32 *val) -{ - struct i2c_msg msgs[2]; - u8 addr_buf[2] = { reg >> 8, reg & 0xff }; - u8 data_buf[4] = { 0, }; - int ret; - - if (len > 4) - return -EINVAL; - - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) { - dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret); - return -EIO; - } - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -static int ov2680_write_reg(struct i2c_client *client, unsigned int len, - u16 reg, u16 val) -{ - u8 buf[6]; - int ret; - - if (len == 2) - put_unaligned_be16(val, buf + 2); - else if (len == 1) - buf[2] = val; - else - return -EINVAL; - - put_unaligned_be16(reg, buf); - - ret = i2c_master_send(client, buf, len + 2); - if (ret != len + 2) { - dev_err(&client->dev, "write error %d reg 0x%04x, val 0x%02x: buf sent: %*ph\n", - ret, reg, val, len + 2, &buf); - return -EIO; - } - - return 0; -} - static int ov2680_write_reg_array(struct i2c_client *client, const struct ov2680_reg *reglist) { @@ -111,7 +54,7 @@ static int ov2680_write_reg_array(struct i2c_client *client, int ret; for (; next->reg != 0; next++) { - ret = ov2680_write_reg(client, 1, next->reg, next->val); + ret = ov_write_reg8(client, next->reg, next->val); if (ret) return ret; } @@ -135,8 +78,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, vts = dev->res->lines_per_frame; /* group hold */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x00); + ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0x00); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_GROUP_ACCESS); @@ -147,7 +89,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) vts = (u16)coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; - ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); + ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, vts); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_TIMING_VTS_H); @@ -158,24 +100,21 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, /* Lower four bit should be 0*/ exp_val = coarse_itg << 4; - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_L, exp_val & 0xFF); + ret = ov_write_reg8(client, OV2680_EXPOSURE_L, exp_val & 0xFF); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_EXPOSURE_L); return ret; } - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); + ret = ov_write_reg8(client, OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_EXPOSURE_M); return ret; } - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); + ret = ov_write_reg8(client, OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_EXPOSURE_H); @@ -183,7 +122,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, } /* Analog gain */ - ret = ov2680_write_reg(client, 2, OV2680_AGC_H, gain); + ret = ov_write_reg16(client, OV2680_AGC_H, gain); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", __func__, OV2680_AGC_H); @@ -191,8 +130,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, } /* Digital gain */ if (digitgain) { - ret = ov2680_write_reg(client, 2, - OV2680_MWB_RED_GAIN_H, digitgain); + ret = ov_write_reg16(client, OV2680_MWB_RED_GAIN_H, digitgain); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", @@ -200,8 +138,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, return ret; } - ret = ov2680_write_reg(client, 2, - OV2680_MWB_GREEN_GAIN_H, digitgain); + ret = ov_write_reg16(client, OV2680_MWB_GREEN_GAIN_H, digitgain); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", @@ -209,8 +146,7 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, return ret; } - ret = ov2680_write_reg(client, 2, - OV2680_MWB_BLUE_GAIN_H, digitgain); + ret = ov_write_reg16(client, OV2680_MWB_BLUE_GAIN_H, digitgain); if (ret) { dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", @@ -220,14 +156,12 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, } /* End group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x10); + ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0x10); if (ret) return ret; /* Delay launch group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0xa0); + ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0xa0); if (ret) return ret; return ret; @@ -294,7 +228,7 @@ static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) int ret; /* get exposure */ - ret = ov2680_read_reg(client, 3, OV2680_EXPOSURE_H, ®_val); + ret = ov_read_reg24(client, OV2680_EXPOSURE_H, ®_val); if (ret) return ret; @@ -312,7 +246,7 @@ static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) u8 index; dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val); + ret = ov_read_reg8(client, OV2680_FLIP_REG, &val); if (ret) return ret; if (value) @@ -320,8 +254,7 @@ static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) else val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov2680_write_reg(client, 1, - OV2680_FLIP_REG, val); + ret = ov_write_reg8(client, OV2680_FLIP_REG, val); if (ret) return ret; index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : @@ -343,7 +276,7 @@ static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, 1, OV2680_MIRROR_REG, &val); + ret = ov_read_reg8(client, OV2680_MIRROR_REG, &val); if (ret) return ret; if (value) @@ -351,8 +284,7 @@ static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) else val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov2680_write_reg(client, 1, - OV2680_MIRROR_REG, val); + ret = ov_write_reg8(client, OV2680_MIRROR_REG, val); if (ret) return ret; index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : @@ -449,7 +381,7 @@ static int ov2680_init_registers(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - ret = ov2680_write_reg(client, 1, OV2680_SW_RESET, 0x01); + ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01); ret |= ov2680_write_reg_array(client, ov2680_global_setting); return ret; @@ -687,7 +619,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN) vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN; - ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); + ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, vts); if (ret) { dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); goto err; @@ -739,14 +671,12 @@ static int ov2680_detect(struct i2c_client *client) if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_CHIP_ID_H, &high); + ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high); if (ret) { dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); return -ENODEV; } - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_CHIP_ID_L, &low); + ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low); id = ((((u16)high) << 8) | (u16)low); if (id != OV2680_ID) { @@ -754,8 +684,7 @@ static int ov2680_detect(struct i2c_client *client) return -ENODEV; } - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_SUB_ID, &high); + ret = ov_read_reg8(client, OV2680_SC_CMMN_SUB_ID, &high); revision = (u8)high & 0x0f; dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n", @@ -776,9 +705,8 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) else dev_dbg(&client->dev, "ov2680_s_stream off\n"); - ret = ov2680_write_reg(client, 1, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : - OV2680_STOP_STREAMING); + ret = ov_write_reg8(client, OV2680_SW_STREAM, + enable ? OV2680_START_STREAMING : OV2680_STOP_STREAMING); //otp valid at stream on state //if(!dev->otp_data) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 596e14453fb3..f4760a70055d 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -32,10 +32,6 @@ #include "../include/linux/atomisp_platform.h" -/* Defines for register writes and register array processing */ -#define I2C_MSG_LENGTH 0x2 -#define I2C_RETRY_COUNT 5 - #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ #define OV2680_BIN_FACTOR_MAX 4 From 91caf7975883a53905fe5e126e8083c265b629c2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 3 Jan 2023 19:53:28 +0100 Subject: [PATCH 140/216] media: atomisp: ov2680: Rework flip ctrls Rework the flip ctrls to be more like those of mainline (non staging) drivers. This is modelled after the main ov2680 and ov5693 drivers. This also introduces __ov2680_get_pad_format() to make the ov2680 code more compliant with the mainline v4l2-subdev APIs. Note the OV2680_FLIP_REG and OV2680_MIRROR_REG defines are renamed to OV2680_REG_FORMAT1 and OV2680_REG_FORMAT2 to match the datasheet. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 296 ++++++++---------- drivers/staging/media/atomisp/i2c/ov2680.h | 31 +- 2 files changed, 159 insertions(+), 168 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index fe1ee09b2a60..d17000df7446 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -38,8 +38,6 @@ #include "ov2680.h" -static int h_flag; -static int v_flag; static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_bggr, atomisp_bayer_order_grbg, @@ -237,82 +235,78 @@ static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) return 0; } -static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) +static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt) { - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u32 val; - u8 index; + static const int ov2680_hv_flip_bayer_order[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + }; + struct camera_mipi_info *ov2680_info; + int hv_flip = 0; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov_read_reg8(client, OV2680_FLIP_REG, &val); - if (ret) - return ret; - if (value) - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - else - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; + if (sensor->ctrls.vflip->val) + hv_flip += 1; - ret = ov_write_reg8(client, OV2680_FLIP_REG, val); - if (ret) - return ret; - index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : - 0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - } - return ret; + if (sensor->ctrls.hflip->val) + hv_flip += 2; + + fmt->code = ov2680_hv_flip_bayer_order[hv_flip]; + + /* TODO atomisp specific custom API, should be removed */ + ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd); + if (ov2680_info) + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip]; } -static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) +static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val) { - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - u32 val; - u8 index; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); + if (sensor->is_streaming) + return -EBUSY; - ret = ov_read_reg8(client, OV2680_MIRROR_REG, &val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT1, BIT(2), val ? BIT(2) : 0); + if (ret < 0) return ret; - if (value) - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - else - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov_write_reg8(client, OV2680_MIRROR_REG, val); - if (ret) + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; +} + +static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val) +{ + int ret; + + if (sensor->is_streaming) + return -EBUSY; + + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT2, BIT(2), val ? BIT(2) : 0); + if (ret < 0) return ret; - index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : - 0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - } - return ret; + + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; } static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) { - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct ov2680_device *sensor = to_ov2680_sensor(sd); + int ret; + + if (!sensor->power_on) { + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; + } switch (ctrl->id) { case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_v_flip(&dev->sd, ctrl->val); + ret = ov2680_set_vflip(sensor, ctrl->val); break; case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_h_flip(&dev->sd, ctrl->val); + ret = ov2680_set_hflip(sensor, ctrl->val); break; default: ret = -EINVAL; @@ -322,13 +316,12 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); int ret = 0; switch (ctrl->id) { case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2680_q_exposure(&dev->sd, &ctrl->val); + ret = ov2680_q_exposure(sd, &ctrl->val); break; default: ret = -EINVAL; @@ -337,45 +330,11 @@ static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static const struct v4l2_ctrl_ops ctrl_ops = { +static const struct v4l2_ctrl_ops ov2680_ctrl_ops = { .s_ctrl = ov2680_s_ctrl, .g_volatile_ctrl = ov2680_g_volatile_ctrl }; -static const struct v4l2_ctrl_config ov2680_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, -}; - static int ov2680_init_registers(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -506,8 +465,6 @@ static int power_down(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - h_flag = 0; - v_flag = 0; if (!dev->platform_data) { dev_err(&client->dev, "no camera_sensor_platform_data"); @@ -558,46 +515,51 @@ static int ov2680_s_power(struct v4l2_subdev *sd, int on) return ret; } +static struct v4l2_mbus_framefmt * +__ov2680_get_pad_format(struct ov2680_device *sensor, + struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&sensor->sd, state, pad); + + return &sensor->mode.fmt; +} + +static void ov2680_fill_format(struct ov2680_device *sensor, + struct v4l2_mbus_framefmt *fmt, + unsigned int width, unsigned int height) +{ + memset(fmt, 0, sizeof(*fmt)); + fmt->width = width; + fmt->height = height; + fmt->field = V4L2_FIELD_NONE; + ov2680_set_bayer_order(sensor, fmt); +} + static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct v4l2_mbus_framefmt *fmt = &format->format; struct ov2680_device *dev = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2680_info = NULL; + struct v4l2_mbus_framefmt *fmt; struct ov2680_resolution *res; int vts, ret = 0; - dev_dbg(&client->dev, "%s: %s: pad: %d, fmt: %p\n", - __func__, - (format->which == V4L2_SUBDEV_FORMAT_TRY) ? "try" : "set", - format->pad, fmt); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (!ov2680_info) - return -EINVAL; - - res = v4l2_find_nearest_size(ov2680_res_preview, - ARRAY_SIZE(ov2680_res_preview), width, - height, fmt->width, fmt->height); + res = v4l2_find_nearest_size(ov2680_res_preview, ARRAY_SIZE(ov2680_res_preview), + width, height, + format->format.width, format->format.height); if (!res) res = &ov2680_res_preview[N_RES_PREVIEW - 1]; - fmt->width = res->width; - fmt->height = res->height; + fmt = __ov2680_get_pad_format(dev, sd_state, format->pad, format->which); + ov2680_fill_format(dev, fmt, res->width, res->height); - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + format->format = *fmt; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - } dev_dbg(&client->dev, "%s: %dx%d\n", __func__, fmt->width, fmt->height); @@ -629,10 +591,9 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, * recall flip functions to avoid flip registers * were overridden by default setting */ - if (h_flag) - ov2680_h_flip(sd, h_flag); - if (v_flag) - ov2680_v_flip(sd, v_flag); + ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); + if (ret < 0) + goto err; dev->res = res; err: @@ -644,19 +605,11 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct v4l2_mbus_framefmt *fmt = &format->format; struct ov2680_device *dev = to_ov2680_sensor(sd); + struct v4l2_mbus_framefmt *fmt; - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = dev->res->width; - fmt->height = dev->res->height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - + fmt = __ov2680_get_pad_format(dev, sd_state, format->pad, format->which); + format->format = *fmt; return 0; } @@ -707,6 +660,11 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) ret = ov_write_reg8(client, OV2680_SW_STREAM, enable ? OV2680_START_STREAMING : OV2680_STOP_STREAMING); + if (ret == 0) { + dev->is_streaming = enable; + v4l2_ctrl_activate(dev->ctrls.vflip, !enable); + v4l2_ctrl_activate(dev->ctrls.hflip, !enable); + } //otp valid at stream on state //if(!dev->otp_data) @@ -867,6 +825,29 @@ static const struct v4l2_subdev_ops ov2680_ops = { .sensor = &ov2680_sensor_ops, }; +static int ov2680_init_controls(struct ov2680_device *sensor) +{ + const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; + struct ov2680_ctrls *ctrls = &sensor->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + + v4l2_ctrl_handler_init(hdl, 2); + + hdl->lock = &sensor->input_lock; + + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + + ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + if (hdl->error) + return hdl->error; + + sensor->sd.ctrl_handler = hdl; + return 0; +} + static void ov2680_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -878,7 +859,7 @@ static void ov2680_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_ctrl_handler_free(&dev->ctrls.handler); kfree(dev); } @@ -887,7 +868,6 @@ static int ov2680_probe(struct i2c_client *client) struct ov2680_device *dev; int ret; void *pdata; - unsigned int i; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -895,6 +875,7 @@ static int ov2680_probe(struct i2c_client *client) mutex_init(&dev->input_lock); + dev->client = client; dev->res = &ov2680_res_preview[0]; dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; dev->gain = 250; /* 0-2047 */ @@ -912,40 +893,31 @@ static int ov2680_probe(struct i2c_client *client) if (ret) goto out_free; - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; dev->pad.flags = MEDIA_PAD_FL_SOURCE; dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov2680_controls)); + + ret = ov2680_init_controls(dev); if (ret) { ov2680_remove(client); return ret; } - for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov2680_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); if (ret) { ov2680_remove(client); - dev_dbg(&client->dev, "+++ remove ov2680\n"); + return ret; } - return ret; + + ov2680_fill_format(dev, &dev->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) { + ov2680_remove(client); + return ret; + } + + return 0; out_free: dev_dbg(&client->dev, "+++ out free\n"); v4l2_device_unregister_subdev(&dev->sd); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index f4760a70055d..c7b6fc8bf33d 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -32,6 +32,9 @@ #include "../include/linux/atomisp_platform.h" +#define OV2680_NATIVE_WIDTH 1616 +#define OV2680_NATIVE_HEIGHT 1216 + #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ #define OV2680_BIN_FACTOR_MAX 4 @@ -112,11 +115,8 @@ #define OV2680_FRAME_OFF_NUM 0x4202 /*Flip/Mirror*/ -#define OV2680_FLIP_REG 0x3820 -#define OV2680_MIRROR_REG 0x3821 -#define OV2680_FLIP_BIT 1 -#define OV2680_MIRROR_BIT 2 -#define OV2680_FLIP_MIRROR_BIT_ENABLE 4 +#define OV2680_REG_FORMAT1 0x3820 +#define OV2680_REG_FORMAT2 0x3821 #define OV2680_MWB_RED_GAIN_H 0x5004/*0x3400*/ #define OV2680_MWB_GREEN_GAIN_H 0x5006/*0x3402*/ @@ -158,13 +158,24 @@ struct ov2680_device { struct v4l2_subdev sd; struct media_pad pad; struct mutex input_lock; - struct v4l2_ctrl_handler ctrl_handler; + struct i2c_client *client; struct ov2680_resolution *res; struct camera_sensor_platform_data *platform_data; bool power_on; + bool is_streaming; u16 exposure; u16 gain; u16 digitgain; + + struct ov2680_mode { + struct v4l2_mbus_framefmt fmt; + } mode; + + struct ov2680_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + } ctrls; }; /** @@ -182,6 +193,14 @@ struct ov2680_reg { #define to_ov2680_sensor(x) container_of(x, struct ov2680_device, sd) +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *sensor = + container_of(ctrl->handler, struct ov2680_device, ctrls.handler); + + return &sensor->sd; +} + #define OV2680_MAX_WRITE_BUF_SIZE 30 struct ov2680_write_buffer { From 8eb47aa3a156fcebe7d5b4d4c34a1341da0df253 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Dec 2022 17:24:34 +0100 Subject: [PATCH 141/216] media: atomisp: ov2680: Drop custom ATOMISP_IOC_S_EXPOSURE support Exposure and gain control should use standard v4l2 controls, not a custom ioctl. The next patch in this series will re-add support as standard controls, this is split into 2 patches for easier reviewing. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 209 +----------------- drivers/staging/media/atomisp/i2c/ov2680.h | 3 - 2 files changed, 2 insertions(+), 210 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index d17000df7446..8fadccfbc1c6 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -60,181 +60,6 @@ static int ov2680_write_reg_array(struct i2c_client *client, return 0; } -static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts; - int ret, exp_val; - - dev_dbg(&client->dev, - "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n", - coarse_itg, gain, digitgain); - - vts = dev->res->lines_per_frame; - - /* group hold */ - ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_GROUP_ACCESS); - return ret; - } - - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = (u16)coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_TIMING_VTS_H); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov_write_reg8(client, OV2680_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_L); - return ret; - } - - ret = ov_write_reg8(client, OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_M); - return ret; - } - - ret = ov_write_reg8(client, OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov_write_reg16(client, OV2680_AGC_H, gain); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_AGC_H); - return ret; - } - /* Digital gain */ - if (digitgain) { - ret = ov_write_reg16(client, OV2680_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov_write_reg16(client, OV2680_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov_write_reg16(client, OV2680_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov_write_reg8(client, OV2680_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret = 0; - - mutex_lock(&dev->input_lock); - - dev->exposure = exposure; - dev->gain = gain; - dev->digitgain = digitgain; - - if (dev->power_on) - ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); - - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov2680_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - -static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2680_s_exposure(sd, arg); - - default: - return -EINVAL; - } - return 0; -} - -/* - * This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 reg_val; - int ret; - - /* get exposure */ - ret = ov_read_reg24(client, OV2680_EXPOSURE_H, ®_val); - if (ret) - return ret; - - /* Lower four bits are not part of the exposure val (always 0) */ - *value = reg_val >> 4; - return 0; -} - static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt) { static const int ov2680_hv_flip_bayer_order[] = { @@ -314,25 +139,8 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = ctrl_to_sd(ctrl); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2680_q_exposure(sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - static const struct v4l2_ctrl_ops ov2680_ctrl_ops = { .s_ctrl = ov2680_s_ctrl, - .g_volatile_ctrl = ov2680_g_volatile_ctrl }; static int ov2680_init_registers(struct v4l2_subdev *sd) @@ -441,10 +249,6 @@ static int power_up(struct v4l2_subdev *sd) if (ret) goto fail_init_registers; - ret = __ov2680_set_exposure(sd, dev->exposure, dev->gain, dev->digitgain); - if (ret) - goto fail_init_registers; - dev->power_on = true; return 0; @@ -545,7 +349,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *fmt; struct ov2680_resolution *res; - int vts, ret = 0; + int ret = 0; res = v4l2_find_nearest_size(ov2680_res_preview, ARRAY_SIZE(ov2680_res_preview), width, height, @@ -575,13 +379,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, goto err; } - vts = dev->res->lines_per_frame; - - /* If necessary increase the VTS to match exposure + MARGIN */ - if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, vts); + ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, dev->res->lines_per_frame); if (ret) { dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); goto err; @@ -807,7 +605,6 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { static const struct v4l2_subdev_core_ops ov2680_core_ops = { .s_power = ov2680_s_power, - .ioctl = ov2680_ioctl, }; static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { @@ -877,8 +674,6 @@ static int ov2680_probe(struct i2c_client *client) dev->client = client; dev->res = &ov2680_res_preview[0]; - dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; - dev->gain = 250; /* 0-2047 */ v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops); pdata = gmin_camera_platform_data(&dev->sd, diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index c7b6fc8bf33d..64a03a7c3e19 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -163,9 +163,6 @@ struct ov2680_device { struct camera_sensor_platform_data *platform_data; bool power_on; bool is_streaming; - u16 exposure; - u16 gain; - u16 digitgain; struct ov2680_mode { struct v4l2_mbus_framefmt fmt; From 250b9a99bed87828e1beee8d3e8c2df6d7206d15 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 30 Dec 2022 19:37:42 +0100 Subject: [PATCH 142/216] media: atomisp: ov2680: Add exposure and gain controls Add exposure and gain controls. This allows controlling the exposure and gain through standard v4l2 IOCTLs. Note the register defines for the exposure and gain registers are renamed to match the datasheet. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 27 +++++++++++++++---- drivers/staging/media/atomisp/i2c/ov2680.h | 9 +++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 8fadccfbc1c6..326e232672c3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -115,6 +115,16 @@ static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val) return 0; } +static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp) +{ + return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4); +} + +static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain) +{ + return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain); +} + static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -133,6 +143,12 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_HFLIP: ret = ov2680_set_hflip(sensor, ctrl->val); break; + case V4L2_CID_EXPOSURE: + ret = ov2680_exposure_set(sensor, ctrl->val); + break; + case V4L2_CID_GAIN: + ret = ov2680_gain_set(sensor, ctrl->val); + break; default: ret = -EINVAL; } @@ -385,10 +401,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, goto err; } - /* - * recall flip functions to avoid flip registers - * were overridden by default setting - */ + /* Restore value of all ctrls */ ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); if (ret < 0) goto err; @@ -627,13 +640,17 @@ static int ov2680_init_controls(struct ov2680_device *sensor) const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; struct ov2680_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int exp_max = sensor->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; - v4l2_ctrl_handler_init(hdl, 2); + v4l2_ctrl_handler_init(hdl, 4); hdl->lock = &sensor->input_lock; ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, exp_max, 1, exp_max); + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250); ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 64a03a7c3e19..17cd982bc822 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -90,11 +90,8 @@ #define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/ -#define OV2680_EXPOSURE_H 0x3500 /*Bit[3:0] Bit[19:16] of exposure, remaining 16 bits lies in Reg0x3501&Reg0x3502*/ -#define OV2680_EXPOSURE_M 0x3501 -#define OV2680_EXPOSURE_L 0x3502 -#define OV2680_AGC_H 0x350A /*Bit[1:0] means Bit[9:8] of gain*/ -#define OV2680_AGC_L 0x350B /*Bit[7:0] of gain*/ +#define OV2680_REG_EXPOSURE_PK_HIGH 0x3500 +#define OV2680_REG_GAIN_PK 0x350a #define OV2680_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/ #define OV2680_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/ @@ -172,6 +169,8 @@ struct ov2680_device { struct v4l2_ctrl_handler handler; struct v4l2_ctrl *hflip; struct v4l2_ctrl *vflip; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; } ctrls; }; From 76f39e721e29a0ea7a503da1ed10d4ebefa49e0a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 3 Jan 2023 21:32:52 +0100 Subject: [PATCH 143/216] media: atomisp: ov2680: Add test pattern control Add a test pattern control. This is a 1:1 copy of the test pattern control in the main drivers/media/i2c/ov2680.c driver. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 33 +++++++++++++++++++ drivers/staging/media/atomisp/i2c/ov2680.h | 3 ++ 2 files changed, 36 insertions(+) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 326e232672c3..9fd5626a36e8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -125,6 +125,24 @@ static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain) return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain); } +static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value) +{ + int ret; + + if (!value) + return ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), 0); + + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, 0x03, value - 1); + if (ret < 0) + return ret; + + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), BIT(7)); + if (ret < 0) + return ret; + + return 0; +} + static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -149,6 +167,9 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_GAIN: ret = ov2680_gain_set(sensor, ctrl->val); break; + case V4L2_CID_TEST_PATTERN: + ret = ov2680_test_pattern_set(sensor, ctrl->val); + break; default: ret = -EINVAL; } @@ -637,6 +658,13 @@ static const struct v4l2_subdev_ops ov2680_ops = { static int ov2680_init_controls(struct ov2680_device *sensor) { + static const char * const test_pattern_menu[] = { + "Disabled", + "Color Bars", + "Random Data", + "Square", + "Black Image", + }; const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; struct ov2680_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; @@ -651,6 +679,11 @@ static int ov2680_init_controls(struct ov2680_device *sensor) ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, exp_max, 1, exp_max); ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250); + ctrls->test_pattern = + v4l2_ctrl_new_std_menu_items(hdl, + &ov2680_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 17cd982bc822..4d1fa054fcf3 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -120,6 +120,8 @@ #define OV2680_MWB_BLUE_GAIN_H 0x5008/*0x3404*/ #define OV2680_MWB_GAIN_MAX 0x0fff +#define OV2680_REG_ISP_CTRL00 0x5080 + #define OV2680_START_STREAMING 0x01 #define OV2680_STOP_STREAMING 0x00 @@ -171,6 +173,7 @@ struct ov2680_device { struct v4l2_ctrl *vflip; struct v4l2_ctrl *exposure; struct v4l2_ctrl *gain; + struct v4l2_ctrl *test_pattern; } ctrls; }; From 1c08b2faa88fbcf813a700120ffe89bc2c8c567c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 2 Jan 2023 22:02:04 +0100 Subject: [PATCH 144/216] media: atomisp: ov2680: Fix window settings and enable window for all resolutions By default the ov2680 automatically sets the window to match the outputsize and automatically adjusts it to keep the bayer pattern stable when enabling hflip/vflip. This does not work for the 1616x1216 mode because there is no room to adjust the window there. To make flipping work in the 1616 wide modes the register lists for those modes set bit 0 of 0x5708 (manual_win_en) to 1 and ov2680_set_bayer_order() updates the bayer-order on the pad to match. But ov2680_set_bayer_order() is always called, so when enabling flipping on modes with a width of less then 1616 now results in the wrong bayer order being reported on the pad since the sensor is auto-adjusting the window in this case. Specify the correct (== output-size) window-size in all resolutions register-list and always set the manual_win_en bit, so that the bayer order is changed on hflip/vflip enable on all resolutions. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov2680.h | 76 +++++++++++----------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 4d1fa054fcf3..d753919be095 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -318,11 +318,11 @@ static struct ov2680_reg const ov2680_QCIF_30fps[] = { {0x4008, 0x00}, {0x4009, 0x03}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x00}, + {0x5705, 0xc0}, + {0x5706, 0x00}, + {0x5707, 0xa0}, {0x3820, 0xc2}, {0x3821, 0x01}, // {0x5090, 0x0c}, @@ -357,11 +357,11 @@ static struct ov2680_reg const ov2680_CIF_30fps[] = { {0x4008, 0x00}, {0x4009, 0x03}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x01}, + {0x5705, 0x70}, + {0x5706, 0x01}, + {0x5707, 0x30}, {0x3820, 0xc2}, {0x3821, 0x01}, // {0x5090, 0x0c}, @@ -396,11 +396,11 @@ static struct ov2680_reg const ov2680_QVGA_30fps[] = { {0x4008, 0x00}, {0x4009, 0x03}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x01}, + {0x5705, 0x50}, + {0x5706, 0x01}, + {0x5707, 0x00}, {0x3820, 0xc2}, {0x3821, 0x01}, // {0x5090, 0x0c}, @@ -435,11 +435,11 @@ static struct ov2680_reg const ov2680_656x496_30fps[] = { {0x4008, 0x00}, {0x4009, 0x03}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x02}, + {0x5705, 0x90}, + {0x5706, 0x01}, + {0x5707, 0xf0}, {0x3820, 0xc2}, {0x3821, 0x01}, // {0x5090, 0x0c}, @@ -473,7 +473,7 @@ static struct ov2680_reg const ov2680_720x592_30fps[] = { {0x3815, 0x31}, {0x4008, 0x00}, {0x4009, 0x03}, - {0x5708, 0x00}, + {0x5708, 0x01}, {0x5704, 0x02}, {0x5705, 0xd0}, // X_WIN; {0x5706, 0x02}, @@ -512,7 +512,7 @@ static struct ov2680_reg const ov2680_800x600_30fps[] = { {0x3813, 0x00}, {0x3814, 0x31}, {0x3815, 0x31}, - {0x5708, 0x00}, + {0x5708, 0x01}, {0x5704, 0x03}, {0x5705, 0x20}, {0x5706, 0x02}, @@ -554,11 +554,11 @@ static struct ov2680_reg const ov2680_720p_30fps[] = { {0x4008, 0x02}, {0x4009, 0x09}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x05}, + {0x5705, 0x10}, + {0x5706, 0x02}, + {0x5707, 0xe0}, {0x3820, 0xc0}, {0x3821, 0x00}, // {0x5090, 0x0c}, @@ -593,11 +593,11 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = { {0x4008, 0x02}, {0x4009, 0x09}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x05}, + {0x5705, 0x10}, + {0x5706, 0x03}, + {0x5707, 0xd0}, {0x3820, 0xc0}, {0x3821, 0x00}, //mirror/flip // {0x5090, 0x0c}, @@ -632,11 +632,11 @@ static struct ov2680_reg const ov2680_1456x1096_30fps[] = { {0x4008, 0x02}, {0x4009, 0x09}, {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, + {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 + {0x5704, 0x05}, + {0x5705, 0xb0}, + {0x5706, 0x04}, + {0x5707, 0x48}, {0x3820, 0xc0}, {0x3821, 0x00}, // {0x5090, 0x0c}, @@ -754,7 +754,7 @@ static struct ov2680_reg const ov2680_1616x1216_30fps[] = { {0x5704, 0x06}, {0x5705, 0x50}, {0x5706, 0x04}, - {0x5707, 0xcc}, + {0x5707, 0xc0}, {0x3820, 0xc0}, {0x3821, 0x00}, // {0x5090, 0x0C}, From 0611888592df86c3f348146dc26d4b00f850e194 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 1 Jan 2023 18:08:42 +0100 Subject: [PATCH 145/216] media: atomisp: ov2680: Make setting the modes algorithm based Instead of using a long fixed register settings list for each resolution, calculate the register settings based on the requested width + height. This will allow future enhancements like adding hblank and vblank controls and adding selection support. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 137 ++++++++++++++++-- drivers/staging/media/atomisp/i2c/ov2680.h | 35 ++++- 2 files changed, 158 insertions(+), 14 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 9fd5626a36e8..ed547e0a38cf 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -378,6 +378,131 @@ static void ov2680_fill_format(struct ov2680_device *sensor, ov2680_set_bayer_order(sensor, fmt); } +static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height) +{ + int orig_width = width; + int orig_height = height; + + if (width <= (OV2680_NATIVE_WIDTH / 2) && + height <= (OV2680_NATIVE_HEIGHT / 2)) { + sensor->mode.binning = true; + width *= 2; + height *= 2; + } else { + sensor->mode.binning = false; + } + + sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1; + sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1; + sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1, + OV2680_NATIVE_WIDTH - 1); + sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1, + OV2680_NATIVE_HEIGHT - 1); + sensor->mode.h_output_size = orig_width; + sensor->mode.v_output_size = orig_height; + sensor->mode.hts = OV2680_PIXELS_PER_LINE; + sensor->mode.vts = OV2680_LINES_PER_FRAME; +} + +static int ov2680_set_mode(struct ov2680_device *sensor, int width, int height) +{ + struct i2c_client *client = sensor->client; + u8 pll_div, unknown, inc, fmt1, fmt2; + int ret; + + ov2680_calc_mode(sensor, width, height); + + if (sensor->mode.binning) { + pll_div = 1; + unknown = 0x23; + inc = 0x31; + fmt1 = 0xc2; + fmt2 = 0x01; + } else { + pll_div = 0; + unknown = 0x21; + inc = 0x11; + fmt1 = 0xc0; + fmt2 = 0x00; + } + + ret = ov_write_reg8(client, 0x3086, pll_div); + if (ret) + return ret; + + ret = ov_write_reg8(client, 0x370a, unknown); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_HORIZONTAL_START_H, sensor->mode.h_start); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_VERTICAL_START_H, sensor->mode.v_start); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_HORIZONTAL_END_H, sensor->mode.h_end); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_VERTICAL_END_H, sensor->mode.v_end); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_HORIZONTAL_OUTPUT_SIZE_H, + sensor->mode.h_output_size); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_VERTICAL_OUTPUT_SIZE_H, + sensor->mode.v_output_size); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_HTS, sensor->mode.hts); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_VTS, sensor->mode.vts); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_ISP_X_WIN, 0); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_ISP_Y_WIN, 0); + if (ret) + return ret; + + ret = ov_write_reg8(client, OV2680_X_INC, inc); + if (ret) + return ret; + + ret = ov_write_reg8(client, OV2680_Y_INC, inc); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_X_WIN, sensor->mode.h_output_size); + if (ret) + return ret; + + ret = ov_write_reg16(client, OV2680_Y_WIN, sensor->mode.v_output_size); + if (ret) + return ret; + + ret = ov_write_reg8(client, OV2680_REG_FORMAT1, fmt1); + if (ret) + return ret; + + ret = ov_write_reg8(client, OV2680_REG_FORMAT2, fmt2); + if (ret) + return ret; + + return 0; +} + static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -409,18 +534,10 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, /* s_power has not been called yet for std v4l2 clients (camorama) */ power_up(sd); - ret = ov2680_write_reg_array(client, dev->res->regs); - if (ret) { - dev_err(&client->dev, - "ov2680 write resolution register err: %d\n", ret); - goto err; - } - ret = ov_write_reg16(client, OV2680_TIMING_VTS_H, dev->res->lines_per_frame); - if (ret) { - dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); + ret = ov2680_set_mode(dev, fmt->width, fmt->height); + if (ret < 0) goto err; - } /* Restore value of all ctrls */ ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index d753919be095..d9e794759575 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -35,6 +35,13 @@ #define OV2680_NATIVE_WIDTH 1616 #define OV2680_NATIVE_HEIGHT 1216 +/* 1704 * 1294 * 30fps = 66MHz pixel clock */ +#define OV2680_PIXELS_PER_LINE 1704 +#define OV2680_LINES_PER_FRAME 1294 + +/* If possible send 16 extra rows / lines to the ISP as padding */ +#define OV2680_END_MARGIN 16 + #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ #define OV2680_BIN_FACTOR_MAX 4 @@ -105,10 +112,13 @@ #define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/ #define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/ #define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/ -#define OV2680_TIMING_HTS_H 0x380C /*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV2680_TIMING_HTS_L 0x380D /*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV2680_TIMING_VTS_H 0x380e /*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV2680_TIMING_VTS_L 0x380f /*High 8-bit, and low 8-bit HTS address is 0x380f*/ +#define OV2680_HTS 0x380c +#define OV2680_VTS 0x380e +#define OV2680_ISP_X_WIN 0x3810 +#define OV2680_ISP_Y_WIN 0x3812 +#define OV2680_X_INC 0x3814 +#define OV2680_Y_INC 0x3815 + #define OV2680_FRAME_OFF_NUM 0x4202 /*Flip/Mirror*/ @@ -122,6 +132,10 @@ #define OV2680_REG_ISP_CTRL00 0x5080 +#define OV2680_X_WIN 0x5704 +#define OV2680_Y_WIN 0x5706 +#define OV2680_WIN_CONTROL 0x5708 + #define OV2680_START_STREAMING 0x01 #define OV2680_STOP_STREAMING 0x00 @@ -165,6 +179,15 @@ struct ov2680_device { struct ov2680_mode { struct v4l2_mbus_framefmt fmt; + bool binning; + u16 h_start; + u16 v_start; + u16 h_end; + u16 v_end; + u16 h_output_size; + u16 v_output_size; + u16 hts; + u16 vts; } mode; struct ov2680_ctrls { @@ -248,6 +271,8 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x3819, 0x04}, {0x4000, 0x81}, {0x4001, 0x40}, + {0x4008, 0x00}, + {0x4009, 0x03}, {0x4602, 0x02}, {0x481f, 0x36}, {0x4825, 0x36}, @@ -260,6 +285,8 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x5008, 0x04}, {0x5009, 0x00}, {0x5080, 0x00}, + {0x5081, 0x41}, + {0x5708, 0x01}, /* add for full size flip off and mirror off 2014/09/11 */ {0x3701, 0x64}, //add on 14/05/13 {0x3784, 0x0c}, //based OV2680_R1A_AM10.ovt add on 14/06/13 {0x5780, 0x3e}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13 From 3406639ee2ad5bf736b9b38091bf108ac600327a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 8 Jan 2023 15:06:26 +0100 Subject: [PATCH 146/216] media: atomisp: ov2680: Use defines for fps, lines-per-frame and skip-frames The fps, lines-per-frame and skip-frames values are the same for all resolutions, use defines for these. The ov2680_res_preview[] incorrectly sets fps to 60 for some low-res modes, this is incorrect with the current fixed (resolution independent) lines-per-frame value. Note this not drop the now no longer used fps, lines-per-frame and skip-frames struct ov2680_resolution members. The entire struct is going away in the next patches so that would just cause unnecessary changes. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/i2c/atomisp-ov2680.c | 16 ++++------------ drivers/staging/media/atomisp/i2c/ov2680.h | 2 ++ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index ed547e0a38cf..36f94406af0f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -678,11 +678,8 @@ static int ov2680_s_config(struct v4l2_subdev *sd, static int ov2680_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - interval->interval.numerator = 1; - interval->interval.denominator = dev->res->fps; - + interval->interval.denominator = OV2680_FPS; return 0; } @@ -726,8 +723,8 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, fie->which > V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; - fract.denominator = ov2680_res_preview[fie->index].fps; fract.numerator = 1; + fract.denominator = OV2680_FPS; fie->interval = fract; @@ -736,12 +733,7 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = dev->res->skip_frames; - mutex_unlock(&dev->input_lock); - + *frames = OV2680_SKIP_FRAMES; return 0; } @@ -785,7 +777,7 @@ static int ov2680_init_controls(struct ov2680_device *sensor) const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; struct ov2680_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; - int exp_max = sensor->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; + int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN; v4l2_ctrl_handler_init(hdl, 4); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index d9e794759575..35c8ea50f6ed 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -38,6 +38,8 @@ /* 1704 * 1294 * 30fps = 66MHz pixel clock */ #define OV2680_PIXELS_PER_LINE 1704 #define OV2680_LINES_PER_FRAME 1294 +#define OV2680_FPS 30 +#define OV2680_SKIP_FRAMES 3 /* If possible send 16 extra rows / lines to the ISP as padding */ #define OV2680_END_MARGIN 16 From 10704b452ab1b1040cfc08fb901e9226b9bfd460 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 8 Jan 2023 16:22:42 +0100 Subject: [PATCH 147/216] media: atomisp: ov2680: Drop unused res member from struct ov2680_device The res member of struct ov2680_device isn't read anywhere anymore, drop it. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 5 ----- drivers/staging/media/atomisp/i2c/ov2680.h | 1 - 2 files changed, 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 36f94406af0f..274acebff79f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -541,10 +541,6 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, /* Restore value of all ctrls */ ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); - if (ret < 0) - goto err; - - dev->res = res; err: mutex_unlock(&dev->input_lock); return ret; @@ -832,7 +828,6 @@ static int ov2680_probe(struct i2c_client *client) mutex_init(&dev->input_lock); dev->client = client; - dev->res = &ov2680_res_preview[0]; v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops); pdata = gmin_camera_platform_data(&dev->sd, diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 35c8ea50f6ed..c601d30ce8cf 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -174,7 +174,6 @@ struct ov2680_device { struct media_pad pad; struct mutex input_lock; struct i2c_client *client; - struct ov2680_resolution *res; struct camera_sensor_platform_data *platform_data; bool power_on; bool is_streaming; From a6fc86ed57a108cdc5078d93b17bcf56c234f94c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 15:40:58 +0100 Subject: [PATCH 148/216] media: atomisp: ov2680: Fix ov2680_enum_frame_interval() Fix and simplify ov2680_enum_frame_interval(), the index is not an index into ov2680_res_preview[], so using N_PREVIEW is wrong. Instead it is an index indexing the different framerates for the resolution specified in fie->width, fie->height. Since the ov2680 code only supports a single fixed 30 fps, index must always be 0 and we don't need to check the other fie input values. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/i2c/atomisp-ov2680.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 274acebff79f..e90a7737a56d 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -711,19 +711,12 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { - struct v4l2_fract fract; - - if (fie->index >= N_RES_PREVIEW || - fie->width > ov2680_res_preview[0].width || - fie->height > ov2680_res_preview[0].height || - fie->which > V4L2_SUBDEV_FORMAT_ACTIVE) + /* Only 1 framerate */ + if (fie->index) return -EINVAL; - fract.numerator = 1; - fract.denominator = OV2680_FPS; - - fie->interval = fract; - + fie->interval.numerator = 1; + fie->interval.denominator = OV2680_FPS; return 0; } From f4ed8e3ba64a5cef32846e63c59897354bcb6d50 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 16:01:40 +0100 Subject: [PATCH 149/216] media: atomisp: ov2680: Drop v4l2_find_nearest_size() call from set_fmt() Since we now calculate timings baded on the desired width and height, any width and height are valid as long as they don't exceed the sensor's dimensions. Drop the v4l2_find_nearest_size() call and instead clamp the requested width and height. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index e90a7737a56d..0433d542226f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -510,17 +510,14 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, struct ov2680_device *dev = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *fmt; - struct ov2680_resolution *res; + unsigned int width, height; int ret = 0; - res = v4l2_find_nearest_size(ov2680_res_preview, ARRAY_SIZE(ov2680_res_preview), - width, height, - format->format.width, format->format.height); - if (!res) - res = &ov2680_res_preview[N_RES_PREVIEW - 1]; + width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH); + height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT); fmt = __ov2680_get_pad_format(dev, sd_state, format->pad, format->which); - ov2680_fill_format(dev, fmt, res->width, res->height); + ov2680_fill_format(dev, fmt, width, height); format->format = *fmt; From ef6504afd046da6afe7c0f4b36df3654268e97e8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 16:46:40 +0100 Subject: [PATCH 150/216] media: atomisp: ov2680: Drop struct ov2680_resolution / ov2680_res_preview Drop struct ov2680_resolution and the ov2680_res_preview[] array, this is now only used in ov2680_enum_frame_size() and only the width + height are used there. Replace this with a new struct v4l2_frmsize_discrete ov2680_frame_sizes[] array. No functional changes. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 24 +- drivers/staging/media/atomisp/i2c/ov2680.h | 610 ------------------ 2 files changed, 19 insertions(+), 615 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 0433d542226f..4f44113871fe 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -691,15 +691,29 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { + static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = { + { 1616, 1216 }, + { 1616, 1082 }, + { 1616, 916 }, + { 1456, 1096 }, + { 1296, 976 }, + { 1296, 736 }, + { 800, 600 }, + { 720, 592 }, + { 656, 496 }, + { 336, 256 }, + { 352, 288 }, + { 176, 144 }, + }; int index = fse->index; - if (index >= N_RES_PREVIEW) + if (index >= ARRAY_SIZE(ov2680_frame_sizes)) return -EINVAL; - fse->min_width = ov2680_res_preview[index].width; - fse->min_height = ov2680_res_preview[index].height; - fse->max_width = ov2680_res_preview[index].width; - fse->max_height = ov2680_res_preview[index].height; + fse->min_width = ov2680_frame_sizes[index].width; + fse->min_height = ov2680_frame_sizes[index].height; + fse->max_width = ov2680_frame_sizes[index].width; + fse->max_height = ov2680_frame_sizes[index].height; return 0; } diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index c601d30ce8cf..53e2f6288ca5 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -148,18 +148,6 @@ struct regval_list { u8 value; }; -struct ov2680_resolution { - const struct ov2680_reg *regs; - int res; - int width; - int height; - int fps; - int pix_clk_freq; - u32 skip_frames; - u16 pixels_per_line; - u16 lines_per_frame; -}; - struct ov2680_format { u8 *desc; u32 pixelformat; @@ -316,602 +304,4 @@ static struct ov2680_reg const ov2680_global_setting[] = { {} }; -/* - * 176x144 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_QCIF_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x05}, - {0x3805, 0xaf}, - {0x3806, 0x04}, - {0x3807, 0x47}, - {0x3808, 0x00}, - {0x3809, 0xC0}, - {0x380a, 0x00}, - {0x380b, 0xa0}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4000, 0x81}, - {0x4001, 0x40}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x00}, - {0x5705, 0xc0}, - {0x5706, 0x00}, - {0x5707, 0xa0}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 352x288 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_CIF_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x03}, - {0x3805, 0x8f}, - {0x3806, 0x02}, - {0x3807, 0xe7}, - {0x3808, 0x01}, - {0x3809, 0x70}, - {0x380a, 0x01}, - {0x380b, 0x30}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x01}, - {0x5705, 0x70}, - {0x5706, 0x01}, - {0x5707, 0x30}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 336x256 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_QVGA_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x03}, - {0x3805, 0x4f}, - {0x3806, 0x02}, - {0x3807, 0x87}, - {0x3808, 0x01}, - {0x3809, 0x50}, - {0x380a, 0x01}, - {0x380b, 0x00}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x01}, - {0x5705, 0x50}, - {0x5706, 0x01}, - {0x5707, 0x00}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 656x496 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_656x496_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x05}, - {0x3805, 0xcf}, - {0x3806, 0x04}, - {0x3807, 0x67}, - {0x3808, 0x02}, - {0x3809, 0x90}, - {0x380a, 0x01}, - {0x380b, 0xf0}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x02}, - {0x5705, 0x90}, - {0x5706, 0x01}, - {0x5707, 0xf0}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 720x592 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_720x592_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0x00}, // X_ADDR_START; - {0x3802, 0x00}, - {0x3803, 0x00}, // Y_ADDR_START; - {0x3804, 0x05}, - {0x3805, 0xaf}, // X_ADDR_END; - {0x3806, 0x04}, - {0x3807, 0xaf}, // Y_ADDR_END; - {0x3808, 0x02}, - {0x3809, 0xd0}, // X_OUTPUT_SIZE; - {0x380a, 0x02}, - {0x380b, 0x50}, // Y_OUTPUT_SIZE; - {0x380c, 0x06}, - {0x380d, 0xac}, // HTS; - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5708, 0x01}, - {0x5704, 0x02}, - {0x5705, 0xd0}, // X_WIN; - {0x5706, 0x02}, - {0x5707, 0x50}, // Y_WIN; - {0x3820, 0xc2}, // FLIP_FORMAT; - {0x3821, 0x01}, // MIRROR_FORMAT; - {0x5090, 0x00}, // PRE ISP CTRL16, default value is 0x0C; - // BIT[3]: Mirror order, BG or GB; - // BIT[2]: Flip order, BR or RB; - {0x5081, 0x41}, - {} -}; - -/* - * 800x600 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_800x600_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0x00}, /* hstart 0 */ - {0x3802, 0x00}, - {0x3803, 0x00}, /* vstart 0 */ - {0x3804, 0x06}, - {0x3805, 0x4f}, /* hend 1615 */ - {0x3806, 0x04}, - {0x3807, 0xbf}, /* vend 1215 */ - {0x3808, 0x03}, - {0x3809, 0x20}, /* hsize 800 */ - {0x380a, 0x02}, - {0x380b, 0x58}, /* vsize 600 */ - {0x380c, 0x06}, - {0x380d, 0xac}, /* htotal 1708 */ - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x5708, 0x01}, - {0x5704, 0x03}, - {0x5705, 0x20}, - {0x5706, 0x02}, - {0x5707, 0x58}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - {0x5090, 0x00}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {} -}; - -/* - * 720p=1280*720 30fps VBlanking 1lane 10Bit (no-Scaling) - */ -static struct ov2680_reg const ov2680_720p_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0xa0}, /* hstart 160 */ - {0x3802, 0x00}, - {0x3803, 0xf2}, /* vstart 242 */ - {0x3804, 0x05}, - {0x3805, 0xbf}, /* hend 1471 */ - {0x3806, 0x03}, - {0x3807, 0xdd}, /* vend 989 */ - {0x3808, 0x05}, - {0x3809, 0x10}, /* hsize 1296 */ - {0x380a, 0x02}, - {0x380b, 0xe0}, /* vsize 736 */ - {0x380c, 0x06}, - {0x380d, 0xa8}, /* htotal 1704 */ - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x06}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x05}, - {0x5705, 0x10}, - {0x5706, 0x02}, - {0x5707, 0xe0}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 1296x976 30fps VBlanking 1lane 10Bit(no-scaling) - */ -static struct ov2680_reg const ov2680_1296x976_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0xa0}, /* hstart 160 */ - {0x3802, 0x00}, - {0x3803, 0x78}, /* vstart 120 */ - {0x3804, 0x05}, - {0x3805, 0xbf}, /* hend 1471 */ - {0x3806, 0x04}, - {0x3807, 0x57}, /* vend 1111 */ - {0x3808, 0x05}, - {0x3809, 0x10}, /* hsize 1296 */ - {0x380a, 0x03}, - {0x380b, 0xd0}, /* vsize 976 */ - {0x380c, 0x06}, - {0x380d, 0xa8}, /* htotal 1704 */ - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x08}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x05}, - {0x5705, 0x10}, - {0x5706, 0x03}, - {0x5707, 0xd0}, - {0x3820, 0xc0}, - {0x3821, 0x00}, //mirror/flip - // {0x5090, 0x0c}, - {} -}; - -/* - * 1456*1096 30fps VBlanking 1lane 10bit(no-scaling) - */ -static struct ov2680_reg const ov2680_1456x1096_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x90}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xC0}, - {0x3808, 0x05}, - {0x3809, 0xb0}, - {0x380a, 0x04}, - {0x380b, 0x48}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x05}, - {0x5705, 0xb0}, - {0x5706, 0x04}, - {0x5707, 0x48}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0c}, - {} -}; - -/* - *1616x916 30fps VBlanking 1lane 10bit - */ - -static struct ov2680_reg const ov2680_1616x916_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x96}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0x39}, - {0x3808, 0x06}, - {0x3809, 0x50}, - {0x380a, 0x03}, - {0x380b, 0x94}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x08}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x03}, - {0x5707, 0x94}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {} -}; - -/* - * 1616x1082 30fps VBlanking 1lane 10Bit - */ -static struct ov2680_reg const ov2680_1616x1082_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x86}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xbf}, - {0x3808, 0x06}, - {0x3809, 0x50}, - {0x380a, 0x04}, - {0x380b, 0x3a}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x04}, - {0x5707, 0x3a}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {} -}; - -/* - * 1616x1216 30fps VBlanking 1lane 10Bit - */ -static struct ov2680_reg const ov2680_1616x1216_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x00}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xbf}, - {0x3808, 0x06}, - {0x3809, 0x50},//50},//4line for mirror and flip - {0x380a, 0x04}, - {0x380b, 0xc0},//c0}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x00}, - {0x4009, 0x0b}, - {0x5081, 0x01}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x04}, - {0x5707, 0xc0}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {} -}; - -static struct ov2680_resolution ov2680_res_preview[] = { - { - .width = 1616, - .height = 1216, - .pix_clk_freq = 66, - .fps = 30, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_1616x1216_30fps, - }, - { - .width = 1616, - .height = 1082, - .pix_clk_freq = 66, - .fps = 30, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_1616x1082_30fps, - }, - { - .width = 1616, - .height = 916, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_1616x916_30fps, - }, - { - .width = 1456, - .height = 1096, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_1456x1096_30fps, - }, - { - .width = 1296, - .height = 976, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_1296x976_30fps, - }, - { - .width = 1296, - .height = 736, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_720p_30fps, - }, - { - .width = 800, - .height = 600, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_800x600_30fps, - }, - { - .width = 720, - .height = 592, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_720x592_30fps, - }, - { - .width = 656, - .height = 496, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_656x496_30fps, - }, - { - .width = 336, - .height = 256, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_QVGA_30fps, - }, - { - .width = 352, - .height = 288, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_CIF_30fps, - }, - { - .width = 176, - .height = 144, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .skip_frames = 3, - .regs = ov2680_QCIF_30fps, - }, -}; - -#define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview)) - #endif From 35fd68153dd3f7d93c8f8208193c504850bbac80 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 16:55:10 +0100 Subject: [PATCH 151/216] media: atomisp: ov2680: Fix frame_size list 3 fixes for the framesize list: 1. Drop modes < 640x480, these are made by significant cropping, leading to such a small remainig field-of-view that they are not really usable 2. 1616x1082 is presumably intended to be 1600x1080 + 16 pixels padding in both dimensions, but the height is wrong. Change this to 1616x1096. 3. The 800x600 mode is missing the 16 pixels padding and 720x592 is missing 16 pixels padding in its width and the 720x576 base mode is a mode with non square pixels, while the sensor has square pixels. Replace both with 768x576 + 16 pixels padding -> 784x592 Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 4f44113871fe..b139c4167cf9 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -693,17 +693,13 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd, { static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = { { 1616, 1216 }, - { 1616, 1082 }, + { 1616, 1096 }, { 1616, 916 }, { 1456, 1096 }, { 1296, 976 }, { 1296, 736 }, - { 800, 600 }, - { 720, 592 }, + { 784, 592 }, { 656, 496 }, - { 336, 256 }, - { 352, 288 }, - { 176, 144 }, }; int index = fse->index; From 8cf66250505e54e1d91f7cae7091f8cfefa4a01e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 16:51:01 +0100 Subject: [PATCH 152/216] media: atomisp: ov2680: Remove unused data-types and defines from ov2680.h Remove a bunch of unused data-types and defines from ov2680.h. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov2680.h | 60 ---------------------- 1 file changed, 60 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 53e2f6288ca5..adf38359afbc 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -46,45 +46,11 @@ #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define OV2680_BIN_FACTOR_MAX 4 - #define MAX_FMTS 1 -/* sensor_mode_data read_mode adaptation */ -#define OV2680_READ_MODE_BINNING_ON 0x0400 -#define OV2680_READ_MODE_BINNING_OFF 0x00 #define OV2680_INTEGRATION_TIME_MARGIN 8 - -#define OV2680_MAX_EXPOSURE_VALUE 0xFFF1 -#define OV2680_MAX_GAIN_VALUE 0xFF - -/* - * focal length bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV2680_FOCAL_LENGTH_DEFAULT 0x1B70064 - -/* - * current f-number bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV2680_F_NUMBER_DEFAULT 0x18000a - -/* - * f-number range bits definition: - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ -#define OV2680_F_NUMBER_RANGE 0x180a180a #define OV2680_ID 0x2680 -#define OV2680_FINE_INTG_TIME_MIN 0 -#define OV2680_FINE_INTG_TIME_MAX_MARGIN 0 -#define OV2680_COARSE_INTG_TIME_MIN 1 -#define OV2680_COARSE_INTG_TIME_MAX_MARGIN 6 - /* * OV2680 System control registers */ @@ -141,19 +107,6 @@ #define OV2680_START_STREAMING 0x01 #define OV2680_STOP_STREAMING 0x00 -#define OV2680_INVALID_CONFIG 0xffffffff - -struct regval_list { - u16 reg_num; - u8 value; -}; - -struct ov2680_format { - u8 *desc; - u32 pixelformat; - struct ov2680_reg *regs; -}; - /* * ov2680 device structure. */ @@ -212,18 +165,6 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) return &sensor->sd; } -#define OV2680_MAX_WRITE_BUF_SIZE 30 - -struct ov2680_write_buffer { - u16 addr; - u8 data[OV2680_MAX_WRITE_BUF_SIZE]; -}; - -struct ov2680_write_ctrl { - int index; - struct ov2680_write_buffer buffer; -}; - static struct ov2680_reg const ov2680_global_setting[] = { {0x0103, 0x01}, {0x3002, 0x00}, @@ -300,7 +241,6 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x5793, 0x00}, {0x5794, 0x03}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13 {0x0100, 0x00}, //stream off - {} }; From bca7822cbc76b22572faf2e17ca9517b68ebeb3e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 16:51:54 +0100 Subject: [PATCH 153/216] media: atomisp: ov2680: Drop MAX_FMTS define The ov2680 only supports a single format, there is no need to use a define for this. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 3 ++- drivers/staging/media/atomisp/i2c/ov2680.h | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index b139c4167cf9..0e51a5f83f12 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -680,7 +680,8 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index >= MAX_FMTS) + /* We support only a single format */ + if (code->index) return -EINVAL; code->code = MEDIA_BUS_FMT_SBGGR10_1X10; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index adf38359afbc..feb8ad055b40 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -46,8 +46,6 @@ #define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define MAX_FMTS 1 - #define OV2680_INTEGRATION_TIME_MARGIN 8 #define OV2680_ID 0x2680 From b8bfc7464bfa6b5ccb9b5556d92124cfca135efe Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 14 Jan 2023 14:01:49 +0100 Subject: [PATCH 154/216] media: atomisp: ov2680: Consistently indent define values Use the same indentation level for all #define values. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov2680.h | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index feb8ad055b40..333acd1520e4 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -44,10 +44,10 @@ /* If possible send 16 extra rows / lines to the ISP as padding */ #define OV2680_END_MARGIN 16 -#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ +#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define OV2680_INTEGRATION_TIME_MARGIN 8 -#define OV2680_ID 0x2680 +#define OV2680_INTEGRATION_TIME_MARGIN 8 +#define OV2680_ID 0x2680 /* * OV2680 System control registers @@ -61,23 +61,23 @@ #define OV2680_SC_CMMN_SCCB_ID 0x302B /* 0x300C*/ #define OV2680_SC_CMMN_SUB_ID 0x302A /* process, version*/ -#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/ +#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/ #define OV2680_REG_EXPOSURE_PK_HIGH 0x3500 #define OV2680_REG_GAIN_PK 0x350a -#define OV2680_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/ -#define OV2680_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/ -#define OV2680_VERTICAL_START_H 0x3802 /*Bit[11:8]*/ -#define OV2680_VERTICAL_START_L 0x3803 /*Bit[7:0]*/ -#define OV2680_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/ -#define OV2680_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/ -#define OV2680_VERTICAL_END_H 0x3806 /*Bit[11:8]*/ -#define OV2680_VERTICAL_END_L 0x3807 /*Bit[7:0]*/ -#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/ -#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/ -#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/ -#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/ +#define OV2680_HORIZONTAL_START_H 0x3800 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_START_L 0x3801 /* Bit[7:0] */ +#define OV2680_VERTICAL_START_H 0x3802 /* Bit[11:8] */ +#define OV2680_VERTICAL_START_L 0x3803 /* Bit[7:0] */ +#define OV2680_HORIZONTAL_END_H 0x3804 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_END_L 0x3805 /* Bit[7:0] */ +#define OV2680_VERTICAL_END_H 0x3806 /* Bit[11:8] */ +#define OV2680_VERTICAL_END_L 0x3807 /* Bit[7:0] */ +#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /* Bit[7:0] */ +#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /* Bit[11:8] */ +#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /* Bit[7:0] */ #define OV2680_HTS 0x380c #define OV2680_VTS 0x380e #define OV2680_ISP_X_WIN 0x3810 @@ -85,7 +85,7 @@ #define OV2680_X_INC 0x3814 #define OV2680_Y_INC 0x3815 -#define OV2680_FRAME_OFF_NUM 0x4202 +#define OV2680_FRAME_OFF_NUM 0x4202 /*Flip/Mirror*/ #define OV2680_REG_FORMAT1 0x3820 @@ -94,7 +94,7 @@ #define OV2680_MWB_RED_GAIN_H 0x5004/*0x3400*/ #define OV2680_MWB_GREEN_GAIN_H 0x5006/*0x3402*/ #define OV2680_MWB_BLUE_GAIN_H 0x5008/*0x3404*/ -#define OV2680_MWB_GAIN_MAX 0x0fff +#define OV2680_MWB_GAIN_MAX 0x0fff #define OV2680_REG_ISP_CTRL00 0x5080 From 0ba7aaa904bc00cd78f8fe48fc62950d8641949f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 14 Jan 2023 13:14:56 +0100 Subject: [PATCH 155/216] media: atomisp: ov2680: Cleanup includes Remove unused includes and sort the remaining ones alphabetically. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 0e51a5f83f12..66557757bac5 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -15,25 +15,15 @@ * */ -#include - +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + #include #include -#include -#include + #include "../include/linux/atomisp_gmin_platform.h" #include "ov2680.h" From 9e70de16120807be121f6e2924f834f3a874b892 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Jan 2023 21:49:20 +0100 Subject: [PATCH 156/216] media: atomisp: ov2680: Delay power-on till streaming is started Move the setting of the mode to stream on, this also allows delaying power-on till streaming is started. And drop the deprecated s_power callback since this now no long is necessary. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 100 +++++++----------- 1 file changed, 40 insertions(+), 60 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 66557757bac5..73054ec858fe 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -328,24 +328,6 @@ static int power_down(struct v4l2_subdev *sd) return 0; } -static int ov2680_s_power(struct v4l2_subdev *sd, int on) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - - if (on == 0) { - ret = power_down(sd); - } else { - ret = power_up(sd); - } - - mutex_unlock(&dev->input_lock); - - return ret; -} - static struct v4l2_mbus_framefmt * __ov2680_get_pad_format(struct ov2680_device *sensor, struct v4l2_subdev_state *state, @@ -394,14 +376,12 @@ static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height sensor->mode.vts = OV2680_LINES_PER_FRAME; } -static int ov2680_set_mode(struct ov2680_device *sensor, int width, int height) +static int ov2680_set_mode(struct ov2680_device *sensor) { struct i2c_client *client = sensor->client; u8 pll_div, unknown, inc, fmt1, fmt2; int ret; - ov2680_calc_mode(sensor, width, height); - if (sensor->mode.binning) { pll_div = 1; unknown = 0x23; @@ -498,10 +478,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *fmt; unsigned int width, height; - int ret = 0; width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH); height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT); @@ -514,23 +492,10 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - dev_dbg(&client->dev, "%s: %dx%d\n", - __func__, fmt->width, fmt->height); - mutex_lock(&dev->input_lock); - - /* s_power has not been called yet for std v4l2 clients (camorama) */ - power_up(sd); - - ret = ov2680_set_mode(dev, fmt->width, fmt->height); - if (ret < 0) - goto err; - - /* Restore value of all ctrls */ - ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); -err: + ov2680_calc_mode(dev, fmt->width, fmt->height); mutex_unlock(&dev->input_lock); - return ret; + return 0; } static int ov2680_get_fmt(struct v4l2_subdev *sd, @@ -580,30 +545,50 @@ static int ov2680_detect(struct i2c_client *client) static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; + int ret = 0; - mutex_lock(&dev->input_lock); - if (enable) - dev_dbg(&client->dev, "ov2680_s_stream one\n"); - else - dev_dbg(&client->dev, "ov2680_s_stream off\n"); + mutex_lock(&sensor->input_lock); - ret = ov_write_reg8(client, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : OV2680_STOP_STREAMING); - if (ret == 0) { - dev->is_streaming = enable; - v4l2_ctrl_activate(dev->ctrls.vflip, !enable); - v4l2_ctrl_activate(dev->ctrls.hflip, !enable); + if (sensor->is_streaming == enable) { + dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped"); + goto error_unlock; } - //otp valid at stream on state - //if(!dev->otp_data) - // dev->otp_data = ov2680_otp_read(sd); + if (enable) { + ret = power_up(sd); + if (ret) + goto error_unlock; - mutex_unlock(&dev->input_lock); + ret = ov2680_set_mode(sensor); + if (ret) + goto error_power_down; + /* Restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) + goto error_power_down; + + ret = ov_write_reg8(client, OV2680_SW_STREAM, OV2680_START_STREAMING); + if (ret) + goto error_power_down; + } else { + ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING); + power_down(sd); + } + + sensor->is_streaming = enable; + v4l2_ctrl_activate(sensor->ctrls.vflip, !enable); + v4l2_ctrl_activate(sensor->ctrls.hflip, !enable); + + mutex_unlock(&sensor->input_lock); + return 0; + +error_power_down: + power_down(sd); +error_unlock: + mutex_unlock(&sensor->input_lock); return ret; } @@ -733,10 +718,6 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { .g_skip_frames = ov2680_g_skip_frames, }; -static const struct v4l2_subdev_core_ops ov2680_core_ops = { - .s_power = ov2680_s_power, -}; - static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { .enum_mbus_code = ov2680_enum_mbus_code, .enum_frame_size = ov2680_enum_frame_size, @@ -746,7 +727,6 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { }; static const struct v4l2_subdev_ops ov2680_ops = { - .core = &ov2680_core_ops, .video = &ov2680_video_ops, .pad = &ov2680_pad_ops, .sensor = &ov2680_sensor_ops, From 361835086993b80fcb1ce006b2c0559ffaf4cfd7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 14 Jan 2023 15:19:18 +0100 Subject: [PATCH 157/216] media: atomisp: ov2680: Add runtime-pm support Add runtime-pm support. This is a preparation patch for letting ACPI deal with the regulators and clocks instead of the DIY code in atomisp_gmin_platform.c. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 57 ++++++++++++------- drivers/staging/media/atomisp/i2c/ov2680.h | 1 - 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 73054ec858fe..a76a6f5b4df6 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -139,7 +140,8 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) struct ov2680_device *sensor = to_ov2680_sensor(sd); int ret; - if (!sensor->power_on) { + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) { ov2680_set_bayer_order(sensor, &sensor->mode.fmt); return 0; } @@ -163,6 +165,8 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) default: ret = -EINVAL; } + + pm_runtime_put(sensor->sd.dev); return ret; } @@ -245,9 +249,6 @@ static int power_up(struct v4l2_subdev *sd) return -ENODEV; } - if (dev->power_on) - return 0; /* Already on */ - /* power control */ ret = power_ctrl(sd, 1); if (ret) @@ -276,7 +277,6 @@ static int power_up(struct v4l2_subdev *sd) if (ret) goto fail_init_registers; - dev->power_on = true; return 0; fail_init_registers: @@ -302,9 +302,6 @@ static int power_down(struct v4l2_subdev *sd) return -ENODEV; } - if (!dev->power_on) - return 0; /* Already off */ - ret = dev->platform_data->flisclk_ctrl(sd, 0); if (ret) dev_err(&client->dev, "flisclk failed\n"); @@ -324,7 +321,6 @@ static int power_down(struct v4l2_subdev *sd) return ret; } - dev->power_on = false; return 0; } @@ -557,8 +553,8 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) } if (enable) { - ret = power_up(sd); - if (ret) + ret = pm_runtime_get_sync(sensor->sd.dev); + if (ret < 0) goto error_unlock; ret = ov2680_set_mode(sensor); @@ -575,7 +571,7 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) goto error_power_down; } else { ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING); - power_down(sd); + pm_runtime_put(sensor->sd.dev); } sensor->is_streaming = enable; @@ -586,7 +582,7 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) return 0; error_power_down: - power_down(sd); + pm_runtime_put(sensor->sd.dev); error_unlock: mutex_unlock(&sensor->input_lock); return ret; @@ -607,8 +603,8 @@ static int ov2680_s_config(struct v4l2_subdev *sd, mutex_lock(&dev->input_lock); - ret = power_up(sd); - if (ret) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { dev_err(&client->dev, "ov2680 power-up err.\n"); goto fail_power_on; } @@ -625,11 +621,7 @@ static int ov2680_s_config(struct v4l2_subdev *sd, } /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_csi_cfg; - } + pm_runtime_put(&client->dev); mutex_unlock(&dev->input_lock); return 0; @@ -637,7 +629,7 @@ static int ov2680_s_config(struct v4l2_subdev *sd, fail_csi_cfg: dev->platform_data->csi_cfg(sd, 0); fail_power_on: - power_down(sd); + pm_runtime_put(&client->dev); dev_err(&client->dev, "sensor power-gating failed\n"); mutex_unlock(&dev->input_lock); return ret; @@ -783,6 +775,7 @@ static void ov2680_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrls.handler); + pm_runtime_disable(&client->dev); kfree(dev); } @@ -809,6 +802,11 @@ static int ov2680_probe(struct i2c_client *client) goto out_free; } + pm_runtime_set_suspended(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + ret = ov2680_s_config(&dev->sd, client->irq, pdata); if (ret) goto out_free; @@ -845,6 +843,22 @@ static int ov2680_probe(struct i2c_client *client) return ret; } +static int ov2680_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + + return power_down(sd); +} + +static int ov2680_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + + return power_up(sd); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL); + static const struct acpi_device_id ov2680_acpi_match[] = { {"XXOV2680"}, {"OVTI2680"}, @@ -855,6 +869,7 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); static struct i2c_driver ov2680_driver = { .driver = { .name = "ov2680", + .pm = pm_sleep_ptr(&ov2680_pm_ops), .acpi_match_table = ov2680_acpi_match, }, .probe_new = ov2680_probe, diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 333acd1520e4..1403255f7c31 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -114,7 +114,6 @@ struct ov2680_device { struct mutex input_lock; struct i2c_client *client; struct camera_sensor_platform_data *platform_data; - bool power_on; bool is_streaming; struct ov2680_mode { From e25a2589e310d8592ca4197c66ad1bfa6eaf99ca Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 13:56:20 +0100 Subject: [PATCH 158/216] media: atomisp: ov2680: s/dev/sensor/ Using dev as name for variables pointing to struct ov2680_device is a bit unfortunate choice. All the recently added / rewritten code is already using sensor for this, replace the remaining usages of "struct ov2680_device *dev" with "struct ov2680_device *sensor". Note the power_up()/power_down() related functions are not changed as these will be removed in one of the next patches. No functional changes. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index a76a6f5b4df6..90c9d7abded4 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -473,24 +473,24 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct v4l2_mbus_framefmt *fmt; unsigned int width, height; width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH); height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT); - fmt = __ov2680_get_pad_format(dev, sd_state, format->pad, format->which); - ov2680_fill_format(dev, fmt, width, height); + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); + ov2680_fill_format(sensor, fmt, width, height); format->format = *fmt; if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - mutex_lock(&dev->input_lock); - ov2680_calc_mode(dev, fmt->width, fmt->height); - mutex_unlock(&dev->input_lock); + mutex_lock(&sensor->input_lock); + ov2680_calc_mode(sensor, fmt->width, fmt->height); + mutex_unlock(&sensor->input_lock); return 0; } @@ -498,10 +498,10 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct v4l2_mbus_framefmt *fmt; - fmt = __ov2680_get_pad_format(dev, sd_state, format->pad, format->which); + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); format->format = *fmt; return 0; } @@ -591,17 +591,17 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) static int ov2680_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; if (!platform_data) return -ENODEV; - dev->platform_data = + sensor->platform_data = (struct camera_sensor_platform_data *)platform_data; - mutex_lock(&dev->input_lock); + mutex_lock(&sensor->input_lock); ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { @@ -609,7 +609,7 @@ static int ov2680_s_config(struct v4l2_subdev *sd, goto fail_power_on; } - ret = dev->platform_data->csi_cfg(sd, 1); + ret = sensor->platform_data->csi_cfg(sd, 1); if (ret) goto fail_csi_cfg; @@ -622,16 +622,16 @@ static int ov2680_s_config(struct v4l2_subdev *sd, /* turn off sensor, after probed */ pm_runtime_put(&client->dev); - mutex_unlock(&dev->input_lock); + mutex_unlock(&sensor->input_lock); return 0; fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); + sensor->platform_data->csi_cfg(sd, 0); fail_power_on: pm_runtime_put(&client->dev); dev_err(&client->dev, "sensor power-gating failed\n"); - mutex_unlock(&dev->input_lock); + mutex_unlock(&sensor->input_lock); return ret; } @@ -766,35 +766,35 @@ static int ov2680_init_controls(struct ov2680_device *sensor) static void ov2680_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); dev_dbg(&client->dev, "ov2680_remove...\n"); - dev->platform_data->csi_cfg(sd, 0); + sensor->platform_data->csi_cfg(sd, 0); v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrls.handler); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); pm_runtime_disable(&client->dev); - kfree(dev); + kfree(sensor); } static int ov2680_probe(struct i2c_client *client) { - struct ov2680_device *dev; + struct ov2680_device *sensor; int ret; void *pdata; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); + if (!sensor) return -ENOMEM; - mutex_init(&dev->input_lock); + mutex_init(&sensor->input_lock); - dev->client = client; - v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops); + sensor->client = client; + v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops); - pdata = gmin_camera_platform_data(&dev->sd, + pdata = gmin_camera_platform_data(&sensor->sd, ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_bggr); if (!pdata) { @@ -807,29 +807,29 @@ static int ov2680_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(&client->dev, 1000); pm_runtime_use_autosuspend(&client->dev); - ret = ov2680_s_config(&dev->sd, client->irq, pdata); + ret = ov2680_s_config(&sensor->sd, client->irq, pdata); if (ret) goto out_free; - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = ov2680_init_controls(dev); + ret = ov2680_init_controls(sensor); if (ret) { ov2680_remove(client); return ret; } - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); if (ret) { ov2680_remove(client); return ret; } - ov2680_fill_format(dev, &dev->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); + ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + ret = atomisp_register_i2c_module(&sensor->sd, pdata, RAW_CAMERA); if (ret) { ov2680_remove(client); return ret; @@ -838,8 +838,8 @@ static int ov2680_probe(struct i2c_client *client) return 0; out_free: dev_dbg(&client->dev, "+++ out free\n"); - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); + v4l2_device_unregister_subdev(&sensor->sd); + kfree(sensor); return ret; } From 66c7b303c7108db0a6fe6525bf6acc749e979de4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Jan 2023 20:30:40 +0100 Subject: [PATCH 159/216] media: atomisp: ov2680: Add dev local variable to probe() Add a dev local variable to probe(), to allow shortening &client->dev in various places, including further patches in this series. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 90c9d7abded4..6d2b0be6bf86 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -781,6 +781,7 @@ static void ov2680_remove(struct i2c_client *client) static int ov2680_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct ov2680_device *sensor; int ret; void *pdata; @@ -802,10 +803,10 @@ static int ov2680_probe(struct i2c_client *client) goto out_free; } - pm_runtime_set_suspended(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); ret = ov2680_s_config(&sensor->sd, client->irq, pdata); if (ret) From e98b8993bfffbe552b7881bd9b7450f10f3bb9d3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 14:05:38 +0100 Subject: [PATCH 160/216] media: atomisp: ov2680: Use devm_kzalloc() for sensor data struct Use devm_kzalloc() to allocate the sensor data struct. It is always free-ed as the last step of probe-error-exit or remove, so it can be devm-managed. This will make unwinding things easier when support is added to the ov2680 code to use standard GPIO APIs instead of the custom atomisp_gmin code. This also allows dropping the out_free label and use direct return on errors. This may seem like a functional change since the out_free label also did a v4l2_device_unregister_subdev() but at the 2 changed returns the device is not registered yet, so that always is a no-op and can be dropped. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/i2c/atomisp-ov2680.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 6d2b0be6bf86..06df78d46689 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -776,7 +776,6 @@ static void ov2680_remove(struct i2c_client *client) media_entity_cleanup(&sensor->sd.entity); v4l2_ctrl_handler_free(&sensor->ctrls.handler); pm_runtime_disable(&client->dev); - kfree(sensor); } static int ov2680_probe(struct i2c_client *client) @@ -786,7 +785,7 @@ static int ov2680_probe(struct i2c_client *client) int ret; void *pdata; - sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) return -ENOMEM; @@ -798,10 +797,8 @@ static int ov2680_probe(struct i2c_client *client) pdata = gmin_camera_platform_data(&sensor->sd, ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_bggr); - if (!pdata) { - ret = -EINVAL; - goto out_free; - } + if (!pdata) + return -EINVAL; pm_runtime_set_suspended(dev); pm_runtime_enable(dev); @@ -810,7 +807,7 @@ static int ov2680_probe(struct i2c_client *client) ret = ov2680_s_config(&sensor->sd, client->irq, pdata); if (ret) - goto out_free; + return ret; sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; @@ -837,11 +834,6 @@ static int ov2680_probe(struct i2c_client *client) } return 0; -out_free: - dev_dbg(&client->dev, "+++ out free\n"); - v4l2_device_unregister_subdev(&sensor->sd); - kfree(sensor); - return ret; } static int ov2680_suspend(struct device *dev) From b7e155e16601b0c6f34e3345b9eca6a2efc5bc5d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 15 Jan 2023 22:03:19 +0100 Subject: [PATCH 161/216] media: atomisp: ov2680: Switch over to ACPI powermanagement The DSDT of all Windows BYT / CHT devices which I have seen has proper ACPI powermagement for the clk and regulators used by the sensors. So there is no need for the whole custom atomisp_gmin custom code to disable the ACPI pm and directly poke at the PMIC for this. Replace all the atomisp_gmin usage with using the new atomisp_register_sensor_no_gmin() / atomisp_unregister_subdev() helpers which allow registering a sensor with the atomisp code without using any of the atomisp_gmin power-management code. Note eventually these calls should be replaced by the standard v4l2_async_register_subdev_sensor() mechanism. But this first requires a bunch of work to the atomisp main code to make it set the necessary fwnodes up, similar to how drivers/media/pci/intel/ipu3/cio2-bridge.c does this. This has been tested on: -Trekstor Surftab duo W1 10.1, CHT, AXP288 PMIC, 2x ov2680 sensor -Asus T101HA, CHT, TI PMIC, 1x ov2680 sensor -MPMAN Converter 9, BYT, AXP288 PMIC, ov2680 back, gc0310 front sensor Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-ov2680.c | 231 ++++-------------- drivers/staging/media/atomisp/i2c/ov2680.h | 3 +- 2 files changed, 53 insertions(+), 181 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 06df78d46689..aeb38599fe13 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -185,145 +187,6 @@ static int ov2680_init_registers(struct v4l2_subdev *sd) return ret; } -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - dev_dbg(&client->dev, "%s: %s", __func__, flag ? "on" : "off"); - - if (flag) { - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } - - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov2680_device *dev = to_ov2680_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* - * The OV2680 documents only one GPIO input (#XSHUTDN), but - * existing integrations often wire two (reset/power_down) - * because that is the way other sensors work. There is no - * way to tell how it is wired internally, so existing - * firmwares expose both and we drive them symmetrically. - */ - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - /* Ignore return from second gpio, it may not be there */ - dev->platform_data->gpio1_ctrl(sd, 1); - usleep_range(10000, 15000); - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->gpio0_ctrl(sd, 0); - } - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); - - ret = ov2680_init_registers(sd); - if (ret) - goto fail_init_registers; - - return 0; - -fail_init_registers: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) { - dev_err(&client->dev, "vprog failed.\n"); - return ret; - } - - return 0; -} - static struct v4l2_mbus_framefmt * __ov2680_get_pad_format(struct ov2680_device *sensor, struct v4l2_subdev_state *state, @@ -588,20 +451,10 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int ov2680_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) +static int ov2680_s_config(struct v4l2_subdev *sd) { - struct ov2680_device *sensor = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - sensor->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&sensor->input_lock); + int ret; ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { @@ -609,29 +462,13 @@ static int ov2680_s_config(struct v4l2_subdev *sd, goto fail_power_on; } - ret = sensor->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - /* config & detect sensor */ ret = ov2680_detect(client); - if (ret) { + if (ret) dev_err(&client->dev, "ov2680_detect err s_config.\n"); - goto fail_csi_cfg; - } - /* turn off sensor, after probed */ - pm_runtime_put(&client->dev); - mutex_unlock(&sensor->input_lock); - - return 0; - -fail_csi_cfg: - sensor->platform_data->csi_cfg(sd, 0); fail_power_on: pm_runtime_put(&client->dev); - dev_err(&client->dev, "sensor power-gating failed\n"); - mutex_unlock(&sensor->input_lock); return ret; } @@ -770,20 +607,33 @@ static void ov2680_remove(struct i2c_client *client) dev_dbg(&client->dev, "ov2680_remove...\n"); - sensor->platform_data->csi_cfg(sd, 0); - + atomisp_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sensor->sd.entity); v4l2_ctrl_handler_free(&sensor->ctrls.handler); pm_runtime_disable(&client->dev); } +/* + * Unlike other sensors which have both a rest and powerdown input pins, + * the OV2680 only has a powerdown input. But some ACPI tables still list + * 2 GPIOs for the OV2680 and it is unclear which to use. So try to get + * up to 2 GPIOs (1 mandatory, 1 optional) and control them in sync. + */ +static const struct acpi_gpio_params ov2680_first_gpio = { 0, 0, true }; +static const struct acpi_gpio_params ov2680_second_gpio = { 1, 0, true }; + +static const struct acpi_gpio_mapping ov2680_gpio_mapping[] = { + { "powerdown-gpios", &ov2680_first_gpio, 1 }, + { "powerdown-alt-gpios", &ov2680_second_gpio, 1 }, + { }, +}; + static int ov2680_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov2680_device *sensor; int ret; - void *pdata; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) @@ -794,18 +644,24 @@ static int ov2680_probe(struct i2c_client *client) sensor->client = client; v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops); - pdata = gmin_camera_platform_data(&sensor->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - if (!pdata) - return -EINVAL; + ret = devm_acpi_dev_add_driver_gpios(&client->dev, ov2680_gpio_mapping); + if (ret) + return ret; + + sensor->powerdown = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n"); + + sensor->powerdown_alt = devm_gpiod_get_optional(dev, "powerdown-alt", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown_alt)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown_alt), "getting powerdown-alt GPIO\n"); pm_runtime_set_suspended(dev); pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - ret = ov2680_s_config(&sensor->sd, client->irq, pdata); + ret = ov2680_s_config(&sensor->sd); if (ret) return ret; @@ -827,7 +683,8 @@ static int ov2680_probe(struct i2c_client *client) ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); - ret = atomisp_register_i2c_module(&sensor->sd, pdata, RAW_CAMERA); + ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); if (ret) { ov2680_remove(client); return ret; @@ -839,15 +696,29 @@ static int ov2680_probe(struct i2c_client *client) static int ov2680_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); - return power_down(sd); + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->powerdown_alt, 1); + return 0; } static int ov2680_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); - return power_up(sd); + /* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */ + usleep_range(5000, 6000); + + gpiod_set_value_cansleep(sensor->powerdown, 0); + gpiod_set_value_cansleep(sensor->powerdown_alt, 0); + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + ov2680_init_registers(sd); + return 0; } static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 1403255f7c31..a37af0a74a53 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -113,7 +113,8 @@ struct ov2680_device { struct media_pad pad; struct mutex input_lock; struct i2c_client *client; - struct camera_sensor_platform_data *platform_data; + struct gpio_desc *powerdown; + struct gpio_desc *powerdown_alt; bool is_streaming; struct ov2680_mode { From 3ddac68f667c15cd1f44a31285d44b2c1a01bfc7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 3 Dec 2022 16:48:07 +0100 Subject: [PATCH 162/216] media: atomisp: ov2722: Call atomisp_gmin_remove_subdev() on probe failure Call atomisp_gmin_remove_subdev() on probe failure to properly free the GPIOs and other resources acquired by the gmin_camera_platform_data() call earlier. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index d819ab5de28a..d874e12da8cc 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -994,6 +994,7 @@ static int ov2722_probe(struct i2c_client *client) v4l2_ctrl_handler_free(&dev->ctrl_handler); out_free: + atomisp_gmin_remove_subdev(&dev->sd); v4l2_device_unregister_subdev(&dev->sd); kfree(dev); return ret; From aec221279a2934de5fbfb8d553fcedb522772d8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 3 Dec 2022 16:44:21 +0100 Subject: [PATCH 163/216] media: atomisp: ov2722: Fix GPIO1 polarity The comment claims the PWDN pin is active when pulled down in other words, it is /power-down so it needs to be driven high to get the sensor powered-up (not powered down) and flag is 1 when powering-up the sensor so the ! is wrong, drop it. This also matches with the schematics which I have which shows GPIO1 also enables a 3.3v line to the sensor-module which controls the privacy-LED and indeed before this patch the privacy LED was inverted from what it should be (and the sensor did not work). Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index d874e12da8cc..83d036b5d772 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -512,10 +512,7 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) * before PWDN# when turning it on or off. */ ret = dev->platform_data->gpio0_ctrl(sd, flag); - /* - *ov2722 PWDN# active high when pull down,opposite to the convention - */ - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + ret |= dev->platform_data->gpio1_ctrl(sd, flag); return ret; } From 4272fd7ae69aef86aa4c9f7d49a9d15beb50547e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 3 Dec 2022 20:44:00 +0100 Subject: [PATCH 164/216] media: atomisp: ov2722: Don't take the input_lock for try_fmt calls. On ov2722_set_fmt() calls with format->which == V4L2_SUBDEV_FORMAT_TRY, ov2722_set_fmt() does not talk to the sensor, so there is no need to lock the dev->input_lock mutex in this case. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 83d036b5d772..e09c80d1f9ec 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -651,7 +651,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, if (!ov2722_info) return -EINVAL; - mutex_lock(&dev->input_lock); res = v4l2_find_nearest_size(ov2722_res_preview, ARRAY_SIZE(ov2722_res_preview), width, height, fmt->width, fmt->height); @@ -665,10 +664,10 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { sd_state->pads->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); return 0; } + mutex_lock(&dev->input_lock); dev->pixels_per_line = dev->res->pixels_per_line; dev->lines_per_frame = dev->res->lines_per_frame; From b3118a942c820c8d94a11ffd3d950660b3566d35 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 3 Dec 2022 21:16:25 +0100 Subject: [PATCH 165/216] media: atomisp: ov2722: Power on sensor from set_fmt() callback Depending on which order userspace makes various v4l2 calls, the sensor might still be powered down when set_fmt is called. What should really happen here is delay the writing of the mode-related registers till streaming is started, but for now use the same quick fix as the atomisp_ov2680 / atomisp_gc0310 code and call power_up() from set_fmt() in combination with keeping track of the power-state to avoid doing the power-up sequence twice. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 12 ++++++++++++ drivers/staging/media/atomisp/i2c/ov2722.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index e09c80d1f9ec..5d2e6e2e72f0 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -528,6 +528,9 @@ static int power_up(struct v4l2_subdev *sd) return -ENODEV; } + if (dev->power_on == 1) + return 0; /* Already on */ + /* power control */ ret = power_ctrl(sd, 1); if (ret) @@ -552,6 +555,7 @@ static int power_up(struct v4l2_subdev *sd) /* according to DS, 20ms is needed between PWDN and i2c access */ msleep(20); + dev->power_on = 1; return 0; fail_clk: @@ -575,6 +579,9 @@ static int power_down(struct v4l2_subdev *sd) return -ENODEV; } + if (dev->power_on == 0) + return 0; /* Already off */ + ret = dev->platform_data->flisclk_ctrl(sd, 0); if (ret) dev_err(&client->dev, "flisclk failed\n"); @@ -592,6 +599,7 @@ static int power_down(struct v4l2_subdev *sd) if (ret) dev_err(&client->dev, "vprog failed.\n"); + dev->power_on = 0; return ret; } @@ -669,6 +677,9 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, mutex_lock(&dev->input_lock); + /* s_power has not been called yet for std v4l2 clients (camorama) */ + power_up(sd); + dev->pixels_per_line = dev->res->pixels_per_line; dev->lines_per_frame = dev->res->lines_per_frame; @@ -959,6 +970,7 @@ static int ov2722_probe(struct i2c_client *client) return -ENOMEM; mutex_init(&dev->input_lock); + dev->power_on = -1; dev->res = &ov2722_res_preview[0]; v4l2_i2c_subdev_init(&dev->sd, client, &ov2722_ops); diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index 020743a944c4..640d3ffcaa5c 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -198,7 +198,7 @@ struct ov2722_device { struct ov2722_resolution *res; struct camera_sensor_platform_data *platform_data; - int run_mode; + int power_on; u16 pixels_per_line; u16 lines_per_frame; u8 type; From 2e82f054b58546efd062595dcfa448ee3d048273 Mon Sep 17 00:00:00 2001 From: Brent Pappas Date: Wed, 18 Jan 2023 17:07:39 +0100 Subject: [PATCH 166/216] media: atomisp: pci: Replace bytes macros with functions Replace the function-like macros FPNTBL_BYTES(), SCTBL_BYTES(), and MORPH_PLANE_BYTES() with functions to comply with Linux coding style standards. Replace multiplication with calls to array_size() and array3_size() to prevent accidental arithmetic overflow. Link: https://lore.kernel.org/r/20230118160739.26059-1-bpappas@pappasbrent.com Signed-off-by: Brent Pappas Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/sh_css_params.c | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index f08564f58242..588f2adab058 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -98,17 +98,27 @@ #include "sh_css_frac.h" #include "ia_css_bufq.h" -#define FPNTBL_BYTES(binary) \ - (sizeof(char) * (binary)->in_frame_info.res.height * \ - (binary)->in_frame_info.padded_width) +static size_t fpntbl_bytes(const struct ia_css_binary *binary) +{ + return array3_size(sizeof(char), + binary->in_frame_info.res.height, + binary->in_frame_info.padded_width); +} -#define SCTBL_BYTES(binary) \ - (sizeof(unsigned short) * (binary)->sctbl_height * \ - (binary)->sctbl_aligned_width_per_color * IA_CSS_SC_NUM_COLORS) +static size_t sctbl_bytes(const struct ia_css_binary *binary) +{ + return size_mul(sizeof(unsigned short), + array3_size(binary->sctbl_height, + binary->sctbl_aligned_width_per_color, + IA_CSS_SC_NUM_COLORS)); +} -#define MORPH_PLANE_BYTES(binary) \ - (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \ - (binary)->morph_tbl_height) +static size_t morph_plane_bytes(const struct ia_css_binary *binary) +{ + return array3_size(SH_CSS_MORPH_TABLE_ELEM_BYTES, + binary->morph_tbl_aligned_width, + binary->morph_tbl_height); +} /* We keep a second copy of the ptr struct for the SP to access. Again, this would not be necessary on the chip. */ @@ -3279,7 +3289,7 @@ sh_css_params_write_to_ddr_internal( if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, - (size_t)(FPNTBL_BYTES(binary)), + fpntbl_bytes(binary), params->config_changed[IA_CSS_FPN_ID], &err); if (err) { @@ -3304,7 +3314,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced = reallocate_buffer(&ddr_map->sc_tbl, &ddr_map_size->sc_tbl, - SCTBL_BYTES(binary), + sctbl_bytes(binary), params->sc_table_changed, &err); if (err) { @@ -3538,8 +3548,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_x[i], virt_size_tetra_x[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { @@ -3549,8 +3558,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_y[i], virt_size_tetra_y[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { From 197ec0f48d7a3aff984c2502af315e5d3e48eedb Mon Sep 17 00:00:00 2001 From: Brent Pappas Date: Fri, 20 Jan 2023 19:26:25 +0100 Subject: [PATCH 167/216] media: atomisp: pci: hive_isp_css_common: host: vmem: Replace SUBWORD macros with functions Replace the macros SUBWORD() and INV_SUBWORD() with functions to comply with Linux coding style standards. Link: https://lore.kernel.org/r/20230120182625.23227-1-bpappas@pappasbrent.com Signed-off-by: Brent Pappas Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../pci/hive_isp_css_common/host/vmem.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c index 6620f091442f..d9cdfbc50197 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c @@ -28,10 +28,18 @@ typedef hive_uedge *hive_wide; /* Copied from SDK: sim_semantics.c */ /* subword bits move like this: MSB[____xxxx____]LSB -> MSB[00000000xxxx]LSB */ -#define SUBWORD(w, start, end) (((w) & (((1ULL << ((end) - 1)) - 1) << 1 | 1)) >> (start)) +static inline hive_uedge +subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return (w & (((1ULL << (end - 1)) - 1) << 1 | 1)) >> start; +} /* inverse subword bits move like this: MSB[xxxx____xxxx]LSB -> MSB[xxxx0000xxxx]LSB */ -#define INV_SUBWORD(w, start, end) ((w) & (~(((1ULL << ((end) - 1)) - 1) << 1 | 1) | ((1ULL << (start)) - 1))) +static inline hive_uedge +inv_subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return w & (~(((1ULL << (end - 1)) - 1) << 1 | 1) | ((1ULL << start) - 1)); +} #define uedge_bits (8 * sizeof(hive_uedge)) #define move_lower_bits(target, target_bit, src, src_bit) move_subword(target, target_bit, src, 0, src_bit) @@ -50,18 +58,18 @@ move_subword( unsigned int start_bit = target_bit % uedge_bits; unsigned int subword_width = src_end - src_start; - hive_uedge src_subword = SUBWORD(src, src_start, src_end); + hive_uedge src_subword = subword(src, src_start, src_end); if (subword_width + start_bit > uedge_bits) { /* overlap */ hive_uedge old_val1; - hive_uedge old_val0 = INV_SUBWORD(target[start_elem], start_bit, uedge_bits); + hive_uedge old_val0 = inv_subword(target[start_elem], start_bit, uedge_bits); target[start_elem] = old_val0 | (src_subword << start_bit); - old_val1 = INV_SUBWORD(target[start_elem + 1], 0, + old_val1 = inv_subword(target[start_elem + 1], 0, subword_width + start_bit - uedge_bits); target[start_elem + 1] = old_val1 | (src_subword >> (uedge_bits - start_bit)); } else { - hive_uedge old_val = INV_SUBWORD(target[start_elem], start_bit, + hive_uedge old_val = inv_subword(target[start_elem], start_bit, start_bit + subword_width); target[start_elem] = old_val | (src_subword << start_bit); From 738dfb32f1305478c2c1b87e997142cefad4ad7e Mon Sep 17 00:00:00 2001 From: Brent Pappas Date: Fri, 20 Jan 2023 18:14:08 +0100 Subject: [PATCH 168/216] media: atomisp: pci: sh_css: Inline single invocation of macro STATS_ENABLED() Inline the single invocation of the macro STATS_ENABLED(). The macro abstraction is not necessary because the logic behind it is only used once. Link: https://lore.kernel.org/r/20230120171408.16099-1-bpappas@pappasbrent.com Signed-off-by: Brent Pappas Reviewed-by: Andy Shevchenko Reviewed-by: Dan Carpenter Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 726cb7aa4ecd..93789500416f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -97,9 +97,6 @@ */ #define JPEG_BYTES (16 * 1024 * 1024) -#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \ - (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis)) - struct sh_css my_css; int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL; @@ -3743,7 +3740,9 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, * The SP will read the params after it got * empty 3a and dis */ - if (STATS_ENABLED(stage)) { + if (stage->binary && stage->binary->info && + (stage->binary->info->sp.enable.s3a || + stage->binary->info->sp.enable.dis)) { /* there is a stage that needs it */ return_err = ia_css_bufq_enqueue_buffer(thread_id, queue_id, From b6a1af0362b3232c7b474b9b46e49b862602018c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 12:58:32 +0100 Subject: [PATCH 169/216] media: visl: make visl_qops static This struct can be static. This fixes a sparse warning: visl-video.c:690:22: warning: symbol 'visl_qops' was not declared. Should it be static? Signed-off-by: Hans Verkuil Cc: Daniel Almeida Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/visl/visl-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index b08664dfbe5f..7cac6a6456eb 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -687,7 +687,7 @@ static void visl_buf_request_complete(struct vb2_buffer *vb) v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); } -const struct vb2_ops visl_qops = { +static const struct vb2_ops visl_qops = { .queue_setup = visl_queue_setup, .buf_out_validate = visl_buf_out_validate, .buf_prepare = visl_buf_prepare, From 9996b9655470ff8bd294e587600734ece0ad695a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:16:40 +0100 Subject: [PATCH 170/216] media: davinci/vpif.c: drop unnecessary cast DEFINE_RES_IRQ_NAMED already casts to (struct resource), so no need to do it again. This fixes a sparse warning: vpif.c:483:20: warning: cast to non-scalar Signed-off-by: Hans Verkuil Cc: "Lad, Prabhakar" Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/davinci/vpif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index da27da4c165a..832489822706 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -480,7 +480,7 @@ static int vpif_probe(struct platform_device *pdev) ret = irq; goto err_put_rpm; } - res_irq = (struct resource)DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); + res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); res_irq.flags |= irq_get_trigger_type(irq); pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL); From 7e5eb42a4952a7c49c6ac48272fb27b63d87f995 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:18:18 +0100 Subject: [PATCH 171/216] media: i2c: s5c73m3: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes a smatch warning: s5c73m3-core.c:439 __s5c73m3_s_stream() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Cc: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 318a4ec2d8a5..7938a3327d3e 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -435,7 +435,7 @@ static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd, state->streaming = !!on; if (!on) - return ret; + return 0; if (state->apply_fiv) { ret = s5c73m3_set_frame_rate(state); From 8963c1195235e5cfff805b84ca7fd40004e8d155 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:20:36 +0100 Subject: [PATCH 172/216] media: dvb-frontends: cxd2880: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes two smatch warnings: cxd2880_tnrdmd.c:2165 cxd2880_tnrdmd_check_internal_cpu_status() warn: missing error code? 'ret' cxd2880_tnrdmd.c:2169 cxd2880_tnrdmd_check_internal_cpu_status() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Cc: Yasunari Takiguchi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c index 4cf2d7cfd3f5..0a1f3899d72c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -2162,11 +2162,11 @@ int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd else *task_completed = 0; - return ret; + return 0; } if (cpu_status != 0) { *task_completed = 0; - return ret; + return 0; } ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status); From a0ccbc65bc751f9337ed985bac3741a596872854 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:26:19 +0100 Subject: [PATCH 173/216] media: usb: dvb-usb-v2: af9015.c: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes two smatch warnings: af9015.c:1168 af9015_rc_query() warn: missing error code? 'ret' af9015.c:1177 af9015_rc_query() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Cc: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index d33514acc2b5..4014f7d07330 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1165,7 +1165,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* If any of these are non-zero, assume invalid data */ if (buf[1] || buf[2] || buf[3]) { dev_dbg(&intf->dev, "invalid data\n"); - return ret; + return 0; } /* Check for repeat of previous code */ @@ -1174,7 +1174,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; - return ret; + return 0; } /* Only process key if canary killed */ From e670d7e3c53d0345c7acfa5b9a2b1c33537a0dad Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:29:11 +0100 Subject: [PATCH 174/216] media: dvb-frontends: cxd2880: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes 10 smatch warnings: cxd2880_tnrdmd_dvbt.c:836 cxd2880_tnrdmd_dvbt_check_demod_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt.c:841 cxd2880_tnrdmd_dvbt_check_demod_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt.c:896 cxd2880_tnrdmd_dvbt_check_ts_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt.c:901 cxd2880_tnrdmd_dvbt_check_ts_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt.c:904 cxd2880_tnrdmd_dvbt_check_ts_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt2.c:1027 cxd2880_tnrdmd_dvbt2_check_demod_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt2.c:1032 cxd2880_tnrdmd_dvbt2_check_demod_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt2.c:1087 cxd2880_tnrdmd_dvbt2_check_ts_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt2.c:1092 cxd2880_tnrdmd_dvbt2_check_ts_lock() warn: missing error code? 'ret' cxd2880_tnrdmd_dvbt2.c:1095 cxd2880_tnrdmd_dvbt2_check_ts_lock() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Cc: Yasunari Takiguchi Signed-off-by: Mauro Carvalho Chehab --- .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c | 14 +++++++------- .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c index fe3c6f8b1b3e..c7e79da8c432 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -833,12 +833,12 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (sync_stat == 6) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } ret = @@ -854,7 +854,7 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd @@ -893,15 +893,15 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (ts_lock) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } else if (!unlock_detected) { *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } ret = @@ -915,5 +915,5 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c index dd32004a12d8..a9ab983348c8 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -1024,12 +1024,12 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (sync_stat == 6) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } ret = @@ -1045,7 +1045,7 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd @@ -1084,15 +1084,15 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (ts_lock) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } else if (!unlock_detected) { *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } ret = @@ -1106,7 +1106,7 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd From 5a1a39a8ac30c7f116d427f7271927d976e4723e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:33:10 +0100 Subject: [PATCH 175/216] media: marvell: change return to goto for proper unwind The probe function used 'goto out' everywhere, except in one place where it returned an error. That too should be a 'goto out'. This fixes a smatch warning: mmp-driver.c:257 mmpcam_probe() warn: missing unwind goto? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell/mmp-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c index df16899ab1cb..ef22bf8f276c 100644 --- a/drivers/media/platform/marvell/mmp-driver.c +++ b/drivers/media/platform/marvell/mmp-driver.c @@ -254,7 +254,7 @@ static int mmpcam_probe(struct platform_device *pdev) */ ret = mccic_register(mcam); if (ret) - return ret; + goto out; /* * Add OF clock provider. From 55869f435d7f6a121722c687e3ac056168e473eb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:37:23 +0100 Subject: [PATCH 176/216] media: dvb-frontends: drx39xyj: replace return with goto for proper unwind In three places there was a return instead of a goto to the unwind code. This fixes three smatch warnings: drxj.c:9542 ctrl_get_qam_sig_quality() warn: missing unwind goto? drxj.c:10919 ctrl_set_standard() warn: missing unwind goto? drxj.c:11466 drxj_open() warn: missing unwind goto? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 1dff59ca21a1..6bf6559b127f 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9539,7 +9539,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM256 << 2; break; default: - return -EIO; + rc = -EIO; + goto rw_error; } /* ------------------------------ */ @@ -10916,7 +10917,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard) break; case DRX_STANDARD_AUTO: default: - return -EINVAL; + rc = -EINVAL; + goto rw_error; } /* @@ -11463,7 +11465,8 @@ static int drxj_open(struct drx_demod_instance *demod) if (DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode)) { pr_err("Should powerup before loading the firmware."); - return -EINVAL; + rc = -EINVAL; + goto rw_error; } rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_UPLOAD); From 5949afa34a0aebe239e3f5b54deb543a464d2125 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:56:20 +0100 Subject: [PATCH 177/216] media: mediatek: mdp3: replace return by goto for proper unwind An error was returned at one point without going through the goto label for proper unwinding. This fixes a smatch warning: mtk-mdp3-comp.c:1005 mdp_comp_config() warn: missing unwind goto? Signed-off-by: Hans Verkuil Cc: Moudy Ho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 7bc05f42a23c..091a68685590 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1002,7 +1002,8 @@ int mdp_comp_config(struct mdp_dev *mdp) if (!pdev) { dev_warn(dev, "can't find platform device of node:%s\n", node->name); - return -ENODEV; + ret = -ENODEV; + goto err_init_comps; } comp->comp_dev = &pdev->dev; From 222370776f9da3edcb702139ca0a3a73484b7986 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 13:59:16 +0100 Subject: [PATCH 178/216] media: mediatek: vcodec/venc: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes a smatch warning: venc_h264_if.c:568 h264_encode_frame() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Cc: Andrew-CT Chen Cc: Yunfei Dong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c index 13c4f860fa69..60fd165c0d94 100644 --- a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c @@ -565,7 +565,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, *bs_size); ++inst->frm_cnt; ++inst->skip_frm_cnt; - return ret; + return 0; } irq_status = h264_enc_wait_venc_done(inst); @@ -580,7 +580,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-", inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm); - return ret; + return 0; } static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, From 0d3732fb1b20d2a636d294cdf51c35f9233d622a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 14:00:47 +0100 Subject: [PATCH 179/216] media: ti: davinci: vpbe_display.c: return 0 instead of 'ret'. Since 'ret' is known to be 0, just return '0'. This fixes a smatch warning: vpbe_display.c:1152 vpbe_display_open() warn: missing error code? 'err' Signed-off-by: Hans Verkuil Cc: "Lad, Prabhakar" Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti/davinci/vpbe_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c index 9ea70817538e..ea2d0795d1e2 100644 --- a/drivers/media/platform/ti/davinci/vpbe_display.c +++ b/drivers/media/platform/ti/davinci/vpbe_display.c @@ -1149,7 +1149,7 @@ static int vpbe_display_open(struct file *file) /* leaving if layer is already initialized */ if (!v4l2_fh_is_singular_file(file)) - return err; + return 0; if (!layer->usrs) { if (mutex_lock_interruptible(&layer->opslock)) From 6a4c664539e6de9b32b65ddcf767ec1bcc1d7f8a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 14:03:51 +0100 Subject: [PATCH 180/216] media: i2c: ov7670: 0 instead of -EINVAL was returned If the media bus is unsupported, then return -EINVAL. Instead it returned 'ret' which happened to be 0. This fixes a smatch warning: ov7670.c:1843 ov7670_parse_dt() warn: missing error code? 'ret' Signed-off-by: Hans Verkuil Fixes: 01b8444828fc ("media: v4l2: i2c: ov7670: Implement OF mbus configuration") Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 27db0a07de1f..b1bb0833571e 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1840,7 +1840,7 @@ static int ov7670_parse_dt(struct device *dev, if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) { dev_err(dev, "Unsupported media bus type\n"); - return ret; + return -EINVAL; } info->mbus_config = bus_cfg.bus.parallel.flags; From 107b7a219bb6ca4e70254cb2247af54939fb4713 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Jan 2023 14:46:49 +0100 Subject: [PATCH 181/216] media: dvb-frontends: mb86a16.c: always use the same error path If the message length was wrong, the dprintk() after the 'err' label was bypassed. Fix that, and fix a smatch warning at the same time: mb86a16.c:1514 mb86a16_send_diseqc_msg() warn: missing unwind goto? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a16.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 2505f1e5794e..d3e29937cf4c 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -1498,6 +1498,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct mb86a16_state *state = fe->demodulator_priv; + int ret = -EREMOTEIO; int i; u8 regs; @@ -1510,8 +1511,10 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, regs = 0x18; - if (cmd->msg_len > 5 || cmd->msg_len < 4) - return -EINVAL; + if (cmd->msg_len > 5 || cmd->msg_len < 4) { + ret = -EINVAL; + goto err; + } for (i = 0; i < cmd->msg_len; i++) { if (mb86a16_write(state, regs, cmd->msg[i]) < 0) @@ -1532,7 +1535,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, err: dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; + return ret; } static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, From ebad8e731c1c06adf04621d6fd327b860c0861b5 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Mon, 23 Jan 2023 03:04:38 +0100 Subject: [PATCH 182/216] media: usb: siano: Fix use after free bugs caused by do_submit_urb There are UAF bugs caused by do_submit_urb(). One of the KASan reports is shown below: [ 36.403605] BUG: KASAN: use-after-free in worker_thread+0x4a2/0x890 [ 36.406105] Read of size 8 at addr ffff8880059600e8 by task kworker/0:2/49 [ 36.408316] [ 36.408867] CPU: 0 PID: 49 Comm: kworker/0:2 Not tainted 6.2.0-rc3-15798-g5a41237ad1d4-dir8 [ 36.411696] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g15584 [ 36.416157] Workqueue: 0x0 (events) [ 36.417654] Call Trace: [ 36.418546] [ 36.419320] dump_stack_lvl+0x96/0xd0 [ 36.420522] print_address_description+0x75/0x350 [ 36.421992] print_report+0x11b/0x250 [ 36.423174] ? _raw_spin_lock_irqsave+0x87/0xd0 [ 36.424806] ? __virt_addr_valid+0xcf/0x170 [ 36.426069] ? worker_thread+0x4a2/0x890 [ 36.427355] kasan_report+0x131/0x160 [ 36.428556] ? worker_thread+0x4a2/0x890 [ 36.430053] worker_thread+0x4a2/0x890 [ 36.431297] ? worker_clr_flags+0x90/0x90 [ 36.432479] kthread+0x166/0x190 [ 36.433493] ? kthread_blkcg+0x50/0x50 [ 36.434669] ret_from_fork+0x22/0x30 [ 36.435923] [ 36.436684] [ 36.437215] Allocated by task 24: [ 36.438289] kasan_set_track+0x50/0x80 [ 36.439436] __kasan_kmalloc+0x89/0xa0 [ 36.440566] smsusb_probe+0x374/0xc90 [ 36.441920] usb_probe_interface+0x2d1/0x4c0 [ 36.443253] really_probe+0x1d5/0x580 [ 36.444539] __driver_probe_device+0xe3/0x130 [ 36.446085] driver_probe_device+0x49/0x220 [ 36.447423] __device_attach_driver+0x19e/0x1b0 [ 36.448931] bus_for_each_drv+0xcb/0x110 [ 36.450217] __device_attach+0x132/0x1f0 [ 36.451470] bus_probe_device+0x59/0xf0 [ 36.452563] device_add+0x4ec/0x7b0 [ 36.453830] usb_set_configuration+0xc63/0xe10 [ 36.455230] usb_generic_driver_probe+0x3b/0x80 [ 36.456166] printk: console [ttyGS0] disabled [ 36.456569] usb_probe_device+0x90/0x110 [ 36.459523] really_probe+0x1d5/0x580 [ 36.461027] __driver_probe_device+0xe3/0x130 [ 36.462465] driver_probe_device+0x49/0x220 [ 36.463847] __device_attach_driver+0x19e/0x1b0 [ 36.465229] bus_for_each_drv+0xcb/0x110 [ 36.466466] __device_attach+0x132/0x1f0 [ 36.467799] bus_probe_device+0x59/0xf0 [ 36.469010] device_add+0x4ec/0x7b0 [ 36.470125] usb_new_device+0x863/0xa00 [ 36.471374] hub_event+0x18c7/0x2220 [ 36.472746] process_one_work+0x34c/0x5b0 [ 36.474041] worker_thread+0x4b7/0x890 [ 36.475216] kthread+0x166/0x190 [ 36.476267] ret_from_fork+0x22/0x30 [ 36.477447] [ 36.478160] Freed by task 24: [ 36.479239] kasan_set_track+0x50/0x80 [ 36.480512] kasan_save_free_info+0x2b/0x40 [ 36.481808] ____kasan_slab_free+0x122/0x1a0 [ 36.483173] __kmem_cache_free+0xc4/0x200 [ 36.484563] smsusb_term_device+0xcd/0xf0 [ 36.485896] smsusb_probe+0xc85/0xc90 [ 36.486976] usb_probe_interface+0x2d1/0x4c0 [ 36.488303] really_probe+0x1d5/0x580 [ 36.489498] __driver_probe_device+0xe3/0x130 [ 36.491140] driver_probe_device+0x49/0x220 [ 36.492475] __device_attach_driver+0x19e/0x1b0 [ 36.493988] bus_for_each_drv+0xcb/0x110 [ 36.495171] __device_attach+0x132/0x1f0 [ 36.496617] bus_probe_device+0x59/0xf0 [ 36.497875] device_add+0x4ec/0x7b0 [ 36.498972] usb_set_configuration+0xc63/0xe10 [ 36.500264] usb_generic_driver_probe+0x3b/0x80 [ 36.501740] usb_probe_device+0x90/0x110 [ 36.503084] really_probe+0x1d5/0x580 [ 36.504241] __driver_probe_device+0xe3/0x130 [ 36.505548] driver_probe_device+0x49/0x220 [ 36.506766] __device_attach_driver+0x19e/0x1b0 [ 36.508368] bus_for_each_drv+0xcb/0x110 [ 36.509646] __device_attach+0x132/0x1f0 [ 36.510911] bus_probe_device+0x59/0xf0 [ 36.512103] device_add+0x4ec/0x7b0 [ 36.513215] usb_new_device+0x863/0xa00 [ 36.514736] hub_event+0x18c7/0x2220 [ 36.516130] process_one_work+0x34c/0x5b0 [ 36.517396] worker_thread+0x4b7/0x890 [ 36.518591] kthread+0x166/0x190 [ 36.519599] ret_from_fork+0x22/0x30 [ 36.520851] [ 36.521405] Last potentially related work creation: [ 36.523143] kasan_save_stack+0x3f/0x60 [ 36.524275] kasan_record_aux_stack_noalloc+0x9d/0xb0 [ 36.525831] insert_work+0x25/0x130 [ 36.527039] __queue_work+0x4d4/0x620 [ 36.528236] queue_work_on+0x72/0xb0 [ 36.529344] __usb_hcd_giveback_urb+0x13f/0x1b0 [ 36.530819] dummy_timer+0x350/0x1a40 [ 36.532149] call_timer_fn+0x2c/0x190 [ 36.533567] expire_timers+0x69/0x1f0 [ 36.534736] __run_timers+0x289/0x2d0 [ 36.535841] run_timer_softirq+0x2d/0x60 [ 36.537110] __do_softirq+0x116/0x380 [ 36.538377] [ 36.538950] Second to last potentially related work creation: [ 36.540855] kasan_save_stack+0x3f/0x60 [ 36.542084] kasan_record_aux_stack_noalloc+0x9d/0xb0 [ 36.543592] insert_work+0x25/0x130 [ 36.544891] __queue_work+0x4d4/0x620 [ 36.546168] queue_work_on+0x72/0xb0 [ 36.547328] __usb_hcd_giveback_urb+0x13f/0x1b0 [ 36.548805] dummy_timer+0x350/0x1a40 [ 36.550116] call_timer_fn+0x2c/0x190 [ 36.551570] expire_timers+0x69/0x1f0 [ 36.552762] __run_timers+0x289/0x2d0 [ 36.553916] run_timer_softirq+0x2d/0x60 [ 36.555118] __do_softirq+0x116/0x380 [ 36.556239] [ 36.556807] The buggy address belongs to the object at ffff888005960000 [ 36.556807] which belongs to the cache kmalloc-4k of size 4096 [ 36.560652] The buggy address is located 232 bytes inside of [ 36.560652] 4096-byte region [ffff888005960000, ffff888005961000) [ 36.564791] [ 36.565355] The buggy address belongs to the physical page: [ 36.567212] page:000000004f0a0731 refcount:1 mapcount:0 mapping:0000000000000000 index:0x00 [ 36.570534] head:000000004f0a0731 order:3 compound_mapcount:0 subpages_mapcount:0 compound0 [ 36.573717] flags: 0x100000000010200(slab|head|node=0|zone=1) [ 36.575481] raw: 0100000000010200 ffff888001042140 dead000000000122 0000000000000000 [ 36.577842] raw: 0000000000000000 0000000000040004 00000001ffffffff 0000000000000000 [ 36.580175] page dumped because: kasan: bad access detected [ 36.581994] [ 36.582548] Memory state around the buggy address: [ 36.583983] ffff88800595ff80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 36.586240] ffff888005960000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 36.588884] >ffff888005960080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 36.591071] ^ [ 36.593295] ffff888005960100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 36.595705] ffff888005960180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 36.598026] ================================================================== [ 36.600224] Disabling lock debugging due to kernel taint [ 36.602681] general protection fault, probably for non-canonical address 0x43600a000000060I [ 36.607129] CPU: 0 PID: 49 Comm: kworker/0:2 Tainted: G B 6.2.0-rc3-15798-8 [ 36.611115] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g15584 [ 36.615026] Workqueue: events do_submit_urb [ 36.616290] RIP: 0010:_raw_spin_lock_irqsave+0x8a/0xd0 [ 36.618107] Code: 24 00 00 00 00 48 89 df be 04 00 00 00 e8 9e b5 c6 fe 48 89 ef be 04 00 5 [ 36.623522] RSP: 0018:ffff888004b6fcf0 EFLAGS: 00010046 [ 36.625072] RAX: 0000000000000000 RBX: 043600a000000060 RCX: ffffffff9fc0e0d7 [ 36.627206] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff888004b6fcf0 [ 36.629813] RBP: ffff888004b6fcf0 R08: dffffc0000000000 R09: ffffed100096df9f [ 36.631974] R10: dfffe9100096dfa0 R11: 1ffff1100096df9e R12: ffff888005960020 [ 36.634285] R13: ffff8880059600f0 R14: 0000000000000246 R15: 0000000000000001 [ 36.636438] FS: 0000000000000000(0000) GS:ffff88806d600000(0000) knlGS:0000000000000000 [ 36.639092] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 36.640951] CR2: 00007f07476819a3 CR3: 0000000004a34000 CR4: 00000000000006f0 [ 36.643411] Call Trace: [ 36.644215] [ 36.644902] smscore_getbuffer+0x3e/0x1e0 [ 36.646147] do_submit_urb+0x4f/0x190 [ 36.647449] process_one_work+0x34c/0x5b0 [ 36.648777] worker_thread+0x4b7/0x890 [ 36.649984] ? worker_clr_flags+0x90/0x90 [ 36.651166] kthread+0x166/0x190 [ 36.652151] ? kthread_blkcg+0x50/0x50 [ 36.653547] ret_from_fork+0x22/0x30 [ 36.655051] [ 36.655733] Modules linked in: [ 36.656787] ---[ end trace 0000000000000000 ]--- [ 36.658328] RIP: 0010:_raw_spin_lock_irqsave+0x8a/0xd0 [ 36.660045] Code: 24 00 00 00 00 48 89 df be 04 00 00 00 e8 9e b5 c6 fe 48 89 ef be 04 00 5 [ 36.665730] RSP: 0018:ffff888004b6fcf0 EFLAGS: 00010046 [ 36.667448] RAX: 0000000000000000 RBX: 043600a000000060 RCX: ffffffff9fc0e0d7 [ 36.669675] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff888004b6fcf0 [ 36.672645] RBP: ffff888004b6fcf0 R08: dffffc0000000000 R09: ffffed100096df9f [ 36.674921] R10: dfffe9100096dfa0 R11: 1ffff1100096df9e R12: ffff888005960020 [ 36.677034] R13: ffff8880059600f0 R14: 0000000000000246 R15: 0000000000000001 [ 36.679184] FS: 0000000000000000(0000) GS:ffff88806d600000(0000) knlGS:0000000000000000 [ 36.681655] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 36.683383] CR2: 00007f07476819a3 CR3: 0000000004a34000 CR4: 00000000000006f0 [ 36.685733] Kernel panic - not syncing: Fatal exception [ 36.688585] Kernel Offset: 0x1d400000 from 0xffffffff81000000 (relocation range: 0xfffffff) [ 36.692199] ---[ end Kernel panic - not syncing: Fatal exception ]--- When the siano device is plugged in, it may call the following functions to initialize the device. smsusb_probe()-->smsusb_init_device()-->smscore_start_device(). When smscore_start_device() gets failed, the function smsusb_term_device() will be called and smsusb_device_t will be deallocated. Although we use usb_kill_urb() in smsusb_stop_streaming() to cancel transfer requests and wait for them to finish, the worker threads that are scheduled by smsusb_onresponse() may be still running. As a result, the UAF bugs could happen. We add cancel_work_sync() in smsusb_stop_streaming() in order that the worker threads could finish before the smsusb_device_t is deallocated. Fixes: dd47fbd40e6e ("[media] smsusb: don't sleep while atomic") Signed-off-by: Duoming Zhou Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/siano/smsusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index fe9c7b3a950e..6f443c542c6d 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -179,6 +179,7 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev) for (i = 0; i < MAX_URBS; i++) { usb_kill_urb(&dev->surbs[i].urb); + cancel_work_sync(&dev->surbs[i].wq); if (dev->surbs[i].cb) { smscore_putbuffer(dev->coredev, dev->surbs[i].cb); From 4ab3f69cba785988b7cb386e35e661bfa1aa0706 Mon Sep 17 00:00:00 2001 From: Benjamin Roszak Date: Mon, 23 Jan 2023 08:17:08 +0100 Subject: [PATCH 183/216] media: meson: vdec: remove redundant if statement Checking if sess->fmt_out->pixfmt is V4L2_PIX_FMT_VP9 was already done as a condition to enter the if statement where this additional check is made. Signed-off-by: Benjamin Roszak Signed-off-by: Christian Hewitt Acked-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/esparser.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c index 86ccc8937afc..7b15fc54efe4 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -314,8 +314,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) num_dst_bufs = codec_ops->num_pending_bufs(sess); num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); - if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) - num_dst_bufs -= 3; + num_dst_bufs -= 3; if (esparser_vififo_get_free_space(sess) < payload_size || atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) From 7a46e2b923939b03735720616743a70fe6917c2d Mon Sep 17 00:00:00 2001 From: Brent Pappas Date: Mon, 23 Jan 2023 20:17:14 +0100 Subject: [PATCH 184/216] media: imx: imx-media-fim: Replace macro icap_enabled() with function Replace the macro icap_enabled() with a static function to comply with Linux coding style standards. Signed-off-by: Brent Pappas Reviewed-by: Marco Felsch Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-fim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c index f456751f100a..e28a33d9dec7 100644 --- a/drivers/staging/media/imx/imx-media-fim.c +++ b/drivers/staging/media/imx/imx-media-fim.c @@ -68,7 +68,10 @@ struct imx_media_fim { bool stream_on; }; -#define icap_enabled(fim) ((fim)->icap_flags != IRQ_TYPE_NONE) +static bool icap_enabled(struct imx_media_fim *fim) +{ + return fim->icap_flags != IRQ_TYPE_NONE; +} static void update_fim_nominal(struct imx_media_fim *fim, const struct v4l2_fract *fi) From bc7635c6435c77a0c168e2cc6535740adfaff4e4 Mon Sep 17 00:00:00 2001 From: Tasos Sahanidis Date: Thu, 26 Jan 2023 12:00:59 +0100 Subject: [PATCH 185/216] media: saa7134: Use video_unregister_device for radio_dev The radio device doesn't use vb2, thus calling vb2_video_unregister_device() which results in the following warning being printed on module unload. WARNING: CPU: 1 PID: 215963 at drivers/media/common/videobuf2/videobuf2-v4l2.c:1236 vb2_video_unregister_device+0xc6/0xe0 [videobuf2_v4l2] Fixes: 11788d9b7e91 ("media: media/pci: use vb2_video_unregister_device()") Signed-off-by: Tasos Sahanidis Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 96328b0af164..cf2871306987 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -978,7 +978,7 @@ static void saa7134_unregister_video(struct saa7134_dev *dev) } if (dev->radio_dev) { if (video_is_registered(dev->radio_dev)) - vb2_video_unregister_device(dev->radio_dev); + video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; From 02240a2764f8381f74b3a25742d6d3fd11fa2144 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 186/216] media: imx: imx7-media-csi: Drop imx7_csi.cc field The imx7_csi.cc field is set but never used. Drop it. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 1ef92c8c0098..f1d7da7763d5 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -228,7 +228,6 @@ struct imx7_csi { struct media_pad pad[IMX7_CSI_PADS_NUM]; struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM]; - const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM]; /* Video device */ struct video_device *vdev; /* Video device */ @@ -1807,8 +1806,6 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace); mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv, mf->colorspace, mf->ycbcr_enc); - - csi->cc[i] = cc; } return 0; @@ -2016,14 +2013,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC, sdformat->which); *outfmt = format.format; - - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->cc[IMX7_CSI_PAD_SRC] = outcc; } - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->cc[sdformat->pad] = cc; - out_unlock: mutex_unlock(&csi->lock); From bc0d3df31ffe87d3162710adc5a6ad0f3744b066 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 187/216] media: imx: imx7-media-csi: Simplify imx7_csi_video_init_format() The imx7_csi_video_init_format() function instantiates a v4l2_subdev_format on the stack, to only use the .format field of that structure. Replace it with a v4l2_mbus_framefmt instance. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index f1d7da7763d5..112af7279ccf 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1600,17 +1600,15 @@ static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi) static int imx7_csi_video_init_format(struct imx7_csi *csi) { - struct v4l2_subdev_format fmt_src = { - .pad = IMX7_CSI_PAD_SRC, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE; - fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH; - fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT; + struct v4l2_mbus_framefmt format = { }; - imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL); - csi->vdev_compose.width = fmt_src.format.width; - csi->vdev_compose.height = fmt_src.format.height; + format.code = IMX7_CSI_DEF_MBUS_CODE; + format.width = IMX7_CSI_DEF_PIX_WIDTH; + format.height = IMX7_CSI_DEF_PIX_HEIGHT; + + imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &format, NULL); + csi->vdev_compose.width = format.width; + csi->vdev_compose.height = format.height; csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat); From db56a4fb6923a37b437a9806189d13c89c38448b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 188/216] media: imx: imx7-media-csi: Drop unneeded check when starting streaming The .s_stream() operation is guaranteed not to be called to start/stop an already started/stopped subdev. Remove the unneeded check. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 112af7279ccf..45b29d312276 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1736,9 +1736,6 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) goto out_unlock; } - if (csi->is_streaming == !!enable) - goto out_unlock; - if (enable) { ret = imx7_csi_init(csi); if (ret < 0) From 8ccfc15380e95e0219c42bc4bb3498d2bdb2cfb6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 189/216] media: imx: imx7-media-csi: Drop unneeded src_sd check The .s_stream() and .link_validate() operations can't be called with a NULL src_sd, as subdev nodes are not registered before the async notifier completes. Remove the unneeded checks. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 45b29d312276..62232cd6775f 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1731,11 +1731,6 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&csi->lock); - if (!csi->src_sd) { - ret = -EPIPE; - goto out_unlock; - } - if (enable) { ret = imx7_csi_init(csi); if (ret < 0) @@ -2026,9 +2021,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, unsigned int i; int ret; - if (!csi->src_sd) - return -EPIPE; - /* * Validate the source link, and record whether the source uses the * parallel input or the CSI-2 receiver. From 49a82584b87c385b267f4ca12674f08bd229ab57 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 190/216] media: imx: imx7-media-csi: Drop unneeded pad checks The subdev core guarantees that the .set_fmt() operation is always called with a valid pad. Drop the unneeded pad checks. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 62232cd6775f..1adf5c3392d9 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1936,6 +1936,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, sdformat->format.quantization = in_fmt->quantization; sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; break; + case IMX7_CSI_PAD_SINK: *cc = imx7_csi_find_mbus_format(sdformat->format.code); if (!*cc) { @@ -1947,8 +1948,6 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, if (sdformat->format.field != V4L2_FIELD_INTERLACED) sdformat->format.field = V4L2_FIELD_NONE; break; - default: - return -EINVAL; } imx7_csi_try_colorimetry(&sdformat->format); @@ -1968,9 +1967,6 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format format; int ret = 0; - if (sdformat->pad >= IMX7_CSI_PADS_NUM) - return -EINVAL; - mutex_lock(&csi->lock); if (csi->is_streaming) { From 2c117550d70578b0b9eb183807b0984c11ecb44b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 27 Jan 2023 02:21:57 +0100 Subject: [PATCH 191/216] media: imx: imx7-media-csi: Cleanup errors in imx7_csi_async_register() It's good practice for functions to perform error cleanup internally when they fail, in order to not leave the device in a half-initialized state. Move the async notifier cleanup from the probe error path to the imx7_csi_async_register(), and drop the v4l2_async_nf_unregister() call as there is no error path after the async notifier gets registered. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 1adf5c3392d9..733e44700ff9 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -2177,7 +2177,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi) ret = PTR_ERR(asd); /* OK if asd already exists */ if (ret != -EEXIST) - return ret; + goto error; } } @@ -2185,9 +2185,13 @@ static int imx7_csi_async_register(struct imx7_csi *csi) ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); if (ret) - return ret; + goto error; return 0; + +error: + v4l2_async_nf_cleanup(&csi->notifier); + return ret; } static void imx7_csi_media_cleanup(struct imx7_csi *csi) @@ -2329,13 +2333,10 @@ static int imx7_csi_probe(struct platform_device *pdev) ret = imx7_csi_async_register(csi); if (ret) - goto subdev_notifier_cleanup; + goto media_cleanup; return 0; -subdev_notifier_cleanup: - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); media_cleanup: imx7_csi_media_cleanup(csi); From d01a1c30777e46bad5e87d60bf149f647064dec5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 192/216] media: imx: imx7-media-csi: Zero format struct before calling .get_fmt() The v4l2_subdev_format structure passed to the .get_fmt() subdev operation in imx7_csi_video_validate_fmt() isn't zeroed, which can cause undefined behaviour. Fix it. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 733e44700ff9..943e541768bd 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1412,13 +1412,14 @@ static void imx7_csi_video_buf_queue(struct vb2_buffer *vb) static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) { - struct v4l2_subdev_format fmt_src; + struct v4l2_subdev_format fmt_src = { + .pad = IMX7_CSI_PAD_SRC, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; const struct imx7_csi_pixfmt *cc; int ret; /* Retrieve the media bus format on the source subdev. */ - fmt_src.pad = IMX7_CSI_PAD_SRC; - fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src); if (ret) return ret; From 1d59fbeb37a70f36ba3f03e41128515eee59f5fb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 193/216] media: imx: imx7-media-csi: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format. This simplifies the driver not only by dropping the state stored in the imx7_csi structure, but also by replacing the manual lock with the state lock. The is_streaming field is now protected by the active state lock, either explicitly in .s_stream(), where the active state is locked manually, or implicitly in .set_fmt(), which is called with the state locked. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mm-beacon-kit Acked-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx7-media-csi.c | 173 ++++++-------------- 1 file changed, 51 insertions(+), 122 deletions(-) diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 943e541768bd..c22bf5c827e7 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -211,7 +211,6 @@ struct imx7_csi { int irq; struct clk *mclk; - struct mutex lock; /* Protects is_streaming, format_mbus, cc */ spinlock_t irqlock; /* Protects last_eof */ /* Media and V4L2 device */ @@ -227,8 +226,6 @@ struct imx7_csi { struct v4l2_subdev sd; struct media_pad pad[IMX7_CSI_PADS_NUM]; - struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM]; - /* Video device */ struct video_device *vdev; /* Video device */ struct media_pad vdev_pad; /* Video device pad */ @@ -509,7 +506,8 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi) imx7_csi_hw_disable_irq(csi); } -static void imx7_csi_configure(struct imx7_csi *csi) +static void imx7_csi_configure(struct imx7_csi *csi, + struct v4l2_subdev_state *sd_state) { struct v4l2_pix_format *out_pix = &csi->vdev_fmt; int width = out_pix->width; @@ -540,12 +538,17 @@ static void imx7_csi_configure(struct imx7_csi *csi) out_pix->pixelformat == V4L2_PIX_FMT_YUYV) width *= 2; } else { + const struct v4l2_mbus_framefmt *sink_fmt; + + sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state, + IMX7_CSI_PAD_SINK); + cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC | BIT_MCLKDIV(1) | BIT_MCLKEN; cr18 |= BIT_DATA_FROM_MIPI; - switch (csi->format_mbus[IMX7_CSI_PAD_SINK].code) { + switch (sink_fmt->code) { case MEDIA_BUS_FMT_Y8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -626,7 +629,8 @@ static void imx7_csi_configure(struct imx7_csi *csi) imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA); } -static int imx7_csi_init(struct imx7_csi *csi) +static int imx7_csi_init(struct imx7_csi *csi, + struct v4l2_subdev_state *sd_state) { int ret; @@ -634,7 +638,7 @@ static int imx7_csi_init(struct imx7_csi *csi) if (ret < 0) return ret; - imx7_csi_configure(csi); + imx7_csi_configure(csi, sd_state); ret = imx7_csi_dma_setup(csi); if (ret < 0) { @@ -1420,7 +1424,7 @@ static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) int ret; /* Retrieve the media bus format on the source subdev. */ - ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src); + ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src); if (ret) return ret; @@ -1728,12 +1732,13 @@ static int imx7_csi_video_init(struct imx7_csi *csi) static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); + struct v4l2_subdev_state *sd_state; int ret = 0; - mutex_lock(&csi->lock); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); if (enable) { - ret = imx7_csi_init(csi); + ret = imx7_csi_init(csi, sd_state); if (ret < 0) goto out_unlock; @@ -1755,29 +1760,14 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) csi->is_streaming = !!enable; out_unlock: - mutex_unlock(&csi->lock); + v4l2_subdev_unlock_state(sd_state); return ret; } -static struct v4l2_mbus_framefmt * -imx7_csi_get_format(struct imx7_csi *csi, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); - - return &csi->format_mbus[pad]; -} - static int imx7_csi_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { - const enum v4l2_subdev_format_whence which = - sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - struct imx7_csi *csi = v4l2_get_subdevdata(sd); const struct imx7_csi_pixfmt *cc; int i; @@ -1785,7 +1775,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { struct v4l2_mbus_framefmt *mf = - imx7_csi_get_format(csi, sd_state, i, which); + v4l2_subdev_get_pad_format(sd, sd_state, i); mf->code = IMX7_CSI_DEF_MBUS_CODE; mf->width = IMX7_CSI_DEF_PIX_WIDTH; @@ -1806,59 +1796,30 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct imx7_csi *csi = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *in_fmt; int ret = 0; - mutex_lock(&csi->lock); - - in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, - code->which); + in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); switch (code->pad) { case IMX7_CSI_PAD_SINK: ret = imx7_csi_enum_mbus_formats(&code->code, code->index); break; + case IMX7_CSI_PAD_SRC: if (code->index != 0) { ret = -EINVAL; - goto out_unlock; + break; } code->code = in_fmt->code; break; + default: ret = -EINVAL; + break; } -out_unlock: - mutex_unlock(&csi->lock); - - return ret; -} - -static int imx7_csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *fmt; - int ret = 0; - - mutex_lock(&csi->lock); - - fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, - sdformat->which); - if (!fmt) { - ret = -EINVAL; - goto out_unlock; - } - - sdformat->format = *fmt; - -out_unlock: - mutex_unlock(&csi->lock); - return ret; } @@ -1908,19 +1869,16 @@ static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt) tryfmt->ycbcr_enc); } -static int imx7_csi_try_fmt(struct imx7_csi *csi, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat, - const struct imx7_csi_pixfmt **cc) +static void imx7_csi_try_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat, + const struct imx7_csi_pixfmt **cc) { const struct imx7_csi_pixfmt *in_cc; struct v4l2_mbus_framefmt *in_fmt; u32 code; - in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, - sdformat->which); - if (!in_fmt) - return -EINVAL; + in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); switch (sdformat->pad) { case IMX7_CSI_PAD_SRC: @@ -1952,8 +1910,6 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, } imx7_csi_try_colorimetry(&sdformat->format); - - return 0; } static int imx7_csi_set_fmt(struct v4l2_subdev *sd, @@ -1966,25 +1922,13 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, const struct imx7_csi_pixfmt *cc; struct v4l2_mbus_framefmt *fmt; struct v4l2_subdev_format format; - int ret = 0; - mutex_lock(&csi->lock); + if (csi->is_streaming) + return -EBUSY; - if (csi->is_streaming) { - ret = -EBUSY; - goto out_unlock; - } + imx7_csi_try_fmt(sd, sd_state, sdformat, &cc); - ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc); - if (ret < 0) - goto out_unlock; - - fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, - sdformat->which); - if (!fmt) { - ret = -EINVAL; - goto out_unlock; - } + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); *fmt = sdformat->format; @@ -1993,19 +1937,14 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, format.pad = IMX7_CSI_PAD_SRC; format.which = sdformat->which; format.format = sdformat->format; - if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) { - ret = -EINVAL; - goto out_unlock; - } - outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC, - sdformat->which); + imx7_csi_try_fmt(sd, sd_state, &format, &outcc); + + outfmt = v4l2_subdev_get_pad_format(sd, sd_state, + IMX7_CSI_PAD_SRC); *outfmt = format.format; } -out_unlock: - mutex_unlock(&csi->lock); - - return ret; + return 0; } static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, @@ -2105,7 +2044,7 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = { static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = { .init_cfg = imx7_csi_init_cfg, .enum_mbus_code = imx7_csi_enum_mbus_code, - .get_fmt = imx7_csi_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx7_csi_set_fmt, .link_validate = imx7_csi_pad_link_validate, }; @@ -2199,6 +2138,7 @@ static void imx7_csi_media_cleanup(struct imx7_csi *csi) { v4l2_device_unregister(&csi->v4l2_dev); media_device_unregister(&csi->mdev); + v4l2_subdev_cleanup(&csi->sd); media_device_cleanup(&csi->mdev); } @@ -2266,6 +2206,10 @@ static int imx7_csi_media_init(struct imx7_csi *csi) if (ret) goto error; + ret = v4l2_subdev_init_finalize(&csi->sd); + if (ret) + goto error; + ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd); if (ret) goto error; @@ -2291,27 +2235,22 @@ static int imx7_csi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, csi); spin_lock_init(&csi->irqlock); - mutex_init(&csi->lock); /* Acquire resources and install interrupt handler. */ csi->mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(csi->mclk)) { ret = PTR_ERR(csi->mclk); dev_err(dev, "Failed to get mclk: %d", ret); - goto destroy_mutex; + return ret; } csi->irq = platform_get_irq(pdev, 0); - if (csi->irq < 0) { - ret = csi->irq; - goto destroy_mutex; - } + if (csi->irq < 0) + return csi->irq; csi->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(csi->regbase)) { - ret = PTR_ERR(csi->regbase); - goto destroy_mutex; - } + if (IS_ERR(csi->regbase)) + return PTR_ERR(csi->regbase); csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); @@ -2319,31 +2258,23 @@ static int imx7_csi_probe(struct platform_device *pdev) (void *)csi); if (ret < 0) { dev_err(dev, "Request CSI IRQ failed.\n"); - goto destroy_mutex; + return ret; } /* Initialize all the media device infrastructure. */ ret = imx7_csi_media_init(csi); if (ret) - goto destroy_mutex; - - /* Set the default mbus formats. */ - ret = imx7_csi_init_cfg(&csi->sd, NULL); - if (ret) - goto media_cleanup; + return ret; ret = imx7_csi_async_register(csi); if (ret) - goto media_cleanup; + goto err_media_cleanup; return 0; -media_cleanup: +err_media_cleanup: imx7_csi_media_cleanup(csi); -destroy_mutex: - mutex_destroy(&csi->lock); - return ret; } @@ -2357,8 +2288,6 @@ static int imx7_csi_remove(struct platform_device *pdev) v4l2_async_nf_cleanup(&csi->notifier); v4l2_async_unregister_subdev(&csi->sd); - mutex_destroy(&csi->lock); - return 0; } From a42b43f7b6708428ce25239d5c245a18758f68c5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 20:29:53 +0100 Subject: [PATCH 194/216] media: imx-mipi-csis: Rename error labels with 'err_' prefix It is customary to prefix error labels with 'err_' to make their purpose clearer. Do so in the probe function. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mn-beacon Acked-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 905072871ed2..d949b2de8e74 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1496,20 +1496,20 @@ static int mipi_csis_probe(struct platform_device *pdev) dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); - goto disable_clock; + goto err_disable_clock; } /* Initialize and register the subdev. */ ret = mipi_csis_subdev_init(csis); if (ret < 0) - goto disable_clock; + goto err_disable_clock; platform_set_drvdata(pdev, &csis->sd); ret = mipi_csis_async_register(csis); if (ret < 0) { dev_err(dev, "async register failed: %d\n", ret); - goto cleanup; + goto err_cleanup; } /* Initialize debugfs. */ @@ -1520,7 +1520,7 @@ static int mipi_csis_probe(struct platform_device *pdev) if (!pm_runtime_enabled(dev)) { ret = mipi_csis_runtime_resume(dev); if (ret < 0) - goto unregister_all; + goto err_unregister_all; } dev_info(dev, "lanes: %d, freq: %u\n", @@ -1528,14 +1528,14 @@ static int mipi_csis_probe(struct platform_device *pdev) return 0; -unregister_all: +err_unregister_all: mipi_csis_debugfs_exit(csis); -cleanup: +err_cleanup: media_entity_cleanup(&csis->sd.entity); v4l2_async_nf_unregister(&csis->notifier); v4l2_async_nf_cleanup(&csis->notifier); v4l2_async_unregister_subdev(&csis->sd); -disable_clock: +err_disable_clock: mipi_csis_clk_disable(csis); fwnode_handle_put(csis->sd.fwnode); mutex_destroy(&csis->lock); From b6a736e79e473dfd6b6c97ea615d347c93dfb07a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 195/216] media: imx-mipi-csis: Don't take lock in runtime PM handlers The runtime PM handlers don't need manual locking as - they are serialized by the runtime PM core - they can't race with other functions taking the same lock, as they don't access any data protect by that lock Drop the locking. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mn-beacon Acked-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 28 +++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index d949b2de8e74..4e1363ff5646 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1348,40 +1348,34 @@ static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - int ret = 0; - - mutex_lock(&csis->lock); + int ret; ret = mipi_csis_phy_disable(csis); if (ret) - goto unlock; + return -EAGAIN; mipi_csis_clk_disable(csis); -unlock: - mutex_unlock(&csis->lock); - - return ret ? -EAGAIN : 0; + return 0; } static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - int ret = 0; - - mutex_lock(&csis->lock); + int ret; ret = mipi_csis_phy_enable(csis); if (ret) - goto unlock; + return -EAGAIN; - mipi_csis_clk_enable(csis); + ret = mipi_csis_clk_enable(csis); + if (ret) { + mipi_csis_phy_disable(csis); + return ret; + } -unlock: - mutex_unlock(&csis->lock); - - return ret ? -EAGAIN : 0; + return 0; } static const struct dev_pm_ops mipi_csis_pm_ops = { From 2f03d3cb06c677bc14fe5697e20aa4e1c9e51d97 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 196/216] media: imx-mipi-csis: Pass format explicitly to internal functions To prepare for usage of the subdev active state that will replace the csis_fmt and format_mbus fields stored in the mipi_csis_device structure, pass the format explicitly to the functions called when starting streaming to avoid accessing those two fields. Not functional change intended. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mn-beacon Acked-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 34 +++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 4e1363ff5646..38ed88646632 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -560,9 +560,10 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) } /* Called with the csis.lock mutex held */ -static void __mipi_csis_set_format(struct mipi_csis_device *csis) +static void __mipi_csis_set_format(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { - struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK]; u32 val; /* Color format */ @@ -583,25 +584,26 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis) * * TODO: Verify which other formats require DUAL (or QUAD) modes. */ - if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) + if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; - val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type); + val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ - val = mf->width | (mf->height << 16); + val = format->width | (format->height << 16); mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val); } -static int mipi_csis_calculate_params(struct mipi_csis_device *csis) +static int mipi_csis_calculate_params(struct mipi_csis_device *csis, + const struct csis_pix_format *csis_fmt) { s64 link_freq; u32 lane_rate; /* Calculate the line rate from the pixel rate. */ link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler, - csis->csis_fmt->width, + csis_fmt->width, csis->bus.num_data_lanes * 2); if (link_freq < 0) { dev_err(csis->dev, "Unable to obtain link frequency: %d\n", @@ -643,7 +645,9 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis) return 0; } -static void mipi_csis_set_params(struct mipi_csis_device *csis) +static void mipi_csis_set_params(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { int lanes = csis->bus.num_data_lanes; u32 val; @@ -655,7 +659,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis) val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - __mipi_csis_set_format(csis); + __mipi_csis_set_format(csis, format, csis_fmt); mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | @@ -728,10 +732,12 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis) return ret; } -static void mipi_csis_start_stream(struct mipi_csis_device *csis) +static void mipi_csis_start_stream(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { mipi_csis_sw_reset(csis); - mipi_csis_set_params(csis); + mipi_csis_set_params(csis, format, csis_fmt); mipi_csis_system_enable(csis, true); mipi_csis_enable_interrupts(csis, true); } @@ -935,6 +941,8 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev) static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); + const struct v4l2_mbus_framefmt *format = &csis->format_mbus[CSIS_PAD_SINK]; + const struct csis_pix_format *csis_fmt = csis->csis_fmt; int ret; if (!enable) { @@ -953,7 +961,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) return 0; } - ret = mipi_csis_calculate_params(csis); + ret = mipi_csis_calculate_params(csis, csis_fmt); if (ret < 0) return ret; @@ -965,7 +973,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&csis->lock); - mipi_csis_start_stream(csis); + mipi_csis_start_stream(csis, format, csis_fmt); ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); if (ret < 0) goto error; From 11927d0fd0d0e428ad19f65768b3abe316bff066 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 197/216] media: imx-mipi-csis: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format. This simplifies the driver not only by dropping the mipi_csis_device csis_fmt and format_mbus fields, but it also allows dropping the device lock, replaced with the state lock. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mn-beacon Acked-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 135 +++++++-------------- 1 file changed, 47 insertions(+), 88 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 38ed88646632..9e424cb1c4b1 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -327,10 +327,6 @@ struct mipi_csis_device { u32 hs_settle; u32 clk_settle; - struct mutex lock; /* Protect csis_fmt and format_mbus */ - const struct csis_pix_format *csis_fmt; - struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM]; - spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; struct dentry *debugfs_root; @@ -559,7 +555,6 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); } -/* Called with the csis.lock mutex held */ static void __mipi_csis_set_format(struct mipi_csis_device *csis, const struct v4l2_mbus_framefmt *format, const struct csis_pix_format *csis_fmt) @@ -941,79 +936,67 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev) static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - const struct v4l2_mbus_framefmt *format = &csis->format_mbus[CSIS_PAD_SINK]; - const struct csis_pix_format *csis_fmt = csis->csis_fmt; + const struct v4l2_mbus_framefmt *format; + const struct csis_pix_format *csis_fmt; + struct v4l2_subdev_state *state; int ret; if (!enable) { - mutex_lock(&csis->lock); - v4l2_subdev_call(csis->src_sd, video, s_stream, 0); mipi_csis_stop_stream(csis); if (csis->debug.enable) mipi_csis_log_counters(csis, true); - mutex_unlock(&csis->lock); - pm_runtime_put(csis->dev); return 0; } + state = v4l2_subdev_lock_and_get_active_state(sd); + + format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK); + csis_fmt = find_csis_format(format->code); + ret = mipi_csis_calculate_params(csis, csis_fmt); if (ret < 0) - return ret; + goto err_unlock; mipi_csis_clear_counters(csis); ret = pm_runtime_resume_and_get(csis->dev); if (ret < 0) - return ret; - - mutex_lock(&csis->lock); + goto err_unlock; mipi_csis_start_stream(csis, format, csis_fmt); + ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); if (ret < 0) - goto error; + goto err_stop; mipi_csis_log_counters(csis, true); - mutex_unlock(&csis->lock); + v4l2_subdev_unlock_state(state); return 0; -error: +err_stop: mipi_csis_stop_stream(csis); - mutex_unlock(&csis->lock); pm_runtime_put(csis->dev); +err_unlock: + v4l2_subdev_unlock_state(state); return ret; } -static struct v4l2_mbus_framefmt * -mipi_csis_get_format(struct mipi_csis_device *csis, - struct v4l2_subdev_state *sd_state, - enum v4l2_subdev_format_whence which, - unsigned int pad) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad); - - return &csis->format_mbus[pad]; -} - static int mipi_csis_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; - enum v4l2_subdev_format_whence which; - which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK); + fmt_sink = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SINK); + fmt_source = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE); fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; @@ -1027,36 +1010,15 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *sd, V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, fmt_sink->ycbcr_enc); - fmt_source = mipi_csis_get_format(csis, sd_state, which, - CSIS_PAD_SOURCE); *fmt_source = *fmt_sink; return 0; } -static int mipi_csis_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - struct v4l2_mbus_framefmt *fmt; - - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&csis->lock); - sdformat->format = *fmt; - mutex_unlock(&csis->lock); - - return 0; -} - static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - /* * The CSIS can't transcode in any way, the source format is identical * to the sink format. @@ -1067,8 +1029,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = mipi_csis_get_format(csis, sd_state, code->which, - code->pad); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad); code->code = fmt->code; return 0; } @@ -1088,7 +1049,6 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -1098,7 +1058,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, * modified. */ if (sdformat->pad == CSIS_PAD_SOURCE) - return mipi_csis_get_fmt(sd, sd_state, sdformat); + return v4l2_subdev_get_fmt(sd, sd_state, sdformat); if (sdformat->pad != CSIS_PAD_SINK) return -EINVAL; @@ -1136,10 +1096,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&csis->lock); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; @@ -1152,44 +1109,40 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - CSIS_PAD_SOURCE); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE); *fmt = sdformat->format; /* The format on the source pad might change due to unpacking. */ fmt->code = csis_fmt->output; - /* Store the CSIS format descriptor for active formats. */ - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csis->csis_fmt = csis_fmt; - - mutex_unlock(&csis->lock); - return 0; } static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0]; + const struct csis_pix_format *csis_fmt; + const struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; if (pad != CSIS_PAD_SOURCE) return -EINVAL; + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE); + csis_fmt = find_csis_format(fmt->code); + v4l2_subdev_unlock_state(state); + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; fd->num_entries = 1; memset(entry, 0, sizeof(*entry)); - mutex_lock(&csis->lock); - entry->flags = 0; - entry->pixelcode = csis->csis_fmt->code; + entry->pixelcode = csis_fmt->code; entry->bus.csi2.vc = 0; - entry->bus.csi2.dt = csis->csis_fmt->data_type; - - mutex_unlock(&csis->lock); + entry->bus.csi2.dt = csis_fmt->data_type; return 0; } @@ -1216,7 +1169,7 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { .init_cfg = mipi_csis_init_cfg, .enum_mbus_code = mipi_csis_enum_mbus_code, - .get_fmt = mipi_csis_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipi_csis_set_fmt, .get_frame_desc = mipi_csis_get_frame_desc, }; @@ -1398,6 +1351,7 @@ static const struct dev_pm_ops mipi_csis_pm_ops = { static int mipi_csis_subdev_init(struct mipi_csis_device *csis) { struct v4l2_subdev *sd = &csis->sd; + int ret; v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner = THIS_MODULE; @@ -1419,15 +1373,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis) return -ENOENT; } - csis->csis_fmt = &mipi_csis_formats[0]; - mipi_csis_init_cfg(sd, NULL); - csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, - csis->pads); + ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads); + if (ret) + return ret; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) { + media_entity_cleanup(&sd->entity); + return ret; + } + + return 0; } static int mipi_csis_parse_dt(struct mipi_csis_device *csis) @@ -1452,7 +1412,6 @@ static int mipi_csis_probe(struct platform_device *pdev) if (!csis) return -ENOMEM; - mutex_init(&csis->lock); spin_lock_init(&csis->slock); csis->dev = dev; @@ -1533,6 +1492,7 @@ static int mipi_csis_probe(struct platform_device *pdev) err_unregister_all: mipi_csis_debugfs_exit(csis); err_cleanup: + v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); v4l2_async_nf_unregister(&csis->notifier); v4l2_async_nf_cleanup(&csis->notifier); @@ -1540,7 +1500,6 @@ static int mipi_csis_probe(struct platform_device *pdev) err_disable_clock: mipi_csis_clk_disable(csis); fwnode_handle_put(csis->sd.fwnode); - mutex_destroy(&csis->lock); return ret; } @@ -1558,9 +1517,9 @@ static int mipi_csis_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); mipi_csis_runtime_suspend(&pdev->dev); mipi_csis_clk_disable(csis); + v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); fwnode_handle_put(csis->sd.fwnode); - mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); return 0; From 77645c6e3a1a3707e71732f6d5151c12e9110e37 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 02:10:01 +0100 Subject: [PATCH 198/216] media: imx-mipi-csis: Implement .init_cfg() using .set_fmt() The .set_fmt() handler is responsible for adjusting the requested format based on the device limitations. Implement .init_cfg() as a wrapper of .set_fmt(), to ensure that the initial configuration always matches the rules implemented in .set_fmt(), should they ever change. Signed-off-by: Laurent Pinchart Tested-by: Adam Ford #imx8mn-beacon Acked-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-mipi-csis.c | 48 ++++++++++------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 9e424cb1c4b1..e99633565463 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -989,32 +989,6 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int mipi_csis_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) -{ - struct v4l2_mbus_framefmt *fmt_sink; - struct v4l2_mbus_framefmt *fmt_source; - - fmt_sink = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SINK); - fmt_source = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE); - - fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; - fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT; - fmt_sink->field = V4L2_FIELD_NONE; - - fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); - fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); - fmt_sink->quantization = - V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, - fmt_sink->ycbcr_enc); - - *fmt_source = *fmt_sink; - - return 0; -} - static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -1101,6 +1075,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; fmt->height = sdformat->format.height; + fmt->field = V4L2_FIELD_NONE; fmt->colorspace = sdformat->format.colorspace; fmt->quantization = sdformat->format.quantization; fmt->xfer_func = sdformat->format.xfer_func; @@ -1147,6 +1122,27 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, return 0; } +static int mipi_csis_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { + .pad = CSIS_PAD_SINK, + }; + + fmt.format.code = mipi_csis_formats[0].code; + fmt.format.width = MIPI_CSIS_DEF_PIX_WIDTH; + fmt.format.height = MIPI_CSIS_DEF_PIX_HEIGHT; + + fmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt.format.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt.format.colorspace); + fmt.format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt.format.colorspace); + fmt.format.quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace, + fmt.format.ycbcr_enc); + + return mipi_csis_set_fmt(sd, sd_state, &fmt); +} + static int mipi_csis_log_status(struct v4l2_subdev *sd) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); From 3ac7165d7221421f7a44097f43ab7790e6f9432c Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Mon, 16 Jan 2023 12:38:56 +0100 Subject: [PATCH 199/216] media: dt-bindings: media: fsl-pxp: convert to yaml Convert the bindings of the Freescale Pixel Pipeline to YAML. The conversion drops the previously listed compatibles for several SoCs. It is unclear, if the PXP on these SoCs is compatible to any of the PXPs on the existing SoCs and would allow to reuse the already defined compatibles. The missing compatibles should be brought back when the support for the PXP on these SoCs is added. Reviewed-by: Philipp Zabel Signed-off-by: Michael Tretter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/fsl,imx6ull-pxp.yaml | 88 +++++++++++++++++++ .../devicetree/bindings/media/fsl-pxp.txt | 26 ------ 2 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml delete mode 100644 Documentation/devicetree/bindings/media/fsl-pxp.txt diff --git a/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml new file mode 100644 index 000000000000..84a5e894ace4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/fsl,imx6ull-pxp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Pixel Pipeline + +maintainers: + - Philipp Zabel + - Michael Tretter + +description: + The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine + that supports scaling, colorspace conversion, alpha blending, rotation, and + pixel conversion via lookup table. Different versions are present on various + i.MX SoCs from i.MX23 to i.MX7. + +properties: + compatible: + oneOf: + - enum: + - fsl,imx6ul-pxp + - fsl,imx6ull-pxp + - fsl,imx7d-pxp + - items: + - enum: + - fsl,imx6sll-pxp + - fsl,imx6sx-pxp + - const: fsl,imx6ull-pxp + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + clocks: + maxItems: 1 + + clock-names: + const: axi + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6sx-pxp + - fsl,imx6ul-pxp + then: + properties: + interrupts: + maxItems: 1 + else: + properties: + interrupts: + minItems: 2 + maxItems: 2 + +additionalProperties: false + +examples: + - | + #include + #include + + pxp: pxp@21cc000 { + compatible = "fsl,imx6ull-pxp"; + reg = <0x021cc000 0x4000>; + interrupts = , + ; + clock-names = "axi"; + clocks = <&clks IMX6UL_CLK_PXP>; + }; diff --git a/Documentation/devicetree/bindings/media/fsl-pxp.txt b/Documentation/devicetree/bindings/media/fsl-pxp.txt deleted file mode 100644 index f8090e06530d..000000000000 --- a/Documentation/devicetree/bindings/media/fsl-pxp.txt +++ /dev/null @@ -1,26 +0,0 @@ -Freescale Pixel Pipeline -======================== - -The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine -that supports scaling, colorspace conversion, alpha blending, rotation, and -pixel conversion via lookup table. Different versions are present on various -i.MX SoCs from i.MX23 to i.MX7. - -Required properties: -- compatible: should be "fsl,-pxp", where SoC can be one of imx23, imx28, - imx6dl, imx6sl, imx6sll, imx6ul, imx6sx, imx6ull, or imx7d. -- reg: the register base and size for the device registers -- interrupts: the PXP interrupt, two interrupts for imx6ull and imx7d. -- clock-names: should be "axi" -- clocks: the PXP AXI clock - -Example: - -pxp@21cc000 { - compatible = "fsl,imx6ull-pxp"; - reg = <0x021cc000 0x4000>; - interrupts = , - ; - clock-names = "axi"; - clocks = <&clks IMX6UL_CLK_PXP>; -}; From a4a69d1386765102640a45002bff6f7db704486d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:08 +0100 Subject: [PATCH 200/216] media: imx-pxp: detect PXP version Different versions of the Pixel Pipeline have different blocks and their routing may be different. Read the PXP_HW_VERSION register to determine the version of the PXP and print it to the log for debugging purposes. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 689ae5e6ac62..20fff1e7addc 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -10,6 +10,7 @@ * Pawel Osciak, * Marek Szyprowski, */ +#include #include #include #include @@ -52,6 +53,11 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define MEM2MEM_HFLIP (1 << 0) #define MEM2MEM_VFLIP (1 << 1) +#define PXP_VERSION_MAJOR(version) \ + FIELD_GET(BM_PXP_VERSION_MAJOR, version) +#define PXP_VERSION_MINOR(version) \ + FIELD_GET(BM_PXP_VERSION_MINOR, version) + #define dprintk(dev, fmt, arg...) \ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) @@ -1664,6 +1670,7 @@ static int pxp_probe(struct platform_device *pdev) { struct pxp_dev *dev; struct video_device *vfd; + u32 hw_version; int irq; int ret; @@ -1705,6 +1712,10 @@ static int pxp_probe(struct platform_device *pdev) goto err_clk; } + hw_version = readl(dev->mmio + HW_PXP_VERSION); + dev_dbg(&pdev->dev, "PXP Version %u.%u\n", + PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version)); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) goto err_clk; From 9fb41a05837583e28a9e8d7d7e4802626dcbc32a Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:09 +0100 Subject: [PATCH 201/216] media: imx-pxp: extract helper function to setup data path The driver must configure the data path through the Pixel Pipeline. Currently, the driver is using a fixed setup, but once there are different pipeline configurations, it is helpful to have a dedicated function for determining the register value for the data path. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 62 +++++++++++++++++++--------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 20fff1e7addc..3e5b5f94b15c 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -724,6 +724,47 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) } } +static u32 pxp_data_path_ctrl0(struct pxp_ctx *ctx) +{ + u32 ctrl0; + + ctrl0 = 0; + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0); + + return ctrl0; +} + +static void pxp_set_data_path(struct pxp_ctx *ctx) +{ + struct pxp_dev *dev = ctx->dev; + u32 ctrl0; + u32 ctrl1; + + ctrl0 = pxp_data_path_ctrl0(ctx); + + ctrl1 = 0; + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1); + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1); + + writel(ctrl0, dev->mmio + HW_PXP_DATA_PATH_CTRL0); + writel(ctrl1, dev->mmio + HW_PXP_DATA_PATH_CTRL1); +} + static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, struct vb2_v4l2_buffer *out_vb) { @@ -910,26 +951,7 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, /* bypass LUT */ writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL); - writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)| - BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)| - BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0), - dev->mmio + HW_PXP_DATA_PATH_CTRL0); - writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) | - BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1), - dev->mmio + HW_PXP_DATA_PATH_CTRL1); + pxp_set_data_path(ctx); writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK); From 47956c921d6a3f6b07007374b6ca96b1675f6114 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:10 +0100 Subject: [PATCH 202/216] media: imx-pxp: explicitly disable unused blocks Various multiplexers in the pipeline are not used with the currently configured data path. Disable all unused multiplexers by selecting the "no output" (3) option. The datasheet doesn't explicitly require this, but the PXP has been seen to hang after processing a few hundreds of frames otherwise. As at it, add documentation for the multiplexers that are actually relevant for the data path. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 30 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 3e5b5f94b15c..094a4f7c5fdf 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -729,22 +729,28 @@ static u32 pxp_data_path_ctrl0(struct pxp_ctx *ctx) u32 ctrl0; ctrl0 = 0; - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3); + /* Bypass Dithering x3CH */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3); + /* Select Rotation */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0); + /* Select LUT */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3); + /* Select MUX8 for LUT */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1); + /* Select CSC 2 */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3); + /* Bypass Rotation 2 */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0); - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3); return ctrl0; } @@ -758,8 +764,8 @@ static void pxp_set_data_path(struct pxp_ctx *ctx) ctrl0 = pxp_data_path_ctrl0(ctx); ctrl1 = 0; - ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1); - ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1); + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3); + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3); writel(ctrl0, dev->mmio + HW_PXP_DATA_PATH_CTRL0); writel(ctrl1, dev->mmio + HW_PXP_DATA_PATH_CTRL1); From fb2e9aa84243db9f2707e4cf257d95a13f9fce23 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:11 +0100 Subject: [PATCH 203/216] media: imx-pxp: disable LUT block The LUT block is always configured in bypass mode. Take it entirely out of the pipeline by disabling it and routing the data path around the LUT. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 094a4f7c5fdf..038abcd97d33 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -735,11 +735,10 @@ static u32 pxp_data_path_ctrl0(struct pxp_ctx *ctx) ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3); /* Select Rotation */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0); - /* Select LUT */ - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0); + /* Bypass LUT */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1); ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3); - /* Select MUX8 for LUT */ - ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3); /* Select CSC 2 */ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3); @@ -964,7 +963,7 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, /* ungate, enable PS/AS/OUT and PXP operation */ writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET); writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 | - BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 | + BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET); return 0; From 76985f4e8d34e0c20f2cde6017914ab9ce49aa17 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:12 +0100 Subject: [PATCH 204/216] media: imx-pxp: make data_path_ctrl0 platform dependent Unfortunately, the PXP_HW_VERSION register reports the PXP on the i.MX7D and on the i.MX6ULL as version 3.0, although the PXP versions on these SoCs have significant differences. Use the compatible to configure the ctrl0 register as required dependent on the platform. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 038abcd97d33..c38c199febd5 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -191,6 +192,12 @@ static struct pxp_fmt *find_format(struct v4l2_format *f) return &formats[k]; } +struct pxp_ctx; + +struct pxp_pdata { + u32 (*data_path_ctrl0)(struct pxp_ctx *ctx); +}; + struct pxp_dev { struct v4l2_device v4l2_dev; struct video_device vfd; @@ -198,6 +205,8 @@ struct pxp_dev { struct clk *clk; void __iomem *mmio; + const struct pxp_pdata *pdata; + atomic_t num_inst; struct mutex dev_mutex; spinlock_t irqlock; @@ -724,7 +733,7 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) } } -static u32 pxp_data_path_ctrl0(struct pxp_ctx *ctx) +static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx) { u32 ctrl0; @@ -760,7 +769,7 @@ static void pxp_set_data_path(struct pxp_ctx *ctx) u32 ctrl0; u32 ctrl1; - ctrl0 = pxp_data_path_ctrl0(ctx); + ctrl0 = dev->pdata->data_path_ctrl0(ctx); ctrl1 = 0; ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3); @@ -1705,6 +1714,8 @@ static int pxp_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; + dev->pdata = of_device_get_match_data(&pdev->dev); + dev->clk = devm_clk_get(&pdev->dev, "axi"); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); @@ -1804,8 +1815,12 @@ static int pxp_remove(struct platform_device *pdev) return 0; } +static const struct pxp_pdata pxp_imx6ull_pdata = { + .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0, +}; + static const struct of_device_id pxp_dt_ids[] = { - { .compatible = "fsl,imx6ull-pxp", .data = NULL }, + { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata }, { }, }; MODULE_DEVICE_TABLE(of, pxp_dt_ids); From cbcd23735726d544380b0a4fe1409950b4becf1c Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:13 +0100 Subject: [PATCH 205/216] media: imx-pxp: add support for i.MX7D The i.MX7D needs a different data path configuration than the i.MX6ULL. Configure the data path as close as possible to the data path on the i.MX6ULL. Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index c38c199febd5..cb242f3104c3 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -763,6 +763,37 @@ static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx) return ctrl0; } +static u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx) +{ + u32 ctrl0; + + ctrl0 = 0; + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3); + /* Select Rotation 0 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3); + /* Select MUX11 for Rotation 0 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1); + /* Bypass LUT */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3); + /* Select CSC 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3); + /* Select Composite Alpha Blending/Color Key 0 for CSC 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3); + /* Bypass Rotation 1 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3); + + return ctrl0; +} + static void pxp_set_data_path(struct pxp_ctx *ctx) { struct pxp_dev *dev = ctx->dev; @@ -1819,8 +1850,13 @@ static const struct pxp_pdata pxp_imx6ull_pdata = { .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0, }; +static const struct pxp_pdata pxp_imx7d_pdata = { + .data_path_ctrl0 = pxp_imx7d_data_path_ctrl0, +}; + static const struct of_device_id pxp_dt_ids[] = { { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata }, + { .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata }, { }, }; MODULE_DEVICE_TABLE(of, pxp_dt_ids); From 371ab9c41be7514c7699aea1ff221519fdb7d127 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:15 +0100 Subject: [PATCH 206/216] media: imx-pxp: Sort headers alphabetically Sorting headers alphabetically helps locating duplicates, and make it easier to figure out where to insert new headers. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index cb242f3104c3..964570ec19a9 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -20,15 +20,15 @@ #include #include #include +#include #include #include -#include -#include -#include -#include #include +#include #include +#include +#include #include #include "imx-pxp.h" From 15acb0824eca2871ea58d09db664422512677966 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:16 +0100 Subject: [PATCH 207/216] media: imx-pxp: Don't set bus_info manually in .querycap() The v4l2_capability.bus_info field is set by the V4L2 core when left empty by the .querycap() handler. This is the recommended practice, in order to ensure bus_info coherence between drivers. Don't set it manually. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 964570ec19a9..8881400f0f49 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1107,8 +1107,6 @@ static int pxp_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", MEM2MEM_NAME); return 0; } From ff89b9b425c86e91f8a840bf7e037302fb3ed7c1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:17 +0100 Subject: [PATCH 208/216] media: imx-pxp: Add media controller support Register a media device for the PXP, using the v4l2-mem2mem MC infrastructure to populate the media graph. No media device operation is implemented, the main use of the MC API is to allow consistent discovery of media devices for userspace. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 8881400f0f49..19efd65b60f2 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -201,6 +202,9 @@ struct pxp_pdata { struct pxp_dev { struct v4l2_device v4l2_dev; struct video_device vfd; +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device mdev; +#endif struct clk *clk; void __iomem *mmio; @@ -1815,8 +1819,34 @@ static int pxp_probe(struct platform_device *pdev) goto err_m2m; } +#ifdef CONFIG_MEDIA_CONTROLLER + dev->mdev.dev = &pdev->dev; + strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model)); + media_device_init(&dev->mdev); + dev->v4l2_dev.mdev = &dev->mdev; + + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize media device\n"); + goto err_vfd; + } + + ret = media_device_register(&dev->mdev); + if (ret) { + dev_err(&pdev->dev, "Failed to register media device\n"); + goto err_m2m_mc; + } +#endif + return 0; +#ifdef CONFIG_MEDIA_CONTROLLER +err_m2m_mc: + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +err_vfd: + video_unregister_device(vfd); +#endif err_m2m: v4l2_m2m_release(dev->m2m_dev); err_v4l2: @@ -1837,6 +1867,11 @@ static int pxp_remove(struct platform_device *pdev) clk_disable_unprepare(dev->clk); v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&dev->mdev); + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +#endif video_unregister_device(&dev->vfd); v4l2_m2m_release(dev->m2m_dev); v4l2_device_unregister(&dev->v4l2_dev); From 8b57a21a77d8e9fac7ad1a542395c4a562571752 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:18 +0100 Subject: [PATCH 209/216] media: imx-pxp: Pass pixel format value to find_format() The find_format() function looks up format information for a given pixel format. It takes a v4l2_format pointer, but only uses the contained pixel format value. To prepare it for being used by callers that don't have v4l2_format, modify it to take the pixel format value directly. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 19efd65b60f2..4738d7aaa2f7 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -176,14 +176,14 @@ enum { V4L2_M2M_DST = 1, }; -static struct pxp_fmt *find_format(struct v4l2_format *f) +static struct pxp_fmt *find_format(unsigned int pixelformat) { struct pxp_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { fmt = &formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) + if (fmt->fourcc == pixelformat) break; } @@ -1256,10 +1256,10 @@ static int pxp_try_fmt_vid_cap(struct file *file, void *priv, struct pxp_fmt *fmt; struct pxp_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_CAPTURE)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1284,10 +1284,10 @@ static int pxp_try_fmt_vid_out(struct file *file, void *priv, struct pxp_fmt *fmt; struct pxp_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_OUTPUT)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1320,7 +1320,7 @@ static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f) return -EBUSY; } - q_data->fmt = find_format(f); + q_data->fmt = find_format(f->fmt.pix.pixelformat); q_data->width = f->fmt.pix.width; q_data->height = f->fmt.pix.height; q_data->bytesperline = f->fmt.pix.bytesperline; From 8293b3ee2418754a1632123501c184e9559210ce Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:19 +0100 Subject: [PATCH 210/216] media: imx-pxp: Implement frame size enumeration Implement support for the VIDIOC_ENUM_FRAMESIZES ioctl. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 4738d7aaa2f7..a08e37b19213 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1379,6 +1379,26 @@ static int pxp_s_fmt_vid_out(struct file *file, void *priv, return 0; } +static int pxp_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (!find_format(fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.max_width = MAX_W; + fsize->stepwise.step_width = 1 << ALIGN_W; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_height = MAX_H; + fsize->stepwise.step_height = 1 << ALIGN_H; + + return 0; +} + static u8 pxp_degrees_to_rot_mode(u32 degrees) { switch (degrees) { @@ -1447,6 +1467,8 @@ static const struct v4l2_ioctl_ops pxp_ioctl_ops = { .vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out, .vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out, + .vidioc_enum_framesizes = pxp_enum_framesizes, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, From 36e5c36240cc94e0d00ad9b900e19479604b8965 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:20 +0100 Subject: [PATCH 211/216] media: imx-pxp: Introduce pxp_read() and pxp_write() wrappers Add pxp_read() and pxp_write() functions to wrap readl() and writel() respectively. This can be useful for debugging register accesses. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 118 +++++++++++++++------------ 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index a08e37b19213..cad1a201e1aa 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -253,6 +253,16 @@ static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx, return &ctx->q_data[V4L2_M2M_DST]; } +static inline u32 pxp_read(struct pxp_dev *dev, u32 reg) +{ + return readl(dev->mmio + reg); +} + +static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value) +{ + writel(value, dev->mmio + reg); +} + static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt) { switch (v4l2_pix_fmt) { @@ -505,11 +515,11 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) csc1_coef = csc1_coef_smpte240m_lim; } - writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0); - writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1); - writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2); + pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]); + pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]); + pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]); } else { - writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0); + pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS); } if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) && @@ -725,15 +735,15 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) BP_PXP_CSC2_CTRL_CSC_MODE; } - writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL); - writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0); - writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1); - writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2); - writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3); - writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4); - writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5); + pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl); + pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]); + pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]); + pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]); + pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]); + pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]); + pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]); } else { - writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL); + pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS); } } @@ -810,8 +820,8 @@ static void pxp_set_data_path(struct pxp_ctx *ctx) ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3); ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3); - writel(ctrl0, dev->mmio + HW_PXP_DATA_PATH_CTRL0); - writel(ctrl1, dev->mmio + HW_PXP_DATA_PATH_CTRL1); + pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0); + pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1); } static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, @@ -967,48 +977,48 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, BF_PXP_PS_SCALE_XSCALE(xscale); ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0); - writel(ctrl, dev->mmio + HW_PXP_CTRL); + pxp_write(dev, HW_PXP_CTRL, ctrl); /* skip STAT */ - writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL); - writel(out_buf, dev->mmio + HW_PXP_OUT_BUF); - writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2); - writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH); - writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC); - writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC); - writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC); - writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC); - writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC); - writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL); - writel(ps_buf, dev->mmio + HW_PXP_PS_BUF); - writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF); - writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF); - writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH); - writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0); - writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE); - writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET); + pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl); + pxp_write(dev, HW_PXP_OUT_BUF, out_buf); + pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2); + pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch); + pxp_write(dev, HW_PXP_OUT_LRC, out_lrc); + pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc); + pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc); + pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc); + pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc); + pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl); + pxp_write(dev, HW_PXP_PS_BUF, ps_buf); + pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf); + pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf); + pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch); + pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff); + pxp_write(dev, HW_PXP_PS_SCALE, ps_scale); + pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset); /* disable processed surface color keying */ - writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0); - writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0); + pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff); + pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000); /* disable alpha surface color keying */ - writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0); - writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0); + pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff); + pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000); /* setup CSC */ pxp_setup_csc(ctx); /* bypass LUT */ - writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL); + pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS); pxp_set_data_path(ctx); - writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK); + pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff); /* ungate, enable PS/AS/OUT and PXP operation */ - writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET); - writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 | - BM_PXP_CTRL_ENABLE_ROTATE0 | - BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE); + pxp_write(dev, HW_PXP_CTRL_SET, + BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 | + BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT); return 0; } @@ -1081,23 +1091,23 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id) struct pxp_dev *dev = dev_id; u32 stat; - stat = readl(dev->mmio + HW_PXP_STAT); + stat = pxp_read(dev, HW_PXP_STAT); if (stat & BM_PXP_STAT_IRQ0) { /* we expect x = 0, y = height, irq0 = 1 */ if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY | BM_PXP_STAT_IRQ0)) dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat); - writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR); + pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0); pxp_job_finish(dev); } else { - u32 irq = readl(dev->mmio + HW_PXP_IRQ); + u32 irq = pxp_read(dev, HW_PXP_IRQ); dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat); dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq); - writel(irq, dev->mmio + HW_PXP_IRQ_CLR); + pxp_write(dev, HW_PXP_IRQ_CLR, irq); } return IRQ_HANDLED; @@ -1741,18 +1751,18 @@ static int pxp_soft_reset(struct pxp_dev *dev) int ret; u32 val; - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE); - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST); ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val, val & BM_PXP_CTRL_CLKGATE, 0, 100); if (ret < 0) return ret; - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE); return 0; } @@ -1805,7 +1815,7 @@ static int pxp_probe(struct platform_device *pdev) goto err_clk; } - hw_version = readl(dev->mmio + HW_PXP_VERSION); + hw_version = pxp_read(dev, HW_PXP_VERSION); dev_dbg(&pdev->dev, "PXP Version %u.%u\n", PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version)); @@ -1883,8 +1893,8 @@ static int pxp_remove(struct platform_device *pdev) { struct pxp_dev *dev = platform_get_drvdata(pdev); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET); - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST); clk_disable_unprepare(dev->clk); From 4d25e97747d3f94c0e8ae9c0da2db801256908d0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 Jan 2023 10:54:21 +0100 Subject: [PATCH 212/216] media: imx-pxp: Use non-threaded IRQ There's no need to use threaded IRQs with the PXP, as the interrupt handler doesn't need to sleep and doesn't perform any time-consuming operation. Switch to regular IRQ handler. This fixes lockups of the PXP noticed on i.MX7, where the PXP would stop generating interrupts after a variable number of frames (from a few dozens to a few hundreds). The root cause is however unknown. Signed-off-by: Laurent Pinchart Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index cad1a201e1aa..f44cf16be942 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1798,8 +1798,8 @@ static int pxp_probe(struct platform_device *pdev) spin_lock_init(&dev->irqlock); - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler, - IRQF_ONESHOT, dev_name(&pdev->dev), dev); + ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0, + dev_name(&pdev->dev), dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); return ret; From 4e5bd3fdbeb3100d1f120999130afb2a7d41d82a Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 13 Jan 2023 10:54:22 +0100 Subject: [PATCH 213/216] media: imx-pxp: convert to regmap Replace the readl and writel with regmap to ease debugging the registers from userspace. Suggested-by: Alexander Stein Signed-off-by: Michael Tretter Reviewed-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/imx-pxp.c | 31 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index f44cf16be942..fde3c36e5e1d 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -176,6 +177,13 @@ enum { V4L2_M2M_DST = 1, }; +static const struct regmap_config pxp_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = HW_PXP_VERSION, +}; + static struct pxp_fmt *find_format(unsigned int pixelformat) { struct pxp_fmt *fmt; @@ -207,7 +215,7 @@ struct pxp_dev { #endif struct clk *clk; - void __iomem *mmio; + struct regmap *regmap; const struct pxp_pdata *pdata; @@ -255,12 +263,16 @@ static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx, static inline u32 pxp_read(struct pxp_dev *dev, u32 reg) { - return readl(dev->mmio + reg); + u32 value; + + regmap_read(dev->regmap, reg, &value); + + return value; } static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value) { - writel(value, dev->mmio + reg); + regmap_write(dev->regmap, reg, value); } static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt) @@ -1756,8 +1768,8 @@ static int pxp_soft_reset(struct pxp_dev *dev) pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST); - ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val, - val & BM_PXP_CTRL_CLKGATE, 0, 100); + ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val, + val & BM_PXP_CTRL_CLKGATE, 0, 100); if (ret < 0) return ret; @@ -1774,6 +1786,7 @@ static int pxp_probe(struct platform_device *pdev) u32 hw_version; int irq; int ret; + void __iomem *mmio; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -1788,9 +1801,11 @@ static int pxp_probe(struct platform_device *pdev) return ret; } - dev->mmio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dev->mmio)) - return PTR_ERR(dev->mmio); + mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, + &pxp_regmap_config); irq = platform_get_irq(pdev, 0); if (irq < 0) From 0fcb867718519060c90afea2d9af0a7cc1c3bd36 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Feb 2023 13:19:27 +0100 Subject: [PATCH 214/216] media: Revert "media: av7110: move to staging/media/deprecated/saa7146" This reverts commit 3e9ad662e34eb2d42ddef5a2883abd34461dfd9a. The av7110 is still in use, so it can't be deprecated. Move it back to staging/media for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/Kconfig | 2 ++ drivers/staging/media/Makefile | 1 + .../{deprecated/saa7146 => }/av7110/Kconfig | 20 ++++--------------- .../{deprecated/saa7146 => }/av7110/Makefile | 0 drivers/staging/media/av7110/TODO | 3 +++ .../av7110/audio-bilingual-channel-select.rst | 0 .../av7110/audio-channel-select.rst | 0 .../av7110/audio-clear-buffer.rst | 0 .../saa7146 => }/av7110/audio-continue.rst | 0 .../saa7146 => }/av7110/audio-fclose.rst | 0 .../saa7146 => }/av7110/audio-fopen.rst | 0 .../saa7146 => }/av7110/audio-fwrite.rst | 0 .../av7110/audio-get-capabilities.rst | 0 .../saa7146 => }/av7110/audio-get-status.rst | 0 .../saa7146 => }/av7110/audio-pause.rst | 0 .../saa7146 => }/av7110/audio-play.rst | 0 .../av7110/audio-select-source.rst | 0 .../saa7146 => }/av7110/audio-set-av-sync.rst | 0 .../av7110/audio-set-bypass-mode.rst | 0 .../saa7146 => }/av7110/audio-set-id.rst | 0 .../saa7146 => }/av7110/audio-set-mixer.rst | 0 .../saa7146 => }/av7110/audio-set-mute.rst | 0 .../av7110/audio-set-streamtype.rst | 0 .../saa7146 => }/av7110/audio-stop.rst | 0 .../{deprecated/saa7146 => }/av7110/audio.rst | 0 .../saa7146 => }/av7110/audio_data_types.rst | 0 .../av7110/audio_function_calls.rst | 0 .../{deprecated/saa7146 => }/av7110/av7110.c | 0 .../{deprecated/saa7146 => }/av7110/av7110.h | 0 .../saa7146 => }/av7110/av7110_av.c | 0 .../saa7146 => }/av7110/av7110_av.h | 0 .../saa7146 => }/av7110/av7110_ca.c | 0 .../saa7146 => }/av7110/av7110_ca.h | 0 .../saa7146 => }/av7110/av7110_hw.c | 0 .../saa7146 => }/av7110/av7110_hw.h | 0 .../saa7146 => }/av7110/av7110_ipack.c | 0 .../saa7146 => }/av7110/av7110_ipack.h | 0 .../saa7146 => }/av7110/av7110_ir.c | 0 .../saa7146 => }/av7110/av7110_v4l.c | 0 .../saa7146 => }/av7110/budget-patch.c | 0 .../saa7146 => }/av7110/dvb_filter.c | 0 .../saa7146 => }/av7110/dvb_filter.h | 0 .../{deprecated/saa7146 => }/av7110/sp8870.c | 0 .../{deprecated/saa7146 => }/av7110/sp8870.h | 0 .../av7110/video-clear-buffer.rst | 0 .../saa7146 => }/av7110/video-command.rst | 0 .../saa7146 => }/av7110/video-continue.rst | 0 .../av7110/video-fast-forward.rst | 0 .../saa7146 => }/av7110/video-fclose.rst | 0 .../saa7146 => }/av7110/video-fopen.rst | 0 .../saa7146 => }/av7110/video-freeze.rst | 0 .../saa7146 => }/av7110/video-fwrite.rst | 0 .../av7110/video-get-capabilities.rst | 0 .../saa7146 => }/av7110/video-get-event.rst | 0 .../av7110/video-get-frame-count.rst | 0 .../saa7146 => }/av7110/video-get-pts.rst | 0 .../saa7146 => }/av7110/video-get-size.rst | 0 .../saa7146 => }/av7110/video-get-status.rst | 0 .../saa7146 => }/av7110/video-play.rst | 0 .../av7110/video-select-source.rst | 0 .../saa7146 => }/av7110/video-set-blank.rst | 0 .../av7110/video-set-display-format.rst | 0 .../saa7146 => }/av7110/video-set-format.rst | 0 .../av7110/video-set-streamtype.rst | 0 .../saa7146 => }/av7110/video-slowmotion.rst | 0 .../av7110/video-stillpicture.rst | 0 .../saa7146 => }/av7110/video-stop.rst | 0 .../saa7146 => }/av7110/video-try-command.rst | 0 .../{deprecated/saa7146 => }/av7110/video.rst | 0 .../av7110/video_function_calls.rst | 0 .../saa7146 => }/av7110/video_types.rst | 0 .../staging/media/deprecated/saa7146/Kconfig | 1 - .../staging/media/deprecated/saa7146/Makefile | 2 +- .../media/deprecated/saa7146/av7110/TODO | 9 --------- 74 files changed, 11 insertions(+), 27 deletions(-) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/Kconfig (82%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/Makefile (100%) create mode 100644 drivers/staging/media/av7110/TODO rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-bilingual-channel-select.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-channel-select.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-clear-buffer.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-continue.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-fclose.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-fopen.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-fwrite.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-get-capabilities.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-get-status.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-pause.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-play.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-select-source.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-av-sync.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-bypass-mode.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-id.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-mixer.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-mute.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-set-streamtype.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio-stop.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio_data_types.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/audio_function_calls.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_av.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_av.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_ca.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_ca.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_hw.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_hw.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_ipack.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_ipack.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_ir.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/av7110_v4l.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/budget-patch.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/dvb_filter.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/dvb_filter.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/sp8870.c (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/sp8870.h (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-clear-buffer.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-command.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-continue.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-fast-forward.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-fclose.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-fopen.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-freeze.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-fwrite.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-capabilities.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-event.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-frame-count.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-pts.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-size.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-get-status.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-play.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-select-source.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-set-blank.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-set-display-format.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-set-format.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-set-streamtype.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-slowmotion.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-stillpicture.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-stop.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video-try-command.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video_function_calls.rst (100%) rename drivers/staging/media/{deprecated/saa7146 => }/av7110/video_types.rst (100%) delete mode 100644 drivers/staging/media/deprecated/saa7146/av7110/TODO diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index d71ee9a5d04b..9a43d8872324 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,6 +22,8 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/atomisp/Kconfig" +source "drivers/staging/media/av7110/Kconfig" + source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/ipu3/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 1a01c1af3224..2efdbf78d5ef 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ +obj-$(CONFIG_DVB_AV7110) += av7110/ obj-y += deprecated/saa7146/ diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig similarity index 82% rename from drivers/staging/media/deprecated/saa7146/av7110/Kconfig rename to drivers/staging/media/av7110/Kconfig index 1571eab31926..9faf9d2d4001 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig +++ b/drivers/staging/media/av7110/Kconfig @@ -5,7 +5,7 @@ config DVB_AV7110_IR default DVB_AV7110 config DVB_AV7110 - tristate "AV7110 cards (DEPRECATED)" + tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV @@ -35,13 +35,10 @@ config DVB_AV7110 kernel image by adding the filename to the EXTRA_FIRMWARE configuration option string. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. config DVB_AV7110_OSD - bool "AV7110 OSD support (DEPRECATED)" + bool "AV7110 OSD support" depends on DVB_AV7110 default y if DVB_AV7110=y || DVB_AV7110=m help @@ -52,13 +49,10 @@ config DVB_AV7110_OSD Anyway, some popular DVB software like VDR uses this OSD to render its menus, so say Y if you want to use this software. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - All other people say N. config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch (DEPRECATED)" + tristate "AV7110 cards with Budget Patch" depends on DVB_BUDGET_CORE && I2C depends on DVB_AV7110 select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -74,9 +68,6 @@ config DVB_BUDGET_PATCH standard AV7110 driver prior to loading this driver. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the @@ -89,7 +80,7 @@ if DVB_AV7110 # it if we drop support for AV7110, as no other driver will use it. config DVB_SP8870 - tristate "Spase sp8870 based (DEPRECATED)" + tristate "Spase sp8870 based" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -100,7 +91,4 @@ config DVB_SP8870 download/extract it, and then copy it to /usr/lib/hotplug/firmware or /lib/firmware (depending on configuration of firmware hotplug). - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - endif diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Makefile b/drivers/staging/media/av7110/Makefile similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/Makefile rename to drivers/staging/media/av7110/Makefile diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO new file mode 100644 index 000000000000..60062d8441b3 --- /dev/null +++ b/drivers/staging/media/av7110/TODO @@ -0,0 +1,3 @@ +- This driver is too old and relies on a different API. + Drop it from Kernel on a couple of versions. +- Cleanup patches for the drivers here won't be accepted. diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst rename to drivers/staging/media/av7110/audio-bilingual-channel-select.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst rename to drivers/staging/media/av7110/audio-channel-select.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst rename to drivers/staging/media/av7110/audio-clear-buffer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst rename to drivers/staging/media/av7110/audio-continue.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst rename to drivers/staging/media/av7110/audio-fclose.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst rename to drivers/staging/media/av7110/audio-fopen.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst rename to drivers/staging/media/av7110/audio-fwrite.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst rename to drivers/staging/media/av7110/audio-get-capabilities.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst rename to drivers/staging/media/av7110/audio-get-status.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst rename to drivers/staging/media/av7110/audio-pause.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst rename to drivers/staging/media/av7110/audio-play.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst rename to drivers/staging/media/av7110/audio-select-source.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst rename to drivers/staging/media/av7110/audio-set-av-sync.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst rename to drivers/staging/media/av7110/audio-set-bypass-mode.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst rename to drivers/staging/media/av7110/audio-set-id.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst rename to drivers/staging/media/av7110/audio-set-mixer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst rename to drivers/staging/media/av7110/audio-set-mute.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst rename to drivers/staging/media/av7110/audio-set-streamtype.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst rename to drivers/staging/media/av7110/audio-stop.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio.rst rename to drivers/staging/media/av7110/audio.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst rename to drivers/staging/media/av7110/audio_data_types.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst rename to drivers/staging/media/av7110/audio_function_calls.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110.c rename to drivers/staging/media/av7110/av7110.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110.h rename to drivers/staging/media/av7110/av7110.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c rename to drivers/staging/media/av7110/av7110_av.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h rename to drivers/staging/media/av7110/av7110_av.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c rename to drivers/staging/media/av7110/av7110_ca.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h rename to drivers/staging/media/av7110/av7110_ca.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c rename to drivers/staging/media/av7110/av7110_hw.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h rename to drivers/staging/media/av7110/av7110_hw.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c rename to drivers/staging/media/av7110/av7110_ipack.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h rename to drivers/staging/media/av7110/av7110_ipack.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c rename to drivers/staging/media/av7110/av7110_ir.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c rename to drivers/staging/media/av7110/av7110_v4l.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c rename to drivers/staging/media/av7110/budget-patch.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c rename to drivers/staging/media/av7110/dvb_filter.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h rename to drivers/staging/media/av7110/dvb_filter.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/sp8870.c rename to drivers/staging/media/av7110/sp8870.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/sp8870.h rename to drivers/staging/media/av7110/sp8870.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst rename to drivers/staging/media/av7110/video-clear-buffer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-command.rst rename to drivers/staging/media/av7110/video-command.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst rename to drivers/staging/media/av7110/video-continue.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst rename to drivers/staging/media/av7110/video-fast-forward.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst rename to drivers/staging/media/av7110/video-fclose.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst rename to drivers/staging/media/av7110/video-fopen.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst rename to drivers/staging/media/av7110/video-freeze.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst rename to drivers/staging/media/av7110/video-fwrite.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst rename to drivers/staging/media/av7110/video-get-capabilities.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst rename to drivers/staging/media/av7110/video-get-event.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst rename to drivers/staging/media/av7110/video-get-frame-count.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst rename to drivers/staging/media/av7110/video-get-pts.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst rename to drivers/staging/media/av7110/video-get-size.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst rename to drivers/staging/media/av7110/video-get-status.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-play.rst rename to drivers/staging/media/av7110/video-play.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst rename to drivers/staging/media/av7110/video-select-source.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst rename to drivers/staging/media/av7110/video-set-blank.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst rename to drivers/staging/media/av7110/video-set-display-format.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst rename to drivers/staging/media/av7110/video-set-format.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst rename to drivers/staging/media/av7110/video-set-streamtype.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst rename to drivers/staging/media/av7110/video-slowmotion.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst rename to drivers/staging/media/av7110/video-stillpicture.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst rename to drivers/staging/media/av7110/video-stop.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst rename to drivers/staging/media/av7110/video-try-command.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video.rst b/drivers/staging/media/av7110/video.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video.rst rename to drivers/staging/media/av7110/video.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst rename to drivers/staging/media/av7110/video_function_calls.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst similarity index 100% rename from drivers/staging/media/deprecated/saa7146/av7110/video_types.rst rename to drivers/staging/media/av7110/video_types.rst diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig index 54154da79f59..d0cb52164ff8 100644 --- a/drivers/staging/media/deprecated/saa7146/Kconfig +++ b/drivers/staging/media/deprecated/saa7146/Kconfig @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 source "drivers/staging/media/deprecated/saa7146/common/Kconfig" -source "drivers/staging/media/deprecated/saa7146/av7110/Kconfig" source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig" source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig" diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile index 68e7aa10c639..9d99fdedf813 100644 --- a/drivers/staging/media/deprecated/saa7146/Makefile +++ b/drivers/staging/media/deprecated/saa7146/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += common/ av7110/ saa7146/ ttpci/ +obj-y += common/ saa7146/ ttpci/ diff --git a/drivers/staging/media/deprecated/saa7146/av7110/TODO b/drivers/staging/media/deprecated/saa7146/av7110/TODO deleted file mode 100644 index 38817e04bb67..000000000000 --- a/drivers/staging/media/deprecated/saa7146/av7110/TODO +++ /dev/null @@ -1,9 +0,0 @@ -- This driver is too old and relies on a different API. - Drop it from Kernel on a couple of versions. -- Cleanup patches for the drivers here won't be accepted. - -These drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). From 39d08ab979b7995d22dd6b3ce74d3179f02847a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Feb 2023 13:21:36 +0100 Subject: [PATCH 215/216] media: Revert "media: saa7146: deprecate hexium_gemini/orion, mxb and ttpci" This reverts commit e33fdb5a02490059e2f48ced2c038c8a46c6476d. The saa7146-based devices are still in use, esp. for DVB. So move these drivers back to mainline. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +++- drivers/media/common/Kconfig | 1 + drivers/media/common/Makefile | 2 +- .../common => media/common/saa7146}/Kconfig | 0 .../common => media/common/saa7146}/Makefile | 0 .../common/saa7146}/saa7146_core.c | 2 +- .../common/saa7146}/saa7146_fops.c | 2 +- .../common/saa7146}/saa7146_hlp.c | 2 +- .../common/saa7146}/saa7146_i2c.c | 2 +- .../common/saa7146}/saa7146_vbi.c | 2 +- .../common/saa7146}/saa7146_video.c | 2 +- drivers/media/pci/Kconfig | 2 ++ drivers/media/pci/Makefile | 4 +++- .../saa7146 => media/pci}/saa7146/Kconfig | 15 +++------------ .../saa7146 => media/pci}/saa7146/Makefile | 0 .../pci}/saa7146/hexium_gemini.c | 2 +- .../pci}/saa7146/hexium_orion.c | 2 +- .../saa7146 => media/pci}/saa7146/mxb.c | 2 +- .../saa7146 => media/pci}/ttpci/Kconfig | 17 ++++------------- .../saa7146 => media/pci}/ttpci/Makefile | 0 .../saa7146 => media/pci}/ttpci/budget-av.c | 2 +- .../saa7146 => media/pci}/ttpci/budget-ci.c | 0 .../saa7146 => media/pci}/ttpci/budget-core.c | 0 .../saa7146 => media/pci}/ttpci/budget.c | 0 .../saa7146 => media/pci}/ttpci/budget.h | 2 +- drivers/staging/media/Kconfig | 1 - drivers/staging/media/Makefile | 1 - drivers/staging/media/av7110/Makefile | 3 +-- drivers/staging/media/av7110/av7110.h | 2 +- .../staging/media/deprecated/saa7146/Kconfig | 4 ---- .../staging/media/deprecated/saa7146/Makefile | 2 -- .../media/deprecated/saa7146/saa7146/TODO | 7 ------- .../staging/media/deprecated/saa7146/ttpci/TODO | 7 ------- .../common => include/media/drv-intf}/saa7146.h | 0 .../media/drv-intf}/saa7146_vv.h | 2 +- 35 files changed, 31 insertions(+), 65 deletions(-) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/Kconfig (100%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/Makefile (100%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_core.c (99%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_fops.c (99%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_hlp.c (99%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_i2c.c (99%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_vbi.c (99%) rename drivers/{staging/media/deprecated/saa7146/common => media/common/saa7146}/saa7146_video.c (99%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/saa7146/Kconfig (67%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/saa7146/Makefile (100%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/saa7146/hexium_gemini.c (99%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/saa7146/hexium_orion.c (99%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/saa7146/mxb.c (99%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/Kconfig (83%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/Makefile (100%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/budget-av.c (99%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/budget-ci.c (100%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/budget-core.c (100%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/budget.c (100%) rename drivers/{staging/media/deprecated/saa7146 => media/pci}/ttpci/budget.h (98%) delete mode 100644 drivers/staging/media/deprecated/saa7146/Kconfig delete mode 100644 drivers/staging/media/deprecated/saa7146/Makefile delete mode 100644 drivers/staging/media/deprecated/saa7146/saa7146/TODO delete mode 100644 drivers/staging/media/deprecated/saa7146/ttpci/TODO rename {drivers/staging/media/deprecated/saa7146/common => include/media/drv-intf}/saa7146.h (100%) rename {drivers/staging/media/deprecated/saa7146/common => include/media/drv-intf}/saa7146_vv.h (99%) diff --git a/MAINTAINERS b/MAINTAINERS index b8a4b52db8ca..14dee6886c6b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18393,7 +18393,9 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: drivers/staging/media/deprecated/saa7146/ +F: drivers/media/common/saa7146/ +F: drivers/media/pci/saa7146/ +F: include/media/drv-intf/saa7146* SAFESETID SECURITY MODULE M: Micah Morton diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 852b7d92fbdd..a2ae71270054 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -22,6 +22,7 @@ config VIDEO_TVEEPROM depends on I2C source "drivers/media/common/b2c2/Kconfig" +source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" source "drivers/media/common/v4l2-tpg/Kconfig" source "drivers/media/common/videobuf2/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index d78a0df15478..ad0b1e95fb12 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/ +obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/ # Please keep it alphabetically sorted by Kconfig name # (e. g. LC_ALL=C sort Makefile) diff --git a/drivers/staging/media/deprecated/saa7146/common/Kconfig b/drivers/media/common/saa7146/Kconfig similarity index 100% rename from drivers/staging/media/deprecated/saa7146/common/Kconfig rename to drivers/media/common/saa7146/Kconfig diff --git a/drivers/staging/media/deprecated/saa7146/common/Makefile b/drivers/media/common/saa7146/Makefile similarity index 100% rename from drivers/staging/media/deprecated/saa7146/common/Makefile rename to drivers/media/common/saa7146/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_core.c rename to drivers/media/common/saa7146/saa7146_core.c index da21d346b870..e50fa0ff7c5d 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -8,8 +8,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include -#include "saa7146.h" static int saa7146_num; diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c rename to drivers/media/common/saa7146/saa7146_fops.c index aa14698a9c54..e9a15de6126e 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include -#include "saa7146_vv.h" /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c rename to drivers/media/common/saa7146/saa7146_hlp.c index b1222a4cfa4a..6c9946a402ee 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -3,7 +3,7 @@ #include #include -#include "saa7146_vv.h" +#include static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) { diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c rename to drivers/media/common/saa7146/saa7146_i2c.c index 7a33fe51775a..df9ebe2a168c 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "saa7146_vv.h" +#include static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c rename to drivers/media/common/saa7146/saa7146_vbi.c index 2d4a05d7bc5b..bd442b984423 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include "saa7146_vv.h" +#include static int vbi_pixel_to_capture = 720 * 2; diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_video.c rename to drivers/media/common/saa7146/saa7146_video.c index 4598a44231fa..2296765079a4 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1,10 +1,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include #include -#include "saa7146_vv.h" static int max_memory = 32; diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index dff0b450f387..480194543d05 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -27,6 +27,7 @@ if MEDIA_ANALOG_TV_SUPPORT source "drivers/media/pci/dt3155/Kconfig" source "drivers/media/pci/ivtv/Kconfig" +source "drivers/media/pci/saa7146/Kconfig" endif @@ -57,6 +58,7 @@ source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/pt1/Kconfig" source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/smipcie/Kconfig" +source "drivers/media/pci/ttpci/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 8f887a8a7f17..8bed619b7130 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -5,7 +5,8 @@ # Please keep it alphabetically sorted by directory # (e. g. LC_ALL=C sort Makefile) -obj-y += b2c2/ \ +obj-y += ttpci/ \ + b2c2/ \ pluto2/ \ dm1105/ \ pt1/ \ @@ -13,6 +14,7 @@ obj-y += b2c2/ \ mantis/ \ ngene/ \ ddbridge/ \ + saa7146/ \ smipcie/ \ netup_unidvb/ \ intel/ diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig similarity index 67% rename from drivers/staging/media/deprecated/saa7146/saa7146/Kconfig rename to drivers/media/pci/saa7146/Kconfig index 228e8d3f8d2b..3bbb68a0ed7b 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber (DEPRECATED)" + tristate "Hexium Gemini frame grabber" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help @@ -8,28 +8,22 @@ config VIDEO_HEXIUM_GEMINI grabber card by Hexium. Please note that the Gemini Dual card is *not* fully supported. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called hexium_gemini. config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber (DEPRECATED)" + tristate "Hexium HV-PCI6 and Orion frame grabber" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help This is a video4linux driver for the Hexium HV-PCI6 and Orion frame grabber cards by Hexium. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called hexium_orion. config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board' (DEPRECATED)" + tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV select VIDEO_TUNER @@ -41,8 +35,5 @@ config VIDEO_MXB This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called mxb. diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile similarity index 100% rename from drivers/staging/media/deprecated/saa7146/saa7146/Makefile rename to drivers/media/pci/saa7146/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c rename to drivers/media/pci/saa7146/hexium_gemini.c index 124e82bd4507..3947701cd6c7 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug +#include #include #include -#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c rename to drivers/media/pci/saa7146/hexium_orion.c index ebd63998ac79..2eb4bee16b71 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug +#include #include #include -#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/saa7146/mxb.c rename to drivers/media/pci/saa7146/mxb.c index 3e568f952dae..7ded8f5b05cb 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -13,13 +13,13 @@ #define DEBUG_VARIABLE debug +#include #include #include #include #include #include -#include "../common/saa7146_vv.h" #include "tea6415c.h" #include "tea6420.h" diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig similarity index 83% rename from drivers/staging/media/deprecated/saa7146/ttpci/Kconfig rename to drivers/media/pci/ttpci/Kconfig index 8c85ed58e938..65a6832a6b96 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI) (DEPRECATED)" + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146 select TTPCI_EEPROM @@ -10,7 +10,7 @@ config DVB_BUDGET_CORE MPEG2 decoder. config DVB_BUDGET - tristate "Budget cards (DEPRECATED)" + tristate "Budget cards" depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT @@ -30,16 +30,13 @@ config DVB_BUDGET or Nova-PCI cards) without onboard MPEG2 decoder, and without analog inputs or an onboard Common Interface connector. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget. config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector (DEPRECATED)" + tristate "Budget cards with onboard CI connector" depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -60,16 +57,13 @@ config DVB_BUDGET_CI Note: The Common Interface is not yet supported by this driver due to lack of information from the vendor. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget-ci. config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs (DEPRECATED)" + tristate "Budget cards with analog video inputs" depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV @@ -86,9 +80,6 @@ config DVB_BUDGET_AV (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, but with one or more analog video inputs. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile similarity index 100% rename from drivers/staging/media/deprecated/saa7146/ttpci/Makefile rename to drivers/media/pci/ttpci/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c similarity index 99% rename from drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c rename to drivers/media/pci/ttpci/budget-av.c index 0c61a2dec221..3cb83005cf09 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -29,7 +29,7 @@ #include "tda1004x.h" #include "tua6100.h" #include "dvb-pll.h" -#include "../common/saa7146_vv.h" +#include #include #include #include diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c rename to drivers/media/pci/ttpci/budget-ci.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c rename to drivers/media/pci/ttpci/budget-core.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c similarity index 100% rename from drivers/staging/media/deprecated/saa7146/ttpci/budget.c rename to drivers/media/pci/ttpci/budget.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h similarity index 98% rename from drivers/staging/media/deprecated/saa7146/ttpci/budget.h rename to drivers/media/pci/ttpci/budget.h index 82cc0df492b3..bd87432e6cde 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -13,7 +13,7 @@ #include #include -#include "../common/saa7146.h" +#include extern int budget_debug; diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 9a43d8872324..bc6c7b248f86 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -54,7 +54,6 @@ menuconfig STAGING_MEDIA_DEPRECATED if STAGING_MEDIA_DEPRECATED source "drivers/staging/media/deprecated/atmel/Kconfig" -source "drivers/staging/media/deprecated/saa7146/Kconfig" endif endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 2efdbf78d5ef..1a4c3a062e3d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -10,4 +10,3 @@ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_DVB_AV7110) += av7110/ -obj-y += deprecated/saa7146/ diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/av7110/Makefile index c04cd0a59109..307b267598ea 100644 --- a/drivers/staging/media/av7110/Makefile +++ b/drivers/staging/media/av7110/Makefile @@ -18,6 +18,5 @@ obj-$(CONFIG_DVB_SP8870) += sp8870.o ccflags-y += -I $(srctree)/drivers/media/dvb-frontends ccflags-y += -I $(srctree)/drivers/media/tuners +ccflags-y += -I $(srctree)/drivers/media/pci/ttpci ccflags-y += -I $(srctree)/drivers/media/common -ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/ttpci -ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/common diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h index 9fde69b38f1c..809d938ae166 100644 --- a/drivers/staging/media/av7110/av7110.h +++ b/drivers/staging/media/av7110/av7110.h @@ -33,7 +33,7 @@ #include "stv0297.h" #include "l64781.h" -#include "saa7146_vv.h" +#include #define ANALOG_TUNER_VES1820 1 diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig deleted file mode 100644 index d0cb52164ff8..000000000000 --- a/drivers/staging/media/deprecated/saa7146/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -source "drivers/staging/media/deprecated/saa7146/common/Kconfig" -source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig" -source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig" diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile deleted file mode 100644 index 9d99fdedf813..000000000000 --- a/drivers/staging/media/deprecated/saa7146/Makefile +++ /dev/null @@ -1,2 +0,0 @@ - # SPDX-License-Identifier: GPL-2.0-only -obj-y += common/ saa7146/ ttpci/ diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/TODO b/drivers/staging/media/deprecated/saa7146/saa7146/TODO deleted file mode 100644 index c9ae2ec79cea..000000000000 --- a/drivers/staging/media/deprecated/saa7146/saa7146/TODO +++ /dev/null @@ -1,7 +0,0 @@ -The saa7146-based drivers are one of the few drivers still not using -the vb2 framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/TODO b/drivers/staging/media/deprecated/saa7146/ttpci/TODO deleted file mode 100644 index c9ae2ec79cea..000000000000 --- a/drivers/staging/media/deprecated/saa7146/ttpci/TODO +++ /dev/null @@ -1,7 +0,0 @@ -The saa7146-based drivers are one of the few drivers still not using -the vb2 framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146.h b/include/media/drv-intf/saa7146.h similarity index 100% rename from drivers/staging/media/deprecated/saa7146/common/saa7146.h rename to include/media/drv-intf/saa7146.h diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h similarity index 99% rename from drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h rename to include/media/drv-intf/saa7146_vv.h index d7bd916fe3ad..635805fb35e8 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h +++ b/include/media/drv-intf/saa7146_vv.h @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include "saa7146.h" #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ From 05165248df6552daaacf5621e3a5e2369117a8a9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 28 Dec 2022 18:02:27 +0100 Subject: [PATCH 216/216] media: v4l2-ctrls-api.c: move ctrl->is_new = 1 to the correct line The patch that fixed string control support somehow got mangled when it was merged in mainline: the added line ended up in the wrong place. Fix this. Fixes: 73278d483378 ("media: v4l2-ctrls-api.c: add back dropped ctrl->is_new = 1") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls-api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index 3d3b6dc24ca6..002ea6588edf 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -150,8 +150,8 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) * then return an error. */ if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last) - ctrl->is_new = 1; return -ERANGE; + ctrl->is_new = 1; } return ret; default: