diff --git a/Documentation/devicetree/bindings/regulator/regulator-max77851.yaml b/Documentation/devicetree/bindings/regulator/regulator-max77851.yaml new file mode 100644 index 00000000..1b5c99f8 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/regulator-max77851.yaml @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: GPL-2.0-only +# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/regulator-max77851.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MAX77851 Power management IC Regulator + +maintainers: + - Joan Na + - Shubhi Garg + +description: | + Regulator DT binding for MAX77851 Power management IC from Maxim Semiconductor. + +properties: + maxim,out-voltage-range: + $ref: "/schemas/types.yaml#/definitions/uint32" + description: + Output Voltage Range + enabled/disabled when system is in active state. + Valid values are: + - MAX77620_FPS_SRC_0, + FPS source is FPS0. + - MAX77620_FPS_SRC_1, + FPS source is FPS1 + - MAX77620_FPS_SRC_2 and + FPS source is FPS2 + - MAX77620_FPS_SRC_NONE. + Regulator is not controlled + by FPS events and it gets + enabled/disabled by register + access. + Absence of this property will leave + the FPS configuration register for that + regulator to default configuration. + + maxim,fps-user-setting-enable: + $ref: /schemas/types.yaml#/definitions/flag + using default setting (OTP/SHADOW) + + maxim,regulator-dvs-mode-enable: + $ref: /schemas/types.yaml#/definitions/flag + DVS Mode Enable + the regulator get disabled when master + FPS input event set to LOW. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + + maxim,regulator-dvs-voltage: + $ref: "/schemas/types.yaml#/definitions/uint32" + VOUT0/VOUT1 Voltage array + + maxim,pu-slot: + $ref: "/schemas/types.yaml#/definitions/uint32" + FPS Power-Up Slot + Valid values are 0 to F. + + maxim,pd-slot: + $ref: "/schemas/types.yaml#/definitions/uint32" + FPS Power-Down Slot + Valid values are 0 to F. + + maxim,slpx-slot: + $ref: "/schemas/types.yaml#/definitions/uint32" + FPS Sleep Exit Slot + Valid values are 0 to F. + + maxim,slpy-slot: + $ref: "/schemas/types.yaml#/definitions/uint32" + FPS Sleep Enter Slot + Valid values are 0 to F. + +examples: + - | + #include + ... + max77851: max77851@3c { + regulators { + + max77851_ldo0: ldo0 { + ... + + #maxim,fps-default-enable; + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + + max77851_ldo1: ldo1 { + ... + + maxim,fps-user-setting-enable; + + maxim,regulator-dvs-mode-enable; + /* + * 0x38(56h) : 0.75V + * 0x30(48h) : 0.70V + */ + maxim,regulator-dvs-voltage = <0x38>, <0x30>; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + + max77851_ldo2: ldo2 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pd-slot = ; + maxim,slpx-slot = ; + maxim,slpy-slot = ; + }; + + max77851_ldo3: ldo3 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pd-slot = ; + maxim,slpx-slot = ; + maxim,slpy-slot = ; + }; + + max77851_ldo4: ldo4 { + ... + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pd-slot = ; + }; + + max77851_ldo5: ldo5 { + ... + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pd-slot = ; + }; + + max77851_ldo6: ldo6 { + ... + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pd-slot = ; + }; + + max77851_buck0: buck0 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + + max77851_buck1: buck1 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + + max77851_buck2: buck2 { + ... + + maxim,fps-user-setting-enable; + + maxim,regulator-dvs-mode-enable; + /* + * 0x50(80h) : 0.50V + * 0x3C(60h) : 0.45V + */ + maxim,regulator-dvs-voltage = <0x50>, <0x3C>; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + + maxim,slpx-slot = ; + maxim,slpy-slot = ; + }; + + max77851_buck3: buck3 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + max77851_buck4: buck4 { + ... + + maxim,fps-user-setting-enable; + + maxim,out-voltage-range = ; + maxim,pu-slpx-master-slot = ; + maxim,pd-slpy-master-slot = ; + maxim,pu-slot = ; + maxim,pd-slot = ; + }; + }; + }; + + ... diff --git a/drivers/Makefile b/drivers/Makefile index 2c59935f..3ab00739 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. LINUXINCLUDE += -I$(srctree.nvidia-oot)/include LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/gpu/host1x/hw/ @@ -52,6 +52,7 @@ obj-m += pinctrl/ obj-m += platform/tegra/ obj-m += pwm/ obj-m += ras/ +obj-m += regulator/ obj-m += rtc/ obj-m += cpuidle/ ifdef CONFIG_SCSI diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile new file mode 100644 index 00000000..b7731227 --- /dev/null +++ b/drivers/regulator/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# Makefile for regulator drivers. +# + +obj-m += max77851-regulator.o + diff --git a/drivers/regulator/max77851-regulator.c b/drivers/regulator/max77851-regulator.c new file mode 100644 index 00000000..38fb8476 --- /dev/null +++ b/drivers/regulator/max77851-regulator.c @@ -0,0 +1,842 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +/* + * Maxim MAX77851 Regulator driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define max77851_rails(_name) "max77851-"#_name + +#define IS_BUCK(type) (type == MAX77851_REGULATOR_TYPE_BUCK) +#define IS_NLDO(type) (type == MAX77851_REGULATOR_TYPE_LDO_N) +#define IS_PLDO(type) (type == MAX77851_REGULATOR_TYPE_LDO_P) + +/* Power Mode */ +#define MAX77851_POWER_MODE_NORMAL BIT_IS_ZERO +#define MAX77851_POWER_MODE_LPM BIT(1) + +#define MAX77851_POWER_MODE_MASK BIT(1) + +/* SD Slew Rate */ +#define MAX77851_SD_SR_13_75 0 +#define MAX77851_SD_SR_27_5 1 +#define MAX77851_SD_SR_55 2 +#define MAX77851_SD_SR_100 3 + +/* FPS ENABLE / DISABLE */ +#define MAX77851_FPS_MODE_DISABLE 0 +#define MAX77851_FPS_MODE_ENABLE 1 + +#define MAX77851_DVS_VOLTAGE_NUM 2 + +#define MAX77851_BUCK_RAMP_DELAY 10000 /* uV/us */ +#define MAX77851_LDO_ENABLE_TIME 100 /* us */ +#define MAX77851_BUCK_ENABLE_TIME 100 /* us */ + +enum max77851_ramp_rate { + RAMP_RATE_0P15MV, + RAMP_RATE_0P625MV, + RAMP_RATE_1P25MV, + RAMP_RATE_2P5MV, + RAMP_RATE_5MV, + RAMP_RATE_10MV, + RAMP_RATE_20MV, + RAMP_RATE_40MV, + RAMP_RATE_NO_CTRL, /* 100mV/us */ +}; + +enum max77851_regulators_ldo { + MAX77851_REGULATOR_ID_LDO0, + MAX77851_REGULATOR_ID_LDO1, + MAX77851_REGULATOR_ID_LDO2, + MAX77851_REGULATOR_ID_LDO3, + MAX77851_REGULATOR_ID_LDO4, + MAX77851_REGULATOR_ID_LDO5, + MAX77851_REGULATOR_ID_LDO6, + + MAX77851_REGULATOR_ID_BUCK0, + MAX77851_REGULATOR_ID_BUCK1, + MAX77851_REGULATOR_ID_BUCK2, + MAX77851_REGULATOR_ID_BUCK3, + MAX77851_REGULATOR_ID_BUCK4, + MAX77851_REGULATOR_ID_NUM, +}; + +/* Regulator types */ +enum max77851_regulator_type { + /* LDO 0-3 */ + MAX77851_REGULATOR_TYPE_LDO_N, + /* LDO 4-6 */ + MAX77851_REGULATOR_TYPE_LDO_P, + /* BUCK */ + MAX77851_REGULATOR_TYPE_BUCK, +}; + +struct max77851_regulator_data { + u8 type; + + u8 cfg_addr; + u8 vout0_addr; + u8 vout1_addr; + u8 ramp_delay_addr; + + /* Common */ + unsigned int en; + unsigned int lp_mode_en; + unsigned int power_mode; + + unsigned int opmode; + unsigned int fps_mode_en; + + unsigned int voltage[MAX77851_DVS_VOLTAGE_NUM]; + + struct regulator_desc desc; +}; + +/* Main Regulator Resource */ +struct max77851_regulator { + struct device *dev; + struct regmap *rmap; + + unsigned int num_reulator; + + /* FPS */ + struct max77851_fps_data *fps_data; + + /* Regulator */ + struct max77851_regulator_data *reg_data; +}; + +static int max77851_regulator_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77851_regulator_data *rdata = &pmic->reg_data[id]; + unsigned int ramp_value; + int ret; + + switch (ramp_delay) { + case 1 ... 150: + ramp_value = RAMP_RATE_0P15MV; + break; + case 151 ... 625: + ramp_value = RAMP_RATE_0P625MV; + break; + case 626 ... 1250: + ramp_value = RAMP_RATE_1P25MV; + break; + case 1251 ... 2500: + ramp_value = RAMP_RATE_1P25MV; + break; + case 2501 ... 5000: + ramp_value = RAMP_RATE_5MV; + break; + case 5001 ... 10000: + ramp_value = RAMP_RATE_10MV; + break; + case 10001 ... 20000: + ramp_value = RAMP_RATE_20MV; + break; + case 20001 ... 40000: + ramp_value = RAMP_RATE_40MV; + break; + default: + pr_warn("%s: ramp_delay: %d not supported\n", rdev->desc->name, ramp_delay); + return -EINVAL; + } + + ret = regmap_update_bits(rdev->regmap, rdata->ramp_delay_addr, + BUCK_CFG5_RD_SR, ramp_value << FFS(BUCK_CFG5_RD_SR)); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", rdata->ramp_delay_addr, ret); + return ret; + } + + ret = regmap_update_bits(rdev->regmap, rdata->ramp_delay_addr, + BUCK_CFG5_RU_SR, ramp_value << FFS(BUCK_CFG5_RU_SR)); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", rdata->ramp_delay_addr, ret); + return ret; + } + + return ret; +} + +static int max77851_regulator_get_enable(struct max77851_regulator *pmic, + int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + unsigned int val; + int ret; + + ret = regmap_read(pmic->rmap, reg_data->cfg_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n", + id, reg_data->cfg_addr, ret); + return ret; + } + + return BITS_VALUE(val, REGULATOR_ENABLE); +} + +static int max77851_regulator_set_enable(struct max77851_regulator *pmic, + int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + unsigned int val; + int ret; + + val = REGULATOR_ENABLE; + ret = regmap_update_bits(pmic->rmap, reg_data->cfg_addr, + REGULATOR_ENABLE_MASK, val); + + return ret; +} + +static int max77851_regulator_set_disable(struct max77851_regulator *pmic, + int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + unsigned int val; + int ret; + + val = REGULATOR_DISABLE; + ret = regmap_update_bits(pmic->rmap, reg_data->cfg_addr, + REGULATOR_ENABLE_MASK, val); + + return ret; +} + +static int max77851_regulator_enable(struct regulator_dev *rdev) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + + if (reg_data->fps_mode_en != MAX77851_FPS_MODE_DISABLE) + return 0; + + return max77851_regulator_set_enable(pmic, id); +} + +static int max77851_regulator_disable(struct regulator_dev *rdev) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + + if (reg_data->fps_mode_en != MAX77851_FPS_MODE_DISABLE) + return 0; + + return max77851_regulator_set_disable(pmic, id); +} + +static int max77851_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + int ret; + + if (reg_data->fps_mode_en != MAX77851_FPS_MODE_DISABLE) + return 1; + + ret = max77851_regulator_get_enable(pmic, id); + if (ret < 0) + return ret; + + if (ret & REGULATOR_ENABLE) + return 1; + + return 0; +} + +static int max77851_regulator_set_power_mode(struct max77851_regulator *pmic, + int power_mode, int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + u8 mask = MAX77851_POWER_MODE_MASK; + int ret; + + ret = regmap_update_bits(pmic->rmap, reg_data->cfg_addr, mask, power_mode); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d mode set failed: %d\n", + id, ret); + return ret; + } + + reg_data->power_mode = power_mode; + + return ret; +} + +static int max77851_regulator_get_power_mode(struct max77851_regulator *pmic, + int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + unsigned int val; + int ret; + + ret = regmap_read(pmic->rmap, reg_data->cfg_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d: Reg 0x%02x read failed: %d\n", + id, reg_data->cfg_addr, ret); + return ret; + } + + return (val & MAX77851_POWER_MODE_MASK); +} + +static unsigned int max77851_regulator_get_mode(struct regulator_dev *rdev) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + int ret; + int power_mode, opmode; + + ret = max77851_regulator_get_power_mode(pmic, id); + if (ret < 0) + return 0; + + power_mode = ret; + + switch (power_mode) { + case MAX77851_POWER_MODE_NORMAL: + opmode = REGULATOR_MODE_NORMAL; + break; + case MAX77851_POWER_MODE_LPM: + opmode = REGULATOR_MODE_IDLE; + break; + default: + return 0; + } + + reg_data->opmode = opmode; + + return opmode; +} + +static int max77851_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct max77851_regulator *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int power_mode = MAX77851_POWER_MODE_NORMAL; + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + + switch (mode) { + case REGULATOR_MODE_IDLE: + power_mode = MAX77851_POWER_MODE_LPM; /* ON in Low Power Mode */ + break; + case REGULATOR_MODE_NORMAL: + power_mode = MAX77851_POWER_MODE_NORMAL; /* ON in Normal Mode */ + break; + default: + dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + reg_data->power_mode = power_mode; + reg_data->opmode = mode; + + return max77851_regulator_set_power_mode(pmic, power_mode, id); +} + +static int max77851_regulator_intial(struct max77851_regulator *pmic, int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + unsigned int val; + int ret; + + ret = regmap_read(pmic->rmap, reg_data->cfg_addr, &val); + if (ret < 0) { + dev_err(pmic->dev, "Reg 0x%02x read failed %d\n", reg_data->cfg_addr, ret); + return ret; + } + + reg_data->en = ret & BIT(0) ? 1 : 0; + reg_data->lp_mode_en = ret & BIT(2) ? 1 : 0; + + return 0; +} + +static int max77851_regulator_set_vout_range(struct max77851_regulator *pmic, + u32 val, int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + u8 reg_addr; + int mask, shift; + int ret; + unsigned int read_val; + + ret = regmap_read(pmic->rmap, reg_data->cfg_addr, &read_val); + + if (IS_BUCK(reg_data->type)) { + reg_addr = reg_data->cfg_addr; + mask = BUCK_CFG0_VOUT_RNG; + shift = FFS(BUCK_CFG0_VOUT_RNG); + } else { + if (IS_NLDO(reg_data->type)) { + reg_addr = reg_data->cfg_addr; + mask = LDO_CFG0_VOUT_RNG; + shift = FFS(LDO_CFG0_VOUT_RNG); + } else { + dev_info(pmic->dev, "PMOS is not supported : %d\n", ret); + return 0; + } + } + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, BITS_REAL_VALUE(val, mask)); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d range set failed: %d\n", + id, ret); + return ret; + } + + ret = regmap_read(pmic->rmap, reg_data->cfg_addr, &read_val); + + return ret; +} + +static int max77851_regulator_set_vout_voltage(struct max77851_regulator *pmic, + unsigned int *vout, int id) +{ + struct max77851_regulator_data *reg_data = &pmic->reg_data[id]; + int ret; + + if (IS_BUCK(reg_data->type)) { + ret = regmap_write(pmic->rmap, reg_data->vout0_addr, vout[0]); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d vout set failed: %d\n", id, ret); + return ret; + } + ret = regmap_write(pmic->rmap, reg_data->vout1_addr, vout[1]); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d vout set failed: %d\n", id, ret); + return ret; + } + } else { + /* Register set vout0 */ + ret = regmap_update_bits(pmic->rmap, reg_data->cfg_addr, LDO_CFG0_VOUT_RW, BIT_IS_ZERO); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d register set failed: %d\n", + id, ret); + return ret; + } + ret = regmap_write(pmic->rmap, reg_data->vout0_addr, vout[0]); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d vout set failed: %d\n", id, ret); + return ret; + } + + /* Register set vout1 */ + ret = regmap_update_bits(pmic->rmap, reg_data->cfg_addr, LDO_CFG0_VOUT_RW, LDO_CFG0_VOUT_RW); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d register set failed: %d\n", + id, ret); + return ret; + } + ret = regmap_write(pmic->rmap, reg_data->vout1_addr, vout[1]); + if (ret < 0) { + dev_err(pmic->dev, "Regulator %d vout set failed: %d\n", id, ret); + return ret; + } + } + + return ret; +} + +static int max77851_regulator_set_fps(struct max77851_regulator *pmic, int id) +{ + struct max77851_fps_data *fps_data = &pmic->fps_data[id]; + unsigned int val; + int mask, shift; + u8 reg_addr; + int ret; + + mask = MAX77851_FPS_PU_SLPX_SLOT_MASK; + shift = FFS(MAX77851_FPS_PU_SLPX_SLOT_MASK); + val = fps_data->pu_slpx_master_slot; + reg_addr = fps_data->fps_cfg0_addr; + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "PY SLPX MASTER SLOT update failed: %d\n", ret); + return ret; + } + + mask = MAX77851_FPS_PD_SLPY_SLOT_MASK; + shift = FFS(MAX77851_FPS_PD_SLPY_SLOT_MASK); + + val = fps_data->pd_slpy_master_slot; + reg_addr = fps_data->fps_cfg0_addr; + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "PD SLPY MASTER SLOT update failed: %d\n", ret); + return ret; + } + + mask = MAX77851_FPS_PU_SLOT_MASK; + shift = FFS(MAX77851_FPS_PU_SLOT_MASK); + + val = fps_data->pu_slot; + reg_addr = fps_data->fps_cfg1_addr; + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "PU SLOT update failed: %d\n", ret); + return ret; + } + + mask = MAX77851_FPS_PD_SLOT_MASK; + shift = FFS(MAX77851_FPS_PD_SLOT_MASK); + + val = fps_data->pd_slot; + reg_addr = fps_data->fps_cfg1_addr; + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "PD SLOT update failed: %d\n", ret); + return ret; + } + + mask = MAX77851_FPS_SLPX_SLOT_MASK; + shift = FFS(MAX77851_FPS_SLPX_SLOT_MASK); + + val = fps_data->slpx_slot; + reg_addr = fps_data->fps_cfg2_addr; + + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "SLPX SLOT update failed: %d\n", ret); + return ret; + } + + mask = MAX77851_FPS_SLPY_SLOT_MASK; + shift = FFS(MAX77851_FPS_SLPY_SLOT_MASK); + + val = fps_data->slpy_slot; + reg_addr = fps_data->fps_cfg2_addr; + ret = regmap_update_bits(pmic->rmap, reg_addr, mask, val << shift); + if (ret < 0) { + dev_err(pmic->dev, "SLPY SLOT update failed: %d\n", ret); + return ret; + } + + return ret; +} + +static int max77851_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77851_regulator *pmic = config->driver_data; + struct max77851_fps_data *fps_data = &pmic->fps_data[desc->id]; + struct max77851_regulator_data *reg_data = &pmic->reg_data[desc->id]; + unsigned int voltage[MAX77851_VOUT_NUM]; + u32 pval; + int ret; + + /* Use FPS Default Data */ + if (of_property_read_bool(np, "maxim,fps-default-enable")) { + reg_data->fps_mode_en = MAX77851_FPS_MODE_ENABLE; + return 0; + } + + reg_data->fps_mode_en = MAX77851_FPS_MODE_DISABLE; + + /* VOUT Range */ + ret = of_property_read_u32(np, "maxim,out-voltage-range", &pval); + if (ret < 0) + pval = MAX77851_VOUT_RNG_LOW; + + max77851_regulator_set_vout_range(pmic, pval, desc->id); + + if (of_property_read_bool(np, "maxim,fps-user-setting-enable")) { + ret = of_property_read_u32(np, "maxim,pu-slpx-master-slot", &pval); + fps_data->pu_slpx_master_slot = (!ret) ? pval : MAX77851_FPS_MASTER_SLOT_0; + + ret = of_property_read_u32(np, "maxim,pd-slpy-master-slot", &pval); + fps_data->pd_slpy_master_slot = (!ret) ? pval : MAX77851_FPS_MASTER_SLOT_0; + + ret = of_property_read_u32(np, "maxim,pu-slot", &pval); + fps_data->pu_slot = (!ret) ? pval : MAX77851_FPS_SLOT_0; + + ret = of_property_read_u32(np, "maxim,pd-slot", &pval); + fps_data->pd_slot = (!ret) ? pval : MAX77851_FPS_SLOT_0; + + ret = of_property_read_u32(np, "maxim,slpy-slot", &pval); + fps_data->slpy_slot = (!ret) ? pval : MAX77851_FPS_SLOT_0; + + ret = of_property_read_u32(np, "maxim,slpx-slot", &pval); + fps_data->slpx_slot = (!ret) ? pval : MAX77851_FPS_SLOT_0; + + reg_data->fps_mode_en = MAX77851_FPS_MODE_ENABLE; + + max77851_regulator_set_fps(pmic, desc->id); + } + + if (of_property_read_bool(np, "maxim,regulator-dvs-mode-enable")) { + if (of_property_read_u32_array(np, "maxim,regulator-dvs-voltage", + voltage, MAX77851_DVS_VOLTAGE_NUM)) { + dev_err(pmic->dev, "dvs voltages not specified\n"); + return -EINVAL; + } + max77851_regulator_set_vout_voltage(pmic, voltage, desc->id); + } + + return max77851_regulator_intial(pmic, desc->id); +} + +static const struct regulator_ops max77851_regulator_ldo_ops = { + .is_enabled = max77851_regulator_is_enabled, + .enable = max77851_regulator_enable, + .disable = max77851_regulator_disable, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_mode = max77851_regulator_set_mode, + .get_mode = max77851_regulator_get_mode, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_ops max77851_regulator_buck_ops = { + .is_enabled = max77851_regulator_is_enabled, + .enable = max77851_regulator_enable, + .disable = max77851_regulator_disable, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_mode = max77851_regulator_set_mode, + .get_mode = max77851_regulator_get_mode, + .set_ramp_delay = max77851_regulator_set_ramp_delay, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +#define REGULATOR_LDO_DESC(_id, _name, _sname, _type, _min_uV, _max_uV, _step_uV) \ + [MAX77851_REGULATOR_ID_##_id] = { \ + .type = MAX77851_REGULATOR_TYPE_LDO_##_type, \ + .cfg_addr = _id##_CFG0_REG, \ + .vout0_addr = _id##_CFG1_REG, \ + .vout1_addr = _id##_CFG1_REG, \ + .desc = { \ + .owner = THIS_MODULE, \ + .name = max77851_rails(_name), \ + .supply_name = _sname, \ + .of_match = of_match_ptr(#_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = max77851_of_parse_cb, \ + .id = MAX77851_REGULATOR_ID_##_id, \ + .ops = &max77851_regulator_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = _min_uV, \ + .uV_step = _step_uV, \ + .enable_time = MAX77851_LDO_ENABLE_TIME, \ + .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ + .vsel_reg = _id##_CFG1_REG, \ + .vsel_mask = LDO_CFG1_VOUT, \ + .enable_reg = _id##_CFG0_REG, \ + .enable_mask = LDO_CFG0_EN, \ + .enable_val = LDO_CFG0_EN, \ + .disable_val = BIT_IS_ZERO, \ + .active_discharge_reg = _id##_CFG0_REG, \ + .active_discharge_mask = LDO_CFG0_ADE, \ + .active_discharge_on = LDO_CFG0_ADE, \ + .active_discharge_off = BIT_IS_ZERO, \ + }, \ +} + +#define REGULATOR_BUCK_DESC(_id, _name, _sname, _min_uV, _max_uV, _step_uV) \ + [MAX77851_REGULATOR_ID_##_id] = { \ + .type = MAX77851_REGULATOR_TYPE_BUCK, \ + .cfg_addr = _id##_CFG0_REG, \ + .vout0_addr = _id##_CFG1_REG, \ + .vout1_addr = _id##_CFG2_REG, \ + .ramp_delay_addr = _id##_CFG5_REG, \ + .desc = { \ + .owner = THIS_MODULE, \ + .name = max77851_rails(_name), \ + .supply_name = _sname, \ + .of_match = of_match_ptr(#_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = max77851_of_parse_cb, \ + .id = MAX77851_REGULATOR_ID_##_id, \ + .ops = &max77851_regulator_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = _min_uV, \ + .uV_step = _step_uV, \ + .ramp_delay = MAX77851_BUCK_RAMP_DELAY, \ + .enable_time = MAX77851_BUCK_ENABLE_TIME, \ + .n_voltages = ((_max_uV - _min_uV) / _step_uV) + 1, \ + .vsel_reg = _id##_CFG1_REG, \ + .vsel_mask = BUCK_CFG1_VOUT0, \ + .enable_reg = _id##_CFG0_REG, \ + .enable_mask = BUCK_CFG0_EN, \ + .enable_val = BUCK_CFG0_EN, \ + .disable_val = BIT_IS_ZERO, \ + .active_discharge_reg = _id##_CFG6_REG, \ + .active_discharge_mask = BUCK_CFG6_ADE, \ + .active_discharge_on = BUCK_CFG6_ADE, \ + .active_discharge_off = BIT_IS_ZERO, \ + }, \ +} + +static struct max77851_regulator_data max77851_regs_data[MAX77851_REGULATOR_ID_NUM] = { + REGULATOR_LDO_DESC(LDO0, ldo0, "in-ldo0", N, 400000, 1993750, 6250), + REGULATOR_LDO_DESC(LDO1, ldo1, "in-ldo1", N, 400000, 1993750, 6250), + REGULATOR_LDO_DESC(LDO2, ldo2, "in-ldo2", N, 400000, 1993750, 6250), + REGULATOR_LDO_DESC(LDO3, ldo3, "in-ldo3", N, 400000, 1993750, 6250), + REGULATOR_LDO_DESC(LDO4, ldo4, "in-ldo4", P, 400000, 3975000, 25000), + REGULATOR_LDO_DESC(LDO5, ldo5, "in-ldo5", P, 400000, 3975000, 25000), + REGULATOR_LDO_DESC(LDO6, ldo6, "in-ldo6", P, 400000, 3975000, 25000), + + REGULATOR_BUCK_DESC(BUCK0, buck0, "in-buck0", 300000, 1200000, 2500), + REGULATOR_BUCK_DESC(BUCK1, buck1, "in-buck1", 300000, 1200000, 2500), + REGULATOR_BUCK_DESC(BUCK2, buck2, "in-buck2", 300000, 1200000, 2500), + REGULATOR_BUCK_DESC(BUCK3, buck3, "in-buck3", 1000000, 2400000, 2500), + REGULATOR_BUCK_DESC(BUCK4, buck4, "in-buck4", 1000000, 2400000, 2500), +}; + +#define MAX77851_FPS_REGULATOR_REG(_fps_name) { \ + .fps_cfg0_addr = _fps_name##_CFG0_REG, \ + .fps_cfg1_addr = _fps_name##_CFG1_REG, \ + .fps_cfg2_addr = _fps_name##_CFG2_REG, \ +} + +static struct max77851_fps_data max77851_fps_data_data[MAX77851_REGULATOR_ID_NUM] = { + MAX77851_FPS_REGULATOR_REG(FPS_LDO0), + MAX77851_FPS_REGULATOR_REG(FPS_LDO1), + MAX77851_FPS_REGULATOR_REG(FPS_LDO2), + MAX77851_FPS_REGULATOR_REG(FPS_LDO3), + MAX77851_FPS_REGULATOR_REG(FPS_LDO4), + MAX77851_FPS_REGULATOR_REG(FPS_LDO5), + MAX77851_FPS_REGULATOR_REG(FPS_LDO6), + + MAX77851_FPS_REGULATOR_REG(FPS_BUCK0), + MAX77851_FPS_REGULATOR_REG(FPS_BUCK1), + MAX77851_FPS_REGULATOR_REG(FPS_BUCK2), + MAX77851_FPS_REGULATOR_REG(FPS_BUCK3), + MAX77851_FPS_REGULATOR_REG(FPS_BUCK4), +}; + +static int max77851_regulator_probe(struct platform_device *pdev) +{ + struct max77851_chip *max77851_chip = dev_get_drvdata(pdev->dev.parent); + struct max77851_regulator *pmic; + struct max77851_fps_data *fps_data; + struct max77851_regulator_data *reg_data; + struct device *dev = &pdev->dev; + struct regulator_config config = { }; + int ret = 0; + int id = 0; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + platform_set_drvdata(pdev, pmic); + + pmic->dev = dev; + pmic->rmap = max77851_chip->rmap; + pmic->dev->of_node = pdev->dev.parent->of_node; + + fps_data = max77851_fps_data_data; + reg_data = max77851_regs_data; + + pmic->reg_data = max77851_regs_data; + pmic->fps_data = max77851_fps_data_data; + + config.regmap = pmic->rmap; + config.dev = dev; + config.driver_data = pmic; + + for (id = 0; id < MAX77851_REGULATOR_ID_NUM; id++) { + struct regulator_dev *rdev; + struct regulator_desc *rdesc; + + rdesc = ®_data[id].desc; + + pmic->reg_data[id].power_mode = MAX77851_POWER_MODE_NORMAL; + + pmic->fps_data[id].pd_slot = -1; + pmic->fps_data[id].pu_slot = -1; + pmic->fps_data[id].slpx_slot = -1; + pmic->fps_data[id].slpy_slot = -1; + pmic->fps_data[id].pu_slpx_master_slot = -1; + pmic->fps_data[id].pd_slpy_master_slot = -1; + + rdev = devm_regulator_register(dev, rdesc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "Regulator registration %s failed: %d\n", + rdesc->name, ret); + return ret; + } + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int max77851_regulator_suspend(struct device *dev) +{ + return 0; +} + +static int max77851_regulator_resume(struct device *dev) +{ + return 0; +} +#endif + +static const struct dev_pm_ops max77851_regulator_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max77851_regulator_suspend, + max77851_regulator_resume) +}; + +static const struct platform_device_id max77851_regulator_devtype[] = { + { .name = "max77851-regulator", }, + {}, +}; +MODULE_DEVICE_TABLE(platform, max77851_regulator_devtype); + +static struct platform_driver max77851_regulator_driver = { + .probe = max77851_regulator_probe, + .id_table = max77851_regulator_devtype, + .driver = { + .name = "max77851-regulator", + .pm = &max77851_regulator_pm_ops, + }, +}; + +static int __init max77851_regulator_init(void) +{ + return platform_driver_register(&max77851_regulator_driver); +} +subsys_initcall(max77851_regulator_init); + +static void __exit max77851_reg_exit(void) +{ + platform_driver_unregister(&max77851_regulator_driver); +} +module_exit(max77851_reg_exit); + +MODULE_DESCRIPTION("MAX77851 regulator driver"); +MODULE_AUTHOR("Shubhi Garg"); +MODULE_AUTHOR("Joan Na"); +MODULE_ALIAS("platform:max77851-regulator"); +MODULE_LICENSE("GPL v2");