* [PATCH v3 1/3] regulator: dt-bindings: willsemi,wl2868c: add the WL2868C camera PMIC
2026-10-31 3:42 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Qianhui Xu
@ 2026-10-31 3:42 ` Qianhui Xu
2026-10-31 3:42 ` [PATCH v3 2/3] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver Qianhui Xu
` (3 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 3:42 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Bjorn Andersson,
devicetree, linux-kernel, linux-arm-msm
The WL2868C is an I2C-controlled camera power management IC from Will
Semiconductor. It provides seven programmable LDOs: LDO1 and LDO2 are
fed from a shared VIN12 input and cover 0.496 V to 1.512 V, LDO3 and
LDO4 share VIN34, and LDO5 to LDO7 each have their own input, covering
1.504 V to 3.544 V. All outputs are programmable in 8 mV steps and are
gated by per-output enable bits with a chip-wide SYS_EN master. The
chip also exposes an optional active-low RST_N input.
Its user on the Lenovo Legion Tab (TB322FC, SM8750) is the camera
subsystem: the rear samsung,s5kjns sensor takes DVDD from LDO1, AVDD
from LDO4 and DOVDD from LDO7, the front galaxycore,gc08a8 sensor
takes DVDD from LDO2, AVDD from LDO3 and DOVDD from LDO7, and the
rear giantec,gt9764 voice coil motor takes VDD from LDO5 and VDDIO
from LDO7. The third patch of this series describes the board wiring
that carries these eight supply references; LDO6 is the only unused
output.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
.../bindings/regulator/willsemi,wl2868c.yaml | 79 +++++++++++++++++++
MAINTAINERS | 6 ++
2 files changed, 85 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml b/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
new file mode 100644
index 0000000000..96541870cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/willsemi,wl2868c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Will Semiconductor WL2868C camera power management IC
+
+maintainers:
+ - Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+
+description:
+ The WL2868C is a camera power management IC with seven programmable LDOs.
+ LDO1 and LDO2 share the VIN12 input and cover 0.496 V to 1.512 V; LDO3 and
+ LDO4 share VIN34, and LDO5 to LDO7 have one input each, covering 1.504 V to
+ 3.544 V. All outputs are programmable in 8 mV steps.
+
+properties:
+ compatible:
+ const: willsemi,wl2868c
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+ description: Active-low RST_N input.
+
+ vin12-supply:
+ description: Input supply for LDO1 and LDO2.
+
+ vin34-supply:
+ description: Input supply for LDO3 and LDO4.
+
+ vin5-supply:
+ description: Input supply for LDO5.
+
+ vin6-supply:
+ description: Input supply for LDO6.
+
+ vin7-supply:
+ description: Input supply for LDO7.
+
+ regulators:
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ "^ldo[1-7]$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - regulators
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@2f {
+ compatible = "willsemi,wl2868c";
+ reg = <0x2f>;
+
+ regulators {
+ ldo1 {
+ regulator-max-microvolt = <1128000>;
+ regulator-min-microvolt = <1128000>;
+ };
+ };
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index f53047aa8d..632b17b3ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29413,6 +29413,12 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-wiimote*
+WILLSEMI WL2868C CAMERA PMIC
+M: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
+
WILOCITY WIL6210 WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v3 2/3] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver
2026-10-31 3:42 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Qianhui Xu
2026-10-31 3:42 ` [PATCH v3 1/3] regulator: dt-bindings: willsemi,wl2868c: add the WL2868C camera PMIC Qianhui Xu
@ 2026-10-31 3:42 ` Qianhui Xu
2026-10-31 3:43 ` [PATCH v3 3/3] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators Qianhui Xu
` (2 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 3:42 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Bjorn Andersson,
devicetree, linux-kernel, linux-arm-msm
The WL2868C is an I2C camera power management IC with seven LDOs.
LDO1 and LDO2 are fed from VIN12 and cover 0.496 V to 1.512 V with a
7-bit voltage selector; LDO3 and LDO4 share VIN34, and LDO5 to LDO7
have one input each, covering 1.504 V to 3.544 V with an 8-bit
selector. All outputs step by 8 mV.
Every output is gated by a per-LDO bit in the enable register, and the
whole chip is additionally gated by the SYS_EN bit in the same
register. The driver sets SYS_EN together with the LDO bit on enable
and requires both to read back before reporting the regulator as
enabled, because no output comes up while SYS_EN is clear. An
optional active-low RST_N GPIO is released during probe, followed by
a 1 ms delay for the device to come up, and is asserted again when
the driver is unbound.
The device is used on the Lenovo Legion Tab (TB322FC, SM8750): the
rear camera (samsung,s5kjns) takes DVDD from LDO1, AVDD from LDO4 and
DOVDD from LDO7, the front camera (galaxycore,gc08a8) takes DVDD from
LDO2, AVDD from LDO3 and DOVDD from LDO7, and the rear VCM
(giantec,gt9764) takes VDD from LDO5 and VDDIO from LDO7. The next
patch wires these supplies up in the board file.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
MAINTAINERS | 1 +
drivers/regulator/Kconfig | 11 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/wl2868c-regulator.c | 155 ++++++++++++++++++++++++++
4 files changed, 168 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 632b17b3ea..a334308798 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29418,6 +29418,7 @@ M: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
L: linux-kernel@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
+F: drivers/regulator/wl2868c-regulator.c
WILOCITY WIL6210 WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 89789ac7a7..53f5b1527f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1858,6 +1858,17 @@ config REGULATOR_VQMMC_IPQ4019
This driver provides support for the VQMMC LDO I/0
voltage regulator of the IPQ4019 SD/EMMC controller.
+config REGULATOR_WL2868C
+ tristate "Will Semiconductor WL2868C regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Support the seven LDO outputs of the Will Semiconductor WL2868C
+ camera power management IC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wl2868c-regulator.
+
config REGULATOR_WM831X
tristate "Wolfson Microelectronics WM831x PMIC regulators"
depends on MFD_WM831X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5a764cec8d..d706959588 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -212,6 +212,7 @@ obj-$(CONFIG_REGULATOR_RZG2L_VBCTRL) += renesas-usb-vbus-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += vqmmc-ipq4019-regulator.o
+obj-$(CONFIG_REGULATOR_WL2868C) += wl2868c-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
diff --git a/drivers/regulator/wl2868c-regulator.c b/drivers/regulator/wl2868c-regulator.c
new file mode 100644
index 0000000000..9c4f4240b1
--- /dev/null
+++ b/drivers/regulator/wl2868c-regulator.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Will Semiconductor WL2868C seven-channel camera regulator driver.
+ *
+ * Copyright (C) 2026 Qianhui Xu
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define WL2868C_DEVICE_ID 0x00
+#define WL2868C_DEVICE_ID_VALUE 0x82
+#define WL2868C_LDO_ENABLE 0x0e
+#define WL2868C_SYS_ENABLE BIT(7)
+
+static int wl2868c_enable(struct regulator_dev *rdev)
+{
+ /*
+ * SYS_EN is the master enable of the chip: no output comes up unless
+ * it is set together with the per-LDO bit.
+ */
+ return regmap_update_bits(rdev->regmap, WL2868C_LDO_ENABLE,
+ WL2868C_SYS_ENABLE | rdev->desc->enable_mask,
+ WL2868C_SYS_ENABLE | rdev->desc->enable_mask);
+}
+
+static int wl2868c_is_enabled(struct regulator_dev *rdev)
+{
+ unsigned int mask = WL2868C_SYS_ENABLE | rdev->desc->enable_mask;
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, WL2868C_LDO_ENABLE, &value);
+ if (ret)
+ return ret;
+
+ return (value & mask) == mask;
+}
+
+static const struct regulator_ops wl2868c_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = wl2868c_enable,
+ .disable = regulator_disable_regmap,
+ .is_enabled = wl2868c_is_enabled,
+};
+
+/*
+ * LDO1 and LDO2 have a 7-bit voltage selector, the other five have an 8-bit
+ * one; all of them step by 8 mV.
+ */
+#define WL2868C_LDO(_num, _supply, _min, _n_voltages, _vsel_reg, _mask, _en) { \
+ .name = "ldo" #_num, \
+ .of_match = "ldo" #_num, \
+ .regulators_node = "regulators", \
+ .id = (_num) - 1, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .ops = &wl2868c_ops, \
+ .supply_name = _supply, \
+ .min_uV = _min, \
+ .uV_step = 8000, \
+ .n_voltages = _n_voltages, \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _mask, \
+ .enable_reg = WL2868C_LDO_ENABLE, \
+ .enable_mask = _en, \
+ .enable_time = 150, \
+}
+
+static const struct regulator_desc wl2868c_regulators[] = {
+ WL2868C_LDO(1, "vin12", 496000, 128, 0x03, 0x7f, BIT(0)),
+ WL2868C_LDO(2, "vin12", 496000, 128, 0x04, 0x7f, BIT(1)),
+ WL2868C_LDO(3, "vin34", 1504000, 256, 0x05, 0xff, BIT(2)),
+ WL2868C_LDO(4, "vin34", 1504000, 256, 0x06, 0xff, BIT(3)),
+ WL2868C_LDO(5, "vin5", 1504000, 256, 0x07, 0xff, BIT(4)),
+ WL2868C_LDO(6, "vin6", 1504000, 256, 0x08, 0xff, BIT(5)),
+ WL2868C_LDO(7, "vin7", 1504000, 256, 0x09, 0xff, BIT(6)),
+};
+
+static const struct regmap_config wl2868c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x25,
+};
+
+static void wl2868c_reset(void *data)
+{
+ gpiod_set_value_cansleep(data, 1);
+}
+
+static int wl2868c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct regulator_config config = { .dev = dev };
+ struct regulator_dev *rdev;
+ struct gpio_desc *reset;
+ unsigned int id;
+ int ret, i;
+
+ reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset))
+ return dev_err_probe(dev, PTR_ERR(reset), "Failed to get reset GPIO\n");
+
+ if (reset) {
+ ret = devm_add_action_or_reset(dev, wl2868c_reset, reset);
+ if (ret)
+ return ret;
+ fsleep(1000);
+ }
+
+ config.regmap = devm_regmap_init_i2c(client, &wl2868c_regmap_config);
+ if (IS_ERR(config.regmap))
+ return dev_err_probe(dev, PTR_ERR(config.regmap),
+ "Failed to create regmap\n");
+
+ ret = regmap_read(config.regmap, WL2868C_DEVICE_ID, &id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read device ID\n");
+ if (id != WL2868C_DEVICE_ID_VALUE)
+ return dev_err_probe(dev, -ENODEV, "Unexpected device ID: %#x\n", id);
+
+ for (i = 0; i < ARRAY_SIZE(wl2868c_regulators); i++) {
+ rdev = devm_regulator_register(dev, &wl2868c_regulators[i], &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register LDO%d\n", i + 1);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id wl2868c_of_match[] = {
+ { .compatible = "willsemi,wl2868c" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wl2868c_of_match);
+
+static struct i2c_driver wl2868c_driver = {
+ .driver = {
+ .name = "wl2868c",
+ .of_match_table = wl2868c_of_match,
+ },
+ .probe = wl2868c_probe,
+};
+module_i2c_driver(wl2868c_driver);
+
+MODULE_DESCRIPTION("Will Semiconductor WL2868C regulator driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v3 3/3] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators
2026-10-31 3:42 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Qianhui Xu
2026-10-31 3:42 ` [PATCH v3 1/3] regulator: dt-bindings: willsemi,wl2868c: add the WL2868C camera PMIC Qianhui Xu
2026-10-31 3:42 ` [PATCH v3 2/3] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver Qianhui Xu
@ 2026-10-31 3:43 ` Qianhui Xu
[not found] ` <sashiko-outbox-191739@kernel.org>
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
2026-11-01 22:40 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Mark Brown
4 siblings, 1 reply; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 3:43 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Bjorn Andersson,
devicetree, linux-kernel, linux-arm-msm
The Lenovo Legion Tab (TB322FC) is an SM8750 tablet. Its camera
devices are powered by a WL2868C camera PMIC on i2c10: LDO1 feeds the
rear sensor DVDD, LDO2 the front sensor DVDD, LDO3 the front sensor
AVDD, LDO4 the rear sensor AVDD, LDO5 the VCM VDD, LDO7 the DOVDD of
both sensors and the VCM VDDIO, all at fixed voltages including the
offsets programmed by the stock firmware. LDO6 is not wired out on
this board.
The camera devices hang off the two CCI I2C controllers, which the
SM8750 dtsi does not describe yet, so add them alongside. The sensors
are described with their supplies only for now; the CSI endpoints
will be added together with the camera subsystem.
The board clocks (XO, sleep clock and the two divided CXO derivatives)
that the SM8750 dtsi consumes are described here, as done on the other
SM8750 boards, and the board compatible is added to qcom.yaml.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
.../devicetree/bindings/arm/qcom.yaml | 1 +
arch/arm64/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/sm8750-lenovo-elden.dts | 202 ++++++++++++++++++
arch/arm64/boot/dts/qcom/sm8750.dtsi | 112 ++++++++++
4 files changed, 316 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index ff8a35df78..41d5e65c4e 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -1168,6 +1168,7 @@ properties:
- items:
- enum:
+ - lenovo,elden
- qcom,sm8750-mtp
- qcom,sm8750-qrd
- const: qcom,sm8750
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 1c86e7e98f..a18fea7beb 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -406,6 +406,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8650-hdk-rear-camera-card.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-hdk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm8750-lenovo-elden.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8750-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8750-qrd.dtb
dtb-$(CONFIG_ARCH_QCOM) += talos-evk.dtb
diff --git a/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts b/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
new file mode 100644
index 0000000000..7bbc1986a8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026, Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "sm8750.dtsi"
+
+/ {
+ model = "Lenovo Legion Y700 Gen4";
+ compatible = "lenovo,elden", "qcom,sm8750";
+ chassis-type = "tablet";
+
+ clocks {
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ clock-frequency = <76800000>;
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+
+ bi_tcxo_div2: bi-tcxo-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+
+ bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK_A>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+ };
+};
+
+&cci0 {
+ status = "okay";
+};
+
+&cci0_i2c0 {
+ clock-frequency = <400000>;
+
+ rear_lens: lens@c {
+ compatible = "giantec,gt9764";
+ reg = <0x0c>;
+ vddio-supply = <&camera_ldo7>;
+ vdd-supply = <&camera_ldo5>;
+ giantec,aac-mode = <0x40>;
+ giantec,aac-timing = <0x7c>;
+ settling-time-us = <7000>;
+ };
+
+ rear_camera: camera@56 {
+ compatible = "samsung,s5kjns";
+ reg = <0x56>;
+ clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK3_CLK>;
+ assigned-clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK3_CLK>;
+ assigned-clock-rates = <19200000>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ reset-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rear_camera_default>;
+ dovdd-supply = <&camera_ldo7>;
+ dvdd-supply = <&camera_ldo1>;
+ avdd-supply = <&camera_ldo4>;
+ lens-focus = <&rear_lens>;
+ orientation = <1>;
+ rotation = <90>;
+ };
+};
+
+&cci1 {
+ status = "okay";
+};
+
+&cci1_i2c0 {
+ clock-frequency = <400000>;
+
+ front_camera: camera@31 {
+ compatible = "galaxycore,gc08a8";
+ reg = <0x31>;
+ clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK4_CLK>;
+ assigned-clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK4_CLK>;
+ assigned-clock-rates = <19200000>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ reset-gpios = <&tlmm 7 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&front_camera_default>;
+ dovdd-supply = <&camera_ldo7>;
+ dvdd-supply = <&camera_ldo2>;
+ avdd-supply = <&camera_ldo3>;
+ orientation = <0>;
+ rotation = <270>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+
+ pmic@2f {
+ compatible = "willsemi,wl2868c";
+ reg = <0x2f>;
+ reset-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_pmic_default>;
+
+ regulators {
+ /* Voltages include the offsets programmed by stock firmware. */
+ camera_ldo1: ldo1 {
+ regulator-name = "camera_ldo1";
+ regulator-min-microvolt = <1128000>;
+ regulator-max-microvolt = <1128000>;
+ };
+
+ camera_ldo2: ldo2 {
+ regulator-name = "camera_ldo2";
+ regulator-min-microvolt = <1288000>;
+ regulator-max-microvolt = <1288000>;
+ };
+
+ camera_ldo3: ldo3 {
+ regulator-name = "camera_ldo3";
+ regulator-min-microvolt = <2816000>;
+ regulator-max-microvolt = <2816000>;
+ };
+
+ camera_ldo4: ldo4 {
+ regulator-name = "camera_ldo4";
+ regulator-min-microvolt = <2824000>;
+ regulator-max-microvolt = <2824000>;
+ };
+
+ camera_ldo5: ldo5 {
+ regulator-name = "camera_ldo5";
+ regulator-min-microvolt = <2808000>;
+ regulator-max-microvolt = <2808000>;
+ };
+
+ /* LDO6 is not wired out on this board. */
+ camera_ldo7: ldo7 {
+ regulator-name = "camera_ldo7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <39 1>, <74 1>;
+
+ camera_pmic_default: camera-pmic-default-state {
+ pins = "gpio126";
+ function = "gpio";
+ bias-disable;
+ };
+
+ rear_camera_default: rear-camera-default-state {
+ mclk-pins {
+ pins = "gpio92";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ reset-pins {
+ pins = "gpio11";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ front_camera_default: front-camera-default-state {
+ mclk-pins {
+ pins = "gpio93";
+ function = "cam_aon_mclk4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ reset-pins {
+ pins = "gpio7";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index dd738d13df..60b8f2fb5a 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -3512,6 +3512,72 @@ camcc: clock-controller@ade0000 {
#power-domain-cells = <1>;
};
+ cci0: cci@ac7b000 {
+ compatible = "qcom,sm8750-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0ac7b000 0x0 0x1000>;
+ interrupts = <GIC_SPI 426 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_0_CLK>;
+ clock-names = "ahb", "cci";
+ assigned-clocks = <&camcc CAM_CC_CCI_0_CLK>;
+ assigned-clock-rates = <37500000>;
+ pinctrl-0 = <&cci0_0_default>;
+ pinctrl-1 = <&cci0_0_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci0_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci0_i2c1: i2c-bus@1 {
+ status = "disabled";
+ reg = <1>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ cci1: cci@ac7c000 {
+ compatible = "qcom,sm8750-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0ac7c000 0x0 0x1000>;
+ interrupts = <GIC_SPI 427 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_1_CLK>;
+ clock-names = "ahb", "cci";
+ assigned-clocks = <&camcc CAM_CC_CCI_1_CLK>;
+ assigned-clock-rates = <37500000>;
+ pinctrl-0 = <&cci1_0_default>;
+ pinctrl-1 = <&cci1_0_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci1_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci1_i2c1: i2c-bus@1 {
+ status = "disabled";
+ reg = <1>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8750-pdc", "qcom,pdc";
reg = <0x0 0x0b220000 0x0 0x10000>, <0x0 0x164400f0 0x0 0x64>;
@@ -4090,6 +4156,52 @@ qup_uart15_default: qup-uart15-default-state {
bias-pull-up;
};
+ cci0_0_default: cci0-0-default-state {
+ sda-pins {
+ pins = "gpio113";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio114";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci0_0_sleep: cci0-0-sleep-state {
+ pins = "gpio113", "gpio114";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci1_0_default: cci1-0-default-state {
+ sda-pins {
+ pins = "gpio117";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio118";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci1_0_sleep: cci1-0-sleep-state {
+ pins = "gpio117", "gpio118";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
sdc2_sleep: sdc2-sleep-state {
clk-pins {
pins = "sdc2_clk";
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC
2026-10-31 3:42 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Qianhui Xu
` (2 preceding siblings ...)
2026-10-31 3:43 ` [PATCH v3 3/3] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators Qianhui Xu
@ 2026-10-31 6:55 ` Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 1/4] regulator: dt-bindings: willsemi,wl2868c: add the " Qianhui Xu
` (3 more replies)
2026-11-01 22:40 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Mark Brown
4 siblings, 4 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 6:55 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
The WL2868C is the camera PMIC on the Lenovo Legion Tab (TB322FC,
SM8750); its seven LDOs feed the rear camera, the front camera and the
VCM on i2c10.
v3 was reviewed by sashiko and Krzysztof; what changed, point by point:
- i2c10 was enabled while its parents were not, so the bus could never
populate and none of the regulators it hosts could have registered.
The board DTS now enables qupv3_2 and gpi_dma2 alongside i2c10
(sashiko, High).
- The binding schema, the SoC dtsi and the board DTS were mixed in the
board patch. The series is now one binding patch (including the
arm/qcom.yaml registration), one driver patch, one sm8750.dtsi patch
and one board DTS patch (sashiko, Low; checkpatch flagged the same
thing).
- The sm8750.dtsi patch now leaves both I2C buses of each CCI
controller available instead of disabling bus 1, as sm8550.dtsi and
sm8650.dtsi do, and carries the bus 1 pinctrl states on gpio115/116
and gpio119/120 (sashiko, Low).
- The CCI nodes moved after videocc@aaf0000 into unit-address order,
and the new pinctrl states sit alphabetically inside &tlmm (sashiko,
Low).
- The commit message now says that the SoC has three CCI controllers
of which two are described, instead of "the two CCI I2C
controllers" (sashiko, Low).
- The front galaxycore,gc08a8 node is dropped: it has no binding at
all, unlike samsung,s5kjns and giantec,gt9764, whose bindings were
posted separately and are still in review. LDO2 and LDO3 stay wired
in the board file for when that series lands. The sensor nodes also
lost their power-domains property: the TITAN_TOP GDSC belongs to the
camera controller that owns the CCI bus, not to an I2C sensor, which
is powered through its supplies and its reset GPIO (sashiko,
Medium). The rear sensor gained its CSI-2 endpoint; the
remote-endpoint side arrives with the camera subsystem series.
Everything above is host-side only. The i2c10 probe and the runtime
existence of the regulators are still unverified on hardware; the
on-board evidence reported earlier (i2c-10 present, camera_ldo1..5,7
registered, LDO6 without consumer) comes from our own downstream board
DTS, not from the files in this series.
Qianhui Xu (4):
regulator: dt-bindings: willsemi,wl2868c: add the WL2868C camera PMIC
regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver
arm64: dts: qcom: sm8750: describe two of the three CCI I2C
controllers
arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators
.../devicetree/bindings/arm/qcom.yaml | 1 +
.../bindings/regulator/willsemi,wl2868c.yaml | 79 ++++++++
MAINTAINERS | 7 +
arch/arm64/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/sm8750-lenovo-elden.dts | 175 ++++++++++++++++++
arch/arm64/boot/dts/qcom/sm8750.dtsi | 158 ++++++++++++++++
drivers/regulator/Kconfig | 11 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/wl2868c-regulator.c | 155 ++++++++++++++++
9 files changed, 588 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
create mode 100644 arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
create mode 100644 drivers/regulator/wl2868c-regulator.c
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v4 1/4] regulator: dt-bindings: willsemi,wl2868c: add the WL2868C camera PMIC
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
@ 2026-10-31 6:55 ` Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 2/4] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver Qianhui Xu
` (2 subsequent siblings)
3 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 6:55 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
The WL2868C is an I2C-controlled camera power management IC from Will
Semiconductor. It provides seven programmable LDOs: LDO1 and LDO2 are
fed from a shared VIN12 input and cover 0.496 V to 1.512 V, LDO3 and
LDO4 share VIN34, and LDO5 to LDO7 each have their own input, covering
1.504 V to 3.544 V. All outputs are programmable in 8 mV steps and are
gated by per-output enable bits with a chip-wide SYS_EN master. The
chip also exposes an optional active-low RST_N input.
Its user on the Lenovo Legion Tab (TB322FC, SM8750) is the camera
subsystem: the rear samsung,s5kjns sensor takes DVDD from LDO1, AVDD
from LDO4 and DOVDD from LDO7, and the rear giantec,gt9764 voice coil
motor takes VDD from LDO5 and VDDIO from LDO7. The front sensor is
powered from LDO2, LDO3 and LDO7, but its binding is still pending, so
its supply wiring follows with that series. The board DTS patch of this
series describes the supply wiring that is documented; LDO6 is the only
output with no user on this board.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
.../devicetree/bindings/arm/qcom.yaml | 1 +
.../bindings/regulator/willsemi,wl2868c.yaml | 79 +++++++++++++++++++
2 files changed, 80 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index ff8a35df78..41d5e65c4e 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -1168,6 +1168,7 @@ properties:
- items:
- enum:
+ - lenovo,elden
- qcom,sm8750-mtp
- qcom,sm8750-qrd
- const: qcom,sm8750
diff --git a/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml b/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
new file mode 100644
index 0000000000..96541870cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/willsemi,wl2868c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Will Semiconductor WL2868C camera power management IC
+
+maintainers:
+ - Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+
+description:
+ The WL2868C is a camera power management IC with seven programmable LDOs.
+ LDO1 and LDO2 share the VIN12 input and cover 0.496 V to 1.512 V; LDO3 and
+ LDO4 share VIN34, and LDO5 to LDO7 have one input each, covering 1.504 V to
+ 3.544 V. All outputs are programmable in 8 mV steps.
+
+properties:
+ compatible:
+ const: willsemi,wl2868c
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+ description: Active-low RST_N input.
+
+ vin12-supply:
+ description: Input supply for LDO1 and LDO2.
+
+ vin34-supply:
+ description: Input supply for LDO3 and LDO4.
+
+ vin5-supply:
+ description: Input supply for LDO5.
+
+ vin6-supply:
+ description: Input supply for LDO6.
+
+ vin7-supply:
+ description: Input supply for LDO7.
+
+ regulators:
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ "^ldo[1-7]$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - regulators
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@2f {
+ compatible = "willsemi,wl2868c";
+ reg = <0x2f>;
+
+ regulators {
+ ldo1 {
+ regulator-max-microvolt = <1128000>;
+ regulator-min-microvolt = <1128000>;
+ };
+ };
+ };
+ };
+...
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v4 2/4] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 1/4] regulator: dt-bindings: willsemi,wl2868c: add the " Qianhui Xu
@ 2026-10-31 6:55 ` Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 3/4] arm64: dts: qcom: sm8750: describe two of the three CCI I2C controllers Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 4/4] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators Qianhui Xu
3 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 6:55 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
The WL2868C is an I2C camera power management IC with seven LDOs.
LDO1 and LDO2 are fed from VIN12 and cover 0.496 V to 1.512 V with a
7-bit voltage selector; LDO3 and LDO4 share VIN34, and LDO5 to LDO7
have one input each, covering 1.504 V to 3.544 V with an 8-bit
selector. All outputs step by 8 mV.
Every output is gated by a per-LDO bit in the enable register, and the
whole chip is additionally gated by the SYS_EN bit in the same
register. The driver sets SYS_EN together with the LDO bit on enable
and requires both to read back before reporting the regulator as
enabled, because no output comes up while SYS_EN is clear. An
optional active-low RST_N GPIO is released during probe, followed by
a 1 ms delay for the device to come up, and is asserted again when
the driver is unbound.
The device is used on the Lenovo Legion Tab (TB322FC, SM8750): the
rear camera (samsung,s5kjns) takes DVDD from LDO1, AVDD from LDO4 and
DOVDD from LDO7, and the rear VCM (giantec,gt9764) takes VDD from LDO5
and VDDIO from LDO7. The front sensor takes DVDD from LDO2, AVDD from
LDO3 and DOVDD from LDO7, and its supply wiring follows with its
pending binding series. The next patch wires the documented supplies
up in the board file.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
MAINTAINERS | 7 ++
drivers/regulator/Kconfig | 11 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/wl2868c-regulator.c | 155 ++++++++++++++++++++++++++
4 files changed, 174 insertions(+)
create mode 100644 drivers/regulator/wl2868c-regulator.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f53047aa8d..a334308798 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29413,6 +29413,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-wiimote*
+WILLSEMI WL2868C CAMERA PMIC
+M: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/regulator/willsemi,wl2868c.yaml
+F: drivers/regulator/wl2868c-regulator.c
+
WILOCITY WIL6210 WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 89789ac7a7..53f5b1527f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1858,6 +1858,17 @@ config REGULATOR_VQMMC_IPQ4019
This driver provides support for the VQMMC LDO I/0
voltage regulator of the IPQ4019 SD/EMMC controller.
+config REGULATOR_WL2868C
+ tristate "Will Semiconductor WL2868C regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Support the seven LDO outputs of the Will Semiconductor WL2868C
+ camera power management IC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wl2868c-regulator.
+
config REGULATOR_WM831X
tristate "Wolfson Microelectronics WM831x PMIC regulators"
depends on MFD_WM831X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5a764cec8d..d706959588 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -212,6 +212,7 @@ obj-$(CONFIG_REGULATOR_RZG2L_VBCTRL) += renesas-usb-vbus-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += vqmmc-ipq4019-regulator.o
+obj-$(CONFIG_REGULATOR_WL2868C) += wl2868c-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
diff --git a/drivers/regulator/wl2868c-regulator.c b/drivers/regulator/wl2868c-regulator.c
new file mode 100644
index 0000000000..9c4f4240b1
--- /dev/null
+++ b/drivers/regulator/wl2868c-regulator.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Will Semiconductor WL2868C seven-channel camera regulator driver.
+ *
+ * Copyright (C) 2026 Qianhui Xu
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define WL2868C_DEVICE_ID 0x00
+#define WL2868C_DEVICE_ID_VALUE 0x82
+#define WL2868C_LDO_ENABLE 0x0e
+#define WL2868C_SYS_ENABLE BIT(7)
+
+static int wl2868c_enable(struct regulator_dev *rdev)
+{
+ /*
+ * SYS_EN is the master enable of the chip: no output comes up unless
+ * it is set together with the per-LDO bit.
+ */
+ return regmap_update_bits(rdev->regmap, WL2868C_LDO_ENABLE,
+ WL2868C_SYS_ENABLE | rdev->desc->enable_mask,
+ WL2868C_SYS_ENABLE | rdev->desc->enable_mask);
+}
+
+static int wl2868c_is_enabled(struct regulator_dev *rdev)
+{
+ unsigned int mask = WL2868C_SYS_ENABLE | rdev->desc->enable_mask;
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, WL2868C_LDO_ENABLE, &value);
+ if (ret)
+ return ret;
+
+ return (value & mask) == mask;
+}
+
+static const struct regulator_ops wl2868c_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = wl2868c_enable,
+ .disable = regulator_disable_regmap,
+ .is_enabled = wl2868c_is_enabled,
+};
+
+/*
+ * LDO1 and LDO2 have a 7-bit voltage selector, the other five have an 8-bit
+ * one; all of them step by 8 mV.
+ */
+#define WL2868C_LDO(_num, _supply, _min, _n_voltages, _vsel_reg, _mask, _en) { \
+ .name = "ldo" #_num, \
+ .of_match = "ldo" #_num, \
+ .regulators_node = "regulators", \
+ .id = (_num) - 1, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .ops = &wl2868c_ops, \
+ .supply_name = _supply, \
+ .min_uV = _min, \
+ .uV_step = 8000, \
+ .n_voltages = _n_voltages, \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _mask, \
+ .enable_reg = WL2868C_LDO_ENABLE, \
+ .enable_mask = _en, \
+ .enable_time = 150, \
+}
+
+static const struct regulator_desc wl2868c_regulators[] = {
+ WL2868C_LDO(1, "vin12", 496000, 128, 0x03, 0x7f, BIT(0)),
+ WL2868C_LDO(2, "vin12", 496000, 128, 0x04, 0x7f, BIT(1)),
+ WL2868C_LDO(3, "vin34", 1504000, 256, 0x05, 0xff, BIT(2)),
+ WL2868C_LDO(4, "vin34", 1504000, 256, 0x06, 0xff, BIT(3)),
+ WL2868C_LDO(5, "vin5", 1504000, 256, 0x07, 0xff, BIT(4)),
+ WL2868C_LDO(6, "vin6", 1504000, 256, 0x08, 0xff, BIT(5)),
+ WL2868C_LDO(7, "vin7", 1504000, 256, 0x09, 0xff, BIT(6)),
+};
+
+static const struct regmap_config wl2868c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x25,
+};
+
+static void wl2868c_reset(void *data)
+{
+ gpiod_set_value_cansleep(data, 1);
+}
+
+static int wl2868c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct regulator_config config = { .dev = dev };
+ struct regulator_dev *rdev;
+ struct gpio_desc *reset;
+ unsigned int id;
+ int ret, i;
+
+ reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset))
+ return dev_err_probe(dev, PTR_ERR(reset), "Failed to get reset GPIO\n");
+
+ if (reset) {
+ ret = devm_add_action_or_reset(dev, wl2868c_reset, reset);
+ if (ret)
+ return ret;
+ fsleep(1000);
+ }
+
+ config.regmap = devm_regmap_init_i2c(client, &wl2868c_regmap_config);
+ if (IS_ERR(config.regmap))
+ return dev_err_probe(dev, PTR_ERR(config.regmap),
+ "Failed to create regmap\n");
+
+ ret = regmap_read(config.regmap, WL2868C_DEVICE_ID, &id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read device ID\n");
+ if (id != WL2868C_DEVICE_ID_VALUE)
+ return dev_err_probe(dev, -ENODEV, "Unexpected device ID: %#x\n", id);
+
+ for (i = 0; i < ARRAY_SIZE(wl2868c_regulators); i++) {
+ rdev = devm_regulator_register(dev, &wl2868c_regulators[i], &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register LDO%d\n", i + 1);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id wl2868c_of_match[] = {
+ { .compatible = "willsemi,wl2868c" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wl2868c_of_match);
+
+static struct i2c_driver wl2868c_driver = {
+ .driver = {
+ .name = "wl2868c",
+ .of_match_table = wl2868c_of_match,
+ },
+ .probe = wl2868c_probe,
+};
+module_i2c_driver(wl2868c_driver);
+
+MODULE_DESCRIPTION("Will Semiconductor WL2868C regulator driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v4 3/4] arm64: dts: qcom: sm8750: describe two of the three CCI I2C controllers
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 1/4] regulator: dt-bindings: willsemi,wl2868c: add the " Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 2/4] regulator: willsemi,wl2868c: add the WL2868C camera PMIC driver Qianhui Xu
@ 2026-10-31 6:55 ` Qianhui Xu
2026-10-31 6:55 ` [PATCH v4 4/4] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators Qianhui Xu
3 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 6:55 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
The SM8750 has three CCI I2C controllers; this dtsi describes the two
that the Qualcomm camera subsystem binds to on this SoC. Each controller
exposes two I2C buses; both buses are described and left available, as
on sm8550 and sm8650, and the second bus pinctrl states are carried for
both controllers (cci0 bus 1 on gpio115/116, cci1 bus 1 on gpio119/120).
The nodes are placed in unit-address order after videocc@aaf0000.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
arch/arm64/boot/dts/qcom/sm8750.dtsi | 158 +++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index dd738d13df..9649af7f6f 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -3060,6 +3060,72 @@ videocc: clock-controller@aaf0000 {
#power-domain-cells = <1>;
};
+ cci0: cci@ac7b000 {
+ compatible = "qcom,sm8750-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0ac7b000 0x0 0x1000>;
+ interrupts = <GIC_SPI 426 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_0_CLK>;
+ clock-names = "ahb", "cci";
+ assigned-clocks = <&camcc CAM_CC_CCI_0_CLK>;
+ assigned-clock-rates = <37500000>;
+ pinctrl-0 = <&cci0_0_default &cci0_1_default>;
+ pinctrl-1 = <&cci0_0_sleep &cci0_1_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci0_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci0_i2c1: i2c-bus@1 {
+ status = "disabled";
+ reg = <1>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ cci1: cci@ac7c000 {
+ compatible = "qcom,sm8750-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0ac7c000 0x0 0x1000>;
+ interrupts = <GIC_SPI 427 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_1_CLK>;
+ clock-names = "ahb", "cci";
+ assigned-clocks = <&camcc CAM_CC_CCI_1_CLK>;
+ assigned-clock-rates = <37500000>;
+ pinctrl-0 = <&cci1_0_default &cci1_1_default>;
+ pinctrl-1 = <&cci1_0_sleep &cci1_1_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci1_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci1_i2c1: i2c-bus@1 {
+ status = "disabled";
+ reg = <1>;
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
mdss: display-subsystem@ae00000 {
compatible = "qcom,sm8750-mdss";
reg = <0x0 0x0ae00000 0x0 0x1000>;
@@ -4090,6 +4156,98 @@ qup_uart15_default: qup-uart15-default-state {
bias-pull-up;
};
+ cci0_0_default: cci0-0-default-state {
+ sda-pins {
+ pins = "gpio113";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio114";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci0_0_sleep: cci0-0-sleep-state {
+ pins = "gpio113", "gpio114";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci1_0_default: cci1-0-default-state {
+ sda-pins {
+ pins = "gpio117";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio118";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci1_0_sleep: cci1-0-sleep-state {
+ pins = "gpio117", "gpio118";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci0_1_default: cci0-1-default-state {
+ sda-pins {
+ pins = "gpio115";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio116";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci0_1_sleep: cci0-1-sleep-state {
+ pins = "gpio115", "gpio116";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ cci1_1_default: cci1-1-default-state {
+ sda-pins {
+ pins = "gpio119";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio120";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci1_1_sleep: cci1-1-sleep-state {
+ pins = "gpio119", "gpio120";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
sdc2_sleep: sdc2-sleep-state {
clk-pins {
pins = "sdc2_clk";
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v4 4/4] arm64: dts: qcom: sm8750-lenovo-elden: describe the WL2868C regulators
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
` (2 preceding siblings ...)
2026-10-31 6:55 ` [PATCH v4 3/4] arm64: dts: qcom: sm8750: describe two of the three CCI I2C controllers Qianhui Xu
@ 2026-10-31 6:55 ` Qianhui Xu
3 siblings, 0 replies; 15+ messages in thread
From: Qianhui Xu @ 2026-10-31 6:55 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
The Lenovo Legion Tab (TB322FC) is an SM8750 tablet. Its camera
devices are powered by a WL2868C camera PMIC on i2c10: LDO1 feeds the
rear sensor DVDD, LDO2 the front sensor DVDD, LDO3 the front sensor
AVDD, LDO4 the rear sensor AVDD, LDO5 the VCM VDD, LDO7 the DOVDD of
both sensors and the VCM VDDIO, all at fixed voltages including the
offsets programmed by the stock firmware. LDO2 and LDO3 are wired to
the front sensor, whose binding is still pending, so its node follows
with that series. LDO6 is not wired out on this board.
The rear camera hangs off cci0 with the VCM. The front camera hangs
off cci1 and arrives together with its binding.
i2c10 is a GENI I2C controller inside the qupv3_2 wrapper, so both
qupv3_2 and its gpi_dma2 parent are enabled alongside, otherwise
i2c10 never populates and the regulators would never register.
The board clocks (XO, sleep clock and the two divided CXO derivatives)
that the SM8750 dtsi consumes are described here, as done on the other
SM8750 boards; the board compatible was registered in the binding
patch of this series.
Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
---
arch/arm64/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/sm8750-lenovo-elden.dts | 175 ++++++++++++++++++
2 files changed, 176 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 1c86e7e98f..a18fea7beb 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -406,6 +406,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8650-hdk-rear-camera-card.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-hdk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm8750-lenovo-elden.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8750-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8750-qrd.dtb
dtb-$(CONFIG_ARCH_QCOM) += talos-evk.dtb
diff --git a/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts b/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
new file mode 100644
index 0000000000..de186b4477
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm8750-lenovo-elden.dts
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026, Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "sm8750.dtsi"
+
+/ {
+ model = "Lenovo Legion Y700 Gen4";
+ compatible = "lenovo,elden", "qcom,sm8750";
+ chassis-type = "tablet";
+
+ clocks {
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ clock-frequency = <76800000>;
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+
+ bi_tcxo_div2: bi-tcxo-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+
+ bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK_A>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+ };
+};
+
+&cci0 {
+ status = "okay";
+};
+
+&cci0_i2c0 {
+ clock-frequency = <400000>;
+
+ rear_lens: lens@c {
+ compatible = "giantec,gt9764";
+ reg = <0x0c>;
+ vddio-supply = <&camera_ldo7>;
+ vdd-supply = <&camera_ldo5>;
+ giantec,aac-mode = <0x40>;
+ giantec,aac-timing = <0x7c>;
+ settling-time-us = <7000>;
+ };
+
+ rear_camera: camera@56 {
+ compatible = "samsung,s5kjns";
+ reg = <0x56>;
+ clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK3_CLK>;
+ assigned-clocks = <&cambistmclkcc CAM_BIST_MCLK_CC_MCLK3_CLK>;
+ assigned-clock-rates = <19200000>;
+ reset-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rear_camera_default>;
+ dovdd-supply = <&camera_ldo7>;
+ dvdd-supply = <&camera_ldo1>;
+ avdd-supply = <&camera_ldo4>;
+ lens-focus = <&rear_lens>;
+ orientation = <1>;
+ rotation = <90>;
+
+ port {
+ rear_camera_ep: endpoint {
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <672000000>;
+ };
+ };
+ };
+};
+
+&gpi_dma2 {
+ status = "okay";
+};
+
+&qupv3_2 {
+ status = "okay";
+};
+
+&i2c10 {
+ status = "okay";
+
+ pmic@2f {
+ compatible = "willsemi,wl2868c";
+ reg = <0x2f>;
+ reset-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&camera_pmic_default>;
+
+ regulators {
+ /* Voltages include the offsets programmed by stock firmware. */
+ camera_ldo1: ldo1 {
+ regulator-name = "camera_ldo1";
+ regulator-min-microvolt = <1128000>;
+ regulator-max-microvolt = <1128000>;
+ };
+
+ camera_ldo2: ldo2 {
+ regulator-name = "camera_ldo2";
+ regulator-min-microvolt = <1288000>;
+ regulator-max-microvolt = <1288000>;
+ };
+
+ camera_ldo3: ldo3 {
+ regulator-name = "camera_ldo3";
+ regulator-min-microvolt = <2816000>;
+ regulator-max-microvolt = <2816000>;
+ };
+
+ camera_ldo4: ldo4 {
+ regulator-name = "camera_ldo4";
+ regulator-min-microvolt = <2824000>;
+ regulator-max-microvolt = <2824000>;
+ };
+
+ camera_ldo5: ldo5 {
+ regulator-name = "camera_ldo5";
+ regulator-min-microvolt = <2808000>;
+ regulator-max-microvolt = <2808000>;
+ };
+
+ /* LDO6 is not wired out on this board. */
+ camera_ldo7: ldo7 {
+ regulator-name = "camera_ldo7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <39 1>, <74 1>;
+
+ camera_pmic_default: camera-pmic-default-state {
+ pins = "gpio126";
+ function = "gpio";
+ bias-disable;
+ };
+
+ rear_camera_default: rear-camera-default-state {
+ mclk-pins {
+ pins = "gpio92";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ reset-pins {
+ pins = "gpio11";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+};
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users
2026-10-31 3:42 ` [PATCH v3 0/3] regulator: add the WL2868C camera PMIC and its users Qianhui Xu
` (3 preceding siblings ...)
2026-10-31 6:55 ` [PATCH v4 0/4] regulator: add the Will Semiconductor WL2868C camera PMIC Qianhui Xu
@ 2026-11-01 22:40 ` Mark Brown
4 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2026-11-01 22:40 UTC (permalink / raw)
To: Qianhui Xu
Cc: Liam Girdwood, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
Bjorn Andersson, devicetree, linux-kernel, linux-arm-msm
[-- Attachment #1: Type: text/plain, Size: 727 bytes --]
On Sat, Oct 31, 2026 at 11:42:57AM +0800, Qianhui Xu wrote:
> regulator: add the WL2868C camera PMIC and its users
>
> Hi all,
>
> this series adds a driver for the WL2868C camera PMIC found on the Lenovo
> Legion Tab (TB322FC / "elden", SM8750). The chip is an I2C regulator with
> seven LDOs; on this board eight supplies are wired to the camera stack
> (S5KJNS sensor, GC08A8 sensor, GT9764 VCM, and the CSIPHY rails).
Please don't send new patches in reply to old patches or serieses, this
makes it harder for both people and tools to understand what is going
on - it can bury things in mailboxes and make it difficult to keep track
of what current patches are, both for the new patches and the old ones.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread