xref: /linux/drivers/misc/tps6594-esm.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1875fdd07SJulien Panis // SPDX-License-Identifier: GPL-2.0
2875fdd07SJulien Panis /*
3875fdd07SJulien Panis  * ESM (Error Signal Monitor) driver for TI TPS6594/TPS6593/LP8764 PMICs
4875fdd07SJulien Panis  *
5875fdd07SJulien Panis  * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
6875fdd07SJulien Panis  */
7875fdd07SJulien Panis 
8875fdd07SJulien Panis #include <linux/interrupt.h>
9875fdd07SJulien Panis #include <linux/module.h>
10875fdd07SJulien Panis #include <linux/platform_device.h>
11875fdd07SJulien Panis #include <linux/pm_runtime.h>
12875fdd07SJulien Panis #include <linux/regmap.h>
13875fdd07SJulien Panis 
14875fdd07SJulien Panis #include <linux/mfd/tps6594.h>
15875fdd07SJulien Panis 
1677107b08SEsteban Blanc #define TPS6594_DEV_REV_1 0x08
1777107b08SEsteban Blanc 
tps6594_esm_isr(int irq,void * dev_id)18875fdd07SJulien Panis static irqreturn_t tps6594_esm_isr(int irq, void *dev_id)
19875fdd07SJulien Panis {
20875fdd07SJulien Panis 	struct platform_device *pdev = dev_id;
21875fdd07SJulien Panis 	int i;
22875fdd07SJulien Panis 
23875fdd07SJulien Panis 	for (i = 0 ; i < pdev->num_resources ; i++) {
24875fdd07SJulien Panis 		if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
25875fdd07SJulien Panis 			dev_err(pdev->dev.parent, "%s error detected\n", pdev->resource[i].name);
26875fdd07SJulien Panis 			return IRQ_HANDLED;
27875fdd07SJulien Panis 		}
28875fdd07SJulien Panis 	}
29875fdd07SJulien Panis 
30875fdd07SJulien Panis 	return IRQ_NONE;
31875fdd07SJulien Panis }
32875fdd07SJulien Panis 
tps6594_esm_probe(struct platform_device * pdev)33875fdd07SJulien Panis static int tps6594_esm_probe(struct platform_device *pdev)
34875fdd07SJulien Panis {
35875fdd07SJulien Panis 	struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
36875fdd07SJulien Panis 	struct device *dev = &pdev->dev;
3777107b08SEsteban Blanc 	unsigned int rev;
38875fdd07SJulien Panis 	int irq;
39875fdd07SJulien Panis 	int ret;
40875fdd07SJulien Panis 	int i;
41875fdd07SJulien Panis 
4277107b08SEsteban Blanc 	/*
4377107b08SEsteban Blanc 	 * Due to a bug in revision 1 of the PMIC, the GPIO3 used for the
4477107b08SEsteban Blanc 	 * SoC ESM function is used to power the load switch instead.
4577107b08SEsteban Blanc 	 * As a consequence, ESM can not be used on those PMIC.
4677107b08SEsteban Blanc 	 * Check the version and return an error in case of revision 1.
4777107b08SEsteban Blanc 	 */
4877107b08SEsteban Blanc 	ret = regmap_read(tps->regmap, TPS6594_REG_DEV_REV, &rev);
4977107b08SEsteban Blanc 	if (ret)
5077107b08SEsteban Blanc 		return dev_err_probe(dev, ret,
5177107b08SEsteban Blanc 				     "Failed to read PMIC revision\n");
5277107b08SEsteban Blanc 	if (rev == TPS6594_DEV_REV_1)
5377107b08SEsteban Blanc 		return dev_err_probe(dev, -ENODEV,
5477107b08SEsteban Blanc 			      "ESM not supported for revision 1 PMIC\n");
5577107b08SEsteban Blanc 
56875fdd07SJulien Panis 	for (i = 0; i < pdev->num_resources; i++) {
57875fdd07SJulien Panis 		irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
58875fdd07SJulien Panis 		if (irq < 0)
59*1314e122SRuan Jinjie 			return irq;
60875fdd07SJulien Panis 
61875fdd07SJulien Panis 		ret = devm_request_threaded_irq(dev, irq, NULL,
62875fdd07SJulien Panis 						tps6594_esm_isr, IRQF_ONESHOT,
63875fdd07SJulien Panis 						pdev->resource[i].name, pdev);
64875fdd07SJulien Panis 		if (ret)
65875fdd07SJulien Panis 			return dev_err_probe(dev, ret, "Failed to request irq\n");
66875fdd07SJulien Panis 	}
67875fdd07SJulien Panis 
68875fdd07SJulien Panis 	ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG,
69875fdd07SJulien Panis 			      TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV);
70875fdd07SJulien Panis 	if (ret)
71875fdd07SJulien Panis 		return dev_err_probe(dev, ret, "Failed to configure ESM\n");
72875fdd07SJulien Panis 
73875fdd07SJulien Panis 	ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
74875fdd07SJulien Panis 			      TPS6594_BIT_ESM_SOC_START);
75875fdd07SJulien Panis 	if (ret)
76875fdd07SJulien Panis 		return dev_err_probe(dev, ret, "Failed to start ESM\n");
77875fdd07SJulien Panis 
78875fdd07SJulien Panis 	pm_runtime_enable(dev);
79875fdd07SJulien Panis 	pm_runtime_get_sync(dev);
80875fdd07SJulien Panis 
81875fdd07SJulien Panis 	return 0;
82875fdd07SJulien Panis }
83875fdd07SJulien Panis 
tps6594_esm_remove(struct platform_device * pdev)8456730af7SUwe Kleine-König static void tps6594_esm_remove(struct platform_device *pdev)
85875fdd07SJulien Panis {
86875fdd07SJulien Panis 	struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
87875fdd07SJulien Panis 	struct device *dev = &pdev->dev;
88875fdd07SJulien Panis 	int ret;
89875fdd07SJulien Panis 
90875fdd07SJulien Panis 	ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
91875fdd07SJulien Panis 				TPS6594_BIT_ESM_SOC_START);
92875fdd07SJulien Panis 	if (ret) {
93875fdd07SJulien Panis 		dev_err(dev, "Failed to stop ESM\n");
94875fdd07SJulien Panis 		goto out;
95875fdd07SJulien Panis 	}
96875fdd07SJulien Panis 
97875fdd07SJulien Panis 	ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG,
98875fdd07SJulien Panis 				TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV);
99875fdd07SJulien Panis 	if (ret)
100875fdd07SJulien Panis 		dev_err(dev, "Failed to unconfigure ESM\n");
101875fdd07SJulien Panis 
102875fdd07SJulien Panis out:
103875fdd07SJulien Panis 	pm_runtime_put_sync(dev);
104875fdd07SJulien Panis 	pm_runtime_disable(dev);
105875fdd07SJulien Panis }
106875fdd07SJulien Panis 
tps6594_esm_suspend(struct device * dev)107875fdd07SJulien Panis static int tps6594_esm_suspend(struct device *dev)
108875fdd07SJulien Panis {
109875fdd07SJulien Panis 	struct tps6594 *tps = dev_get_drvdata(dev->parent);
110875fdd07SJulien Panis 	int ret;
111875fdd07SJulien Panis 
112875fdd07SJulien Panis 	ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
113875fdd07SJulien Panis 				TPS6594_BIT_ESM_SOC_START);
114875fdd07SJulien Panis 
115875fdd07SJulien Panis 	pm_runtime_put_sync(dev);
116875fdd07SJulien Panis 
117875fdd07SJulien Panis 	return ret;
118875fdd07SJulien Panis }
119875fdd07SJulien Panis 
tps6594_esm_resume(struct device * dev)120875fdd07SJulien Panis static int tps6594_esm_resume(struct device *dev)
121875fdd07SJulien Panis {
122875fdd07SJulien Panis 	struct tps6594 *tps = dev_get_drvdata(dev->parent);
123875fdd07SJulien Panis 
124875fdd07SJulien Panis 	pm_runtime_get_sync(dev);
125875fdd07SJulien Panis 
126875fdd07SJulien Panis 	return regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
127875fdd07SJulien Panis 			       TPS6594_BIT_ESM_SOC_START);
128875fdd07SJulien Panis }
129875fdd07SJulien Panis 
130875fdd07SJulien Panis static DEFINE_SIMPLE_DEV_PM_OPS(tps6594_esm_pm_ops, tps6594_esm_suspend, tps6594_esm_resume);
131875fdd07SJulien Panis 
132875fdd07SJulien Panis static struct platform_driver tps6594_esm_driver = {
133875fdd07SJulien Panis 	.driver	= {
134875fdd07SJulien Panis 		.name = "tps6594-esm",
135875fdd07SJulien Panis 		.pm = pm_sleep_ptr(&tps6594_esm_pm_ops),
136875fdd07SJulien Panis 	},
137875fdd07SJulien Panis 	.probe = tps6594_esm_probe,
13856730af7SUwe Kleine-König 	.remove_new = tps6594_esm_remove,
139875fdd07SJulien Panis };
140875fdd07SJulien Panis 
141875fdd07SJulien Panis module_platform_driver(tps6594_esm_driver);
142875fdd07SJulien Panis 
143875fdd07SJulien Panis MODULE_ALIAS("platform:tps6594-esm");
144875fdd07SJulien Panis MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
145875fdd07SJulien Panis MODULE_DESCRIPTION("TPS6594 Error Signal Monitor Driver");
146875fdd07SJulien Panis MODULE_LICENSE("GPL");
147