139b27ad9SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0+ 239b27ad9SKrzysztof Kozlowski // 339b27ad9SKrzysztof Kozlowski // Copyright (c) 2012 Samsung Electronics Co., Ltd 439b27ad9SKrzysztof Kozlowski // http://www.samsung.com 566c9fbb9SSangbeom Kim 666c9fbb9SSangbeom Kim #include <linux/module.h> 766c9fbb9SSangbeom Kim #include <linux/moduleparam.h> 866c9fbb9SSangbeom Kim #include <linux/init.h> 966c9fbb9SSangbeom Kim #include <linux/err.h> 1066c9fbb9SSangbeom Kim #include <linux/slab.h> 1166c9fbb9SSangbeom Kim #include <linux/i2c.h> 121c5a099bSSachin Kamat #include <linux/of.h> 1326aec009SAmit Daniel Kachhap #include <linux/of_irq.h> 1466c9fbb9SSangbeom Kim #include <linux/interrupt.h> 1566c9fbb9SSangbeom Kim #include <linux/pm_runtime.h> 1666c9fbb9SSangbeom Kim #include <linux/mutex.h> 1766c9fbb9SSangbeom Kim #include <linux/mfd/core.h> 1854227bcfSSangbeom Kim #include <linux/mfd/samsung/core.h> 1954227bcfSSangbeom Kim #include <linux/mfd/samsung/irq.h> 20ce24991eSSachin Kamat #include <linux/mfd/samsung/s2mpa01.h> 2125f311faSMark Brown #include <linux/mfd/samsung/s2mps11.h> 2276b9840bSChanwoo Choi #include <linux/mfd/samsung/s2mps13.h> 23dc691966SKrzysztof Kozlowski #include <linux/mfd/samsung/s2mps14.h> 249e4808d2SThomas Abraham #include <linux/mfd/samsung/s2mps15.h> 2500e2573dSChanwoo Choi #include <linux/mfd/samsung/s2mpu02.h> 2625f311faSMark Brown #include <linux/mfd/samsung/s5m8763.h> 2725f311faSMark Brown #include <linux/mfd/samsung/s5m8767.h> 2866c9fbb9SSangbeom Kim #include <linux/regmap.h> 2966c9fbb9SSangbeom Kim 305ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8751_devs[] = { 3166c9fbb9SSangbeom Kim { 3266c9fbb9SSangbeom Kim .name = "s5m8751-pmic", 3366c9fbb9SSangbeom Kim }, { 3466c9fbb9SSangbeom Kim .name = "s5m-charger", 3566c9fbb9SSangbeom Kim }, { 3666c9fbb9SSangbeom Kim .name = "s5m8751-codec", 3766c9fbb9SSangbeom Kim }, 3866c9fbb9SSangbeom Kim }; 3966c9fbb9SSangbeom Kim 405ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8763_devs[] = { 4166c9fbb9SSangbeom Kim { 4266c9fbb9SSangbeom Kim .name = "s5m8763-pmic", 4366c9fbb9SSangbeom Kim }, { 4466c9fbb9SSangbeom Kim .name = "s5m-rtc", 4566c9fbb9SSangbeom Kim }, { 4666c9fbb9SSangbeom Kim .name = "s5m-charger", 4766c9fbb9SSangbeom Kim }, 4866c9fbb9SSangbeom Kim }; 4966c9fbb9SSangbeom Kim 505ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8767_devs[] = { 5166c9fbb9SSangbeom Kim { 5266c9fbb9SSangbeom Kim .name = "s5m8767-pmic", 5366c9fbb9SSangbeom Kim }, { 5466c9fbb9SSangbeom Kim .name = "s5m-rtc", 5539fed00fSTushar Behera }, { 5639fed00fSTushar Behera .name = "s5m8767-clk", 5753c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s5m8767-clk", 5839fed00fSTushar Behera } 5966c9fbb9SSangbeom Kim }; 6066c9fbb9SSangbeom Kim 615ac98553SGeert Uytterhoeven static const struct mfd_cell s2mps11_devs[] = { 629b6d1343SSangbeom Kim { 632fadbbf0SAlim Akhtar .name = "s2mps11-regulator", 643134bcaeSYadwinder Singh Brar }, { 65eea2e596SKrzysztof Kozlowski .name = "s2mps14-rtc", 66eea2e596SKrzysztof Kozlowski }, { 673134bcaeSYadwinder Singh Brar .name = "s2mps11-clk", 6853c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps11-clk", 693134bcaeSYadwinder Singh Brar } 709b6d1343SSangbeom Kim }; 719b6d1343SSangbeom Kim 723bc2ee91SChanwoo Choi static const struct mfd_cell s2mps13_devs[] = { 732fadbbf0SAlim Akhtar { .name = "s2mps13-regulator", }, 743bc2ee91SChanwoo Choi { .name = "s2mps13-rtc", }, 753bc2ee91SChanwoo Choi { 763bc2ee91SChanwoo Choi .name = "s2mps13-clk", 773bc2ee91SChanwoo Choi .of_compatible = "samsung,s2mps13-clk", 783bc2ee91SChanwoo Choi }, 793bc2ee91SChanwoo Choi }; 803bc2ee91SChanwoo Choi 81dc691966SKrzysztof Kozlowski static const struct mfd_cell s2mps14_devs[] = { 82dc691966SKrzysztof Kozlowski { 832fadbbf0SAlim Akhtar .name = "s2mps14-regulator", 84dc691966SKrzysztof Kozlowski }, { 85dc691966SKrzysztof Kozlowski .name = "s2mps14-rtc", 86dc691966SKrzysztof Kozlowski }, { 87dc691966SKrzysztof Kozlowski .name = "s2mps14-clk", 8853c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps14-clk", 89dc691966SKrzysztof Kozlowski } 90dc691966SKrzysztof Kozlowski }; 91dc691966SKrzysztof Kozlowski 929e4808d2SThomas Abraham static const struct mfd_cell s2mps15_devs[] = { 939e4808d2SThomas Abraham { 949e4808d2SThomas Abraham .name = "s2mps15-regulator", 959e4808d2SThomas Abraham }, { 969e4808d2SThomas Abraham .name = "s2mps15-rtc", 979e4808d2SThomas Abraham }, { 989e4808d2SThomas Abraham .name = "s2mps13-clk", 999e4808d2SThomas Abraham .of_compatible = "samsung,s2mps13-clk", 1009e4808d2SThomas Abraham }, 1019e4808d2SThomas Abraham }; 1029e4808d2SThomas Abraham 103ce24991eSSachin Kamat static const struct mfd_cell s2mpa01_devs[] = { 104ce24991eSSachin Kamat { 105ce24991eSSachin Kamat .name = "s2mpa01-pmic", 106ce24991eSSachin Kamat }, 107ce24991eSSachin Kamat }; 108ce24991eSSachin Kamat 10954e8827dSChanwoo Choi static const struct mfd_cell s2mpu02_devs[] = { 11054e8827dSChanwoo Choi { 1112fadbbf0SAlim Akhtar .name = "s2mpu02-regulator", 112644a3746SKrzysztof Kozlowski }, 11354e8827dSChanwoo Choi }; 11454e8827dSChanwoo Choi 11526aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 116df20b7c5SKrzysztof Kozlowski static const struct of_device_id sec_dt_match[] = { 11726aec009SAmit Daniel Kachhap { .compatible = "samsung,s5m8767-pmic", 11826aec009SAmit Daniel Kachhap .data = (void *)S5M8767X, 119ce24991eSSachin Kamat }, { 120ce24991eSSachin Kamat .compatible = "samsung,s2mps11-pmic", 121aa32acadSYadwinder Singh Brar .data = (void *)S2MPS11X, 122ce24991eSSachin Kamat }, { 1233bc2ee91SChanwoo Choi .compatible = "samsung,s2mps13-pmic", 1243bc2ee91SChanwoo Choi .data = (void *)S2MPS13X, 1253bc2ee91SChanwoo Choi }, { 126ce24991eSSachin Kamat .compatible = "samsung,s2mps14-pmic", 127dc691966SKrzysztof Kozlowski .data = (void *)S2MPS14X, 128ce24991eSSachin Kamat }, { 1299e4808d2SThomas Abraham .compatible = "samsung,s2mps15-pmic", 1309e4808d2SThomas Abraham .data = (void *)S2MPS15X, 1319e4808d2SThomas Abraham }, { 132ce24991eSSachin Kamat .compatible = "samsung,s2mpa01-pmic", 133ce24991eSSachin Kamat .data = (void *)S2MPA01, 134ce24991eSSachin Kamat }, { 13554e8827dSChanwoo Choi .compatible = "samsung,s2mpu02-pmic", 13654e8827dSChanwoo Choi .data = (void *)S2MPU02, 13754e8827dSChanwoo Choi }, { 138ce24991eSSachin Kamat /* Sentinel */ 139dc691966SKrzysztof Kozlowski }, 14026aec009SAmit Daniel Kachhap }; 141fe8166c9SKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, sec_dt_match); 14226aec009SAmit Daniel Kachhap #endif 14326aec009SAmit Daniel Kachhap 144ce24991eSSachin Kamat static bool s2mpa01_volatile(struct device *dev, unsigned int reg) 145ce24991eSSachin Kamat { 146ce24991eSSachin Kamat switch (reg) { 147ce24991eSSachin Kamat case S2MPA01_REG_INT1M: 148ce24991eSSachin Kamat case S2MPA01_REG_INT2M: 149ce24991eSSachin Kamat case S2MPA01_REG_INT3M: 150ce24991eSSachin Kamat return false; 151ce24991eSSachin Kamat default: 152ce24991eSSachin Kamat return true; 153ce24991eSSachin Kamat } 154ce24991eSSachin Kamat } 155ce24991eSSachin Kamat 1566b845ba9SMark Brown static bool s2mps11_volatile(struct device *dev, unsigned int reg) 1576b845ba9SMark Brown { 1586b845ba9SMark Brown switch (reg) { 1596b845ba9SMark Brown case S2MPS11_REG_INT1M: 1606b845ba9SMark Brown case S2MPS11_REG_INT2M: 1616b845ba9SMark Brown case S2MPS11_REG_INT3M: 1626b845ba9SMark Brown return false; 1636b845ba9SMark Brown default: 1646b845ba9SMark Brown return true; 1656b845ba9SMark Brown } 1666b845ba9SMark Brown } 1676b845ba9SMark Brown 16800e2573dSChanwoo Choi static bool s2mpu02_volatile(struct device *dev, unsigned int reg) 16900e2573dSChanwoo Choi { 17000e2573dSChanwoo Choi switch (reg) { 17100e2573dSChanwoo Choi case S2MPU02_REG_INT1M: 17200e2573dSChanwoo Choi case S2MPU02_REG_INT2M: 17300e2573dSChanwoo Choi case S2MPU02_REG_INT3M: 17400e2573dSChanwoo Choi return false; 17500e2573dSChanwoo Choi default: 17600e2573dSChanwoo Choi return true; 17700e2573dSChanwoo Choi } 17800e2573dSChanwoo Choi } 17900e2573dSChanwoo Choi 1806b845ba9SMark Brown static bool s5m8763_volatile(struct device *dev, unsigned int reg) 1816b845ba9SMark Brown { 1826b845ba9SMark Brown switch (reg) { 1836b845ba9SMark Brown case S5M8763_REG_IRQM1: 1846b845ba9SMark Brown case S5M8763_REG_IRQM2: 1856b845ba9SMark Brown case S5M8763_REG_IRQM3: 1866b845ba9SMark Brown case S5M8763_REG_IRQM4: 1876b845ba9SMark Brown return false; 1886b845ba9SMark Brown default: 1896b845ba9SMark Brown return true; 1906b845ba9SMark Brown } 1916b845ba9SMark Brown } 1926b845ba9SMark Brown 193a30fffb0SKrzysztof Kozlowski static const struct regmap_config sec_regmap_config = { 19466c9fbb9SSangbeom Kim .reg_bits = 8, 19566c9fbb9SSangbeom Kim .val_bits = 8, 19666c9fbb9SSangbeom Kim }; 19766c9fbb9SSangbeom Kim 198ce24991eSSachin Kamat static const struct regmap_config s2mpa01_regmap_config = { 199ce24991eSSachin Kamat .reg_bits = 8, 200ce24991eSSachin Kamat .val_bits = 8, 201ce24991eSSachin Kamat 202ce24991eSSachin Kamat .max_register = S2MPA01_REG_LDO_OVCB4, 203ce24991eSSachin Kamat .volatile_reg = s2mpa01_volatile, 204ce24991eSSachin Kamat .cache_type = REGCACHE_FLAT, 205ce24991eSSachin Kamat }; 206ce24991eSSachin Kamat 207a30fffb0SKrzysztof Kozlowski static const struct regmap_config s2mps11_regmap_config = { 20825f311faSMark Brown .reg_bits = 8, 20925f311faSMark Brown .val_bits = 8, 21025f311faSMark Brown 21125f311faSMark Brown .max_register = S2MPS11_REG_L38CTRL, 2126b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2136b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 21425f311faSMark Brown }; 21525f311faSMark Brown 21676b9840bSChanwoo Choi static const struct regmap_config s2mps13_regmap_config = { 21776b9840bSChanwoo Choi .reg_bits = 8, 21876b9840bSChanwoo Choi .val_bits = 8, 21976b9840bSChanwoo Choi 22076b9840bSChanwoo Choi .max_register = S2MPS13_REG_LDODSCH5, 22176b9840bSChanwoo Choi .volatile_reg = s2mps11_volatile, 22276b9840bSChanwoo Choi .cache_type = REGCACHE_FLAT, 22376b9840bSChanwoo Choi }; 22476b9840bSChanwoo Choi 225dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_regmap_config = { 226dc691966SKrzysztof Kozlowski .reg_bits = 8, 227dc691966SKrzysztof Kozlowski .val_bits = 8, 228dc691966SKrzysztof Kozlowski 229dc691966SKrzysztof Kozlowski .max_register = S2MPS14_REG_LDODSCH3, 230dc691966SKrzysztof Kozlowski .volatile_reg = s2mps11_volatile, 231dc691966SKrzysztof Kozlowski .cache_type = REGCACHE_FLAT, 232dc691966SKrzysztof Kozlowski }; 233dc691966SKrzysztof Kozlowski 2349e4808d2SThomas Abraham static const struct regmap_config s2mps15_regmap_config = { 2359e4808d2SThomas Abraham .reg_bits = 8, 2369e4808d2SThomas Abraham .val_bits = 8, 2379e4808d2SThomas Abraham 2389e4808d2SThomas Abraham .max_register = S2MPS15_REG_LDODSCH4, 2399e4808d2SThomas Abraham .volatile_reg = s2mps11_volatile, 2409e4808d2SThomas Abraham .cache_type = REGCACHE_FLAT, 2419e4808d2SThomas Abraham }; 2429e4808d2SThomas Abraham 24300e2573dSChanwoo Choi static const struct regmap_config s2mpu02_regmap_config = { 24400e2573dSChanwoo Choi .reg_bits = 8, 24500e2573dSChanwoo Choi .val_bits = 8, 24600e2573dSChanwoo Choi 24700e2573dSChanwoo Choi .max_register = S2MPU02_REG_DVSDATA, 24800e2573dSChanwoo Choi .volatile_reg = s2mpu02_volatile, 24900e2573dSChanwoo Choi .cache_type = REGCACHE_FLAT, 25000e2573dSChanwoo Choi }; 25100e2573dSChanwoo Choi 252a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = { 25325f311faSMark Brown .reg_bits = 8, 25425f311faSMark Brown .val_bits = 8, 25525f311faSMark Brown 25625f311faSMark Brown .max_register = S5M8763_REG_LBCNFG2, 2576b845ba9SMark Brown .volatile_reg = s5m8763_volatile, 2586b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 25925f311faSMark Brown }; 26025f311faSMark Brown 261a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = { 26225f311faSMark Brown .reg_bits = 8, 26325f311faSMark Brown .val_bits = 8, 26425f311faSMark Brown 26525f311faSMark Brown .max_register = S5M8767_REG_LDO28CTRL, 2666b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2676b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 26825f311faSMark Brown }; 26926aec009SAmit Daniel Kachhap 270c2c9f1feSKrzysztof Kozlowski static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) 271c2c9f1feSKrzysztof Kozlowski { 272c2c9f1feSKrzysztof Kozlowski unsigned int val; 273c2c9f1feSKrzysztof Kozlowski 274c2c9f1feSKrzysztof Kozlowski /* For each device type, the REG_ID is always the first register */ 275c2c9f1feSKrzysztof Kozlowski if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) 276c2c9f1feSKrzysztof Kozlowski dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); 277c2c9f1feSKrzysztof Kozlowski } 278c2c9f1feSKrzysztof Kozlowski 2798a97d428SKrzysztof Kozlowski static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) 2808a97d428SKrzysztof Kozlowski { 2818a97d428SKrzysztof Kozlowski int err; 2828a97d428SKrzysztof Kozlowski 2838a97d428SKrzysztof Kozlowski if (sec_pmic->device_type != S2MPS13X) 2848a97d428SKrzysztof Kozlowski return; 2858a97d428SKrzysztof Kozlowski 2868a97d428SKrzysztof Kozlowski if (sec_pmic->pdata->disable_wrstbi) { 2878a97d428SKrzysztof Kozlowski /* 2888a97d428SKrzysztof Kozlowski * If WRSTBI pin is pulled down this feature must be disabled 2898a97d428SKrzysztof Kozlowski * because each Suspend to RAM will trigger buck voltage reset 2908a97d428SKrzysztof Kozlowski * to default values. 2918a97d428SKrzysztof Kozlowski */ 2928a97d428SKrzysztof Kozlowski err = regmap_update_bits(sec_pmic->regmap_pmic, 2938a97d428SKrzysztof Kozlowski S2MPS13_REG_WRSTBI, 2948a97d428SKrzysztof Kozlowski S2MPS13_REG_WRSTBI_MASK, 0x0); 2958a97d428SKrzysztof Kozlowski if (err) 2968a97d428SKrzysztof Kozlowski dev_warn(sec_pmic->dev, 2978a97d428SKrzysztof Kozlowski "Cannot initialize WRSTBI config: %d\n", 2988a97d428SKrzysztof Kozlowski err); 2998a97d428SKrzysztof Kozlowski } 3008a97d428SKrzysztof Kozlowski } 3018a97d428SKrzysztof Kozlowski 30226aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 30326aec009SAmit Daniel Kachhap /* 30426aec009SAmit Daniel Kachhap * Only the common platform data elements for s5m8767 are parsed here from the 30526aec009SAmit Daniel Kachhap * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 30626aec009SAmit Daniel Kachhap * others have to parse their own platform data elements from device tree. 30726aec009SAmit Daniel Kachhap * 30826aec009SAmit Daniel Kachhap * The s5m8767 platform data structure is instantiated here and the drivers for 30926aec009SAmit Daniel Kachhap * the sub-modules need not instantiate another instance while parsing their 31026aec009SAmit Daniel Kachhap * platform data. 31126aec009SAmit Daniel Kachhap */ 31226aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 31326aec009SAmit Daniel Kachhap struct device *dev) 31426aec009SAmit Daniel Kachhap { 31526aec009SAmit Daniel Kachhap struct sec_platform_data *pd; 31626aec009SAmit Daniel Kachhap 31726aec009SAmit Daniel Kachhap pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 31882a00c49SKrzysztof Kozlowski if (!pd) 31926aec009SAmit Daniel Kachhap return ERR_PTR(-ENOMEM); 32026aec009SAmit Daniel Kachhap 32126aec009SAmit Daniel Kachhap /* 32226aec009SAmit Daniel Kachhap * ToDo: the 'wakeup' member in the platform data is more of a linux 32326aec009SAmit Daniel Kachhap * specfic information. Hence, there is no binding for that yet and 32426aec009SAmit Daniel Kachhap * not parsed here. 32526aec009SAmit Daniel Kachhap */ 32626aec009SAmit Daniel Kachhap 327d785334aSKrzysztof Kozlowski pd->manual_poweroff = of_property_read_bool(dev->of_node, 328d785334aSKrzysztof Kozlowski "samsung,s2mps11-acokb-ground"); 3298a97d428SKrzysztof Kozlowski pd->disable_wrstbi = of_property_read_bool(dev->of_node, 3308a97d428SKrzysztof Kozlowski "samsung,s2mps11-wrstbi-ground"); 33126aec009SAmit Daniel Kachhap return pd; 33226aec009SAmit Daniel Kachhap } 33326aec009SAmit Daniel Kachhap #else 334197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 33526aec009SAmit Daniel Kachhap struct device *dev) 33626aec009SAmit Daniel Kachhap { 337005718c0SWei Yongjun return NULL; 33826aec009SAmit Daniel Kachhap } 33926aec009SAmit Daniel Kachhap #endif 34026aec009SAmit Daniel Kachhap 3418f695de5SPankaj Dubey static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, 34226aec009SAmit Daniel Kachhap const struct i2c_device_id *id) 34326aec009SAmit Daniel Kachhap { 34426aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 34526aec009SAmit Daniel Kachhap if (i2c->dev.of_node) { 34626aec009SAmit Daniel Kachhap const struct of_device_id *match; 347b6c1cb4dSLee Jones 34826aec009SAmit Daniel Kachhap match = of_match_node(sec_dt_match, i2c->dev.of_node); 3498f695de5SPankaj Dubey return (unsigned long)match->data; 35026aec009SAmit Daniel Kachhap } 35126aec009SAmit Daniel Kachhap #endif 3528f695de5SPankaj Dubey return id->driver_data; 35326aec009SAmit Daniel Kachhap } 35426aec009SAmit Daniel Kachhap 35563063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c, 35666c9fbb9SSangbeom Kim const struct i2c_device_id *id) 35766c9fbb9SSangbeom Kim { 358334a41ceSJingoo Han struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); 359e349c910SKrzysztof Kozlowski const struct regmap_config *regmap; 36054e8827dSChanwoo Choi const struct mfd_cell *sec_devs; 36163063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic; 3629549b5ffSKrzysztof Kozlowski unsigned long device_type; 36354e8827dSChanwoo Choi int ret, num_sec_devs; 36466c9fbb9SSangbeom Kim 36563063bfbSSangbeom Kim sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), 36666c9fbb9SSangbeom Kim GFP_KERNEL); 36763063bfbSSangbeom Kim if (sec_pmic == NULL) 36866c9fbb9SSangbeom Kim return -ENOMEM; 36966c9fbb9SSangbeom Kim 37063063bfbSSangbeom Kim i2c_set_clientdata(i2c, sec_pmic); 37163063bfbSSangbeom Kim sec_pmic->dev = &i2c->dev; 37263063bfbSSangbeom Kim sec_pmic->i2c = i2c; 37363063bfbSSangbeom Kim sec_pmic->irq = i2c->irq; 3749549b5ffSKrzysztof Kozlowski device_type = sec_i2c_get_driver_data(i2c, id); 37566c9fbb9SSangbeom Kim 37626aec009SAmit Daniel Kachhap if (sec_pmic->dev->of_node) { 37726aec009SAmit Daniel Kachhap pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); 37826aec009SAmit Daniel Kachhap if (IS_ERR(pdata)) { 37926aec009SAmit Daniel Kachhap ret = PTR_ERR(pdata); 38026aec009SAmit Daniel Kachhap return ret; 38126aec009SAmit Daniel Kachhap } 3829549b5ffSKrzysztof Kozlowski pdata->device_type = device_type; 38326aec009SAmit Daniel Kachhap } 38466c9fbb9SSangbeom Kim if (pdata) { 38563063bfbSSangbeom Kim sec_pmic->device_type = pdata->device_type; 38663063bfbSSangbeom Kim sec_pmic->irq_base = pdata->irq_base; 38763063bfbSSangbeom Kim sec_pmic->wakeup = pdata->wakeup; 38826aec009SAmit Daniel Kachhap sec_pmic->pdata = pdata; 38966c9fbb9SSangbeom Kim } 39066c9fbb9SSangbeom Kim 39125f311faSMark Brown switch (sec_pmic->device_type) { 392ce24991eSSachin Kamat case S2MPA01: 393ce24991eSSachin Kamat regmap = &s2mpa01_regmap_config; 394ce24991eSSachin Kamat break; 39525f311faSMark Brown case S2MPS11X: 39625f311faSMark Brown regmap = &s2mps11_regmap_config; 397dc691966SKrzysztof Kozlowski break; 39876b9840bSChanwoo Choi case S2MPS13X: 39976b9840bSChanwoo Choi regmap = &s2mps13_regmap_config; 40076b9840bSChanwoo Choi break; 401dc691966SKrzysztof Kozlowski case S2MPS14X: 402dc691966SKrzysztof Kozlowski regmap = &s2mps14_regmap_config; 40325f311faSMark Brown break; 4049e4808d2SThomas Abraham case S2MPS15X: 4059e4808d2SThomas Abraham regmap = &s2mps15_regmap_config; 4069e4808d2SThomas Abraham break; 40725f311faSMark Brown case S5M8763X: 40825f311faSMark Brown regmap = &s5m8763_regmap_config; 40925f311faSMark Brown break; 41025f311faSMark Brown case S5M8767X: 41125f311faSMark Brown regmap = &s5m8767_regmap_config; 41225f311faSMark Brown break; 41300e2573dSChanwoo Choi case S2MPU02: 41400e2573dSChanwoo Choi regmap = &s2mpu02_regmap_config; 41500e2573dSChanwoo Choi break; 41625f311faSMark Brown default: 41725f311faSMark Brown regmap = &sec_regmap_config; 41825f311faSMark Brown break; 41925f311faSMark Brown } 42025f311faSMark Brown 4213e1e4a5fSKrzysztof Kozlowski sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); 4223e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_pmic)) { 4233e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_pmic); 42466c9fbb9SSangbeom Kim dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 42566c9fbb9SSangbeom Kim ret); 42666c9fbb9SSangbeom Kim return ret; 42766c9fbb9SSangbeom Kim } 42866c9fbb9SSangbeom Kim 42966c9fbb9SSangbeom Kim if (pdata && pdata->cfg_pmic_irq) 43066c9fbb9SSangbeom Kim pdata->cfg_pmic_irq(); 43166c9fbb9SSangbeom Kim 43263063bfbSSangbeom Kim sec_irq_init(sec_pmic); 43366c9fbb9SSangbeom Kim 43463063bfbSSangbeom Kim pm_runtime_set_active(sec_pmic->dev); 43566c9fbb9SSangbeom Kim 43663063bfbSSangbeom Kim switch (sec_pmic->device_type) { 43766c9fbb9SSangbeom Kim case S5M8751X: 43854e8827dSChanwoo Choi sec_devs = s5m8751_devs; 43954e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8751_devs); 44066c9fbb9SSangbeom Kim break; 44166c9fbb9SSangbeom Kim case S5M8763X: 44254e8827dSChanwoo Choi sec_devs = s5m8763_devs; 44354e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8763_devs); 44466c9fbb9SSangbeom Kim break; 44566c9fbb9SSangbeom Kim case S5M8767X: 44654e8827dSChanwoo Choi sec_devs = s5m8767_devs; 44754e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8767_devs); 44866c9fbb9SSangbeom Kim break; 449ce24991eSSachin Kamat case S2MPA01: 45054e8827dSChanwoo Choi sec_devs = s2mpa01_devs; 45154e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpa01_devs); 452ce24991eSSachin Kamat break; 4539b6d1343SSangbeom Kim case S2MPS11X: 45454e8827dSChanwoo Choi sec_devs = s2mps11_devs; 45554e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps11_devs); 4569b6d1343SSangbeom Kim break; 4573bc2ee91SChanwoo Choi case S2MPS13X: 4583bc2ee91SChanwoo Choi sec_devs = s2mps13_devs; 4593bc2ee91SChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps13_devs); 4603bc2ee91SChanwoo Choi break; 461dc691966SKrzysztof Kozlowski case S2MPS14X: 46254e8827dSChanwoo Choi sec_devs = s2mps14_devs; 46354e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps14_devs); 46454e8827dSChanwoo Choi break; 4659e4808d2SThomas Abraham case S2MPS15X: 4669e4808d2SThomas Abraham sec_devs = s2mps15_devs; 4679e4808d2SThomas Abraham num_sec_devs = ARRAY_SIZE(s2mps15_devs); 4689e4808d2SThomas Abraham break; 46954e8827dSChanwoo Choi case S2MPU02: 47054e8827dSChanwoo Choi sec_devs = s2mpu02_devs; 47154e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpu02_devs); 472dc691966SKrzysztof Kozlowski break; 47366c9fbb9SSangbeom Kim default: 47466c9fbb9SSangbeom Kim /* If this happens the probe function is problem */ 47566c9fbb9SSangbeom Kim BUG(); 47666c9fbb9SSangbeom Kim } 4773dc6f4aaSLaxman Dewangan ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, 4783dc6f4aaSLaxman Dewangan NULL, 0, NULL); 47915447a46SLeon Romanovsky if (ret) 4803dc6f4aaSLaxman Dewangan return ret; 48166c9fbb9SSangbeom Kim 482f6d6daafSKrzysztof Kozlowski device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); 4838a97d428SKrzysztof Kozlowski sec_pmic_configure(sec_pmic); 484c2c9f1feSKrzysztof Kozlowski sec_pmic_dump_rev(sec_pmic); 485f6d6daafSKrzysztof Kozlowski 48666c9fbb9SSangbeom Kim return ret; 48766c9fbb9SSangbeom Kim } 48866c9fbb9SSangbeom Kim 489d785334aSKrzysztof Kozlowski static void sec_pmic_shutdown(struct i2c_client *i2c) 490d785334aSKrzysztof Kozlowski { 491d785334aSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 492d785334aSKrzysztof Kozlowski unsigned int reg, mask; 493d785334aSKrzysztof Kozlowski 494d785334aSKrzysztof Kozlowski if (!sec_pmic->pdata->manual_poweroff) 495d785334aSKrzysztof Kozlowski return; 496d785334aSKrzysztof Kozlowski 497d785334aSKrzysztof Kozlowski switch (sec_pmic->device_type) { 498d785334aSKrzysztof Kozlowski case S2MPS11X: 499d785334aSKrzysztof Kozlowski reg = S2MPS11_REG_CTRL1; 500d785334aSKrzysztof Kozlowski mask = S2MPS11_CTRL1_PWRHOLD_MASK; 501d785334aSKrzysztof Kozlowski break; 502d785334aSKrzysztof Kozlowski default: 503d785334aSKrzysztof Kozlowski /* 504d785334aSKrzysztof Kozlowski * Currently only one board with S2MPS11 needs this, so just 505d785334aSKrzysztof Kozlowski * ignore the rest. 506d785334aSKrzysztof Kozlowski */ 507d785334aSKrzysztof Kozlowski dev_warn(sec_pmic->dev, 508d785334aSKrzysztof Kozlowski "Unsupported device %lu for manual power off\n", 509d785334aSKrzysztof Kozlowski sec_pmic->device_type); 510d785334aSKrzysztof Kozlowski return; 511d785334aSKrzysztof Kozlowski } 512d785334aSKrzysztof Kozlowski 513d785334aSKrzysztof Kozlowski regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); 514d785334aSKrzysztof Kozlowski } 515d785334aSKrzysztof Kozlowski 5168321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 517f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev) 518f6d6daafSKrzysztof Kozlowski { 5191b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev); 520f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 521f6d6daafSKrzysztof Kozlowski 522360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 523f6d6daafSKrzysztof Kozlowski enable_irq_wake(sec_pmic->irq); 524f6d6daafSKrzysztof Kozlowski /* 525f6d6daafSKrzysztof Kozlowski * PMIC IRQ must be disabled during suspend for RTC alarm 526f6d6daafSKrzysztof Kozlowski * to work properly. 527360d15d6SKrzysztof Kozlowski * When device is woken up from suspend, an 528f6d6daafSKrzysztof Kozlowski * interrupt occurs before resuming I2C bus controller. 529f6d6daafSKrzysztof Kozlowski * The interrupt is handled by regmap_irq_thread which tries 530f6d6daafSKrzysztof Kozlowski * to read RTC registers. This read fails (I2C is still 531f6d6daafSKrzysztof Kozlowski * suspended) and RTC Alarm interrupt is disabled. 532f6d6daafSKrzysztof Kozlowski */ 533f6d6daafSKrzysztof Kozlowski disable_irq(sec_pmic->irq); 534f6d6daafSKrzysztof Kozlowski 535f6d6daafSKrzysztof Kozlowski return 0; 536f6d6daafSKrzysztof Kozlowski } 537f6d6daafSKrzysztof Kozlowski 538f6d6daafSKrzysztof Kozlowski static int sec_pmic_resume(struct device *dev) 539f6d6daafSKrzysztof Kozlowski { 5401b5420e1SGeliang Tang struct i2c_client *i2c = to_i2c_client(dev); 541f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 542f6d6daafSKrzysztof Kozlowski 543360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 544f6d6daafSKrzysztof Kozlowski disable_irq_wake(sec_pmic->irq); 545f6d6daafSKrzysztof Kozlowski enable_irq(sec_pmic->irq); 546f6d6daafSKrzysztof Kozlowski 547f6d6daafSKrzysztof Kozlowski return 0; 548f6d6daafSKrzysztof Kozlowski } 5498321bbf8SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */ 550f6d6daafSKrzysztof Kozlowski 551f6d6daafSKrzysztof Kozlowski static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); 552f6d6daafSKrzysztof Kozlowski 55363063bfbSSangbeom Kim static const struct i2c_device_id sec_pmic_id[] = { 55463063bfbSSangbeom Kim { "sec_pmic", 0 }, 55566c9fbb9SSangbeom Kim { } 55666c9fbb9SSangbeom Kim }; 55763063bfbSSangbeom Kim MODULE_DEVICE_TABLE(i2c, sec_pmic_id); 55866c9fbb9SSangbeom Kim 55963063bfbSSangbeom Kim static struct i2c_driver sec_pmic_driver = { 56066c9fbb9SSangbeom Kim .driver = { 56163063bfbSSangbeom Kim .name = "sec_pmic", 562f6d6daafSKrzysztof Kozlowski .pm = &sec_pmic_pm_ops, 56326aec009SAmit Daniel Kachhap .of_match_table = of_match_ptr(sec_dt_match), 56466c9fbb9SSangbeom Kim }, 56563063bfbSSangbeom Kim .probe = sec_pmic_probe, 566d785334aSKrzysztof Kozlowski .shutdown = sec_pmic_shutdown, 56763063bfbSSangbeom Kim .id_table = sec_pmic_id, 56866c9fbb9SSangbeom Kim }; 56966c9fbb9SSangbeom Kim 57063063bfbSSangbeom Kim static int __init sec_pmic_init(void) 57166c9fbb9SSangbeom Kim { 57263063bfbSSangbeom Kim return i2c_add_driver(&sec_pmic_driver); 57366c9fbb9SSangbeom Kim } 57466c9fbb9SSangbeom Kim 57563063bfbSSangbeom Kim subsys_initcall(sec_pmic_init); 57666c9fbb9SSangbeom Kim 57763063bfbSSangbeom Kim static void __exit sec_pmic_exit(void) 57866c9fbb9SSangbeom Kim { 57963063bfbSSangbeom Kim i2c_del_driver(&sec_pmic_driver); 58066c9fbb9SSangbeom Kim } 58163063bfbSSangbeom Kim module_exit(sec_pmic_exit); 58266c9fbb9SSangbeom Kim 58366c9fbb9SSangbeom Kim MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 58466c9fbb9SSangbeom Kim MODULE_DESCRIPTION("Core support for the S5M MFD"); 58566c9fbb9SSangbeom Kim MODULE_LICENSE("GPL"); 586