162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Core driver for TI TPS6586x PMIC family
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2010 CompuLab Ltd.
662306a36Sopenharmony_ci * Mike Rapoport <mike@compulab.co.il>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on da903x.c.
962306a36Sopenharmony_ci * Copyright (C) 2008 Compulab, Ltd.
1062306a36Sopenharmony_ci * Mike Rapoport <mike@compulab.co.il>
1162306a36Sopenharmony_ci * Copyright (C) 2006-2008 Marvell International Ltd.
1262306a36Sopenharmony_ci * Eric Miao <eric.miao@marvell.com>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/irq.h>
1762306a36Sopenharmony_ci#include <linux/irqdomain.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/mutex.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/err.h>
2362306a36Sopenharmony_ci#include <linux/i2c.h>
2462306a36Sopenharmony_ci#include <linux/platform_device.h>
2562306a36Sopenharmony_ci#include <linux/regmap.h>
2662306a36Sopenharmony_ci#include <linux/of.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/mfd/core.h>
2962306a36Sopenharmony_ci#include <linux/mfd/tps6586x.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define TPS6586X_SUPPLYENE	0x14
3262306a36Sopenharmony_ci#define EXITSLREQ_BIT		BIT(1)
3362306a36Sopenharmony_ci#define SLEEP_MODE_BIT		BIT(3)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* interrupt control registers */
3662306a36Sopenharmony_ci#define TPS6586X_INT_ACK1	0xb5
3762306a36Sopenharmony_ci#define TPS6586X_INT_ACK2	0xb6
3862306a36Sopenharmony_ci#define TPS6586X_INT_ACK3	0xb7
3962306a36Sopenharmony_ci#define TPS6586X_INT_ACK4	0xb8
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* interrupt mask registers */
4262306a36Sopenharmony_ci#define TPS6586X_INT_MASK1	0xb0
4362306a36Sopenharmony_ci#define TPS6586X_INT_MASK2	0xb1
4462306a36Sopenharmony_ci#define TPS6586X_INT_MASK3	0xb2
4562306a36Sopenharmony_ci#define TPS6586X_INT_MASK4	0xb3
4662306a36Sopenharmony_ci#define TPS6586X_INT_MASK5	0xb4
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* device id */
4962306a36Sopenharmony_ci#define TPS6586X_VERSIONCRC	0xcd
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Maximum register */
5262306a36Sopenharmony_ci#define TPS6586X_MAX_REGISTER	TPS6586X_VERSIONCRC
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct tps6586x_irq_data {
5562306a36Sopenharmony_ci	u8	mask_reg;
5662306a36Sopenharmony_ci	u8	mask_mask;
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define TPS6586X_IRQ(_reg, _mask)				\
6062306a36Sopenharmony_ci	{							\
6162306a36Sopenharmony_ci		.mask_reg = (_reg) - TPS6586X_INT_MASK1,	\
6262306a36Sopenharmony_ci		.mask_mask = (_mask),				\
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic const struct tps6586x_irq_data tps6586x_irqs[] = {
6662306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_0]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0),
6762306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_1]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1),
6862306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_2]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2),
6962306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_3]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3),
7062306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_4]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4),
7162306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_5]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5),
7262306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_6]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6),
7362306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_7]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7),
7462306a36Sopenharmony_ci	[TPS6586X_INT_COMP_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0),
7562306a36Sopenharmony_ci	[TPS6586X_INT_ADC]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1),
7662306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_8]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2),
7762306a36Sopenharmony_ci	[TPS6586X_INT_PLDO_9]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3),
7862306a36Sopenharmony_ci	[TPS6586X_INT_PSM_0]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4),
7962306a36Sopenharmony_ci	[TPS6586X_INT_PSM_1]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5),
8062306a36Sopenharmony_ci	[TPS6586X_INT_PSM_2]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6),
8162306a36Sopenharmony_ci	[TPS6586X_INT_PSM_3]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7),
8262306a36Sopenharmony_ci	[TPS6586X_INT_RTC_ALM1]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4),
8362306a36Sopenharmony_ci	[TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03),
8462306a36Sopenharmony_ci	[TPS6586X_INT_USB_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2),
8562306a36Sopenharmony_ci	[TPS6586X_INT_AC_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3),
8662306a36Sopenharmony_ci	[TPS6586X_INT_BAT_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0),
8762306a36Sopenharmony_ci	[TPS6586X_INT_CHG_STAT]	= TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc),
8862306a36Sopenharmony_ci	[TPS6586X_INT_CHG_TEMP]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06),
8962306a36Sopenharmony_ci	[TPS6586X_INT_PP]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0),
9062306a36Sopenharmony_ci	[TPS6586X_INT_RESUME]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5),
9162306a36Sopenharmony_ci	[TPS6586X_INT_LOW_SYS]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6),
9262306a36Sopenharmony_ci	[TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1),
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const struct resource tps6586x_rtc_resources[] = {
9662306a36Sopenharmony_ci	{
9762306a36Sopenharmony_ci		.start  = TPS6586X_INT_RTC_ALM1,
9862306a36Sopenharmony_ci		.end	= TPS6586X_INT_RTC_ALM1,
9962306a36Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
10062306a36Sopenharmony_ci	},
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const struct mfd_cell tps6586x_cell[] = {
10462306a36Sopenharmony_ci	{
10562306a36Sopenharmony_ci		.name = "tps6586x-gpio",
10662306a36Sopenharmony_ci	},
10762306a36Sopenharmony_ci	{
10862306a36Sopenharmony_ci		.name = "tps6586x-regulator",
10962306a36Sopenharmony_ci	},
11062306a36Sopenharmony_ci	{
11162306a36Sopenharmony_ci		.name = "tps6586x-rtc",
11262306a36Sopenharmony_ci		.num_resources = ARRAY_SIZE(tps6586x_rtc_resources),
11362306a36Sopenharmony_ci		.resources = &tps6586x_rtc_resources[0],
11462306a36Sopenharmony_ci	},
11562306a36Sopenharmony_ci	{
11662306a36Sopenharmony_ci		.name = "tps6586x-onkey",
11762306a36Sopenharmony_ci	},
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct tps6586x {
12162306a36Sopenharmony_ci	struct device		*dev;
12262306a36Sopenharmony_ci	struct i2c_client	*client;
12362306a36Sopenharmony_ci	struct regmap		*regmap;
12462306a36Sopenharmony_ci	int			version;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	int			irq;
12762306a36Sopenharmony_ci	struct irq_chip		irq_chip;
12862306a36Sopenharmony_ci	struct mutex		irq_lock;
12962306a36Sopenharmony_ci	int			irq_base;
13062306a36Sopenharmony_ci	u32			irq_en;
13162306a36Sopenharmony_ci	u8			mask_reg[5];
13262306a36Sopenharmony_ci	struct irq_domain	*irq_domain;
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic inline struct tps6586x *dev_to_tps6586x(struct device *dev)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return i2c_get_clientdata(to_i2c_client(dev));
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciint tps6586x_write(struct device *dev, int reg, uint8_t val)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return regmap_write(tps6586x->regmap, reg, val);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_write);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciint tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return regmap_bulk_write(tps6586x->regmap, reg, val, len);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_writes);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciint tps6586x_read(struct device *dev, int reg, uint8_t *val)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
15962306a36Sopenharmony_ci	unsigned int rval;
16062306a36Sopenharmony_ci	int ret;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ret = regmap_read(tps6586x->regmap, reg, &rval);
16362306a36Sopenharmony_ci	if (!ret)
16462306a36Sopenharmony_ci		*val = rval;
16562306a36Sopenharmony_ci	return ret;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_read);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ciint tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return regmap_bulk_read(tps6586x->regmap, reg, val, len);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_reads);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciint tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return regmap_update_bits(tps6586x->regmap, reg, bit_mask, bit_mask);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_set_bits);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ciint tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return regmap_update_bits(tps6586x->regmap, reg, bit_mask, 0);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_clr_bits);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ciint tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return regmap_update_bits(tps6586x->regmap, reg, mask, val);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_update);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciint tps6586x_irq_get_virq(struct device *dev, int irq)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_to_tps6586x(dev);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return irq_create_mapping(tps6586x->irq_domain, irq);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_irq_get_virq);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciint tps6586x_get_version(struct device *dev)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_get_drvdata(dev);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return tps6586x->version;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tps6586x_get_version);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int __remove_subdev(struct device *dev, void *unused)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	platform_device_unregister(to_platform_device(dev));
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void tps6586x_irq_lock(struct irq_data *data)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	mutex_lock(&tps6586x->irq_lock);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void tps6586x_irq_enable(struct irq_data *irq_data)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
23862306a36Sopenharmony_ci	unsigned int __irq = irq_data->hwirq;
23962306a36Sopenharmony_ci	const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
24262306a36Sopenharmony_ci	tps6586x->irq_en |= (1 << __irq);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void tps6586x_irq_disable(struct irq_data *irq_data)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	unsigned int __irq = irq_data->hwirq;
25062306a36Sopenharmony_ci	const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
25362306a36Sopenharmony_ci	tps6586x->irq_en &= ~(1 << __irq);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic void tps6586x_irq_sync_unlock(struct irq_data *data)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
25962306a36Sopenharmony_ci	int i;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
26262306a36Sopenharmony_ci		int ret;
26362306a36Sopenharmony_ci		ret = tps6586x_write(tps6586x->dev,
26462306a36Sopenharmony_ci					    TPS6586X_INT_MASK1 + i,
26562306a36Sopenharmony_ci					    tps6586x->mask_reg[i]);
26662306a36Sopenharmony_ci		WARN_ON(ret);
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	mutex_unlock(&tps6586x->irq_lock);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int tps6586x_irq_set_wake(struct irq_data *irq_data, unsigned int on)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
27562306a36Sopenharmony_ci	return irq_set_irq_wake(tps6586x->irq, on);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic struct irq_chip tps6586x_irq_chip = {
27962306a36Sopenharmony_ci	.name = "tps6586x",
28062306a36Sopenharmony_ci	.irq_bus_lock = tps6586x_irq_lock,
28162306a36Sopenharmony_ci	.irq_bus_sync_unlock = tps6586x_irq_sync_unlock,
28262306a36Sopenharmony_ci	.irq_disable = tps6586x_irq_disable,
28362306a36Sopenharmony_ci	.irq_enable = tps6586x_irq_enable,
28462306a36Sopenharmony_ci	.irq_set_wake = pm_sleep_ptr(tps6586x_irq_set_wake),
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int tps6586x_irq_map(struct irq_domain *h, unsigned int virq,
28862306a36Sopenharmony_ci				irq_hw_number_t hw)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct tps6586x *tps6586x = h->host_data;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	irq_set_chip_data(virq, tps6586x);
29362306a36Sopenharmony_ci	irq_set_chip_and_handler(virq, &tps6586x_irq_chip, handle_simple_irq);
29462306a36Sopenharmony_ci	irq_set_nested_thread(virq, 1);
29562306a36Sopenharmony_ci	irq_set_noprobe(virq);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic const struct irq_domain_ops tps6586x_domain_ops = {
30162306a36Sopenharmony_ci	.map    = tps6586x_irq_map,
30262306a36Sopenharmony_ci	.xlate  = irq_domain_xlate_twocell,
30362306a36Sopenharmony_ci};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic irqreturn_t tps6586x_irq(int irq, void *data)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct tps6586x *tps6586x = data;
30862306a36Sopenharmony_ci	uint32_t acks;
30962306a36Sopenharmony_ci	__le32 val;
31062306a36Sopenharmony_ci	int ret = 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1,
31362306a36Sopenharmony_ci			     sizeof(acks), (uint8_t *)&val);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (ret < 0) {
31662306a36Sopenharmony_ci		dev_err(tps6586x->dev, "failed to read interrupt status\n");
31762306a36Sopenharmony_ci		return IRQ_NONE;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	acks = le32_to_cpu(val);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	while (acks) {
32362306a36Sopenharmony_ci		int i = __ffs(acks);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		if (tps6586x->irq_en & (1 << i))
32662306a36Sopenharmony_ci			handle_nested_irq(
32762306a36Sopenharmony_ci				irq_find_mapping(tps6586x->irq_domain, i));
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		acks &= ~(1 << i);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return IRQ_HANDLED;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
33662306a36Sopenharmony_ci				       int irq_base)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int i, ret;
33962306a36Sopenharmony_ci	u8 tmp[4];
34062306a36Sopenharmony_ci	int new_irq_base;
34162306a36Sopenharmony_ci	int irq_num = ARRAY_SIZE(tps6586x_irqs);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	tps6586x->irq = irq;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	mutex_init(&tps6586x->irq_lock);
34662306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
34762306a36Sopenharmony_ci		tps6586x->mask_reg[i] = 0xff;
34862306a36Sopenharmony_ci		tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if  (irq_base > 0) {
35462306a36Sopenharmony_ci		new_irq_base = irq_alloc_descs(irq_base, 0, irq_num, -1);
35562306a36Sopenharmony_ci		if (new_irq_base < 0) {
35662306a36Sopenharmony_ci			dev_err(tps6586x->dev,
35762306a36Sopenharmony_ci				"Failed to alloc IRQs: %d\n", new_irq_base);
35862306a36Sopenharmony_ci			return new_irq_base;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci		new_irq_base = 0;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	tps6586x->irq_domain = irq_domain_add_simple(tps6586x->dev->of_node,
36562306a36Sopenharmony_ci				irq_num, new_irq_base, &tps6586x_domain_ops,
36662306a36Sopenharmony_ci				tps6586x);
36762306a36Sopenharmony_ci	if (!tps6586x->irq_domain) {
36862306a36Sopenharmony_ci		dev_err(tps6586x->dev, "Failed to create IRQ domain\n");
36962306a36Sopenharmony_ci		return -ENOMEM;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci	ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT,
37262306a36Sopenharmony_ci				   "tps6586x", tps6586x);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (!ret)
37562306a36Sopenharmony_ci		device_init_wakeup(tps6586x->dev, 1);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int tps6586x_add_subdevs(struct tps6586x *tps6586x,
38162306a36Sopenharmony_ci					  struct tps6586x_platform_data *pdata)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct tps6586x_subdev_info *subdev;
38462306a36Sopenharmony_ci	struct platform_device *pdev;
38562306a36Sopenharmony_ci	int i, ret = 0;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	for (i = 0; i < pdata->num_subdevs; i++) {
38862306a36Sopenharmony_ci		subdev = &pdata->subdevs[i];
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		pdev = platform_device_alloc(subdev->name, subdev->id);
39162306a36Sopenharmony_ci		if (!pdev) {
39262306a36Sopenharmony_ci			ret = -ENOMEM;
39362306a36Sopenharmony_ci			goto failed;
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		pdev->dev.parent = tps6586x->dev;
39762306a36Sopenharmony_ci		pdev->dev.platform_data = subdev->platform_data;
39862306a36Sopenharmony_ci		pdev->dev.of_node = subdev->of_node;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		ret = platform_device_add(pdev);
40162306a36Sopenharmony_ci		if (ret) {
40262306a36Sopenharmony_ci			platform_device_put(pdev);
40362306a36Sopenharmony_ci			goto failed;
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cifailed:
40962306a36Sopenharmony_ci	tps6586x_remove_subdevs(tps6586x);
41062306a36Sopenharmony_ci	return ret;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci#ifdef CONFIG_OF
41462306a36Sopenharmony_cistatic struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct device_node *np = client->dev.of_node;
41762306a36Sopenharmony_ci	struct tps6586x_platform_data *pdata;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
42062306a36Sopenharmony_ci	if (!pdata)
42162306a36Sopenharmony_ci		return NULL;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	pdata->num_subdevs = 0;
42462306a36Sopenharmony_ci	pdata->subdevs = NULL;
42562306a36Sopenharmony_ci	pdata->gpio_base = -1;
42662306a36Sopenharmony_ci	pdata->irq_base = -1;
42762306a36Sopenharmony_ci	pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller");
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return pdata;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic const struct of_device_id tps6586x_of_match[] = {
43362306a36Sopenharmony_ci	{ .compatible = "ti,tps6586x", },
43462306a36Sopenharmony_ci	{ },
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci#else
43762306a36Sopenharmony_cistatic struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	return NULL;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci#endif
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic bool is_volatile_reg(struct device *dev, unsigned int reg)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	/* Cache all interrupt mask register */
44662306a36Sopenharmony_ci	if ((reg >= TPS6586X_INT_MASK1) && (reg <= TPS6586X_INT_MASK5))
44762306a36Sopenharmony_ci		return false;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return true;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const struct regmap_config tps6586x_regmap_config = {
45362306a36Sopenharmony_ci	.reg_bits = 8,
45462306a36Sopenharmony_ci	.val_bits = 8,
45562306a36Sopenharmony_ci	.max_register = TPS6586X_MAX_REGISTER,
45662306a36Sopenharmony_ci	.volatile_reg = is_volatile_reg,
45762306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic struct device *tps6586x_dev;
46162306a36Sopenharmony_cistatic void tps6586x_power_off(void)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT))
46462306a36Sopenharmony_ci		return;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void tps6586x_print_version(struct i2c_client *client, int version)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	const char *name;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	switch (version) {
47462306a36Sopenharmony_ci	case TPS658621A:
47562306a36Sopenharmony_ci		name = "TPS658621A";
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci	case TPS658621CD:
47862306a36Sopenharmony_ci		name = "TPS658621C/D";
47962306a36Sopenharmony_ci		break;
48062306a36Sopenharmony_ci	case TPS658623:
48162306a36Sopenharmony_ci		name = "TPS658623";
48262306a36Sopenharmony_ci		break;
48362306a36Sopenharmony_ci	case TPS658640:
48462306a36Sopenharmony_ci	case TPS658640v2:
48562306a36Sopenharmony_ci		name = "TPS658640";
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	case TPS658643:
48862306a36Sopenharmony_ci		name = "TPS658643";
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	default:
49162306a36Sopenharmony_ci		name = "TPS6586X";
49262306a36Sopenharmony_ci		break;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	dev_info(&client->dev, "Found %s, VERSIONCRC is %02x\n", name, version);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int tps6586x_i2c_probe(struct i2c_client *client)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct tps6586x_platform_data *pdata = dev_get_platdata(&client->dev);
50162306a36Sopenharmony_ci	struct tps6586x *tps6586x;
50262306a36Sopenharmony_ci	int ret;
50362306a36Sopenharmony_ci	int version;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!pdata && client->dev.of_node)
50662306a36Sopenharmony_ci		pdata = tps6586x_parse_dt(client);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (!pdata) {
50962306a36Sopenharmony_ci		dev_err(&client->dev, "tps6586x requires platform data\n");
51062306a36Sopenharmony_ci		return -ENOTSUPP;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	version = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
51462306a36Sopenharmony_ci	if (version < 0) {
51562306a36Sopenharmony_ci		dev_err(&client->dev, "Chip ID read failed: %d\n", version);
51662306a36Sopenharmony_ci		return -EIO;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	tps6586x = devm_kzalloc(&client->dev, sizeof(*tps6586x), GFP_KERNEL);
52062306a36Sopenharmony_ci	if (!tps6586x)
52162306a36Sopenharmony_ci		return -ENOMEM;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	tps6586x->version = version;
52462306a36Sopenharmony_ci	tps6586x_print_version(client, tps6586x->version);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	tps6586x->client = client;
52762306a36Sopenharmony_ci	tps6586x->dev = &client->dev;
52862306a36Sopenharmony_ci	i2c_set_clientdata(client, tps6586x);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	tps6586x->regmap = devm_regmap_init_i2c(client,
53162306a36Sopenharmony_ci					&tps6586x_regmap_config);
53262306a36Sopenharmony_ci	if (IS_ERR(tps6586x->regmap)) {
53362306a36Sopenharmony_ci		ret = PTR_ERR(tps6586x->regmap);
53462306a36Sopenharmony_ci		dev_err(&client->dev, "regmap init failed: %d\n", ret);
53562306a36Sopenharmony_ci		return ret;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (client->irq) {
54062306a36Sopenharmony_ci		ret = tps6586x_irq_init(tps6586x, client->irq,
54162306a36Sopenharmony_ci					pdata->irq_base);
54262306a36Sopenharmony_ci		if (ret) {
54362306a36Sopenharmony_ci			dev_err(&client->dev, "IRQ init failed: %d\n", ret);
54462306a36Sopenharmony_ci			return ret;
54562306a36Sopenharmony_ci		}
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = mfd_add_devices(tps6586x->dev, -1,
54962306a36Sopenharmony_ci			      tps6586x_cell, ARRAY_SIZE(tps6586x_cell),
55062306a36Sopenharmony_ci			      NULL, 0, tps6586x->irq_domain);
55162306a36Sopenharmony_ci	if (ret < 0) {
55262306a36Sopenharmony_ci		dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret);
55362306a36Sopenharmony_ci		goto err_mfd_add;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ret = tps6586x_add_subdevs(tps6586x, pdata);
55762306a36Sopenharmony_ci	if (ret) {
55862306a36Sopenharmony_ci		dev_err(&client->dev, "add devices failed: %d\n", ret);
55962306a36Sopenharmony_ci		goto err_add_devs;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (pdata->pm_off && !pm_power_off) {
56362306a36Sopenharmony_ci		tps6586x_dev = &client->dev;
56462306a36Sopenharmony_ci		pm_power_off = tps6586x_power_off;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return 0;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cierr_add_devs:
57062306a36Sopenharmony_ci	mfd_remove_devices(tps6586x->dev);
57162306a36Sopenharmony_cierr_mfd_add:
57262306a36Sopenharmony_ci	if (client->irq)
57362306a36Sopenharmony_ci		free_irq(client->irq, tps6586x);
57462306a36Sopenharmony_ci	return ret;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic void tps6586x_i2c_remove(struct i2c_client *client)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct tps6586x *tps6586x = i2c_get_clientdata(client);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	tps6586x_remove_subdevs(tps6586x);
58262306a36Sopenharmony_ci	mfd_remove_devices(tps6586x->dev);
58362306a36Sopenharmony_ci	if (client->irq)
58462306a36Sopenharmony_ci		free_irq(client->irq, tps6586x);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic int __maybe_unused tps6586x_i2c_suspend(struct device *dev)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_get_drvdata(dev);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (tps6586x->client->irq)
59262306a36Sopenharmony_ci		disable_irq(tps6586x->client->irq);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return 0;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int __maybe_unused tps6586x_i2c_resume(struct device *dev)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct tps6586x *tps6586x = dev_get_drvdata(dev);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (tps6586x->client->irq)
60262306a36Sopenharmony_ci		enable_irq(tps6586x->client->irq);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend,
60862306a36Sopenharmony_ci			 tps6586x_i2c_resume);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic const struct i2c_device_id tps6586x_id_table[] = {
61162306a36Sopenharmony_ci	{ "tps6586x", 0 },
61262306a36Sopenharmony_ci	{ },
61362306a36Sopenharmony_ci};
61462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tps6586x_id_table);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic struct i2c_driver tps6586x_driver = {
61762306a36Sopenharmony_ci	.driver	= {
61862306a36Sopenharmony_ci		.name	= "tps6586x",
61962306a36Sopenharmony_ci		.of_match_table = of_match_ptr(tps6586x_of_match),
62062306a36Sopenharmony_ci		.pm	= &tps6586x_pm_ops,
62162306a36Sopenharmony_ci	},
62262306a36Sopenharmony_ci	.probe		= tps6586x_i2c_probe,
62362306a36Sopenharmony_ci	.remove		= tps6586x_i2c_remove,
62462306a36Sopenharmony_ci	.id_table	= tps6586x_id_table,
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int __init tps6586x_init(void)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	return i2c_add_driver(&tps6586x_driver);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_cisubsys_initcall(tps6586x_init);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void __exit tps6586x_exit(void)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	i2c_del_driver(&tps6586x_driver);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_cimodule_exit(tps6586x_exit);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ciMODULE_DESCRIPTION("TPS6586X core driver");
64062306a36Sopenharmony_ciMODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
641