xref: /openbmc/linux/drivers/mfd/tps65090.c (revision dc0c386e)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23c33be06SVenu Byravarasu /*
33c33be06SVenu Byravarasu  * Core driver for TI TPS65090 PMIC family
43c33be06SVenu Byravarasu  *
53c33be06SVenu Byravarasu  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
626fce5e0SPaul Gortmaker  *
726fce5e0SPaul Gortmaker  * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
83c33be06SVenu Byravarasu  */
93c33be06SVenu Byravarasu 
103c33be06SVenu Byravarasu #include <linux/interrupt.h>
113c33be06SVenu Byravarasu #include <linux/irq.h>
123c33be06SVenu Byravarasu #include <linux/kernel.h>
1326fce5e0SPaul Gortmaker #include <linux/init.h>
143c33be06SVenu Byravarasu #include <linux/mutex.h>
153c33be06SVenu Byravarasu #include <linux/slab.h>
163c33be06SVenu Byravarasu #include <linux/i2c.h>
173c33be06SVenu Byravarasu #include <linux/mfd/core.h>
183c33be06SVenu Byravarasu #include <linux/mfd/tps65090.h>
1940719314SLaxman Dewangan #include <linux/of.h>
203c33be06SVenu Byravarasu #include <linux/err.h>
213c33be06SVenu Byravarasu 
223c33be06SVenu Byravarasu #define NUM_INT_REG 2
233c33be06SVenu Byravarasu 
24759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_VAC_STATUS_CHANGE		1
25759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE		2
26759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_BAT_STATUS_CHANGE		3
27759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE	4
28759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_CHARGING_COMPLETE		5
29759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_OVERLOAD_DCDC1		6
30759f2598SLaxman Dewangan #define TPS65090_INT1_MASK_OVERLOAD_DCDC2		7
31759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_DCDC3		0
32759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET1		1
33759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET2		2
34759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET3		3
35759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET4		4
36759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET5		5
37759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET6		6
38759f2598SLaxman Dewangan #define TPS65090_INT2_MASK_OVERLOAD_FET7		7
393c33be06SVenu Byravarasu 
40c4a164f4SRikard Falkeborn static const struct resource charger_resources[] = {
4136c772e3SRhyland Klein 	{
4236c772e3SRhyland Klein 		.start  = TPS65090_IRQ_VAC_STATUS_CHANGE,
4336c772e3SRhyland Klein 		.end    = TPS65090_IRQ_VAC_STATUS_CHANGE,
4436c772e3SRhyland Klein 		.flags  = IORESOURCE_IRQ,
4536c772e3SRhyland Klein 	}
4636c772e3SRhyland Klein };
4736c772e3SRhyland Klein 
487d811771SDoug Anderson enum tps65090_cells {
497d811771SDoug Anderson 	PMIC = 0,
507d811771SDoug Anderson 	CHARGER = 1,
517d811771SDoug Anderson };
527d811771SDoug Anderson 
537d811771SDoug Anderson static struct mfd_cell tps65090s[] = {
547d811771SDoug Anderson 	[PMIC] = {
55b7e53786SVenu Byravarasu 		.name = "tps65090-pmic",
563c33be06SVenu Byravarasu 	},
577d811771SDoug Anderson 	[CHARGER] = {
58e2e8ffc9SLaxman Dewangan 		.name = "tps65090-charger",
5936c772e3SRhyland Klein 		.num_resources = ARRAY_SIZE(charger_resources),
6036c772e3SRhyland Klein 		.resources = &charger_resources[0],
61b50cf35bSRhyland Klein 		.of_compatible = "ti,tps65090-charger",
623c33be06SVenu Byravarasu 	},
633c33be06SVenu Byravarasu };
643c33be06SVenu Byravarasu 
65759f2598SLaxman Dewangan static const struct regmap_irq tps65090_irqs[] = {
66759f2598SLaxman Dewangan 	/* INT1 IRQs*/
67759f2598SLaxman Dewangan 	[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
68759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
69759f2598SLaxman Dewangan 	},
70759f2598SLaxman Dewangan 	[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
71759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
72759f2598SLaxman Dewangan 	},
73759f2598SLaxman Dewangan 	[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
74759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
75759f2598SLaxman Dewangan 	},
76759f2598SLaxman Dewangan 	[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
77759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
78759f2598SLaxman Dewangan 	},
79759f2598SLaxman Dewangan 	[TPS65090_IRQ_CHARGING_COMPLETE] = {
80759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
81759f2598SLaxman Dewangan 	},
82759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_DCDC1] = {
83759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
84759f2598SLaxman Dewangan 	},
85759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_DCDC2] = {
86759f2598SLaxman Dewangan 		.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
87759f2598SLaxman Dewangan 	},
88759f2598SLaxman Dewangan 	/* INT2 IRQs*/
89759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_DCDC3] = {
90759f2598SLaxman Dewangan 		.reg_offset = 1,
91759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
92759f2598SLaxman Dewangan 	},
93759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET1] = {
94759f2598SLaxman Dewangan 		.reg_offset = 1,
95759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
96759f2598SLaxman Dewangan 	},
97759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET2] = {
98759f2598SLaxman Dewangan 		.reg_offset = 1,
99759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
100759f2598SLaxman Dewangan 	},
101759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET3] = {
102759f2598SLaxman Dewangan 		.reg_offset = 1,
103759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
104759f2598SLaxman Dewangan 	},
105759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET4] = {
106759f2598SLaxman Dewangan 		.reg_offset = 1,
107759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
108759f2598SLaxman Dewangan 	},
109759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET5] = {
110759f2598SLaxman Dewangan 		.reg_offset = 1,
111759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
112759f2598SLaxman Dewangan 	},
113759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET6] = {
114759f2598SLaxman Dewangan 		.reg_offset = 1,
115759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
116759f2598SLaxman Dewangan 	},
117759f2598SLaxman Dewangan 	[TPS65090_IRQ_OVERLOAD_FET7] = {
118759f2598SLaxman Dewangan 		.reg_offset = 1,
119759f2598SLaxman Dewangan 		.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
120759f2598SLaxman Dewangan 	},
121759f2598SLaxman Dewangan };
1223c33be06SVenu Byravarasu 
123759f2598SLaxman Dewangan static struct regmap_irq_chip tps65090_irq_chip = {
124759f2598SLaxman Dewangan 	.name = "tps65090",
125759f2598SLaxman Dewangan 	.irqs = tps65090_irqs,
126759f2598SLaxman Dewangan 	.num_irqs = ARRAY_SIZE(tps65090_irqs),
127759f2598SLaxman Dewangan 	.num_regs = NUM_INT_REG,
128c42ba72eSDoug Anderson 	.status_base = TPS65090_REG_INTR_STS,
12950ff095bSAidan MacDonald 	.unmask_base = TPS65090_REG_INTR_MASK,
130759f2598SLaxman Dewangan };
1313c33be06SVenu Byravarasu 
is_volatile_reg(struct device * dev,unsigned int reg)1323c33be06SVenu Byravarasu static bool is_volatile_reg(struct device *dev, unsigned int reg)
1333c33be06SVenu Byravarasu {
134c42ba72eSDoug Anderson 	/* Nearly all registers have status bits mixed in, except a few */
135c42ba72eSDoug Anderson 	switch (reg) {
136c42ba72eSDoug Anderson 	case TPS65090_REG_INTR_MASK:
137c42ba72eSDoug Anderson 	case TPS65090_REG_INTR_MASK2:
138c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL0:
139c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL1:
140c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL2:
141c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL3:
142c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL4:
143c42ba72eSDoug Anderson 	case TPS65090_REG_CG_CTRL5:
1443c33be06SVenu Byravarasu 		return false;
1453c33be06SVenu Byravarasu 	}
146c42ba72eSDoug Anderson 	return true;
147c42ba72eSDoug Anderson }
1483c33be06SVenu Byravarasu 
1493c33be06SVenu Byravarasu static const struct regmap_config tps65090_regmap_config = {
1503c33be06SVenu Byravarasu 	.reg_bits = 8,
1513c33be06SVenu Byravarasu 	.val_bits = 8,
1525c148890SMaciej S. Szmigiero 	.max_register = TPS65090_MAX_REG,
1535c148890SMaciej S. Szmigiero 	.num_reg_defaults_raw = TPS65090_NUM_REGS,
1543c33be06SVenu Byravarasu 	.cache_type = REGCACHE_RBTREE,
1553c33be06SVenu Byravarasu 	.volatile_reg = is_volatile_reg,
1563c33be06SVenu Byravarasu };
1573c33be06SVenu Byravarasu 
15840719314SLaxman Dewangan #ifdef CONFIG_OF
15940719314SLaxman Dewangan static const struct of_device_id tps65090_of_match[] = {
16040719314SLaxman Dewangan 	{ .compatible = "ti,tps65090",},
16140719314SLaxman Dewangan 	{},
16240719314SLaxman Dewangan };
16340719314SLaxman Dewangan #endif
16440719314SLaxman Dewangan 
tps65090_i2c_probe(struct i2c_client * client)165b6325098SUwe Kleine-König static int tps65090_i2c_probe(struct i2c_client *client)
1663c33be06SVenu Byravarasu {
167334a41ceSJingoo Han 	struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
16840719314SLaxman Dewangan 	int irq_base = 0;
1693c33be06SVenu Byravarasu 	struct tps65090 *tps65090;
1703c33be06SVenu Byravarasu 	int ret;
1713c33be06SVenu Byravarasu 
17240719314SLaxman Dewangan 	if (!pdata && !client->dev.of_node) {
17340719314SLaxman Dewangan 		dev_err(&client->dev,
17440719314SLaxman Dewangan 			"tps65090 requires platform data or of_node\n");
1753c33be06SVenu Byravarasu 		return -EINVAL;
1763c33be06SVenu Byravarasu 	}
1773c33be06SVenu Byravarasu 
17840719314SLaxman Dewangan 	if (pdata)
17940719314SLaxman Dewangan 		irq_base = pdata->irq_base;
18040719314SLaxman Dewangan 
181e8e6f047SLaxman Dewangan 	tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
1828a232f0bSMarkus Elfring 	if (!tps65090)
1833c33be06SVenu Byravarasu 		return -ENOMEM;
1843c33be06SVenu Byravarasu 
1853c33be06SVenu Byravarasu 	tps65090->dev = &client->dev;
1863c33be06SVenu Byravarasu 	i2c_set_clientdata(client, tps65090);
1873c33be06SVenu Byravarasu 
1883863db3eSLaxman Dewangan 	tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config);
1893c33be06SVenu Byravarasu 	if (IS_ERR(tps65090->rmap)) {
190b683a0a6SAxel Lin 		ret = PTR_ERR(tps65090->rmap);
191b683a0a6SAxel Lin 		dev_err(&client->dev, "regmap_init failed with err: %d\n", ret);
192759f2598SLaxman Dewangan 		return ret;
193759f2598SLaxman Dewangan 	}
194759f2598SLaxman Dewangan 
195759f2598SLaxman Dewangan 	if (client->irq) {
196759f2598SLaxman Dewangan 		ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
19740719314SLaxman Dewangan 					  IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
198759f2598SLaxman Dewangan 					  &tps65090_irq_chip, &tps65090->irq_data);
199759f2598SLaxman Dewangan 		if (ret) {
200759f2598SLaxman Dewangan 			dev_err(&client->dev,
201759f2598SLaxman Dewangan 				"IRQ init failed with err: %d\n", ret);
202759f2598SLaxman Dewangan 			return ret;
203759f2598SLaxman Dewangan 		}
2047d811771SDoug Anderson 	} else {
2057d811771SDoug Anderson 		/* Don't tell children they have an IRQ that'll never fire */
2067d811771SDoug Anderson 		tps65090s[CHARGER].num_resources = 0;
207b683a0a6SAxel Lin 	}
2083c33be06SVenu Byravarasu 
2093c33be06SVenu Byravarasu 	ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
210759f2598SLaxman Dewangan 			      ARRAY_SIZE(tps65090s), NULL,
2114f979ed5SLaxman Dewangan 			      0, regmap_irq_get_domain(tps65090->irq_data));
2123c33be06SVenu Byravarasu 	if (ret) {
2133c33be06SVenu Byravarasu 		dev_err(&client->dev, "add mfd devices failed with err: %d\n",
2143c33be06SVenu Byravarasu 			ret);
2151d88f7a0SAxel Lin 		goto err_irq_exit;
2163c33be06SVenu Byravarasu 	}
2173c33be06SVenu Byravarasu 
2183c33be06SVenu Byravarasu 	return 0;
2193c33be06SVenu Byravarasu 
2203c33be06SVenu Byravarasu err_irq_exit:
2213c33be06SVenu Byravarasu 	if (client->irq)
222759f2598SLaxman Dewangan 		regmap_del_irq_chip(client->irq, tps65090->irq_data);
2233c33be06SVenu Byravarasu 	return ret;
2243c33be06SVenu Byravarasu }
2253c33be06SVenu Byravarasu 
2263c33be06SVenu Byravarasu 
2273c33be06SVenu Byravarasu static const struct i2c_device_id tps65090_id_table[] = {
2283c33be06SVenu Byravarasu 	{ "tps65090", 0 },
2293c33be06SVenu Byravarasu 	{ },
2303c33be06SVenu Byravarasu };
2313c33be06SVenu Byravarasu 
2323c33be06SVenu Byravarasu static struct i2c_driver tps65090_driver = {
2333c33be06SVenu Byravarasu 	.driver	= {
2343c33be06SVenu Byravarasu 		.name	= "tps65090",
23526fce5e0SPaul Gortmaker 		.suppress_bind_attrs = true,
23640719314SLaxman Dewangan 		.of_match_table = of_match_ptr(tps65090_of_match),
2373c33be06SVenu Byravarasu 	},
238*9816d859SUwe Kleine-König 	.probe		= tps65090_i2c_probe,
2393c33be06SVenu Byravarasu 	.id_table	= tps65090_id_table,
2403c33be06SVenu Byravarasu };
2413c33be06SVenu Byravarasu 
tps65090_init(void)2423c33be06SVenu Byravarasu static int __init tps65090_init(void)
2433c33be06SVenu Byravarasu {
2443c33be06SVenu Byravarasu 	return i2c_add_driver(&tps65090_driver);
2453c33be06SVenu Byravarasu }
2463c33be06SVenu Byravarasu subsys_initcall(tps65090_init);
247