From 3c3227c4e1ca2cb458887876a34b1d50611eee89 Mon Sep 17 00:00:00 2001 From: Kim Taejeong Date: Mon, 11 Feb 2019 16:07:19 +0900 Subject: [PATCH] [RAMEN9610-11989][COMMON] mfd: integrate MU004 and MU106 Change-Id: I8ec36e5eaa46df2b9a96e7f21eba925eb31cbbfc Signed-off-by: Kim Taejeong --- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/s2mu106_core.c | 407 +++++++++++++++++++++++ drivers/mfd/s2mu106_irq.c | 479 ++++++++++++++++++++++++++++ include/linux/mfd/samsung/s2mu106.h | 282 ++++++++++++++++ 5 files changed, 1179 insertions(+) create mode 100644 drivers/mfd/s2mu106_core.c create mode 100644 drivers/mfd/s2mu106_irq.c create mode 100644 include/linux/mfd/samsung/s2mu106.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d1317c152be1..4e13d02d7936 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -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 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 6d04eb0cbd31..6928f7e5ce0c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -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 index 000000000000..ace20bdf421d --- /dev/null +++ b/drivers/mfd/s2mu106_core.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 index 000000000000..f861f2899fdb --- /dev/null +++ b/drivers/mfd/s2mu106_irq.c @@ -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 +#include +#include +#include +#include + +#if defined(CONFIG_CHARGER_S2MU106) +#include +#endif +#if defined(CONFIG_MUIC_S2MU106) +#include +#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 index 000000000000..48ca014a2bcf --- /dev/null +++ b/include/linux/mfd/samsung/s2mu106.h @@ -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 +#include +#include +#include + +#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 */ + -- 2.20.1