diff mbox series

[1/6] drivers: mfd: add MAX77659 PMIC support

Message ID 20221220132250.19383-2-Zeynep.Arslanbenzer@analog.com
State New
Headers show
Series [1/6] drivers: mfd: add MAX77659 PMIC support | expand

Commit Message

Arslanbenzer, Zeynep Dec. 20, 2022, 1:22 p.m. UTC
This patch adds MFD driver for MAX77659 to enable its sub
devices.

The MAX77659 is a multi-function devices. It includes
charger and regulator

Signed-off-by: Nurettin Bolucu <Nurettin.Bolucu@analog.com>
Signed-off-by: Zeynep Arslanbenzer <Zeynep.Arslanbenzer@analog.com>
---
 MAINTAINERS                  |   8 ++
 drivers/mfd/Kconfig          |  14 +++
 drivers/mfd/Makefile         |   1 +
 drivers/mfd/max77659.c       | 188 +++++++++++++++++++++++++++++++++++
 include/linux/mfd/max77659.h |  60 +++++++++++
 5 files changed, 271 insertions(+)
 create mode 100644 drivers/mfd/max77659.c
 create mode 100644 include/linux/mfd/max77659.h
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index a608f19da3a9..45a8a471c7c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12640,6 +12640,14 @@  F:	drivers/power/supply/max77650-charger.c
 F:	drivers/regulator/max77650-regulator.c
 F:	include/linux/mfd/max77650.h
 
+ANALOG DEVICES MAX77659 PMIC MFD DRIVER
+M:	Nurettin Bolucu <Nurettin.Bolucu@analog.com>
+M:	Zeynep Arslanbenzer <Zeynep.Arslanbenzer@analog.com>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/mfd/max77659.c
+F:	include/linux/mfd/max77659.h
+
 MAXIM MAX77714 PMIC MFD DRIVER
 M:	Luca Ceresoli <luca@lucaceresoli.net>
 S:	Maintained
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8b93856de432..4d5e446edfa5 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -821,6 +821,20 @@  config MFD_MAX77650
 	  the following functionalities of the device: GPIO, regulator,
 	  charger, LED, onkey.
 
+config MFD_MAX77659
+	tristate "Analog Devices MAX77659 PMIC Support"
+	depends on I2C
+	depends on OF
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  Say Y here to add support for Analog Devices MAX77659 Power
+	  Management IC. This is the core multifunction
+	  driver for interacting with the device. Additional drivers can be
+	  enabled in order to use the following functionalities of the device:
+	  regulator, charger.
+
 config MFD_MAX77686
 	tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
 	depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 7ed3ef4a698c..f7b39bf4aacb 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -163,6 +163,7 @@  obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77620)	+= max77620.o
 obj-$(CONFIG_MFD_MAX77650)	+= max77650.o
+obj-$(CONFIG_MFD_MAX77659)	+= max77659.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
 obj-$(CONFIG_MFD_MAX77714)	+= max77714.o
