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> 2854227bcfSSangbeom Kim #include <linux/mfd/samsung/rtc.h> 29ce24991eSSachin Kamat #include <linux/mfd/samsung/s2mpa01.h> 3025f311faSMark Brown #include <linux/mfd/samsung/s2mps11.h> 31dc691966SKrzysztof Kozlowski #include <linux/mfd/samsung/s2mps14.h> 3225f311faSMark Brown #include <linux/mfd/samsung/s5m8763.h> 3325f311faSMark Brown #include <linux/mfd/samsung/s5m8767.h> 3466c9fbb9SSangbeom Kim #include <linux/regmap.h> 3566c9fbb9SSangbeom Kim 365ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8751_devs[] = { 3766c9fbb9SSangbeom Kim { 3866c9fbb9SSangbeom Kim .name = "s5m8751-pmic", 3966c9fbb9SSangbeom Kim }, { 4066c9fbb9SSangbeom Kim .name = "s5m-charger", 4166c9fbb9SSangbeom Kim }, { 4266c9fbb9SSangbeom Kim .name = "s5m8751-codec", 4366c9fbb9SSangbeom Kim }, 4466c9fbb9SSangbeom Kim }; 4566c9fbb9SSangbeom Kim 465ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8763_devs[] = { 4766c9fbb9SSangbeom Kim { 4866c9fbb9SSangbeom Kim .name = "s5m8763-pmic", 4966c9fbb9SSangbeom Kim }, { 5066c9fbb9SSangbeom Kim .name = "s5m-rtc", 5166c9fbb9SSangbeom Kim }, { 5266c9fbb9SSangbeom Kim .name = "s5m-charger", 5366c9fbb9SSangbeom Kim }, 5466c9fbb9SSangbeom Kim }; 5566c9fbb9SSangbeom Kim 565ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8767_devs[] = { 5766c9fbb9SSangbeom Kim { 5866c9fbb9SSangbeom Kim .name = "s5m8767-pmic", 5966c9fbb9SSangbeom Kim }, { 6066c9fbb9SSangbeom Kim .name = "s5m-rtc", 6139fed00fSTushar Behera }, { 6239fed00fSTushar Behera .name = "s5m8767-clk", 6353c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s5m8767-clk", 6439fed00fSTushar Behera } 6566c9fbb9SSangbeom Kim }; 6666c9fbb9SSangbeom Kim 675ac98553SGeert Uytterhoeven static const struct mfd_cell s2mps11_devs[] = { 689b6d1343SSangbeom Kim { 699b6d1343SSangbeom Kim .name = "s2mps11-pmic", 703134bcaeSYadwinder Singh Brar }, { 713134bcaeSYadwinder Singh Brar .name = "s2mps11-clk", 7253c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps11-clk", 733134bcaeSYadwinder Singh Brar } 749b6d1343SSangbeom Kim }; 759b6d1343SSangbeom Kim 76dc691966SKrzysztof Kozlowski static const struct mfd_cell s2mps14_devs[] = { 77dc691966SKrzysztof Kozlowski { 78dc691966SKrzysztof Kozlowski .name = "s2mps14-pmic", 79dc691966SKrzysztof Kozlowski }, { 80dc691966SKrzysztof Kozlowski .name = "s2mps14-rtc", 81dc691966SKrzysztof Kozlowski }, { 82dc691966SKrzysztof Kozlowski .name = "s2mps14-clk", 8353c31b34SKrzysztof Kozlowski .of_compatible = "samsung,s2mps14-clk", 84dc691966SKrzysztof Kozlowski } 85dc691966SKrzysztof Kozlowski }; 86dc691966SKrzysztof Kozlowski 87ce24991eSSachin Kamat static const struct mfd_cell s2mpa01_devs[] = { 88ce24991eSSachin Kamat { 89ce24991eSSachin Kamat .name = "s2mpa01-pmic", 90ce24991eSSachin Kamat }, 91ce24991eSSachin Kamat }; 92ce24991eSSachin Kamat 9326aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 9426aec009SAmit Daniel Kachhap static struct of_device_id sec_dt_match[] = { 9526aec009SAmit Daniel Kachhap { .compatible = "samsung,s5m8767-pmic", 9626aec009SAmit Daniel Kachhap .data = (void *)S5M8767X, 97ce24991eSSachin Kamat }, { 98ce24991eSSachin Kamat .compatible = "samsung,s2mps11-pmic", 99aa32acadSYadwinder Singh Brar .data = (void *)S2MPS11X, 100ce24991eSSachin Kamat }, { 101ce24991eSSachin Kamat .compatible = "samsung,s2mps14-pmic", 102dc691966SKrzysztof Kozlowski .data = (void *)S2MPS14X, 103ce24991eSSachin Kamat }, { 104ce24991eSSachin Kamat .compatible = "samsung,s2mpa01-pmic", 105ce24991eSSachin Kamat .data = (void *)S2MPA01, 106ce24991eSSachin Kamat }, { 107ce24991eSSachin Kamat /* Sentinel */ 108dc691966SKrzysztof Kozlowski }, 10926aec009SAmit Daniel Kachhap }; 11026aec009SAmit Daniel Kachhap #endif 11126aec009SAmit Daniel Kachhap 112ce24991eSSachin Kamat static bool s2mpa01_volatile(struct device *dev, unsigned int reg) 113ce24991eSSachin Kamat { 114ce24991eSSachin Kamat switch (reg) { 115ce24991eSSachin Kamat case S2MPA01_REG_INT1M: 116ce24991eSSachin Kamat case S2MPA01_REG_INT2M: 117ce24991eSSachin Kamat case S2MPA01_REG_INT3M: 118ce24991eSSachin Kamat return false; 119ce24991eSSachin Kamat default: 120ce24991eSSachin Kamat return true; 121ce24991eSSachin Kamat } 122ce24991eSSachin Kamat } 123ce24991eSSachin Kamat 1246b845ba9SMark Brown static bool s2mps11_volatile(struct device *dev, unsigned int reg) 1256b845ba9SMark Brown { 1266b845ba9SMark Brown switch (reg) { 1276b845ba9SMark Brown case S2MPS11_REG_INT1M: 1286b845ba9SMark Brown case S2MPS11_REG_INT2M: 1296b845ba9SMark Brown case S2MPS11_REG_INT3M: 1306b845ba9SMark Brown return false; 1316b845ba9SMark Brown default: 1326b845ba9SMark Brown return true; 1336b845ba9SMark Brown } 1346b845ba9SMark Brown } 1356b845ba9SMark Brown 1366b845ba9SMark Brown static bool s5m8763_volatile(struct device *dev, unsigned int reg) 1376b845ba9SMark Brown { 1386b845ba9SMark Brown switch (reg) { 1396b845ba9SMark Brown case S5M8763_REG_IRQM1: 1406b845ba9SMark Brown case S5M8763_REG_IRQM2: 1416b845ba9SMark Brown case S5M8763_REG_IRQM3: 1426b845ba9SMark Brown case S5M8763_REG_IRQM4: 1436b845ba9SMark Brown return false; 1446b845ba9SMark Brown default: 1456b845ba9SMark Brown return true; 1466b845ba9SMark Brown } 1476b845ba9SMark Brown } 1486b845ba9SMark Brown 149a30fffb0SKrzysztof Kozlowski static const struct regmap_config sec_regmap_config = { 15066c9fbb9SSangbeom Kim .reg_bits = 8, 15166c9fbb9SSangbeom Kim .val_bits = 8, 15266c9fbb9SSangbeom Kim }; 15366c9fbb9SSangbeom Kim 154ce24991eSSachin Kamat static const struct regmap_config s2mpa01_regmap_config = { 155ce24991eSSachin Kamat .reg_bits = 8, 156ce24991eSSachin Kamat .val_bits = 8, 157ce24991eSSachin Kamat 158ce24991eSSachin Kamat .max_register = S2MPA01_REG_LDO_OVCB4, 159ce24991eSSachin Kamat .volatile_reg = s2mpa01_volatile, 160ce24991eSSachin Kamat .cache_type = REGCACHE_FLAT, 161ce24991eSSachin Kamat }; 162ce24991eSSachin Kamat 163a30fffb0SKrzysztof Kozlowski static const struct regmap_config s2mps11_regmap_config = { 16425f311faSMark Brown .reg_bits = 8, 16525f311faSMark Brown .val_bits = 8, 16625f311faSMark Brown 16725f311faSMark Brown .max_register = S2MPS11_REG_L38CTRL, 1686b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 1696b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 17025f311faSMark Brown }; 17125f311faSMark Brown 172dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_regmap_config = { 173dc691966SKrzysztof Kozlowski .reg_bits = 8, 174dc691966SKrzysztof Kozlowski .val_bits = 8, 175dc691966SKrzysztof Kozlowski 176dc691966SKrzysztof Kozlowski .max_register = S2MPS14_REG_LDODSCH3, 177dc691966SKrzysztof Kozlowski .volatile_reg = s2mps11_volatile, 178dc691966SKrzysztof Kozlowski .cache_type = REGCACHE_FLAT, 179dc691966SKrzysztof Kozlowski }; 180dc691966SKrzysztof Kozlowski 181a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = { 18225f311faSMark Brown .reg_bits = 8, 18325f311faSMark Brown .val_bits = 8, 18425f311faSMark Brown 18525f311faSMark Brown .max_register = S5M8763_REG_LBCNFG2, 1866b845ba9SMark Brown .volatile_reg = s5m8763_volatile, 1876b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 18825f311faSMark Brown }; 18925f311faSMark Brown 190a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = { 19125f311faSMark Brown .reg_bits = 8, 19225f311faSMark Brown .val_bits = 8, 19325f311faSMark Brown 19425f311faSMark Brown .max_register = S5M8767_REG_LDO28CTRL, 1956b845ba9SMark Brown .volatile_reg = s2mps11_volatile, 1966b845ba9SMark Brown .cache_type = REGCACHE_FLAT, 19725f311faSMark Brown }; 19826aec009SAmit Daniel Kachhap 199dc691966SKrzysztof Kozlowski static const struct regmap_config s5m_rtc_regmap_config = { 2003e1e4a5fSKrzysztof Kozlowski .reg_bits = 8, 2013e1e4a5fSKrzysztof Kozlowski .val_bits = 8, 202b07e2b70SKrzysztof Kozlowski 203b07e2b70SKrzysztof Kozlowski .max_register = SEC_RTC_REG_MAX, 2043e1e4a5fSKrzysztof Kozlowski }; 2053e1e4a5fSKrzysztof Kozlowski 206dc691966SKrzysztof Kozlowski static const struct regmap_config s2mps14_rtc_regmap_config = { 207dc691966SKrzysztof Kozlowski .reg_bits = 8, 208dc691966SKrzysztof Kozlowski .val_bits = 8, 209dc691966SKrzysztof Kozlowski 210dc691966SKrzysztof Kozlowski .max_register = S2MPS_RTC_REG_MAX, 211dc691966SKrzysztof Kozlowski }; 212dc691966SKrzysztof Kozlowski 21326aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 21426aec009SAmit Daniel Kachhap /* 21526aec009SAmit Daniel Kachhap * Only the common platform data elements for s5m8767 are parsed here from the 21626aec009SAmit Daniel Kachhap * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 21726aec009SAmit Daniel Kachhap * others have to parse their own platform data elements from device tree. 21826aec009SAmit Daniel Kachhap * 21926aec009SAmit Daniel Kachhap * The s5m8767 platform data structure is instantiated here and the drivers for 22026aec009SAmit Daniel Kachhap * the sub-modules need not instantiate another instance while parsing their 22126aec009SAmit Daniel Kachhap * platform data. 22226aec009SAmit Daniel Kachhap */ 22326aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 22426aec009SAmit Daniel Kachhap struct device *dev) 22526aec009SAmit Daniel Kachhap { 22626aec009SAmit Daniel Kachhap struct sec_platform_data *pd; 22726aec009SAmit Daniel Kachhap 22826aec009SAmit Daniel Kachhap pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 22926aec009SAmit Daniel Kachhap if (!pd) { 23026aec009SAmit Daniel Kachhap dev_err(dev, "could not allocate memory for pdata\n"); 23126aec009SAmit Daniel Kachhap return ERR_PTR(-ENOMEM); 23226aec009SAmit Daniel Kachhap } 23326aec009SAmit Daniel Kachhap 23426aec009SAmit Daniel Kachhap /* 23526aec009SAmit Daniel Kachhap * ToDo: the 'wakeup' member in the platform data is more of a linux 23626aec009SAmit Daniel Kachhap * specfic information. Hence, there is no binding for that yet and 23726aec009SAmit Daniel Kachhap * not parsed here. 23826aec009SAmit Daniel Kachhap */ 23926aec009SAmit Daniel Kachhap 24026aec009SAmit Daniel Kachhap return pd; 24126aec009SAmit Daniel Kachhap } 24226aec009SAmit Daniel Kachhap #else 243197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( 24426aec009SAmit Daniel Kachhap struct device *dev) 24526aec009SAmit Daniel Kachhap { 246005718c0SWei Yongjun return NULL; 24726aec009SAmit Daniel Kachhap } 24826aec009SAmit Daniel Kachhap #endif 24926aec009SAmit Daniel Kachhap 2508f695de5SPankaj Dubey static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, 25126aec009SAmit Daniel Kachhap const struct i2c_device_id *id) 25226aec009SAmit Daniel Kachhap { 25326aec009SAmit Daniel Kachhap #ifdef CONFIG_OF 25426aec009SAmit Daniel Kachhap if (i2c->dev.of_node) { 25526aec009SAmit Daniel Kachhap const struct of_device_id *match; 25626aec009SAmit Daniel Kachhap match = of_match_node(sec_dt_match, i2c->dev.of_node); 2578f695de5SPankaj Dubey return (unsigned long)match->data; 25826aec009SAmit Daniel Kachhap } 25926aec009SAmit Daniel Kachhap #endif 2608f695de5SPankaj Dubey return id->driver_data; 26126aec009SAmit Daniel Kachhap } 26226aec009SAmit Daniel Kachhap 26363063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c, 26466c9fbb9SSangbeom Kim const struct i2c_device_id *id) 26566c9fbb9SSangbeom Kim { 266334a41ceSJingoo Han struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); 2673e5a45f7SKrzysztof Kozlowski const struct regmap_config *regmap, *regmap_rtc; 26863063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic; 26966c9fbb9SSangbeom Kim int ret; 27066c9fbb9SSangbeom Kim 27163063bfbSSangbeom Kim sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), 27266c9fbb9SSangbeom Kim GFP_KERNEL); 27363063bfbSSangbeom Kim if (sec_pmic == NULL) 27466c9fbb9SSangbeom Kim return -ENOMEM; 27566c9fbb9SSangbeom Kim 27663063bfbSSangbeom Kim i2c_set_clientdata(i2c, sec_pmic); 27763063bfbSSangbeom Kim sec_pmic->dev = &i2c->dev; 27863063bfbSSangbeom Kim sec_pmic->i2c = i2c; 27963063bfbSSangbeom Kim sec_pmic->irq = i2c->irq; 28026aec009SAmit Daniel Kachhap sec_pmic->type = sec_i2c_get_driver_data(i2c, id); 28166c9fbb9SSangbeom Kim 28226aec009SAmit Daniel Kachhap if (sec_pmic->dev->of_node) { 28326aec009SAmit Daniel Kachhap pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); 28426aec009SAmit Daniel Kachhap if (IS_ERR(pdata)) { 28526aec009SAmit Daniel Kachhap ret = PTR_ERR(pdata); 28626aec009SAmit Daniel Kachhap return ret; 28726aec009SAmit Daniel Kachhap } 28826aec009SAmit Daniel Kachhap pdata->device_type = sec_pmic->type; 28926aec009SAmit Daniel Kachhap } 29066c9fbb9SSangbeom Kim if (pdata) { 29163063bfbSSangbeom Kim sec_pmic->device_type = pdata->device_type; 29263063bfbSSangbeom Kim sec_pmic->ono = pdata->ono; 29363063bfbSSangbeom Kim sec_pmic->irq_base = pdata->irq_base; 29463063bfbSSangbeom Kim sec_pmic->wakeup = pdata->wakeup; 29526aec009SAmit Daniel Kachhap sec_pmic->pdata = pdata; 29666c9fbb9SSangbeom Kim } 29766c9fbb9SSangbeom Kim 29825f311faSMark Brown switch (sec_pmic->device_type) { 299ce24991eSSachin Kamat case S2MPA01: 300ce24991eSSachin Kamat regmap = &s2mpa01_regmap_config; 301ce24991eSSachin Kamat break; 30225f311faSMark Brown case S2MPS11X: 30325f311faSMark Brown regmap = &s2mps11_regmap_config; 3043e5a45f7SKrzysztof Kozlowski /* 3053e5a45f7SKrzysztof Kozlowski * The rtc-s5m driver does not support S2MPS11 and there 3063e5a45f7SKrzysztof Kozlowski * is no mfd_cell for S2MPS11 RTC device. 3073e5a45f7SKrzysztof Kozlowski * However we must pass something to devm_regmap_init_i2c() 3083e5a45f7SKrzysztof Kozlowski * so use S5M-like regmap config even though it wouldn't work. 3093e5a45f7SKrzysztof Kozlowski */ 310dc691966SKrzysztof Kozlowski regmap_rtc = &s5m_rtc_regmap_config; 311dc691966SKrzysztof Kozlowski break; 312dc691966SKrzysztof Kozlowski case S2MPS14X: 313dc691966SKrzysztof Kozlowski regmap = &s2mps14_regmap_config; 314dc691966SKrzysztof Kozlowski regmap_rtc = &s2mps14_rtc_regmap_config; 31525f311faSMark Brown break; 31625f311faSMark Brown case S5M8763X: 31725f311faSMark Brown regmap = &s5m8763_regmap_config; 318dc691966SKrzysztof Kozlowski regmap_rtc = &s5m_rtc_regmap_config; 31925f311faSMark Brown break; 32025f311faSMark Brown case S5M8767X: 32125f311faSMark Brown regmap = &s5m8767_regmap_config; 322dc691966SKrzysztof Kozlowski regmap_rtc = &s5m_rtc_regmap_config; 32325f311faSMark Brown break; 32425f311faSMark Brown default: 32525f311faSMark Brown regmap = &sec_regmap_config; 326dc691966SKrzysztof Kozlowski regmap_rtc = &s5m_rtc_regmap_config; 32725f311faSMark Brown break; 32825f311faSMark Brown } 32925f311faSMark Brown 3303e1e4a5fSKrzysztof Kozlowski sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); 3313e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_pmic)) { 3323e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_pmic); 33366c9fbb9SSangbeom Kim dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 33466c9fbb9SSangbeom Kim ret); 33566c9fbb9SSangbeom Kim return ret; 33666c9fbb9SSangbeom Kim } 33766c9fbb9SSangbeom Kim 33863063bfbSSangbeom Kim sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); 33965aba1e0SKrzysztof Kozlowski if (!sec_pmic->rtc) { 34065aba1e0SKrzysztof Kozlowski dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); 34165aba1e0SKrzysztof Kozlowski return -ENODEV; 34265aba1e0SKrzysztof Kozlowski } 34363063bfbSSangbeom Kim i2c_set_clientdata(sec_pmic->rtc, sec_pmic); 34466c9fbb9SSangbeom Kim 3453e5a45f7SKrzysztof Kozlowski sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); 3463e1e4a5fSKrzysztof Kozlowski if (IS_ERR(sec_pmic->regmap_rtc)) { 3473e1e4a5fSKrzysztof Kozlowski ret = PTR_ERR(sec_pmic->regmap_rtc); 3483e1e4a5fSKrzysztof Kozlowski dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", 3493e1e4a5fSKrzysztof Kozlowski ret); 3503e1e4a5fSKrzysztof Kozlowski return ret; 3513e1e4a5fSKrzysztof Kozlowski } 3523e1e4a5fSKrzysztof Kozlowski 35366c9fbb9SSangbeom Kim if (pdata && pdata->cfg_pmic_irq) 35466c9fbb9SSangbeom Kim pdata->cfg_pmic_irq(); 35566c9fbb9SSangbeom Kim 35663063bfbSSangbeom Kim sec_irq_init(sec_pmic); 35766c9fbb9SSangbeom Kim 35863063bfbSSangbeom Kim pm_runtime_set_active(sec_pmic->dev); 35966c9fbb9SSangbeom Kim 36063063bfbSSangbeom Kim switch (sec_pmic->device_type) { 36166c9fbb9SSangbeom Kim case S5M8751X: 36263063bfbSSangbeom Kim ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs, 3630848c94fSMark Brown ARRAY_SIZE(s5m8751_devs), NULL, 0, NULL); 36466c9fbb9SSangbeom Kim break; 36566c9fbb9SSangbeom Kim case S5M8763X: 36663063bfbSSangbeom Kim ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs, 3670848c94fSMark Brown ARRAY_SIZE(s5m8763_devs), NULL, 0, NULL); 36866c9fbb9SSangbeom Kim break; 36966c9fbb9SSangbeom Kim case S5M8767X: 37063063bfbSSangbeom Kim ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, 3710848c94fSMark Brown ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); 37266c9fbb9SSangbeom Kim break; 373ce24991eSSachin Kamat case S2MPA01: 374ce24991eSSachin Kamat ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs, 375ce24991eSSachin Kamat ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL); 376ce24991eSSachin Kamat break; 3779b6d1343SSangbeom Kim case S2MPS11X: 3789b6d1343SSangbeom Kim ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, 3790848c94fSMark Brown ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); 3809b6d1343SSangbeom Kim break; 381dc691966SKrzysztof Kozlowski case S2MPS14X: 382dc691966SKrzysztof Kozlowski ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs, 383dc691966SKrzysztof Kozlowski ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL); 384dc691966SKrzysztof Kozlowski break; 38566c9fbb9SSangbeom Kim default: 38666c9fbb9SSangbeom Kim /* If this happens the probe function is problem */ 38766c9fbb9SSangbeom Kim BUG(); 38866c9fbb9SSangbeom Kim } 38966c9fbb9SSangbeom Kim 39015447a46SLeon Romanovsky if (ret) 39166c9fbb9SSangbeom Kim goto err; 39266c9fbb9SSangbeom Kim 393f6d6daafSKrzysztof Kozlowski device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); 394f6d6daafSKrzysztof Kozlowski 39566c9fbb9SSangbeom Kim return ret; 39666c9fbb9SSangbeom Kim 39766c9fbb9SSangbeom Kim err: 39863063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 39963063bfbSSangbeom Kim i2c_unregister_device(sec_pmic->rtc); 40066c9fbb9SSangbeom Kim return ret; 40166c9fbb9SSangbeom Kim } 40266c9fbb9SSangbeom Kim 40363063bfbSSangbeom Kim static int sec_pmic_remove(struct i2c_client *i2c) 40466c9fbb9SSangbeom Kim { 40563063bfbSSangbeom Kim struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 40666c9fbb9SSangbeom Kim 40763063bfbSSangbeom Kim mfd_remove_devices(sec_pmic->dev); 40863063bfbSSangbeom Kim sec_irq_exit(sec_pmic); 40963063bfbSSangbeom Kim i2c_unregister_device(sec_pmic->rtc); 41066c9fbb9SSangbeom Kim return 0; 41166c9fbb9SSangbeom Kim } 41266c9fbb9SSangbeom Kim 4138321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 414f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev) 415f6d6daafSKrzysztof Kozlowski { 416f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 417f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 418f6d6daafSKrzysztof Kozlowski 419f6d6daafSKrzysztof Kozlowski if (device_may_wakeup(dev)) { 420f6d6daafSKrzysztof Kozlowski enable_irq_wake(sec_pmic->irq); 421f6d6daafSKrzysztof Kozlowski /* 422f6d6daafSKrzysztof Kozlowski * PMIC IRQ must be disabled during suspend for RTC alarm 423f6d6daafSKrzysztof Kozlowski * to work properly. 424f6d6daafSKrzysztof Kozlowski * When device is woken up from suspend by RTC Alarm, an 425f6d6daafSKrzysztof Kozlowski * interrupt occurs before resuming I2C bus controller. 426f6d6daafSKrzysztof Kozlowski * The interrupt is handled by regmap_irq_thread which tries 427f6d6daafSKrzysztof Kozlowski * to read RTC registers. This read fails (I2C is still 428f6d6daafSKrzysztof Kozlowski * suspended) and RTC Alarm interrupt is disabled. 429f6d6daafSKrzysztof Kozlowski */ 430f6d6daafSKrzysztof Kozlowski disable_irq(sec_pmic->irq); 431f6d6daafSKrzysztof Kozlowski } 432f6d6daafSKrzysztof Kozlowski 433f6d6daafSKrzysztof Kozlowski return 0; 434f6d6daafSKrzysztof Kozlowski } 435f6d6daafSKrzysztof Kozlowski 436f6d6daafSKrzysztof Kozlowski static int sec_pmic_resume(struct device *dev) 437f6d6daafSKrzysztof Kozlowski { 438f6d6daafSKrzysztof Kozlowski struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 439f6d6daafSKrzysztof Kozlowski struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); 440f6d6daafSKrzysztof Kozlowski 441f6d6daafSKrzysztof Kozlowski if (device_may_wakeup(dev)) { 442f6d6daafSKrzysztof Kozlowski disable_irq_wake(sec_pmic->irq); 443f6d6daafSKrzysztof Kozlowski enable_irq(sec_pmic->irq); 444f6d6daafSKrzysztof Kozlowski } 445f6d6daafSKrzysztof Kozlowski 446f6d6daafSKrzysztof Kozlowski return 0; 447f6d6daafSKrzysztof Kozlowski } 4488321bbf8SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */ 449f6d6daafSKrzysztof Kozlowski 450f6d6daafSKrzysztof Kozlowski static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); 451f6d6daafSKrzysztof Kozlowski 45263063bfbSSangbeom Kim static const struct i2c_device_id sec_pmic_id[] = { 45363063bfbSSangbeom Kim { "sec_pmic", 0 }, 45466c9fbb9SSangbeom Kim { } 45566c9fbb9SSangbeom Kim }; 45663063bfbSSangbeom Kim MODULE_DEVICE_TABLE(i2c, sec_pmic_id); 45766c9fbb9SSangbeom Kim 45863063bfbSSangbeom Kim static struct i2c_driver sec_pmic_driver = { 45966c9fbb9SSangbeom Kim .driver = { 46063063bfbSSangbeom Kim .name = "sec_pmic", 46166c9fbb9SSangbeom Kim .owner = THIS_MODULE, 462f6d6daafSKrzysztof Kozlowski .pm = &sec_pmic_pm_ops, 46326aec009SAmit Daniel Kachhap .of_match_table = of_match_ptr(sec_dt_match), 46466c9fbb9SSangbeom Kim }, 46563063bfbSSangbeom Kim .probe = sec_pmic_probe, 46663063bfbSSangbeom Kim .remove = sec_pmic_remove, 46763063bfbSSangbeom Kim .id_table = sec_pmic_id, 46866c9fbb9SSangbeom Kim }; 46966c9fbb9SSangbeom Kim 47063063bfbSSangbeom Kim static int __init sec_pmic_init(void) 47166c9fbb9SSangbeom Kim { 47263063bfbSSangbeom Kim return i2c_add_driver(&sec_pmic_driver); 47366c9fbb9SSangbeom Kim } 47466c9fbb9SSangbeom Kim 47563063bfbSSangbeom Kim subsys_initcall(sec_pmic_init); 47666c9fbb9SSangbeom Kim 47763063bfbSSangbeom Kim static void __exit sec_pmic_exit(void) 47866c9fbb9SSangbeom Kim { 47963063bfbSSangbeom Kim i2c_del_driver(&sec_pmic_driver); 48066c9fbb9SSangbeom Kim } 48163063bfbSSangbeom Kim module_exit(sec_pmic_exit); 48266c9fbb9SSangbeom Kim 48366c9fbb9SSangbeom Kim MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 48466c9fbb9SSangbeom Kim MODULE_DESCRIPTION("Core support for the S5M MFD"); 48566c9fbb9SSangbeom Kim MODULE_LICENSE("GPL"); 486