xref: /openbmc/linux/drivers/mfd/tps65217.c (revision dc0c386e)
12aec85b2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d48f411cSAnilKumar Ch /*
3d48f411cSAnilKumar Ch  * tps65217.c
4d48f411cSAnilKumar Ch  *
5d48f411cSAnilKumar Ch  * TPS65217 chip family multi-function driver
6d48f411cSAnilKumar Ch  *
74f4ed454SAlexander A. Klimov  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
8d48f411cSAnilKumar Ch  */
9d48f411cSAnilKumar Ch 
10d48f411cSAnilKumar Ch #include <linux/device.h>
11d48f411cSAnilKumar Ch #include <linux/err.h>
126556bdacSMarcin Niestroj #include <linux/init.h>
136556bdacSMarcin Niestroj #include <linux/interrupt.h>
146556bdacSMarcin Niestroj #include <linux/i2c.h>
156556bdacSMarcin Niestroj #include <linux/irq.h>
166556bdacSMarcin Niestroj #include <linux/irqdomain.h>
176556bdacSMarcin Niestroj #include <linux/kernel.h>
186556bdacSMarcin Niestroj #include <linux/module.h>
19817bb7fbSAnilKumar Ch #include <linux/of.h>
206556bdacSMarcin Niestroj #include <linux/platform_device.h>
216556bdacSMarcin Niestroj #include <linux/regmap.h>
226556bdacSMarcin Niestroj #include <linux/slab.h>
23d48f411cSAnilKumar Ch 
24d48f411cSAnilKumar Ch #include <linux/mfd/core.h>
25d48f411cSAnilKumar Ch #include <linux/mfd/tps65217.h>
26d48f411cSAnilKumar Ch 
270aefed0eSRikard Falkeborn static const struct resource charger_resources[] = {
286556bdacSMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_AC, "AC"),
296556bdacSMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_USB, "USB"),
306556bdacSMarcin Niestroj };
316556bdacSMarcin Niestroj 
320aefed0eSRikard Falkeborn static const struct resource pb_resources[] = {
33dea9c730SMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
34dea9c730SMarcin Niestroj };
35dea9c730SMarcin Niestroj 
tps65217_irq_lock(struct irq_data * data)366556bdacSMarcin Niestroj static void tps65217_irq_lock(struct irq_data *data)
376556bdacSMarcin Niestroj {
386556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
396556bdacSMarcin Niestroj 
406556bdacSMarcin Niestroj 	mutex_lock(&tps->irq_lock);
416556bdacSMarcin Niestroj }
426556bdacSMarcin Niestroj 
tps65217_irq_sync_unlock(struct irq_data * data)436556bdacSMarcin Niestroj static void tps65217_irq_sync_unlock(struct irq_data *data)
446556bdacSMarcin Niestroj {
456556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
466556bdacSMarcin Niestroj 	int ret;
476556bdacSMarcin Niestroj 
48fa917052SMilo Kim 	ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
49fa917052SMilo Kim 				tps->irq_mask, TPS65217_PROTECT_NONE);
506556bdacSMarcin Niestroj 	if (ret != 0)
516556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to sync IRQ masks\n");
526556bdacSMarcin Niestroj 
536556bdacSMarcin Niestroj 	mutex_unlock(&tps->irq_lock);
546556bdacSMarcin Niestroj }
556556bdacSMarcin Niestroj 
tps65217_irq_enable(struct irq_data * data)566556bdacSMarcin Niestroj static void tps65217_irq_enable(struct irq_data *data)
576556bdacSMarcin Niestroj {
586556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
59fa917052SMilo Kim 	u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
606556bdacSMarcin Niestroj 
61fa917052SMilo Kim 	tps->irq_mask &= ~mask;
626556bdacSMarcin Niestroj }
636556bdacSMarcin Niestroj 
tps65217_irq_disable(struct irq_data * data)646556bdacSMarcin Niestroj static void tps65217_irq_disable(struct irq_data *data)
656556bdacSMarcin Niestroj {
666556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
67fa917052SMilo Kim 	u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
686556bdacSMarcin Niestroj 
69fa917052SMilo Kim 	tps->irq_mask |= mask;
706556bdacSMarcin Niestroj }
716556bdacSMarcin Niestroj 
726556bdacSMarcin Niestroj static struct irq_chip tps65217_irq_chip = {
73f6602064SMilo Kim 	.name			= "tps65217",
746556bdacSMarcin Niestroj 	.irq_bus_lock		= tps65217_irq_lock,
756556bdacSMarcin Niestroj 	.irq_bus_sync_unlock	= tps65217_irq_sync_unlock,
766556bdacSMarcin Niestroj 	.irq_enable		= tps65217_irq_enable,
776556bdacSMarcin Niestroj 	.irq_disable		= tps65217_irq_disable,
786556bdacSMarcin Niestroj };
796556bdacSMarcin Niestroj 
806556bdacSMarcin Niestroj static struct mfd_cell tps65217s[] = {
81817bb7fbSAnilKumar Ch 	{
82817bb7fbSAnilKumar Ch 		.name = "tps65217-pmic",
8311d0d300SJohannes Pointner 		.of_compatible = "ti,tps65217-pmic",
84817bb7fbSAnilKumar Ch 	},
85b6290ffeSMatthias Kaehlcke 	{
86b6290ffeSMatthias Kaehlcke 		.name = "tps65217-bl",
8711d0d300SJohannes Pointner 		.of_compatible = "ti,tps65217-bl",
88b6290ffeSMatthias Kaehlcke 	},
8955cec67aSEnric Balletbo i Serra 	{
9055cec67aSEnric Balletbo i Serra 		.name = "tps65217-charger",
916556bdacSMarcin Niestroj 		.num_resources = ARRAY_SIZE(charger_resources),
926556bdacSMarcin Niestroj 		.resources = charger_resources,
9355cec67aSEnric Balletbo i Serra 		.of_compatible = "ti,tps65217-charger",
9455cec67aSEnric Balletbo i Serra 	},
95dea9c730SMarcin Niestroj 	{
96dea9c730SMarcin Niestroj 		.name = "tps65217-pwrbutton",
97dea9c730SMarcin Niestroj 		.num_resources = ARRAY_SIZE(pb_resources),
98dea9c730SMarcin Niestroj 		.resources = pb_resources,
99dea9c730SMarcin Niestroj 		.of_compatible = "ti,tps65217-pwrbutton",
100dea9c730SMarcin Niestroj 	},
101817bb7fbSAnilKumar Ch };
102817bb7fbSAnilKumar Ch 
tps65217_irq_thread(int irq,void * data)1036556bdacSMarcin Niestroj static irqreturn_t tps65217_irq_thread(int irq, void *data)
1046556bdacSMarcin Niestroj {
1056556bdacSMarcin Niestroj 	struct tps65217 *tps = data;
1066556bdacSMarcin Niestroj 	unsigned int status;
1076556bdacSMarcin Niestroj 	bool handled = false;
1086556bdacSMarcin Niestroj 	int i;
1096556bdacSMarcin Niestroj 	int ret;
1106556bdacSMarcin Niestroj 
1116556bdacSMarcin Niestroj 	ret = tps65217_reg_read(tps, TPS65217_REG_INT, &status);
1126556bdacSMarcin Niestroj 	if (ret < 0) {
1136556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to read IRQ status: %d\n",
1146556bdacSMarcin Niestroj 			ret);
1156556bdacSMarcin Niestroj 		return IRQ_NONE;
1166556bdacSMarcin Niestroj 	}
1176556bdacSMarcin Niestroj 
118fa917052SMilo Kim 	for (i = 0; i < TPS65217_NUM_IRQ; i++) {
119fa917052SMilo Kim 		if (status & BIT(i)) {
1206556bdacSMarcin Niestroj 			handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
1216556bdacSMarcin Niestroj 			handled = true;
1226556bdacSMarcin Niestroj 		}
1236556bdacSMarcin Niestroj 	}
1246556bdacSMarcin Niestroj 
1256556bdacSMarcin Niestroj 	if (handled)
1266556bdacSMarcin Niestroj 		return IRQ_HANDLED;
1276556bdacSMarcin Niestroj 
1286556bdacSMarcin Niestroj 	return IRQ_NONE;
1296556bdacSMarcin Niestroj }
1306556bdacSMarcin Niestroj 
tps65217_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)1316556bdacSMarcin Niestroj static int tps65217_irq_map(struct irq_domain *h, unsigned int virq,
1326556bdacSMarcin Niestroj 			irq_hw_number_t hw)
1336556bdacSMarcin Niestroj {
1346556bdacSMarcin Niestroj 	struct tps65217 *tps = h->host_data;
1356556bdacSMarcin Niestroj 
1366556bdacSMarcin Niestroj 	irq_set_chip_data(virq, tps);
1376556bdacSMarcin Niestroj 	irq_set_chip_and_handler(virq, &tps65217_irq_chip, handle_edge_irq);
1386556bdacSMarcin Niestroj 	irq_set_nested_thread(virq, 1);
1396556bdacSMarcin Niestroj 	irq_set_parent(virq, tps->irq);
1406556bdacSMarcin Niestroj 	irq_set_noprobe(virq);
1416556bdacSMarcin Niestroj 
1426556bdacSMarcin Niestroj 	return 0;
1436556bdacSMarcin Niestroj }
1446556bdacSMarcin Niestroj 
1456556bdacSMarcin Niestroj static const struct irq_domain_ops tps65217_irq_domain_ops = {
1466556bdacSMarcin Niestroj 	.map = tps65217_irq_map,
1476556bdacSMarcin Niestroj };
1486556bdacSMarcin Niestroj 
tps65217_irq_init(struct tps65217 * tps,int irq)1496556bdacSMarcin Niestroj static int tps65217_irq_init(struct tps65217 *tps, int irq)
1506556bdacSMarcin Niestroj {
1516556bdacSMarcin Niestroj 	int ret;
1526556bdacSMarcin Niestroj 
1536556bdacSMarcin Niestroj 	mutex_init(&tps->irq_lock);
1546556bdacSMarcin Niestroj 	tps->irq = irq;
1556556bdacSMarcin Niestroj 
1566556bdacSMarcin Niestroj 	/* Mask all interrupt sources */
1576d2c2b9fSMilo Kim 	tps->irq_mask = TPS65217_INT_MASK;
1586d2c2b9fSMilo Kim 	tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
1596d2c2b9fSMilo Kim 			  TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
1606556bdacSMarcin Niestroj 
1616556bdacSMarcin Niestroj 	tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
1626556bdacSMarcin Niestroj 		TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
1636556bdacSMarcin Niestroj 	if (!tps->irq_domain) {
1646556bdacSMarcin Niestroj 		dev_err(tps->dev, "Could not create IRQ domain\n");
1656556bdacSMarcin Niestroj 		return -ENOMEM;
1666556bdacSMarcin Niestroj 	}
1676556bdacSMarcin Niestroj 
1686556bdacSMarcin Niestroj 	ret = devm_request_threaded_irq(tps->dev, irq, NULL,
1696556bdacSMarcin Niestroj 					tps65217_irq_thread, IRQF_ONESHOT,
1706556bdacSMarcin Niestroj 					"tps65217-irq", tps);
1716556bdacSMarcin Niestroj 	if (ret) {
1726556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
1736556bdacSMarcin Niestroj 			irq, ret);
1746556bdacSMarcin Niestroj 		return ret;
1756556bdacSMarcin Niestroj 	}
1766556bdacSMarcin Niestroj 
17793559191SMilo Kim 	enable_irq_wake(irq);
17893559191SMilo Kim 
1796556bdacSMarcin Niestroj 	return 0;
1806556bdacSMarcin Niestroj }
1816556bdacSMarcin Niestroj 
182d48f411cSAnilKumar Ch /**
183d48f411cSAnilKumar Ch  * tps65217_reg_read: Read a single tps65217 register.
184d48f411cSAnilKumar Ch  *
185d48f411cSAnilKumar Ch  * @tps: Device to read from.
186d48f411cSAnilKumar Ch  * @reg: Register to read.
187d48f411cSAnilKumar Ch  * @val: Contians the value
188d48f411cSAnilKumar Ch  */
tps65217_reg_read(struct tps65217 * tps,unsigned int reg,unsigned int * val)189d48f411cSAnilKumar Ch int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
190d48f411cSAnilKumar Ch 			unsigned int *val)
191d48f411cSAnilKumar Ch {
192d48f411cSAnilKumar Ch 	return regmap_read(tps->regmap, reg, val);
193d48f411cSAnilKumar Ch }
194d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_reg_read);
195d48f411cSAnilKumar Ch 
196d48f411cSAnilKumar Ch /**
197d48f411cSAnilKumar Ch  * tps65217_reg_write: Write a single tps65217 register.
198d48f411cSAnilKumar Ch  *
1994976bfb8SLee Jones  * @tps: Device to write to.
200d48f411cSAnilKumar Ch  * @reg: Register to write to.
201d48f411cSAnilKumar Ch  * @val: Value to write.
202d48f411cSAnilKumar Ch  * @level: Password protected level
203d48f411cSAnilKumar Ch  */
tps65217_reg_write(struct tps65217 * tps,unsigned int reg,unsigned int val,unsigned int level)204d48f411cSAnilKumar Ch int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
205d48f411cSAnilKumar Ch 			unsigned int val, unsigned int level)
206d48f411cSAnilKumar Ch {
207d48f411cSAnilKumar Ch 	int ret;
208d48f411cSAnilKumar Ch 	unsigned int xor_reg_val;
209d48f411cSAnilKumar Ch 
210d48f411cSAnilKumar Ch 	switch (level) {
211d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_NONE:
212d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
213d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_L1:
214d48f411cSAnilKumar Ch 		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
215d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
216d48f411cSAnilKumar Ch 							xor_reg_val);
217d48f411cSAnilKumar Ch 		if (ret < 0)
218d48f411cSAnilKumar Ch 			return ret;
219d48f411cSAnilKumar Ch 
220d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
221d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_L2:
222d48f411cSAnilKumar Ch 		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
223d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
224d48f411cSAnilKumar Ch 							xor_reg_val);
225d48f411cSAnilKumar Ch 		if (ret < 0)
226d48f411cSAnilKumar Ch 			return ret;
227d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, reg, val);
228d48f411cSAnilKumar Ch 		if (ret < 0)
229d48f411cSAnilKumar Ch 			return ret;
230d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
231d48f411cSAnilKumar Ch 							xor_reg_val);
232d48f411cSAnilKumar Ch 		if (ret < 0)
233d48f411cSAnilKumar Ch 			return ret;
234d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
235d48f411cSAnilKumar Ch 	default:
236d48f411cSAnilKumar Ch 		return -EINVAL;
237d48f411cSAnilKumar Ch 	}
238d48f411cSAnilKumar Ch }
239d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_reg_write);
240d48f411cSAnilKumar Ch 
241d48f411cSAnilKumar Ch /**
242d48f411cSAnilKumar Ch  * tps65217_update_bits: Modify bits w.r.t mask, val and level.
243d48f411cSAnilKumar Ch  *
2444976bfb8SLee Jones  * @tps: Device to write to.
245d48f411cSAnilKumar Ch  * @reg: Register to read-write to.
246d48f411cSAnilKumar Ch  * @mask: Mask.
247d48f411cSAnilKumar Ch  * @val: Value to write.
248d48f411cSAnilKumar Ch  * @level: Password protected level
249d48f411cSAnilKumar Ch  */
tps65217_update_bits(struct tps65217 * tps,unsigned int reg,unsigned int mask,unsigned int val,unsigned int level)25027757e82SMark Brown static int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
251d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int val, unsigned int level)
252d48f411cSAnilKumar Ch {
253d48f411cSAnilKumar Ch 	int ret;
254d48f411cSAnilKumar Ch 	unsigned int data;
255d48f411cSAnilKumar Ch 
256d48f411cSAnilKumar Ch 	ret = tps65217_reg_read(tps, reg, &data);
257d48f411cSAnilKumar Ch 	if (ret) {
258d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
259d48f411cSAnilKumar Ch 		return ret;
260d48f411cSAnilKumar Ch 	}
261d48f411cSAnilKumar Ch 
262d48f411cSAnilKumar Ch 	data &= ~mask;
263d48f411cSAnilKumar Ch 	data |= val & mask;
264d48f411cSAnilKumar Ch 
265d48f411cSAnilKumar Ch 	ret = tps65217_reg_write(tps, reg, data, level);
266d48f411cSAnilKumar Ch 	if (ret)
267d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
268d48f411cSAnilKumar Ch 
269d48f411cSAnilKumar Ch 	return ret;
270d48f411cSAnilKumar Ch }
271d48f411cSAnilKumar Ch 
tps65217_set_bits(struct tps65217 * tps,unsigned int reg,unsigned int mask,unsigned int val,unsigned int level)272d48f411cSAnilKumar Ch int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
273d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int val, unsigned int level)
274d48f411cSAnilKumar Ch {
275d48f411cSAnilKumar Ch 	return tps65217_update_bits(tps, reg, mask, val, level);
276d48f411cSAnilKumar Ch }
277d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_set_bits);
278d48f411cSAnilKumar Ch 
tps65217_clear_bits(struct tps65217 * tps,unsigned int reg,unsigned int mask,unsigned int level)279d48f411cSAnilKumar Ch int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
280d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int level)
281d48f411cSAnilKumar Ch {
282d48f411cSAnilKumar Ch 	return tps65217_update_bits(tps, reg, mask, 0, level);
283d48f411cSAnilKumar Ch }
284d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_clear_bits);
285d48f411cSAnilKumar Ch 
tps65217_volatile_reg(struct device * dev,unsigned int reg)2866556bdacSMarcin Niestroj static bool tps65217_volatile_reg(struct device *dev, unsigned int reg)
2876556bdacSMarcin Niestroj {
2886556bdacSMarcin Niestroj 	switch (reg) {
2896556bdacSMarcin Niestroj 	case TPS65217_REG_INT:
2906556bdacSMarcin Niestroj 		return true;
2916556bdacSMarcin Niestroj 	default:
2926556bdacSMarcin Niestroj 		return false;
2936556bdacSMarcin Niestroj 	}
2946556bdacSMarcin Niestroj }
2956556bdacSMarcin Niestroj 
296af0a837dSKrzysztof Kozlowski static const struct regmap_config tps65217_regmap_config = {
297d48f411cSAnilKumar Ch 	.reg_bits = 8,
298d48f411cSAnilKumar Ch 	.val_bits = 8,
2990b496b4cSMark Brown 
3000b496b4cSMark Brown 	.max_register = TPS65217_REG_MAX,
3016556bdacSMarcin Niestroj 	.volatile_reg = tps65217_volatile_reg,
302d48f411cSAnilKumar Ch };
303d48f411cSAnilKumar Ch 
304817bb7fbSAnilKumar Ch static const struct of_device_id tps65217_of_match[] = {
305511cb174SKeerthy 	{ .compatible = "ti,tps65217"},
306817bb7fbSAnilKumar Ch 	{ /* sentinel */ },
307817bb7fbSAnilKumar Ch };
3084895e493SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, tps65217_of_match);
309817bb7fbSAnilKumar Ch 
tps65217_probe(struct i2c_client * client)310511cb174SKeerthy static int tps65217_probe(struct i2c_client *client)
311d48f411cSAnilKumar Ch {
312d48f411cSAnilKumar Ch 	struct tps65217 *tps;
313d48f411cSAnilKumar Ch 	unsigned int version;
314eb433dadSColin Foe-Parker 	bool status_off = false;
315817bb7fbSAnilKumar Ch 	int ret;
316d48f411cSAnilKumar Ch 
317eb433dadSColin Foe-Parker 	status_off = of_property_read_bool(client->dev.of_node,
318eb433dadSColin Foe-Parker 					   "ti,pmic-shutdown-controller");
319a7f1b63eSAnilKumar Ch 
320d48f411cSAnilKumar Ch 	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
321d48f411cSAnilKumar Ch 	if (!tps)
322d48f411cSAnilKumar Ch 		return -ENOMEM;
323d48f411cSAnilKumar Ch 
324817bb7fbSAnilKumar Ch 	i2c_set_clientdata(client, tps);
325817bb7fbSAnilKumar Ch 	tps->dev = &client->dev;
326817bb7fbSAnilKumar Ch 
3270ef4619cSAxel Lin 	tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
328d48f411cSAnilKumar Ch 	if (IS_ERR(tps->regmap)) {
329d48f411cSAnilKumar Ch 		ret = PTR_ERR(tps->regmap);
330d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Failed to allocate register map: %d\n",
331d48f411cSAnilKumar Ch 			ret);
332d48f411cSAnilKumar Ch 		return ret;
333d48f411cSAnilKumar Ch 	}
334d48f411cSAnilKumar Ch 
3356556bdacSMarcin Niestroj 	if (client->irq) {
3366556bdacSMarcin Niestroj 		tps65217_irq_init(tps, client->irq);
3376556bdacSMarcin Niestroj 	} else {
3386556bdacSMarcin Niestroj 		int i;
3396556bdacSMarcin Niestroj 
3406556bdacSMarcin Niestroj 		/* Don't tell children about IRQ resources which won't fire */
3416556bdacSMarcin Niestroj 		for (i = 0; i < ARRAY_SIZE(tps65217s); i++)
3426556bdacSMarcin Niestroj 			tps65217s[i].num_resources = 0;
3436556bdacSMarcin Niestroj 	}
3446556bdacSMarcin Niestroj 
345b89b6b6bSLaxman Dewangan 	ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
3466556bdacSMarcin Niestroj 				   ARRAY_SIZE(tps65217s), NULL, 0,
3476556bdacSMarcin Niestroj 				   tps->irq_domain);
348817bb7fbSAnilKumar Ch 	if (ret < 0) {
349817bb7fbSAnilKumar Ch 		dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
350817bb7fbSAnilKumar Ch 		return ret;
351817bb7fbSAnilKumar Ch 	}
352d48f411cSAnilKumar Ch 
353d48f411cSAnilKumar Ch 	ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
354d48f411cSAnilKumar Ch 	if (ret < 0) {
3550ef4619cSAxel Lin 		dev_err(tps->dev, "Failed to read revision register: %d\n",
3560ef4619cSAxel Lin 			ret);
3570ef4619cSAxel Lin 		return ret;
358d48f411cSAnilKumar Ch 	}
359d48f411cSAnilKumar Ch 
360eb433dadSColin Foe-Parker 	/* Set the PMIC to shutdown on PWR_EN toggle */
361eb433dadSColin Foe-Parker 	if (status_off) {
362eb433dadSColin Foe-Parker 		ret = tps65217_set_bits(tps, TPS65217_REG_STATUS,
363eb433dadSColin Foe-Parker 				TPS65217_STATUS_OFF, TPS65217_STATUS_OFF,
364eb433dadSColin Foe-Parker 				TPS65217_PROTECT_NONE);
365eb433dadSColin Foe-Parker 		if (ret)
366eb433dadSColin Foe-Parker 			dev_warn(tps->dev, "unable to set the status OFF\n");
367eb433dadSColin Foe-Parker 	}
368eb433dadSColin Foe-Parker 
369d48f411cSAnilKumar Ch 	dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
370d48f411cSAnilKumar Ch 			(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
371d48f411cSAnilKumar Ch 			version & TPS65217_CHIPID_REV_MASK);
372d48f411cSAnilKumar Ch 
373d48f411cSAnilKumar Ch 	return 0;
374d48f411cSAnilKumar Ch }
375d48f411cSAnilKumar Ch 
tps65217_remove(struct i2c_client * client)376ed5c2f5fSUwe Kleine-König static void tps65217_remove(struct i2c_client *client)
37740a50f8bSMilo Kim {
37840a50f8bSMilo Kim 	struct tps65217 *tps = i2c_get_clientdata(client);
37940a50f8bSMilo Kim 	unsigned int virq;
38040a50f8bSMilo Kim 	int i;
38140a50f8bSMilo Kim 
382fa917052SMilo Kim 	for (i = 0; i < TPS65217_NUM_IRQ; i++) {
38340a50f8bSMilo Kim 		virq = irq_find_mapping(tps->irq_domain, i);
38440a50f8bSMilo Kim 		if (virq)
38540a50f8bSMilo Kim 			irq_dispose_mapping(virq);
38640a50f8bSMilo Kim 	}
38740a50f8bSMilo Kim 
38840a50f8bSMilo Kim 	irq_domain_remove(tps->irq_domain);
38940a50f8bSMilo Kim 	tps->irq_domain = NULL;
39040a50f8bSMilo Kim }
39140a50f8bSMilo Kim 
392d48f411cSAnilKumar Ch static const struct i2c_device_id tps65217_id_table[] = {
393817bb7fbSAnilKumar Ch 	{"tps65217", TPS65217},
394817bb7fbSAnilKumar Ch 	{ /* sentinel */ }
395d48f411cSAnilKumar Ch };
396d48f411cSAnilKumar Ch MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
397d48f411cSAnilKumar Ch 
398d48f411cSAnilKumar Ch static struct i2c_driver tps65217_driver = {
399d48f411cSAnilKumar Ch 	.driver		= {
400d48f411cSAnilKumar Ch 		.name	= "tps65217",
401a351451aSSachin Kamat 		.of_match_table = tps65217_of_match,
402d48f411cSAnilKumar Ch 	},
403d48f411cSAnilKumar Ch 	.id_table	= tps65217_id_table,
404*9816d859SUwe Kleine-König 	.probe		= tps65217_probe,
40540a50f8bSMilo Kim 	.remove		= tps65217_remove,
406d48f411cSAnilKumar Ch };
407d48f411cSAnilKumar Ch 
tps65217_init(void)408d48f411cSAnilKumar Ch static int __init tps65217_init(void)
409d48f411cSAnilKumar Ch {
410d48f411cSAnilKumar Ch 	return i2c_add_driver(&tps65217_driver);
411d48f411cSAnilKumar Ch }
412d48f411cSAnilKumar Ch subsys_initcall(tps65217_init);
413d48f411cSAnilKumar Ch 
tps65217_exit(void)414d48f411cSAnilKumar Ch static void __exit tps65217_exit(void)
415d48f411cSAnilKumar Ch {
416d48f411cSAnilKumar Ch 	i2c_del_driver(&tps65217_driver);
417d48f411cSAnilKumar Ch }
418d48f411cSAnilKumar Ch module_exit(tps65217_exit);
419d48f411cSAnilKumar Ch 
420d48f411cSAnilKumar Ch MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
421d48f411cSAnilKumar Ch MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
422d48f411cSAnilKumar Ch MODULE_LICENSE("GPL v2");
423