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