From patchwork Fri Feb 8 01:05:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Lunn X-Patchwork-Id: 1038409 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-i2c-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=lunn.ch Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=lunn.ch header.i=@lunn.ch header.b="MppibzpR"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43wcTV1pJPz9sMl for ; Fri, 8 Feb 2019 12:06:54 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726781AbfBHBGx (ORCPT ); Thu, 7 Feb 2019 20:06:53 -0500 Received: from vps0.lunn.ch ([185.16.172.187]:43196 "EHLO vps0.lunn.ch" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726691AbfBHBGx (ORCPT ); Thu, 7 Feb 2019 20:06:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lunn.ch; s=20171124; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=gscr8Zg26o4ajhfhMVvMpi7a9SCVSiyb7h1anTHs04I=; b=MppibzpRJtTrvzva53/agxXnOR evg5vcs0adb0dPAa8JguVwA+gPSi7+Su2g0QIAQ7FddX7e1hYWMTEsm+Bjd8rrk9G0g6H47bgaEMt H3h1ayIntSJoMbBAKJn43hzmmLisuVIjq7LLfrqAqSghWoQaiy72vFLu/8PR2Ji8bvXQ=; Received: from andrew by vps0.lunn.ch with local (Exim 4.89) (envelope-from ) id 1grubz-0003FC-D0; Fri, 08 Feb 2019 02:05:47 +0100 From: Andrew Lunn To: Wolfram Sang Cc: Lee Jones , linux-i2c@vger.kernel.org, Federico Vaga , Andrew Lunn Subject: [PATCH v3 4/4] i2c: ocores: Add support for polling interrupt status Date: Fri, 8 Feb 2019 02:05:07 +0100 Message-Id: <20190208010507.12411-5-andrew@lunn.ch> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190208010507.12411-1-andrew@lunn.ch> References: <20190208010507.12411-1-andrew@lunn.ch> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Not all implementations of the OCORES i2c bus master support generating interrupts. Add support for polling the interrupt status bit when no interrupt is defined. Signed-off-by: Andrew Lunn --- drivers/i2c/busses/i2c-ocores.c | 64 ++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d2730efe6bec..9576e842e557 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -40,10 +41,14 @@ struct ocores_i2c { struct clk *clk; int ip_clock_khz; int bus_clock_khz; + int flags; void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); u8 (*getreg)(struct ocores_i2c *i2c, int reg); }; +/* flags */ +#define I2C_FLAG_NOIRQ BIT(0) + /* registers */ #define OCI2C_PRELOW 0 #define OCI2C_PREHIGH 1 @@ -224,6 +229,27 @@ static irqreturn_t ocores_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void ocores_poll_irq(struct ocores_i2c *i2c) +{ + int timeout = 500; + u8 stat; + + do { + /* delay 2-3 SCL (5-7usec for 400KHz) */ + usleep_range(5, 7); + stat = oc_getreg(i2c, OCI2C_STATUS); + } while ((stat & OCI2C_STAT_TIP) && timeout--); + + + if (!(stat & OCI2C_STAT_TIP)) { + ocores_process(i2c); + } else { + i2c->state = STATE_ERROR; + dev_dbg(&i2c->adap.dev, "Timeout while polling %02x\n", stat); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + } +} + static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct ocores_i2c *i2c = i2c_get_adapdata(adap); @@ -236,11 +262,18 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); - if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ)) + if (i2c->flags & I2C_FLAG_NOIRQ) { + while (!((i2c->state == STATE_DONE) || + (i2c->state == STATE_ERROR))) + ocores_poll_irq(i2c); return (i2c->state == STATE_DONE) ? num : -EIO; - else - return -ETIMEDOUT; + } else { + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ)) + return (i2c->state == STATE_DONE) ? num : -EIO; + } + return -ETIMEDOUT; } static int ocores_init(struct device *dev, struct ocores_i2c *i2c) @@ -425,14 +458,17 @@ static int ocores_i2c_probe(struct platform_device *pdev) int ret; int i; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) + i2c->flags |= I2C_FLAG_NOIRQ; + else + if (irq < 0) + return irq; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { i2c->base = devm_ioremap_resource(&pdev->dev, res); @@ -504,11 +540,13 @@ static int ocores_i2c_probe(struct platform_device *pdev) goto err_clk; init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, - pdev->name, i2c); - if (ret) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_clk; + if (!(i2c->flags & I2C_FLAG_NOIRQ)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } } /* hook up driver to tree */