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
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
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
+