[PATCH 3/5] i2c: imx-lpi2c: manage IRQ request/release in runtime pm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Carlos Song <carlos.song@xxxxxxx>

Request the parent interrupt during runtime resume and release the
parent interrupt dunring runtime suspend for allowing the parent
interrupt controller to enter runtime suspend if there are no active
users.

No visible impact if the parent controller is the GIC, but it has
significant power savings for parent IRQ controllers like IRQSteer
inside a subsystem on i.MX8 SoCs. Releasing the parent IRQ provides
an opportunity for the subsystem to enter suspend states if there are
no active users.

Signed-off-by: Carlos Song <carlos.song@xxxxxxx>
Signed-off-by: Frank Li <Frank.Li@xxxxxxx>
---
 drivers/i2c/busses/i2c-imx-lpi2c.c | 40 ++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index 23f83f10d5f6..0159ade235ef 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -168,6 +168,7 @@ struct lpi2c_imx_struct {
 	struct i2c_adapter	adapter;
 	int			num_clks;
 	struct clk_bulk_data	*clks;
+	int			irq;
 	void __iomem		*base;
 	__u8			*rx_buf;
 	__u8			*tx_buf;
@@ -1252,6 +1253,27 @@ static int lpi2c_dma_init(struct device *dev, dma_addr_t phy_addr)
 	return ret;
 }
 
+static int lpi2c_manage_irq_handler(struct lpi2c_imx_struct *lpi2c_imx, bool enable)
+{
+	int ret;
+
+	if (enable) {
+		ret = devm_request_irq(lpi2c_imx->adapter.dev.parent, lpi2c_imx->irq,
+				   lpi2c_imx_isr, IRQF_NO_SUSPEND,
+				   dev_name(lpi2c_imx->adapter.dev.parent),
+				   lpi2c_imx);
+		if (ret) {
+			dev_err(lpi2c_imx->adapter.dev.parent, "can't claim irq %d\n",
+				   lpi2c_imx->irq);
+			return ret;
+		}
+	} else {
+		devm_free_irq(lpi2c_imx->adapter.dev.parent, lpi2c_imx->irq, lpi2c_imx);
+	}
+
+	return 0;
+}
+
 static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
@@ -1277,7 +1299,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
 	struct resource *res;
 	dma_addr_t phy_addr;
 	unsigned int temp;
-	int irq, ret;
+	int ret;
 
 	lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
 	if (!lpi2c_imx)
@@ -1287,9 +1309,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
 	if (IS_ERR(lpi2c_imx->base))
 		return PTR_ERR(lpi2c_imx->base);
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	lpi2c_imx->irq = platform_get_irq(pdev, 0);
+	if (lpi2c_imx->irq < 0)
+		return lpi2c_imx->irq;
 
 	lpi2c_imx->adapter.owner	= THIS_MODULE;
 	lpi2c_imx->adapter.algo		= &lpi2c_imx_algo;
@@ -1309,10 +1331,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
 	if (ret)
 		lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
 
-	ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
-			       pdev->name, lpi2c_imx);
+	ret = lpi2c_manage_irq_handler(lpi2c_imx, true);
 	if (ret)
-		return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq);
+		return ret;
 
 	i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
 	platform_set_drvdata(pdev, lpi2c_imx);
@@ -1392,6 +1413,7 @@ static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
 {
 	struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
 
+	lpi2c_manage_irq_handler(lpi2c_imx, false);
 	clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks);
 	pinctrl_pm_select_sleep_state(dev);
 
@@ -1410,6 +1432,10 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
 		return ret;
 	}
 
+	ret = lpi2c_manage_irq_handler(lpi2c_imx, true);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
2.34.1





[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux