162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Core driver for TI TPS65090 PMIC family
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/irq.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/mutex.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/i2c.h>
1762306a36Sopenharmony_ci#include <linux/mfd/core.h>
1862306a36Sopenharmony_ci#include <linux/mfd/tps65090.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/err.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define NUM_INT_REG 2
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define TPS65090_INT1_MASK_VAC_STATUS_CHANGE		1
2562306a36Sopenharmony_ci#define TPS65090_INT1_MASK_VSYS_STATUS_CHANGE		2
2662306a36Sopenharmony_ci#define TPS65090_INT1_MASK_BAT_STATUS_CHANGE		3
2762306a36Sopenharmony_ci#define TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE	4
2862306a36Sopenharmony_ci#define TPS65090_INT1_MASK_CHARGING_COMPLETE		5
2962306a36Sopenharmony_ci#define TPS65090_INT1_MASK_OVERLOAD_DCDC1		6
3062306a36Sopenharmony_ci#define TPS65090_INT1_MASK_OVERLOAD_DCDC2		7
3162306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_DCDC3		0
3262306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET1		1
3362306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET2		2
3462306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET3		3
3562306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET4		4
3662306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET5		5
3762306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET6		6
3862306a36Sopenharmony_ci#define TPS65090_INT2_MASK_OVERLOAD_FET7		7
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic const struct resource charger_resources[] = {
4162306a36Sopenharmony_ci	{
4262306a36Sopenharmony_ci		.start  = TPS65090_IRQ_VAC_STATUS_CHANGE,
4362306a36Sopenharmony_ci		.end    = TPS65090_IRQ_VAC_STATUS_CHANGE,
4462306a36Sopenharmony_ci		.flags  = IORESOURCE_IRQ,
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cienum tps65090_cells {
4962306a36Sopenharmony_ci	PMIC = 0,
5062306a36Sopenharmony_ci	CHARGER = 1,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct mfd_cell tps65090s[] = {
5462306a36Sopenharmony_ci	[PMIC] = {
5562306a36Sopenharmony_ci		.name = "tps65090-pmic",
5662306a36Sopenharmony_ci	},
5762306a36Sopenharmony_ci	[CHARGER] = {
5862306a36Sopenharmony_ci		.name = "tps65090-charger",
5962306a36Sopenharmony_ci		.num_resources = ARRAY_SIZE(charger_resources),
6062306a36Sopenharmony_ci		.resources = &charger_resources[0],
6162306a36Sopenharmony_ci		.of_compatible = "ti,tps65090-charger",
6262306a36Sopenharmony_ci	},
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic const struct regmap_irq tps65090_irqs[] = {
6662306a36Sopenharmony_ci	/* INT1 IRQs*/
6762306a36Sopenharmony_ci	[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
6862306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
6962306a36Sopenharmony_ci	},
7062306a36Sopenharmony_ci	[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
7162306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
7262306a36Sopenharmony_ci	},
7362306a36Sopenharmony_ci	[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
7462306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
7562306a36Sopenharmony_ci	},
7662306a36Sopenharmony_ci	[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
7762306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
7862306a36Sopenharmony_ci	},
7962306a36Sopenharmony_ci	[TPS65090_IRQ_CHARGING_COMPLETE] = {
8062306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
8162306a36Sopenharmony_ci	},
8262306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_DCDC1] = {
8362306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
8462306a36Sopenharmony_ci	},
8562306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_DCDC2] = {
8662306a36Sopenharmony_ci		.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
8762306a36Sopenharmony_ci	},
8862306a36Sopenharmony_ci	/* INT2 IRQs*/
8962306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_DCDC3] = {
9062306a36Sopenharmony_ci		.reg_offset = 1,
9162306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
9262306a36Sopenharmony_ci	},
9362306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET1] = {
9462306a36Sopenharmony_ci		.reg_offset = 1,
9562306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
9662306a36Sopenharmony_ci	},
9762306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET2] = {
9862306a36Sopenharmony_ci		.reg_offset = 1,
9962306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
10062306a36Sopenharmony_ci	},
10162306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET3] = {
10262306a36Sopenharmony_ci		.reg_offset = 1,
10362306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET4] = {
10662306a36Sopenharmony_ci		.reg_offset = 1,
10762306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
10862306a36Sopenharmony_ci	},
10962306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET5] = {
11062306a36Sopenharmony_ci		.reg_offset = 1,
11162306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
11262306a36Sopenharmony_ci	},
11362306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET6] = {
11462306a36Sopenharmony_ci		.reg_offset = 1,
11562306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
11662306a36Sopenharmony_ci	},
11762306a36Sopenharmony_ci	[TPS65090_IRQ_OVERLOAD_FET7] = {
11862306a36Sopenharmony_ci		.reg_offset = 1,
11962306a36Sopenharmony_ci		.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
12062306a36Sopenharmony_ci	},
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic struct regmap_irq_chip tps65090_irq_chip = {
12462306a36Sopenharmony_ci	.name = "tps65090",
12562306a36Sopenharmony_ci	.irqs = tps65090_irqs,
12662306a36Sopenharmony_ci	.num_irqs = ARRAY_SIZE(tps65090_irqs),
12762306a36Sopenharmony_ci	.num_regs = NUM_INT_REG,
12862306a36Sopenharmony_ci	.status_base = TPS65090_REG_INTR_STS,
12962306a36Sopenharmony_ci	.unmask_base = TPS65090_REG_INTR_MASK,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic bool is_volatile_reg(struct device *dev, unsigned int reg)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	/* Nearly all registers have status bits mixed in, except a few */
13562306a36Sopenharmony_ci	switch (reg) {
13662306a36Sopenharmony_ci	case TPS65090_REG_INTR_MASK:
13762306a36Sopenharmony_ci	case TPS65090_REG_INTR_MASK2:
13862306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL0:
13962306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL1:
14062306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL2:
14162306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL3:
14262306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL4:
14362306a36Sopenharmony_ci	case TPS65090_REG_CG_CTRL5:
14462306a36Sopenharmony_ci		return false;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	return true;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic const struct regmap_config tps65090_regmap_config = {
15062306a36Sopenharmony_ci	.reg_bits = 8,
15162306a36Sopenharmony_ci	.val_bits = 8,
15262306a36Sopenharmony_ci	.max_register = TPS65090_MAX_REG,
15362306a36Sopenharmony_ci	.num_reg_defaults_raw = TPS65090_NUM_REGS,
15462306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
15562306a36Sopenharmony_ci	.volatile_reg = is_volatile_reg,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#ifdef CONFIG_OF
15962306a36Sopenharmony_cistatic const struct of_device_id tps65090_of_match[] = {
16062306a36Sopenharmony_ci	{ .compatible = "ti,tps65090",},
16162306a36Sopenharmony_ci	{},
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci#endif
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int tps65090_i2c_probe(struct i2c_client *client)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
16862306a36Sopenharmony_ci	int irq_base = 0;
16962306a36Sopenharmony_ci	struct tps65090 *tps65090;
17062306a36Sopenharmony_ci	int ret;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!pdata && !client->dev.of_node) {
17362306a36Sopenharmony_ci		dev_err(&client->dev,
17462306a36Sopenharmony_ci			"tps65090 requires platform data or of_node\n");
17562306a36Sopenharmony_ci		return -EINVAL;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (pdata)
17962306a36Sopenharmony_ci		irq_base = pdata->irq_base;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
18262306a36Sopenharmony_ci	if (!tps65090)
18362306a36Sopenharmony_ci		return -ENOMEM;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	tps65090->dev = &client->dev;
18662306a36Sopenharmony_ci	i2c_set_clientdata(client, tps65090);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config);
18962306a36Sopenharmony_ci	if (IS_ERR(tps65090->rmap)) {
19062306a36Sopenharmony_ci		ret = PTR_ERR(tps65090->rmap);
19162306a36Sopenharmony_ci		dev_err(&client->dev, "regmap_init failed with err: %d\n", ret);
19262306a36Sopenharmony_ci		return ret;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (client->irq) {
19662306a36Sopenharmony_ci		ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
19762306a36Sopenharmony_ci					  IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
19862306a36Sopenharmony_ci					  &tps65090_irq_chip, &tps65090->irq_data);
19962306a36Sopenharmony_ci		if (ret) {
20062306a36Sopenharmony_ci			dev_err(&client->dev,
20162306a36Sopenharmony_ci				"IRQ init failed with err: %d\n", ret);
20262306a36Sopenharmony_ci			return ret;
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci	} else {
20562306a36Sopenharmony_ci		/* Don't tell children they have an IRQ that'll never fire */
20662306a36Sopenharmony_ci		tps65090s[CHARGER].num_resources = 0;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
21062306a36Sopenharmony_ci			      ARRAY_SIZE(tps65090s), NULL,
21162306a36Sopenharmony_ci			      0, regmap_irq_get_domain(tps65090->irq_data));
21262306a36Sopenharmony_ci	if (ret) {
21362306a36Sopenharmony_ci		dev_err(&client->dev, "add mfd devices failed with err: %d\n",
21462306a36Sopenharmony_ci			ret);
21562306a36Sopenharmony_ci		goto err_irq_exit;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cierr_irq_exit:
22162306a36Sopenharmony_ci	if (client->irq)
22262306a36Sopenharmony_ci		regmap_del_irq_chip(client->irq, tps65090->irq_data);
22362306a36Sopenharmony_ci	return ret;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic const struct i2c_device_id tps65090_id_table[] = {
22862306a36Sopenharmony_ci	{ "tps65090", 0 },
22962306a36Sopenharmony_ci	{ },
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic struct i2c_driver tps65090_driver = {
23362306a36Sopenharmony_ci	.driver	= {
23462306a36Sopenharmony_ci		.name	= "tps65090",
23562306a36Sopenharmony_ci		.suppress_bind_attrs = true,
23662306a36Sopenharmony_ci		.of_match_table = of_match_ptr(tps65090_of_match),
23762306a36Sopenharmony_ci	},
23862306a36Sopenharmony_ci	.probe		= tps65090_i2c_probe,
23962306a36Sopenharmony_ci	.id_table	= tps65090_id_table,
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int __init tps65090_init(void)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	return i2c_add_driver(&tps65090_driver);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_cisubsys_initcall(tps65090_init);
247