diff --git a/drivers/mfd/max77659.c b/drivers/mfd/max77659.c
new file mode 100644
index 000000000000..8401aea20e8c
--- /dev/null
+++ b/drivers/mfd/max77659.c
@@ -0,0 +1,188 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77659.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+
+static const struct regmap_config max77659_regmap_config = {
+	.reg_bits   = 8,
+	.val_bits   = 8,
+};
+
+static const struct regmap_irq max77659_glbl0_irqs[] = {
+	{ .mask = MAX77659_BIT_INT_GLBL0_GPIO0_F, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_GPIO0_R, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_EN_F, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_EN_R, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_TJAL1_R, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_TJAL2_R, },
+	{ .mask = MAX77659_BIT_INT_GLBL0_DOD0_R, },
+};
+
+static const struct regmap_irq_chip max77659_glbl0_irq_chip = {
+	.name           = "max77659_glbl0",
+	.status_base    = MAX77659_REG_INT_GLBL0,
+	.mask_base      = MAX77659_REG_INTM_GLBL0,
+	.num_regs       = 1,
+	.irqs           = max77659_glbl0_irqs,
+	.num_irqs       = ARRAY_SIZE(max77659_glbl0_irqs),
+};
+
+static const struct regmap_irq max77659_glbl1_irqs[] = {
+	{ .mask = MAX77659_BIT_INT_GLBL1_GPI1_F, },
+	{ .mask = MAX77659_BIT_INT_GLBL1_GPI1_R, },
+	{ .mask = MAX77659_BIT_INT_GLBL1_SBB_TO, },
+	{ .mask = MAX77659_BIT_INT_GLBL1_LDO0_F, },
+};
+
+static const struct regmap_irq_chip max77659_glbl1_irq_chip = {
+	.name           = "max77659_glbl1",
+	.status_base    = MAX77659_REG_INT_GLBL1,
+	.mask_base      = MAX77659_REG_INTM_GLBL1,
+	.num_regs       = 1,
+	.irqs           = max77659_glbl1_irqs,
+	.num_irqs       = ARRAY_SIZE(max77659_glbl1_irqs),
+};
+
+static const struct regmap_irq max77659_chg_irqs[] = {
+	{ .mask = MAX77659_BIT_INT_THM, },
+	{ .mask = MAX77659_BIT_INT_CHG, },
+	{ .mask = MAX77659_BIT_INT_CHGIN, },
+	{ .mask = MAX77659_BIT_INT_TJ_REG, },
+	{ .mask = MAX77659_BIT_INT_SYS_CTRL, },
+};
+
+static const struct regmap_irq_chip max77659_chg_irq_chip = {
+	.name = "max77659_chg",
+	.status_base = MAX77659_REG_INT_CHG,
+	.mask_base = MAX77659_REG_INT_M_CHG,
+	.num_regs = 1,
+	.irqs = max77659_chg_irqs,
+	.num_irqs = ARRAY_SIZE(max77659_chg_irqs),
+};
+
+static const struct mfd_cell max77659_devs[] = {
+	MFD_CELL_OF(MAX77659_REGULATOR_NAME, NULL, NULL, 0, 0, "adi,max77659-regulator"),
+	MFD_CELL_OF(MAX77659_CHARGER_NAME, NULL, NULL, 0, 0, "adi,max77659-charger"),
+};
+
+static int max77659_pmic_irq_init(struct max77659_dev *me)
+{
+	struct device *dev = me->dev;
+	int ret;
+
+	ret = regmap_write(me->regmap, MAX77659_REG_INTM_GLBL0, MAX77659_INT_GLBL0_MASK);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to write Global0 Interrupt Masking register\n");
+
+	ret = regmap_write(me->regmap, MAX77659_REG_INTM_GLBL1, MAX77659_INT_GLBL1_MASK);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to write Global1 Interrupt Masking register\n");
+
+	ret = devm_regmap_add_irq_chip(dev, me->regmap, me->irq,
+				       IRQF_ONESHOT | IRQF_SHARED, 0,
+				       &max77659_glbl0_irq_chip, &me->irqc_glbl0);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add global0 IRQ chip\n");
+
+	ret = devm_regmap_add_irq_chip(dev, me->regmap, me->irq,
+				       IRQF_ONESHOT | IRQF_SHARED, 0,
+				       &max77659_glbl1_irq_chip, &me->irqc_glbl1);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add global1 IRQ chip\n");
+
+	return devm_regmap_add_irq_chip(dev, me->regmap, me->irq,
+					IRQF_ONESHOT | IRQF_SHARED, 0,
+					&max77659_chg_irq_chip, &me->irqc_chg);
+}
+
+static int max77659_pmic_setup(struct max77659_dev *me)
+{
+	struct device *dev = me->dev;
+	unsigned int val;
+	int ret;
+
+	ret = max77659_pmic_irq_init(me);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to initialize IRQ\n");
+
+	ret = regmap_read(me->regmap, MAX77659_REG_INT_GLBL0, &val);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to read Global0 Interrupt Status register\n");
+
+	ret = regmap_read(me->regmap, MAX77659_REG_INT_GLBL1, &val);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to read Global1 Interrupt Status register\n");
+
+	ret = regmap_read(me->regmap, MAX77659_REG_INT_CHG, &val);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to read Charger Interrupt Status register\n");
+	ret = device_init_wakeup(dev, true);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to init wakeup\n");
+
+	ret = devm_mfd_add_devices(dev, -1, max77659_devs, ARRAY_SIZE(max77659_devs),
+				   NULL, 0, NULL);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add sub-devices\n");
+
+	enable_irq_wake(me->irq);
+
+	return 0;
+}
+
+static int max77659_i2c_probe(struct i2c_client *client)
+{
+	struct max77659_dev *me;
+
+	me = devm_kzalloc(&client->dev, sizeof(*me), GFP_KERNEL);
+	if (!me)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, me);
+	me->dev = &client->dev;
+	me->irq = client->irq;
+
+	me->regmap = devm_regmap_init_i2c(client, &max77659_regmap_config);
+
+	if (IS_ERR(me->regmap))
+		return dev_err_probe(&client->dev, PTR_ERR(me->regmap),
+				     "Failed to allocate register map\n");
+
+	return max77659_pmic_setup(me);
+}
+
+static const struct of_device_id max77659_of_id[] = {
+	{ .compatible = "adi,max77659" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max77659_of_id);
+
+static const struct i2c_device_id max77659_i2c_id[] = {
+	{ MAX77659_NAME, 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, max77659_i2c_id);
+
+static struct i2c_driver max77659_i2c_driver = {
+	.driver = {
+		.name = MAX77659_NAME,
+		.of_match_table = of_match_ptr(max77659_of_id),
+	},
+	.probe_new = max77659_i2c_probe,
+	.id_table = max77659_i2c_id,
+};
+
+module_i2c_driver(max77659_i2c_driver);
+
+MODULE_DESCRIPTION("max77659 MFD Driver");
+MODULE_AUTHOR("Nurettin.Bolucu@analog.com, Zeynep.Arslanbenzer@analog.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
diff --git a/include/linux/mfd/max77659.h b/include/linux/mfd/max77659.h
new file mode 100644
index 000000000000..ef781e6e54c2
--- /dev/null
+++ b/include/linux/mfd/max77659.h
@@ -0,0 +1,60 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __MAX77659_MFD_H__
+#define __MAX77659_MFD_H__
+
+#include <linux/bits.h>
+
+#define MAX77659_NAME "max77659"
+
+#define MAX77659_REGULATOR_NAME MAX77659_NAME "-regulator"
+#define MAX77659_CHARGER_NAME MAX77659_NAME "-charger"
+
+#define MAX77659_REG_INT_GLBL0 0x00
+#define MAX77659_REG_INT_CHG 0x01
+#define MAX77659_REG_INT_GLBL1 0x04
+#define MAX77659_REG_INT_M_CHG 0x07
+#define MAX77659_REG_INTM_GLBL1 0x08
+#define MAX77659_REG_INTM_GLBL0 0x09
+
+#define MAX77659_INT_GLBL0_MASK 0xFF
+#define MAX77659_INT_GLBL1_MASK 0x33
+
+#define MAX77659_BIT_INT_GLBL0_GPIO0_F BIT(0)
+#define MAX77659_BIT_INT_GLBL0_GPIO0_R BIT(1)
+#define MAX77659_BIT_INT_GLBL0_EN_F BIT(2)
+#define MAX77659_BIT_INT_GLBL0_EN_R BIT(3)
+#define MAX77659_BIT_INT_GLBL0_TJAL1_R BIT(4)
+#define MAX77659_BIT_INT_GLBL0_TJAL2_R BIT(5)
+#define MAX77659_BIT_INT_GLBL0_DOD0_R BIT(7)
+
+#define MAX77659_BIT_INT_GLBL1_GPI1_F BIT(0)
+#define MAX77659_BIT_INT_GLBL1_GPI1_R BIT(1)
+#define MAX77659_BIT_INT_GLBL1_SBB_TO BIT(4)
+#define MAX77659_BIT_INT_GLBL1_LDO0_F BIT(5)
+
+#define MAX77659_BIT_INT_THM BIT(0)
+#define MAX77659_BIT_INT_CHG BIT(1)
+#define MAX77659_BIT_INT_CHGIN BIT(2)
+#define MAX77659_BIT_INT_TJ_REG BIT(3)
+#define MAX77659_BIT_INT_SYS_CTRL BIT(4)
+
+enum {
+	MAX77659_DEV_PMIC,
+	MAX77659_DEV_CHARGER,
+	MAX77659_DEV_REGULATOR,
+	MAX77659_NUM_DEVS,
+};
+
+struct max77659_dev {
+	struct device *dev;
+
+	int irq;
+	struct regmap_irq_chip_data *irqc_glbl0;
+	struct regmap_irq_chip_data *irqc_glbl1;
+	struct regmap_irq_chip_data	*irqc_chg;
+
+	struct regmap *regmap;
+};
+
+#endif /* __MAX77659_MFD_H__ */