166c9fbb9SSangbeom Kim /* 263063bfbSSangbeom Kim * sec-core.c 366c9fbb9SSangbeom Kim * 463063bfbSSangbeom Kim * Copyright (c) 2012 Samsung Electronics Co., Ltd 566c9fbb9SSangbeom Kim * http://www.samsung.com 666c9fbb9SSangbeom Kim * 766c9fbb9SSangbeom Kim * This program is free software; you can redistribute it and/or modify it 866c9fbb9SSangbeom Kim * under the terms of the GNU General Public License as published by the 966c9fbb9SSangbeom Kim * Free Software Foundation; either version 2 of the License, or (at your 1066c9fbb9SSangbeom Kim * option) any later version. 1166c9fbb9SSangbeom Kim * 1266c9fbb9SSangbeom Kim */ 1366c9fbb9SSangbeom Kim 1466c9fbb9SSangbeom Kim #include <linux/module.h> 1566c9fbb9SSangbeom Kim #include <linux/moduleparam.h> 1666c9fbb9SSangbeom Kim #include <linux/init.h> 1766c9fbb9SSangbeom Kim #include <linux/err.h> 1866c9fbb9SSangbeom Kim #include <linux/slab.h> 1966c9fbb9SSangbeom Kim #include <linux/i2c.h> 201c5a099bSSachin Kamat #include <linux/of.h> 2126aec009SAmit Daniel Kachhap #include <linux/of_irq.h> 2266c9fbb9SSangbeom Kim #include <linux/interrupt.h> 2366c9fbb9SSangbeom Kim #include <linux/pm_runtime.h> 2466c9fbb9SSangbeom Kim #include <linux/mutex.h> 2566c9fbb9SSangbeom Kim #include <linux/mfd/core.h> 2654227bcfSSangbeom Kim #include <linux/mfd/samsung/core.h> 2754227bcfSSangbeom Kim #include <linux/mfd/samsung/irq.h> 28ce24991eSSachin Kamat #include <linux/mfd/samsung/s2mpa01.h> 2925f311faSMark Brown #include <linux/mfd/samsung/s2mps11.h> 3076b9840bSChanwoo Choi #include <linux/mfd/samsung/s2mps13.h> 31dc691966SKrzysztof Kozlowski #include <linux/mfd/samsung/s2mps14.h> 3200e2573dSChanwoo Choi #include <linux/mfd/samsung/s2mpu02.h> 3325f311faSMark Brown #include <linux/mfd/samsung/s5m8763.h> 3425f311faSMark Brown #include <linux/mfd/samsung/s5m8767.h> 3566c9fbb9SSangbeom Kim #include <linux/regmap.h> 3666c9fbb9SSangbeom Kim 375ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8751_devs[] = { 3866c9fbb9SSangbeom Kim { 3966c9fbb9SSangbeom Kim .name = "s5m8751-pmic", 4066c9fbb9SSangbeom Kim }, { 4166c9fbb9SSangbeom Kim .name = "s5m-charger", 4266c9fbb9SSangbeom Kim }, { 4366c9fbb9SSangbeom Kim .name = "s5m8751-codec", 4466c9fbb9SSangbeom Kim }, 4566c9fbb9SSangbeom Kim }; 4666c9fbb9SSangbeom Kim 475ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8763_devs[] = { 4866c9fbb9SSangbeom Kim { 4966c9fbb9SSangbeom Kim .name = "s5m8763-pmic", 5066c9fbb9SSangbeom Kim }, { 5166c9fbb9SSangbeom Kim .name = "s5m-rtc", 5266c9fbb9SSangbeom Kim }, { 5366c9fbb9SSangbeom Kim .name = "s5m-charger", 5466c9fbb9SSangbeom Kim }, 5566c9fbb9SSangbeom Kim }; 5666c9fbb9SSangbeom Kim 575ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8767_devs[] = { 5866c9fbb9SSangbeom Kim { 5966c9fbb9SSangbeom Kim .name = "s5m8767-pmic", 6066c9fbb9SSangbeom Kim }, { 6166c9fbb9SSangbeom Kim .name = "s5m-rtc", 6239fed00fSTushar Behera }, { 6339fed00fSTushar Behera .name = "s5m8767-clk", 6453c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s5m8767-clk", 6539fed00fSTushar Behera } 6666c9fbb9SSangbeom Kim }; 6766c9fbb9SSangbeom Kim 685ac98553SGeert Uytterhoeven static const struct mfd_cell s2mps11_devs[] = { 699b6d1343SSangbeom Kim { 709b6d1343SSangbeom Kim .name = "s2mps11-pmic", 713134bcaeSYadwinder Singh Brar }, { 72eea2e596SKrzysztof Kozlowski .name = "s2mps14-rtc", 73eea2e596SKrzysztof Kozlowski }, { 743134bcaeSYadwinder Singh Brar .name = "s2mps11-clk", 7553c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps11-clk", 763134bcaeSYadwinder Singh Brar } 779b6d1343SSangbeom Kim }; 789b6d1343SSangbeom Kim 793bc2ee91SChanwoo Choi static const struct mfd_cell s2mps13_devs[] = { 803bc2ee91SChanwoo Choi { .name = "s2mps13-pmic", }, 813bc2ee91SChanwoo Choi { .name = "s2mps13-rtc", }, 823bc2ee91SChanwoo Choi { 833bc2ee91SChanwoo Choi .name = "s2mps13-clk", 843bc2ee91SChanwoo Choi .of_compatible = "samsung,s2mps13-clk", 853bc2ee91SChanwoo Choi }, 863bc2ee91SChanwoo Choi }; 873bc2ee91SChanwoo Choi 88dc691966SKrzysztof Kozlowski static const struct mfd_cell s2mps14_devs[] = { 89dc691966SKrzysztof Kozlowski { 90dc691966SKrzysztof Kozlowski .name = "s2mps14-pmic", 91dc691966SKrzysztof Kozlowski }, { 92dc691966SKrzysztof Kozlowski .name = "s2mps14-rtc", 93dc691966SKrzysztof Kozlowski }, { 94dc691966SKrzysztof Kozlowski .name = "s2mps14-clk", 9553c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps14-clk", 96dc691966SKrzysztof Kozlowski } 97dc691966SKrzysztof Kozlowski }; 98dc691966SKrzysztof Kozlowski 99ce24991eSSachin Kamat static const struct mfd_cell s2mpa01_devs[] = { 100ce24991eSSachin Kamat { 101ce24991eSSachin Kamat .name = "s2mpa01-pmic", 102ce24991eSSachin Kamat }, 103ce24991eSSachin Kamat }; 104ce24991eSSachin Kamat 10554e8827dSChanwoo Choi static const struct mfd_cell s2mpu02_devs[] = { 10654e8827dSChanwoo Choi { .name = "s2mpu02-pmic", }, 10754e8827dSChanwoo Choi { .name = "s2mpu02-rtc", }, 10854e8827dSChanwoo Choi { 10954e8827dSChanwoo Choi .name = "s2mpu02-clk", 11054e8827dSChanwoo Choi .of_compatible = "samsung,s2mpu02-clk", 11154e8827dSChanwoo Choi } 11254e8827dSChanwoo Choi }; 11354e8827dSChanwoo Choi 11426aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 115df20b7c5SKrzysztof Kozlowski static const struct of_device_id sec_dt_match[] = { 11626aec009SAmit Daniel Kachhap { .compatible = "samsung,s5m8767-pmic", 11726aec009SAmit Daniel Kachhap .data = (void *)S5M8767X, 118ce24991eSSachin Kamat }, { 119ce24991eSSachin Kamat .compatible = "samsung,s2mps11-pmic", 120aa32acadSYadwinder Singh Brar .data = (void *)S2MPS11X, 121ce24991eSSachin Kamat }, { 1223bc2ee91SChanwoo Choi .compatible = "samsung,s2mps13-pmic", 1233bc2ee91SChanwoo Choi .data = (void *)S2MPS13X, 1243bc2ee91SChanwoo Choi }, { 125ce24991eSSachin Kamat .compatible = "samsung,s2mps14-pmic", 126dc691966SKrzysztof Kozlowski .data = (void *)S2MPS14X, 127ce24991eSSachin Kamat }, { 128ce24991eSSachin Kamat .compatible = "samsung,s2mpa01-pmic", 129ce24991eSSachin Kamat .data = (void *)S2MPA01, 130ce24991eSSachin Kamat }, { 13154e8827dSChanwoo Choi .compatible = "samsung,s2mpu02-pmic", 13254e8827dSChanwoo Choi .data = (void *)S2MPU02, 13354e8827dSChanwoo Choi }, { 134ce24991eSSachin Kamat /* Sentinel */ 135dc691966SKrzysztof Kozlowski }, 13626aec009SAmit Daniel Kachhap }; 13726aec009SAmit Daniel Kachhap #endif 13826aec009SAmit Daniel Kachhap 139ce24991eSSachin Kamat static bool s2mpa01_volatile(struct device *dev, unsigned int reg) 140ce24991eSSachin Kamat { 141ce24991eSSachin Kamat switch (reg) { 142ce24991eSSachin Kamat case S2MPA01_REG_INT1M: 143ce24991eSSachin Kamat case S2MPA01_REG_INT2M: 144ce24991eSSachin Kamat case S2MPA01_REG_INT3M: 145ce24991eSSachin Kamat return false; 146ce24991eSSachin Kamat default: 147ce24991eSSachin Kamat return true; 148ce24991eSSachin Kamat } 149ce24991eSSachin Kamat } 150ce24991eSSachin Kamat 1516b845ba9SMark Brown static bool s2mps11_volatile(struct device *dev, unsigned int reg) 1526b845ba9SMark Brown { 1536b845ba9SMark Brown switch (reg) { 1546b845ba9SMark Brown case S2MPS11_REG_INT1M: 1556b845ba9SMark Brown case S2MPS11_REG_INT2M: 1566b845ba9SMark Brown case S2MPS11_REG_INT3M: 1576b845ba9SMark Brown return false; 1586b845ba9SMark Brown default: 1596b845ba9SMark Brown return true; 1606b845ba9SMark Brown } 1616b845ba9SMark Brown } 1626b845ba9SMark Brown 16300e2573dSChanwoo Choi static bool s2mpu02_volatile(struct device *dev, unsigned int reg) 16400e2573dSChanwoo Choi { 16500e2573dSChanwoo Choi switch (reg) { 16600e2573dSChanwoo Choi case S2MPU02_REG_INT1M: 16700e2573dSChanwoo Choi case S2MPU02_REG_INT2M: 16800e2573dSChanwoo Choi case S2MPU02_REG_INT3M: 16900e2573dSChanwoo Choi return false; 17000e2573dSChanwoo Choi default: 17100e2573dSChanwoo Choi return true; 17200e2573dSChanwoo Choi } 17300e2573dSChanwoo Choi } 17400e2573dSChanwoo Choi 1756b845ba9SMark Brown static bool s5m8763_volatile(struct device *dev, unsigned int reg) 1766b845ba9SMark Brown { 1776b845ba9SMark Brown switch (reg) { 1786b845ba9SMark Brown case S5M8763_REG_IRQM1: 1796b845ba9SMark Brown case S5M8763_REG_IRQM2: 1806b845ba9SMark Brown case S5M8763_REG_IRQM3: 1816b845ba9SMark Brown case S5M8763_REG_IRQM4: 1826b845ba9SMark Brown return false; 1836b845ba9SMark Brown default: 1846b845ba9SMark Brown return true; 1856b845ba9SMark Brown } 1866b845ba9SMark Brown } 1876b845ba9SMark Brown 188a30fffb0SKrzysztof Kozlowski static const struct regmap_config sec_regmap_config = { 18966c9fbb9SSangbeom Kim .reg_bits = 8, 19066c9fbb9SSangbeom Kim .val_bits = 8, 19166c9fbb9SSangbeom Kim }; 19266c9fbb9SSangbeom Kim 193ce24991eSSachin Kamat static const struct regmap_config s2mpa01_regmap_config = { 194ce24991eSSachin Kamat .reg_bits = 8, 195ce24991eSSachin Kamat .val_bits = 8, 196ce24991eSSachin Kamat 197ce24991eSSachin Kamat .max_register = S2MPA01_REG_LDO_OVCB4, 198ce24991eSSachin Kamat .volatile_reg = s2mpa01_volatile, 199ce24991eSSachin Kamat .cache_type = REGCACHE_FLAT, 200ce24991eSSachin Kamat }; 201ce24991eSSachin Kamat 202a30fffb0SKrzysztof Kozlowski static const struct regmap_config s2mps11_regmap_config = { 20325f311faSMark Brown .reg_bits = 8, 20425f311faSMark Brown .val_bits = 8, 20525f311faSMark Brown 20625f311faSMark Brown .max_register = S2MPS11_REG_L38CTRL, 2076b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2086b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 20925f311faSMark Brown }; 21025f311faSMark Brown 21176b9840bSChanwoo Choi static const struct regmap_config s2mps13_regmap_config = { 21276b9840bSChanwoo Choi .reg_bits = 8, 21376b9840bSChanwoo Choi .val_bits = 8, 21476b9840bSChanwoo Choi 21576b9840bSChanwoo Choi .max_register = S2MPS13_REG_LDODSCH5, 21676b9840bSChanwoo Choi .volatile_reg = s2mps11_volatile, 21776b9840bSChanwoo Choi .cache_type = REGCACHE_FLAT, 21876b9840bSChanwoo Choi }; 21976b9840bSChanwoo Choi 220dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_regmap_config = { 221dc691966SKrzysztof Kozlowski .reg_bits = 8, 222dc691966SKrzysztof Kozlowski .val_bits = 8, 223dc691966SKrzysztof Kozlowski 224dc691966SKrzysztof Kozlowski .max_register = S2MPS14_REG_LDODSCH3, 225dc691966SKrzysztof Kozlowski .volatile_reg = s2mps11_volatile, 226dc691966SKrzysztof Kozlowski .cache_type = REGCACHE_FLAT, 227dc691966SKrzysztof Kozlowski }; 228dc691966SKrzysztof Kozlowski 22900e2573dSChanwoo Choi static const struct regmap_config s2mpu02_regmap_config = { 23000e2573dSChanwoo Choi .reg_bits = 8, 23100e2573dSChanwoo Choi .val_bits = 8, 23200e2573dSChanwoo Choi 23300e2573dSChanwoo Choi .max_register = S2MPU02_REG_DVSDATA, 23400e2573dSChanwoo Choi .volatile_reg = s2mpu02_volatile, 23500e2573dSChanwoo Choi .cache_type = REGCACHE_FLAT, 23600e2573dSChanwoo Choi }; 23700e2573dSChanwoo Choi 238a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = { 23925f311faSMark Brown .reg_bits = 8, 24025f311faSMark Brown .val_bits = 8, 24125f311faSMark Brown 24225f311faSMark Brown .max_register = S5M8763_REG_LBCNFG2, 2436b845ba9SMark Brown .volatile_reg = s5m8763_volatile, 2446b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 24525f311faSMark Brown }; 24625f311faSMark Brown 247a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = { 24825f311faSMark Brown .reg_bits = 8, 24925f311faSMark Brown .val_bits = 8, 25025f311faSMark Brown 25125f311faSMark Brown .max_register = S5M8767_REG_LDO28CTRL, 2526b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2536b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 25425f311faSMark Brown }; 25526aec009SAmit Daniel Kachhap 256c2c9f1feSKrzysztof Kozlowski static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) 257c2c9f1feSKrzysztof Kozlowski { 258c2c9f1feSKrzysztof Kozlowski unsigned int val; 259c2c9f1feSKrzysztof Kozlowski 260c2c9f1feSKrzysztof Kozlowski /* For each device type, the REG_ID is always the first register */ 261c2c9f1feSKrzysztof Kozlowski if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) 262c2c9f1feSKrzysztof Kozlowski dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); 263c2c9f1feSKrzysztof Kozlowski } 264c2c9f1feSKrzysztof Kozlowski 2658a97d428SKrzysztof Kozlowski static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) 2668a97d428SKrzysztof Kozlowski { 2678a97d428SKrzysztof Kozlowski int err; 2688a97d428SKrzysztof Kozlowski 2698a97d428SKrzysztof Kozlowski if (sec_pmic->device_type != S2MPS13X) 2708a97d428SKrzysztof Kozlowski return; 2718a97d428SKrzysztof Kozlowski 2728a97d428SKrzysztof Kozlowski if (sec_pmic->pdata->disable_wrstbi) { 2738a97d428SKrzysztof Kozlowski /* 2748a97d428SKrzysztof Kozlowski * If WRSTBI pin is pulled down this feature must be disabled 2758a97d428SKrzysztof Kozlowski * because each Suspend to RAM will trigger buck voltage reset 2768a97d428SKrzysztof Kozlowski * to default values. 2778a97d428SKrzysztof Kozlowski */ 2788a97d428SKrzysztof Kozlowski err = regmap_update_bits(sec_pmic->regmap_pmic, 2798a97d428SKrzysztof Kozlowski S2MPS13_REG_WRSTBI, 2808a97d428SKrzysztof Kozlowski S2MPS13_REG_WRSTBI_MASK, 0x0); 2818a97d428SKrzysztof Kozlowski if (err) 2828a97d428SKrzysztof Kozlowski dev_warn(sec_pmic->dev, 2838a97d428SKrzysztof Kozlowski "Cannot initialize WRSTBI config: %d\n", 2848a97d428SKrzysztof Kozlowski err); 2858a97d428SKrzysztof Kozlowski } 2868a97d428SKrzysztof Kozlowski } 2878a97d428SKrzysztof Kozlowski 28826aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 28926aec009SAmit Daniel Kachhap /* 29026aec009SAmit Daniel Kachhap * Only the common platform data elements for s5m8767 are parsed here from the 29126aec009SAmit Daniel Kachhap * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 29226aec009SAmit Daniel Kachhap * others have to parse their own platform data elements from device tree. 29326aec009SAmit Daniel Kachhap * 29426aec009SAmit Daniel Kachhap * The s5m8767 platform data structure is instantiated here and the drivers for 29526aec009SAmit Daniel Kachhap * the sub-modules need not instantiate another instance while parsing their 29626aec009SAmit Daniel Kachhap * platform data. 29726aec009SAmit Daniel Kachhap */ 29826aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 29926aec009SAmit Daniel Kachhap struct device *dev) 30026aec009SAmit Daniel Kachhap { 30126aec009SAmit Daniel Kachhap struct sec_platform_data *pd; 30226aec009SAmit Daniel Kachhap 30326aec009SAmit Daniel Kachhap pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 30482a00c49SKrzysztof Kozlowski if (!pd) 30526aec009SAmit Daniel Kachhap return ERR_PTR(-ENOMEM); 30626aec009SAmit Daniel Kachhap 30726aec009SAmit Daniel Kachhap /* 30826aec009SAmit Daniel Kachhap * ToDo: the 'wakeup' member in the platform data is more of a linux 30926aec009SAmit Daniel Kachhap * specfic information. Hence, there is no binding for that yet and 31026aec009SAmit Daniel Kachhap * not parsed here. 31126aec009SAmit Daniel Kachhap */ 31226aec009SAmit Daniel Kachhap 313d785334aSKrzysztof Kozlowski pd->manual_poweroff = of_property_read_bool(dev->of_node, 314d785334aSKrzysztof Kozlowski "samsung,s2mps11-acokb-ground"); 3158a97d428SKrzysztof Kozlowski pd->disable_wrstbi = of_property_read_bool(dev->of_node, 3168a97d428SKrzysztof Kozlowski "samsung,s2mps11-wrstbi-ground"); 31726aec009SAmit Daniel Kachhap return pd; 31826aec009SAmit Daniel Kachhap } 31926aec009SAmit Daniel Kachhap #else 320197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 32126aec009SAmit Daniel Kachhap struct device *dev) 32226aec009SAmit Daniel Kachhap { 323005718c0SWei Yongjun return NULL; 32426aec009SAmit Daniel Kachhap } 32526aec009SAmit Daniel Kachhap #endif 32626aec009SAmit Daniel Kachhap 3278f695de5SPankaj Dubey static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, 32826aec009SAmit Daniel Kachhap const struct i2c_device_id *id) 32926aec009SAmit Daniel Kachhap { 33026aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 33126aec009SAmit Daniel Kachhap if (i2c->dev.of_node) { 33226aec009SAmit Daniel Kachhap const struct of_device_id *match; 333b6c1cb4dSLee Jones 33426aec009SAmit Daniel Kachhap match = of_match_node(sec_dt_match, i2c->dev.of_node); 3358f695de5SPankaj Dubey return (unsigned long)match->data; 33626aec009SAmit Daniel Kachhap } 33726aec009SAmit Daniel Kachhap #endif 3388f695de5SPankaj Dubey return id->driver_data; 33926aec009SAmit Daniel Kachhap } 34026aec009SAmit Daniel Kachhap 34163063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c, 34266c9fbb9SSangbeom Kim const struct i2c_device_id *id) 34366c9fbb9SSangbeom Kim { 344334a41ceSJingoo Han struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); 345e349c910SKrzysztof Kozlowski const struct regmap_config *regmap; 34654e8827dSChanwoo Choi const struct mfd_cell *sec_devs; 34763063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic; 3489549b5ffSKrzysztof Kozlowski unsigned long device_type; 34954e8827dSChanwoo Choi int ret, num_sec_devs; 35066c9fbb9SSangbeom Kim 35163063bfbSSangbeom Kim sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), 35266c9fbb9SSangbeom Kim GFP_KERNEL); 35363063bfbSSangbeom Kim if (sec_pmic == NULL) 35466c9fbb9SSangbeom Kim return -ENOMEM; 35566c9fbb9SSangbeom Kim 35663063bfbSSangbeom Kim i2c_set_clientdata(i2c, sec_pmic); 35763063bfbSSangbeom Kim sec_pmic->dev = &i2c->dev; 35863063bfbSSangbeom Kim sec_pmic->i2c = i2c; 35963063bfbSSangbeom Kim sec_pmic->irq = i2c->irq; 3609549b5ffSKrzysztof Kozlowski device_type = sec_i2c_get_driver_data(i2c, id); 36166c9fbb9SSangbeom Kim 36226aec009SAmit Daniel Kachhap if (sec_pmic->dev->of_node) { 36326aec009SAmit Daniel Kachhap pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); 36426aec009SAmit Daniel Kachhap if (IS_ERR(pdata)) { 36526aec009SAmit Daniel Kachhap ret = PTR_ERR(pdata); 36626aec009SAmit Daniel Kachhap return ret; 36726aec009SAmit Daniel Kachhap } 3689549b5ffSKrzysztof Kozlowski pdata->device_type = device_type; 36926aec009SAmit Daniel Kachhap } 37066c9fbb9SSangbeom Kim if (pdata) { 37163063bfbSSangbeom Kim sec_pmic->device_type = pdata->device_type; 37263063bfbSSangbeom Kim sec_pmic->irq_base = pdata->irq_base; 37363063bfbSSangbeom Kim sec_pmic->wakeup = pdata->wakeup; 37426aec009SAmit Daniel Kachhap sec_pmic->pdata = pdata; 37566c9fbb9SSangbeom Kim } 37666c9fbb9SSangbeom Kim 37725f311faSMark Brown switch (sec_pmic->device_type) { 378ce24991eSSachin Kamat case S2MPA01: 379ce24991eSSachin Kamat regmap = &s2mpa01_regmap_config; 380ce24991eSSachin Kamat break; 38125f311faSMark Brown case S2MPS11X: 38225f311faSMark Brown regmap = &s2mps11_regmap_config; 383dc691966SKrzysztof Kozlowski break; 38476b9840bSChanwoo Choi case S2MPS13X: 38576b9840bSChanwoo Choi regmap = &s2mps13_regmap_config; 38676b9840bSChanwoo Choi break; 387dc691966SKrzysztof Kozlowski case S2MPS14X: 388dc691966SKrzysztof Kozlowski regmap = &s2mps14_regmap_config; 38925f311faSMark Brown break; 39025f311faSMark Brown case S5M8763X: 39125f311faSMark Brown regmap = &s5m8763_regmap_config; 39225f311faSMark Brown break; 39325f311faSMark Brown case S5M8767X: 39425f311faSMark Brown regmap = &s5m8767_regmap_config; 39525f311faSMark Brown break; 39600e2573dSChanwoo Choi case S2MPU02: 39700e2573dSChanwoo Choi regmap = &s2mpu02_regmap_config; 39800e2573dSChanwoo Choi break; 39925f311faSMark Brown default: 40025f311faSMark Brown regmap = &sec_regmap_config; 40125f311faSMark Brown break; 40225f311faSMark Brown } 40325f311faSMark Brown 4043e1e4a5fSKrzysztof Kozlowski sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); 4053e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_pmic)) { 4063e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_pmic); 40766c9fbb9SSangbeom Kim dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 40866c9fbb9SSangbeom Kim ret); 40966c9fbb9SSangbeom Kim return ret; 41066c9fbb9SSangbeom Kim } 41166c9fbb9SSangbeom Kim 41266c9fbb9SSangbeom Kim if (pdata && pdata->cfg_pmic_irq) 41366c9fbb9SSangbeom Kim pdata->cfg_pmic_irq(); 41466c9fbb9SSangbeom Kim 41563063bfbSSangbeom Kim sec_irq_init(sec_pmic); 41666c9fbb9SSangbeom Kim 41763063bfbSSangbeom Kim pm_runtime_set_active(sec_pmic->dev); 41866c9fbb9SSangbeom Kim 41963063bfbSSangbeom Kim switch (sec_pmic->device_type) { 42066c9fbb9SSangbeom Kim case S5M8751X: 42154e8827dSChanwoo Choi sec_devs = s5m8751_devs; 42254e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8751_devs); 42366c9fbb9SSangbeom Kim break; 42466c9fbb9SSangbeom Kim case S5M8763X: 42554e8827dSChanwoo Choi sec_devs = s5m8763_devs; 42654e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8763_devs); 42766c9fbb9SSangbeom Kim break; 42866c9fbb9SSangbeom Kim case S5M8767X: 42954e8827dSChanwoo Choi sec_devs = s5m8767_devs; 43054e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8767_devs); 43166c9fbb9SSangbeom Kim break; 432ce24991eSSachin Kamat case S2MPA01: 43354e8827dSChanwoo Choi sec_devs = s2mpa01_devs; 43454e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpa01_devs); 435ce24991eSSachin Kamat break; 4369b6d1343SSangbeom Kim case S2MPS11X: 43754e8827dSChanwoo Choi sec_devs = s2mps11_devs; 43854e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps11_devs); 4399b6d1343SSangbeom Kim break; 4403bc2ee91SChanwoo Choi case S2MPS13X: 4413bc2ee91SChanwoo Choi sec_devs = s2mps13_devs; 4423bc2ee91SChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps13_devs); 4433bc2ee91SChanwoo Choi break; 444dc691966SKrzysztof Kozlowski case S2MPS14X: 44554e8827dSChanwoo Choi sec_devs = s2mps14_devs; 44654e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps14_devs); 44754e8827dSChanwoo Choi break; 44854e8827dSChanwoo Choi case S2MPU02: 44954e8827dSChanwoo Choi sec_devs = s2mpu02_devs; 45054e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpu02_devs); 451dc691966SKrzysztof Kozlowski break; 45266c9fbb9SSangbeom Kim default: 45366c9fbb9SSangbeom Kim /* If this happens the probe function is problem */ 45466c9fbb9SSangbeom Kim BUG(); 45566c9fbb9SSangbeom Kim } 45654e8827dSChanwoo Choi ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL, 45754e8827dSChanwoo Choi 0, NULL); 45815447a46SLeon Romanovsky if (ret) 4598c66eeceSKrzysztof Kozlowski goto err_mfd; 46066c9fbb9SSangbeom Kim 461f6d6daafSKrzysztof Kozlowski device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); 4628a97d428SKrzysztof Kozlowski sec_pmic_configure(sec_pmic); 463c2c9f1feSKrzysztof Kozlowski sec_pmic_dump_rev(sec_pmic); 464f6d6daafSKrzysztof Kozlowski 46566c9fbb9SSangbeom Kim return ret; 46666c9fbb9SSangbeom Kim 4678c66eeceSKrzysztof Kozlowski err_mfd: 46863063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 46966c9fbb9SSangbeom Kim return ret; 47066c9fbb9SSangbeom Kim } 47166c9fbb9SSangbeom Kim 47263063bfbSSangbeom Kim static int sec_pmic_remove(struct i2c_client *i2c) 47366c9fbb9SSangbeom Kim { 47463063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 47566c9fbb9SSangbeom Kim 47663063bfbSSangbeom Kim mfd_remove_devices(sec_pmic->dev); 47763063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 47866c9fbb9SSangbeom Kim return 0; 47966c9fbb9SSangbeom Kim } 48066c9fbb9SSangbeom Kim 481d785334aSKrzysztof Kozlowski static void sec_pmic_shutdown(struct i2c_client *i2c) 482d785334aSKrzysztof Kozlowski { 483d785334aSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 484d785334aSKrzysztof Kozlowski unsigned int reg, mask; 485d785334aSKrzysztof Kozlowski 486d785334aSKrzysztof Kozlowski if (!sec_pmic->pdata->manual_poweroff) 487d785334aSKrzysztof Kozlowski return; 488d785334aSKrzysztof Kozlowski 489d785334aSKrzysztof Kozlowski switch (sec_pmic->device_type) { 490d785334aSKrzysztof Kozlowski case S2MPS11X: 491d785334aSKrzysztof Kozlowski reg = S2MPS11_REG_CTRL1; 492d785334aSKrzysztof Kozlowski mask = S2MPS11_CTRL1_PWRHOLD_MASK; 493d785334aSKrzysztof Kozlowski break; 494d785334aSKrzysztof Kozlowski default: 495d785334aSKrzysztof Kozlowski /* 496d785334aSKrzysztof Kozlowski * Currently only one board with S2MPS11 needs this, so just 497d785334aSKrzysztof Kozlowski * ignore the rest. 498d785334aSKrzysztof Kozlowski */ 499d785334aSKrzysztof Kozlowski dev_warn(sec_pmic->dev, 500d785334aSKrzysztof Kozlowski "Unsupported device %lu for manual power off\n", 501d785334aSKrzysztof Kozlowski sec_pmic->device_type); 502d785334aSKrzysztof Kozlowski return; 503d785334aSKrzysztof Kozlowski } 504d785334aSKrzysztof Kozlowski 505d785334aSKrzysztof Kozlowski regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); 506d785334aSKrzysztof Kozlowski } 507d785334aSKrzysztof Kozlowski 5088321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 509f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev) 510f6d6daafSKrzysztof Kozlowski { 511f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 512f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 513f6d6daafSKrzysztof Kozlowski 514360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 515f6d6daafSKrzysztof Kozlowski enable_irq_wake(sec_pmic->irq); 516f6d6daafSKrzysztof Kozlowski /* 517f6d6daafSKrzysztof Kozlowski * PMIC IRQ must be disabled during suspend for RTC alarm 518f6d6daafSKrzysztof Kozlowski * to work properly. 519360d15d6SKrzysztof Kozlowski * When device is woken up from suspend, an 520f6d6daafSKrzysztof Kozlowski * interrupt occurs before resuming I2C bus controller. 521f6d6daafSKrzysztof Kozlowski * The interrupt is handled by regmap_irq_thread which tries 522f6d6daafSKrzysztof Kozlowski * to read RTC registers. This read fails (I2C is still 523f6d6daafSKrzysztof Kozlowski * suspended) and RTC Alarm interrupt is disabled. 524f6d6daafSKrzysztof Kozlowski */ 525f6d6daafSKrzysztof Kozlowski disable_irq(sec_pmic->irq); 526f6d6daafSKrzysztof Kozlowski 527f6d6daafSKrzysztof Kozlowski return 0; 528f6d6daafSKrzysztof Kozlowski } 529f6d6daafSKrzysztof Kozlowski 530f6d6daafSKrzysztof Kozlowski static int sec_pmic_resume(struct device *dev) 531f6d6daafSKrzysztof Kozlowski { 532f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 533f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 534f6d6daafSKrzysztof Kozlowski 535360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 536f6d6daafSKrzysztof Kozlowski disable_irq_wake(sec_pmic->irq); 537f6d6daafSKrzysztof Kozlowski enable_irq(sec_pmic->irq); 538f6d6daafSKrzysztof Kozlowski 539f6d6daafSKrzysztof Kozlowski return 0; 540f6d6daafSKrzysztof Kozlowski } 5418321bbf8SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */ 542f6d6daafSKrzysztof Kozlowski 543f6d6daafSKrzysztof Kozlowski static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); 544f6d6daafSKrzysztof Kozlowski 54563063bfbSSangbeom Kim static const struct i2c_device_id sec_pmic_id[] = { 54663063bfbSSangbeom Kim { "sec_pmic", 0 }, 54766c9fbb9SSangbeom Kim { } 54866c9fbb9SSangbeom Kim }; 54963063bfbSSangbeom Kim MODULE_DEVICE_TABLE(i2c, sec_pmic_id); 55066c9fbb9SSangbeom Kim 55163063bfbSSangbeom Kim static struct i2c_driver sec_pmic_driver = { 55266c9fbb9SSangbeom Kim .driver = { 55363063bfbSSangbeom Kim .name = "sec_pmic", 554f6d6daafSKrzysztof Kozlowski .pm = &sec_pmic_pm_ops, 55526aec009SAmit Daniel Kachhap .of_match_table = of_match_ptr(sec_dt_match), 55666c9fbb9SSangbeom Kim }, 55763063bfbSSangbeom Kim .probe = sec_pmic_probe, 55863063bfbSSangbeom Kim .remove = sec_pmic_remove, 559d785334aSKrzysztof Kozlowski .shutdown = sec_pmic_shutdown, 56063063bfbSSangbeom Kim .id_table = sec_pmic_id, 56166c9fbb9SSangbeom Kim }; 56266c9fbb9SSangbeom Kim 56363063bfbSSangbeom Kim static int __init sec_pmic_init(void) 56466c9fbb9SSangbeom Kim { 56563063bfbSSangbeom Kim return i2c_add_driver(&sec_pmic_driver); 56666c9fbb9SSangbeom Kim } 56766c9fbb9SSangbeom Kim 56863063bfbSSangbeom Kim subsys_initcall(sec_pmic_init); 56966c9fbb9SSangbeom Kim 57063063bfbSSangbeom Kim static void __exit sec_pmic_exit(void) 57166c9fbb9SSangbeom Kim { 57263063bfbSSangbeom Kim i2c_del_driver(&sec_pmic_driver); 57366c9fbb9SSangbeom Kim } 57463063bfbSSangbeom Kim module_exit(sec_pmic_exit); 57566c9fbb9SSangbeom Kim 57666c9fbb9SSangbeom Kim MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 57766c9fbb9SSangbeom Kim MODULE_DESCRIPTION("Core support for the S5M MFD"); 57866c9fbb9SSangbeom Kim MODULE_LICENSE("GPL"); 579