From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77812C433E7 for ; Thu, 8 Oct 2020 21:46:13 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DEAC522241 for ; Thu, 8 Oct 2020 21:46:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="gsiWP0FX"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OE2IBRjW" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DEAC522241 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=UgIbIvTkPzSV8/MwH83q77+Xos1SJo2zA2p4DfMgCQE=; b=gsiWP0FXopY1ExIaWE4OoVVbN +IRk1ZXYFjGYcFKDY1VM5BUpYavBd6I9k2pg4+vwarxPEazccUq4ARZW6FsT6ymgcc/KIv9l19M/p O580qqqjh62JzAmVxsM1EVIg7fEnOnkZDdihO/M0KU7K9rvravF45XNYQRm79fpsO1OaaXzl/yKC7 jmCZfAm8SPJQT4gn4P+0fCt2zpT/eAA098P++xlTFe0zvTRnAOavBv5OHenMRpx07PRGTUKCKXgpo SC9qogTFozuN/r+wuLE5hNo8hmZ4BMiGyK6d4uYnbmfPmPvO/RMM4ZZ9Tj6Nf13DprxIltlFgGK+v 5b3Ws8htw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQdiW-0007Ao-Lh; Thu, 08 Oct 2020 21:44:52 +0000 Received: from mail-ej1-x641.google.com ([2a00:1450:4864:20::641]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kQdiQ-00077g-7k; Thu, 08 Oct 2020 21:44:47 +0000 Received: by mail-ej1-x641.google.com with SMTP id t25so10145695ejd.13; Thu, 08 Oct 2020 14:44:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+vRhCjiVUVFH3G124IdR61piZRspREO/rEPWGy9BWxg=; b=OE2IBRjWd1oAfXKOsWiOL4VCsAwNQrmacHLACHq020C/pF8A01mqO3kz8WdRidTioQ YEb40WH5hgxYNl85yufupO6XKmskcdIawqcuqX0O1gbS5N3WpaVdENN+8QMG+z1m4jJQ YfxA6d2aEJybfDES/B6qKYxc/1jw7Z1Nd4jIl5WnIvT9Gp/atbnFJr6KtQVmUfuoDa7O AheSmt3DnF/gyYENcUhfgQ+AaZmqbYVshRhWUkf/Rev6ESSij5O+2+lAJT1cBH/iTyys NhrKVlGG7vXrYmCf5H54lQ9pR82+7QOnzcIG6uGlgSext2FQrtX+R6aW7pW9In5zvU+w aQhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+vRhCjiVUVFH3G124IdR61piZRspREO/rEPWGy9BWxg=; b=Wc37r3DbWC8K9ypXDu3ruxIiKdxBz8iFNRpXLhObmUwGWCqZ09Kuva4t3OezTuVAI6 dHOZe0Urte3ETKpqscrpPs7ctWMUptHefmIitgxK3vsxgbg8uviQfUIXecvkaQ6I6m+r eVwP67b1melypweIULHLMWOUUyUt4QcJ0MvGDRNQ5kcxzYn/TcXZ+1Ll09IQ0RsJNJde Ewd7HzEm6AYK7cs8snpZmMthWkxY4qnoFox6ET6JitFFmdS7OGq9iOj8g9G5fcpMMLcQ ZtjXEdVrUGF38OnHWZI+L7Jo5AO9RPy9E0Nwu+v0yssDDtDuvYwJiBQcie+ryzQZr4Gv og0Q== X-Gm-Message-State: AOAM531dtPIGSowGOrWWYHgLRtwC5JE8kSOvAmjeNr92qxhSup1tk9XG K0503N6pxQ3oCNOrJhFe2og= X-Google-Smtp-Source: ABdhPJycEWkipjHPOyuKr4qGRzpT/wp+WtXANx4UquZVnTc2ogQ5cZOicR7zj7rC27AN5WotS68Bbg== X-Received: by 2002:a17:906:515:: with SMTP id j21mr10816344eja.105.1602193485084; Thu, 08 Oct 2020 14:44:45 -0700 (PDT) Received: from localhost.localdomain ([188.24.159.61]) by smtp.gmail.com with ESMTPSA id i8sm4831800ejg.84.2020.10.08.14.44.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Oct 2020 14:44:44 -0700 (PDT) From: Cristian Ciocaltea To: Manivannan Sadhasivam , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Wolfram Sang , Peter Rosin Subject: [PATCH 2/3] i2c: owl: Add support for atomic transfers Date: Fri, 9 Oct 2020 00:44:40 +0300 Message-Id: <1af37112fafd6cf069dfe864560f77996f57d80d.1602190168.git.cristian.ciocaltea@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201008_174446_301228_A798CEC7 X-CRM114-Status: GOOD ( 22.86 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-actions@lists.infradead.org, linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Atomic transfers are required to properly power off a machine through an I2C controlled PMIC, such as the Actions Semi ATC260x series. System shutdown may happen with interrupts being disabled and, as a consequence, the kernel may hang if the driver does not support atomic transfers. This functionality is essentially implemented by polling the FIFO Status register until either Command Execute Completed or NACK Error bits are set. Signed-off-by: Cristian Ciocaltea --- drivers/i2c/busses/i2c-owl.c | 76 ++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c index a163b8f308c1..547132768119 100644 --- a/drivers/i2c/busses/i2c-owl.c +++ b/drivers/i2c/busses/i2c-owl.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,7 @@ #define OWL_I2C_FIFOCTL_TFR BIT(2) /* I2Cc_FIFOSTAT Bit Mask */ +#define OWL_I2C_FIFOSTAT_CECB BIT(0) #define OWL_I2C_FIFOSTAT_RNB BIT(1) #define OWL_I2C_FIFOSTAT_RFE BIT(2) #define OWL_I2C_FIFOSTAT_TFF BIT(5) @@ -83,7 +85,8 @@ #define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8) /* I2C bus timeout */ -#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000) +#define OWL_I2C_TIMEOUT_MS (4 * 1000) +#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS) #define OWL_I2C_MAX_RETRIES 50 @@ -161,15 +164,11 @@ static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev) writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV); } -static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) +static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev) { - struct owl_i2c_dev *i2c_dev = _dev; struct i2c_msg *msg = i2c_dev->msg; - unsigned long flags; unsigned int stat, fifostat; - spin_lock_irqsave(&i2c_dev->lock, flags); - i2c_dev->err = 0; /* Handle NACK from slave */ @@ -179,7 +178,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) /* Clear NACK error bit by writing "1" */ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, OWL_I2C_FIFOSTAT_RNB, true); - goto stop; + return; } /* Handle bus error */ @@ -189,7 +188,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) /* Clear BUS error bit by writing "1" */ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, OWL_I2C_STAT_BEB, true); - goto stop; + return; } /* Handle FIFO read */ @@ -207,13 +206,23 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) i2c_dev->base + OWL_I2C_REG_TXDAT); } } +} + +static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) +{ + struct owl_i2c_dev *i2c_dev = _dev; + unsigned long flags; + + spin_lock_irqsave(&i2c_dev->lock, flags); + + owl_i2c_xfer_data(i2c_dev); -stop: /* Clear pending interrupts */ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, OWL_I2C_STAT_IRQP, true); complete_all(&i2c_dev->msg_complete); + spin_unlock_irqrestore(&i2c_dev->lock, flags); return IRQ_HANDLED; @@ -241,8 +250,8 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap) return 0; } -static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num, bool atomic) { struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); struct i2c_msg *msg; @@ -286,11 +295,12 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto err_exit; } - reinit_completion(&i2c_dev->msg_complete); + if (!atomic) + reinit_completion(&i2c_dev->msg_complete); - /* Enable I2C controller interrupt */ + /* Enable/disable I2C controller interrupt */ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, - OWL_I2C_CTL_IRQE, true); + OWL_I2C_CTL_IRQE, !atomic); /* * Select: FIFO enable, Master mode, Stop enable, Data count enable, @@ -358,20 +368,33 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, spin_unlock_irqrestore(&i2c_dev->lock, flags); - time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, - adap->timeout); + if (atomic) { + /* Wait for Command Execute Completed or NACK Error bits */ + ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, + val, val & (OWL_I2C_FIFOSTAT_CECB | + OWL_I2C_FIFOSTAT_RNB), + 10, OWL_I2C_TIMEOUT_MS * 1000); + } else { + time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, + adap->timeout); + if (!time_left) + ret = -ETIMEDOUT; + } spin_lock_irqsave(&i2c_dev->lock, flags); - if (time_left == 0) { + + if (ret) { dev_err(&adap->dev, "Transaction timed out\n"); /* Send stop condition and release the bus */ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB, true); - ret = -ETIMEDOUT; goto err_exit; } + if (atomic) + owl_i2c_xfer_data(i2c_dev); + ret = i2c_dev->err < 0 ? i2c_dev->err : num; err_exit: @@ -385,9 +408,22 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, return ret; } +static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + return owl_i2c_xfer_common(adap, msgs, num, false); +} + +static int owl_i2c_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return owl_i2c_xfer_common(adap, msgs, num, true); +} + static const struct i2c_algorithm owl_i2c_algorithm = { - .master_xfer = owl_i2c_master_xfer, - .functionality = owl_i2c_func, + .master_xfer = owl_i2c_xfer, + .master_xfer_atomic = owl_i2c_xfer_atomic, + .functionality = owl_i2c_func, }; static const struct i2c_adapter_quirks owl_i2c_quirks = { -- 2.28.0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel