Linux kernel staging patches
 help / color / mirror / Atom feed
From: Maurizio Casciano <mauriziocasciano7@gmail.com>
To: linux-media@vger.kernel.org
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>,
	Sakari Ailus <sakari.ailus@linux.intel.com>,
	Bingbu Cao <bingbu.cao@amd.com>,
	Jacopo Mondi <jacopo.mondi@ideasonboard.com>,
	Nicholas Roth <nicholas@rothemail.net>,
	Andy Shevchenko <andy@kernel.org>,
	Hans de Goede <hansg@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Jose Maria Martin <jmmartinf@hotmail.com>,
	linux-staging@lists.linux.dev, linux-kernel@vger.kernel.org,
	Maurizio Casciano <mauriziocasciano7@gmail.com>
Subject: [PATCH 8/8] media: i2c: Add WV517S lens actuator driver
Date: Wed, 26 Aug 2026 15:22:56 +0200	[thread overview]
Message-ID: <20260826132256.3343451-9-mauriziocasciano7@gmail.com> (raw)
In-Reply-To: <20260826132256.3343451-1-mauriziocasciano7@gmail.com>

The Lenovo Yoga Book YB1-X91 rear camera contains a WV517S
voice-coil actuator. Add a V4L2 lens subdevice exposing the standard
10-bit FOCUS_ABSOLUTE control and the device ringing-control mode.

Tie register access to runtime PM so the IPU bridge sensor link keeps
shared power resources active. Propagate PM acquisition failures and
restore the drive mode and requested focus position after resume.

The register addresses and drive-mode value are derived from Intel's
GPL-2.0 WV517 driver. Retain its copyright notice.

Link: https://github.com/jekhor/yogabook-linux-android-kernel/blob/574bae692716f1b14093497bfab8a007fe8e460b/drivers/external_drivers/camera/drivers/media/i2c/wv517.c

Signed-off-by: Maurizio Casciano <mauriziocasciano7@gmail.com>
Assisted-by: Codex:gpt-5.6-sol sparse
---
 MAINTAINERS                |   1 +
 drivers/media/i2c/Kconfig  |   8 ++
 drivers/media/i2c/Makefile |   1 +
 drivers/media/i2c/wv517s.c | 199 +++++++++++++++++++++++++++++++++++++
 4 files changed, 209 insertions(+)
 create mode 100644 drivers/media/i2c/wv517s.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3785b8c1de0a..205a42646a7d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28268,6 +28268,7 @@ S:	Maintained
 F:	drivers/media/i2c/ak*
 F:	drivers/media/i2c/dw*
 F:	drivers/media/i2c/lm*
+F:	drivers/media/i2c/wv517s.c
 
 V4L2 CAMERA SENSOR DRIVERS
 M:	Sakari Ailus <sakari.ailus@linux.intel.com>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5c52007f9cbe..c488452c1b38 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -949,6 +949,14 @@ config VIDEO_DW9807_VCM
 	  capability. This is designed for linear control of
 	  voice coil motors, controlled via I2C serial interface.
 
+config VIDEO_WV517S
+	tristate "WV517S lens voice coil support"
+	help
+	  This is a driver for the WV517S camera lens voice coil. It supports
+	  the 10-bit focus control used by the Lenovo Yoga Book rear camera.
+	  The driver exposes the actuator through the standard V4L2 lens
+	  sub-device interface.
+
 endif
 
 menu "Flash devices"
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index d04bd5724552..e480932a9540 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -173,4 +173,5 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WV517S) += wv517s.o
 obj-$(CONFIG_VIDEO_INTEL_CVS) += cvs/
diff --git a/drivers/media/i2c/wv517s.c b/drivers/media/i2c/wv517s.c
new file mode 100644
index 000000000000..43d15aadea30
--- /dev/null
+++ b/drivers/media/i2c/wv517s.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * WV517S voice-coil motor driver
+ *
+ * Copyright (c) 2014 Intel Corporation.
+ *
+ * On the Lenovo Yoga Book the IPU bridge instantiates this actuator as a
+ * secondary I2C client of the rear camera.  The bridge holds the sensor's
+ * shared power resources on while probing the actuator and adds a runtime-PM
+ * device link for subsequent accesses.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define WV517S_MAX_FOCUS_POSITION	1023
+#define WV517S_DEFAULT_FOCUS_POSITION	300
+
+#define WV517S_REG_FOCUS		0x41
+#define WV517S_REG_DRIVE_MODE		0x43
+#define WV517S_DRIVE_MODE_12_6_MS	0x0211
+
+struct wv517s_device {
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl *focus;
+};
+
+static inline struct wv517s_device *to_wv517s(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct wv517s_device, sd);
+}
+
+static int wv517s_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	u8 buf[] = { reg, value >> 8, value };
+	int ret;
+
+	ret = i2c_master_send(client, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	return ret == sizeof(buf) ? 0 : -EIO;
+}
+
+static int wv517s_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct wv517s_device *wv517s = container_of(ctrl->handler,
+						      struct wv517s_device,
+						      ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&wv517s->sd);
+	int ret;
+
+	ret = pm_runtime_get_if_in_use(&client->dev);
+	if (ret <= 0)
+		return ret;
+
+	if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE)
+		ret = wv517s_write(client, WV517S_REG_FOCUS, ctrl->val);
+	else
+		ret = -EINVAL;
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops wv517s_ctrl_ops = {
+	.s_ctrl = wv517s_set_ctrl,
+};
+
+static int wv517s_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return pm_runtime_resume_and_get(sd->dev);
+}
+
+static int wv517s_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	pm_runtime_put(sd->dev);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops wv517s_internal_ops = {
+	.open = wv517s_open,
+	.close = wv517s_close,
+};
+
+static const struct v4l2_subdev_ops wv517s_subdev_ops = { };
+
+static int wv517s_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct wv517s_device *wv517s = to_wv517s(sd);
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	/* Restore the vendor-recommended 12.6 ms ringing-control mode. */
+	ret = wv517s_write(client, WV517S_REG_DRIVE_MODE,
+			   WV517S_DRIVE_MODE_12_6_MS);
+	if (ret)
+		return ret;
+
+	return wv517s_write(client, WV517S_REG_FOCUS, wv517s->focus->val);
+}
+
+static int wv517s_probe(struct i2c_client *client)
+{
+	struct wv517s_device *wv517s;
+	int ret;
+
+	wv517s = devm_kzalloc(&client->dev, sizeof(*wv517s), GFP_KERNEL);
+	if (!wv517s)
+		return -ENOMEM;
+
+	v4l2_i2c_subdev_init(&wv517s->sd, client, &wv517s_subdev_ops);
+	wv517s->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	wv517s->sd.internal_ops = &wv517s_internal_ops;
+	wv517s->sd.entity.function = MEDIA_ENT_F_LENS;
+
+	v4l2_ctrl_handler_init(&wv517s->ctrl_handler, 1);
+	wv517s->focus = v4l2_ctrl_new_std(&wv517s->ctrl_handler,
+					  &wv517s_ctrl_ops,
+					  V4L2_CID_FOCUS_ABSOLUTE, 0,
+					  WV517S_MAX_FOCUS_POSITION, 1,
+					  WV517S_DEFAULT_FOCUS_POSITION);
+	if (wv517s->ctrl_handler.error) {
+		ret = wv517s->ctrl_handler.error;
+		goto err_free_ctrl_handler;
+	}
+	wv517s->sd.ctrl_handler = &wv517s->ctrl_handler;
+
+	ret = media_entity_pads_init(&wv517s->sd.entity, 0, NULL);
+	if (ret)
+		goto err_free_ctrl_handler;
+
+	ret = wv517s_resume(&client->dev);
+	if (ret)
+		goto err_cleanup_entity;
+
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+
+	ret = v4l2_async_register_subdev(&wv517s->sd);
+	if (ret)
+		goto err_disable_pm;
+
+	pm_runtime_idle(&client->dev);
+
+	return 0;
+
+err_disable_pm:
+	pm_runtime_disable(&client->dev);
+err_cleanup_entity:
+	media_entity_cleanup(&wv517s->sd.entity);
+err_free_ctrl_handler:
+	v4l2_ctrl_handler_free(&wv517s->ctrl_handler);
+
+	return ret;
+}
+
+static void wv517s_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct wv517s_device *wv517s = to_wv517s(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	pm_runtime_disable(&client->dev);
+	v4l2_ctrl_handler_free(&wv517s->ctrl_handler);
+	media_entity_cleanup(&sd->entity);
+}
+
+static const struct i2c_device_id wv517s_id_table[] = {
+	{ "wv517s" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wv517s_id_table);
+
+static DEFINE_RUNTIME_DEV_PM_OPS(wv517s_pm_ops, NULL, wv517s_resume, NULL);
+
+static struct i2c_driver wv517s_i2c_driver = {
+	.driver = {
+		.name = "wv517s",
+		.pm = pm_ptr(&wv517s_pm_ops),
+	},
+	.probe = wv517s_probe,
+	.remove = wv517s_remove,
+	.id_table = wv517s_id_table,
+};
+module_i2c_driver(wv517s_i2c_driver);
+
+MODULE_AUTHOR("Maurizio Casciano");
+MODULE_DESCRIPTION("WV517S VCM driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0


  parent reply	other threads:[~2026-08-26 13:23 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 13:22 [PATCH 0/8] media: Add Lenovo Yoga Book YB1-X91 camera support Maurizio Casciano
2026-08-26 13:22 ` [PATCH 1/8] media: ov8858: support 19.2 MHz clock and CHT gain setup Maurizio Casciano
2026-08-27  9:40   ` Andy Shevchenko
2026-08-27 11:59     ` Sakari Ailus
2026-08-27 18:19     ` Maurizio Casciano
2026-08-26 13:22 ` [PATCH 2/8] media: i2c: Add Yoga Book camera ACPI IDs Maurizio Casciano
2026-08-27  9:58   ` Andy Shevchenko
2026-08-27 12:14     ` Sakari Ailus
2026-08-27 12:46       ` Andy Shevchenko
2026-08-27 18:19     ` Maurizio Casciano
2026-08-27 23:18     ` Maurizio Casciano
2026-08-27 12:13   ` Sakari Ailus
2026-08-26 13:22 ` [PATCH 3/8] media: intel: ipu-bridge: Add Yoga Book camera sensors Maurizio Casciano
2026-08-26 13:22 ` [PATCH 4/8] media: atomisp: Add Yoga Book camera configuration Maurizio Casciano
2026-08-26 13:22 ` [PATCH 5/8] media: atomisp: support the Yoga Book OV2740 link Maurizio Casciano
2026-08-27 14:26   ` Andy Shevchenko
2026-08-27 23:18     ` Maurizio Casciano
2026-08-26 13:22 ` [PATCH 6/8] media: ov2740: add manual white balance controls Maurizio Casciano
2026-08-27  3:13   ` Cao, Bingbu
2026-08-27 18:19     ` Maurizio Casciano
2026-08-27 14:32   ` Andy Shevchenko
2026-08-26 13:22 ` [PATCH 7/8] media: atomisp: allow opt-in raw Bayer capture Maurizio Casciano
2026-08-27 14:43   ` Andy Shevchenko
2026-08-26 13:22 ` Maurizio Casciano [this message]
2026-08-27 12:30   ` [PATCH 8/8] media: i2c: Add WV517S lens actuator driver Sakari Ailus
2026-08-27 18:19     ` Maurizio Casciano
2026-08-27 18:17 ` [PATCH v2 00/11] media: Add Lenovo Yoga Book YB1-X91 camera support Maurizio Casciano
2026-08-27 18:17   ` [PATCH v2 01/11] media: ov8858: Extract digital gain programming Maurizio Casciano
2026-08-27 18:17   ` [PATCH v2 02/11] media: ov8858: support 19.2 MHz clock and CHT gain setup Maurizio Casciano
2026-08-27 19:46     ` Andy Shevchenko
2026-08-27 23:18       ` Maurizio Casciano
2026-08-28  7:28       ` Sakari Ailus
2026-08-28  7:48         ` Andy Shevchenko
2026-08-27 18:17   ` [PATCH v2 03/11] media: ov2740: Use C99 initializers for ACPI IDs Maurizio Casciano
2026-08-27 19:47     ` Andy Shevchenko
2026-08-27 18:17   ` [PATCH v2 04/11] media: ov2740: Add OVTI2740 ACPI ID Maurizio Casciano
2026-08-27 18:17   ` [PATCH v2 05/11] media: ov8858: Add INT3477 " Maurizio Casciano
2026-08-28 11:21     ` Sakari Ailus
2026-08-28 13:24       ` Andy Shevchenko
2026-08-28 13:31         ` Andy Shevchenko
2026-08-27 18:17   ` [PATCH v2 06/11] media: intel: ipu-bridge: Add Yoga Book camera sensors Maurizio Casciano
2026-08-27 18:17   ` [PATCH v2 07/11] media: atomisp: Add Yoga Book camera configuration Maurizio Casciano
2026-08-27 18:17   ` [PATCH v2 08/11] media: atomisp: support the Yoga Book OV2740 link Maurizio Casciano
2026-08-27 19:57     ` Andy Shevchenko
2026-08-28 11:37     ` Sakari Ailus
2026-08-28 11:42     ` Sakari Ailus
2026-08-27 18:17   ` [PATCH v2 09/11] media: ov2740: add manual white balance controls Maurizio Casciano
2026-08-27 20:03     ` Andy Shevchenko
2026-08-27 18:17   ` [PATCH v2 10/11] media: atomisp: allow raw Bayer capture Maurizio Casciano
2026-08-27 20:24     ` Andy Shevchenko
2026-08-27 18:17   ` [PATCH v2 11/11] media: i2c: Add WV517S lens actuator driver Maurizio Casciano
2026-08-27 20:31     ` Andy Shevchenko
2026-08-27 18:58   ` [PATCH v2 00/11] media: Add Lenovo Yoga Book YB1-X91 camera support Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260826132256.3343451-9-mauriziocasciano7@gmail.com \
    --to=mauriziocasciano7@gmail.com \
    --cc=andy@kernel.org \
    --cc=bingbu.cao@amd.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hansg@kernel.org \
    --cc=jacopo.mondi@ideasonboard.com \
    --cc=jmmartinf@hotmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-staging@lists.linux.dev \
    --cc=mchehab@kernel.org \
    --cc=nicholas@rothemail.net \
    --cc=sakari.ailus@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox