Release develop 251108

This commit is contained in:
hongyi
2025-11-08 12:11:19 +08:00
parent 3dd1665eea
commit 194010441d
5 changed files with 358 additions and 1 deletions

View File

@@ -807,12 +807,76 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c6_pins>;
clock-frequency = <400000>;
pmic_wl2866d_0:wl2866d_0@28 {
compatible = "willsemi,wl2866d";
reg = <0x28>;
status = "okay";
regulators {
dvdd1_mipicsi0_reg: dvdd1_mipicsi0 {
regulator-name = "dvdd1_mipicsi0";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1300000>;
};
dvdd2_mipicsi0_reg: dvdd2_mipicsi0 {
regulator-name = "dvdd2_mipicsi0";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
avdd1_mipicsi0_reg: avdd1_mipicsi0 {
regulator-name = "avdd1_mipicsi0";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
avdd2_mipicsi0_reg: avdd2_mipicsi0 {
regulator-name = "avdd2_mipicsi0";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
};
};
};
&i2c7 {
pinctrl-names = "default";
pinctrl-0 = <&i2c7_pins>;
clock-frequency = <400000>;
pmic_wl2866d_1:wl2866d_1@28 {
compatible = "willsemi,wl2866d";
reg = <0x28>;
status = "okay";
regulators {
dvdd1_mipicsi1_reg: dvdd1_mipicsi1 {
regulator-name = "dvdd1_mipicsi1";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1300000>;
};
dvdd2_mipicsi1_reg: dvdd2_mipicsi1 {
regulator-name = "dvdd2_mipicsi1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
avdd1_mipicsi1_reg: avdd1_mipicsi1 {
regulator-name = "avdd1_mipicsi1";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
avdd2_mipicsi1_reg: avdd2_mipicsi1 {
regulator-name = "avdd2_mipicsi1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
};
};
};
&aoi2c1 {

View File

@@ -186,6 +186,7 @@ CONFIG_DWMAC_ZHIHE=y
# CONFIG_NET_VENDOR_WANGXUN is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_NET_VENDOR_XILINX is not set
CONFIG_MOTORCOMM_PHY=y
CONFIG_REALTEK_PHY=y
CONFIG_CAN_FLEXCAN=m
CONFIG_IWLWIFI=m
@@ -235,6 +236,7 @@ CONFIG_DW_WATCHDOG=y
CONFIG_ZHIHE_WATCHDOG=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_WL2866D=y
# CONFIG_MEDIA_CEC_SUPPORT is not set
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_USB_SUPPORT=y

View File

@@ -1653,6 +1653,15 @@ config REGULATOR_WM8994
This driver provides support for the voltage regulators on the
WM8994 CODEC.
config REGULATOR_WL2866D
tristate "Willsemi WL2866D PMIC voltage regulator support"
depends on I2C
select REGMAP_I2C
help
This driver supports WL2866D voltage regulator chips. WL2866D provides
four LDO voltage regulators.Each regulator can be individually configured for voltage
level and enable state through the standard Linux regulator framework
config REGULATOR_QCOM_LABIBB
tristate "QCOM LAB/IBB regulator support"
depends on SPMI || COMPILE_TEST
@@ -1682,5 +1691,5 @@ config REGULATOR_ZHIHE_AON
that inmplemented on Zhihe Aon system.
This driver relies on the IPC interface between host CPU and the AON
firmware runnint on E902.
endif

View File

@@ -197,5 +197,6 @@ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
obj-$(CONFIG_REGULATOR_TH1520_AON) +=th1520-aon-regulator.o
obj-$(CONFIG_REGULATOR_ZHIHE_AON) +=zhihe-aon-regulator.o
obj-$(CONFIG_REGULATOR_WL2866D) += wl2866d-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG

View File

@@ -0,0 +1,281 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2025 Zhihe Group Holding Limited.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/of.h>
#include <linux/slab.h>
#define WL2866D_REG_DVDD1_VOUT 0x03
#define WL2866D_REG_DVDD2_VOUT 0x04
#define WL2866D_REG_AVDD1_VOUT 0x05
#define WL2866D_REG_AVDD2_VOUT 0x06
#define WL2866D_REG_ENABLE 0x0E
#define WL2866D_REG_CHIP_REV 0x00
#define WL2866D_EN_DVDD1 BIT(0)
#define WL2866D_EN_DVDD2 BIT(1)
#define WL2866D_EN_AVDD1 BIT(2)
#define WL2866D_EN_AVDD2 BIT(3)
enum wl2866d_regulator_id {
WL2866D_DVDD1_MIPICSI0, /* dvdd_mipicsi0 */
WL2866D_DVDD2_MIPICSI0, /* dvdd_mipicsi0 */
WL2866D_AVDD1_MIPICSI0, /* avdd_mipicsi0 */
WL2866D_AVDD2_MIPICSI0, /* avdd_mipicsi0 */
WL2866D_DVDD1_MIPICSI1, /* dvdd_mipicsi1 */
WL2866D_DVDD2_MIPICSI1, /* dvdd_mipicsi1 */
WL2866D_AVDD1_MIPICSI1, /* avdd_mipicsi1 */
WL2866D_AVDD2_MIPICSI1, /* avdd_mipicsi1 */
WL2866D_NUM_REGULATORS,
};
struct wl2866d {
struct device *dev;
struct regmap *regmap;
};
static inline u8 wl2866d_clamp_sel(unsigned int sel)
{
if (sel > 0xFF)
return 0xFF;
return sel & 0xFF;
}
static int wl2866d_enable(struct regulator_dev *rdev)
{
struct regmap *regmap = rdev->regmap;
unsigned int mask = rdev->desc->enable_mask;
int ret;
if (!rdev->desc->enable_reg)
return -EINVAL;
ret = regmap_update_bits(regmap, rdev->desc->enable_reg, mask, mask);
if (ret)
dev_err(&rdev->dev, "%s: enable write failed: %d\n",
rdev->desc->name, ret);
return ret;
}
static int wl2866d_disable(struct regulator_dev *rdev)
{
struct regmap *regmap = rdev->regmap;
unsigned int mask = rdev->desc->enable_mask;
int ret;
if (!rdev->desc->enable_reg)
return -EINVAL;
ret = regmap_update_bits(regmap, rdev->desc->enable_reg, mask, 0);
if (ret)
dev_err(&rdev->dev, "%s: disable write failed: %d\n",
rdev->desc->name, ret);
return ret;
}
static int wl2866d_is_enabled(struct regulator_dev *rdev)
{
struct regmap *regmap = rdev->regmap;
unsigned int val;
int ret;
if (!rdev->desc->enable_reg)
return -EINVAL;
ret = regmap_read(regmap, rdev->desc->enable_reg, &val);
if (ret) {
dev_err(&rdev->dev, "%s: read enable_reg failed: %d\n",
rdev->desc->name, ret);
return ret;
}
return (val & rdev->desc->enable_mask);
}
static int wl2866d_set_voltage_sel(struct regulator_dev *rdev,
unsigned int sel)
{
struct regmap *regmap = rdev->regmap;
u8 val = wl2866d_clamp_sel(sel);
int ret;
if (!rdev->desc->vsel_reg)
return -EINVAL;
ret = regmap_write(regmap, rdev->desc->vsel_reg, val);
if (ret)
dev_err(&rdev->dev, "%s: set vsel failed: %d\n",
rdev->desc->name, ret);
return ret;
}
static int wl2866d_get_voltage_sel(struct regulator_dev *rdev)
{
struct regmap *regmap = rdev->regmap;
int val;
int ret;
if (!rdev->desc->vsel_reg)
return -EINVAL;
ret = regmap_read(regmap, rdev->desc->vsel_reg, &val);
if (ret) {
dev_err(&rdev->dev, "%s: get vsel failed: %d\n",
rdev->desc->name, ret);
return ret;
}
return val & 0xFF;
}
int wl2866d_match_regulator_name(struct regulator_desc *regus_set, const char *string)
{
int index;
const char *item;
for (index = 0; index < WL2866D_NUM_REGULATORS; index++) {
item = regus_set[index].name;
if (!item)
break;
if (!strcmp(item, string))
return index;
}
return -EINVAL;
}
static const struct regulator_ops wl2866d_regulator_ops = {
.enable = wl2866d_enable,
.disable = wl2866d_disable,
.is_enabled = wl2866d_is_enabled,
.set_voltage_sel = wl2866d_set_voltage_sel,
.get_voltage_sel = wl2866d_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
};
#define WL2866D_DESC(_id, _name, _min_uv, _step_uv, _vsel_reg, _en_bit) { \
.name = _name, \
.of_match = of_match_ptr(_name), \
.regulators_node = of_match_ptr("regulators"), \
.id = _id, \
.ops = &wl2866d_regulator_ops, \
.n_voltages = 256, \
.min_uV = (_min_uv), \
.uV_step = (_step_uv), \
.vsel_reg = (_vsel_reg), \
.vsel_mask = 0xFF, \
.enable_reg = WL2866D_REG_ENABLE, \
.enable_mask = (_en_bit), \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
static const struct regulator_desc wl2866d_descs[] = {
WL2866D_DESC(WL2866D_DVDD1_MIPICSI0, "dvdd1_mipicsi0", 600000, 6000, WL2866D_REG_DVDD1_VOUT, WL2866D_EN_DVDD1),
WL2866D_DESC(WL2866D_DVDD2_MIPICSI0, "dvdd2_mipicsi0", 600000, 6000, WL2866D_REG_DVDD2_VOUT, WL2866D_EN_DVDD2),
WL2866D_DESC(WL2866D_AVDD1_MIPICSI0, "avdd1_mipicsi0", 1200000, 12500, WL2866D_REG_AVDD1_VOUT, WL2866D_EN_AVDD1),
WL2866D_DESC(WL2866D_AVDD2_MIPICSI0, "avdd2_mipicsi0", 1200000, 12500, WL2866D_REG_AVDD2_VOUT, WL2866D_EN_AVDD2),
WL2866D_DESC(WL2866D_DVDD1_MIPICSI1, "dvdd1_mipicsi1", 600000, 6000, WL2866D_REG_DVDD1_VOUT, WL2866D_EN_DVDD1),
WL2866D_DESC(WL2866D_DVDD2_MIPICSI1, "dvdd2_mipicsi1", 600000, 6000, WL2866D_REG_DVDD2_VOUT, WL2866D_EN_DVDD2),
WL2866D_DESC(WL2866D_AVDD1_MIPICSI1, "avdd1_mipicsi1", 1200000, 12500, WL2866D_REG_AVDD1_VOUT, WL2866D_EN_AVDD1),
WL2866D_DESC(WL2866D_AVDD2_MIPICSI1, "avdd2_mipicsi1", 1200000, 12500, WL2866D_REG_AVDD2_VOUT, WL2866D_EN_AVDD2),
};
static const struct regmap_config wl2866d_regmap_cfg = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
};
static int wl2866d_probe(struct i2c_client *client)
{
struct wl2866d *pmic;
struct device_node *regulators, *child;
struct regulator_config cfg = { };
struct device_node *node = client->dev.of_node;
struct regulator_dev *rdev;
const char *regulator_name;
int index, ret;
unsigned int chiprev;
if (!node)
dev_warn(&client->dev, "No device-tree node\n");
pmic = devm_kzalloc(&client->dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
pmic->dev = &client->dev;
pmic->regmap = devm_regmap_init_i2c(client, &wl2866d_regmap_cfg);
if (IS_ERR(pmic->regmap))
return dev_err_probe(&client->dev, PTR_ERR(pmic->regmap),
"regmap init failed\n");
/* optional: read chip revision to sanity-check */
ret = regmap_read(pmic->regmap, WL2866D_REG_CHIP_REV, &chiprev);
if (ret == 0)
dev_info(&client->dev, "WL2866D chip rev 0x%02x\n", chiprev);
else
dev_info(&client->dev, "WL2866D (chip rev read failed: %d)\n", ret);
regulators = of_get_child_by_name(node, "regulators");
if (!regulators) {
dev_err(&client->dev, "No regulators node found\n");
return -ENODEV;
}
for_each_child_of_node(regulators, child) {
of_property_read_string(child, "regulator-name", &regulator_name);
if (!regulator_name) {
dev_err(&client->dev, "failed to get a regulator-name\n");
return -EINVAL;
}
index = wl2866d_match_regulator_name((struct regulator_desc *)wl2866d_descs, regulator_name);
if (index < 0) {
dev_err(&client->dev, "no regulator matches %s\n", regulator_name);
return -EINVAL;
}
cfg.dev = &client->dev;
cfg.regmap = pmic->regmap;
cfg.of_node = child;
cfg.init_data = of_get_regulator_init_data(&client->dev, child, &wl2866d_descs[index]);
rdev = devm_regulator_register(&client->dev, &wl2866d_descs[index], &cfg);
if (IS_ERR(rdev)) {
dev_err(&client->dev, "Failed to register regulator %s\n", regulator_name);
return PTR_ERR(rdev);
}
}
dev_info(&client->dev, "WL2866D regulators registered\n");
return 0;
}
static const struct of_device_id wl2866d_of_match[] = {
{ .compatible = "willsemi,wl2866d" },
{ }
};
MODULE_DEVICE_TABLE(of, wl2866d_of_match);
static struct i2c_driver wl2866d_driver = {
.driver = {
.name = "wl2866d-regulator",
.of_match_table = wl2866d_of_match,
},
.probe = wl2866d_probe,
};
module_i2c_driver(wl2866d_driver);
MODULE_AUTHOR("hongkun.xu <xuhongkun@zhcomputing.com>");
MODULE_DESCRIPTION("wl2866d regulator driver");
MODULE_LICENSE("GPL");