From patchwork Tue Feb 6 14:51:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 770479 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 034B3133282 for ; Tue, 6 Feb 2024 14:52:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231129; cv=none; b=GkCHMvKDQZvxx0BVlTjY0FQ5LYAr7B6YeopEwuqX/NvwR8e7TZeL/6TzCVee5gomVKWYrdqepJfDeli6baBFM6FxBjse1T0lZq8zIApYs1N0xhzZjVo416UCuVk1tlq88bximR10XuGh/YCgb5vjvt1Zra0z22oyU6bUVDGZhec= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231129; c=relaxed/simple; bh=sKBP/0cCh2+waP1FdOLfePMO3191pbtjj5ecHS18hjs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TXgEu9Q+Gnfa6ZaTmr6Af+P0ANEPl/Ymx/x0Cp8wWyD3AvFkRXjtv3d3uD5KallJ8+gZgbszuX4Z8yHRWTfMe6ARoKxpzUkkKf6cEPsqmX1LUUb2Oh7IgDaUBxXsDgCNlO+gpE5BIfN9jha2FEuUfw/xbpsCgJ/Mv18pWoaZmKQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=RUO2ZSdt; arc=none smtp.client-ip=192.198.163.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="RUO2ZSdt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1707231128; x=1738767128; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sKBP/0cCh2+waP1FdOLfePMO3191pbtjj5ecHS18hjs=; b=RUO2ZSdt8LmHHcDvD1qLcOcgqLfUfFcNb723mcPJ4Fkc/AbwZxBFdhnC EGgmic6aCqxESyhAwf2gb7ol2TBbdSA58zwATPl/j84Cb2RUHji1OE8tc 0tez1Cqo4y/cWark8aLr5dcmMghbQwW0sqvvR82GlGQCbltAldGCZmIpt hRPHl8Ojj7xEF60rokC6Oxxlsq3Sc73k/6hw7HXho/6UESbTo+mzJ1c5s jyc1/Kdz2STiLFQF0cs5kosvt8Z5rmD5YCOiVx7y0fP7sKIUQ0fAqxHwb LJbjskA8JmKrWGHsM6paO4BE5NGzyEmQ0tFviKlHP8rcby+8xZ091DE9Q g==; X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="26206579" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="26206579" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Feb 2024 06:52:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="933481903" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="933481903" Received: from marquiz-s-2.fi.intel.com (HELO mylly.fi.intel.com.) ([10.237.72.58]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2024 06:52:04 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , michael.j.ruhl@intel.com, Hans de Goede , Jarkko Nikula Subject: [PATCH v2 1/9] i2c: designware: Add some flexiblity to the model info Date: Tue, 6 Feb 2024 16:51:50 +0200 Message-ID: <20240206145158.227254-2-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> References: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Michael J. Ruhl" Currently the way to identify a model is via a bit field, of which 4 bits are currently defined. Use a shifted value to that more models can be defined. Reviewed-by: Andy Shevchenko Suggested-by: Andy Shevchenko Signed-off-by: Michael J. Ruhl Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index a7f6f3eafad7..4e1f0924f493 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -304,10 +304,10 @@ struct dw_i2c_dev { #define ACCESS_NO_IRQ_SUSPEND BIT(1) #define ARBITRATION_SEMAPHORE BIT(2) -#define MODEL_MSCC_OCELOT BIT(8) -#define MODEL_BAIKAL_BT1 BIT(9) -#define MODEL_AMD_NAVI_GPU BIT(10) -#define MODEL_WANGXUN_SP BIT(11) +#define MODEL_MSCC_OCELOT (1 << 8) +#define MODEL_BAIKAL_BT1 (2 << 8) +#define MODEL_AMD_NAVI_GPU (3 << 8) +#define MODEL_WANGXUN_SP (4 << 8) #define MODEL_MASK GENMASK(11, 8) /* From patchwork Tue Feb 6 14:51:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 770478 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 687F613248D for ; Tue, 6 Feb 2024 14:52:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231138; cv=none; b=XcjRxdFORtZz74LQt8+J1YzrYgUtEO7kjs7hIgo8AqpRvar5yzyN90e2D65MgFWeC7/XQbiQR/4wAxKEhFBHaHCapNxxIaD7KtyELdj7hi4iCj57ydeCtpR5Ai5pL8yhwYno+M5E2cctiRRiUgSs1JBtE2pHr4VKKVKadOwoLIQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231138; c=relaxed/simple; bh=G/LdQdyvkNe9+2Q1hCbMEiqDjUsESN22cr+x9wkcxbo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qssbtYUTnn9rjMux/14ZY/kjXN6BDZZoSirF1RaiCHKVQaVOlkALOX3kjAy82Ttha1il5nN3bRLgmimtoiGOu55a5P78Aof6Q28k6TG3zxx+M3fv1GHRhxEOEsTgGHi7fQ7+6cMh3/N0hx6Nen0yqOgUF2NqqaGeg72H53LI6Lg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=jky/c+8L; arc=none smtp.client-ip=192.198.163.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="jky/c+8L" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1707231137; x=1738767137; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=G/LdQdyvkNe9+2Q1hCbMEiqDjUsESN22cr+x9wkcxbo=; b=jky/c+8LiiJ66wQvCFWs1ifuiTH1H5gpt3YIgsPs0iY0SvJgDUMbRPdP QwRRoFOED5OiSILy15wvbhaPWMthiaMJxBH5X8EepkBoSOYUIyohdqRXQ 0U7JufB4mtnAtMTnQDWiQEcCLWm/yy2mx+gEPVEqdL5Ul/lBYeEd8DbmT EXh2gAtAjZ1rXxuvZi8v8pzLFXpUUtk0dTToT3EsXkomCzYtSQ8bwyHWV 0epRrJCPQe8UubBfbGHpcfFEOW9jEPxQXAt03ugHF41FNhhoOgnSC2cE2 WkOO7u/xaTn0bqy6D/KGV1kvg3Mj9dA3totNzuzRg8Yn4Nd9B+t64L/9G Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="26206624" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="26206624" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Feb 2024 06:52:17 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="933481937" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="933481937" Received: from marquiz-s-2.fi.intel.com (HELO mylly.fi.intel.com.) ([10.237.72.58]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2024 06:52:11 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , michael.j.ruhl@intel.com, Hans de Goede , Jarkko Nikula Subject: [PATCH v2 3/9] i2c: designware: Convert shared_with_punit boolean as semaphore type Date: Tue, 6 Feb 2024 16:51:52 +0200 Message-ID: <20240206145158.227254-4-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> References: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Remove the shared_with_punit member variable from the struct dw_i2c_dev and make it one semaphore type. Idea is to make code more uniform when there is need to differentiate between bus semaphores. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-baytrail.c | 2 +- drivers/i2c/busses/i2c-designware-core.h | 3 +-- drivers/i2c/busses/i2c-designware-platdrv.c | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index 45774aa47c28..159db4802cdf 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -38,7 +38,7 @@ int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev) dev_info(dev->dev, "I2C bus managed by PUNIT\n"); dev->acquire_lock = iosf_mbi_block_punit_i2c_access; dev->release_lock = iosf_mbi_unblock_punit_i2c_access; - dev->shared_with_punit = true; + dev->flags |= SEMAPHORE_INTEL_PUNIT; return 0; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index bac0aec3cb15..30b29d6e58ce 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -235,7 +235,6 @@ struct reset_control; * @release_lock: function to release a hardware lock on the bus * @semaphore_idx: Index of table with semaphore type attached to the bus. It's * -1 if there is no semaphore. - * @shared_with_punit: true if this bus is shared with the SoCs PUNIT * @disable: function to disable the controller * @init: function to initialize the I2C hardware * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing @@ -292,7 +291,6 @@ struct dw_i2c_dev { int (*acquire_lock)(void); void (*release_lock)(void); int semaphore_idx; - bool shared_with_punit; void (*disable)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int (*set_sda_hold_time)(struct dw_i2c_dev *dev); @@ -304,6 +302,7 @@ struct dw_i2c_dev { #define ACCESS_NO_IRQ_SUSPEND BIT(1) #define SEMAPHORE_AMD_PSP (1 << 4) +#define SEMAPHORE_INTEL_PUNIT (2 << 4) #define SEMAPHORE_MASK GENMASK(7, 4) #define MODEL_MSCC_OCELOT (1 << 8) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index efe9b8e0b7a2..c07385c20cee 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -181,7 +181,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) { pm_runtime_disable(dev->dev); - if (dev->shared_with_punit) + if ((dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT) pm_runtime_put_noidle(dev->dev); } @@ -381,7 +381,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); - if (dev->shared_with_punit) + if ((dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT) pm_runtime_get_noresume(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -433,7 +433,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - if (i_dev->shared_with_punit) + if ((i_dev->flags & SEMAPHORE_MASK) == SEMAPHORE_INTEL_PUNIT) return 0; i_dev->disable(i_dev); @@ -455,7 +455,7 @@ static int dw_i2c_plat_runtime_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - if (!i_dev->shared_with_punit) + if ((i_dev->flags & SEMAPHORE_MASK) != SEMAPHORE_INTEL_PUNIT) i2c_dw_prepare_clk(i_dev, true); i_dev->init(i_dev); From patchwork Tue Feb 6 14:51:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 770477 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E283132C26 for ; Tue, 6 Feb 2024 14:52:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231145; cv=none; b=SXMZD2uWK15HVkHiE/QBWmV8U9mgFyldTpZknDUCQ257gGqWj1Zl42vP6VQZ9H0AlJ7o8liG6m6cqoJ1rZSbTQS3FHyrFm/7eI9e7OhZoGhOn3zEhGn4IddWvNMilboiz5OU78G2iK2UlZn5qAVNRQX/2Y2Xb0MSSAKkE/lLx0k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231145; c=relaxed/simple; bh=R+4q0KD9BvmZdxD81eEs6HX9hWzEr3vbU7jF+NEAE3Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gz37yi9FJJIsS/LlYwWR/5/oO2lBfrYJH0HG8tYxDFCezDfR2ZMcTt6sjWP6mcyVJ5PIzKT62vF6FMrrOP/TuSz/alTJFhhd0ZyVCbZaVMSdENuJwZwEI/f1fAkoflx+bNpy5UAS1DYd0Om31YmGf3IJallJXnhZ0S5Tmudt13E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=AWvJUHgA; arc=none smtp.client-ip=192.198.163.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="AWvJUHgA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1707231144; x=1738767144; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=R+4q0KD9BvmZdxD81eEs6HX9hWzEr3vbU7jF+NEAE3Y=; b=AWvJUHgA05W7BNRIigTXUaoWBXMMVKJacGz63W+3J3gFrNh/OgCckDYy 7lKU+b2CrRtMtL6aF9Vu/Wxd0N5QRwS/EqaCZy0J48nISPWSc0J0UMAlu ceroZRgoB2KEjPsQfH0+cosCvK5CApR7GBWFyrab9U+P2f020+YZLCDry BYG5Y014q+QHPRiEM9+qjB/tptsCQYtmQtl0pCucOmmJdlkMcg4TgLHQq lbvaODjemJkmpUCqwVZpw0yngDQhq5v1ipz5wnaygh9MaznJNqgFnldQK 81wWi9OGtzxE0/YIqDyszZwRdqUd2gbc1c+fQoJUIJLLrt1Vsxgc8PNG1 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="26206667" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="26206667" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Feb 2024 06:52:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="933481983" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="933481983" Received: from marquiz-s-2.fi.intel.com (HELO mylly.fi.intel.com.) ([10.237.72.58]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2024 06:52:17 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , michael.j.ruhl@intel.com, Hans de Goede , Jarkko Nikula Subject: [PATCH v2 5/9] i2c: designware: Do not enable interrupts shortly in polling mode Date: Tue, 6 Feb 2024 16:51:54 +0200 Message-ID: <20240206145158.227254-6-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> References: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 I was testing the polling mode txgbe_i2c_dw_xfer_quirk() on a HW where the i2c-designware has interrupt connected and shared with other device. I noticed there is a bogus interrupt for each transfer. Reason for this that both polling mode functions call the i2c_dw_xfer_init() which enable interrupts then followed by immediate disable by the same polling mode functions. This is enough to trigger TX_EMPTY interrupt. Fix this by introducing a __i2c_dw_write_intr_mask() helper that unmasks interrupts conditionally and use it in i2c_dw_xfer_init(). Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 8 ++++++++ drivers/i2c/busses/i2c-designware-master.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index ee93c0b4e817..353d753d9d5d 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -353,6 +353,14 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) dev->status &= ~STATUS_ACTIVE; } +static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, + unsigned int intr_mask) +{ + unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask; + + regmap_write(dev->map, DW_IC_INTR_MASK, val); +} + void __i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index e879a0f5cc97..835d82e2c5fe 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -250,7 +250,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* Clear and enable interrupts */ regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); - regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK); + __i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK); } static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev) @@ -300,7 +300,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, dev->msgs = msgs; dev->msgs_num = num_msgs; i2c_dw_xfer_init(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); /* Initiate messages read/write transaction */ for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) { @@ -384,7 +383,6 @@ static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msg dev->msgs = msgs; dev->msgs_num = num_msgs; i2c_dw_xfer_init(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) { buf = msgs[msg_idx].buf; From patchwork Tue Feb 6 14:51:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 770476 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3F454132C28 for ; Tue, 6 Feb 2024 14:52:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231148; cv=none; b=bubHIJ8X4754XaYLWq9nX8jXbhDvRI7izXJIzAM1HwgOZ8rOPIgUmg5d2AfnjVzZKb03RVWDRkpbV6v+gULTPO/U7zds0gof2P3rmLBcWOkSbfZ0FaGnVsZ7EapyFB4r5c0vCInm2UEtde3TvHLKR58si2kw6vSlHEnl0uCoE7I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231148; c=relaxed/simple; bh=UoiwHy7xqEgMy8eOAK4q8jh0JHOFwvCIB7tA/aMNWu8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BCSTNX67F39d/k7LPQPhDW6xapCuVkpQsCE/Zq24dL8eEBSE5cvHm34baaF6EYMxeUhBY6fectiBCkV8Mni5m1ZfVxBcgUrLw0bewxYJ9g+g/cGKIKBFATVGUXGv7WUqfJc1aB9sj2q7zuF2cBa8/BGXcuXCKxC+YIkznTi/iCU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=LJaCbN+Y; arc=none smtp.client-ip=192.198.163.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="LJaCbN+Y" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1707231147; x=1738767147; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UoiwHy7xqEgMy8eOAK4q8jh0JHOFwvCIB7tA/aMNWu8=; b=LJaCbN+YDM2r6VnOj+Bc2GJliBv5mEy4hpY0MMIn5bUES6wBmVqWNxcV SWpCCERX9E2Z0enmUDtdKC+3rLJT64W9a3wI30ZxiG4j1ojXIb5O9aE3/ W3VcK8g5EosWbDXFmN016M/BHqBF1umYJNkU/o0YVLh3ou5LhvLCPWDpk 28Z9+d69/HEDa/qsbcSWgjMYBC3F1oMgX31QCQM8bzBWd04cR49yQige+ ji7IcKwiP1BbatJj7nTy7zStk75RG0egEqsD6EJP4nGHHE+UO4RAYHRpi tgtV0+YeOOF3suiv/3pf3R4HpQztzGeiAResm8DHAlTGa3yu2NBbFPnyF w==; X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="26206714" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="26206714" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Feb 2024 06:52:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="933482012" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="933482012" Received: from marquiz-s-2.fi.intel.com (HELO mylly.fi.intel.com.) ([10.237.72.58]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2024 06:52:24 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , michael.j.ruhl@intel.com, Hans de Goede , Jarkko Nikula Subject: [PATCH v2 7/9] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Date: Tue, 6 Feb 2024 16:51:56 +0200 Message-ID: <20240206145158.227254-8-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> References: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Code is more logically arranged when i2c_dw_read_clear_intrbits() and i2c_dw_isr() are located before i2c_dw_xfer(). Real reason for this is to prepare for more shared code between interrupt and polling mode code. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-master.c | 226 ++++++++++----------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 2e8f9733ddd3..856c955c6560 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -633,119 +633,6 @@ i2c_dw_read(struct dw_i2c_dev *dev) } } -/* - * Prepare controller for a transaction and call i2c_dw_xfer_msg. - */ -static int -i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -{ - struct dw_i2c_dev *dev = i2c_get_adapdata(adap); - int ret; - - dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); - - pm_runtime_get_sync(dev->dev); - - /* - * Initiate I2C message transfer when polling mode is enabled, - * As it is polling based transfer mechanism, which does not support - * interrupt based functionalities of existing DesignWare driver. - */ - switch (dev->flags & MODEL_MASK) { - case MODEL_AMD_NAVI_GPU: - ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; - case MODEL_WANGXUN_SP: - ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; - default: - break; - } - - reinit_completion(&dev->cmd_complete); - dev->msgs = msgs; - dev->msgs_num = num; - dev->cmd_err = 0; - dev->msg_write_idx = 0; - dev->msg_read_idx = 0; - dev->msg_err = 0; - dev->status = 0; - dev->abort_source = 0; - dev->rx_outstanding = 0; - - ret = i2c_dw_acquire_lock(dev); - if (ret) - goto done_nolock; - - ret = i2c_dw_wait_bus_not_busy(dev); - if (ret < 0) - goto done; - - /* Start the transfers */ - i2c_dw_xfer_init(dev); - - /* Wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { - dev_err(dev->dev, "controller timed out\n"); - /* i2c_dw_init implicitly disables the adapter */ - i2c_recover_bus(&dev->adapter); - i2c_dw_init_master(dev); - ret = -ETIMEDOUT; - goto done; - } - - /* - * We must disable the adapter before returning and signaling the end - * of the current transfer. Otherwise the hardware might continue - * generating interrupts which in turn causes a race condition with - * the following transfer. Needs some more investigation if the - * additional interrupts are a hardware bug or this driver doesn't - * handle them correctly yet. - */ - __i2c_dw_disable_nowait(dev); - - if (dev->msg_err) { - ret = dev->msg_err; - goto done; - } - - /* No error */ - if (likely(!dev->cmd_err && !dev->status)) { - ret = num; - goto done; - } - - /* We have an error */ - if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { - ret = i2c_dw_handle_tx_abort(dev); - goto done; - } - - if (dev->status) - dev_err(dev->dev, - "transfer terminated early - interrupt latency too high?\n"); - - ret = -EIO; - -done: - i2c_dw_release_lock(dev); - -done_nolock: - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); - - return ret; -} - -static const struct i2c_algorithm i2c_dw_algo = { - .master_xfer = i2c_dw_xfer, - .functionality = i2c_dw_func, -}; - -static const struct i2c_adapter_quirks i2c_dw_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { unsigned int stat, dummy; @@ -872,6 +759,119 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +/* + * Prepare controller for a transaction and call i2c_dw_xfer_msg. + */ +static int +i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + + pm_runtime_get_sync(dev->dev); + + /* + * Initiate I2C message transfer when polling mode is enabled, + * As it is polling based transfer mechanism, which does not support + * interrupt based functionalities of existing DesignWare driver. + */ + switch (dev->flags & MODEL_MASK) { + case MODEL_AMD_NAVI_GPU: + ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); + goto done_nolock; + case MODEL_WANGXUN_SP: + ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); + goto done_nolock; + default: + break; + } + + reinit_completion(&dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = 0; + dev->abort_source = 0; + dev->rx_outstanding = 0; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + goto done_nolock; + + ret = i2c_dw_wait_bus_not_busy(dev); + if (ret < 0) + goto done; + + /* Start the transfers */ + i2c_dw_xfer_init(dev); + + /* Wait for tx to complete */ + if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { + dev_err(dev->dev, "controller timed out\n"); + /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); + i2c_dw_init_master(dev); + ret = -ETIMEDOUT; + goto done; + } + + /* + * We must disable the adapter before returning and signaling the end + * of the current transfer. Otherwise the hardware might continue + * generating interrupts which in turn causes a race condition with + * the following transfer. Needs some more investigation if the + * additional interrupts are a hardware bug or this driver doesn't + * handle them correctly yet. + */ + __i2c_dw_disable_nowait(dev); + + if (dev->msg_err) { + ret = dev->msg_err; + goto done; + } + + /* No error */ + if (likely(!dev->cmd_err && !dev->status)) { + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { + ret = i2c_dw_handle_tx_abort(dev); + goto done; + } + + if (dev->status) + dev_err(dev->dev, + "transfer terminated early - interrupt latency too high?\n"); + + ret = -EIO; + +done: + i2c_dw_release_lock(dev); + +done_nolock: + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + return ret; +} + +static const struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; + +static const struct i2c_adapter_quirks i2c_dw_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + void i2c_dw_configure_master(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; From patchwork Tue Feb 6 14:51:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 770475 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F2BC131E53 for ; Tue, 6 Feb 2024 14:52:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231155; cv=none; b=ViP5UV5HR+13QHUVL8EHvpnSwdkzFFcQh+VOhVYcHbQT7EILVp/1wHs644LQL0SKKDiOyLXFhxSLE3CS0lvOPfF9YZfpjdZIH4BRNuPA7D9VLI2W6VCC+2xmJ+9hzKzxAIUpsSxzAhaZvKANOCZ3zdboUUVFrMusOmY7p/qj1e8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707231155; c=relaxed/simple; bh=B6mG1u9IFmK5V0XW/+xsw1/HsXCcEbp1ivsRgNJyH40=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=kuQ/fDK/LpkeZuV+3YeHzDaqUAlPS1mm9orFYYJVuuYRp6Ncw4Of8Q2vkamBn/JKQpuKKKFibANRm4iwjQRCQ9FEDSOxomucv+EqsR/gJaP2nwOMRKNkMyD/MYJWeFjSz+2xJ7FQiMSbV4QYhnj1dnsp+w0nr4PNnva3NafTAck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=asgOXhnD; arc=none smtp.client-ip=192.198.163.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="asgOXhnD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1707231153; x=1738767153; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=B6mG1u9IFmK5V0XW/+xsw1/HsXCcEbp1ivsRgNJyH40=; b=asgOXhnDPwDbwkBjSQJM8lE1hRE1DkE8DlDqN73fdzGbtjhJty5SHM+H kIevLb/ojk5CehiyancXvi68ciBCbAo67zdCKxFmy7z6kIfAmW0tjnhuO BeYorFDQ1u/r8QguNJ08Mc7/+9P0AbJQrUfp/4qriVdOA170vQUcHv/NO nLoP9UqY/dY8pTCchduggpwnp08extVWA+A7kJvQj+GcvIsYv3V5Vddfz uvhnkNJ2Xc+JZihcBfqJUh3q4iTSg8Yn40kJH+2KWabYk4UonuhLaNVqK ivlJKRYXH+TRLejkswFAS2TqSbrQcNx4f0FrTDARMe0s3IR5ZRUfHj+7G w==; X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="26206756" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="26206756" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Feb 2024 06:52:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10975"; a="933482058" X-IronPort-AV: E=Sophos;i="6.05,247,1701158400"; d="scan'208";a="933482058" Received: from marquiz-s-2.fi.intel.com (HELO mylly.fi.intel.com.) ([10.237.72.58]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2024 06:52:30 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , michael.j.ruhl@intel.com, Hans de Goede , Jarkko Nikula Subject: [PATCH v2 9/9] i2c: designware: Implement generic polling mode code for Wangxun 10Gb NIC Date: Tue, 6 Feb 2024 16:51:58 +0200 Message-ID: <20240206145158.227254-10-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> References: <20240206145158.227254-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 I got an idea the i2c-designware should not need duplicated state machines for the interrupt and polling modes. The IP is practically the same and state transitions happens in response to the events that can be observed from the DW_IC_RAW_INTR_STAT register. Either by interrupts or by polling. Another reasons are the interrupt mode is the most tested, has handling for special cases as well as transmit abort handling and those are missing from two polling mode quirks. Patch implements a generic polling mode by using existing code for interrupt mode. This is done by moving event handling from the i2c_dw_isr() into a new i2c_dw_process_transfer() that will be called both from the i2c_dw_isr() and a polling loop. Polling loop is implemented in a new i2c_dw_wait_transfer() that is shared between both modes. In interrupt mode it waits for the completion object as before. In polling mode both completion object and DW_IC_RAW_INTR_STAT are polled to determine completed transfer and state transitions. Loop tries to save power by sleeping "stetson guessed" range between 3 and 25 µS which falls between 10 cycles of High-speed mode 3.4 Mb/s and Fast mode 400 kHz. With it the CPU usage was reduced under heavy Fast mode I2C transfer without much increase in total transfer time but otherwise no more effort has been put to optimize this. I decided to convert the txgbe_i2c_dw_xfer_quirk() straight to generic polling mode code in this patch. It doesn't have HW dependent quirks like the amd_i2c_dw_xfer_quirk() does have and without users this patch is needless. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 5 + drivers/i2c/busses/i2c-designware-master.c | 169 +++++++++------------ 2 files changed, 77 insertions(+), 97 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 94da70ce1f32..b62206db4f09 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -212,6 +212,7 @@ struct reset_control; * @msg_err: error status of the current transfer * @status: i2c master status, one of STATUS_* * @abort_source: copy of the TX_ABRT_SOURCE register + * @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode * @irq: interrupt number for the i2c master * @flags: platform specific flags like type of IO accessors or model * @adapter: i2c subsystem adapter node @@ -269,6 +270,7 @@ struct dw_i2c_dev { int msg_err; unsigned int status; unsigned int abort_source; + unsigned int sw_mask; int irq; u32 flags; struct i2c_adapter adapter; @@ -359,6 +361,7 @@ static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask; regmap_write(dev->map, DW_IC_INTR_MASK, val); + dev->sw_mask = intr_mask; } static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, @@ -366,6 +369,8 @@ static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, { if (!(dev->flags & ACCESS_POLLING)) regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask); + else + *intr_mask = dev->sw_mask; } void __i2c_dw_disable(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 856c955c6560..5897fad544c0 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -354,67 +354,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, return 0; } -static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev) -{ - u32 val; - - return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val, - val & DW_IC_INTR_TX_EMPTY, - 100, 1000); -} - -static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev) -{ - u32 val; - - return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val, - val & DW_IC_INTR_RX_FULL, - 100, 1000); -} - -static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num_msgs) -{ - struct dw_i2c_dev *dev = i2c_get_adapdata(adap); - int msg_idx, buf_len, data_idx, ret; - unsigned int val, stop = 0; - u8 *buf; - - dev->msgs = msgs; - dev->msgs_num = num_msgs; - i2c_dw_xfer_init(dev); - - for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) { - buf = msgs[msg_idx].buf; - buf_len = msgs[msg_idx].len; - - for (data_idx = 0; data_idx < buf_len; data_idx++) { - if (msg_idx == num_msgs - 1 && data_idx == buf_len - 1) - stop |= BIT(9); - - if (msgs[msg_idx].flags & I2C_M_RD) { - regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | stop); - - ret = i2c_dw_poll_rx_full(dev); - if (ret) - return ret; - - regmap_read(dev->map, DW_IC_DATA_CMD, &val); - buf[data_idx] = val; - } else { - ret = i2c_dw_poll_tx_empty(dev); - if (ret) - return ret; - - regmap_write(dev->map, DW_IC_DATA_CMD, - buf[data_idx] | stop); - } - } - } - - return num_msgs; -} - /* * Initiate (and continue) low level master read/write transaction. * This function is only called from i2c_dw_isr, and pumping i2c_msg @@ -649,7 +588,12 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) * * The raw version might be useful for debugging purposes. */ - regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + if (!(dev->flags & ACCESS_POLLING)) { + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + } else { + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + stat &= dev->sw_mask; + } /* * Do not use the IC_CLR_INTR register to clear interrupts, or @@ -689,37 +633,8 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) return stat; } -/* - * Interrupt service routine. This gets called whenever an I2C master interrupt - * occurs. - */ -static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat) { - struct dw_i2c_dev *dev = dev_id; - unsigned int stat, enabled; - - regmap_read(dev->map, DW_IC_ENABLE, &enabled); - regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); - if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) - return IRQ_NONE; - if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0)) - return IRQ_NONE; - dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); - - stat = i2c_dw_read_clear_intrbits(dev); - - if (!(dev->status & STATUS_ACTIVE)) { - /* - * Unexpected interrupt in driver point of view. State - * variables are either unset or stale so acknowledge and - * disable interrupts for suppressing further interrupts if - * interrupt really came from this HW (E.g. firmware has left - * the HW active). - */ - __i2c_dw_write_intr_mask(dev, 0); - return IRQ_HANDLED; - } - if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status &= ~STATUS_MASK; @@ -755,10 +670,73 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) __i2c_dw_write_intr_mask(dev, 0); __i2c_dw_write_intr_mask(dev, stat); } +} + +/* + * Interrupt service routine. This gets called whenever an I2C master interrupt + * occurs. + */ +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +{ + struct dw_i2c_dev *dev = dev_id; + unsigned int stat, enabled; + + regmap_read(dev->map, DW_IC_ENABLE, &enabled); + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) + return IRQ_NONE; + if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0)) + return IRQ_NONE; + dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); + + stat = i2c_dw_read_clear_intrbits(dev); + + if (!(dev->status & STATUS_ACTIVE)) { + /* + * Unexpected interrupt in driver point of view. State + * variables are either unset or stale so acknowledge and + * disable interrupts for suppressing further interrupts if + * interrupt really came from this HW (E.g. firmware has left + * the HW active). + */ + __i2c_dw_write_intr_mask(dev, 0); + return IRQ_HANDLED; + } + + i2c_dw_process_transfer(dev, stat); return IRQ_HANDLED; } +static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev) +{ + unsigned long timeout = dev->adapter.timeout; + unsigned int stat; + int ret = 0; + + if (!(dev->flags & ACCESS_POLLING)) { + ret = wait_for_completion_timeout(&dev->cmd_complete, + timeout) ? 0 : -ETIMEDOUT; + } else { + timeout += jiffies; + do { + if (try_wait_for_completion(&dev->cmd_complete)) + goto out; + + stat = i2c_dw_read_clear_intrbits(dev); + if (stat) + i2c_dw_process_transfer(dev, stat); + else + /* Try save some power */ + usleep_range(3, 25); + } while (time_before(jiffies, timeout)); + ret = ETIMEDOUT; + } + +out: + return ret; +} + /* * Prepare controller for a transaction and call i2c_dw_xfer_msg. */ @@ -781,9 +759,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) case MODEL_AMD_NAVI_GPU: ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); goto done_nolock; - case MODEL_WANGXUN_SP: - ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; default: break; } @@ -811,12 +786,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* Wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { + ret = i2c_dw_wait_transfer(dev); + if (ret) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); - ret = -ETIMEDOUT; goto done; }