From patchwork Fri Oct 30 06:53:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rayagonda Kokatanur X-Patchwork-Id: 314931 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,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MIME_HEADER_CTYPE_ONLY, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, T_TVD_MIME_NO_HEADERS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham 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 C4857C56201 for ; Fri, 30 Oct 2020 06:54:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5AA4A22206 for ; Fri, 30 Oct 2020 06:54:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="Nu7L8FHj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725838AbgJ3GyE (ORCPT ); Fri, 30 Oct 2020 02:54:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48500 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725355AbgJ3GyE (ORCPT ); Fri, 30 Oct 2020 02:54:04 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D2B9C0613CF for ; Thu, 29 Oct 2020 23:54:04 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id 15so4381640pgd.12 for ; Thu, 29 Oct 2020 23:54:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3D7C6lvkSxGGJeIa3XJBvmbloIWB9HX9Yj9MOnaBSM4=; b=Nu7L8FHjvrC4zq20j6bgS2k2y1/gMPnAIf0P0QD62t59RvgLyZLkckAeqS3pyS6TqN 3aF4SyY55O/nusEtIH6VLFP4L3DxBvui7x8FflmkDTHSOuHJEEgt8j0ah6u/SGatAhFn 3NAGA7MEDIbV+ujg3JZCgMTr2XsO+/9VR2PDE= 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; bh=3D7C6lvkSxGGJeIa3XJBvmbloIWB9HX9Yj9MOnaBSM4=; b=XBwW4ssMYwszm+cNSz6iwZBJExTyOXsEAA32/PjCCF2Elxbkhg5ew3q6ppkIv3Aomu oH4oKmAg/cK4qtjzwnsslrEY79owtMbGoOrfuKRt2ZTVvZEVP6BVrjiCSZP+LcnIwwWS DHlHG84zeGU1L3xyy2wICg7aBM9x5PI/8iPSwvfh/wwjtdEs3yt+/5hoqrnCa/dPCLn/ 7vtm3rvB7IYrwXQtS9FC0AC9s9/YpcEd3j9vCG7F+CdIJIuCADs2jDErGFCa4/m9rY5V Xbno+Yne8TjA0AkhXMG4clWlkSHXW4m2Oirg+1SchSanWv217Vi+8+b4R8KzHBEM+Psj oXIQ== X-Gm-Message-State: AOAM532/wDI97vZSGjKMVRISfGRSN2wRd2ERL0undqSH+8jgaBNDoVEt HID1WTYVB/oZYeaNLdiG6lM7AQ== X-Google-Smtp-Source: ABdhPJxdS9/aIeQB6jOaeDfbVW+kXRz6W/Etxf4U+vB7XrHdtQgqNyPLHBURISVDPSqz9FtqzyirNA== X-Received: by 2002:a17:90a:a48c:: with SMTP id z12mr1133870pjp.108.1604040843875; Thu, 29 Oct 2020 23:54:03 -0700 (PDT) Received: from rayagonda.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id n1sm4561547pgl.31.2020.10.29.23.53.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2020 23:54:02 -0700 (PDT) From: Rayagonda Kokatanur To: Ray Jui , Scott Branden , bcm-kernel-feedback-list@broadcom.com, Wolfram Sang , Florian Fainelli , Brendan Higgins , Andy Shevchenko , Lori Hikichi , Dhananjay Phadke , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Rayagonda Kokatanur Subject: [PATCH v2 1/6] i2c: iproc: handle Master aborted error Date: Fri, 30 Oct 2020 12:23:34 +0530 Message-Id: <20201030065339.955-2-rayagonda.kokatanur@broadcom.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> References: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Handle Master aborted error by flushing tx and rx fifo and reinitializing the hw. Signed-off-by: Rayagonda Kokatanur --- drivers/i2c/busses/i2c-bcm-iproc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index d8295b1c379d..834a98caeada 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -93,6 +93,7 @@ #define S_CMD_STATUS_MASK 0x07 #define S_CMD_STATUS_SUCCESS 0x0 #define S_CMD_STATUS_TIMEOUT 0x5 +#define S_CMD_STATUS_MASTER_ABORT 0x7 #define IE_OFFSET 0x38 #define IE_M_RX_FIFO_FULL_SHIFT 31 @@ -311,9 +312,10 @@ static void bcm_iproc_i2c_check_slave_status( return; val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; - if (val == S_CMD_STATUS_TIMEOUT) { - dev_err(iproc_i2c->device, "slave random stretch time timeout\n"); - + if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) { + dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ? + "slave random stretch time timeout\n" : + "Master aborted read transaction\n"); /* re-initialize i2c for recovery */ bcm_iproc_i2c_enable_disable(iproc_i2c, false); bcm_iproc_i2c_slave_init(iproc_i2c, true); From patchwork Fri Oct 30 06:53:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rayagonda Kokatanur X-Patchwork-Id: 314930 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,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MIME_HEADER_CTYPE_ONLY, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, T_TVD_MIME_NO_HEADERS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham 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 65C9FC4742C for ; Fri, 30 Oct 2020 06:54:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E48E622203 for ; Fri, 30 Oct 2020 06:54:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="TEXz9ViK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725882AbgJ3GyR (ORCPT ); Fri, 30 Oct 2020 02:54:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725948AbgJ3GyQ (ORCPT ); Fri, 30 Oct 2020 02:54:16 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4817AC0613CF for ; Thu, 29 Oct 2020 23:54:16 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id f38so4417917pgm.2 for ; Thu, 29 Oct 2020 23:54:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BoR2Vmif+0u3j9F3e+UrASJyApB17Ix4z/Z7FITHdbk=; b=TEXz9ViKVEnMeIk5TpjqNswxr9mdYac+tgZnkqadH2/Ra0w7uvwaE2R5oQNBvb5SBZ MQZ9Iv4LmUVjgjE/XZLKnnPfDt8zNnu1Yz4LhlUVeGwcVTxS/DQ5ODDcBYYjaMO1XW5a 0He1lRjWe7FwXEQdlf9494d407zwRgMbk9nAE= 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; bh=BoR2Vmif+0u3j9F3e+UrASJyApB17Ix4z/Z7FITHdbk=; b=jnpldDmu3omiE5ONA6WF1GccroAd/JNQDWm7JFPIYdRVn+/EG2Ua7Zy7ZNEJ4adt6F z6hX/il/ThseO/yt5iGhdJtS7CRE23HYKdaesUcRZ29GhzYSXDSiffxHRdJ6Z14BIges 9qiMjyXi7TOh6qo2Ts8R8tKMPp+pwPOI248ixOxSBm6ObnnYRl4pCJznVYj2AHFqCVIL 8LmuULELmNUFu6BFOv7J502b8Q04t7yVRiGJks6ID/xwT26dCXVpsU3I3YJkwRVCyRmf xdFl3x7U4q7AcPnNPO55Kec/bSt52U7+Wl1xLVCXfFwwAVzsJVHASS2ia1spVElObJgv Ce9Q== X-Gm-Message-State: AOAM5328UBcYgugGeVNv3pYSiMV7cNYiVwVYPIJZHiSsQG9aZIFMJY7I 6QI2bDzai6PjTgZ24TyK+vDHXg== X-Google-Smtp-Source: ABdhPJwhpXMG+ZMd6b0Zowiw9iHoUNYR3WFJPjIueYSku0pEqPe6igYz08wuJPo62F0FR3UUYYUyZA== X-Received: by 2002:a17:90a:f683:: with SMTP id cl3mr1160637pjb.84.1604040855688; Thu, 29 Oct 2020 23:54:15 -0700 (PDT) Received: from rayagonda.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id n1sm4561547pgl.31.2020.10.29.23.54.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2020 23:54:14 -0700 (PDT) From: Rayagonda Kokatanur To: Ray Jui , Scott Branden , bcm-kernel-feedback-list@broadcom.com, Wolfram Sang , Florian Fainelli , Brendan Higgins , Andy Shevchenko , Lori Hikichi , Dhananjay Phadke , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Rayagonda Kokatanur Subject: [PATCH v2 3/6] i2c: iproc: update slave isr mask (ISR_MASK_SLAVE) Date: Fri, 30 Oct 2020 12:23:36 +0530 Message-Id: <20201030065339.955-4-rayagonda.kokatanur@broadcom.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> References: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Update slave isr mask (ISR_MASK_SLAVE) to include remaining two slave interrupts. Fixes: c245d94ed106 ("i2c: iproc: Add multi byte read-write support for slave mode") Signed-off-by: Rayagonda Kokatanur --- drivers/i2c/busses/i2c-bcm-iproc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index b54f5130d246..cd687696bf0b 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -216,7 +216,8 @@ struct bcm_iproc_i2c_dev { #define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\ | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\ - | BIT(IS_S_TX_UNDERRUN_SHIFT)) + | BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\ + | BIT(IS_S_RX_THLD_SHIFT)) static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave); static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave); From patchwork Fri Oct 30 06:53:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rayagonda Kokatanur X-Patchwork-Id: 314929 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,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MIME_HEADER_CTYPE_ONLY, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, T_TVD_MIME_NO_HEADERS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham 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 4B4AFC00A89 for ; Fri, 30 Oct 2020 06:54:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CB0BC22206 for ; Fri, 30 Oct 2020 06:54:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="AuLKoxKU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725944AbgJ3Gy2 (ORCPT ); Fri, 30 Oct 2020 02:54:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48576 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725971AbgJ3Gy1 (ORCPT ); Fri, 30 Oct 2020 02:54:27 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AFDFEC0613D2 for ; Thu, 29 Oct 2020 23:54:27 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id i26so4399715pgl.5 for ; Thu, 29 Oct 2020 23:54:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tNaUOpA6K6C1YteBz5AC3cuJXG3DyMjiGraSENeeF5Q=; b=AuLKoxKUL3oUcmhYEe2kaM4JuyI2iqfWymUCuCubpljz857mLnNmIxWMgYnPmTcFOR SFaJ5DBocX3GujZXug+kviDWcg1Q9Scld2iTFYXM5hfj1nRGBwH8mKTJ23iFlp3CmhGY 97XrJdkdGEwNo+P1WBsCKkl4jvoUICld5D/pM= 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; bh=tNaUOpA6K6C1YteBz5AC3cuJXG3DyMjiGraSENeeF5Q=; b=mbe/BF6vuG3f5qxoNXkcwJWWO+mLxPQKgl6MO4GZkHbiTDbdOyjmy/DhlJN8hIaQQu ZtBe6yokMg5AIyLPE76ALeXVcBmnSEJXQZ8BpcJ+I2ZZW2QYFpk9Mg2jwkz8Tk+kMsAY tantTugwVg+n+smaQBgh1FOqUC25gn5m+AcljvH8OZp+ni3wW78UU+u+5fo/FjaVBNb4 RSeJBRigmQ93ZIpW7ZkZ0cnDa0Qq83JAe/8AW0qwZhk+FbLqP8dKhhzUj58Gil2bDSFt ATZf8ciVzNZVQdDkD9B9eYDg/4ubjFI5r9wu2OG1v5aTvmAVPZZuun/P7AjYebzoK8BV 9J3Q== X-Gm-Message-State: AOAM531fYrYeqDn/dmFrrxi+3H8PunDULvHmCGIytH/hdPwO13IP8SMR dof8IcAYAOPk9NCDVhlDWCDigg== X-Google-Smtp-Source: ABdhPJwrNfJRhvZnxGWm/DbUs97GQAMkF5JXyTG3+yfjlIvVv6cGs1tnb8ZU5EZZ1gEqY/Vbdb7VDA== X-Received: by 2002:a65:57ce:: with SMTP id q14mr939908pgr.55.1604040866806; Thu, 29 Oct 2020 23:54:26 -0700 (PDT) Received: from rayagonda.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id n1sm4561547pgl.31.2020.10.29.23.54.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2020 23:54:26 -0700 (PDT) From: Rayagonda Kokatanur To: Ray Jui , Scott Branden , bcm-kernel-feedback-list@broadcom.com, Wolfram Sang , Florian Fainelli , Brendan Higgins , Andy Shevchenko , Lori Hikichi , Dhananjay Phadke , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Rayagonda Kokatanur Subject: [PATCH v2 5/6] i2c: iproc: handle master read request Date: Fri, 30 Oct 2020 12:23:38 +0530 Message-Id: <20201030065339.955-6-rayagonda.kokatanur@broadcom.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> References: <20201030065339.955-1-rayagonda.kokatanur@broadcom.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Handle single or multi byte master read request with or without repeated start. Fixes: c245d94ed106 ("i2c: iproc: Add multi byte read-write support for slave mode") Signed-off-by: Rayagonda Kokatanur --- drivers/i2c/busses/i2c-bcm-iproc.c | 215 +++++++++++++++++++++++------ 1 file changed, 170 insertions(+), 45 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 7a235f9f5884..22e04055b447 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -160,6 +160,11 @@ #define IE_S_ALL_INTERRUPT_SHIFT 21 #define IE_S_ALL_INTERRUPT_MASK 0x3f +/* + * It takes ~18us to reading 10bytes of data, hence to keep tasklet + * running for less time, max slave read per tasklet is set to 10 bytes. + */ +#define MAX_SLAVE_RX_PER_INT 10 enum i2c_slave_read_status { I2C_SLAVE_RX_FIFO_EMPTY = 0, @@ -206,8 +211,18 @@ struct bcm_iproc_i2c_dev { /* bytes that have been read */ unsigned int rx_bytes; unsigned int thld_bytes; + + bool slave_rx_only; + bool rx_start_rcvd; + bool slave_read_complete; + u32 tx_underrun; + u32 slave_int_mask; + struct tasklet_struct slave_rx_tasklet; }; +/* tasklet to process slave rx data */ +static void slave_rx_tasklet_fn(unsigned long); + /* * Can be expanded in the future if more interrupt status bits are utilized */ @@ -261,6 +276,7 @@ static void bcm_iproc_i2c_slave_init( { u32 val; + iproc_i2c->tx_underrun = 0; if (need_reset) { /* put controller in reset */ val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET); @@ -297,8 +313,11 @@ static void bcm_iproc_i2c_slave_init( /* Enable interrupt register to indicate a valid byte in receive fifo */ val = BIT(IE_S_RX_EVENT_SHIFT); + /* Enable interrupt register to indicate a Master read transaction */ + val |= BIT(IE_S_RD_EVENT_SHIFT); /* Enable interrupt register for the Slave BUSY command */ val |= BIT(IE_S_START_BUSY_SHIFT); + iproc_i2c->slave_int_mask = val; iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); } @@ -324,76 +343,176 @@ static void bcm_iproc_i2c_check_slave_status( } } -static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, - u32 status) +static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c) { + u8 rx_data, rx_status; + u32 rx_bytes = 0; u32 val; - u8 value, rx_status; - /* Slave RX byte receive */ - if (status & BIT(IS_S_RX_EVENT_SHIFT)) { + while (rx_bytes < MAX_SLAVE_RX_PER_INT) { val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK; - if (rx_status == I2C_SLAVE_RX_START) { - /* Start of SMBUS for Master write */ - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_REQUESTED, &value); + rx_data = ((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); - val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); - value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); + if (rx_status == I2C_SLAVE_RX_START) { + /* Start of SMBUS Master write */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_RECEIVED, &value); - } else if (status & BIT(IS_S_RD_EVENT_SHIFT)) { - /* Start of SMBUS for Master Read */ + I2C_SLAVE_WRITE_REQUESTED, &rx_data); + iproc_i2c->rx_start_rcvd = true; + iproc_i2c->slave_read_complete = false; + } else if (rx_status == I2C_SLAVE_RX_DATA && + iproc_i2c->rx_start_rcvd) { + /* Middle of SMBUS Master write */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_REQUESTED, &value); - iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + I2C_SLAVE_WRITE_RECEIVED, &rx_data); + } else if (rx_status == I2C_SLAVE_RX_END && + iproc_i2c->rx_start_rcvd) { + /* End of SMBUS Master write */ + if (iproc_i2c->slave_rx_only) + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_WRITE_RECEIVED, + &rx_data); + + i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, + &rx_data); + } else if (rx_status == I2C_SLAVE_RX_FIFO_EMPTY) { + iproc_i2c->rx_start_rcvd = false; + iproc_i2c->slave_read_complete = true; + break; + } - val = BIT(S_CMD_START_BUSY_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + rx_bytes++; + } +} - /* - * Enable interrupt for TX FIFO becomes empty and - * less than PKT_LENGTH bytes were output on the SMBUS - */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val |= BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); - } else { - /* Master write other than start */ - value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); +static void slave_rx_tasklet_fn(unsigned long data) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = (struct bcm_iproc_i2c_dev *)data; + u32 int_clr; + + bcm_iproc_i2c_slave_read(iproc_i2c); + + /* clear pending IS_S_RX_EVENT_SHIFT interrupt */ + int_clr = BIT(IS_S_RX_EVENT_SHIFT); + + if (!iproc_i2c->slave_rx_only && iproc_i2c->slave_read_complete) { + /* + * In case of single byte master-read request, + * IS_S_TX_UNDERRUN_SHIFT event is generated before + * IS_S_START_BUSY_SHIFT event. Hence start slave data send + * from first IS_S_TX_UNDERRUN_SHIFT event. + * + * This means don't send any data from slave when + * IS_S_RD_EVENT_SHIFT event is generated else it will increment + * eeprom or other backend slave driver read pointer twice. + */ + iproc_i2c->tx_underrun = 0; + iproc_i2c->slave_int_mask |= BIT(IE_S_TX_UNDERRUN_SHIFT); + + /* clear IS_S_RD_EVENT_SHIFT interrupt */ + int_clr |= BIT(IS_S_RD_EVENT_SHIFT); + } + + /* clear slave interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, int_clr); + /* enable slave interrupts */ + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, iproc_i2c->slave_int_mask); +} + +static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, + u32 status) +{ + u32 val; + u8 value; + + /* + * Slave events in case of master-write, master-write-read and, + * master-read + * + * Master-write : only IS_S_RX_EVENT_SHIFT event + * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events + * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events or only IS_S_RD_EVENT_SHIFT + */ + if (status & BIT(IS_S_RX_EVENT_SHIFT) || + status & BIT(IS_S_RD_EVENT_SHIFT)) { + /* disable slave interrupts */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~iproc_i2c->slave_int_mask; + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + + if (status & BIT(IS_S_RD_EVENT_SHIFT)) + /* Master-write-read request */ + iproc_i2c->slave_rx_only = false; + else + /* Master-write request only */ + iproc_i2c->slave_rx_only = true; + + /* schedule tasklet to read data later */ + tasklet_schedule(&iproc_i2c->slave_rx_tasklet); + + /* clear only IS_S_RX_EVENT_SHIFT interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_RX_EVENT_SHIFT)); + } + + if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { + iproc_i2c->tx_underrun++; + if (iproc_i2c->tx_underrun == 1) + /* Start of SMBUS for Master Read */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_RECEIVED, &value); - if (rx_status == I2C_SLAVE_RX_END) - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_STOP, &value); - } - } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { - /* Master read other than start */ - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_PROCESSED, &value); + I2C_SLAVE_READ_REQUESTED, + &value); + else + /* Master read other than start */ + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_READ_PROCESSED, + &value); iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + /* start transfer */ val = BIT(S_CMD_START_BUSY_SHIFT); iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + + /* clear interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_TX_UNDERRUN_SHIFT)); } - /* Stop */ + /* Stop received from master in case of master read transaction */ if (status & BIT(IS_S_START_BUSY_SHIFT)) { - i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); /* * Disable interrupt for TX FIFO becomes empty and * less than PKT_LENGTH bytes were output on the SMBUS */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, + iproc_i2c->slave_int_mask); + + /* End of SMBUS for Master Read */ + val = BIT(S_TX_WR_STATUS_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val); + + val = BIT(S_CMD_START_BUSY_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + + /* flush TX FIFOs */ + val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET); + val |= (BIT(S_FIFO_TX_FLUSH_SHIFT)); + iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val); + + i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); + + /* clear interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_START_BUSY_SHIFT)); } - /* clear interrupt status */ - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status); + /* check slave transmit status only if slave is transmitting */ + if (!iproc_i2c->slave_rx_only) + bcm_iproc_i2c_check_slave_status(iproc_i2c); - bcm_iproc_i2c_check_slave_status(iproc_i2c); return true; } @@ -1074,6 +1193,10 @@ static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave) return -EAFNOSUPPORT; iproc_i2c->slave = slave; + + tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn, + (unsigned long)iproc_i2c); + bcm_iproc_i2c_slave_init(iproc_i2c, false); return 0; } @@ -1094,6 +1217,8 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave) IE_S_ALL_INTERRUPT_SHIFT); iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp); + tasklet_kill(&iproc_i2c->slave_rx_tasklet); + /* Erase the slave address programmed */ tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET); tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);