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 }, { 723134bcaeSYadwinder Singh Brar .name = "s2mps11-clk", 7353c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps11-clk", 743134bcaeSYadwinder Singh Brar } 759b6d1343SSangbeom Kim }; 769b6d1343SSangbeom Kim 773bc2ee91SChanwoo Choi static const struct mfd_cell s2mps13_devs[] = { 783bc2ee91SChanwoo Choi { .name = "s2mps13-pmic", }, 793bc2ee91SChanwoo Choi { .name = "s2mps13-rtc", }, 803bc2ee91SChanwoo Choi { 813bc2ee91SChanwoo Choi .name = "s2mps13-clk", 823bc2ee91SChanwoo Choi .of_compatible = "samsung,s2mps13-clk", 833bc2ee91SChanwoo Choi }, 843bc2ee91SChanwoo Choi }; 853bc2ee91SChanwoo Choi 86dc691966SKrzysztof Kozlowski static const struct mfd_cell s2mps14_devs[] = { 87dc691966SKrzysztof Kozlowski { 88dc691966SKrzysztof Kozlowski .name = "s2mps14-pmic", 89dc691966SKrzysztof Kozlowski }, { 90dc691966SKrzysztof Kozlowski .name = "s2mps14-rtc", 91dc691966SKrzysztof Kozlowski }, { 92dc691966SKrzysztof Kozlowski .name = "s2mps14-clk", 9353c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps14-clk", 94dc691966SKrzysztof Kozlowski } 95dc691966SKrzysztof Kozlowski }; 96dc691966SKrzysztof Kozlowski 97ce24991eSSachin Kamat static const struct mfd_cell s2mpa01_devs[] = { 98ce24991eSSachin Kamat { 99ce24991eSSachin Kamat .name = "s2mpa01-pmic", 100ce24991eSSachin Kamat }, 101ce24991eSSachin Kamat }; 102ce24991eSSachin Kamat 10354e8827dSChanwoo Choi static const struct mfd_cell s2mpu02_devs[] = { 10454e8827dSChanwoo Choi { .name = "s2mpu02-pmic", }, 10554e8827dSChanwoo Choi { .name = "s2mpu02-rtc", }, 10654e8827dSChanwoo Choi { 10754e8827dSChanwoo Choi .name = "s2mpu02-clk", 10854e8827dSChanwoo Choi .of_compatible = "samsung,s2mpu02-clk", 10954e8827dSChanwoo Choi } 11054e8827dSChanwoo Choi }; 11154e8827dSChanwoo Choi 11226aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 113df20b7c5SKrzysztof Kozlowski static const struct of_device_id sec_dt_match[] = { 11426aec009SAmit Daniel Kachhap { .compatible = "samsung,s5m8767-pmic", 11526aec009SAmit Daniel Kachhap .data = (void *)S5M8767X, 116ce24991eSSachin Kamat }, { 117ce24991eSSachin Kamat .compatible = "samsung,s2mps11-pmic", 118aa32acadSYadwinder Singh Brar .data = (void *)S2MPS11X, 119ce24991eSSachin Kamat }, { 1203bc2ee91SChanwoo Choi .compatible = "samsung,s2mps13-pmic", 1213bc2ee91SChanwoo Choi .data = (void *)S2MPS13X, 1223bc2ee91SChanwoo Choi }, { 123ce24991eSSachin Kamat .compatible = "samsung,s2mps14-pmic", 124dc691966SKrzysztof Kozlowski .data = (void *)S2MPS14X, 125ce24991eSSachin Kamat }, { 126ce24991eSSachin Kamat .compatible = "samsung,s2mpa01-pmic", 127ce24991eSSachin Kamat .data = (void *)S2MPA01, 128ce24991eSSachin Kamat }, { 12954e8827dSChanwoo Choi .compatible = "samsung,s2mpu02-pmic", 13054e8827dSChanwoo Choi .data = (void *)S2MPU02, 13154e8827dSChanwoo Choi }, { 132ce24991eSSachin Kamat /* Sentinel */ 133dc691966SKrzysztof Kozlowski }, 13426aec009SAmit Daniel Kachhap }; 13526aec009SAmit Daniel Kachhap #endif 13626aec009SAmit Daniel Kachhap 137ce24991eSSachin Kamat static bool s2mpa01_volatile(struct device *dev, unsigned int reg) 138ce24991eSSachin Kamat { 139ce24991eSSachin Kamat switch (reg) { 140ce24991eSSachin Kamat case S2MPA01_REG_INT1M: 141ce24991eSSachin Kamat case S2MPA01_REG_INT2M: 142ce24991eSSachin Kamat case S2MPA01_REG_INT3M: 143ce24991eSSachin Kamat return false; 144ce24991eSSachin Kamat default: 145ce24991eSSachin Kamat return true; 146ce24991eSSachin Kamat } 147ce24991eSSachin Kamat } 148ce24991eSSachin Kamat 1496b845ba9SMark Brown static bool s2mps11_volatile(struct device *dev, unsigned int reg) 1506b845ba9SMark Brown { 1516b845ba9SMark Brown switch (reg) { 1526b845ba9SMark Brown case S2MPS11_REG_INT1M: 1536b845ba9SMark Brown case S2MPS11_REG_INT2M: 1546b845ba9SMark Brown case S2MPS11_REG_INT3M: 1556b845ba9SMark Brown return false; 1566b845ba9SMark Brown default: 1576b845ba9SMark Brown return true; 1586b845ba9SMark Brown } 1596b845ba9SMark Brown } 1606b845ba9SMark Brown 16100e2573dSChanwoo Choi static bool s2mpu02_volatile(struct device *dev, unsigned int reg) 16200e2573dSChanwoo Choi { 16300e2573dSChanwoo Choi switch (reg) { 16400e2573dSChanwoo Choi case S2MPU02_REG_INT1M: 16500e2573dSChanwoo Choi case S2MPU02_REG_INT2M: 16600e2573dSChanwoo Choi case S2MPU02_REG_INT3M: 16700e2573dSChanwoo Choi return false; 16800e2573dSChanwoo Choi default: 16900e2573dSChanwoo Choi return true; 17000e2573dSChanwoo Choi } 17100e2573dSChanwoo Choi } 17200e2573dSChanwoo Choi 1736b845ba9SMark Brown static bool s5m8763_volatile(struct device *dev, unsigned int reg) 1746b845ba9SMark Brown { 1756b845ba9SMark Brown switch (reg) { 1766b845ba9SMark Brown case S5M8763_REG_IRQM1: 1776b845ba9SMark Brown case S5M8763_REG_IRQM2: 1786b845ba9SMark Brown case S5M8763_REG_IRQM3: 1796b845ba9SMark Brown case S5M8763_REG_IRQM4: 1806b845ba9SMark Brown return false; 1816b845ba9SMark Brown default: 1826b845ba9SMark Brown return true; 1836b845ba9SMark Brown } 1846b845ba9SMark Brown } 1856b845ba9SMark Brown 186a30fffb0SKrzysztof Kozlowski static const struct regmap_config sec_regmap_config = { 18766c9fbb9SSangbeom Kim .reg_bits = 8, 18866c9fbb9SSangbeom Kim .val_bits = 8, 18966c9fbb9SSangbeom Kim }; 19066c9fbb9SSangbeom Kim 191ce24991eSSachin Kamat static const struct regmap_config s2mpa01_regmap_config = { 192ce24991eSSachin Kamat .reg_bits = 8, 193ce24991eSSachin Kamat .val_bits = 8, 194ce24991eSSachin Kamat 195ce24991eSSachin Kamat .max_register = S2MPA01_REG_LDO_OVCB4, 196ce24991eSSachin Kamat .volatile_reg = s2mpa01_volatile, 197ce24991eSSachin Kamat .cache_type = REGCACHE_FLAT, 198ce24991eSSachin Kamat }; 199ce24991eSSachin Kamat 200a30fffb0SKrzysztof Kozlowski static const struct regmap_config s2mps11_regmap_config = { 20125f311faSMark Brown .reg_bits = 8, 20225f311faSMark Brown .val_bits = 8, 20325f311faSMark Brown 20425f311faSMark Brown .max_register = S2MPS11_REG_L38CTRL, 2056b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2066b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 20725f311faSMark Brown }; 20825f311faSMark Brown 20976b9840bSChanwoo Choi static const struct regmap_config s2mps13_regmap_config = { 21076b9840bSChanwoo Choi .reg_bits = 8, 21176b9840bSChanwoo Choi .val_bits = 8, 21276b9840bSChanwoo Choi 21376b9840bSChanwoo Choi .max_register = S2MPS13_REG_LDODSCH5, 21476b9840bSChanwoo Choi .volatile_reg = s2mps11_volatile, 21576b9840bSChanwoo Choi .cache_type = REGCACHE_FLAT, 21676b9840bSChanwoo Choi }; 21776b9840bSChanwoo Choi 218dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_regmap_config = { 219dc691966SKrzysztof Kozlowski .reg_bits = 8, 220dc691966SKrzysztof Kozlowski .val_bits = 8, 221dc691966SKrzysztof Kozlowski 222dc691966SKrzysztof Kozlowski .max_register = S2MPS14_REG_LDODSCH3, 223dc691966SKrzysztof Kozlowski .volatile_reg = s2mps11_volatile, 224dc691966SKrzysztof Kozlowski .cache_type = REGCACHE_FLAT, 225dc691966SKrzysztof Kozlowski }; 226dc691966SKrzysztof Kozlowski 22700e2573dSChanwoo Choi static const struct regmap_config s2mpu02_regmap_config = { 22800e2573dSChanwoo Choi .reg_bits = 8, 22900e2573dSChanwoo Choi .val_bits = 8, 23000e2573dSChanwoo Choi 23100e2573dSChanwoo Choi .max_register = S2MPU02_REG_DVSDATA, 23200e2573dSChanwoo Choi .volatile_reg = s2mpu02_volatile, 23300e2573dSChanwoo Choi .cache_type = REGCACHE_FLAT, 23400e2573dSChanwoo Choi }; 23500e2573dSChanwoo Choi 236a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = { 23725f311faSMark Brown .reg_bits = 8, 23825f311faSMark Brown .val_bits = 8, 23925f311faSMark Brown 24025f311faSMark Brown .max_register = S5M8763_REG_LBCNFG2, 2416b845ba9SMark Brown .volatile_reg = s5m8763_volatile, 2426b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 24325f311faSMark Brown }; 24425f311faSMark Brown 245a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = { 24625f311faSMark Brown .reg_bits = 8, 24725f311faSMark Brown .val_bits = 8, 24825f311faSMark Brown 24925f311faSMark Brown .max_register = S5M8767_REG_LDO28CTRL, 2506b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2516b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 25225f311faSMark Brown }; 25326aec009SAmit Daniel Kachhap 25426aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 25526aec009SAmit Daniel Kachhap /* 25626aec009SAmit Daniel Kachhap * Only the common platform data elements for s5m8767 are parsed here from the 25726aec009SAmit Daniel Kachhap * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 25826aec009SAmit Daniel Kachhap * others have to parse their own platform data elements from device tree. 25926aec009SAmit Daniel Kachhap * 26026aec009SAmit Daniel Kachhap * The s5m8767 platform data structure is instantiated here and the drivers for 26126aec009SAmit Daniel Kachhap * the sub-modules need not instantiate another instance while parsing their 26226aec009SAmit Daniel Kachhap * platform data. 26326aec009SAmit Daniel Kachhap */ 26426aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 26526aec009SAmit Daniel Kachhap struct device *dev) 26626aec009SAmit Daniel Kachhap { 26726aec009SAmit Daniel Kachhap struct sec_platform_data *pd; 26826aec009SAmit Daniel Kachhap 26926aec009SAmit Daniel Kachhap pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 27082a00c49SKrzysztof Kozlowski if (!pd) 27126aec009SAmit Daniel Kachhap return ERR_PTR(-ENOMEM); 27226aec009SAmit Daniel Kachhap 27326aec009SAmit Daniel Kachhap /* 27426aec009SAmit Daniel Kachhap * ToDo: the 'wakeup' member in the platform data is more of a linux 27526aec009SAmit Daniel Kachhap * specfic information. Hence, there is no binding for that yet and 27626aec009SAmit Daniel Kachhap * not parsed here. 27726aec009SAmit Daniel Kachhap */ 27826aec009SAmit Daniel Kachhap 27926aec009SAmit Daniel Kachhap return pd; 28026aec009SAmit Daniel Kachhap } 28126aec009SAmit Daniel Kachhap #else 282197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 28326aec009SAmit Daniel Kachhap struct device *dev) 28426aec009SAmit Daniel Kachhap { 285005718c0SWei Yongjun return NULL; 28626aec009SAmit Daniel Kachhap } 28726aec009SAmit Daniel Kachhap #endif 28826aec009SAmit Daniel Kachhap 2898f695de5SPankaj Dubey static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, 29026aec009SAmit Daniel Kachhap const struct i2c_device_id *id) 29126aec009SAmit Daniel Kachhap { 29226aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 29326aec009SAmit Daniel Kachhap if (i2c->dev.of_node) { 29426aec009SAmit Daniel Kachhap const struct of_device_id *match; 295b6c1cb4dSLee Jones 29626aec009SAmit Daniel Kachhap match = of_match_node(sec_dt_match, i2c->dev.of_node); 2978f695de5SPankaj Dubey return (unsigned long)match->data; 29826aec009SAmit Daniel Kachhap } 29926aec009SAmit Daniel Kachhap #endif 3008f695de5SPankaj Dubey return id->driver_data; 30126aec009SAmit Daniel Kachhap } 30226aec009SAmit Daniel Kachhap 30363063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c, 30466c9fbb9SSangbeom Kim const struct i2c_device_id *id) 30566c9fbb9SSangbeom Kim { 306334a41ceSJingoo Han struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); 307e349c910SKrzysztof Kozlowski const struct regmap_config *regmap; 30854e8827dSChanwoo Choi const struct mfd_cell *sec_devs; 30963063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic; 3109549b5ffSKrzysztof Kozlowski unsigned long device_type; 31154e8827dSChanwoo Choi int ret, num_sec_devs; 31266c9fbb9SSangbeom Kim 31363063bfbSSangbeom Kim sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), 31466c9fbb9SSangbeom Kim GFP_KERNEL); 31563063bfbSSangbeom Kim if (sec_pmic == NULL) 31666c9fbb9SSangbeom Kim return -ENOMEM; 31766c9fbb9SSangbeom Kim 31863063bfbSSangbeom Kim i2c_set_clientdata(i2c, sec_pmic); 31963063bfbSSangbeom Kim sec_pmic->dev = &i2c->dev; 32063063bfbSSangbeom Kim sec_pmic->i2c = i2c; 32163063bfbSSangbeom Kim sec_pmic->irq = i2c->irq; 3229549b5ffSKrzysztof Kozlowski device_type = sec_i2c_get_driver_data(i2c, id); 32366c9fbb9SSangbeom Kim 32426aec009SAmit Daniel Kachhap if (sec_pmic->dev->of_node) { 32526aec009SAmit Daniel Kachhap pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); 32626aec009SAmit Daniel Kachhap if (IS_ERR(pdata)) { 32726aec009SAmit Daniel Kachhap ret = PTR_ERR(pdata); 32826aec009SAmit Daniel Kachhap return ret; 32926aec009SAmit Daniel Kachhap } 3309549b5ffSKrzysztof Kozlowski pdata->device_type = device_type; 33126aec009SAmit Daniel Kachhap } 33266c9fbb9SSangbeom Kim if (pdata) { 33363063bfbSSangbeom Kim sec_pmic->device_type = pdata->device_type; 33463063bfbSSangbeom Kim sec_pmic->irq_base = pdata->irq_base; 33563063bfbSSangbeom Kim sec_pmic->wakeup = pdata->wakeup; 33626aec009SAmit Daniel Kachhap sec_pmic->pdata = pdata; 33766c9fbb9SSangbeom Kim } 33866c9fbb9SSangbeom Kim 33925f311faSMark Brown switch (sec_pmic->device_type) { 340ce24991eSSachin Kamat case S2MPA01: 341ce24991eSSachin Kamat regmap = &s2mpa01_regmap_config; 342ce24991eSSachin Kamat break; 34325f311faSMark Brown case S2MPS11X: 34425f311faSMark Brown regmap = &s2mps11_regmap_config; 345dc691966SKrzysztof Kozlowski break; 34676b9840bSChanwoo Choi case S2MPS13X: 34776b9840bSChanwoo Choi regmap = &s2mps13_regmap_config; 34876b9840bSChanwoo Choi break; 349dc691966SKrzysztof Kozlowski case S2MPS14X: 350dc691966SKrzysztof Kozlowski regmap = &s2mps14_regmap_config; 35125f311faSMark Brown break; 35225f311faSMark Brown case S5M8763X: 35325f311faSMark Brown regmap = &s5m8763_regmap_config; 35425f311faSMark Brown break; 35525f311faSMark Brown case S5M8767X: 35625f311faSMark Brown regmap = &s5m8767_regmap_config; 35725f311faSMark Brown break; 35800e2573dSChanwoo Choi case S2MPU02: 35900e2573dSChanwoo Choi regmap = &s2mpu02_regmap_config; 36000e2573dSChanwoo Choi break; 36125f311faSMark Brown default: 36225f311faSMark Brown regmap = &sec_regmap_config; 36325f311faSMark Brown break; 36425f311faSMark Brown } 36525f311faSMark Brown 3663e1e4a5fSKrzysztof Kozlowski sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); 3673e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_pmic)) { 3683e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_pmic); 36966c9fbb9SSangbeom Kim dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 37066c9fbb9SSangbeom Kim ret); 37166c9fbb9SSangbeom Kim return ret; 37266c9fbb9SSangbeom Kim } 37366c9fbb9SSangbeom Kim 37466c9fbb9SSangbeom Kim if (pdata && pdata->cfg_pmic_irq) 37566c9fbb9SSangbeom Kim pdata->cfg_pmic_irq(); 37666c9fbb9SSangbeom Kim 37763063bfbSSangbeom Kim sec_irq_init(sec_pmic); 37866c9fbb9SSangbeom Kim 37963063bfbSSangbeom Kim pm_runtime_set_active(sec_pmic->dev); 38066c9fbb9SSangbeom Kim 38163063bfbSSangbeom Kim switch (sec_pmic->device_type) { 38266c9fbb9SSangbeom Kim case S5M8751X: 38354e8827dSChanwoo Choi sec_devs = s5m8751_devs; 38454e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8751_devs); 38566c9fbb9SSangbeom Kim break; 38666c9fbb9SSangbeom Kim case S5M8763X: 38754e8827dSChanwoo Choi sec_devs = s5m8763_devs; 38854e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8763_devs); 38966c9fbb9SSangbeom Kim break; 39066c9fbb9SSangbeom Kim case S5M8767X: 39154e8827dSChanwoo Choi sec_devs = s5m8767_devs; 39254e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8767_devs); 39366c9fbb9SSangbeom Kim break; 394ce24991eSSachin Kamat case S2MPA01: 39554e8827dSChanwoo Choi sec_devs = s2mpa01_devs; 39654e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpa01_devs); 397ce24991eSSachin Kamat break; 3989b6d1343SSangbeom Kim case S2MPS11X: 39954e8827dSChanwoo Choi sec_devs = s2mps11_devs; 40054e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps11_devs); 4019b6d1343SSangbeom Kim break; 4023bc2ee91SChanwoo Choi case S2MPS13X: 4033bc2ee91SChanwoo Choi sec_devs = s2mps13_devs; 4043bc2ee91SChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps13_devs); 4053bc2ee91SChanwoo Choi break; 406dc691966SKrzysztof Kozlowski case S2MPS14X: 40754e8827dSChanwoo Choi sec_devs = s2mps14_devs; 40854e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps14_devs); 40954e8827dSChanwoo Choi break; 41054e8827dSChanwoo Choi case S2MPU02: 41154e8827dSChanwoo Choi sec_devs = s2mpu02_devs; 41254e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpu02_devs); 413dc691966SKrzysztof Kozlowski break; 41466c9fbb9SSangbeom Kim default: 41566c9fbb9SSangbeom Kim /* If this happens the probe function is problem */ 41666c9fbb9SSangbeom Kim BUG(); 41766c9fbb9SSangbeom Kim } 41854e8827dSChanwoo Choi ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL, 41954e8827dSChanwoo Choi 0, NULL); 42015447a46SLeon Romanovsky if (ret) 4218c66eeceSKrzysztof Kozlowski goto err_mfd; 42266c9fbb9SSangbeom Kim 423f6d6daafSKrzysztof Kozlowski device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); 424f6d6daafSKrzysztof Kozlowski 42566c9fbb9SSangbeom Kim return ret; 42666c9fbb9SSangbeom Kim 4278c66eeceSKrzysztof Kozlowski err_mfd: 42863063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 42966c9fbb9SSangbeom Kim return ret; 43066c9fbb9SSangbeom Kim } 43166c9fbb9SSangbeom Kim 43263063bfbSSangbeom Kim static int sec_pmic_remove(struct i2c_client *i2c) 43366c9fbb9SSangbeom Kim { 43463063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 43566c9fbb9SSangbeom Kim 43663063bfbSSangbeom Kim mfd_remove_devices(sec_pmic->dev); 43763063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 43866c9fbb9SSangbeom Kim return 0; 43966c9fbb9SSangbeom Kim } 44066c9fbb9SSangbeom Kim 4418321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 442f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev) 443f6d6daafSKrzysztof Kozlowski { 444f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 445f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 446f6d6daafSKrzysztof Kozlowski 447360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 448f6d6daafSKrzysztof Kozlowski enable_irq_wake(sec_pmic->irq); 449f6d6daafSKrzysztof Kozlowski /* 450f6d6daafSKrzysztof Kozlowski * PMIC IRQ must be disabled during suspend for RTC alarm 451f6d6daafSKrzysztof Kozlowski * to work properly. 452360d15d6SKrzysztof Kozlowski * When device is woken up from suspend, an 453f6d6daafSKrzysztof Kozlowski * interrupt occurs before resuming I2C bus controller. 454f6d6daafSKrzysztof Kozlowski * The interrupt is handled by regmap_irq_thread which tries 455f6d6daafSKrzysztof Kozlowski * to read RTC registers. This read fails (I2C is still 456f6d6daafSKrzysztof Kozlowski * suspended) and RTC Alarm interrupt is disabled. 457f6d6daafSKrzysztof Kozlowski */ 458f6d6daafSKrzysztof Kozlowski disable_irq(sec_pmic->irq); 459f6d6daafSKrzysztof Kozlowski 460f6d6daafSKrzysztof Kozlowski return 0; 461f6d6daafSKrzysztof Kozlowski } 462f6d6daafSKrzysztof Kozlowski 463f6d6daafSKrzysztof Kozlowski static int sec_pmic_resume(struct device *dev) 464f6d6daafSKrzysztof Kozlowski { 465f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 466f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 467f6d6daafSKrzysztof Kozlowski 468360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 469f6d6daafSKrzysztof Kozlowski disable_irq_wake(sec_pmic->irq); 470f6d6daafSKrzysztof Kozlowski enable_irq(sec_pmic->irq); 471f6d6daafSKrzysztof Kozlowski 472f6d6daafSKrzysztof Kozlowski return 0; 473f6d6daafSKrzysztof Kozlowski } 4748321bbf8SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */ 475f6d6daafSKrzysztof Kozlowski 476f6d6daafSKrzysztof Kozlowski static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); 477f6d6daafSKrzysztof Kozlowski 47863063bfbSSangbeom Kim static const struct i2c_device_id sec_pmic_id[] = { 47963063bfbSSangbeom Kim { "sec_pmic", 0 }, 48066c9fbb9SSangbeom Kim { } 48166c9fbb9SSangbeom Kim }; 48263063bfbSSangbeom Kim MODULE_DEVICE_TABLE(i2c, sec_pmic_id); 48366c9fbb9SSangbeom Kim 48463063bfbSSangbeom Kim static struct i2c_driver sec_pmic_driver = { 48566c9fbb9SSangbeom Kim .driver = { 48663063bfbSSangbeom Kim .name = "sec_pmic", 48766c9fbb9SSangbeom Kim .owner = THIS_MODULE, 488f6d6daafSKrzysztof Kozlowski .pm = &sec_pmic_pm_ops, 48926aec009SAmit Daniel Kachhap .of_match_table = of_match_ptr(sec_dt_match), 49066c9fbb9SSangbeom Kim }, 49163063bfbSSangbeom Kim .probe = sec_pmic_probe, 49263063bfbSSangbeom Kim .remove = sec_pmic_remove, 49363063bfbSSangbeom Kim .id_table = sec_pmic_id, 49466c9fbb9SSangbeom Kim }; 49566c9fbb9SSangbeom Kim 49663063bfbSSangbeom Kim static int __init sec_pmic_init(void) 49766c9fbb9SSangbeom Kim { 49863063bfbSSangbeom Kim return i2c_add_driver(&sec_pmic_driver); 49966c9fbb9SSangbeom Kim } 50066c9fbb9SSangbeom Kim 50163063bfbSSangbeom Kim subsys_initcall(sec_pmic_init); 50266c9fbb9SSangbeom Kim 50363063bfbSSangbeom Kim static void __exit sec_pmic_exit(void) 50466c9fbb9SSangbeom Kim { 50563063bfbSSangbeom Kim i2c_del_driver(&sec_pmic_driver); 50666c9fbb9SSangbeom Kim } 50763063bfbSSangbeom Kim module_exit(sec_pmic_exit); 50866c9fbb9SSangbeom Kim 50966c9fbb9SSangbeom Kim MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 51066c9fbb9SSangbeom Kim MODULE_DESCRIPTION("Core support for the S5M MFD"); 51166c9fbb9SSangbeom Kim MODULE_LICENSE("GPL"); 512