xref: /openbmc/linux/drivers/mfd/tps65217.c (revision ed5c2f5f)
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>
20817bb7fbSAnilKumar Ch #include <linux/of_device.h>
216556bdacSMarcin Niestroj #include <linux/platform_device.h>
226556bdacSMarcin Niestroj #include <linux/regmap.h>
236556bdacSMarcin Niestroj #include <linux/slab.h>
24d48f411cSAnilKumar Ch 
25d48f411cSAnilKumar Ch #include <linux/mfd/core.h>
26d48f411cSAnilKumar Ch #include <linux/mfd/tps65217.h>
27d48f411cSAnilKumar Ch 
280aefed0eSRikard Falkeborn static const struct resource charger_resources[] = {
296556bdacSMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_AC, "AC"),
306556bdacSMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_USB, "USB"),
316556bdacSMarcin Niestroj };
326556bdacSMarcin Niestroj 
330aefed0eSRikard Falkeborn static const struct resource pb_resources[] = {
34dea9c730SMarcin Niestroj 	DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
35dea9c730SMarcin Niestroj };
36dea9c730SMarcin Niestroj 
376556bdacSMarcin Niestroj static void tps65217_irq_lock(struct irq_data *data)
386556bdacSMarcin Niestroj {
396556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
406556bdacSMarcin Niestroj 
416556bdacSMarcin Niestroj 	mutex_lock(&tps->irq_lock);
426556bdacSMarcin Niestroj }
436556bdacSMarcin Niestroj 
446556bdacSMarcin Niestroj static void tps65217_irq_sync_unlock(struct irq_data *data)
456556bdacSMarcin Niestroj {
466556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
476556bdacSMarcin Niestroj 	int ret;
486556bdacSMarcin Niestroj 
49fa917052SMilo Kim 	ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
50fa917052SMilo Kim 				tps->irq_mask, TPS65217_PROTECT_NONE);
516556bdacSMarcin Niestroj 	if (ret != 0)
526556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to sync IRQ masks\n");
536556bdacSMarcin Niestroj 
546556bdacSMarcin Niestroj 	mutex_unlock(&tps->irq_lock);
556556bdacSMarcin Niestroj }
566556bdacSMarcin Niestroj 
576556bdacSMarcin Niestroj static void tps65217_irq_enable(struct irq_data *data)
586556bdacSMarcin Niestroj {
596556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
60fa917052SMilo Kim 	u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
616556bdacSMarcin Niestroj 
62fa917052SMilo Kim 	tps->irq_mask &= ~mask;
636556bdacSMarcin Niestroj }
646556bdacSMarcin Niestroj 
656556bdacSMarcin Niestroj static void tps65217_irq_disable(struct irq_data *data)
666556bdacSMarcin Niestroj {
676556bdacSMarcin Niestroj 	struct tps65217 *tps = irq_data_get_irq_chip_data(data);
68fa917052SMilo Kim 	u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
696556bdacSMarcin Niestroj 
70fa917052SMilo Kim 	tps->irq_mask |= mask;
716556bdacSMarcin Niestroj }
726556bdacSMarcin Niestroj 
736556bdacSMarcin Niestroj static struct irq_chip tps65217_irq_chip = {
74f6602064SMilo Kim 	.name			= "tps65217",
756556bdacSMarcin Niestroj 	.irq_bus_lock		= tps65217_irq_lock,
766556bdacSMarcin Niestroj 	.irq_bus_sync_unlock	= tps65217_irq_sync_unlock,
776556bdacSMarcin Niestroj 	.irq_enable		= tps65217_irq_enable,
786556bdacSMarcin Niestroj 	.irq_disable		= tps65217_irq_disable,
796556bdacSMarcin Niestroj };
806556bdacSMarcin Niestroj 
816556bdacSMarcin Niestroj static struct mfd_cell tps65217s[] = {
82817bb7fbSAnilKumar Ch 	{
83817bb7fbSAnilKumar Ch 		.name = "tps65217-pmic",
8411d0d300SJohannes Pointner 		.of_compatible = "ti,tps65217-pmic",
85817bb7fbSAnilKumar Ch 	},
86b6290ffeSMatthias Kaehlcke 	{
87b6290ffeSMatthias Kaehlcke 		.name = "tps65217-bl",
8811d0d300SJohannes Pointner 		.of_compatible = "ti,tps65217-bl",
89b6290ffeSMatthias Kaehlcke 	},
9055cec67aSEnric Balletbo i Serra 	{
9155cec67aSEnric Balletbo i Serra 		.name = "tps65217-charger",
926556bdacSMarcin Niestroj 		.num_resources = ARRAY_SIZE(charger_resources),
936556bdacSMarcin Niestroj 		.resources = charger_resources,
9455cec67aSEnric Balletbo i Serra 		.of_compatible = "ti,tps65217-charger",
9555cec67aSEnric Balletbo i Serra 	},
96dea9c730SMarcin Niestroj 	{
97dea9c730SMarcin Niestroj 		.name = "tps65217-pwrbutton",
98dea9c730SMarcin Niestroj 		.num_resources = ARRAY_SIZE(pb_resources),
99dea9c730SMarcin Niestroj 		.resources = pb_resources,
100dea9c730SMarcin Niestroj 		.of_compatible = "ti,tps65217-pwrbutton",
101dea9c730SMarcin Niestroj 	},
102817bb7fbSAnilKumar Ch };
103817bb7fbSAnilKumar Ch 
1046556bdacSMarcin Niestroj static irqreturn_t tps65217_irq_thread(int irq, void *data)
1056556bdacSMarcin Niestroj {
1066556bdacSMarcin Niestroj 	struct tps65217 *tps = data;
1076556bdacSMarcin Niestroj 	unsigned int status;
1086556bdacSMarcin Niestroj 	bool handled = false;
1096556bdacSMarcin Niestroj 	int i;
1106556bdacSMarcin Niestroj 	int ret;
1116556bdacSMarcin Niestroj 
1126556bdacSMarcin Niestroj 	ret = tps65217_reg_read(tps, TPS65217_REG_INT, &status);
1136556bdacSMarcin Niestroj 	if (ret < 0) {
1146556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to read IRQ status: %d\n",
1156556bdacSMarcin Niestroj 			ret);
1166556bdacSMarcin Niestroj 		return IRQ_NONE;
1176556bdacSMarcin Niestroj 	}
1186556bdacSMarcin Niestroj 
119fa917052SMilo Kim 	for (i = 0; i < TPS65217_NUM_IRQ; i++) {
120fa917052SMilo Kim 		if (status & BIT(i)) {
1216556bdacSMarcin Niestroj 			handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
1226556bdacSMarcin Niestroj 			handled = true;
1236556bdacSMarcin Niestroj 		}
1246556bdacSMarcin Niestroj 	}
1256556bdacSMarcin Niestroj 
1266556bdacSMarcin Niestroj 	if (handled)
1276556bdacSMarcin Niestroj 		return IRQ_HANDLED;
1286556bdacSMarcin Niestroj 
1296556bdacSMarcin Niestroj 	return IRQ_NONE;
1306556bdacSMarcin Niestroj }
1316556bdacSMarcin Niestroj 
1326556bdacSMarcin Niestroj static int tps65217_irq_map(struct irq_domain *h, unsigned int virq,
1336556bdacSMarcin Niestroj 			irq_hw_number_t hw)
1346556bdacSMarcin Niestroj {
1356556bdacSMarcin Niestroj 	struct tps65217 *tps = h->host_data;
1366556bdacSMarcin Niestroj 
1376556bdacSMarcin Niestroj 	irq_set_chip_data(virq, tps);
1386556bdacSMarcin Niestroj 	irq_set_chip_and_handler(virq, &tps65217_irq_chip, handle_edge_irq);
1396556bdacSMarcin Niestroj 	irq_set_nested_thread(virq, 1);
1406556bdacSMarcin Niestroj 	irq_set_parent(virq, tps->irq);
1416556bdacSMarcin Niestroj 	irq_set_noprobe(virq);
1426556bdacSMarcin Niestroj 
1436556bdacSMarcin Niestroj 	return 0;
1446556bdacSMarcin Niestroj }
1456556bdacSMarcin Niestroj 
1466556bdacSMarcin Niestroj static const struct irq_domain_ops tps65217_irq_domain_ops = {
1476556bdacSMarcin Niestroj 	.map = tps65217_irq_map,
1486556bdacSMarcin Niestroj };
1496556bdacSMarcin Niestroj 
1506556bdacSMarcin Niestroj static int tps65217_irq_init(struct tps65217 *tps, int irq)
1516556bdacSMarcin Niestroj {
1526556bdacSMarcin Niestroj 	int ret;
1536556bdacSMarcin Niestroj 
1546556bdacSMarcin Niestroj 	mutex_init(&tps->irq_lock);
1556556bdacSMarcin Niestroj 	tps->irq = irq;
1566556bdacSMarcin Niestroj 
1576556bdacSMarcin Niestroj 	/* Mask all interrupt sources */
1586d2c2b9fSMilo Kim 	tps->irq_mask = TPS65217_INT_MASK;
1596d2c2b9fSMilo Kim 	tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
1606d2c2b9fSMilo Kim 			  TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
1616556bdacSMarcin Niestroj 
1626556bdacSMarcin Niestroj 	tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
1636556bdacSMarcin Niestroj 		TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
1646556bdacSMarcin Niestroj 	if (!tps->irq_domain) {
1656556bdacSMarcin Niestroj 		dev_err(tps->dev, "Could not create IRQ domain\n");
1666556bdacSMarcin Niestroj 		return -ENOMEM;
1676556bdacSMarcin Niestroj 	}
1686556bdacSMarcin Niestroj 
1696556bdacSMarcin Niestroj 	ret = devm_request_threaded_irq(tps->dev, irq, NULL,
1706556bdacSMarcin Niestroj 					tps65217_irq_thread, IRQF_ONESHOT,
1716556bdacSMarcin Niestroj 					"tps65217-irq", tps);
1726556bdacSMarcin Niestroj 	if (ret) {
1736556bdacSMarcin Niestroj 		dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
1746556bdacSMarcin Niestroj 			irq, ret);
1756556bdacSMarcin Niestroj 		return ret;
1766556bdacSMarcin Niestroj 	}
1776556bdacSMarcin Niestroj 
17893559191SMilo Kim 	enable_irq_wake(irq);
17993559191SMilo Kim 
1806556bdacSMarcin Niestroj 	return 0;
1816556bdacSMarcin Niestroj }
1826556bdacSMarcin Niestroj 
183d48f411cSAnilKumar Ch /**
184d48f411cSAnilKumar Ch  * tps65217_reg_read: Read a single tps65217 register.
185d48f411cSAnilKumar Ch  *
186d48f411cSAnilKumar Ch  * @tps: Device to read from.
187d48f411cSAnilKumar Ch  * @reg: Register to read.
188d48f411cSAnilKumar Ch  * @val: Contians the value
189d48f411cSAnilKumar Ch  */
190d48f411cSAnilKumar Ch int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
191d48f411cSAnilKumar Ch 			unsigned int *val)
192d48f411cSAnilKumar Ch {
193d48f411cSAnilKumar Ch 	return regmap_read(tps->regmap, reg, val);
194d48f411cSAnilKumar Ch }
195d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_reg_read);
196d48f411cSAnilKumar Ch 
197d48f411cSAnilKumar Ch /**
198d48f411cSAnilKumar Ch  * tps65217_reg_write: Write a single tps65217 register.
199d48f411cSAnilKumar Ch  *
2004976bfb8SLee Jones  * @tps: Device to write to.
201d48f411cSAnilKumar Ch  * @reg: Register to write to.
202d48f411cSAnilKumar Ch  * @val: Value to write.
203d48f411cSAnilKumar Ch  * @level: Password protected level
204d48f411cSAnilKumar Ch  */
205d48f411cSAnilKumar Ch int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
206d48f411cSAnilKumar Ch 			unsigned int val, unsigned int level)
207d48f411cSAnilKumar Ch {
208d48f411cSAnilKumar Ch 	int ret;
209d48f411cSAnilKumar Ch 	unsigned int xor_reg_val;
210d48f411cSAnilKumar Ch 
211d48f411cSAnilKumar Ch 	switch (level) {
212d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_NONE:
213d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
214d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_L1:
215d48f411cSAnilKumar Ch 		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
216d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
217d48f411cSAnilKumar Ch 							xor_reg_val);
218d48f411cSAnilKumar Ch 		if (ret < 0)
219d48f411cSAnilKumar Ch 			return ret;
220d48f411cSAnilKumar Ch 
221d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
222d48f411cSAnilKumar Ch 	case TPS65217_PROTECT_L2:
223d48f411cSAnilKumar Ch 		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
224d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
225d48f411cSAnilKumar Ch 							xor_reg_val);
226d48f411cSAnilKumar Ch 		if (ret < 0)
227d48f411cSAnilKumar Ch 			return ret;
228d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, reg, val);
229d48f411cSAnilKumar Ch 		if (ret < 0)
230d48f411cSAnilKumar Ch 			return ret;
231d48f411cSAnilKumar Ch 		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
232d48f411cSAnilKumar Ch 							xor_reg_val);
233d48f411cSAnilKumar Ch 		if (ret < 0)
234d48f411cSAnilKumar Ch 			return ret;
235d48f411cSAnilKumar Ch 		return regmap_write(tps->regmap, reg, val);
236d48f411cSAnilKumar Ch 	default:
237d48f411cSAnilKumar Ch 		return -EINVAL;
238d48f411cSAnilKumar Ch 	}
239d48f411cSAnilKumar Ch }
240d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_reg_write);
241d48f411cSAnilKumar Ch 
242d48f411cSAnilKumar Ch /**
243d48f411cSAnilKumar Ch  * tps65217_update_bits: Modify bits w.r.t mask, val and level.
244d48f411cSAnilKumar Ch  *
2454976bfb8SLee Jones  * @tps: Device to write to.
246d48f411cSAnilKumar Ch  * @reg: Register to read-write to.
247d48f411cSAnilKumar Ch  * @mask: Mask.
248d48f411cSAnilKumar Ch  * @val: Value to write.
249d48f411cSAnilKumar Ch  * @level: Password protected level
250d48f411cSAnilKumar Ch  */
25127757e82SMark Brown static int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
252d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int val, unsigned int level)
253d48f411cSAnilKumar Ch {
254d48f411cSAnilKumar Ch 	int ret;
255d48f411cSAnilKumar Ch 	unsigned int data;
256d48f411cSAnilKumar Ch 
257d48f411cSAnilKumar Ch 	ret = tps65217_reg_read(tps, reg, &data);
258d48f411cSAnilKumar Ch 	if (ret) {
259d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
260d48f411cSAnilKumar Ch 		return ret;
261d48f411cSAnilKumar Ch 	}
262d48f411cSAnilKumar Ch 
263d48f411cSAnilKumar Ch 	data &= ~mask;
264d48f411cSAnilKumar Ch 	data |= val & mask;
265d48f411cSAnilKumar Ch 
266d48f411cSAnilKumar Ch 	ret = tps65217_reg_write(tps, reg, data, level);
267d48f411cSAnilKumar Ch 	if (ret)
268d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
269d48f411cSAnilKumar Ch 
270d48f411cSAnilKumar Ch 	return ret;
271d48f411cSAnilKumar Ch }
272d48f411cSAnilKumar Ch 
273d48f411cSAnilKumar Ch int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
274d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int val, unsigned int level)
275d48f411cSAnilKumar Ch {
276d48f411cSAnilKumar Ch 	return tps65217_update_bits(tps, reg, mask, val, level);
277d48f411cSAnilKumar Ch }
278d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_set_bits);
279d48f411cSAnilKumar Ch 
280d48f411cSAnilKumar Ch int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
281d48f411cSAnilKumar Ch 		unsigned int mask, unsigned int level)
282d48f411cSAnilKumar Ch {
283d48f411cSAnilKumar Ch 	return tps65217_update_bits(tps, reg, mask, 0, level);
284d48f411cSAnilKumar Ch }
285d48f411cSAnilKumar Ch EXPORT_SYMBOL_GPL(tps65217_clear_bits);
286d48f411cSAnilKumar Ch 
2876556bdacSMarcin Niestroj static bool tps65217_volatile_reg(struct device *dev, unsigned int reg)
2886556bdacSMarcin Niestroj {
2896556bdacSMarcin Niestroj 	switch (reg) {
2906556bdacSMarcin Niestroj 	case TPS65217_REG_INT:
2916556bdacSMarcin Niestroj 		return true;
2926556bdacSMarcin Niestroj 	default:
2936556bdacSMarcin Niestroj 		return false;
2946556bdacSMarcin Niestroj 	}
2956556bdacSMarcin Niestroj }
2966556bdacSMarcin Niestroj 
297af0a837dSKrzysztof Kozlowski static const struct regmap_config tps65217_regmap_config = {
298d48f411cSAnilKumar Ch 	.reg_bits = 8,
299d48f411cSAnilKumar Ch 	.val_bits = 8,
3000b496b4cSMark Brown 
3010b496b4cSMark Brown 	.max_register = TPS65217_REG_MAX,
3026556bdacSMarcin Niestroj 	.volatile_reg = tps65217_volatile_reg,
303d48f411cSAnilKumar Ch };
304d48f411cSAnilKumar Ch 
305817bb7fbSAnilKumar Ch static const struct of_device_id tps65217_of_match[] = {
306511cb174SKeerthy 	{ .compatible = "ti,tps65217"},
307817bb7fbSAnilKumar Ch 	{ /* sentinel */ },
308817bb7fbSAnilKumar Ch };
3094895e493SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, tps65217_of_match);
310817bb7fbSAnilKumar Ch 
311511cb174SKeerthy static int tps65217_probe(struct i2c_client *client)
312d48f411cSAnilKumar Ch {
313d48f411cSAnilKumar Ch 	struct tps65217 *tps;
314d48f411cSAnilKumar Ch 	unsigned int version;
315eb433dadSColin Foe-Parker 	bool status_off = false;
316817bb7fbSAnilKumar Ch 	int ret;
317d48f411cSAnilKumar Ch 
318eb433dadSColin Foe-Parker 	status_off = of_property_read_bool(client->dev.of_node,
319eb433dadSColin Foe-Parker 					   "ti,pmic-shutdown-controller");
320a7f1b63eSAnilKumar Ch 
321d48f411cSAnilKumar Ch 	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
322d48f411cSAnilKumar Ch 	if (!tps)
323d48f411cSAnilKumar Ch 		return -ENOMEM;
324d48f411cSAnilKumar Ch 
325817bb7fbSAnilKumar Ch 	i2c_set_clientdata(client, tps);
326817bb7fbSAnilKumar Ch 	tps->dev = &client->dev;
327817bb7fbSAnilKumar Ch 
3280ef4619cSAxel Lin 	tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
329d48f411cSAnilKumar Ch 	if (IS_ERR(tps->regmap)) {
330d48f411cSAnilKumar Ch 		ret = PTR_ERR(tps->regmap);
331d48f411cSAnilKumar Ch 		dev_err(tps->dev, "Failed to allocate register map: %d\n",
332d48f411cSAnilKumar Ch 			ret);
333d48f411cSAnilKumar Ch 		return ret;
334d48f411cSAnilKumar Ch 	}
335d48f411cSAnilKumar Ch 
3366556bdacSMarcin Niestroj 	if (client->irq) {
3376556bdacSMarcin Niestroj 		tps65217_irq_init(tps, client->irq);
3386556bdacSMarcin Niestroj 	} else {
3396556bdacSMarcin Niestroj 		int i;
3406556bdacSMarcin Niestroj 
3416556bdacSMarcin Niestroj 		/* Don't tell children about IRQ resources which won't fire */
3426556bdacSMarcin Niestroj 		for (i = 0; i < ARRAY_SIZE(tps65217s); i++)
3436556bdacSMarcin Niestroj 			tps65217s[i].num_resources = 0;
3446556bdacSMarcin Niestroj 	}
3456556bdacSMarcin Niestroj 
346b89b6b6bSLaxman Dewangan 	ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
3476556bdacSMarcin Niestroj 				   ARRAY_SIZE(tps65217s), NULL, 0,
3486556bdacSMarcin Niestroj 				   tps->irq_domain);
349817bb7fbSAnilKumar Ch 	if (ret < 0) {
350817bb7fbSAnilKumar Ch 		dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
351817bb7fbSAnilKumar Ch 		return ret;
352817bb7fbSAnilKumar Ch 	}
353d48f411cSAnilKumar Ch 
354d48f411cSAnilKumar Ch 	ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
355d48f411cSAnilKumar Ch 	if (ret < 0) {
3560ef4619cSAxel Lin 		dev_err(tps->dev, "Failed to read revision register: %d\n",
3570ef4619cSAxel Lin 			ret);
3580ef4619cSAxel Lin 		return ret;
359d48f411cSAnilKumar Ch 	}
360d48f411cSAnilKumar Ch 
361eb433dadSColin Foe-Parker 	/* Set the PMIC to shutdown on PWR_EN toggle */
362eb433dadSColin Foe-Parker 	if (status_off) {
363eb433dadSColin Foe-Parker 		ret = tps65217_set_bits(tps, TPS65217_REG_STATUS,
364eb433dadSColin Foe-Parker 				TPS65217_STATUS_OFF, TPS65217_STATUS_OFF,
365eb433dadSColin Foe-Parker 				TPS65217_PROTECT_NONE);
366eb433dadSColin Foe-Parker 		if (ret)
367eb433dadSColin Foe-Parker 			dev_warn(tps->dev, "unable to set the status OFF\n");
368eb433dadSColin Foe-Parker 	}
369eb433dadSColin Foe-Parker 
370d48f411cSAnilKumar Ch 	dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
371d48f411cSAnilKumar Ch 			(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
372d48f411cSAnilKumar Ch 			version & TPS65217_CHIPID_REV_MASK);
373d48f411cSAnilKumar Ch 
374d48f411cSAnilKumar Ch 	return 0;
375d48f411cSAnilKumar Ch }
376d48f411cSAnilKumar Ch 
377*ed5c2f5fSUwe Kleine-König static void tps65217_remove(struct i2c_client *client)
37840a50f8bSMilo Kim {
37940a50f8bSMilo Kim 	struct tps65217 *tps = i2c_get_clientdata(client);
38040a50f8bSMilo Kim 	unsigned int virq;
38140a50f8bSMilo Kim 	int i;
38240a50f8bSMilo Kim 
383fa917052SMilo Kim 	for (i = 0; i < TPS65217_NUM_IRQ; i++) {
38440a50f8bSMilo Kim 		virq = irq_find_mapping(tps->irq_domain, i);
38540a50f8bSMilo Kim 		if (virq)
38640a50f8bSMilo Kim 			irq_dispose_mapping(virq);
38740a50f8bSMilo Kim 	}
38840a50f8bSMilo Kim 
38940a50f8bSMilo Kim 	irq_domain_remove(tps->irq_domain);
39040a50f8bSMilo Kim 	tps->irq_domain = NULL;
39140a50f8bSMilo Kim }
39240a50f8bSMilo Kim 
393d48f411cSAnilKumar Ch static const struct i2c_device_id tps65217_id_table[] = {
394817bb7fbSAnilKumar Ch 	{"tps65217", TPS65217},
395817bb7fbSAnilKumar Ch 	{ /* sentinel */ }
396d48f411cSAnilKumar Ch };
397d48f411cSAnilKumar Ch MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
398d48f411cSAnilKumar Ch 
399d48f411cSAnilKumar Ch static struct i2c_driver tps65217_driver = {
400d48f411cSAnilKumar Ch 	.driver		= {
401d48f411cSAnilKumar Ch 		.name	= "tps65217",
402a351451aSSachin Kamat 		.of_match_table = tps65217_of_match,
403d48f411cSAnilKumar Ch 	},
404d48f411cSAnilKumar Ch 	.id_table	= tps65217_id_table,
405511cb174SKeerthy 	.probe_new	= tps65217_probe,
40640a50f8bSMilo Kim 	.remove		= tps65217_remove,
407d48f411cSAnilKumar Ch };
408d48f411cSAnilKumar Ch 
409d48f411cSAnilKumar Ch static int __init tps65217_init(void)
410d48f411cSAnilKumar Ch {
411d48f411cSAnilKumar Ch 	return i2c_add_driver(&tps65217_driver);
412d48f411cSAnilKumar Ch }
413d48f411cSAnilKumar Ch subsys_initcall(tps65217_init);
414d48f411cSAnilKumar Ch 
415d48f411cSAnilKumar Ch static void __exit tps65217_exit(void)
416d48f411cSAnilKumar Ch {
417d48f411cSAnilKumar Ch 	i2c_del_driver(&tps65217_driver);
418d48f411cSAnilKumar Ch }
419d48f411cSAnilKumar Ch module_exit(tps65217_exit);
420d48f411cSAnilKumar Ch 
421d48f411cSAnilKumar Ch MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
422d48f411cSAnilKumar Ch MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
423d48f411cSAnilKumar Ch MODULE_LICENSE("GPL v2");
424