From: Joy Zou <joy....@nxp.com> Support NXP pmic pf5300
Signed-off-by: Joy Zou <joy....@nxp.com> Reviewed-by: Ye Li <ye...@nxp.com> Signed-off-by: Peng Fan <peng....@nxp.com> --- drivers/power/pmic/Kconfig | 15 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/pf5300.c | 168 ++++++++++++++++++++++++++++++++++++ include/power/pf5300.h | 100 +++++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 drivers/power/pmic/pf5300.c create mode 100644 include/power/pf5300.h diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 1a5ef279ed6..420c4099937 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -186,6 +186,21 @@ config SPL_DM_PMIC_PF0900 This config enables implementation of driver-model pmic uclass features for PMIC PF0900 in SPL. The driver implements read/write operations. +config DM_PMIC_PF5300 + bool "Enable Driver Model for PMIC PF5300" + depends on DM_I2C + help + This config enables implementation of driver-model pmic uclass features + for PMIC PF5300. The driver implements read/write operations. + +config SPL_DM_PMIC_PF5300 + bool "Enable Driver Model for PMIC PF5300 in SPL" + depends on SPL_DM_PMIC + depends on SPL_DM_I2C + help + This config enables implementation of driver-model pmic uclass features + for PMIC PF5300 in SPL. The driver implements read/write operations. + config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" ---help--- diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 0041ab59406..74ace69daf5 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_MP5416) += mp5416.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o obj-$(CONFIG_$(SPL_)DM_PMIC_PF0900) += pf0900.o +obj-$(CONFIG_$(SPL_)DM_PMIC_PF5300) += pf5300.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_AB8500) += ab8500.o diff --git a/drivers/power/pmic/pf5300.c b/drivers/power/pmic/pf5300.c new file mode 100644 index 00000000000..b66fa756109 --- /dev/null +++ b/drivers/power/pmic/pf5300.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023 NXP + */ + +#include <asm/global_data.h> +#include <asm-generic/gpio.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <i2c.h> +#include <errno.h> +#include <fdtdec.h> +#include <linux/err.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/pf5300.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + /* sw */ + { .prefix = "S", .driver = PF5300_REGULATOR_DRIVER}, + { }, +}; + +static int pf5300_reg_count(struct udevice *dev) +{ + return PF5300_MAX_REGISTER; +} + +static u8 crc8_j1850(u8 *data, u8 length) +{ + u8 t_crc; + u8 i, j; + + t_crc = 0xFF; + for (i = 0; i < length; i++) { + t_crc ^= data[i]; + for (j = 0; j < 8; j++) { + if ((t_crc & 0x80) != 0) { + t_crc <<= 1; + t_crc ^= 0x1D; + } else { + t_crc <<= 1; + } + } + } + return t_crc; +} + +static int pf5300_read(struct udevice *dev, uint reg, u8 *buff, + int len) +{ + u8 crcBuf[3]; + u8 data[2], crc; + int ret; + struct pf5300_priv *priv = dev_get_priv(dev); + + if (reg < PF5300_MAX_REGISTER) { + ret = dm_i2c_read(dev, reg, data, + priv->crc_en ? 2U : 1U); + if (ret) + return ret; + buff[0] = data[0]; + if (priv->crc_en) { + /* Get CRC */ + crcBuf[0] = priv->addr << 1U | 0x1U; + crcBuf[1] = reg; + crcBuf[2] = data[0]; + crc = crc8_j1850(crcBuf, 3U); + if (crc != data[1]) + return -EINVAL; + } + } else { + return -EINVAL; + } + return ret; +} + +static int pf5300_write(struct udevice *dev, uint reg, const u8 *buff, + int len) +{ + u8 crcBuf[3]; + u8 data[2]; + int ret; + struct pf5300_priv *priv = dev_get_priv(dev); + + if (reg < PF5300_MAX_REGISTER) { + data[0] = buff[0]; + if (priv->crc_en) { + /* Get CRC */ + crcBuf[0] = priv->addr << 1U; + crcBuf[1] = reg; + crcBuf[2] = data[0]; + data[1] = crc8_j1850(crcBuf, 3U); + } + /* Write data */ + ret = dm_i2c_write(dev, reg, data, + priv->crc_en ? 2U : 1U); + if (ret) + return ret; + } + return ret; +} + +static int pf5300_bind(struct udevice *dev) +{ + int children; + ofnode regulators_node; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, + pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static int pf5300_probe(struct udevice *dev) +{ + struct pf5300_priv *priv = dev_get_priv(dev); + unsigned int reg; + int ret = 0; + + ret = ofnode_read_u32(dev_ofnode(dev), "reg", ®); + if (ret) + return ret; + priv->addr = reg; + + if (ofnode_read_bool(dev_ofnode(dev), "i2c-crc-enable")) + priv->crc_en = true; + + return ret; +} + +static struct dm_pmic_ops pf5300_ops = { + .reg_count = pf5300_reg_count, + .read = pf5300_read, + .write = pf5300_write, +}; + +static const struct udevice_id pf5300_ids[] = { + { .compatible = "nxp,pf5300", .data = PF5300_TYPE_PF5300, }, + { .compatible = "nxp,pf5301", .data = PF5300_TYPE_PF5301, }, + { .compatible = "nxp,pf5302", .data = PF5300_TYPE_PF5302, }, + { } +}; + +U_BOOT_DRIVER(pmic_pf5300) = { + .name = "pf5300 pmic", + .id = UCLASS_PMIC, + .of_match = pf5300_ids, + .bind = pf5300_bind, + .probe = pf5300_probe, + .ops = &pf5300_ops, + .priv_auto = sizeof(struct pf5300_priv), +}; diff --git a/include/power/pf5300.h b/include/power/pf5300.h new file mode 100644 index 00000000000..0d2fa548a70 --- /dev/null +++ b/include/power/pf5300.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2023 NXP + */ + +#ifndef PF5300_H_ +#define PF5300_H_ + +#define PF5300_REGULATOR_DRIVER "pf5300_regulator" + +struct pf5300_priv { + u8 addr; + bool crc_en; +}; + +enum pf5300_chip_type { + PF5300_TYPE_PF5300 = 0, + PF5300_TYPE_PF5301 = 1, + PF5300_TYPE_PF5302 = 2, + PF5300_TYPE_AMOUNT, +}; + +enum { + PF5300_SW1 = 0, + PF5300_REGULATOR_CNT, +}; + +enum { + PF5300_DVS_LEVEL_RUN = 0, + PF5300_DVS_LEVEL_STANDBY, + PF5300_DVS_LEVEL_MAX, +}; + +#define PF5300_SW1_VOLTAGE_NUM 0x100 + +enum { + PF5300_REG_DEV_ID = 0x00, + PF5300_REG_REV_ID = 0x01, + PF5300_REG_EMREV = 0x02, + PF5300_REG_PROG_ID = 0x03, + PF5300_REG_CONFIG1 = 0x04, + PF5300_REG_INT_STATUS1 = 0x05, + PF5300_REG_INT_SENSE1 = 0x06, + PF5300_REG_INT_STATUS2 = 0x07, + PF5300_REG_INT_SENSE2 = 0x08, + PF5300_REG_BIST_STAT1 = 0x09, + PF5300_REG_BIST_CTRL = 0x0A, + PF5300_REG_STATE = 0x0B, + PF5300_REG_STATE_CTRL = 0x0C, + PF5300_REG_SW1_VOLT = 0x0D, + PF5300_REG_SW1_STBY_VOLT = 0x0E, + PF5300_REG_SW1_CTRL1 = 0x0F, + PF5300_REG_SW1_CTRL2 = 0x10, + PF5300_REG_CLK_CTRL = 0x11, + PF5300_REG_SEQ_CTRL1 = 0x12, + PF5300_REG_SEQ_CTRL2 = 0x13, + PF5300_REG_RANDOM_CHK = 0x14, + PF5300_REG_RANDOM_GEN = 0x15, + PF5300_REG_WD_CTRL = 0x16, + PF5300_REG_WD_SEED = 0x17, + PF5300_REG_WD_ANSWER = 0x18, + PF5300_REG_FLT_CNT1 = 0x19, + PF5300_REG_FLT_CNT2 = 0x1A, + PF5300_MAX_REGISTER, +}; + +/* PF5300 SW1_CTRL1 */ +#define SW_MODE_OFF 0x00 +#define SW_MODE_PWM 0x0c + +#define SW1_MODE_MASK 0x0C +#define SW1_STBY_MODE_MASK 0x30 + +#define SW1_RAMP_MASK 0x03 + +/* PF5300 SW1_VOLT/SW1_STBY_VOLT MASK */ +#define SW1_VOLT_MASK 0xFF +#define SW1_STBY_VOLT_MASK 0xFF + +/* PF5300_REG_INT_STATUS1 bits */ +#define IRQ_SDWN 0x80 +#define IRQ_BG_ERR 0x40 +#define IRQ_CRC 0x20 +#define IRQ_SW1_DVS_DONE 0x10 +#define IRQ_SW1_ILIM 0x08 +#define IRQ_VMON_UV 0x04 +#define IRQ_VMON_OV 0x02 +#define IRQ_VIN_OVLO 0x01 + +/* PF5300_REG_INT_STATUS2 bits */ +#define IRQ_PGOOD_STUCK_AT0 0x80 +#define IRQ_PGOOD_STUCK_AT1 0x40 +#define IRQ_DVS_ERR 0x20 +#define IRQ_FSYNC 0x10 +#define IRQ_THERM_155 0x08 +#define IRQ_THERM_140 0x04 +#define IRQ_THERM_125 0x02 +#define IRQ_THERM_110 0x01 + +#endif -- 2.35.3