]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
mfd: Add new driver for MAX77705 PMIC
authorDzmitry Sankouski <dsankouski@gmail.com>
Thu, 23 Jan 2025 15:04:30 +0000 (18:04 +0300)
committerLee Jones <lee@kernel.org>
Thu, 20 Feb 2025 16:37:40 +0000 (16:37 +0000)
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>
MAINTAINERS
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/max77705.c [new file with mode: 0644]
include/linux/mfd/max77693-common.h
include/linux/mfd/max77705-private.h [new file with mode: 0644]

index 7b85deb55c6131c0608c600596ad8b2bbd808bc8..342a2dcbd36f293eb39f7fee97c548fee7ea74dc 100644 (file)
@@ -14320,6 +14320,7 @@ F:      drivers/*/*max77843.c
 F:     drivers/*/max14577*.c
 F:     drivers/*/max77686*.c
 F:     drivers/*/max77693*.c
+F:     drivers/*/max77705*.c
 F:     drivers/clk/clk-max77686.c
 F:     drivers/extcon/extcon-max14577.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/max77686*.h
 F:     include/linux/mfd/max77693*.h
+F:     include/linux/mfd/max77705*.h
 
 MAXIRADIO FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
index 6b0682af6e32b434ee3e99940005a6cce14ff55c..5064b1b42f76ed02519f8d330aa42ff8d1e671ea 100644 (file)
@@ -916,6 +916,19 @@ config MFD_MAX77693
          additional drivers must be enabled in order to use the functionality
          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
        tristate "Maxim Semiconductor MAX77714 PMIC Support"
        depends on I2C
index 9220eaf7cf1255a8922430fe3e50e41771bbaa60..b7086f1f35a29744af149ae7a532f01d5601393b 100644 (file)
@@ -168,6 +168,7 @@ obj-$(CONFIG_MFD_MAX77620)  += max77620.o
 obj-$(CONFIG_MFD_MAX77650)     += max77650.o
 obj-$(CONFIG_MFD_MAX77686)     += max77686.o
 obj-$(CONFIG_MFD_MAX77693)     += max77693.o
+obj-$(CONFIG_MFD_MAX77705)     += max77705.o
 obj-$(CONFIG_MFD_MAX77714)     += max77714.o
 obj-$(CONFIG_MFD_MAX77843)     += max77843.o
 obj-$(CONFIG_MFD_MAX8907)      += max8907.o
diff --git a/drivers/mfd/max77705.c b/drivers/mfd/max77705.c
new file mode 100644 (file)
index 0000000..60c457c
--- /dev/null
@@ -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");
index a5bce099f1ed47b6874d3064a6a50976296eb27b..ec2e1b2dceb8c7833b0f71de6f8038b3b4ef4407 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
  */
@@ -11,6 +11,7 @@
 enum max77693_types {
        TYPE_MAX77693_UNKNOWN,
        TYPE_MAX77693,
+       TYPE_MAX77705,
        TYPE_MAX77843,
 
        TYPE_MAX77693_NUM,
@@ -32,6 +33,7 @@ struct max77693_dev {
        struct regmap *regmap_muic;
        struct regmap *regmap_haptic;   /* Only MAX77693 */
        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_topsys;
diff --git a/include/linux/mfd/max77705-private.h b/include/linux/mfd/max77705-private.h
new file mode 100644 (file)
index 0000000..0c8b07a
--- /dev/null
@@ -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 */