[linux-yocto] [PATCH 2/8] i2c: axxia: Fall back to polling mode when no IRQ

Charlie Paul cpaul.windriver at gmail.com
Tue Jun 3 18:14:24 PDT 2014


From: Anders Berg <anders.berg at avagotech.com>

If the device tree does not specify an interrupt property, the device falls
back to polling the controller status. This is needed to support simulator
models without interrupt capabilities.

Signed-off-by: Anders Berg <anders.berg at avagotech.com>
---
 drivers/i2c/busses/i2c-axxia.c |   82 +++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 34 deletions(-)

diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 4721d3c..93f73ec 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -123,6 +123,8 @@ struct axxia_i2c_dev {
 	size_t msg_xfrd;
 	/* error code for completed message */
 	int msg_err;
+	/* IRQ number (or 0 if not using interrupt) */
+	int irq;
 	/* current i2c bus clock rate */
 	u32 bus_clk_rate;
 };
@@ -327,15 +329,11 @@ status_str(u32 status)
 	return buf;
 }
 
-static irqreturn_t
-axxia_i2c_isr(int irq, void *_dev)
+static void
+axxia_i2c_service_irq(struct axxia_i2c_dev *idev)
 {
-	struct axxia_i2c_dev *idev = _dev;
 	u32 status = readl(&idev->regs->mst_int_status);
 
-	/* Clear interrupt */
-	writel(0x01, &idev->regs->interrupt_status);
-
 	/* RX FIFO needs service? */
 	if (i2c_m_rd(idev->msg) && (status & MST_STATUS_RFL))
 		axxia_i2c_empty_rx_fifo(idev);
@@ -370,6 +368,23 @@ axxia_i2c_isr(int irq, void *_dev)
 			readl(&idev->regs->mst_tx_xfer));
 		complete(&idev->msg_complete);
 	}
+}
+
+static irqreturn_t
+axxia_i2c_isr(int irq, void *_dev)
+{
+	struct axxia_i2c_dev *idev = _dev;
+
+	if ((readl(&idev->regs->interrupt_status) & 0x1) == 0)
+		return IRQ_NONE;
+
+	if (!idev->msg)
+		return IRQ_NONE;
+
+	axxia_i2c_service_irq(idev);
+
+	/* Clear interrupt */
+	writel(0x01, &idev->regs->interrupt_status);
 
 	return IRQ_HANDLED;
 }
@@ -436,14 +451,21 @@ axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 	/* Start manual mode */
 	writel(0x8, &idev->regs->mst_command);
 
-	i2c_int_enable(idev, int_mask);
-
-	ret = wait_for_completion_timeout(&idev->msg_complete,
-					  I2C_XFER_TIMEOUT);
-
-	i2c_int_disable(idev, int_mask);
+	if (idev->irq > 0) {
+		i2c_int_enable(idev, int_mask);
+		ret = wait_for_completion_timeout(&idev->msg_complete,
+						  I2C_XFER_TIMEOUT);
+		i2c_int_disable(idev, int_mask);
+		WARN_ON(readl(&idev->regs->mst_command) & 0x8);
+	} else {
+		unsigned long tmo = jiffies + I2C_XFER_TIMEOUT;
 
-	WARN_ON(readl(&idev->regs->mst_command) & 0x8);
+		do {
+			/* Poll interrupt status */
+			axxia_i2c_service_irq(idev);
+			ret = try_wait_for_completion(&idev->msg_complete);
+		} while (!ret && time_before(jiffies, tmo));
+	}
 
 	if (ret == 0) {
 		dev_warn(idev->dev, "xfer timeout (%#x)\n", msg->addr);
@@ -518,7 +540,6 @@ axxia_i2c_probe(struct platform_device *pdev)
 	struct axxia_i2c_dev *idev = NULL;
 	struct resource *res;
 	void __iomem *base;
-	int irq;
 	int ret = 0;
 
 	idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
@@ -526,48 +547,41 @@ axxia_i2c_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "can't get device io-resource\n");
-		return -ENOENT;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "can't get irq number\n");
-		return -ENOENT;
-	}
-
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
+	idev->irq = platform_get_irq(pdev, 0);
+	if (idev->irq < 0)
+		dev_info(&pdev->dev, "No IRQ specified, using polling mode\n");
+
 	idev->i2c_clk = devm_clk_get(&pdev->dev, "i2c");
 	if (IS_ERR(idev->i2c_clk)) {
 		dev_err(&pdev->dev, "missing I2C bus clock");
 		return PTR_ERR(idev->i2c_clk);
 	}
 
-	idev->regs         = (struct i2c_regs __iomem *) base;
-	idev->dev          = &pdev->dev;
+	idev->regs = (struct i2c_regs __iomem *) base;
+	idev->dev = &pdev->dev;
 	init_completion(&idev->msg_complete);
 
 	of_property_read_u32(np, "clock-frequency", &idev->bus_clk_rate);
 	if (idev->bus_clk_rate == 0)
 		idev->bus_clk_rate = 100000; /* default clock rate */
 
-	platform_set_drvdata(pdev, idev);
-
 	ret = axxia_i2c_init(idev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize i2c controller");
 		return ret;
 	}
 
-	ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0,
-			pdev->name, idev);
-	if (ret) {
-		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
-		return ret;
+	if (idev->irq >= 0) {
+		ret = devm_request_irq(&pdev->dev, idev->irq, axxia_i2c_isr, 0,
+				       pdev->name, idev);
+		if (ret) {
+			dev_err(&pdev->dev, "can't claim irq %d\n", idev->irq);
+			return ret;
+		}
 	}
 
 	clk_enable(idev->i2c_clk);
-- 
1.7.9.5



More information about the linux-yocto mailing list