Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Dzmitry Sankouski and committed by
Lee Jones
c8d50f02 7b591ef9

+379 -1
+2
MAINTAINERS
··· 14320 14320 F: drivers/*/max14577*.c 14321 14321 F: drivers/*/max77686*.c 14322 14322 F: drivers/*/max77693*.c 14323 + F: drivers/*/max77705*.c 14323 14324 F: drivers/clk/clk-max77686.c 14324 14325 F: drivers/extcon/extcon-max14577.c 14325 14326 F: drivers/extcon/extcon-max77693.c ··· 14328 14327 F: include/linux/mfd/max14577*.h 14329 14328 F: include/linux/mfd/max77686*.h 14330 14329 F: include/linux/mfd/max77693*.h 14330 + F: include/linux/mfd/max77705*.h 14331 14331 14332 14332 MAXIRADIO FM RADIO RECEIVER DRIVER 14333 14333 M: Hans Verkuil <hverkuil@xs4all.nl>
+13
drivers/mfd/Kconfig
··· 916 916 additional drivers must be enabled in order to use the functionality 917 917 of the device. 918 918 919 + config MFD_MAX77705 920 + tristate "Maxim MAX77705 PMIC Support" 921 + depends on I2C 922 + select MFD_CORE 923 + select MFD_SIMPLE_MFD_I2C 924 + help 925 + Say yes here to add support for Maxim Integrated MAX77705 PMIC. 926 + This is a Power Management IC with Charger, safe LDOs, Flash, Haptic 927 + and MUIC controls on chip. 928 + This driver provides common support for accessing the device; 929 + additional drivers must be enabled in order to use the functionality 930 + of the device. 931 + 919 932 config MFD_MAX77714 920 933 tristate "Maxim Semiconductor MAX77714 PMIC Support" 921 934 depends on I2C
+1
drivers/mfd/Makefile
··· 168 168 obj-$(CONFIG_MFD_MAX77650) += max77650.o 169 169 obj-$(CONFIG_MFD_MAX77686) += max77686.o 170 170 obj-$(CONFIG_MFD_MAX77693) += max77693.o 171 + obj-$(CONFIG_MFD_MAX77705) += max77705.o 171 172 obj-$(CONFIG_MFD_MAX77714) += max77714.o 172 173 obj-$(CONFIG_MFD_MAX77843) += max77843.o 173 174 obj-$(CONFIG_MFD_MAX8907) += max8907.o
+182
drivers/mfd/max77705.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Maxim MAX77705 PMIC core driver 4 + * 5 + * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com> 6 + **/ 7 + #include <linux/i2c.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/mfd/core.h> 10 + #include <linux/mfd/max77705-private.h> 11 + #include <linux/mfd/max77693-common.h> 12 + #include <linux/pm.h> 13 + #include <linux/power/max17042_battery.h> 14 + #include <linux/module.h> 15 + #include <linux/regmap.h> 16 + #include <linux/of.h> 17 + 18 + static struct mfd_cell max77705_devs[] = { 19 + MFD_CELL_OF("max77705-rgb", NULL, NULL, 0, 0, "maxim,max77705-rgb"), 20 + MFD_CELL_OF("max77705-charger", NULL, NULL, 0, 0, "maxim,max77705-charger"), 21 + MFD_CELL_OF("max77705-haptic", NULL, NULL, 0, 0, "maxim,max77705-haptic"), 22 + }; 23 + 24 + static const struct regmap_range max77705_readable_ranges[] = { 25 + regmap_reg_range(MAX77705_PMIC_REG_PMICID1, MAX77705_PMIC_REG_BSTOUT_MASK), 26 + regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), 27 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 28 + regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), 29 + regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), 30 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 31 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), 32 + regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), 33 + }; 34 + 35 + static const struct regmap_range max77705_writable_ranges[] = { 36 + regmap_reg_range(MAX77705_PMIC_REG_MAINCTRL1, MAX77705_PMIC_REG_BSTOUT_MASK), 37 + regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), 38 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 39 + regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), 40 + regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), 41 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 42 + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), 43 + regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), 44 + }; 45 + 46 + static const struct regmap_access_table max77705_readable_table = { 47 + .yes_ranges = max77705_readable_ranges, 48 + .n_yes_ranges = ARRAY_SIZE(max77705_readable_ranges), 49 + }; 50 + 51 + static const struct regmap_access_table max77705_writable_table = { 52 + .yes_ranges = max77705_writable_ranges, 53 + .n_yes_ranges = ARRAY_SIZE(max77705_writable_ranges), 54 + }; 55 + 56 + static const struct regmap_config max77705_regmap_config = { 57 + .reg_bits = 8, 58 + .val_bits = 8, 59 + .rd_table = &max77705_readable_table, 60 + .wr_table = &max77705_writable_table, 61 + .max_register = MAX77705_PMIC_REG_USBC_RESET, 62 + }; 63 + 64 + static const struct regmap_irq max77705_topsys_irqs[] = { 65 + { .mask = MAX77705_SYSTEM_IRQ_BSTEN_INT, }, 66 + { .mask = MAX77705_SYSTEM_IRQ_SYSUVLO_INT, }, 67 + { .mask = MAX77705_SYSTEM_IRQ_SYSOVLO_INT, }, 68 + { .mask = MAX77705_SYSTEM_IRQ_TSHDN_INT, }, 69 + { .mask = MAX77705_SYSTEM_IRQ_TM_INT, }, 70 + }; 71 + 72 + static const struct regmap_irq_chip max77705_topsys_irq_chip = { 73 + .name = "max77705-topsys", 74 + .status_base = MAX77705_PMIC_REG_SYSTEM_INT, 75 + .mask_base = MAX77705_PMIC_REG_SYSTEM_INT_MASK, 76 + .num_regs = 1, 77 + .irqs = max77705_topsys_irqs, 78 + .num_irqs = ARRAY_SIZE(max77705_topsys_irqs), 79 + }; 80 + 81 + static int max77705_i2c_probe(struct i2c_client *i2c) 82 + { 83 + struct device *dev = &i2c->dev; 84 + struct max77693_dev *max77705; 85 + struct regmap_irq_chip_data *irq_data; 86 + struct irq_domain *domain; 87 + enum max77705_hw_rev pmic_rev; 88 + unsigned int pmic_rev_value; 89 + int ret; 90 + 91 + max77705 = devm_kzalloc(dev, sizeof(*max77705), GFP_KERNEL); 92 + if (!max77705) 93 + return -ENOMEM; 94 + 95 + max77705->i2c = i2c; 96 + max77705->type = TYPE_MAX77705; 97 + i2c_set_clientdata(i2c, max77705); 98 + 99 + max77705->regmap = devm_regmap_init_i2c(i2c, &max77705_regmap_config); 100 + if (IS_ERR(max77705->regmap)) 101 + return PTR_ERR(max77705->regmap); 102 + 103 + ret = regmap_read(max77705->regmap, MAX77705_PMIC_REG_PMICREV, &pmic_rev_value); 104 + if (ret < 0) 105 + return -ENODEV; 106 + 107 + pmic_rev = pmic_rev_value & MAX77705_REVISION_MASK; 108 + if (pmic_rev != MAX77705_PASS3) 109 + return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev); 110 + 111 + ret = devm_regmap_add_irq_chip(dev, max77705->regmap, 112 + i2c->irq, 113 + IRQF_ONESHOT | IRQF_SHARED, 0, 114 + &max77705_topsys_irq_chip, 115 + &irq_data); 116 + if (ret) 117 + return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); 118 + 119 + /* Unmask interrupts from all blocks in interrupt source register */ 120 + ret = regmap_update_bits(max77705->regmap, 121 + MAX77705_PMIC_REG_INTSRC_MASK, 122 + MAX77705_SRC_IRQ_ALL, (unsigned int)~MAX77705_SRC_IRQ_ALL); 123 + if (ret < 0) 124 + return dev_err_probe(dev, ret, "Could not unmask interrupts in INTSRC\n"); 125 + 126 + domain = regmap_irq_get_domain(irq_data); 127 + 128 + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 129 + max77705_devs, ARRAY_SIZE(max77705_devs), 130 + NULL, 0, domain); 131 + if (ret) 132 + return dev_err_probe(dev, ret, "Failed to register child devices\n"); 133 + 134 + device_init_wakeup(dev, true); 135 + 136 + return 0; 137 + } 138 + 139 + static int max77705_suspend(struct device *dev) 140 + { 141 + struct i2c_client *i2c = to_i2c_client(dev); 142 + 143 + disable_irq(i2c->irq); 144 + 145 + if (device_may_wakeup(dev)) 146 + enable_irq_wake(i2c->irq); 147 + 148 + return 0; 149 + } 150 + 151 + static int max77705_resume(struct device *dev) 152 + { 153 + struct i2c_client *i2c = to_i2c_client(dev); 154 + 155 + if (device_may_wakeup(dev)) 156 + disable_irq_wake(i2c->irq); 157 + 158 + enable_irq(i2c->irq); 159 + 160 + return 0; 161 + } 162 + DEFINE_SIMPLE_DEV_PM_OPS(max77705_pm_ops, max77705_suspend, max77705_resume); 163 + 164 + static const struct of_device_id max77705_i2c_of_match[] = { 165 + { .compatible = "maxim,max77705" }, 166 + { } 167 + }; 168 + MODULE_DEVICE_TABLE(of, max77705_i2c_of_match); 169 + 170 + static struct i2c_driver max77705_i2c_driver = { 171 + .driver = { 172 + .name = "max77705", 173 + .of_match_table = max77705_i2c_of_match, 174 + .pm = pm_sleep_ptr(&max77705_pm_ops), 175 + }, 176 + .probe = max77705_i2c_probe 177 + }; 178 + module_i2c_driver(max77705_i2c_driver); 179 + 180 + MODULE_DESCRIPTION("Maxim MAX77705 PMIC core driver"); 181 + MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>"); 182 + MODULE_LICENSE("GPL");
+3 -1
include/linux/mfd/max77693-common.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0+ */ 2 2 /* 3 - * Common data shared between Maxim 77693 and 77843 drivers 3 + * Common data shared between Maxim 77693, 77705 and 77843 drivers 4 4 * 5 5 * Copyright (C) 2015 Samsung Electronics 6 6 */ ··· 11 11 enum max77693_types { 12 12 TYPE_MAX77693_UNKNOWN, 13 13 TYPE_MAX77693, 14 + TYPE_MAX77705, 14 15 TYPE_MAX77843, 15 16 16 17 TYPE_MAX77693_NUM, ··· 33 32 struct regmap *regmap_muic; 34 33 struct regmap *regmap_haptic; /* Only MAX77693 */ 35 34 struct regmap *regmap_chg; /* Only MAX77843 */ 35 + struct regmap *regmap_leds; /* Only MAX77705 */ 36 36 37 37 struct regmap_irq_chip_data *irq_data_led; 38 38 struct regmap_irq_chip_data *irq_data_topsys;
+178
include/linux/mfd/max77705-private.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Maxim MAX77705 definitions. 4 + * 5 + * Copyright (C) 2015 Samsung Electronics, Inc. 6 + * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com> 7 + */ 8 + 9 + #ifndef __LINUX_MFD_MAX77705_PRIV_H 10 + #define __LINUX_MFD_MAX77705_PRIV_H 11 + 12 + #define MAX77705_SRC_IRQ_CHG BIT(0) 13 + #define MAX77705_SRC_IRQ_TOP BIT(1) 14 + #define MAX77705_SRC_IRQ_FG BIT(2) 15 + #define MAX77705_SRC_IRQ_USBC BIT(3) 16 + #define MAX77705_SRC_IRQ_ALL (MAX77705_SRC_IRQ_CHG | MAX77705_SRC_IRQ_TOP | \ 17 + MAX77705_SRC_IRQ_FG | MAX77705_SRC_IRQ_USBC) 18 + 19 + /* MAX77705_PMIC_REG_PMICREV register */ 20 + #define MAX77705_VERSION_SHIFT 3 21 + #define MAX77705_REVISION_MASK GENMASK(2, 0) 22 + #define MAX77705_VERSION_MASK GENMASK(7, MAX77705_VERSION_SHIFT) 23 + /* MAX77705_PMIC_REG_MAINCTRL1 register */ 24 + #define MAX77705_MAINCTRL1_BIASEN_SHIFT 7 25 + #define MAX77705_MAINCTRL1_BIASEN_MASK BIT(MAX77705_MAINCTRL1_BIASEN_SHIFT) 26 + /* MAX77705_PMIC_REG_MCONFIG2 (haptics) register */ 27 + #define MAX77705_CONFIG2_MEN_SHIFT 6 28 + #define MAX77705_CONFIG2_MODE_SHIFT 7 29 + #define MAX77705_CONFIG2_HTYP_SHIFT 5 30 + /* MAX77705_PMIC_REG_SYSTEM_INT_MASK register */ 31 + #define MAX77705_SYSTEM_IRQ_BSTEN_INT BIT(3) 32 + #define MAX77705_SYSTEM_IRQ_SYSUVLO_INT BIT(4) 33 + #define MAX77705_SYSTEM_IRQ_SYSOVLO_INT BIT(5) 34 + #define MAX77705_SYSTEM_IRQ_TSHDN_INT BIT(6) 35 + #define MAX77705_SYSTEM_IRQ_TM_INT BIT(7) 36 + 37 + enum max77705_hw_rev { 38 + MAX77705_PASS1 = 1, 39 + MAX77705_PASS2, 40 + MAX77705_PASS3 41 + }; 42 + 43 + enum max77705_reg { 44 + MAX77705_PMIC_REG_PMICID1 = 0x00, 45 + MAX77705_PMIC_REG_PMICREV = 0x01, 46 + MAX77705_PMIC_REG_MAINCTRL1 = 0x02, 47 + MAX77705_PMIC_REG_BSTOUT_MASK = 0x03, 48 + MAX77705_PMIC_REG_FORCE_EN_MASK = 0x08, 49 + MAX77705_PMIC_REG_MCONFIG = 0x10, 50 + MAX77705_PMIC_REG_MCONFIG2 = 0x11, 51 + MAX77705_PMIC_REG_INTSRC = 0x22, 52 + MAX77705_PMIC_REG_INTSRC_MASK = 0x23, 53 + MAX77705_PMIC_REG_SYSTEM_INT = 0x24, 54 + MAX77705_PMIC_REG_RESERVED_25 = 0x25, 55 + MAX77705_PMIC_REG_SYSTEM_INT_MASK = 0x26, 56 + MAX77705_PMIC_REG_RESERVED_27 = 0x27, 57 + MAX77705_PMIC_REG_RESERVED_28 = 0x28, 58 + MAX77705_PMIC_REG_RESERVED_29 = 0x29, 59 + MAX77705_PMIC_REG_BOOSTCONTROL1 = 0x4C, 60 + MAX77705_PMIC_REG_BOOSTCONTROL2 = 0x4F, 61 + MAX77705_PMIC_REG_SW_RESET = 0x50, 62 + MAX77705_PMIC_REG_USBC_RESET = 0x51, 63 + 64 + MAX77705_PMIC_REG_END 65 + }; 66 + 67 + enum max77705_chg_reg { 68 + MAX77705_CHG_REG_BASE = 0xB0, 69 + MAX77705_CHG_REG_INT = 0, 70 + MAX77705_CHG_REG_INT_MASK, 71 + MAX77705_CHG_REG_INT_OK, 72 + MAX77705_CHG_REG_DETAILS_00, 73 + MAX77705_CHG_REG_DETAILS_01, 74 + MAX77705_CHG_REG_DETAILS_02, 75 + MAX77705_CHG_REG_DTLS_03, 76 + MAX77705_CHG_REG_CNFG_00, 77 + MAX77705_CHG_REG_CNFG_01, 78 + MAX77705_CHG_REG_CNFG_02, 79 + MAX77705_CHG_REG_CNFG_03, 80 + MAX77705_CHG_REG_CNFG_04, 81 + MAX77705_CHG_REG_CNFG_05, 82 + MAX77705_CHG_REG_CNFG_06, 83 + MAX77705_CHG_REG_CNFG_07, 84 + MAX77705_CHG_REG_CNFG_08, 85 + MAX77705_CHG_REG_CNFG_09, 86 + MAX77705_CHG_REG_CNFG_10, 87 + MAX77705_CHG_REG_CNFG_11, 88 + 89 + MAX77705_CHG_REG_CNFG_12, 90 + MAX77705_CHG_REG_CNFG_13, 91 + MAX77705_CHG_REG_CNFG_14, 92 + MAX77705_CHG_REG_SAFEOUT_CTRL 93 + }; 94 + 95 + enum max77705_fuelgauge_reg { 96 + STATUS_REG = 0x00, 97 + VALRT_THRESHOLD_REG = 0x01, 98 + TALRT_THRESHOLD_REG = 0x02, 99 + SALRT_THRESHOLD_REG = 0x03, 100 + REMCAP_REP_REG = 0x05, 101 + SOCREP_REG = 0x06, 102 + TEMPERATURE_REG = 0x08, 103 + VCELL_REG = 0x09, 104 + TIME_TO_EMPTY_REG = 0x11, 105 + FULLSOCTHR_REG = 0x13, 106 + CURRENT_REG = 0x0A, 107 + AVG_CURRENT_REG = 0x0B, 108 + SOCMIX_REG = 0x0D, 109 + SOCAV_REG = 0x0E, 110 + REMCAP_MIX_REG = 0x0F, 111 + FULLCAP_REG = 0x10, 112 + RFAST_REG = 0x15, 113 + AVR_TEMPERATURE_REG = 0x16, 114 + CYCLES_REG = 0x17, 115 + DESIGNCAP_REG = 0x18, 116 + AVR_VCELL_REG = 0x19, 117 + TIME_TO_FULL_REG = 0x20, 118 + CONFIG_REG = 0x1D, 119 + ICHGTERM_REG = 0x1E, 120 + REMCAP_AV_REG = 0x1F, 121 + FULLCAP_NOM_REG = 0x23, 122 + LEARN_CFG_REG = 0x28, 123 + FILTER_CFG_REG = 0x29, 124 + MISCCFG_REG = 0x2B, 125 + QRTABLE20_REG = 0x32, 126 + FULLCAP_REP_REG = 0x35, 127 + RCOMP_REG = 0x38, 128 + VEMPTY_REG = 0x3A, 129 + FSTAT_REG = 0x3D, 130 + DISCHARGE_THRESHOLD_REG = 0x40, 131 + QRTABLE30_REG = 0x42, 132 + ISYS_REG = 0x43, 133 + DQACC_REG = 0x45, 134 + DPACC_REG = 0x46, 135 + AVGISYS_REG = 0x4B, 136 + QH_REG = 0x4D, 137 + VSYS_REG = 0xB1, 138 + TALRTTH2_REG = 0xB2, 139 + VBYP_REG = 0xB3, 140 + CONFIG2_REG = 0xBB, 141 + IIN_REG = 0xD0, 142 + OCV_REG = 0xEE, 143 + VFOCV_REG = 0xFB, 144 + VFSOC_REG = 0xFF, 145 + 146 + MAX77705_FG_END 147 + }; 148 + 149 + enum max77705_led_reg { 150 + MAX77705_RGBLED_REG_BASE = 0x30, 151 + MAX77705_RGBLED_REG_LEDEN = 0, 152 + MAX77705_RGBLED_REG_LED0BRT, 153 + MAX77705_RGBLED_REG_LED1BRT, 154 + MAX77705_RGBLED_REG_LED2BRT, 155 + MAX77705_RGBLED_REG_LED3BRT, 156 + MAX77705_RGBLED_REG_LEDRMP, 157 + MAX77705_RGBLED_REG_LEDBLNK, 158 + MAX77705_LED_REG_END 159 + }; 160 + 161 + enum max77705_charger_battery_state { 162 + MAX77705_BATTERY_NOBAT, 163 + MAX77705_BATTERY_PREQUALIFICATION, 164 + MAX77705_BATTERY_DEAD, 165 + MAX77705_BATTERY_GOOD, 166 + MAX77705_BATTERY_LOWVOLTAGE, 167 + MAX77705_BATTERY_OVERVOLTAGE, 168 + MAX77705_BATTERY_RESERVED 169 + }; 170 + 171 + enum max77705_charger_charge_type { 172 + MAX77705_CHARGER_CONSTANT_CURRENT = 1, 173 + MAX77705_CHARGER_CONSTANT_VOLTAGE, 174 + MAX77705_CHARGER_END_OF_CHARGE, 175 + MAX77705_CHARGER_DONE 176 + }; 177 + 178 + #endif /* __LINUX_MFD_MAX77705_PRIV_H */