xref: /openbmc/linux/drivers/mfd/sec-core.c (revision 3e5a45f7)
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>
2925f311faSMark Brown #include <linux/mfd/samsung/s2mps11.h>
3025f311faSMark Brown #include <linux/mfd/samsung/s5m8763.h>
3125f311faSMark Brown #include <linux/mfd/samsung/s5m8767.h>
3266c9fbb9SSangbeom Kim #include <linux/regmap.h>
3366c9fbb9SSangbeom Kim 
345ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8751_devs[] = {
3566c9fbb9SSangbeom Kim 	{
3666c9fbb9SSangbeom Kim 		.name = "s5m8751-pmic",
3766c9fbb9SSangbeom Kim 	}, {
3866c9fbb9SSangbeom Kim 		.name = "s5m-charger",
3966c9fbb9SSangbeom Kim 	}, {
4066c9fbb9SSangbeom Kim 		.name = "s5m8751-codec",
4166c9fbb9SSangbeom Kim 	},
4266c9fbb9SSangbeom Kim };
4366c9fbb9SSangbeom Kim 
445ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8763_devs[] = {
4566c9fbb9SSangbeom Kim 	{
4666c9fbb9SSangbeom Kim 		.name = "s5m8763-pmic",
4766c9fbb9SSangbeom Kim 	}, {
4866c9fbb9SSangbeom Kim 		.name = "s5m-rtc",
4966c9fbb9SSangbeom Kim 	}, {
5066c9fbb9SSangbeom Kim 		.name = "s5m-charger",
5166c9fbb9SSangbeom Kim 	},
5266c9fbb9SSangbeom Kim };
5366c9fbb9SSangbeom Kim 
545ac98553SGeert Uytterhoeven static const struct mfd_cell s5m8767_devs[] = {
5566c9fbb9SSangbeom Kim 	{
5666c9fbb9SSangbeom Kim 		.name = "s5m8767-pmic",
5766c9fbb9SSangbeom Kim 	}, {
5866c9fbb9SSangbeom Kim 		.name = "s5m-rtc",
5939fed00fSTushar Behera 	}, {
6039fed00fSTushar Behera 		.name = "s5m8767-clk",
6139fed00fSTushar Behera 	}
6266c9fbb9SSangbeom Kim };
6366c9fbb9SSangbeom Kim 
645ac98553SGeert Uytterhoeven static const struct mfd_cell s2mps11_devs[] = {
659b6d1343SSangbeom Kim 	{
669b6d1343SSangbeom Kim 		.name = "s2mps11-pmic",
673134bcaeSYadwinder Singh Brar 	}, {
683134bcaeSYadwinder Singh Brar 		.name = "s2mps11-clk",
693134bcaeSYadwinder Singh Brar 	}
709b6d1343SSangbeom Kim };
719b6d1343SSangbeom Kim 
7226aec009SAmit Daniel Kachhap #ifdef CONFIG_OF
7326aec009SAmit Daniel Kachhap static struct of_device_id sec_dt_match[] = {
7426aec009SAmit Daniel Kachhap 	{	.compatible = "samsung,s5m8767-pmic",
7526aec009SAmit Daniel Kachhap 		.data = (void *)S5M8767X,
7626aec009SAmit Daniel Kachhap 	},
77aa32acadSYadwinder Singh Brar 	{	.compatible = "samsung,s2mps11-pmic",
78aa32acadSYadwinder Singh Brar 		.data = (void *)S2MPS11X,
79aa32acadSYadwinder Singh Brar 	},
8026aec009SAmit Daniel Kachhap 	{},
8126aec009SAmit Daniel Kachhap };
8226aec009SAmit Daniel Kachhap #endif
8326aec009SAmit Daniel Kachhap 
846b845ba9SMark Brown static bool s2mps11_volatile(struct device *dev, unsigned int reg)
856b845ba9SMark Brown {
866b845ba9SMark Brown 	switch (reg) {
876b845ba9SMark Brown 	case S2MPS11_REG_INT1M:
886b845ba9SMark Brown 	case S2MPS11_REG_INT2M:
896b845ba9SMark Brown 	case S2MPS11_REG_INT3M:
906b845ba9SMark Brown 		return false;
916b845ba9SMark Brown 	default:
926b845ba9SMark Brown 		return true;
936b845ba9SMark Brown 	}
946b845ba9SMark Brown }
956b845ba9SMark Brown 
966b845ba9SMark Brown static bool s5m8763_volatile(struct device *dev, unsigned int reg)
976b845ba9SMark Brown {
986b845ba9SMark Brown 	switch (reg) {
996b845ba9SMark Brown 	case S5M8763_REG_IRQM1:
1006b845ba9SMark Brown 	case S5M8763_REG_IRQM2:
1016b845ba9SMark Brown 	case S5M8763_REG_IRQM3:
1026b845ba9SMark Brown 	case S5M8763_REG_IRQM4:
1036b845ba9SMark Brown 		return false;
1046b845ba9SMark Brown 	default:
1056b845ba9SMark Brown 		return true;
1066b845ba9SMark Brown 	}
1076b845ba9SMark Brown }
1086b845ba9SMark Brown 
109a30fffb0SKrzysztof Kozlowski static const struct regmap_config sec_regmap_config = {
11066c9fbb9SSangbeom Kim 	.reg_bits = 8,
11166c9fbb9SSangbeom Kim 	.val_bits = 8,
11266c9fbb9SSangbeom Kim };
11366c9fbb9SSangbeom Kim 
114a30fffb0SKrzysztof Kozlowski static const struct regmap_config s2mps11_regmap_config = {
11525f311faSMark Brown 	.reg_bits = 8,
11625f311faSMark Brown 	.val_bits = 8,
11725f311faSMark Brown 
11825f311faSMark Brown 	.max_register = S2MPS11_REG_L38CTRL,
1196b845ba9SMark Brown 	.volatile_reg = s2mps11_volatile,
1206b845ba9SMark Brown 	.cache_type = REGCACHE_FLAT,
12125f311faSMark Brown };
12225f311faSMark Brown 
123a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8763_regmap_config = {
12425f311faSMark Brown 	.reg_bits = 8,
12525f311faSMark Brown 	.val_bits = 8,
12625f311faSMark Brown 
12725f311faSMark Brown 	.max_register = S5M8763_REG_LBCNFG2,
1286b845ba9SMark Brown 	.volatile_reg = s5m8763_volatile,
1296b845ba9SMark Brown 	.cache_type = REGCACHE_FLAT,
13025f311faSMark Brown };
13125f311faSMark Brown 
132a30fffb0SKrzysztof Kozlowski static const struct regmap_config s5m8767_regmap_config = {
13325f311faSMark Brown 	.reg_bits = 8,
13425f311faSMark Brown 	.val_bits = 8,
13525f311faSMark Brown 
13625f311faSMark Brown 	.max_register = S5M8767_REG_LDO28CTRL,
1376b845ba9SMark Brown 	.volatile_reg = s2mps11_volatile,
1386b845ba9SMark Brown 	.cache_type = REGCACHE_FLAT,
13925f311faSMark Brown };
14026aec009SAmit Daniel Kachhap 
1413e1e4a5fSKrzysztof Kozlowski static const struct regmap_config sec_rtc_regmap_config = {
1423e1e4a5fSKrzysztof Kozlowski 	.reg_bits = 8,
1433e1e4a5fSKrzysztof Kozlowski 	.val_bits = 8,
144b07e2b70SKrzysztof Kozlowski 
145b07e2b70SKrzysztof Kozlowski 	.max_register = SEC_RTC_REG_MAX,
1463e1e4a5fSKrzysztof Kozlowski };
1473e1e4a5fSKrzysztof Kozlowski 
14826aec009SAmit Daniel Kachhap #ifdef CONFIG_OF
14926aec009SAmit Daniel Kachhap /*
15026aec009SAmit Daniel Kachhap  * Only the common platform data elements for s5m8767 are parsed here from the
15126aec009SAmit Daniel Kachhap  * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
15226aec009SAmit Daniel Kachhap  * others have to parse their own platform data elements from device tree.
15326aec009SAmit Daniel Kachhap  *
15426aec009SAmit Daniel Kachhap  * The s5m8767 platform data structure is instantiated here and the drivers for
15526aec009SAmit Daniel Kachhap  * the sub-modules need not instantiate another instance while parsing their
15626aec009SAmit Daniel Kachhap  * platform data.
15726aec009SAmit Daniel Kachhap  */
15826aec009SAmit Daniel Kachhap static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
15926aec009SAmit Daniel Kachhap 					struct device *dev)
16026aec009SAmit Daniel Kachhap {
16126aec009SAmit Daniel Kachhap 	struct sec_platform_data *pd;
16226aec009SAmit Daniel Kachhap 
16326aec009SAmit Daniel Kachhap 	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
16426aec009SAmit Daniel Kachhap 	if (!pd) {
16526aec009SAmit Daniel Kachhap 		dev_err(dev, "could not allocate memory for pdata\n");
16626aec009SAmit Daniel Kachhap 		return ERR_PTR(-ENOMEM);
16726aec009SAmit Daniel Kachhap 	}
16826aec009SAmit Daniel Kachhap 
16926aec009SAmit Daniel Kachhap 	/*
17026aec009SAmit Daniel Kachhap 	 * ToDo: the 'wakeup' member in the platform data is more of a linux
17126aec009SAmit Daniel Kachhap 	 * specfic information. Hence, there is no binding for that yet and
17226aec009SAmit Daniel Kachhap 	 * not parsed here.
17326aec009SAmit Daniel Kachhap 	 */
17426aec009SAmit Daniel Kachhap 
17526aec009SAmit Daniel Kachhap 	return pd;
17626aec009SAmit Daniel Kachhap }
17726aec009SAmit Daniel Kachhap #else
178197bf856SMark Brown static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
17926aec009SAmit Daniel Kachhap 					struct device *dev)
18026aec009SAmit Daniel Kachhap {
181005718c0SWei Yongjun 	return NULL;
18226aec009SAmit Daniel Kachhap }
18326aec009SAmit Daniel Kachhap #endif
18426aec009SAmit Daniel Kachhap 
18526aec009SAmit Daniel Kachhap static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
18626aec009SAmit Daniel Kachhap 						const struct i2c_device_id *id)
18726aec009SAmit Daniel Kachhap {
18826aec009SAmit Daniel Kachhap #ifdef CONFIG_OF
18926aec009SAmit Daniel Kachhap 	if (i2c->dev.of_node) {
19026aec009SAmit Daniel Kachhap 		const struct of_device_id *match;
19126aec009SAmit Daniel Kachhap 		match = of_match_node(sec_dt_match, i2c->dev.of_node);
19226aec009SAmit Daniel Kachhap 		return (int)match->data;
19326aec009SAmit Daniel Kachhap 	}
19426aec009SAmit Daniel Kachhap #endif
19526aec009SAmit Daniel Kachhap 	return (int)id->driver_data;
19626aec009SAmit Daniel Kachhap }
19726aec009SAmit Daniel Kachhap 
19863063bfbSSangbeom Kim static int sec_pmic_probe(struct i2c_client *i2c,
19966c9fbb9SSangbeom Kim 			    const struct i2c_device_id *id)
20066c9fbb9SSangbeom Kim {
201334a41ceSJingoo Han 	struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
2023e5a45f7SKrzysztof Kozlowski 	const struct regmap_config *regmap, *regmap_rtc;
20363063bfbSSangbeom Kim 	struct sec_pmic_dev *sec_pmic;
20466c9fbb9SSangbeom Kim 	int ret;
20566c9fbb9SSangbeom Kim 
20663063bfbSSangbeom Kim 	sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
20766c9fbb9SSangbeom Kim 				GFP_KERNEL);
20863063bfbSSangbeom Kim 	if (sec_pmic == NULL)
20966c9fbb9SSangbeom Kim 		return -ENOMEM;
21066c9fbb9SSangbeom Kim 
21163063bfbSSangbeom Kim 	i2c_set_clientdata(i2c, sec_pmic);
21263063bfbSSangbeom Kim 	sec_pmic->dev = &i2c->dev;
21363063bfbSSangbeom Kim 	sec_pmic->i2c = i2c;
21463063bfbSSangbeom Kim 	sec_pmic->irq = i2c->irq;
21526aec009SAmit Daniel Kachhap 	sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
21666c9fbb9SSangbeom Kim 
21726aec009SAmit Daniel Kachhap 	if (sec_pmic->dev->of_node) {
21826aec009SAmit Daniel Kachhap 		pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
21926aec009SAmit Daniel Kachhap 		if (IS_ERR(pdata)) {
22026aec009SAmit Daniel Kachhap 			ret = PTR_ERR(pdata);
22126aec009SAmit Daniel Kachhap 			return ret;
22226aec009SAmit Daniel Kachhap 		}
22326aec009SAmit Daniel Kachhap 		pdata->device_type = sec_pmic->type;
22426aec009SAmit Daniel Kachhap 	}
22566c9fbb9SSangbeom Kim 	if (pdata) {
22663063bfbSSangbeom Kim 		sec_pmic->device_type = pdata->device_type;
22763063bfbSSangbeom Kim 		sec_pmic->ono = pdata->ono;
22863063bfbSSangbeom Kim 		sec_pmic->irq_base = pdata->irq_base;
22963063bfbSSangbeom Kim 		sec_pmic->wakeup = pdata->wakeup;
23026aec009SAmit Daniel Kachhap 		sec_pmic->pdata = pdata;
23166c9fbb9SSangbeom Kim 	}
23266c9fbb9SSangbeom Kim 
23325f311faSMark Brown 	switch (sec_pmic->device_type) {
23425f311faSMark Brown 	case S2MPS11X:
23525f311faSMark Brown 		regmap = &s2mps11_regmap_config;
2363e5a45f7SKrzysztof Kozlowski 		/*
2373e5a45f7SKrzysztof Kozlowski 		 * The rtc-s5m driver does not support S2MPS11 and there
2383e5a45f7SKrzysztof Kozlowski 		 * is no mfd_cell for S2MPS11 RTC device.
2393e5a45f7SKrzysztof Kozlowski 		 * However we must pass something to devm_regmap_init_i2c()
2403e5a45f7SKrzysztof Kozlowski 		 * so use S5M-like regmap config even though it wouldn't work.
2413e5a45f7SKrzysztof Kozlowski 		 */
2423e5a45f7SKrzysztof Kozlowski 		regmap_rtc = &sec_rtc_regmap_config;
24325f311faSMark Brown 		break;
24425f311faSMark Brown 	case S5M8763X:
24525f311faSMark Brown 		regmap = &s5m8763_regmap_config;
2463e5a45f7SKrzysztof Kozlowski 		regmap_rtc = &sec_rtc_regmap_config;
24725f311faSMark Brown 		break;
24825f311faSMark Brown 	case S5M8767X:
24925f311faSMark Brown 		regmap = &s5m8767_regmap_config;
2503e5a45f7SKrzysztof Kozlowski 		regmap_rtc = &sec_rtc_regmap_config;
25125f311faSMark Brown 		break;
25225f311faSMark Brown 	default:
25325f311faSMark Brown 		regmap = &sec_regmap_config;
2543e5a45f7SKrzysztof Kozlowski 		regmap_rtc = &sec_rtc_regmap_config;
25525f311faSMark Brown 		break;
25625f311faSMark Brown 	}
25725f311faSMark Brown 
2583e1e4a5fSKrzysztof Kozlowski 	sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap);
2593e1e4a5fSKrzysztof Kozlowski 	if (IS_ERR(sec_pmic->regmap_pmic)) {
2603e1e4a5fSKrzysztof Kozlowski 		ret = PTR_ERR(sec_pmic->regmap_pmic);
26166c9fbb9SSangbeom Kim 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
26266c9fbb9SSangbeom Kim 			ret);
26366c9fbb9SSangbeom Kim 		return ret;
26466c9fbb9SSangbeom Kim 	}
26566c9fbb9SSangbeom Kim 
26663063bfbSSangbeom Kim 	sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
26763063bfbSSangbeom Kim 	i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
26866c9fbb9SSangbeom Kim 
2693e5a45f7SKrzysztof Kozlowski 	sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
2703e1e4a5fSKrzysztof Kozlowski 	if (IS_ERR(sec_pmic->regmap_rtc)) {
2713e1e4a5fSKrzysztof Kozlowski 		ret = PTR_ERR(sec_pmic->regmap_rtc);
2723e1e4a5fSKrzysztof Kozlowski 		dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
2733e1e4a5fSKrzysztof Kozlowski 			ret);
2743e1e4a5fSKrzysztof Kozlowski 		return ret;
2753e1e4a5fSKrzysztof Kozlowski 	}
2763e1e4a5fSKrzysztof Kozlowski 
27766c9fbb9SSangbeom Kim 	if (pdata && pdata->cfg_pmic_irq)
27866c9fbb9SSangbeom Kim 		pdata->cfg_pmic_irq();
27966c9fbb9SSangbeom Kim 
28063063bfbSSangbeom Kim 	sec_irq_init(sec_pmic);
28166c9fbb9SSangbeom Kim 
28263063bfbSSangbeom Kim 	pm_runtime_set_active(sec_pmic->dev);
28366c9fbb9SSangbeom Kim 
28463063bfbSSangbeom Kim 	switch (sec_pmic->device_type) {
28566c9fbb9SSangbeom Kim 	case S5M8751X:
28663063bfbSSangbeom Kim 		ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs,
2870848c94fSMark Brown 				      ARRAY_SIZE(s5m8751_devs), NULL, 0, NULL);
28866c9fbb9SSangbeom Kim 		break;
28966c9fbb9SSangbeom Kim 	case S5M8763X:
29063063bfbSSangbeom Kim 		ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs,
2910848c94fSMark Brown 				      ARRAY_SIZE(s5m8763_devs), NULL, 0, NULL);
29266c9fbb9SSangbeom Kim 		break;
29366c9fbb9SSangbeom Kim 	case S5M8767X:
29463063bfbSSangbeom Kim 		ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
2950848c94fSMark Brown 				      ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
29666c9fbb9SSangbeom Kim 		break;
2979b6d1343SSangbeom Kim 	case S2MPS11X:
2989b6d1343SSangbeom Kim 		ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
2990848c94fSMark Brown 				      ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
3009b6d1343SSangbeom Kim 		break;
30166c9fbb9SSangbeom Kim 	default:
30266c9fbb9SSangbeom Kim 		/* If this happens the probe function is problem */
30366c9fbb9SSangbeom Kim 		BUG();
30466c9fbb9SSangbeom Kim 	}
30566c9fbb9SSangbeom Kim 
30615447a46SLeon Romanovsky 	if (ret)
30766c9fbb9SSangbeom Kim 		goto err;
30866c9fbb9SSangbeom Kim 
309f6d6daafSKrzysztof Kozlowski 	device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
310f6d6daafSKrzysztof Kozlowski 
31166c9fbb9SSangbeom Kim 	return ret;
31266c9fbb9SSangbeom Kim 
31366c9fbb9SSangbeom Kim err:
31463063bfbSSangbeom Kim 	sec_irq_exit(sec_pmic);
31563063bfbSSangbeom Kim 	i2c_unregister_device(sec_pmic->rtc);
31666c9fbb9SSangbeom Kim 	return ret;
31766c9fbb9SSangbeom Kim }
31866c9fbb9SSangbeom Kim 
31963063bfbSSangbeom Kim static int sec_pmic_remove(struct i2c_client *i2c)
32066c9fbb9SSangbeom Kim {
32163063bfbSSangbeom Kim 	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
32266c9fbb9SSangbeom Kim 
32363063bfbSSangbeom Kim 	mfd_remove_devices(sec_pmic->dev);
32463063bfbSSangbeom Kim 	sec_irq_exit(sec_pmic);
32563063bfbSSangbeom Kim 	i2c_unregister_device(sec_pmic->rtc);
32666c9fbb9SSangbeom Kim 	return 0;
32766c9fbb9SSangbeom Kim }
32866c9fbb9SSangbeom Kim 
3298321bbf8SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP
330f6d6daafSKrzysztof Kozlowski static int sec_pmic_suspend(struct device *dev)
331f6d6daafSKrzysztof Kozlowski {
332f6d6daafSKrzysztof Kozlowski 	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
333f6d6daafSKrzysztof Kozlowski 	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
334f6d6daafSKrzysztof Kozlowski 
335f6d6daafSKrzysztof Kozlowski 	if (device_may_wakeup(dev)) {
336f6d6daafSKrzysztof Kozlowski 		enable_irq_wake(sec_pmic->irq);
337f6d6daafSKrzysztof Kozlowski 		/*
338f6d6daafSKrzysztof Kozlowski 		 * PMIC IRQ must be disabled during suspend for RTC alarm
339f6d6daafSKrzysztof Kozlowski 		 * to work properly.
340f6d6daafSKrzysztof Kozlowski 		 * When device is woken up from suspend by RTC Alarm, an
341f6d6daafSKrzysztof Kozlowski 		 * interrupt occurs before resuming I2C bus controller.
342f6d6daafSKrzysztof Kozlowski 		 * The interrupt is handled by regmap_irq_thread which tries
343f6d6daafSKrzysztof Kozlowski 		 * to read RTC registers. This read fails (I2C is still
344f6d6daafSKrzysztof Kozlowski 		 * suspended) and RTC Alarm interrupt is disabled.
345f6d6daafSKrzysztof Kozlowski 		 */
346f6d6daafSKrzysztof Kozlowski 		disable_irq(sec_pmic->irq);
347f6d6daafSKrzysztof Kozlowski 	}
348f6d6daafSKrzysztof Kozlowski 
349f6d6daafSKrzysztof Kozlowski 	return 0;
350f6d6daafSKrzysztof Kozlowski }
351f6d6daafSKrzysztof Kozlowski 
352f6d6daafSKrzysztof Kozlowski static int sec_pmic_resume(struct device *dev)
353f6d6daafSKrzysztof Kozlowski {
354f6d6daafSKrzysztof Kozlowski 	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
355f6d6daafSKrzysztof Kozlowski 	struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
356f6d6daafSKrzysztof Kozlowski 
357f6d6daafSKrzysztof Kozlowski 	if (device_may_wakeup(dev)) {
358f6d6daafSKrzysztof Kozlowski 		disable_irq_wake(sec_pmic->irq);
359f6d6daafSKrzysztof Kozlowski 		enable_irq(sec_pmic->irq);
360f6d6daafSKrzysztof Kozlowski 	}
361f6d6daafSKrzysztof Kozlowski 
362f6d6daafSKrzysztof Kozlowski 	return 0;
363f6d6daafSKrzysztof Kozlowski }
3648321bbf8SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */
365f6d6daafSKrzysztof Kozlowski 
366f6d6daafSKrzysztof Kozlowski static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
367f6d6daafSKrzysztof Kozlowski 
36863063bfbSSangbeom Kim static const struct i2c_device_id sec_pmic_id[] = {
36963063bfbSSangbeom Kim 	{ "sec_pmic", 0 },
37066c9fbb9SSangbeom Kim 	{ }
37166c9fbb9SSangbeom Kim };
37263063bfbSSangbeom Kim MODULE_DEVICE_TABLE(i2c, sec_pmic_id);
37366c9fbb9SSangbeom Kim 
37463063bfbSSangbeom Kim static struct i2c_driver sec_pmic_driver = {
37566c9fbb9SSangbeom Kim 	.driver = {
37663063bfbSSangbeom Kim 		   .name = "sec_pmic",
37766c9fbb9SSangbeom Kim 		   .owner = THIS_MODULE,
378f6d6daafSKrzysztof Kozlowski 		   .pm = &sec_pmic_pm_ops,
37926aec009SAmit Daniel Kachhap 		   .of_match_table = of_match_ptr(sec_dt_match),
38066c9fbb9SSangbeom Kim 	},
38163063bfbSSangbeom Kim 	.probe = sec_pmic_probe,
38263063bfbSSangbeom Kim 	.remove = sec_pmic_remove,
38363063bfbSSangbeom Kim 	.id_table = sec_pmic_id,
38466c9fbb9SSangbeom Kim };
38566c9fbb9SSangbeom Kim 
38663063bfbSSangbeom Kim static int __init sec_pmic_init(void)
38766c9fbb9SSangbeom Kim {
38863063bfbSSangbeom Kim 	return i2c_add_driver(&sec_pmic_driver);
38966c9fbb9SSangbeom Kim }
39066c9fbb9SSangbeom Kim 
39163063bfbSSangbeom Kim subsys_initcall(sec_pmic_init);
39266c9fbb9SSangbeom Kim 
39363063bfbSSangbeom Kim static void __exit sec_pmic_exit(void)
39466c9fbb9SSangbeom Kim {
39563063bfbSSangbeom Kim 	i2c_del_driver(&sec_pmic_driver);
39666c9fbb9SSangbeom Kim }
39763063bfbSSangbeom Kim module_exit(sec_pmic_exit);
39866c9fbb9SSangbeom Kim 
39966c9fbb9SSangbeom Kim MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
40066c9fbb9SSangbeom Kim MODULE_DESCRIPTION("Core support for the S5M MFD");
40166c9fbb9SSangbeom Kim MODULE_LICENSE("GPL");
402