From patchwork Mon Aug 13 21:16:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Lengfeld X-Patchwork-Id: 10564817 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5476C1515 for ; Mon, 13 Aug 2018 21:16:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 46D58286FD for ; Mon, 13 Aug 2018 21:16:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3B2FE28E29; Mon, 13 Aug 2018 21:16:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D0AD528B68 for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729947AbeHNAAW (ORCPT ); Mon, 13 Aug 2018 20:00:22 -0400 Received: from stcim.de ([78.46.90.227]:34456 "EHLO stcim.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730027AbeHNAAT (ORCPT ); Mon, 13 Aug 2018 20:00:19 -0400 Received: from xdsl-87-78-37-34.netcologne.de ([87.78.37.34] helo=localhost.localdomain) by stcim with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fpKCF-0008Ap-Nn; Mon, 13 Aug 2018 23:16:15 +0200 From: Stefan Lengfeld To: linux-i2c@vger.kernel.org Cc: wsa@the-dreams.de, preid@electromag.com.au, j-keerthy@ti.com, tony@atomide.com, nsekhar@ti.com, vigneshr@ti.com, linux-omap@vger.kernel.org Subject: [RFC PATCH 1/4] i2c: allow drivers to announce that they are IRQ safe Date: Mon, 13 Aug 2018 23:16:11 +0200 Message-Id: <20180813211614.16440-2-contact@stefanchrist.eu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180813211614.16440-1-contact@stefanchrist.eu> References: <5bb4b898-acc3-7c73-2285-cf84a88961e6@ti.com> <20180813211614.16440-1-contact@stefanchrist.eu> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Like the PM subsystem routine pm_runtime_irq_safe() and flag 'irq_safe' add a similar function i2c_adapter_irq_safe() to the I2C core. A driver should be able to announce whether his transfer implementations are safe to be called in IRQ disabled or atomic contexts, also called polling mode or sleep free operation. Making I2C transfers in atomic context is sometimes needed, e.g. for reboot handlers. Every driver should be able to declare explicitly whether IRQ disabled operation is supported or not. When you try make a I2C transfer in atomic contexts, it's already hard enough to ensure that every code path through the kernel is sleep-free. So give the curious developer a strong hint whether a driver supports atomic operation or not. Fail early instead of hoping that the LOCKDEP framework noticed the programming error. TODOs: - checkpatch complains hat in_atomic() should not be used in driver code Signed-off-by: Stefan Lengfeld Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 8 ++++++++ include/linux/i2c.h | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 15c95aaa484c..d4a76c8cd777 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1858,6 +1858,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP; + if (in_atomic() || irqs_disabled()) { + if (!adap->irq_safe) { + dev_err(&adap->dev, + "IRQ disabled transfers not supported by the driver\n"); + return -EOPNOTSUPP; + } + } + /* * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 254cd34eeae2..f2d31ba09afe 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -664,6 +664,13 @@ struct i2c_adapter { const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; + /* + * implementations in i2c_algorithm like 'master_xfer' are safe to be + * use in IRQ disabled contexts. A driver should set the flag with + * i2c_adapter_irq_safe() in it's probe function. + */ + bool irq_safe; + /* data fields that are valid for all devices */ const struct i2c_lock_operations *lock_ops; struct rt_mutex bus_lock; @@ -710,6 +717,15 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter) return NULL; } +/** + * i2c_adapter_irq_safe - driver is safe to be used in IRQ disabled context + * @adapter: Target I2C bus segment + */ +static inline void i2c_adapter_irq_safe(struct i2c_adapter *adapter) +{ + adapter->irq_safe = true; +} + int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)); /* Adapter locking functions, exported for shared pin cases */ From patchwork Mon Aug 13 21:16:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Lengfeld X-Patchwork-Id: 10564815 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CC0961815 for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BCC07286FD for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B11F428B68; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E449C2946D for ; Mon, 13 Aug 2018 21:16:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730131AbeHNAAU (ORCPT ); Mon, 13 Aug 2018 20:00:20 -0400 Received: from stcim.de ([78.46.90.227]:34450 "EHLO stcim.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729815AbeHNAAT (ORCPT ); Mon, 13 Aug 2018 20:00:19 -0400 Received: from xdsl-87-78-37-34.netcologne.de ([87.78.37.34] helo=localhost.localdomain) by stcim with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fpKCG-0008Ap-5a; Mon, 13 Aug 2018 23:16:16 +0200 From: Stefan Lengfeld To: linux-i2c@vger.kernel.org Cc: wsa@the-dreams.de, preid@electromag.com.au, j-keerthy@ti.com, tony@atomide.com, nsekhar@ti.com, vigneshr@ti.com, linux-omap@vger.kernel.org Subject: [RFC PATCH 2/4] i2c: imx: implement IRQ less master_xfer function Date: Mon, 13 Aug 2018 23:16:12 +0200 Message-Id: <20180813211614.16440-3-contact@stefanchrist.eu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180813211614.16440-1-contact@stefanchrist.eu> References: <5bb4b898-acc3-7c73-2285-cf84a88961e6@ti.com> <20180813211614.16440-1-contact@stefanchrist.eu> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Rework the read and write code paths in the driver to support operation in IRQ disabled contexts. The patch is currently tested only on a phyCORE-i.MX6 Solo board. The driver supports normal operation, DMA transfers and now the polling mode or also called sleep-free or IRQ-less operation. It makes the code not simpler or easier to read, but IRQ less I2C transfers are needed on some hardware configurations, e.g. to trigger a reboot in an external PMIC chip. TODOs: - checkpatch complains that in_atomic() should not be used in driver code. Signed-off-by: Stefan Lengfeld --- drivers/i2c/busses/i2c-imx.c | 113 +++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 498c5e891649..8a17c8c454c7 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -404,7 +404,7 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) dma->chan_using = NULL; } -static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) +static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool polling) { unsigned long orig_jiffies = jiffies; unsigned int temp; @@ -430,15 +430,39 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) "<%s> I2C bus is busy\n", __func__); return -ETIMEDOUT; } - schedule(); + if (!polling) + schedule(); + else + udelay(100); } return 0; } -static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx) +static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool polling) { - wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10); + if (!polling) { + wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10); + } else { + int counter = 0; + + while (1) { + unsigned int reg; + + reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + i2c_imx->i2csr = reg; + if (reg & I2SR_IIF) + break; + + if (counter > 1000) { + dev_err(&i2c_imx->adapter.dev, "<%s> TXR timeout\n", __func__); + return -EIO; + } + udelay(100); + counter++; + } + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); + } if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) { dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__); @@ -516,7 +540,7 @@ static int i2c_imx_clk_notifier_call(struct notifier_block *nb, return NOTIFY_OK; } -static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) +static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool polling) { unsigned int temp = 0; int result; @@ -529,24 +553,33 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR); /* Wait controller to be stable */ - usleep_range(50, 150); + if (!polling) + usleep_range(50, 150); + else + udelay(50); /* Start I2C transaction */ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp |= I2CR_MSTA; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - result = i2c_imx_bus_busy(i2c_imx, 1); + result = i2c_imx_bus_busy(i2c_imx, 1, polling); if (result) return result; i2c_imx->stopped = 0; - temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; + if (!polling) { + temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; + } else { + temp |= I2CR_MTX | I2CR_TXAK; + temp &= ~I2CR_IIEN; /* Disable interrupt */ + } + temp &= ~I2CR_DMAEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); return result; } -static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) +static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool polling) { unsigned int temp = 0; @@ -568,7 +601,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) } if (!i2c_imx->stopped) { - i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx_bus_busy(i2c_imx, 0, polling); i2c_imx->stopped = 1; } @@ -651,7 +684,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, /* The last data byte must be transferred by the CPU. */ imx_i2c_write_reg(msgs->buf[msgs->len-1], i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, false); if (result) return result; @@ -713,7 +746,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* read n byte data */ - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, false); if (result) return result; @@ -726,7 +759,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx_bus_busy(i2c_imx, 0, false); i2c_imx->stopped = 1; } else { /* @@ -745,7 +778,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, return 0; } -static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool polling) { int i, result; @@ -754,7 +787,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) /* write slave address */ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, polling); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -768,7 +801,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) "<%s> write byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, polling); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -778,7 +811,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg, bool polling) { int i, result; unsigned int temp; @@ -790,7 +823,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo /* write slave address */ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, polling); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -814,14 +847,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) + if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data && !polling) return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; - result = i2c_imx_trx_complete(i2c_imx); + result = i2c_imx_trx_complete(i2c_imx, polling); if (result) return result; /* @@ -849,7 +882,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx_bus_busy(i2c_imx, 0, polling); i2c_imx->stopped = 1; } else { /* @@ -888,6 +921,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, int result; bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); + bool polling = in_atomic() || irqs_disabled(); dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); @@ -896,11 +930,11 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, goto out; /* Start I2C transfer */ - result = i2c_imx_start(i2c_imx); + result = i2c_imx_start(i2c_imx, polling); if (result) { if (i2c_imx->adapter.bus_recovery_info) { i2c_recover_bus(&i2c_imx->adapter); - result = i2c_imx_start(i2c_imx); + result = i2c_imx_start(i2c_imx, polling); } } @@ -918,7 +952,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp |= I2CR_RSTA; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - result = i2c_imx_bus_busy(i2c_imx, 1); + result = i2c_imx_bus_busy(i2c_imx, 1, polling); if (result) goto fail0; } @@ -942,13 +976,17 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), (temp & I2SR_RXAK ? 1 : 0)); #endif - if (msgs[i].flags & I2C_M_RD) - result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); - else { - if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD) - result = i2c_imx_dma_write(i2c_imx, &msgs[i]); - else - result = i2c_imx_write(i2c_imx, &msgs[i]); + if (msgs[i].flags & I2C_M_RD) { + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, polling); + } else { + if (!polling) { + if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD) + result = i2c_imx_dma_write(i2c_imx, &msgs[i]); + else + result = i2c_imx_write(i2c_imx, &msgs[i], polling); + } else { + result = i2c_imx_write(i2c_imx, &msgs[i], polling); + } } if (result) goto fail0; @@ -956,7 +994,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, fail0: /* Stop I2C transfer */ - i2c_imx_stop(i2c_imx); + i2c_imx_stop(i2c_imx, polling); pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); @@ -1088,6 +1126,9 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.dev.of_node = pdev->dev.of_node; i2c_imx->base = base; + /* Drivers supports IRQ less operations */ + i2c_adapter_irq_safe(&i2c_imx->adapter); + /* Get I2C clock */ i2c_imx->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_imx->clk)) { @@ -1118,6 +1159,14 @@ static int i2c_imx_probe(struct platform_device *pdev) /* Set up platform driver data */ platform_set_drvdata(pdev, i2c_imx); + /* + * Driver's PM callbacks are safe to be called in IRQ disabled + * contexts. Providing this information to the PM subsystem is required + * for the 'master_xfer' implementation that calls PM routines in IRQ + * disabled/atomic contexts, too. + */ + pm_runtime_irq_safe(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); From patchwork Mon Aug 13 21:16:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Lengfeld X-Patchwork-Id: 10564813 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 363F79093 for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 25487286FD for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 19B9028B68; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 47E7428E29 for ; Mon, 13 Aug 2018 21:16:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730178AbeHNAAU (ORCPT ); Mon, 13 Aug 2018 20:00:20 -0400 Received: from stcim.de ([78.46.90.227]:34454 "EHLO stcim.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729947AbeHNAAT (ORCPT ); Mon, 13 Aug 2018 20:00:19 -0400 Received: from xdsl-87-78-37-34.netcologne.de ([87.78.37.34] helo=localhost.localdomain) by stcim with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fpKCG-0008Ap-IC; Mon, 13 Aug 2018 23:16:16 +0200 From: Stefan Lengfeld To: linux-i2c@vger.kernel.org Cc: wsa@the-dreams.de, preid@electromag.com.au, j-keerthy@ti.com, tony@atomide.com, nsekhar@ti.com, vigneshr@ti.com, linux-omap@vger.kernel.org Subject: [RFC PATCH 3/4] watchdog: da9062: avoid regmap in restart handler Date: Mon, 13 Aug 2018 23:16:13 +0200 Message-Id: <20180813211614.16440-4-contact@stefanchrist.eu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180813211614.16440-1-contact@stefanchrist.eu> References: <5bb4b898-acc3-7c73-2285-cf84a88961e6@ti.com> <20180813211614.16440-1-contact@stefanchrist.eu> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Using i2c_transfer() to set the shutdown bit is more reliable than using regmap. Furthermore you have to void the default lock configuration in the regmap configuration, e.g. by setting use_hwlock to true, to used in atomic/IRQ disabled contexts. Tested on a phyCORE-i.MX6 Solo board. Signed-off-by: Stefan Lengfeld --- drivers/mfd/da9062-core.c | 1 + drivers/watchdog/da9062_wdt.c | 17 +++++++++++++---- include/linux/mfd/da9062/core.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 9f6105906c09..b6a01054ba0f 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -609,6 +609,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, chip); chip->dev = &i2c->dev; + chip->i2c = i2c; if (!i2c->irq) { dev_err(chip->dev, "No IRQ configured\n"); diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index fe169d8e1fb2..ad6483d25f83 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -152,12 +153,20 @@ static int da9062_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) { struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd); + struct i2c_client *client = wdt->hw->i2c; + __u8 buf[3] = {DA9062AA_CONTROL_F, DA9062AA_SHUTDOWN_MASK, 0x0}; + struct i2c_msg msgs[1] = { + { + .addr = client->addr, + .flags = (client->flags & I2C_M_TEN), + .len = sizeof(buf), + .buf = buf, + } + }; int ret; - ret = regmap_write(wdt->hw->regmap, - DA9062AA_CONTROL_F, - DA9062AA_SHUTDOWN_MASK); - if (ret) + ret = i2c_transfer(client->adapter, msgs, sizeof(msgs)); + if (ret < 0) dev_alert(wdt->hw->dev, "Failed to shutdown (err = %d)\n", ret); diff --git a/include/linux/mfd/da9062/core.h b/include/linux/mfd/da9062/core.h index 74d33a01ddae..c994293b3aef 100644 --- a/include/linux/mfd/da9062/core.h +++ b/include/linux/mfd/da9062/core.h @@ -68,6 +68,7 @@ enum da9062_irqs { struct da9062 { struct device *dev; struct regmap *regmap; + struct i2c_client *i2c; struct regmap_irq_chip_data *regmap_irq; enum da9062_compatible_types chip_type; }; From patchwork Mon Aug 13 21:16:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Lengfeld X-Patchwork-Id: 10564809 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 11CF71057 for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 041E2286FD for ; Mon, 13 Aug 2018 21:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E921629469; Mon, 13 Aug 2018 21:16:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B016286FD for ; Mon, 13 Aug 2018 21:16:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730014AbeHNAAT (ORCPT ); Mon, 13 Aug 2018 20:00:19 -0400 Received: from stcim.de ([78.46.90.227]:34452 "EHLO stcim.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729126AbeHNAAT (ORCPT ); Mon, 13 Aug 2018 20:00:19 -0400 Received: from xdsl-87-78-37-34.netcologne.de ([87.78.37.34] helo=localhost.localdomain) by stcim with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fpKCG-0008Ap-W6; Mon, 13 Aug 2018 23:16:17 +0200 From: Stefan Lengfeld To: linux-i2c@vger.kernel.org Cc: wsa@the-dreams.de, preid@electromag.com.au, j-keerthy@ti.com, tony@atomide.com, nsekhar@ti.com, vigneshr@ti.com, linux-omap@vger.kernel.org Subject: [RFC PATCH 4/4] ARM: dts: phyboard-mira-dl: rely on PMIC for reboot and watchdog Date: Mon, 13 Aug 2018 23:16:14 +0200 Message-Id: <20180813211614.16440-5-contact@stefanchrist.eu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180813211614.16440-1-contact@stefanchrist.eu> References: <5bb4b898-acc3-7c73-2285-cf84a88961e6@ti.com> <20180813211614.16440-1-contact@stefanchrist.eu> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stefan Christ Rely on PMIC watchdog and reboot support. The i.MX6 internal cannot be used, because it does not reset external PMIC voltages on reset. Signed-off-by: Stefan Christ Signed-off-by: Christian Hemp --- arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts b/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts index 9f7f9f98139d..04e2d5a1b998 100644 --- a/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts +++ b/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts @@ -62,3 +62,11 @@ &usdhc1 { status = "okay"; }; + +&wdog1 { + /* + * Rely on PMIC reboot handler. Internal i.MX6 watchdog, that is also + * used for reboot, does not reset all external PMIC voltages on reset. + */ + status = "disabled"; +};