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