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