mfd: Add new driver for MAX77705 PMIC

Add the core MFD driver for max77705 PMIC. Drivers for sub-devices
will be added in subsequent patches.

Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20250123-starqltechn_integration_upstream-v17-5-8b06685b6612@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>
pull/1188/head
Dzmitry Sankouski 2025-01-23 18:04:30 +03:00 committed by Lee Jones
parent 7b591ef98b
commit c8d50f0297
6 changed files with 379 additions and 1 deletions

View File

@ -14320,6 +14320,7 @@ F: drivers/*/*max77843.c
F: drivers/*/max14577*.c F: drivers/*/max14577*.c
F: drivers/*/max77686*.c F: drivers/*/max77686*.c
F: drivers/*/max77693*.c F: drivers/*/max77693*.c
F: drivers/*/max77705*.c
F: drivers/clk/clk-max77686.c F: drivers/clk/clk-max77686.c
F: drivers/extcon/extcon-max14577.c F: drivers/extcon/extcon-max14577.c
F: drivers/extcon/extcon-max77693.c F: drivers/extcon/extcon-max77693.c
@ -14327,6 +14328,7 @@ F: drivers/rtc/rtc-max77686.c
F: include/linux/mfd/max14577*.h F: include/linux/mfd/max14577*.h
F: include/linux/mfd/max77686*.h F: include/linux/mfd/max77686*.h
F: include/linux/mfd/max77693*.h F: include/linux/mfd/max77693*.h
F: include/linux/mfd/max77705*.h
MAXIRADIO FM RADIO RECEIVER DRIVER MAXIRADIO FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl> M: Hans Verkuil <hverkuil@xs4all.nl>

View File

@ -916,6 +916,19 @@ config MFD_MAX77693
additional drivers must be enabled in order to use the functionality additional drivers must be enabled in order to use the functionality
of the device. of the device.
config MFD_MAX77705
tristate "Maxim MAX77705 PMIC Support"
depends on I2C
select MFD_CORE
select MFD_SIMPLE_MFD_I2C
help
Say yes here to add support for Maxim Integrated MAX77705 PMIC.
This is a Power Management IC with Charger, safe LDOs, Flash, Haptic
and MUIC controls on chip.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_MAX77714 config MFD_MAX77714
tristate "Maxim Semiconductor MAX77714 PMIC Support" tristate "Maxim Semiconductor MAX77714 PMIC Support"
depends on I2C depends on I2C

View File

@ -168,6 +168,7 @@ obj-$(CONFIG_MFD_MAX77620) += max77620.o
obj-$(CONFIG_MFD_MAX77650) += max77650.o obj-$(CONFIG_MFD_MAX77650) += max77650.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o obj-$(CONFIG_MFD_MAX77693) += max77693.o
obj-$(CONFIG_MFD_MAX77705) += max77705.o
obj-$(CONFIG_MFD_MAX77714) += max77714.o obj-$(CONFIG_MFD_MAX77714) += max77714.o
obj-$(CONFIG_MFD_MAX77843) += max77843.o obj-$(CONFIG_MFD_MAX77843) += max77843.o
obj-$(CONFIG_MFD_MAX8907) += max8907.o obj-$(CONFIG_MFD_MAX8907) += max8907.o

182
drivers/mfd/max77705.c Normal file
View File

