1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ESM (Error Signal Monitor) driver for TI TPS6594/TPS6593/LP8764 PMICs 4 * 5 * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ 6 */ 7 8 #include <linux/interrupt.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/regmap.h> 13 14 #include <linux/mfd/tps6594.h> 15 16 static irqreturn_t tps6594_esm_isr(int irq, void *dev_id) 17 { 18 struct platform_device *pdev = dev_id; 19 int i; 20 21 for (i = 0 ; i < pdev->num_resources ; i++) { 22 if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) { 23 dev_err(pdev->dev.parent, "%s error detected\n", pdev->resource[i].name); 24 return IRQ_HANDLED; 25 } 26 } 27 28 return IRQ_NONE; 29 } 30 31 static int tps6594_esm_probe(struct platform_device *pdev) 32 { 33 struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); 34 struct device *dev = &pdev->dev; 35 int irq; 36 int ret; 37 int i; 38 39 for (i = 0 ; i < pdev->num_resources ; i++) { 40 irq = platform_get_irq_byname(pdev, pdev->resource[i].name); 41 if (irq < 0) 42 return dev_err_probe(dev, irq, "Failed to get %s irq\n", 43 pdev->resource[i].name); 44 45 ret = devm_request_threaded_irq(dev, irq, NULL, 46 tps6594_esm_isr, IRQF_ONESHOT, 47 pdev->resource[i].name, pdev); 48 if (ret) 49 return dev_err_probe(dev, ret, "Failed to request irq\n"); 50 } 51 52 ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG, 53 TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV); 54 if (ret) 55 return dev_err_probe(dev, ret, "Failed to configure ESM\n"); 56 57 ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG, 58 TPS6594_BIT_ESM_SOC_START); 59 if (ret) 60 return dev_err_probe(dev, ret, "Failed to start ESM\n"); 61 62 pm_runtime_enable(dev); 63 pm_runtime_get_sync(dev); 64 65 return 0; 66 } 67 68 static int tps6594_esm_remove(struct platform_device *pdev) 69 { 70 struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); 71 struct device *dev = &pdev->dev; 72 int ret; 73 74 ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG, 75 TPS6594_BIT_ESM_SOC_START); 76 if (ret) { 77 dev_err(dev, "Failed to stop ESM\n"); 78 goto out; 79 } 80 81 ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG, 82 TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV); 83 if (ret) 84 dev_err(dev, "Failed to unconfigure ESM\n"); 85 86 out: 87 pm_runtime_put_sync(dev); 88 pm_runtime_disable(dev); 89 90 return ret; 91 } 92 93 static int tps6594_esm_suspend(struct device *dev) 94 { 95 struct tps6594 *tps = dev_get_drvdata(dev->parent); 96 int ret; 97 98 ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG, 99 TPS6594_BIT_ESM_SOC_START); 100 101 pm_runtime_put_sync(dev); 102 103 return ret; 104 } 105 106 static int tps6594_esm_resume(struct device *dev) 107 { 108 struct tps6594 *tps = dev_get_drvdata(dev->parent); 109 110 pm_runtime_get_sync(dev); 111 112 return regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG, 113 TPS6594_BIT_ESM_SOC_START); 114 } 115 116 static DEFINE_SIMPLE_DEV_PM_OPS(tps6594_esm_pm_ops, tps6594_esm_suspend, tps6594_esm_resume); 117 118 static struct platform_driver tps6594_esm_driver = { 119 .driver = { 120 .name = "tps6594-esm", 121 .pm = pm_sleep_ptr(&tps6594_esm_pm_ops), 122 }, 123 .probe = tps6594_esm_probe, 124 .remove = tps6594_esm_remove, 125 }; 126 127 module_platform_driver(tps6594_esm_driver); 128 129 MODULE_ALIAS("platform:tps6594-esm"); 130 MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>"); 131 MODULE_DESCRIPTION("TPS6594 Error Signal Monitor Driver"); 132 MODULE_LICENSE("GPL"); 133