diff --git a/Documentation/devicetree/bindings/regulator/adi,max77533-regulator.yaml b/Documentation/devicetree/bindings/regulator/adi,max77533-regulator.yaml new file mode 100644 index 00000000000000..c1bbe64527ed0b --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/adi,max77533-regulator.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright (c) 2025 Analog Devices, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/adi,max77533-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX77533 Buck Converter + +maintainers: + - Sean Park + +description: + The Analog Devices MAX77533 is a single channel 14V input, 1.5A + high-efficiency buck converter with 9µA quiescent current. + This converter has 94% efficiency for 2-Cell/3-Cell battery applications. + It supports both SKIP mode for high efficiency at light loads and + forced-PWM mode for better load transient response. + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + enum: + - adi,max77533 + - maxim,max77533 + - maxim,max77533a + - maxim,max77533b-12 + - maxim,max77533b-18 + - maxim,max77533b-33 + - maxim,max77533q + + reg: + description: I2C address of the device + items: + - enum: [0x1e, 0x24, 0x37, 0x77] + + pok-gpios: + maxItems: 1 + description: + GPIO connected to the POK (Power-OK) output pin. + This open-drain output indicates when the output voltage + is above 92% of the target regulation voltage. + + adi,peak-current-limit-microamp: + enum: [500000, 2000000] + default: 2000000 + description: + Peak inductor current limit in microamps. + 500000 for 500mA, 2000000 for 2000mA (default). + + adi,soft-start-us: + enum: [1000, 2000, 4000, 8000] + default: 1000 + description: + Soft-start ramp time in microseconds. + + adi,fpwm-mode: + type: boolean + description: + Enable forced PWM mode for better load transient response. + If not set, SKIP mode is used (default) for lower quiescent current. + + adi,en-logic-and: + type: boolean + description: + Use AND logic between EN pin and EN_BIT register bit. + If not set, OR logic is used (default). + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@1e { + compatible = "adi,max77533"; + reg = <0x1e>; + + pok-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + + regulator-name = "vdd_buck"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + + adi,peak-current-limit-microamp = <2000000>; + adi,soft-start-us = <1000>; + }; + }; diff --git a/Kconfig.adi b/Kconfig.adi index 0c81eb50f7e415..d291f7065b2004 100644 --- a/Kconfig.adi +++ b/Kconfig.adi @@ -97,6 +97,7 @@ config KERNEL_ALL_ADI_DRIVERS imply GPIO_DS4520 imply RTC_DRV_MAX31335 imply REGULATOR_MAX77503 + imply REGULATOR_MAX77533 imply REGULATOR_MAX77857 imply REGULATOR_MAX77541 imply MFD_MAX77541 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4c08cf755d88e5..04e05c6113bd90 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -613,6 +613,18 @@ config REGULATOR_MAX77503 Say M here if you want to include support for the regulator as a module. +config REGULATOR_MAX77533 + tristate "Analog Devices MAX77533 Regulator" + depends on I2C + select REGMAP_I2C + help + This driver controls a Analog Devices MAX77533 14V input, 1.5A + high-efficiency buck converter via I2C bus. The device features + ultra-low 9µA quiescent current and supports both SKIP and FPWM + operating modes. + Say M here if you want to include support for the regulator as a + module. + config REGULATOR_MAX77541 tristate "Analog Devices MAX77541/77540 Regulator" depends on MFD_MAX77541 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 71f45d9317d24e..0ba9ded0be1974 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX5970) += max5970-regulator.o obj-$(CONFIG_REGULATOR_MAX77503) += max77503-regulator.o +obj-$(CONFIG_REGULATOR_MAX77533) += max77533-regulator.o obj-$(CONFIG_REGULATOR_MAX77541) += max77541-regulator.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o diff --git a/drivers/regulator/max77533-regulator.c b/drivers/regulator/max77533-regulator.c new file mode 100644 index 00000000000000..218deb47cb6e5c --- /dev/null +++ b/drivers/regulator/max77533-regulator.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 Analog Devices, Inc. + * ADI regulator driver for MAX77533. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register Addresses */ +#define MAX77533_REG_CFG 0x00 +#define MAX77533_REG_VOUT 0x01 + +/* CFG Register Bits */ +#define MAX77533_BIT_EN BIT(0) +#define MAX77533_BIT_EN_LOGIC BIT(1) +#define MAX77533_BIT_MODE BIT(2) +#define MAX77533_BIT_IPEAK BIT(3) +#define MAX77533_BIT_ADEN BIT(6) + +#define MAX77533_BITS_SFT_STRT GENMASK(5, 4) + +/* VOUT Register Bits */ +#define MAX77533_BITS_VOUT GENMASK(6, 0) + +struct max77533_regulator { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev; + struct gpio_desc *pok_gpio; + int pok_irq; +}; + +static const struct regmap_config max77533_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x01, +}; + +static const unsigned int max77533_current_limit_table[] = { + 500000, 2000000 +}; + +static irqreturn_t max77533_pok_irq_handler(int irq, void *data) +{ + struct max77533_regulator *max77533 = data; + int pok_state; + + pok_state = gpiod_get_value_cansleep(max77533->pok_gpio); + if (pok_state < 0) + return IRQ_HANDLED; + + if (pok_state) + regulator_notifier_call_chain(max77533->rdev, + REGULATOR_EVENT_VOLTAGE_CHANGE, + NULL); + else + regulator_notifier_call_chain(max77533->rdev, + REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + + return IRQ_HANDLED; +} + +static int max77533_get_status(struct regulator_dev *rdev) +{ + struct max77533_regulator *max77533 = rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + ret = regmap_read(max77533->regmap, MAX77533_REG_CFG, &val); + if (ret) + return REGULATOR_STATUS_ERROR; + + if (!(val & MAX77533_BIT_EN)) + return REGULATOR_STATUS_OFF; + + if (max77533->pok_gpio) { + int pok = gpiod_get_value_cansleep(max77533->pok_gpio); + + if (pok < 0) + return REGULATOR_STATUS_ERROR; + if (pok) + return REGULATOR_STATUS_ON; + + return REGULATOR_STATUS_ERROR; + } + + return REGULATOR_STATUS_ON; +} + +static int max77533_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct max77533_regulator *max77533 = rdev_get_drvdata(rdev); + + switch (mode) { + case REGULATOR_MODE_FAST: + return regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BIT_MODE, MAX77533_BIT_MODE); + case REGULATOR_MODE_NORMAL: + return regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BIT_MODE, 0); + default: + return -EINVAL; + } +} + +static unsigned int max77533_get_mode(struct regulator_dev *rdev) +{ + struct max77533_regulator *max77533 = rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + ret = regmap_read(max77533->regmap, MAX77533_REG_CFG, &val); + if (ret) + return REGULATOR_MODE_NORMAL; + + if (val & MAX77533_BIT_MODE) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + +static const struct regulator_ops max77533_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_soft_start = regulator_set_soft_start_regmap, + .set_mode = max77533_set_mode, + .get_mode = max77533_get_mode, + .get_status = max77533_get_status, +}; + +static const struct regulator_desc max77533_desc = { + .name = "max77533", + .ops = &max77533_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 800000, + .uV_step = 50000, + .n_voltages = 85, + .vsel_reg = MAX77533_REG_VOUT, + .vsel_mask = MAX77533_BITS_VOUT, + .enable_reg = MAX77533_REG_CFG, + .enable_mask = MAX77533_BIT_EN, + .active_discharge_reg = MAX77533_REG_CFG, + .active_discharge_mask = MAX77533_BIT_ADEN, + .active_discharge_off = 0, + .active_discharge_on = MAX77533_BIT_ADEN, + .soft_start_reg = MAX77533_REG_CFG, + .soft_start_mask = MAX77533_BITS_SFT_STRT, + .csel_reg = MAX77533_REG_CFG, + .csel_mask = MAX77533_BIT_IPEAK, + .curr_table = max77533_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77533_current_limit_table), +}; + +static int max77533_parse_dt(struct device *dev, struct max77533_regulator *max77533) +{ + struct device_node *np = dev->of_node; + u32 val; + int ret; + + ret = of_property_read_u32(np, "adi,peak-current-limit-microamp", &val); + if (!ret) { + unsigned int sel; + + if (val == 500000) + sel = 0; + else if (val == 2000000) + sel = 1; + else + return dev_err_probe(dev, -EINVAL, + "Invalid adi,peak-current-limit-microamp: %u\n", + val); + + ret = regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BIT_IPEAK, + sel ? MAX77533_BIT_IPEAK : 0); + if (ret) + return ret; + } + + ret = of_property_read_u32(np, "adi,soft-start-us", &val); + if (!ret) { + unsigned int sel; + + switch (val) { + case 1000: + sel = 0; + break; + case 2000: + sel = 1; + break; + case 4000: + sel = 2; + break; + case 8000: + sel = 3; + break; + default: + return dev_err_probe(dev, -EINVAL, + "Invalid adi,soft-start-us: %u\n", + val); + } + + ret = regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BITS_SFT_STRT, + FIELD_PREP(MAX77533_BITS_SFT_STRT, sel)); + if (ret) + return ret; + } + + if (of_property_read_bool(np, "adi,fpwm-mode")) { + ret = regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BIT_MODE, MAX77533_BIT_MODE); + if (ret) + return ret; + } + + if (of_property_read_bool(np, "adi,en-logic-and")) { + ret = regmap_update_bits(max77533->regmap, MAX77533_REG_CFG, + MAX77533_BIT_EN_LOGIC, MAX77533_BIT_EN_LOGIC); + if (ret) + return ret; + } + + return 0; +} + +static int max77533_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct max77533_regulator *max77533; + struct regulator_config config = {}; + int ret; + + max77533 = devm_kzalloc(dev, sizeof(*max77533), GFP_KERNEL); + if (!max77533) + return -ENOMEM; + + max77533->dev = dev; + + max77533->regmap = devm_regmap_init_i2c(client, &max77533_regmap_config); + if (IS_ERR(max77533->regmap)) + return dev_err_probe(dev, PTR_ERR(max77533->regmap), + "Failed to init regmap\n"); + + ret = max77533_parse_dt(dev, max77533); + if (ret) + return ret; + + max77533->pok_gpio = devm_gpiod_get_optional(dev, "pok", GPIOD_IN); + if (IS_ERR(max77533->pok_gpio)) + return dev_err_probe(dev, PTR_ERR(max77533->pok_gpio), + "Failed to get POK GPIO\n"); + + config.dev = dev; + config.driver_data = max77533; + config.of_node = dev->of_node; + config.regmap = max77533->regmap; + config.init_data = of_get_regulator_init_data(dev, dev->of_node, + &max77533_desc); + + max77533->rdev = devm_regulator_register(dev, &max77533_desc, &config); + if (IS_ERR(max77533->rdev)) + return dev_err_probe(dev, PTR_ERR(max77533->rdev), + "Failed to register regulator\n"); + + if (max77533->pok_gpio) { + max77533->pok_irq = gpiod_to_irq(max77533->pok_gpio); + if (max77533->pok_irq < 0) + return dev_err_probe(dev, max77533->pok_irq, + "Failed to get POK IRQ\n"); + + ret = devm_request_threaded_irq(dev, max77533->pok_irq, + NULL, + max77533_pok_irq_handler, + IRQF_ONESHOT | + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, + "max77533-pok", max77533); + if (ret) + return dev_err_probe(dev, ret, + "Failed to request POK IRQ\n"); + } + + return 0; +} + +static const struct of_device_id max77533_of_match[] = { + { .compatible = "adi,max77533" }, + { .compatible = "maxim,max77533" }, + { .compatible = "maxim,max77533a" }, + { .compatible = "maxim,max77533b-12" }, + { .compatible = "maxim,max77533b-18" }, + { .compatible = "maxim,max77533b-33" }, + { .compatible = "maxim,max77533q" }, + { } +}; +MODULE_DEVICE_TABLE(of, max77533_of_match); + +static const struct i2c_device_id max77533_id[] = { + { "max77533" }, + { "max77533a" }, + { "max77533b-12" }, + { "max77533b-18" }, + { "max77533b-33" }, + { "max77533q" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max77533_id); + +static struct i2c_driver max77533_driver = { + .driver = { + .name = "max77533", + .of_match_table = max77533_of_match, + }, + .probe = max77533_probe, + .id_table = max77533_id, +}; +module_i2c_driver(max77533_driver); + +MODULE_AUTHOR("Sean Park "); +MODULE_DESCRIPTION("MAX77533 regulator driver"); +MODULE_LICENSE("GPL");