[RAMEN9610-11989][COMMON] mfd: integrate MU004 and MU106
authorKim Taejeong <tj.kim@samsung.com>
Mon, 11 Feb 2019 07:07:19 +0000 (16:07 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:15 +0000 (20:23 +0300)
Change-Id: I8ec36e5eaa46df2b9a96e7f21eba925eb31cbbfc
Signed-off-by: Kim Taejeong <tj.kim@samsung.com>
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/s2mu106_core.c [new file with mode: 0644]
drivers/mfd/s2mu106_irq.c [new file with mode: 0644]
include/linux/mfd/samsung/s2mu106.h [new file with mode: 0644]

index d1317c152be175700c99e68dd6d2287a142e3633..4e13d02d793623e13d566fb3ec7db310742c3e17 100644 (file)
@@ -1076,6 +1076,16 @@ config MFD_S2MU004
          additional drivers must be enabled in order to use the functionality
          of the device
 
+config MFD_S2MU106
+       bool "Samsung Electronics S2MU106 IF PMIC Series Support"
+       depends on I2C=y
+       select MFD_CORE
+       help
+         Support for the Samsung Electronics MFD series.
+         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_S2MPU09
        bool "SAMSUNG Electronics S2MPU09 PMIC Series Support"
        depends on I2C=y
index 6d04eb0cbd31aeaa09d5e544904d30a3f55662a9..6928f7e5ce0c2604b5b7b9d2015c09818547f45b 100644 (file)
@@ -220,6 +220,7 @@ obj-$(CONFIG_MFD_RK808)             += rk808.o
 obj-$(CONFIG_MFD_RN5T618)      += rn5t618.o
 obj-$(CONFIG_MFD_SEC_CORE)     += sec-core.o sec-irq.o
 obj-$(CONFIG_MFD_S2MU004)      += s2mu004_core.o s2mu004_irq.o
+obj-$(CONFIG_MFD_S2MU106)      += s2mu106_core.o s2mu106_irq.o
 obj-$(CONFIG_MFD_S2MPU09)      += s2mpu09-core.o s2mpu09-irq.o
 obj-$(CONFIG_MFD_S2MPB02)      += s2mpb02-core.o s2mpb02-irq.o
 obj-$(CONFIG_MFD_SYSCON)       += syscon.o
diff --git a/drivers/mfd/s2mu106_core.c b/drivers/mfd/s2mu106_core.c
new file mode 100644 (file)
index 0000000..ace20bd
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * s2mu106.c - mfd core driver for the s2mu106
+ *
+ * Copyright (C) 2018 Samsung Electronics
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/samsung/s2mu106.h>
+#include <linux/of_gpio.h>
+
+#if defined(CONFIG_CHARGER_S2MU106)
+#define CONFIG_PM_S2MU106
+#endif
+
+static struct mfd_cell s2mu106_devs[] = {
+#if defined(CONFIG_CHARGER_S2MU106)
+       { .name = "s2mu106-charger", },
+#endif
+#if defined(CONFIG_BATTERY_S2MU00X)
+       { .name = "s2mu00x-battery", },
+#endif
+#if defined(CONFIG_LEDS_S2MU106_FLASH)
+       { .name = "leds-s2mu106", },
+#endif
+#if defined(CONFIG_LEDS_S2MU106_RGB)
+       { .name = "leds-s2mu106-rgb", },
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       { .name = "s2mu106-muic", },
+#endif
+#if defined(CONFIG_AFC_S2MU106)
+       { .name = "s2mu106-afc", },
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       { .name = "s2mu106-mst", },
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       { .name = "s2mu106-powermeter", },
+#endif
+#if defined(CONFIG_INPUT_S2MU106_HAPTIC)
+       { .name = "s2mu106-haptic", },
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       { .name = "s2mu106-regulator", },
+#endif
+};
+
+int s2mu106_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0) {
+               pr_err("%s:%s reg(0x%x), ret(%d)\n", MFD_DEV_NAME,
+                               __func__, reg, ret);
+               return ret;
+       }
+
+       ret &= 0xff;
+       *dest = ret;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s2mu106_read_reg);
+
+int s2mu106_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s2mu106_bulk_read);
+
+int s2mu106_read_word(struct i2c_client *i2c, u8 reg)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_read_word_data(i2c, reg);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(s2mu106_read_word);
+
+int s2mu106_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_write_byte_data(i2c, reg, value);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0)
+               pr_err("%s:%s reg(0x%x), ret(%d)\n",
+                               MFD_DEV_NAME, __func__, reg, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(s2mu106_write_reg);
+
+int s2mu106_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s2mu106_bulk_write);
+
+int s2mu106_write_word(struct i2c_client *i2c, u8 reg, u16 value)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_write_word_data(i2c, reg, value);
+       mutex_unlock(&s2mu106->i2c_lock);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s2mu106_write_word);
+
+int s2mu106_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+       int ret;
+       u8 old_val, new_val;
+
+       mutex_lock(&s2mu106->i2c_lock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       if (ret >= 0) {
+               old_val = ret & 0xff;
+               new_val = (val & mask) | (old_val & (~mask));
+               ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
+       }
+       mutex_unlock(&s2mu106->i2c_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(s2mu106_update_reg);
+
+#if defined(CONFIG_OF)
+static int of_s2mu106_dt(struct device *dev,
+                               struct s2mu106_platform_data *pdata)
+{
+       struct device_node *np_s2mu106 = dev->of_node;
+       int ret = 0;
+
+       if (!np_s2mu106)
+               return -EINVAL;
+
+       ret = of_get_named_gpio(np_s2mu106, "s2mu106,irq-gpio", 0);
+       if (ret < 0)
+               return ret;
+       else
+               pdata->irq_gpio = ret;
+
+       pdata->wakeup = of_property_read_bool(np_s2mu106, "s2mu106,wakeup");
+
+       pr_debug("%s: irq-gpio: %u\n", __func__, pdata->irq_gpio);
+
+       return 0;
+}
+#else
+static int of_s2mu106_dt(struct device *dev,
+                               struct max77834_platform_data *pdata)
+{
+       return 0;
+}
+#endif /* CONFIG_OF */
+
+static int s2mu106_i2c_probe(struct i2c_client *i2c,
+                               const struct i2c_device_id *dev_id)
+{
+       struct s2mu106_dev *s2mu106;
+       struct s2mu106_platform_data *pdata = i2c->dev.platform_data;
+
+       int ret = 0;
+       u8 temp = 0;
+
+       pr_info("%s start\n", __func__);
+
+       s2mu106 = devm_kzalloc(&i2c->dev, sizeof(struct s2mu106_dev), GFP_KERNEL);
+       if (!s2mu106) {
+               dev_err(&i2c->dev, "%s: Failed to alloc mem for s2mu106\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       if (i2c->dev.of_node) {
+               pdata = devm_kzalloc(&i2c->dev,
+                        sizeof(struct s2mu106_platform_data), GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(&i2c->dev, "Failed to allocate memory\n");
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               ret = of_s2mu106_dt(&i2c->dev, pdata);
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to get device of_node\n");
+                       goto err;
+               }
+
+               i2c->dev.platform_data = pdata;
+       } else
+               pdata = i2c->dev.platform_data;
+
+       s2mu106->dev = &i2c->dev;
+       s2mu106->i2c = i2c;
+       s2mu106->irq = i2c->irq;
+       if (pdata) {
+               s2mu106->pdata = pdata;
+
+               pdata->irq_base = irq_alloc_descs(-1, 0, S2MU106_IRQ_NR, -1);
+               if (pdata->irq_base < 0) {
+                       pr_err("%s:%s irq_alloc_descs Fail! ret(%d)\n",
+                               MFD_DEV_NAME, __func__, pdata->irq_base);
+                       ret = -EINVAL;
+                       goto err;
+               } else
+                       s2mu106->irq_base = pdata->irq_base;
+
+               s2mu106->irq_gpio = pdata->irq_gpio;
+               s2mu106->wakeup = pdata->wakeup;
+       } else {
+               ret = -EINVAL;
+               goto err;
+       }
+       mutex_init(&s2mu106->i2c_lock);
+
+       i2c_set_clientdata(i2c, s2mu106);
+
+       s2mu106_read_reg(s2mu106->i2c, S2MU106_REG_PMICID, &temp);
+       if (temp < 0)
+               pr_err("[s2mu106 mfd] %s : i2c read error\n", __func__);
+
+       s2mu106->pmic_ver = temp & S2MU106_REG_PMICID_MASK;
+       pr_err("%s : ver=0x%x\n", __func__, s2mu106->pmic_ver);
+
+       /* I2C enable for MUIC, AFC, MST, Powermeter */
+       s2mu106->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_7C_SLAVE);
+       i2c_set_clientdata(s2mu106->muic, s2mu106);
+
+       /* I2C enable for Haptic, Haptic Boost */
+       s2mu106->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
+       i2c_set_clientdata(s2mu106->haptic, s2mu106);
+
+       ret = s2mu106_irq_init(s2mu106);
+
+       if (ret < 0)
+               goto err_irq_init;
+
+       ret = mfd_add_devices(s2mu106->dev, -1, s2mu106_devs,
+                       ARRAY_SIZE(s2mu106_devs), NULL, 0, NULL);
+       if (ret < 0)
+               goto err_mfd;
+
+       device_init_wakeup(s2mu106->dev, pdata->wakeup);
+
+       return ret;
+
+err_mfd:
+       mutex_destroy(&s2mu106->i2c_lock);
+       mfd_remove_devices(s2mu106->dev);
+err_irq_init:
+       i2c_unregister_device(s2mu106->i2c);
+err:
+       kfree(s2mu106);
+       i2c_set_clientdata(i2c, NULL);
+
+       return ret;
+}
+
+static int s2mu106_i2c_remove(struct i2c_client *i2c)
+{
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(s2mu106->dev);
+       i2c_unregister_device(s2mu106->i2c);
+       i2c_set_clientdata(i2c, NULL);
+
+       return 0;
+}
+
+static const struct i2c_device_id s2mu106_i2c_id[] = {
+       { MFD_DEV_NAME, TYPE_S2MU106 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, s2mu106_i2c_id);
+
+#if defined(CONFIG_OF)
+static struct of_device_id s2mu106_i2c_dt_ids[] = {
+       {.compatible = "samsung,s2mu106mfd"},
+       { },
+};
+#endif /* CONFIG_OF */
+
+#if defined(CONFIG_PM)
+static int s2mu106_suspend(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(s2mu106->irq);
+
+       disable_irq(s2mu106->irq);
+
+       return 0;
+}
+
+static int s2mu106_resume(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct s2mu106_dev *s2mu106 = i2c_get_clientdata(i2c);
+
+       pr_debug("%s:%s\n", MFD_DEV_NAME, __func__);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(s2mu106->irq);
+
+       enable_irq(s2mu106->irq);
+
+       return 0;
+}
+#else
+#define s2mu106_suspend        NULL
+#define s2mu106_resume NULL
+#endif /* CONFIG_PM */
+
+const struct dev_pm_ops s2mu106_pm = {
+       .suspend = s2mu106_suspend,
+       .resume = s2mu106_resume,
+};
+
+static struct i2c_driver s2mu106_i2c_driver = {
+       .driver         = {
+               .name   = MFD_DEV_NAME,
+               .owner  = THIS_MODULE,
+#if defined(CONFIG_PM)
+               .pm     = &s2mu106_pm,
+#endif /* CONFIG_PM */
+#if defined(CONFIG_OF)
+               .of_match_table = s2mu106_i2c_dt_ids,
+#endif /* CONFIG_OF */
+       },
+       .probe          = s2mu106_i2c_probe,
+       .remove         = s2mu106_i2c_remove,
+       .id_table       = s2mu106_i2c_id,
+};
+
+static int __init s2mu106_i2c_init(void)
+{
+       pr_info("%s:%s\n", MFD_DEV_NAME, __func__);
+       return i2c_add_driver(&s2mu106_i2c_driver);
+}
+subsys_initcall(s2mu106_i2c_init);
+
+static void __exit s2mu106_i2c_exit(void)
+{
+       i2c_del_driver(&s2mu106_i2c_driver);
+}
+module_exit(s2mu106_i2c_exit);
+
+MODULE_DESCRIPTION("s2mu106 multi-function core driver");
+MODULE_AUTHOR("Samsung Electronics");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s2mu106_irq.c b/drivers/mfd/s2mu106_irq.c
new file mode 100644 (file)
index 0000000..f861f28
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * s2mu106-irq.c - Interrupt controller support for s2mu106
+ *
+ * Copyright (C) 2018 Samsung Electronics Co.Ltd
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mfd/samsung/s2mu106.h>
+#include <linux/err.h>
+
+#if defined(CONFIG_CHARGER_S2MU106)
+#include <linux/power/s2mu106_charger.h>
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+#include <linux/muic/s2mu106-muic.h>
+#endif
+/* TODO : add IP Header file include*/
+
+static const u8 s2mu106_mask_reg[] = {
+#if defined(CONFIG_CHARGER_S2MU106)
+       [CHG_INT1] = S2MU106_CHG_INT1M,
+       [CHG_INT2] = S2MU106_CHG_INT2M,
+       [CHG_INT3] = S2MU106_CHG_INT3M,
+#endif
+/* TODO : add the code after IP Header file include
+
+*/
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+    [AFC_INT] = S2MU106_REG_AFC_INT,
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+    [MUIC_INT1] = S2MU106_REG_MUIC_INT1,
+    [MUIC_INT2] = S2MU106_REG_MUIC_INT2,
+#endif
+};
+
+struct s2mu106_irq_data {
+       int mask;
+       enum s2mu106_irq_source group;
+};
+
+static struct i2c_client *get_i2c(struct s2mu106_dev *s2mu106,
+                                       enum s2mu106_irq_source src)
+{
+       switch (src) {
+#if defined(CONFIG_CHARGER_S2MU106)
+       case CHG_INT1 ... CHG_INT3:
+               return s2mu106->i2c;
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       case FLED_INT1 ... FLED_INT2:
+               return s2mu106->i2c;
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       case AFC_INT:
+               return s2mu106->muic;
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       case MUIC_INT1 ... MUIC_INT2:
+               return s2mu106->muic;
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       case PM_VAL_UP1 ... PM_INT2:
+               return s2mu106->muic;
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       case MST_INT:
+               return s2mu106->muic;
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       case HAPTIC_INT:
+               return s2mu106->haptic;
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       case HBST_INT:
+               return s2mu106->haptic;
+#endif
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+}
+
+#define DECLARE_IRQ(idx, _group, _mask)                \
+       [(idx)] = { .group = (_group), .mask = (_mask) }
+static const struct s2mu106_irq_data s2mu106_irqs[] = {
+#if defined(CONFIG_CHARGER_S2MU106)
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_SYS,       CHG_INT1,       1 << 0),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_CV,        CHG_INT1,       1 << 1),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_CHG_Fault, CHG_INT1,       1 << 2),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_CHG_RSTART, CHG_INT1,      1 << 3),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_DONE,      CHG_INT1,       1 << 4),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_TOP_OFF,   CHG_INT1,       1 << 5),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_WCIN,      CHG_INT1,       1 << 6),
+       DECLARE_IRQ(S2MU106_CHG1_IRQ_CHGIN,     CHG_INT1,       1 << 7),
+
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_ICR,       CHG_INT2,       1 << 0),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_IVR,       CHG_INT2,       1 << 1),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_AICL,      CHG_INT2,       1 << 2),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_DET_BAT,   CHG_INT2,       1 << 3),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_BAT,       CHG_INT2,       1 << 4),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_BATN_OPEN, CHG_INT2,       1 << 5),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_BATP_OPEN, CHG_INT2,       1 << 6),
+       DECLARE_IRQ(S2MU106_CHG2_IRQ_QBAT_OFF,  CHG_INT2,       1 << 7),
+
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_BST,       CHG_INT3,       1 << 0),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_TX,        CHG_INT3,       1 << 1),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_OTG,       CHG_INT3,       1 << 2),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_VBUS_Short, CHG_INT3,      1 << 3),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_MaxDuty,   CHG_INT3,       1 << 4),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_PEdone,    CHG_INT3,       1 << 5),
+       DECLARE_IRQ(S2MU106_CHG3_IRQ_BAT_Contact_CK_Done, CHG_INT3, 1 << 6),
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_C2F_Vbyp_ovp_prot, FLED_INT1, 1 << 0),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_C2F_Vbyp_OK_Warning, FLED_INT1, 1 << 1),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_OPEN_CH3, FLED_INT1,      1 << 2),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_OPEN_CH2, FLED_INT1,      1 << 3),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_OPEN_CH1, FLED_INT1,      1 << 4),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_SHORT_CH3, FLED_INT1,     1 << 5),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_SHORT_CH2, FLED_INT1,     1 << 6),
+       DECLARE_IRQ(S2MU106_FLED1_IRQ_SHORT_CH1, FLED_INT1,     1 << 7),
+
+       DECLARE_IRQ(S2MU106_FLED2_IRQ_CH3_ON,   FLED_INT2,      1 << 2),
+       DECLARE_IRQ(S2MU106_FLED2_IRQ_CH2_ON,   FLED_INT2,      1 << 3),
+       DECLARE_IRQ(S2MU106_FLED2_IRQ_CH1_ON,   FLED_INT2,      1 << 4),
+       DECLARE_IRQ(S2MU106_FLED2_IRQ_TORCH_ON, FLED_INT2,      1 << 6),
+       DECLARE_IRQ(S2MU106_FLED2_IRQ_LED_ON_TA_Detach, FLED_INT2, 1 << 7),
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       DECLARE_IRQ(S2MU106_AFC_IRQ_VbADC,      AFC_INT,        1 << 0),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_VDNMon,     AFC_INT,        1 << 1),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_DNRes,      AFC_INT,        1 << 2),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_MPNack,     AFC_INT,        1 << 3),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_MRxTrf,     AFC_INT,        1 << 5),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_MRxPerr,    AFC_INT,        1 << 6),
+       DECLARE_IRQ(S2MU106_AFC_IRQ_MRxRdy,     AFC_INT,        1 << 7),
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_DETACH,   MUIC_INT1,      1 << 1),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_ATTATCH,  MUIC_INT1,      1 << 0),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_KP,       MUIC_INT1,      1 << 2),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_LKP,      MUIC_INT1,      1 << 3),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_LKR,      MUIC_INT1,      1 << 4),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_RID_CHG,  MUIC_INT1,      1 << 5),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ1_USB_Killer,       MUIC_INT1,      1 << 6),
+
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_VBUS_ON,          MUIC_INT2, 1 << 0),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_RSVD_ATTACH,      MUIC_INT2, 1 << 1),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_ADC_CHANGE,       MUIC_INT2, 1 << 2),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_STUCK,            MUIC_INT2, 1 << 3),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_STUCKRCV,         MUIC_INT2, 1 << 4),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_MHDL,             MUIC_INT2, 1 << 5),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_AV_CHARGE,        MUIC_INT2, 1 << 6),
+       DECLARE_IRQ(S2MU106_MUIC_IRQ2_VBUS_OFF,         MUIC_INT2, 1 << 7),
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VCC2UP,   PM_VALUP1,      1 << 0),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VGPADCUP, PM_VALUP1,      1 << 1),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VCC1UP,   PM_VALUP1,      1 << 2),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VBATAUP,  PM_VALUP1,      1 << 3),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VSYSAUP,  PM_VALUP1,      1 << 4),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VBYPUP,   PM_VALUP1,      1 << 5),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VWCINUP,  PM_VALUP1,      1 << 6),
+       DECLARE_IRQ(S2MU106_PM_VALUP1_VCHGINUP, PM_VALUP1,      1 << 7),
+
+       DECLARE_IRQ(S2MU106_PM_VALUP2_ITXUP,    PM_VALUP2,      1 << 3),
+       DECLARE_IRQ(S2MU106_PM_VALUP2_IOTGUP,   PM_VALUP2,      1 << 4),
+       DECLARE_IRQ(S2MU106_PM_VALUP2_IWCINUP,  PM_VALUP2,      1 << 6),
+       DECLARE_IRQ(S2MU106_PM_VALUP2_ICHGINUP, PM_VALUP2,      1 << 7),
+
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VCC2UP,     PM_INT1,        1 << 0),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VGPADCUP,   PM_INT1,        1 << 1),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VCC1UP,     PM_INT1,        1 << 2),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VBATAUP,    PM_INT1,        1 << 3),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VSYSAUP,    PM_INT1,        1 << 4),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VBYPUP,     PM_INT1,        1 << 5),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VWCINUP,    PM_INT1,        1 << 6),
+       DECLARE_IRQ(S2MU106_PM_IRQ1_VCHGINUP,   PM_INT1,        1 << 7),
+
+       DECLARE_IRQ(S2MU106_PM_IRQ2_ITXUP,      PM_INT2,        1 << 3),
+       DECLARE_IRQ(S2MU106_PM_IRQ2_IOTGUP,     PM_INT2,        1 << 4),
+       DECLARE_IRQ(S2MU106_PM_IRQ2_IWCINUP,    PM_INT2,        1 << 6),
+       DECLARE_IRQ(S2MU106_PM_IRQ2_ICHGINUP,   PM_INT2,        1 << 7),
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       DECLARE_IRQ(S2MU106_MST_IRQ_SHORT,      MST_INT,        1 << 3);
+       DECLARE_IRQ(S2MU106_MST_IRQ_OCP,        MST_INT,        1 << 4);
+       DECLARE_IRQ(S2MU106_MST_IRQ_EN_OVL,     MST_INT,        1 << 5);
+       DECLARE_IRQ(S2MU106_MST_IRQ_DONE,       MST_INT,        1 << 6);
+       DECLARE_IRQ(S2MU106_MST_IRQ_EN,         MST_INT,        1 << 7);
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       DECLARE_IRQ(S2MU106_HAPTIC_IRQ_OCP,     HAPTIC_INT,     1 << 0);
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       DECLARE_IRQ(S2MU106_HBST_IRQ_OFF,       HBST_INT        1 << 0);
+       DECLARE_IRQ(S2MU106_HBST_IRQ_ON,        HBST_INT        1 << 1);
+       DECLARE_IRQ(S2MU106_HBST_IRQ_SCP,       HBST_INT        1 << 2);
+#endif
+};
+
+static void s2mu106_irq_lock(struct irq_data *data)
+{
+       struct s2mu106_dev *s2mu106 = irq_get_chip_data(data->irq);
+
+       mutex_lock(&s2mu106->irqlock);
+}
+
+static void s2mu106_irq_sync_unlock(struct irq_data *data)
+{
+       struct s2mu106_dev *s2mu106 = irq_get_chip_data(data->irq);
+       int i;
+       u8 mask_reg;
+       struct i2c_client *i2c;
+
+       for (i = 0; i < S2MU106_IRQ_GROUP_NR; i++) {
+               mask_reg = s2mu106_mask_reg[i];
+               i2c = get_i2c(s2mu106, i);
+
+               if (mask_reg == S2MU106_REG_INVALID ||
+                               IS_ERR_OR_NULL(i2c))
+                       continue;
+               s2mu106->irq_masks_cache[i] = s2mu106->irq_masks_cur[i];
+
+               s2mu106_write_reg(i2c, s2mu106_mask_reg[i],
+                               s2mu106->irq_masks_cur[i]);
+       }
+
+       mutex_unlock(&s2mu106->irqlock);
+}
+
+static const inline struct s2mu106_irq_data *
+irq_to_s2mu106_irq(struct s2mu106_dev *s2mu106, int irq)
+{
+       return &s2mu106_irqs[irq - s2mu106->irq_base];
+}
+
+static void s2mu106_irq_mask(struct irq_data *data)
+{
+       struct s2mu106_dev *s2mu106 = irq_get_chip_data(data->irq);
+       const struct s2mu106_irq_data *irq_data =
+           irq_to_s2mu106_irq(s2mu106, data->irq);
+
+       if (irq_data->group >= S2MU106_IRQ_GROUP_NR)
+               return;
+
+       s2mu106->irq_masks_cur[irq_data->group] |= irq_data->mask;
+}
+
+static void s2mu106_irq_unmask(struct irq_data *data)
+{
+       struct s2mu106_dev *s2mu106 = irq_get_chip_data(data->irq);
+       const struct s2mu106_irq_data *irq_data =
+           irq_to_s2mu106_irq(s2mu106, data->irq);
+
+       if (irq_data->group >= S2MU106_IRQ_GROUP_NR)
+               return;
+
+       s2mu106->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
+}
+
+static struct irq_chip s2mu106_irq_chip = {
+       .name                   = MFD_DEV_NAME,
+       .irq_bus_lock   = s2mu106_irq_lock,
+       .irq_bus_sync_unlock    = s2mu106_irq_sync_unlock,
+       .irq_mask               = s2mu106_irq_mask,
+       .irq_unmask             = s2mu106_irq_unmask,
+};
+
+static irqreturn_t s2mu106_irq_thread(int irq, void *data)
+{
+       struct s2mu106_dev *s2mu106 = data;
+       u8 irq_reg[S2MU106_IRQ_GROUP_NR] = {0, };
+       int i, ret;
+       u8 irq_src;
+
+       ret = s2mu106_read_reg(s2mu106->i2c, S2MU106_REG_IPINT, &irq_src);
+       if (ret) {
+        pr_err("%s:%s Failed to read interrupt source: %d\n",
+            MFD_DEV_NAME, __func__, ret);
+        return IRQ_NONE;
+       }
+       pr_info("%s: Top interrupt(0x%02x)\n", __func__, irq_src);
+
+#if defined(CONFIG_CHARGER_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_CHG) {
+               ret = s2mu106_bulk_read(s2mu106->i2c, S2MU106_CHG_INT1,
+                       S2MU106_NUM_IRQ_CHG_REGS, &irq_reg[CHG_INT1]);
+               if (ret) {
+                       pr_err("%s:%s Failed to read charger interrupt: %d\n",
+                               MFD_DEV_NAME, __func__, ret);
+                       return IRQ_NONE;
+               }
+               pr_info("%s() CHARGER intrrupt(0x%02x, 0x%02x, 0x%02x)\n",
+                       __func__, irq_reg[CHG_INT1], irq_reg[CHG_INT2],
+                       irq_reg[CHG_INT3]);
+       }
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_FLED) {
+       }
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       if (irq_src & S2MU106_IRQSRC_AFC) {
+        s2mu106_read_reg(s2mu106->muic, S2MU106_REG_AFC_INT, &irq_reg[AFC_INT]);
+        pr_info("%s: AFC interrupt(0x%02x)\n", __func__, irq_reg[AFC_INT]);
+       }
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_MUIC) {
+        s2mu106_read_reg(s2mu106->muic, S2MU106_REG_MUIC_INT1, &irq_reg[MUIC_INT1]);
+        s2mu106_read_reg(s2mu106->muic, S2MU106_REG_MUIC_INT2, &irq_reg[MUIC_INT2]);
+        pr_info("%s: muic interrupt(0x%02x, 0x%02x)\n", __func__, irq_reg[MUIC_INT1],
+            irq_reg[MUIC_INT2]);
+       }
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_PM) {
+       }
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_MST) {
+       }
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_HAPTIC) {
+       }
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       if (irq_src & S2MU106_IRQSRC_HBST) {
+       }
+#endif
+
+       /* Apply masking */
+       for (i = 0; i < S2MU106_IRQ_GROUP_NR; i++)
+               irq_reg[i] &= ~s2mu106->irq_masks_cur[i];
+
+       /* Report */
+       for (i = 0; i < S2MU106_IRQ_NR; i++) {
+               if (irq_reg[s2mu106_irqs[i].group] & s2mu106_irqs[i].mask)
+                       handle_nested_irq(s2mu106->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+static int irq_is_enable = true;
+int s2mu106_irq_init(struct s2mu106_dev *s2mu106)
+{
+       int i;
+       int ret;
+       struct i2c_client *i2c = s2mu106->i2c;
+       int cur_irq;
+       u8 i2c_data;
+
+       if (!s2mu106->irq_gpio) {
+               dev_warn(s2mu106->dev, "No interrupt specified.\n");
+               s2mu106->irq_base = 0;
+               return 0;
+       }
+
+       if (!s2mu106->irq_base) {
+               dev_err(s2mu106->dev, "No interrupt base specified.\n");
+               return 0;
+       }
+
+       mutex_init(&s2mu106->irqlock);
+
+       s2mu106->irq = gpio_to_irq(s2mu106->irq_gpio);
+       pr_err("%s:%s irq=%d, irq->gpio=%d\n", MFD_DEV_NAME, __func__,
+                       s2mu106->irq, s2mu106->irq_gpio);
+
+       ret = gpio_request(s2mu106->irq_gpio, "if_pmic_irq");
+       if (ret) {
+               dev_err(s2mu106->dev, "%s: failed requesting gpio %d\n",
+                       __func__, s2mu106->irq_gpio);
+               return ret;
+       }
+       gpio_direction_input(s2mu106->irq_gpio);
+       gpio_free(s2mu106->irq_gpio);
+
+       /* Mask individual interrupt sources */
+       for (i = 0; i < S2MU106_IRQ_GROUP_NR; i++) {
+
+               s2mu106->irq_masks_cur[i] = 0xff;
+               s2mu106->irq_masks_cache[i] = 0xff;
+        i2c = get_i2c(s2mu106, i);
+
+               if (IS_ERR_OR_NULL(i2c))
+                       continue;
+               if (s2mu106_mask_reg[i] == S2MU106_REG_INVALID)
+                       continue;
+               s2mu106_write_reg(i2c, s2mu106_mask_reg[i], 0xff);
+       }
+
+       /* Register with genirq */
+       for (i = 0; i < S2MU106_IRQ_NR; i++) {
+               cur_irq = 0;
+               cur_irq = i + s2mu106->irq_base;
+               irq_set_chip_data(cur_irq, s2mu106);
+               irq_set_chip_and_handler(cur_irq, &s2mu106_irq_chip,
+                                               handle_level_irq);
+               irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               irq_set_noprobe(cur_irq);
+#endif
+       }
+
+       /* Unmask S2MU106 interrupt */
+       i2c_data = 0xff;
+#if defined(CONFIG_CHARGER_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_CHG);
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_FLED);
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       i2c_data &= ~(S2MU106_IRQSRC_AFC);
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_MUIC);
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_PM);
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_MST);
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_HAPTIC);
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       i2c_data &= ~(S2MU106_IRQSRC_HBST);
+#endif
+       s2mu106_write_reg(s2mu106->i2c, S2MU106_REG_IPINT_MASK, i2c_data);
+       pr_info("%s: %s init top-irq mask(0x%02x)\n", MFD_DEV_NAME, __func__, i2c_data);
+       pr_info("%s: irq gpio pre-state(0x%02x)\n", __func__,
+               gpio_get_value(s2mu106->irq_gpio));
+
+       if (irq_is_enable) {
+               ret = request_threaded_irq(s2mu106->irq, NULL,
+                               s2mu106_irq_thread,
+                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                               "s2mu106-irq", s2mu106);
+       }
+
+       if (ret) {
+               dev_err(s2mu106->dev, "Failed to request IRQ %d: %d\n",
+                       s2mu106->irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void s2mu106_irq_exit(struct s2mu106_dev *s2mu106)
+{
+       if (s2mu106->irq)
+               free_irq(s2mu106->irq, s2mu106);
+}
diff --git a/include/linux/mfd/samsung/s2mu106.h b/include/linux/mfd/samsung/s2mu106.h
new file mode 100644 (file)
index 0000000..48ca014
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * s2mu106-private.h - Voltage regulator driver for the s2mu106
+ *
+ * Copyright (C) 2016 Samsung Electronics Co.Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __LINUX_MFD_S2MU106_PRIV_H
+#define __LINUX_MFD_S2MU106_PRIV_H
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MFD_DEV_NAME "s2mu106"
+
+/* Slave Address for
+       Charger
+       RGBLED
+       Flash LED */
+#define I2C_ADDR_PM    (0x3D)
+
+/*
+ * Slave Address for the MFD
+ * includes :
+ * MUIC, AFC, PM, MST.
+ * 1 bit right-shifted.
+ */
+#define I2C_ADDR_7C_SLAVE      ((0x7C) >> 1)
+
+/* Slave Address for
+       Haptic
+       Haptic Boost */
+#define I2C_ADDR_HAPTIC        (0x3A)
+
+/* Master Register Addr */
+#define S2MU106_REG_IPINT              0x00
+#define S2MU106_REG_IPINT_MASK         0x07
+#define S2MU106_REG_PMICID             0xF5
+#define S2MU106_REG_PMICID_MASK                0x0F
+#define S2MU106_REG_INVALID            0xFF
+
+/* IRQ */
+enum s2mu106_irq_source {
+#if defined(CONFIG_CHARGER_S2MU106)
+       CHG_INT1,
+       CHG_INT2,
+       CHG_INT3,
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       FLED_INT1,
+       FLED_INT2,
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       AFC_INT,
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       MUIC_INT1,
+       MUIC_INT2,
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       PM_VALUP1,
+       PM_VALUP2,
+       PM_INT1,
+       PM_INT2,
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       MST_INT,
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       HAPTIC_INT,
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       HBST_INT,
+#endif
+       S2MU106_IRQ_GROUP_NR,
+};
+
+#define S2MU106_NUM_IRQ_CHG_REGS       3
+#define S2MU106_NUM_IRQ_LED_REGS       2
+#define S2MU106_NUM_IRQ_AFC_REGS       1
+#define S2MU106_NUM_IRQ_MUIC_REGS      2
+#define S2MU106_NUM_IRQ_PM_REGS                4
+#define S2MU106_NUM_IRQ_MST_REGS       1
+#define S2MU106_NUM_IRQ_HAPTIC_REGS    1
+#define S2MU106_NUM_IRQ_HBST_REGS      1
+
+#define S2MU106_IRQSRC_PM      (1 << 0)
+#define S2MU106_IRQSRC_AFC     (1 << 1)
+#define S2MU106_IRQSRC_MUIC    (1 << 2)
+#define S2MU106_IRQSRC_MST     (1 << 3)
+#define S2MU106_IRQSRC_HBST    (1 << 4)
+#define S2MU106_IRQSRC_FLED    (1 << 5)
+#define S2MU106_IRQSRC_CHG     (1 << 6)
+#define S2MU106_IRQSRC_HAPTIC  (1 << 7)
+
+enum s2mu106_irq {
+#if defined(CONFIG_CHARGER_S2MU106)
+       S2MU106_CHG1_IRQ_SYS,
+       S2MU106_CHG1_IRQ_CV,
+       S2MU106_CHG1_IRQ_CHG_Fault,
+       S2MU106_CHG1_IRQ_CHG_RSTART,
+       S2MU106_CHG1_IRQ_DONE,
+       S2MU106_CHG1_IRQ_TOP_OFF,
+       S2MU106_CHG1_IRQ_WCIN,
+       S2MU106_CHG1_IRQ_CHGIN,
+
+       S2MU106_CHG2_IRQ_ICR,
+       S2MU106_CHG2_IRQ_IVR,
+       S2MU106_CHG2_IRQ_AICL,
+       S2MU106_CHG2_IRQ_DET_BAT,
+       S2MU106_CHG2_IRQ_BAT,
+       S2MU106_CHG2_IRQ_BATN_OPEN,
+       S2MU106_CHG2_IRQ_BATP_OPEN,
+       S2MU106_CHG2_IRQ_QBAT_OFF,
+
+       S2MU106_CHG3_IRQ_BST,
+       S2MU106_CHG3_IRQ_TX,
+       S2MU106_CHG3_IRQ_OTG,
+       S2MU106_CHG3_IRQ_VBUS_Short,
+       S2MU106_CHG3_IRQ_MaxDuty,
+       S2MU106_CHG3_IRQ_PEdone,
+       S2MU106_CHG3_IRQ_BAT_Contact_CK_Done,
+#endif
+#if defined(CONFIG_LEDS_S2MU106)
+       S2MU106_FLED1_IRQ_C2F_Vbyp_ovp_prot,
+       S2MU106_FLED1_IRQ_C2F_Vbyp_OK_Warning,
+       S2MU106_FLED1_IRQ_OPEN_CH3,
+       S2MU106_FLED1_IRQ_OPEN_CH2,
+       S2MU106_FLED1_IRQ_OPEN_CH1,
+       S2MU106_FLED1_IRQ_SHORT_CH3,
+       S2MU106_FLED1_IRQ_SHORT_CH2,
+       S2MU106_FLED1_IRQ_SHORT_CH1,
+
+       S2MU106_FLED2_IRQ_CH3_ON,
+       S2MU106_FLED2_IRQ_CH2_ON,
+       S2MU106_FLED2_IRQ_CH1_ON,
+       S2MU106_FLED2_IRQ_TORCH_ON,
+       S2MU106_FLED2_IRQ_LED_ON_TA_Detach,
+#endif
+#if defined(CONFIG_HV_MUIC_S2MU106_AFC)
+       S2MU106_AFC_IRQ_VbADC,
+       S2MU106_AFC_IRQ_VDNMon,
+       S2MU106_AFC_IRQ_DNRes,
+       S2MU106_AFC_IRQ_MPNack,
+       S2MU106_AFC_IRQ_MRxBufOw,
+       S2MU106_AFC_IRQ_MRxTrf,
+       S2MU106_AFC_IRQ_MRxPerr,
+       S2MU106_AFC_IRQ_MRxRdy,
+#endif
+#if defined(CONFIG_MUIC_S2MU106)
+       S2MU106_MUIC_IRQ1_DETACH,
+       S2MU106_MUIC_IRQ1_ATTATCH,
+       S2MU106_MUIC_IRQ1_KP,
+       S2MU106_MUIC_IRQ1_LKP,
+       S2MU106_MUIC_IRQ1_LKR,
+       S2MU106_MUIC_IRQ1_RID_CHG,
+       S2MU106_MUIC_IRQ1_USB_Killer,
+       S2MU106_MUIC_IRQ1_WAKE_UP,
+
+       S2MU106_MUIC_IRQ2_VBUS_ON,
+       S2MU106_MUIC_IRQ2_RSVD_ATTACH,
+       S2MU106_MUIC_IRQ2_ADC_CHANGE,
+       S2MU106_MUIC_IRQ2_STUCK,
+       S2MU106_MUIC_IRQ2_STUCKRCV,
+       S2MU106_MUIC_IRQ2_MHDL,
+       S2MU106_MUIC_IRQ2_AV_CHARGE,
+       S2MU106_MUIC_IRQ2_VBUS_OFF,
+#endif
+#if defined(CONFIG_PM_S2MU106)
+       S2MU106_PM_VALUP1_VCC2UP,
+       S2MU106_PM_VALUP1_VGPADCUP,
+       S2MU106_PM_VALUP1_VCC1UP,
+       S2MU106_PM_VALUP1_VBATAUP,
+       S2MU106_PM_VALUP1_VSYSAUP,
+       S2MU106_PM_VALUP1_VBYPUP,
+       S2MU106_PM_VALUP1_VWCINUP,
+       S2MU106_PM_VALUP1_VCHGINUP,
+
+       S2MU106_PM_VALUP2_ITXUP,
+       S2MU106_PM_VALUP2_IOTGUP,
+       S2MU106_PM_VALUP2_IWCINUP,
+       S2MU106_PM_VALUP2_ICHGINUP,
+
+       S2MU106_PM_IRQ1_VCC2UP,
+       S2MU106_PM_IRQ1_VGPADCUP,
+       S2MU106_PM_IRQ1_VCC1UP,
+       S2MU106_PM_IRQ1_VBATAUP,
+       S2MU106_PM_IRQ1_VSYSAUP,
+       S2MU106_PM_IRQ1_VBYPUP,
+       S2MU106_PM_IRQ1_VWCINUP,
+       S2MU106_PM_IRQ1_VCHGINUP,
+
+       S2MU106_PM_IRQ2_ITXUP,
+       S2MU106_PM_IRQ2_IOTGUP,
+       S2MU106_PM_IRQ2_IWCINUP,
+       S2MU106_PM_IRQ2_ICHGINUP,
+#endif
+#if defined(CONFIG_MST_S2MU106)
+       S2MU106_MST_IRQ_SHORT,
+       S2MU106_MST_IRQ_OCP,
+       S2MU106_MST_IRQ_EN_OVL,
+       S2MU106_MST_IRQ_DONE,
+       S2MU106_MST_IRQ_EN,
+#endif
+#if defined(CONFIG_MOTOR_S2MU106)
+       S2MU106_HAPTIC_IRQ_OCP,
+#endif
+#if defined(CONFIG_REGULATOR_S2MU106)
+       S2MU106_HBST_IRQ_OFF,
+       S2MU106_HBST_IRQ_ON,
+       S2MU106_HBST_IRQ_SCP,
+#endif
+       S2MU106_IRQ_NR,
+};
+
+struct s2mu106_platform_data {
+       /* IRQ */
+       int irq_base;
+       int irq_gpio;
+       bool wakeup;
+};
+
+struct s2mu106_dev {
+       struct device *dev;
+       struct i2c_client *i2c;         /* Slave addr = 0x3D */
+       struct i2c_client *muic;        /* Slave addr = 0x3E */
+       struct i2c_client *haptic;      /* Slave addr = 0x3A */
+       struct mutex i2c_lock;
+
+       int type;
+
+       int irq;
+       int irq_base;
+       int irq_gpio;
+       bool wakeup;
+       struct mutex irqlock;
+       int irq_masks_cur[S2MU106_IRQ_GROUP_NR];
+       int irq_masks_cache[S2MU106_IRQ_GROUP_NR];
+
+       /* pmic VER/REV register */
+       u8 pmic_rev;    /* pmic Rev */
+       u8 pmic_ver;    /* pmic version */
+
+       struct s2mu106_platform_data *pdata;
+};
+
+enum s2mu106_types {
+       TYPE_S2MU106,
+};
+
+extern int s2mu106_irq_init(struct s2mu106_dev *s2mu106);
+extern void s2mu106_irq_exit(struct s2mu106_dev *s2mu106);
+
+/* s2mu106 shared i2c API function */
+extern int s2mu106_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
+extern int s2mu106_bulk_read(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int s2mu106_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
+extern int s2mu106_bulk_write(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int s2mu106_write_word(struct i2c_client *i2c, u8 reg, u16 value);
+extern int s2mu106_read_word(struct i2c_client *i2c, u8 reg);
+
+extern int s2mu106_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask);
+
+#endif /* __LINUX_MFD_S2MU106_PRIV_H */
+