1c8d50f02SDzmitry Sankouski // SPDX-License-Identifier: GPL-2.0+ 2c8d50f02SDzmitry Sankouski /* 3c8d50f02SDzmitry Sankouski * Maxim MAX77705 PMIC core driver 4c8d50f02SDzmitry Sankouski * 5c8d50f02SDzmitry Sankouski * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com> 6c8d50f02SDzmitry Sankouski **/ 7c8d50f02SDzmitry Sankouski #include <linux/i2c.h> 8c8d50f02SDzmitry Sankouski #include <linux/interrupt.h> 9c8d50f02SDzmitry Sankouski #include <linux/mfd/core.h> 10c8d50f02SDzmitry Sankouski #include <linux/mfd/max77705-private.h> 11c8d50f02SDzmitry Sankouski #include <linux/mfd/max77693-common.h> 12c8d50f02SDzmitry Sankouski #include <linux/pm.h> 13c8d50f02SDzmitry Sankouski #include <linux/power/max17042_battery.h> 14c8d50f02SDzmitry Sankouski #include <linux/module.h> 15c8d50f02SDzmitry Sankouski #include <linux/regmap.h> 16c8d50f02SDzmitry Sankouski #include <linux/of.h> 17c8d50f02SDzmitry Sankouski 18c8d50f02SDzmitry Sankouski static struct mfd_cell max77705_devs[] = { 19c8d50f02SDzmitry Sankouski MFD_CELL_OF("max77705-rgb", NULL, NULL, 0, 0, "maxim,max77705-rgb"), 20c8d50f02SDzmitry Sankouski MFD_CELL_OF("max77705-charger", NULL, NULL, 0, 0, "maxim,max77705-charger"), 21c8d50f02SDzmitry Sankouski MFD_CELL_OF("max77705-haptic", NULL, NULL, 0, 0, "maxim,max77705-haptic"), 22c8d50f02SDzmitry Sankouski }; 23c8d50f02SDzmitry Sankouski 24c8d50f02SDzmitry Sankouski static const struct regmap_range max77705_readable_ranges[] = { 25c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_PMICID1, MAX77705_PMIC_REG_BSTOUT_MASK), 26c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), 27c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 28c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), 29c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), 30c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 31c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), 32c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), 33c8d50f02SDzmitry Sankouski }; 34c8d50f02SDzmitry Sankouski 35c8d50f02SDzmitry Sankouski static const struct regmap_range max77705_writable_ranges[] = { 36c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_MAINCTRL1, MAX77705_PMIC_REG_BSTOUT_MASK), 37c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), 38c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 39c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), 40c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), 41c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), 42c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), 43c8d50f02SDzmitry Sankouski regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), 44c8d50f02SDzmitry Sankouski }; 45c8d50f02SDzmitry Sankouski 46c8d50f02SDzmitry Sankouski static const struct regmap_access_table max77705_readable_table = { 47c8d50f02SDzmitry Sankouski .yes_ranges = max77705_readable_ranges, 48c8d50f02SDzmitry Sankouski .n_yes_ranges = ARRAY_SIZE(max77705_readable_ranges), 49c8d50f02SDzmitry Sankouski }; 50c8d50f02SDzmitry Sankouski 51c8d50f02SDzmitry Sankouski static const struct regmap_access_table max77705_writable_table = { 52c8d50f02SDzmitry Sankouski .yes_ranges = max77705_writable_ranges, 53c8d50f02SDzmitry Sankouski .n_yes_ranges = ARRAY_SIZE(max77705_writable_ranges), 54c8d50f02SDzmitry Sankouski }; 55c8d50f02SDzmitry Sankouski 56c8d50f02SDzmitry Sankouski static const struct regmap_config max77705_regmap_config = { 57c8d50f02SDzmitry Sankouski .reg_bits = 8, 58c8d50f02SDzmitry Sankouski .val_bits = 8, 59c8d50f02SDzmitry Sankouski .rd_table = &max77705_readable_table, 60c8d50f02SDzmitry Sankouski .wr_table = &max77705_writable_table, 61c8d50f02SDzmitry Sankouski .max_register = MAX77705_PMIC_REG_USBC_RESET, 62c8d50f02SDzmitry Sankouski }; 63c8d50f02SDzmitry Sankouski 64c8d50f02SDzmitry Sankouski static const struct regmap_irq max77705_topsys_irqs[] = { 65c8d50f02SDzmitry Sankouski { .mask = MAX77705_SYSTEM_IRQ_BSTEN_INT, }, 66c8d50f02SDzmitry Sankouski { .mask = MAX77705_SYSTEM_IRQ_SYSUVLO_INT, }, 67c8d50f02SDzmitry Sankouski { .mask = MAX77705_SYSTEM_IRQ_SYSOVLO_INT, }, 68c8d50f02SDzmitry Sankouski { .mask = MAX77705_SYSTEM_IRQ_TSHDN_INT, }, 69c8d50f02SDzmitry Sankouski { .mask = MAX77705_SYSTEM_IRQ_TM_INT, }, 70c8d50f02SDzmitry Sankouski }; 71c8d50f02SDzmitry Sankouski 72c8d50f02SDzmitry Sankouski static const struct regmap_irq_chip max77705_topsys_irq_chip = { 73c8d50f02SDzmitry Sankouski .name = "max77705-topsys", 74c8d50f02SDzmitry Sankouski .status_base = MAX77705_PMIC_REG_SYSTEM_INT, 75c8d50f02SDzmitry Sankouski .mask_base = MAX77705_PMIC_REG_SYSTEM_INT_MASK, 76c8d50f02SDzmitry Sankouski .num_regs = 1, 77c8d50f02SDzmitry Sankouski .irqs = max77705_topsys_irqs, 78c8d50f02SDzmitry Sankouski .num_irqs = ARRAY_SIZE(max77705_topsys_irqs), 79c8d50f02SDzmitry Sankouski }; 80c8d50f02SDzmitry Sankouski 81c8d50f02SDzmitry Sankouski static int max77705_i2c_probe(struct i2c_client *i2c) 82c8d50f02SDzmitry Sankouski { 83c8d50f02SDzmitry Sankouski struct device *dev = &i2c->dev; 84c8d50f02SDzmitry Sankouski struct max77693_dev *max77705; 85c8d50f02SDzmitry Sankouski struct regmap_irq_chip_data *irq_data; 86c8d50f02SDzmitry Sankouski struct irq_domain *domain; 87c8d50f02SDzmitry Sankouski enum max77705_hw_rev pmic_rev; 88c8d50f02SDzmitry Sankouski unsigned int pmic_rev_value; 89c8d50f02SDzmitry Sankouski int ret; 90c8d50f02SDzmitry Sankouski 91c8d50f02SDzmitry Sankouski max77705 = devm_kzalloc(dev, sizeof(*max77705), GFP_KERNEL); 92c8d50f02SDzmitry Sankouski if (!max77705) 93c8d50f02SDzmitry Sankouski return -ENOMEM; 94c8d50f02SDzmitry Sankouski 95c8d50f02SDzmitry Sankouski max77705->i2c = i2c; 96c8d50f02SDzmitry Sankouski max77705->type = TYPE_MAX77705; 97c8d50f02SDzmitry Sankouski i2c_set_clientdata(i2c, max77705); 98c8d50f02SDzmitry Sankouski 99c8d50f02SDzmitry Sankouski max77705->regmap = devm_regmap_init_i2c(i2c, &max77705_regmap_config); 100c8d50f02SDzmitry Sankouski if (IS_ERR(max77705->regmap)) 101c8d50f02SDzmitry Sankouski return PTR_ERR(max77705->regmap); 102c8d50f02SDzmitry Sankouski 103c8d50f02SDzmitry Sankouski ret = regmap_read(max77705->regmap, MAX77705_PMIC_REG_PMICREV, &pmic_rev_value); 104c8d50f02SDzmitry Sankouski if (ret < 0) 105c8d50f02SDzmitry Sankouski return -ENODEV; 106c8d50f02SDzmitry Sankouski 107c8d50f02SDzmitry Sankouski pmic_rev = pmic_rev_value & MAX77705_REVISION_MASK; 108c8d50f02SDzmitry Sankouski if (pmic_rev != MAX77705_PASS3) 109c8d50f02SDzmitry Sankouski return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev); 110c8d50f02SDzmitry Sankouski 111c8d50f02SDzmitry Sankouski ret = devm_regmap_add_irq_chip(dev, max77705->regmap, 112c8d50f02SDzmitry Sankouski i2c->irq, 113c8d50f02SDzmitry Sankouski IRQF_ONESHOT | IRQF_SHARED, 0, 114c8d50f02SDzmitry Sankouski &max77705_topsys_irq_chip, 115c8d50f02SDzmitry Sankouski &irq_data); 116c8d50f02SDzmitry Sankouski if (ret) 117c8d50f02SDzmitry Sankouski return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); 118c8d50f02SDzmitry Sankouski 119c8d50f02SDzmitry Sankouski /* Unmask interrupts from all blocks in interrupt source register */ 120c8d50f02SDzmitry Sankouski ret = regmap_update_bits(max77705->regmap, 121c8d50f02SDzmitry Sankouski MAX77705_PMIC_REG_INTSRC_MASK, 122c8d50f02SDzmitry Sankouski MAX77705_SRC_IRQ_ALL, (unsigned int)~MAX77705_SRC_IRQ_ALL); 123c8d50f02SDzmitry Sankouski if (ret < 0) 124c8d50f02SDzmitry Sankouski return dev_err_probe(dev, ret, "Could not unmask interrupts in INTSRC\n"); 125c8d50f02SDzmitry Sankouski 126c8d50f02SDzmitry Sankouski domain = regmap_irq_get_domain(irq_data); 127c8d50f02SDzmitry Sankouski 128c8d50f02SDzmitry Sankouski ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 129c8d50f02SDzmitry Sankouski max77705_devs, ARRAY_SIZE(max77705_devs), 130c8d50f02SDzmitry Sankouski NULL, 0, domain); 131c8d50f02SDzmitry Sankouski if (ret) 132c8d50f02SDzmitry Sankouski return dev_err_probe(dev, ret, "Failed to register child devices\n"); 133c8d50f02SDzmitry Sankouski 134*a59a56ccSKrzysztof Kozlowski ret = devm_device_init_wakeup(dev); 135*a59a56ccSKrzysztof Kozlowski if (ret) 136*a59a56ccSKrzysztof Kozlowski return dev_err_probe(dev, ret, "Failed to init wakeup\n"); 137c8d50f02SDzmitry Sankouski 138c8d50f02SDzmitry Sankouski return 0; 139c8d50f02SDzmitry Sankouski } 140c8d50f02SDzmitry Sankouski 141c8d50f02SDzmitry Sankouski static int max77705_suspend(struct device *dev) 142c8d50f02SDzmitry Sankouski { 143c8d50f02SDzmitry Sankouski struct i2c_client *i2c = to_i2c_client(dev); 144c8d50f02SDzmitry Sankouski 145c8d50f02SDzmitry Sankouski disable_irq(i2c->irq); 146c8d50f02SDzmitry Sankouski 147c8d50f02SDzmitry Sankouski if (device_may_wakeup(dev)) 148c8d50f02SDzmitry Sankouski enable_irq_wake(i2c->irq); 149c8d50f02SDzmitry Sankouski 150c8d50f02SDzmitry Sankouski return 0; 151c8d50f02SDzmitry Sankouski } 152c8d50f02SDzmitry Sankouski 153c8d50f02SDzmitry Sankouski static int max77705_resume(struct device *dev) 154c8d50f02SDzmitry Sankouski { 155c8d50f02SDzmitry Sankouski struct i2c_client *i2c = to_i2c_client(dev); 156c8d50f02SDzmitry Sankouski 157c8d50f02SDzmitry Sankouski if (device_may_wakeup(dev)) 158c8d50f02SDzmitry Sankouski disable_irq_wake(i2c->irq); 159c8d50f02SDzmitry Sankouski 160c8d50f02SDzmitry Sankouski enable_irq(i2c->irq); 161c8d50f02SDzmitry Sankouski 162c8d50f02SDzmitry Sankouski return 0; 163c8d50f02SDzmitry Sankouski } 164c8d50f02SDzmitry Sankouski DEFINE_SIMPLE_DEV_PM_OPS(max77705_pm_ops, max77705_suspend, max77705_resume); 165c8d50f02SDzmitry Sankouski 166c8d50f02SDzmitry Sankouski static const struct of_device_id max77705_i2c_of_match[] = { 167c8d50f02SDzmitry Sankouski { .compatible = "maxim,max77705" }, 168c8d50f02SDzmitry Sankouski { } 169c8d50f02SDzmitry Sankouski }; 170c8d50f02SDzmitry Sankouski MODULE_DEVICE_TABLE(of, max77705_i2c_of_match); 171c8d50f02SDzmitry Sankouski 172c8d50f02SDzmitry Sankouski static struct i2c_driver max77705_i2c_driver = { 173c8d50f02SDzmitry Sankouski .driver = { 174c8d50f02SDzmitry Sankouski .name = "max77705", 175c8d50f02SDzmitry Sankouski .of_match_table = max77705_i2c_of_match, 176c8d50f02SDzmitry Sankouski .pm = pm_sleep_ptr(&max77705_pm_ops), 177c8d50f02SDzmitry Sankouski }, 178c8d50f02SDzmitry Sankouski .probe = max77705_i2c_probe 179c8d50f02SDzmitry Sankouski }; 180c8d50f02SDzmitry Sankouski module_i2c_driver(max77705_i2c_driver); 181c8d50f02SDzmitry Sankouski 182c8d50f02SDzmitry Sankouski MODULE_DESCRIPTION("Maxim MAX77705 PMIC core driver"); 183c8d50f02SDzmitry Sankouski MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>"); 184c8d50f02SDzmitry Sankouski MODULE_LICENSE("GPL"); 185