@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Maxim MAX77705 PMIC core driver
*
* Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
**/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max77705-private.h>
#include <linux/mfd/max77693-common.h>
#include <linux/pm.h>
#include <linux/power/max17042_battery.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/of.h>
static struct mfd_cell max77705_devs[] = {
MFD_CELL_OF("max77705-rgb", NULL, NULL, 0, 0, "maxim,max77705-rgb"),
MFD_CELL_OF("max77705-charger", NULL, NULL, 0, 0, "maxim,max77705-charger"),
MFD_CELL_OF("max77705-haptic", NULL, NULL, 0, 0, "maxim,max77705-haptic"),
};
static const struct regmap_range max77705_readable_ranges[] = {
regmap_reg_range(MAX77705_PMIC_REG_PMICID1, MAX77705_PMIC_REG_BSTOUT_MASK),
regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1),
regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2),
regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2),
regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET),
};
static const struct regmap_range max77705_writable_ranges[] = {
regmap_reg_range(MAX77705_PMIC_REG_MAINCTRL1, MAX77705_PMIC_REG_BSTOUT_MASK),
regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1),
regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2),
regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1),
regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2),
regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET),
};
static const struct regmap_access_table max77705_readable_table = {
.yes_ranges = max77705_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77705_readable_ranges),
};
static const struct regmap_access_table max77705_writable_table = {
.yes_ranges = max77705_writable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77705_writable_ranges),
};
static const struct regmap_config max77705_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.rd_table = &max77705_readable_table,
.wr_table = &max77705_writable_table,
.max_register = MAX77705_PMIC_REG_USBC_RESET,
};
static const struct regmap_irq max77705_topsys_irqs[] = {
{ .mask = MAX77705_SYSTEM_IRQ_BSTEN_INT, },
{ .mask = MAX77705_SYSTEM_IRQ_SYSUVLO_INT, },
{ .mask = MAX77705_SYSTEM_IRQ_SYSOVLO_INT, },
{ .mask = MAX77705_SYSTEM_IRQ_TSHDN_INT, },
{ .mask = MAX77705_SYSTEM_IRQ_TM_INT, },
};
static const struct regmap_irq_chip max77705_topsys_irq_chip = {
.name = "max77705-topsys",
.status_base = MAX77705_PMIC_REG_SYSTEM_INT,
.mask_base = MAX77705_PMIC_REG_SYSTEM_INT_MASK,
.num_regs = 1,
.irqs = max77705_topsys_irqs,
.num_irqs = ARRAY_SIZE(max77705_topsys_irqs),
};
static int max77705_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct max77693_dev *max77705;
struct regmap_irq_chip_data *irq_data;
struct irq_domain *domain;
enum max77705_hw_rev pmic_rev;
unsigned int pmic_rev_value;
int ret;
max77705 = devm_kzalloc(dev, sizeof(*max77705), GFP_KERNEL);
if (!max77705)
return -ENOMEM;
max77705->i2c = i2c;
max77705->type = TYPE_MAX77705;
i2c_set_clientdata(i2c, max77705);
max77705->regmap = devm_regmap_init_i2c(i2c, &max77705_regmap_config);
if (IS_ERR(max77705->regmap))
return PTR_ERR(max77705->regmap);
ret = regmap_read(max77705->regmap, MAX77705_PMIC_REG_PMICREV, &pmic_rev_value);
if (ret < 0)
return -ENODEV;
pmic_rev = pmic_rev_value & MAX77705_REVISION_MASK;
if (pmic_rev != MAX77705_PASS3)
return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev);
ret = devm_regmap_add_irq_chip(dev, max77705->regmap,
i2c->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
&max77705_topsys_irq_chip,
&irq_data);
if (ret)
return dev_err_probe(dev, ret, "Failed to add IRQ chip\n");
/* Unmask interrupts from all blocks in interrupt source register */
ret = regmap_update_bits(max77705->regmap,
MAX77705_PMIC_REG_INTSRC_MASK,
MAX77705_SRC_IRQ_ALL, (unsigned int)~MAX77705_SRC_IRQ_ALL);
if (ret < 0)
return dev_err_probe(dev, ret, "Could not unmask interrupts in INTSRC\n");
domain = regmap_irq_get_domain(irq_data);
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
max77705_devs, ARRAY_SIZE(max77705_devs),
NULL, 0, domain);
if (ret)
return dev_err_probe(dev, ret, "Failed to register child devices\n");
device_init_wakeup(dev, true);
return 0;
}
static int max77705_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
disable_irq(i2c->irq);
if (device_may_wakeup(dev))
enable_irq_wake(i2c->irq);
return 0;
}
static int max77705_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
if (device_may_wakeup(dev))
disable_irq_wake(i2c->irq);
enable_irq(i2c->irq);
return 0;
}
DEFINE_SIMPLE_DEV_PM_OPS(max77705_pm_ops, max77705_suspend, max77705_resume);
static const struct of_device_id max77705_i2c_of_match[] = {
{ .compatible = "maxim,max77705" },
{ }
};
MODULE_DEVICE_TABLE(of, max77705_i2c_of_match);
static struct i2c_driver max77705_i2c_driver = {
.driver = {
.name = "max77705",
.of_match_table = max77705_i2c_of_match,
.pm = pm_sleep_ptr(&max77705_pm_ops),
},
.probe = max77705_i2c_probe
};
module_i2c_driver(max77705_i2c_driver);
MODULE_DESCRIPTION("Maxim MAX77705 PMIC core driver");
MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
MODULE_LICENSE("GPL");

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */ /* SPDX-License-Identifier: GPL-2.0+ */
/* /*
* Common data shared between Maxim 77693 and 77843 drivers * Common data shared between Maxim 77693, 77705 and 77843 drivers
* *
* Copyright (C) 2015 Samsung Electronics * Copyright (C) 2015 Samsung Electronics
*/ */
@ -11,6 +11,7 @@
enum max77693_types { enum max77693_types {
TYPE_MAX77693_UNKNOWN, TYPE_MAX77693_UNKNOWN,
TYPE_MAX77693, TYPE_MAX77693,
TYPE_MAX77705,
TYPE_MAX77843, TYPE_MAX77843,
TYPE_MAX77693_NUM, TYPE_MAX77693_NUM,
@ -32,6 +33,7 @@ struct max77693_dev {
struct regmap *regmap_muic; struct regmap *regmap_muic;
struct regmap *regmap_haptic; /* Only MAX77693 */ struct regmap *regmap_haptic; /* Only MAX77693 */
struct regmap *regmap_chg; /* Only MAX77843 */ struct regmap *regmap_chg; /* Only MAX77843 */
struct regmap *regmap_leds; /* Only MAX77705 */
struct regmap_irq_chip_data *irq_data_led; struct regmap_irq_chip_data *irq_data_led;
struct regmap_irq_chip_data *irq_data_topsys; struct regmap_irq_chip_data *irq_data_topsys;

View File

@ -0,0 +1,178 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Maxim MAX77705 definitions.
*
* Copyright (C) 2015 Samsung Electronics, Inc.
* Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
*/
#ifndef __LINUX_MFD_MAX77705_PRIV_H
#define __LINUX_MFD_MAX77705_PRIV_H
#define MAX77705_SRC_IRQ_CHG BIT(0)
#define MAX77705_SRC_IRQ_TOP BIT(1)
#define MAX77705_SRC_IRQ_FG BIT(2)
#define MAX77705_SRC_IRQ_USBC BIT(3)
#define MAX77705_SRC_IRQ_ALL (MAX77705_SRC_IRQ_CHG | MAX77705_SRC_IRQ_TOP | \
MAX77705_SRC_IRQ_FG | MAX77705_SRC_IRQ_USBC)
/* MAX77705_PMIC_REG_PMICREV register */
#define MAX77705_VERSION_SHIFT 3
#define MAX77705_REVISION_MASK GENMASK(2, 0)
#define MAX77705_VERSION_MASK GENMASK(7, MAX77705_VERSION_SHIFT)
/* MAX77705_PMIC_REG_MAINCTRL1 register */
#define MAX77705_MAINCTRL1_BIASEN_SHIFT 7
#define MAX77705_MAINCTRL1_BIASEN_MASK BIT(MAX77705_MAINCTRL1_BIASEN_SHIFT)
/* MAX77705_PMIC_REG_MCONFIG2 (haptics) register */
#define MAX77705_CONFIG2_MEN_SHIFT 6
#define MAX77705_CONFIG2_MODE_SHIFT 7
#define MAX77705_CONFIG2_HTYP_SHIFT 5
/* MAX77705_PMIC_REG_SYSTEM_INT_MASK register */
#define MAX77705_SYSTEM_IRQ_BSTEN_INT BIT(3)
#define MAX77705_SYSTEM_IRQ_SYSUVLO_INT BIT(4)
#define MAX77705_SYSTEM_IRQ_SYSOVLO_INT BIT(5)
#define MAX77705_SYSTEM_IRQ_TSHDN_INT BIT(6)
#define MAX77705_SYSTEM_IRQ_TM_INT BIT(7)
enum max77705_hw_rev {
MAX77705_PASS1 = 1,
MAX77705_PASS2,
MAX77705_PASS3
};
enum max77705_reg {
MAX77705_PMIC_REG_PMICID1 = 0x00,
MAX77705_PMIC_REG_PMICREV = 0x01,
MAX77705_PMIC_REG_MAINCTRL1 = 0x02,
MAX77705_PMIC_REG_BSTOUT_MASK = 0x03,
MAX77705_PMIC_REG_FORCE_EN_MASK = 0x08,
MAX77705_PMIC_REG_MCONFIG = 0x10,
MAX77705_PMIC_REG_MCONFIG2 = 0x11,
MAX77705_PMIC_REG_INTSRC = 0x22,
MAX77705_PMIC_REG_INTSRC_MASK = 0x23,
MAX77705_PMIC_REG_SYSTEM_INT = 0x24,
MAX77705_PMIC_REG_RESERVED_25 = 0x25,
MAX77705_PMIC_REG_SYSTEM_INT_MASK = 0x26,
MAX77705_PMIC_REG_RESERVED_27 = 0x27,
MAX77705_PMIC_REG_RESERVED_28 = 0x28,
MAX77705_PMIC_REG_RESERVED_29 = 0x29,
MAX77705_PMIC_REG_BOOSTCONTROL1 = 0x4C,
MAX77705_PMIC_REG_BOOSTCONTROL2 = 0x4F,
MAX77705_PMIC_REG_SW_RESET = 0x50,
MAX77705_PMIC_REG_USBC_RESET = 0x51,
MAX77705_PMIC_REG_END
};
enum max77705_chg_reg {
MAX77705_CHG_REG_BASE = 0xB0,
MAX77705_CHG_REG_INT = 0,
MAX77705_CHG_REG_INT_MASK,
MAX77705_CHG_REG_INT_OK,
MAX77705_CHG_REG_DETAILS_00,
MAX77705_CHG_REG_DETAILS_01,
MAX77705_CHG_REG_DETAILS_02,
MAX77705_CHG_REG_DTLS_03,
MAX77705_CHG_REG_CNFG_00,
MAX77705_CHG_REG_CNFG_01,
MAX77705_CHG_REG_CNFG_02,
MAX77705_CHG_REG_CNFG_03,
MAX77705_CHG_REG_CNFG_04,
MAX77705_CHG_REG_CNFG_05,
MAX77705_CHG_REG_CNFG_06,
MAX77705_CHG_REG_CNFG_07,
MAX77705_CHG_REG_CNFG_08,
MAX77705_CHG_REG_CNFG_09,
MAX77705_CHG_REG_CNFG_10,
MAX77705_CHG_REG_CNFG_11,
MAX77705_CHG_REG_CNFG_12,
MAX77705_CHG_REG_CNFG_13,
MAX77705_CHG_REG_CNFG_14,
MAX77705_CHG_REG_SAFEOUT_CTRL
};
enum max77705_fuelgauge_reg {
STATUS_REG = 0x00,
VALRT_THRESHOLD_REG = 0x01,
TALRT_THRESHOLD_REG = 0x02,
SALRT_THRESHOLD_REG = 0x03,
REMCAP_REP_REG = 0x05,
SOCREP_REG = 0x06,
TEMPERATURE_REG = 0x08,
VCELL_REG = 0x09,
TIME_TO_EMPTY_REG = 0x11,
FULLSOCTHR_REG = 0x13,
CURRENT_REG = 0x0A,
AVG_CURRENT_REG = 0x0B,
SOCMIX_REG = 0x0D,
SOCAV_REG = 0x0E,
REMCAP_MIX_REG = 0x0F,
FULLCAP_REG = 0x10,
RFAST_REG = 0x15,
AVR_TEMPERATURE_REG = 0x16,
CYCLES_REG = 0x17,
DESIGNCAP_REG = 0x18,
AVR_VCELL_REG = 0x19,
TIME_TO_FULL_REG = 0x20,
CONFIG_REG = 0x1D,
ICHGTERM_REG = 0x1E,
REMCAP_AV_REG = 0x1F,
FULLCAP_NOM_REG = 0x23,
LEARN_CFG_REG = 0x28,
FILTER_CFG_REG = 0x29,
MISCCFG_REG = 0x2B,
QRTABLE20_REG = 0x32,
FULLCAP_REP_REG = 0x35,
RCOMP_REG = 0x38,
VEMPTY_REG = 0x3A,
FSTAT_REG = 0x3D,
DISCHARGE_THRESHOLD_REG = 0x40,
QRTABLE30_REG = 0x42,
ISYS_REG = 0x43,
DQACC_REG = 0x45,
DPACC_REG = 0x46,
AVGISYS_REG = 0x4B,
QH_REG = 0x4D,
VSYS_REG = 0xB1,
TALRTTH2_REG = 0xB2,
VBYP_REG = 0xB3,
CONFIG2_REG = 0xBB,
IIN_REG = 0xD0,
OCV_REG = 0xEE,
VFOCV_REG = 0xFB,
VFSOC_REG = 0xFF,
MAX77705_FG_END
};
enum max77705_led_reg {
MAX77705_RGBLED_REG_BASE = 0x30,
MAX77705_RGBLED_REG_LEDEN = 0,
MAX77705_RGBLED_REG_LED0BRT,
MAX77705_RGBLED_REG_LED1BRT,
MAX77705_RGBLED_REG_LED2BRT,
MAX77705_RGBLED_REG_LED3BRT,
MAX77705_RGBLED_REG_LEDRMP,
MAX77705_RGBLED_REG_LEDBLNK,
MAX77705_LED_REG_END
};
enum max77705_charger_battery_state {
MAX77705_BATTERY_NOBAT,
MAX77705_BATTERY_PREQUALIFICATION,
MAX77705_BATTERY_DEAD,
MAX77705_BATTERY_GOOD,
MAX77705_BATTERY_LOWVOLTAGE,
MAX77705_BATTERY_OVERVOLTAGE,
MAX77705_BATTERY_RESERVED
};
enum max77705_charger_charge_type {
MAX77705_CHARGER_CONSTANT_CURRENT = 1,
MAX77705_CHARGER_CONSTANT_VOLTAGE,
MAX77705_CHARGER_END_OF_CHARGE,
MAX77705_CHARGER_DONE
};
#endif /* __LINUX_MFD_MAX77705_PRIV_H */