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> 30dc691966SKrzysztof Kozlowski #include <linux/mfd/samsung/s2mps14.h> 3100e2573dSChanwoo Choi #include <linux/mfd/samsung/s2mpu02.h> 3225f311faSMark Brown #include <linux/mfd/samsung/s5m8763.h> 3325f311faSMark Brown #include <linux/mfd/samsung/s5m8767.h> 34b7cde707SChanwoo Choi #include <linux/regulator/machine.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 209dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_regmap_config = { 210dc691966SKrzysztof Kozlowski .reg_bits = 8, 211dc691966SKrzysztof Kozlowski .val_bits = 8, 212dc691966SKrzysztof Kozlowski 213dc691966SKrzysztof Kozlowski .max_register = S2MPS14_REG_LDODSCH3, 214dc691966SKrzysztof Kozlowski .volatile_reg = s2mps11_volatile, 215dc691966SKrzysztof Kozlowski .cache_type = REGCACHE_FLAT, 216dc691966SKrzysztof Kozlowski }; 217dc691966SKrzysztof Kozlowski 21800e2573dSChanwoo Choi static const struct regmap_config s2mpu02_regmap_config = { 21900e2573dSChanwoo Choi .reg_bits = 8, 22000e2573dSChanwoo Choi .val_bits = 8, 22100e2573dSChanwoo Choi 22200e2573dSChanwoo Choi .max_register = S2MPU02_REG_DVSDATA, 22300e2573dSChanwoo Choi .volatile_reg = s2mpu02_volatile, 22400e2573dSChanwoo Choi .cache_type = REGCACHE_FLAT, 22500e2573dSChanwoo Choi }; 22600e2573dSChanwoo Choi 227a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = { 22825f311faSMark Brown .reg_bits = 8, 22925f311faSMark Brown .val_bits = 8, 23025f311faSMark Brown 23125f311faSMark Brown .max_register = S5M8763_REG_LBCNFG2, 2326b845ba9SMark Brown .volatile_reg = s5m8763_volatile, 2336b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 23425f311faSMark Brown }; 23525f311faSMark Brown 236a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = { 23725f311faSMark Brown .reg_bits = 8, 23825f311faSMark Brown .val_bits = 8, 23925f311faSMark Brown 24025f311faSMark Brown .max_register = S5M8767_REG_LDO28CTRL, 2416b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 2426b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 24325f311faSMark Brown }; 24426aec009SAmit Daniel Kachhap 24526aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 24626aec009SAmit Daniel Kachhap /* 24726aec009SAmit Daniel Kachhap * Only the common platform data elements for s5m8767 are parsed here from the 24826aec009SAmit Daniel Kachhap * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 24926aec009SAmit Daniel Kachhap * others have to parse their own platform data elements from device tree. 25026aec009SAmit Daniel Kachhap * 25126aec009SAmit Daniel Kachhap * The s5m8767 platform data structure is instantiated here and the drivers for 25226aec009SAmit Daniel Kachhap * the sub-modules need not instantiate another instance while parsing their 25326aec009SAmit Daniel Kachhap * platform data. 25426aec009SAmit Daniel Kachhap */ 25526aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 25626aec009SAmit Daniel Kachhap struct device *dev) 25726aec009SAmit Daniel Kachhap { 25826aec009SAmit Daniel Kachhap struct sec_platform_data *pd; 25926aec009SAmit Daniel Kachhap 26026aec009SAmit Daniel Kachhap pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 26126aec009SAmit Daniel Kachhap if (!pd) { 26226aec009SAmit Daniel Kachhap dev_err(dev, "could not allocate memory for pdata\n"); 26326aec009SAmit Daniel Kachhap return ERR_PTR(-ENOMEM); 26426aec009SAmit Daniel Kachhap } 26526aec009SAmit Daniel Kachhap 26626aec009SAmit Daniel Kachhap /* 26726aec009SAmit Daniel Kachhap * ToDo: the 'wakeup' member in the platform data is more of a linux 26826aec009SAmit Daniel Kachhap * specfic information. Hence, there is no binding for that yet and 26926aec009SAmit Daniel Kachhap * not parsed here. 27026aec009SAmit Daniel Kachhap */ 27126aec009SAmit Daniel Kachhap 27226aec009SAmit Daniel Kachhap return pd; 27326aec009SAmit Daniel Kachhap } 27426aec009SAmit Daniel Kachhap #else 275197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 27626aec009SAmit Daniel Kachhap struct device *dev) 27726aec009SAmit Daniel Kachhap { 278005718c0SWei Yongjun return NULL; 27926aec009SAmit Daniel Kachhap } 28026aec009SAmit Daniel Kachhap #endif 28126aec009SAmit Daniel Kachhap 2828f695de5SPankaj Dubey static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, 28326aec009SAmit Daniel Kachhap const struct i2c_device_id *id) 28426aec009SAmit Daniel Kachhap { 28526aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 28626aec009SAmit Daniel Kachhap if (i2c->dev.of_node) { 28726aec009SAmit Daniel Kachhap const struct of_device_id *match; 288b6c1cb4dSLee Jones 28926aec009SAmit Daniel Kachhap match = of_match_node(sec_dt_match, i2c->dev.of_node); 2908f695de5SPankaj Dubey return (unsigned long)match->data; 29126aec009SAmit Daniel Kachhap } 29226aec009SAmit Daniel Kachhap #endif 2938f695de5SPankaj Dubey return id->driver_data; 29426aec009SAmit Daniel Kachhap } 29526aec009SAmit Daniel Kachhap 29663063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c, 29766c9fbb9SSangbeom Kim const struct i2c_device_id *id) 29866c9fbb9SSangbeom Kim { 299334a41ceSJingoo Han struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); 300e349c910SKrzysztof Kozlowski const struct regmap_config *regmap; 30154e8827dSChanwoo Choi const struct mfd_cell *sec_devs; 30263063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic; 3039549b5ffSKrzysztof Kozlowski unsigned long device_type; 30454e8827dSChanwoo Choi int ret, num_sec_devs; 30566c9fbb9SSangbeom Kim 30663063bfbSSangbeom Kim sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), 30766c9fbb9SSangbeom Kim GFP_KERNEL); 30863063bfbSSangbeom Kim if (sec_pmic == NULL) 30966c9fbb9SSangbeom Kim return -ENOMEM; 31066c9fbb9SSangbeom Kim 31163063bfbSSangbeom Kim i2c_set_clientdata(i2c, sec_pmic); 31263063bfbSSangbeom Kim sec_pmic->dev = &i2c->dev; 31363063bfbSSangbeom Kim sec_pmic->i2c = i2c; 31463063bfbSSangbeom Kim sec_pmic->irq = i2c->irq; 3159549b5ffSKrzysztof Kozlowski device_type = sec_i2c_get_driver_data(i2c, id); 31666c9fbb9SSangbeom Kim 31726aec009SAmit Daniel Kachhap if (sec_pmic->dev->of_node) { 31826aec009SAmit Daniel Kachhap pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); 31926aec009SAmit Daniel Kachhap if (IS_ERR(pdata)) { 32026aec009SAmit Daniel Kachhap ret = PTR_ERR(pdata); 32126aec009SAmit Daniel Kachhap return ret; 32226aec009SAmit Daniel Kachhap } 3239549b5ffSKrzysztof Kozlowski pdata->device_type = device_type; 32426aec009SAmit Daniel Kachhap } 32566c9fbb9SSangbeom Kim if (pdata) { 32663063bfbSSangbeom Kim sec_pmic->device_type = pdata->device_type; 32763063bfbSSangbeom Kim sec_pmic->ono = pdata->ono; 32863063bfbSSangbeom Kim sec_pmic->irq_base = pdata->irq_base; 32963063bfbSSangbeom Kim sec_pmic->wakeup = pdata->wakeup; 33026aec009SAmit Daniel Kachhap sec_pmic->pdata = pdata; 33166c9fbb9SSangbeom Kim } 33266c9fbb9SSangbeom Kim 33325f311faSMark Brown switch (sec_pmic->device_type) { 334ce24991eSSachin Kamat case S2MPA01: 335ce24991eSSachin Kamat regmap = &s2mpa01_regmap_config; 336ce24991eSSachin Kamat break; 33725f311faSMark Brown case S2MPS11X: 33825f311faSMark Brown regmap = &s2mps11_regmap_config; 339dc691966SKrzysztof Kozlowski break; 340dc691966SKrzysztof Kozlowski case S2MPS14X: 341dc691966SKrzysztof Kozlowski regmap = &s2mps14_regmap_config; 34225f311faSMark Brown break; 34325f311faSMark Brown case S5M8763X: 34425f311faSMark Brown regmap = &s5m8763_regmap_config; 34525f311faSMark Brown break; 34625f311faSMark Brown case S5M8767X: 34725f311faSMark Brown regmap = &s5m8767_regmap_config; 34825f311faSMark Brown break; 34900e2573dSChanwoo Choi case S2MPU02: 35000e2573dSChanwoo Choi regmap = &s2mpu02_regmap_config; 35100e2573dSChanwoo Choi break; 35225f311faSMark Brown default: 35325f311faSMark Brown regmap = &sec_regmap_config; 35425f311faSMark Brown break; 35525f311faSMark Brown } 35625f311faSMark Brown 3573e1e4a5fSKrzysztof Kozlowski sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); 3583e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_pmic)) { 3593e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_pmic); 36066c9fbb9SSangbeom Kim dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 36166c9fbb9SSangbeom Kim ret); 36266c9fbb9SSangbeom Kim return ret; 36366c9fbb9SSangbeom Kim } 36466c9fbb9SSangbeom Kim 36566c9fbb9SSangbeom Kim if (pdata && pdata->cfg_pmic_irq) 36666c9fbb9SSangbeom Kim pdata->cfg_pmic_irq(); 36766c9fbb9SSangbeom Kim 36863063bfbSSangbeom Kim sec_irq_init(sec_pmic); 36966c9fbb9SSangbeom Kim 37063063bfbSSangbeom Kim pm_runtime_set_active(sec_pmic->dev); 37166c9fbb9SSangbeom Kim 37263063bfbSSangbeom Kim switch (sec_pmic->device_type) { 37366c9fbb9SSangbeom Kim case S5M8751X: 37454e8827dSChanwoo Choi sec_devs = s5m8751_devs; 37554e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8751_devs); 37666c9fbb9SSangbeom Kim break; 37766c9fbb9SSangbeom Kim case S5M8763X: 37854e8827dSChanwoo Choi sec_devs = s5m8763_devs; 37954e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8763_devs); 38066c9fbb9SSangbeom Kim break; 38166c9fbb9SSangbeom Kim case S5M8767X: 38254e8827dSChanwoo Choi sec_devs = s5m8767_devs; 38354e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s5m8767_devs); 38466c9fbb9SSangbeom Kim break; 385ce24991eSSachin Kamat case S2MPA01: 38654e8827dSChanwoo Choi sec_devs = s2mpa01_devs; 38754e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpa01_devs); 388ce24991eSSachin Kamat break; 3899b6d1343SSangbeom Kim case S2MPS11X: 39054e8827dSChanwoo Choi sec_devs = s2mps11_devs; 39154e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps11_devs); 3929b6d1343SSangbeom Kim break; 3933bc2ee91SChanwoo Choi case S2MPS13X: 3943bc2ee91SChanwoo Choi sec_devs = s2mps13_devs; 3953bc2ee91SChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps13_devs); 3963bc2ee91SChanwoo Choi break; 397dc691966SKrzysztof Kozlowski case S2MPS14X: 39854e8827dSChanwoo Choi sec_devs = s2mps14_devs; 39954e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mps14_devs); 40054e8827dSChanwoo Choi break; 40154e8827dSChanwoo Choi case S2MPU02: 40254e8827dSChanwoo Choi sec_devs = s2mpu02_devs; 40354e8827dSChanwoo Choi num_sec_devs = ARRAY_SIZE(s2mpu02_devs); 404dc691966SKrzysztof Kozlowski break; 40566c9fbb9SSangbeom Kim default: 40666c9fbb9SSangbeom Kim /* If this happens the probe function is problem */ 40766c9fbb9SSangbeom Kim BUG(); 40866c9fbb9SSangbeom Kim } 40954e8827dSChanwoo Choi ret = mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, NULL, 41054e8827dSChanwoo Choi 0, NULL); 41115447a46SLeon Romanovsky if (ret) 4128c66eeceSKrzysztof Kozlowski goto err_mfd; 41366c9fbb9SSangbeom Kim 414f6d6daafSKrzysztof Kozlowski device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); 415f6d6daafSKrzysztof Kozlowski 41666c9fbb9SSangbeom Kim return ret; 41766c9fbb9SSangbeom Kim 4188c66eeceSKrzysztof Kozlowski err_mfd: 41963063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 42066c9fbb9SSangbeom Kim return ret; 42166c9fbb9SSangbeom Kim } 42266c9fbb9SSangbeom Kim 42363063bfbSSangbeom Kim static int sec_pmic_remove(struct i2c_client *i2c) 42466c9fbb9SSangbeom Kim { 42563063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 42666c9fbb9SSangbeom Kim 42763063bfbSSangbeom Kim mfd_remove_devices(sec_pmic->dev); 42863063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 42966c9fbb9SSangbeom Kim return 0; 43066c9fbb9SSangbeom Kim } 43166c9fbb9SSangbeom Kim 4328321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 433f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev) 434f6d6daafSKrzysztof Kozlowski { 435f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 436f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 437f6d6daafSKrzysztof Kozlowski 438360d15d6SKrzysztof Kozlowski if (device_may_wakeup(dev)) 439f6d6daafSKrzysztof Kozlowski enable_irq_wake(sec_pmic->irq); 440f6d6daafSKrzysztof Kozlowski /* 441f6d6daafSKrzysztof Kozlowski * PMIC IRQ must be disabled during suspend for RTC alarm 442f6d6daafSKrzysztof Kozlowski * to work properly. 443360d15d6SKrzysztof Kozlowski * When device is woken up from suspend, an 444f6d6daafSKrzysztof Kozlowski * interrupt occurs before resuming I2C bus controller. 445f6d6daafSKrzysztof Kozlowski * The interrupt is handled by regmap_irq_thread which tries 446f6d6daafSKrzysztof Kozlowski * to read RTC registers. This read fails (I2C is still 447f6d6daafSKrzysztof Kozlowski * suspended) and RTC Alarm interrupt is disabled. 448f6d6daafSKrzysztof Kozlowski */ 449f6d6daafSKrzysztof Kozlowski disable_irq(sec_pmic->irq); 450f6d6daafSKrzysztof Kozlowski 451b7cde707SChanwoo Choi switch (sec_pmic->device_type) { 452b7cde707SChanwoo Choi case S2MPS14X: 453b7cde707SChanwoo Choi case S2MPU02: 454b7cde707SChanwoo Choi regulator_suspend_prepare(PM_SUSPEND_MEM); 455b7cde707SChanwoo Choi break; 456b7cde707SChanwoo Choi default: 457b7cde707SChanwoo Choi break; 458b7cde707SChanwoo Choi } 459b7cde707SChanwoo Choi 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