From patchwork Tue Mar 19 22:51:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 1913857 X-Patchwork-Delegate: andi.shyti@kernel.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=eYly9WZP; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=147.75.80.249; helo=am.mirrors.kernel.org; envelope-from=linux-i2c+bounces-2429-incoming=patchwork.ozlabs.org@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from am.mirrors.kernel.org (am.mirrors.kernel.org [147.75.80.249]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Tzy3z6HVvz1yXD for ; Wed, 20 Mar 2024 16:35:43 +1100 (AEDT) Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 234211F22CD6 for ; Wed, 20 Mar 2024 05:35:41 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 461B317996; Wed, 20 Mar 2024 05:35:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eYly9WZP" X-Original-To: linux-i2c@vger.kernel.org Received: from mail-io1-f53.google.com (mail-io1-f53.google.com [209.85.166.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80D781428E; Wed, 20 Mar 2024 05:35:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912925; cv=none; b=S79FeBfjLRkvwuUK+0Cep55D7mQVA5jZtX49hIy0XzB9fVgC+Xv6Xh6EfCZYNQfwVIDgU1jHHJ04m3Jk+piPIWHBooXF0FghC2QZH+ogqsmIbcEs3ltG+HjReN01JmDkXJcdNIJ03348JiEQ2R9KAmvHs3U/EZT+8TSmkrDqwSE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912925; c=relaxed/simple; bh=ldkBIpP1iQ2aO/IzaLnzxa3HL6kC7m3EDYC2KyM3Mps=; h=Message-ID:From:To:Cc:Date:Subject; b=OcqHHE0svn57CoXtvWTmGsZNJQVUNm0v8dP+d8PlK3x/ulfyKUDP9i0FN9M4U7yfYHDFQDYkdjrSECKq+DCHnrFYFxzJWsqR51RhYtgR9VaSyHdhRnpLRwWMVwW+lduHhKA3ORyMj9ZatQ4f08OS4AUhAU36LFJgrRXhThJIwDg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eYly9WZP; arc=none smtp.client-ip=209.85.166.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-io1-f53.google.com with SMTP id ca18e2360f4ac-7cc01644f51so178715039f.2; Tue, 19 Mar 2024 22:35:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710912924; x=1711517724; darn=vger.kernel.org; h=subject:date:cc:to:from:message-id:from:to:cc:subject:date :message-id:reply-to; bh=cdzaMW1y8chZwthZH4ERyUEDxEvHFRT3urSQfaKxNec=; b=eYly9WZP+FeSBhqspLuJ/REtpPmOc4LWlVOq7Iko7pqHvgCbLC3IQQ5JNCilVh3PCz AeerY5qlgqs79KxV7m+UhTqphy+IncdDiaLd+/PuK0djLjWKpoUKEFizznLe2oJFSWW6 j2CbF3nR7EkP9jZ9Gctf+chwZgTRxZrhvSnCt9B1al4icuCGlP7EUWY9NRYo6Br4G5+4 UbXEcor30vphyLlMpaCjK8JDAFcxMigDPz5yj8I6GfqzMV7ACjqNGXSI0wRcDTBT0Owb uhjeycpld6R6uNdGrdvvkFgrT2499kBHdLUf7o2TbBDXxlZXBuSRrxlSwCNQBXdAwSUS M5yA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710912924; x=1711517724; h=subject:date:cc:to:from:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cdzaMW1y8chZwthZH4ERyUEDxEvHFRT3urSQfaKxNec=; b=eAcFTyFMN3iScvoh5T4ncDt6e/xv0nIrDd4emeomUDb7aFwqiAUoaUnhnp2G9VtSvC exi96HMl5bhD+RCkVYVY4w9bEGHIzRHneNgqoXTaA+/sPw6omZHTG+wjNF09YHZDyadA Z4eZqD3z4N9nLd+d4JTbZAFM2G+IuKpTz//kRlq8JUe8rIWpo/Nqb5VNF9yc0xt2GiVz 0AhEgiE8NK7PwMwuzNTvd5/v58X8YfK04BFyUoR5tcneCr/dyiuUcfzy9bJaZN0gRX+z XEW2oU2ZWWQgIcH94nudggJfyzWy0UJRk9fV+mTErhPqghbsdh4eD3OF8ynBDdVQBXY4 5pAQ== X-Forwarded-Encrypted: i=1; AJvYcCUgYpo+iPYHL1Hst50sXAmLRpXT1k/0tUTig4gKdUnCq4GvQ+R5ld6CSDdceMWDG+uNfaWjcPmuWmbVjuEuZTNSzaFV0fo3pfI8Poa/ X-Gm-Message-State: AOJu0YzrBmUPf6rOaG19fTwCe4WlJeJtVK/UvlPYdC0ojjM4lVVcUr7/ IMJJsuwwAXlez468MiIP7qij87f8v1mv1iwZNmA1GKqZfHk3aZoS X-Google-Smtp-Source: AGHT+IG9TmyAa6Gnq24FoX6mBn6doGEL9SzpbRHMACexCR5sHZfMAO83l9bHXVdDLtPIjeBOMZYnQQ== X-Received: by 2002:a5d:984e:0:b0:7cf:15be:6834 with SMTP id p14-20020a5d984e000000b007cf15be6834mr1105012ios.4.1710912923728; Tue, 19 Mar 2024 22:35:23 -0700 (PDT) Received: from ?IPV6:2001:470:42c4:101:9af9:b18f:3f69:51be? ([2001:470:42c4:101:9af9:b18f:3f69:51be]) by smtp.gmail.com with ESMTPSA id q6-20020a5d9f06000000b007cc6af6686esm1679597iot.30.2024.03.19.22.35.23 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 22:35:23 -0700 (PDT) Message-ID: <65fa759b.5d0a0220.fe5f7.1fa0@mx.google.com> From: Sam Edwards X-Google-Original-From: Sam Edwards To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 19 Mar 2024 16:51:51 -0600 Subject: [RESEND v2 RFC 1/5] i2c: mv64xxx: Clear bus errors before transfer Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: The MV64XXX hardware can act as either a bus controller or target device. In order to protect target devices from a glitching bus (apparently), the core listens on the lines even when idle and moves the hardware FSM to the "BUS_ERR" state if an invalid transition is detected. The hardware then does not exit this state until reset. This feature is actually counterproductive when using the hardware as a controller (as this driver does): we do not actually *care* what happened on the bus previously, as long as it's ready for use when the new transfer starts. However, the controller will remember a previous glitch and trip up the driver after it attempts to send the start command. The driver logs and error and resets the controller, recovering from the BUS_ERR state, but not without erroring back the transfer with errno EAGAIN. Clients generally do not handle this gracefully. This is easily fixed by checking for the BUS_ERR condition upfront and issuing the hardware reset before beginning the transfer. This patch does NOT also call i2c_recover_bus(): the assumption is that the bus is fine, just the hardware is upset; if the bus is also in a bad state, this should not pass silently. Signed-off-by: Sam Edwards --- drivers/i2c/busses/i2c-mv64xxx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index fd8403b07fa6..cfc16909fba3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -753,6 +753,7 @@ mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); int rc, ret = num; + u32 status; rc = pm_runtime_resume_and_get(&adap->dev); if (rc) @@ -762,6 +763,11 @@ mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) drv_data->msgs = msgs; drv_data->num_msgs = num; + /* Calm down the hardware if it was upset by a bus glitch while idle */ + status = readl(drv_data->reg_base + drv_data->reg_offsets.status); + if (status == MV64XXX_I2C_STATUS_BUS_ERR) + mv64xxx_i2c_hw_init(drv_data); + if (mv64xxx_i2c_can_offload(drv_data) && !drv_data->atomic) rc = mv64xxx_i2c_offload_xfer(drv_data); else From patchwork Tue Mar 19 22:52:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 1913858 X-Patchwork-Delegate: andi.shyti@kernel.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=TmIx+hU+; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=147.75.199.223; helo=ny.mirrors.kernel.org; envelope-from=linux-i2c+bounces-2430-incoming=patchwork.ozlabs.org@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org [147.75.199.223]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Tzy4H3hLxz1yXD for ; Wed, 20 Mar 2024 16:35:59 +1100 (AEDT) Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 380C51C21651 for ; Wed, 20 Mar 2024 05:35:57 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 56C0A1CA98; Wed, 20 Mar 2024 05:35:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="TmIx+hU+" X-Original-To: linux-i2c@vger.kernel.org Received: from mail-io1-f54.google.com (mail-io1-f54.google.com [209.85.166.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8650017BA1; Wed, 20 Mar 2024 05:35:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912927; cv=none; b=GNBtbZJYpeSFost0+NBeiU9yMz4vJb3hPqQvDCctEnaSqlVgmqs4UYkPpmXkGn24sOVLernrW9NSlaSNp46YCg++DwvRSyQ2kt8chHjVqlewC7b9aBjX3Zxas/G2uqO2UMW6gXEqmvW4/NFwjR4RC7HcYoLo0gCEfB/XQn8FYPs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912927; c=relaxed/simple; bh=Am4zE7z4HcN+wmSJsY3Azrgn2swXF4zvomMjAUCjKYE=; h=Message-ID:From:To:Cc:Date:Subject; b=iUjIX/vBqkLC0Vta35bwLTCs0gJA11yOs+qWyEZ2kqgpdntSfK96OoPczdxBsuxmEmsbhHNbbvZdt9QdyEwZQwjNLxWJDXYwawDw4XdFlMsnZgyKlKasPnxPZzspJxUUyo3dKGPpE4+OySQJRzrKU1G3MtNmJtwPfdXTlt77aDo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=TmIx+hU+; arc=none smtp.client-ip=209.85.166.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-io1-f54.google.com with SMTP id ca18e2360f4ac-7c8b777ff8bso160673039f.0; Tue, 19 Mar 2024 22:35:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710912926; x=1711517726; darn=vger.kernel.org; h=subject:date:cc:to:from:message-id:from:to:cc:subject:date :message-id:reply-to; bh=3fWtKmJ3MfVCnV+E74sqM2ekSX6lKZRkdLbepWZrZ6o=; b=TmIx+hU+wbltV/mR0gjmgfwSBBIOeNz/LwEH4WEoLM4+zvhTEh+j3kJAt1QovfqfK+ BHSIR75zKIeZq+a1bQzSSv9BnlR2M/hahisY1z6i/O/nzX62BGHHUKSCFY+ER1w/yMY9 i+ndWq8N6cs/V3AW2rDbgzUIIKfpz5VB8v5pmHMgoa+KvXzoTRHStBWPUKXm2/YVIvW/ 5aN5DQkIV4msTEuX1xRbCYkEx+hgTKCZbUYysjHeZVzo5mFb5Tvl6pgoDZX7h9iJ3RtW DnEo0e8GjGSH9PCvY40KfXRBMn1eMLUaAwbxCgDzQpa4xIRGlGcfVmwEY3Fdztl9ylxg 9r7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710912926; x=1711517726; h=subject:date:cc:to:from:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3fWtKmJ3MfVCnV+E74sqM2ekSX6lKZRkdLbepWZrZ6o=; b=F6LUu99bkCLycrxSeoX8B9lsr7C+vSOQjJ+SpiYzqsVv7l4nF9NK95Lp3m5+Ze/1HR stJXUYvbvvjfNAMs5OuJ5LjwOj5b8OFXMujUsKRYb56kKoAEo/nClGjyXxzycE9CuCxM Xxlb5mimbagQMa4GLfkKbkJuR4WE8CkFDbp90CQvxUnRZEu5BELFX7M0XXJTY1oPdlsE mpKozO0cyu0+5oO2l5qHyXEprsjAmv0QP4DfYoTqnnfMPQGsu0pI6dtjkGDJ1UN2Xb30 GZThPAM2DtM1ziaI8aOhwNYNZtkvpvZDo8iW3hnYmyr/o2xmSpuLjWFcgpp/P5HTMgKY bAcA== X-Forwarded-Encrypted: i=1; AJvYcCWzdMuK8TNQMg7jkZmq2HnHlCw+Tgj4NcjupOQKNqG08OxFA6cHfjUiBZsjYtAu0vKbGrGaENjBsM/2lPGAJSE4xERPmkuxdlyIGvku X-Gm-Message-State: AOJu0Ywe6FyoERJG8eIlZqSbALwRDx/rnVGuPct/NNyqM6vTNM8vrP75 nSRwFsjc0QAOR/UyMvd+EqrilV+gAThY/8hFguVuPhfzcouZzGAG X-Google-Smtp-Source: AGHT+IFKES2Uky1bgEuvMP9uVTfS556lGod7x+XvTY99r/zbRtvCkX+z+Y6EHGgnbRL1lsatJyU+OQ== X-Received: by 2002:a6b:6a16:0:b0:7cb:ffe6:b320 with SMTP id x22-20020a6b6a16000000b007cbffe6b320mr5023095iog.5.1710912925663; Tue, 19 Mar 2024 22:35:25 -0700 (PDT) Received: from ?IPV6:2001:470:42c4:101:9af9:b18f:3f69:51be? ([2001:470:42c4:101:9af9:b18f:3f69:51be]) by smtp.gmail.com with ESMTPSA id q6-20020a5d9f06000000b007cc6af6686esm1679597iot.30.2024.03.19.22.35.25 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 22:35:25 -0700 (PDT) Message-ID: <65fa759d.5d0a0220.fe5f7.1fa1@mx.google.com> From: Sam Edwards X-Google-Original-From: Sam Edwards To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 19 Mar 2024 16:52:10 -0600 Subject: [RESEND v2 RFC 2/5] i2c: mv64xxx: Clean up the private data struct Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: There are many fields in `struct mv64xxx_i2c_data` with `u32` type despite this not being the correct type for those fields. Change the types to accurately reflect what is being kept in each field. Signed-off-by: Sam Edwards --- drivers/i2c/busses/i2c-mv64xxx.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index cfc16909fba3..bb048e655be7 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -83,7 +83,7 @@ #define MV64XXX_I2C_BRIDGE_STATUS_ERROR BIT(0) /* Driver states */ -enum { +enum mv64xxx_i2c_state { MV64XXX_I2C_STATE_INVALID, MV64XXX_I2C_STATE_IDLE, MV64XXX_I2C_STATE_WAITING_FOR_START_COND, @@ -95,7 +95,7 @@ enum { }; /* Driver actions */ -enum { +enum mv64xxx_i2c_action { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_SEND_RESTART, @@ -121,21 +121,21 @@ struct mv64xxx_i2c_data { struct i2c_msg *msgs; int num_msgs; int irq; - u32 state; - u32 action; - u32 aborting; + enum mv64xxx_i2c_state state; + enum mv64xxx_i2c_action action; + bool aborting; u32 cntl_bits; void __iomem *reg_base; struct mv64xxx_i2c_regs reg_offsets; - u32 addr1; - u32 addr2; - u32 bytes_left; - u32 byte_posn; - u32 send_stop; - u32 block; + u8 addr1; + u8 addr2; + size_t bytes_left; + size_t byte_posn; + bool send_stop; + bool block; int rc; - u32 freq_m; - u32 freq_n; + u8 freq_m; + u8 freq_n; struct clk *clk; struct clk *reg_clk; wait_queue_head_t waitq; From patchwork Tue Mar 19 22:52:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 1913859 X-Patchwork-Delegate: andi.shyti@kernel.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=mdadvEum; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=147.75.48.161; helo=sy.mirrors.kernel.org; envelope-from=linux-i2c+bounces-2431-incoming=patchwork.ozlabs.org@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org [147.75.48.161]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Tzy4Y6gvtz1yXD for ; Wed, 20 Mar 2024 16:36:13 +1100 (AEDT) Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 9E7D0B21CFE for ; Wed, 20 Mar 2024 05:36:12 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 25E841E539; Wed, 20 Mar 2024 05:35:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mdadvEum" X-Original-To: linux-i2c@vger.kernel.org Received: from mail-il1-f175.google.com (mail-il1-f175.google.com [209.85.166.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 012341A5A2; Wed, 20 Mar 2024 05:35:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912929; cv=none; b=Ty+iZnj7zk8OoW9VYRphAAaWHuubilbt5FFRfrhQjzyFJfN4RQy50YKHMks9dLH0dneUsuha/oMwbvyBuVaOQ55cNv2ajbJ4eLXDR0f1gzR/DLPMucmh8fXfflynYTXej4eaEBnthLw5eQV0OgCk0EM/Z4j6qEc+X9ga7xHMzdI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912929; c=relaxed/simple; bh=0QUR7CvQsIAP48SPSK12CRPs8R99SB04ja257Bp1u+I=; h=Message-ID:From:To:Cc:Date:Subject; b=sHxJHgvFKxMUk+2OHAfvzS8b+KyssMpI9tq9Zhm9Ibd1MUphg4FrXXpFsizUX7W9rzN4AfjBrYVU01xZsFra8TOhYiC7Ey2lNoiNmwogDqnR/CC5NhCUYGoWltgRumMQvDfJVJNhJ6J+rVFkLoB9u++EUpwNaOu4ewfYd8p8+Ds= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mdadvEum; arc=none smtp.client-ip=209.85.166.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-il1-f175.google.com with SMTP id e9e14a558f8ab-366bc265e58so11777765ab.1; Tue, 19 Mar 2024 22:35:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710912927; x=1711517727; darn=vger.kernel.org; h=subject:date:cc:to:from:message-id:from:to:cc:subject:date :message-id:reply-to; bh=zOVOSmqgmZjyb38stmrb/+FvriE9SAmYfY33yzJaL+w=; b=mdadvEumOerf+VMa6ouNZcS2fgnpTR/oI0k301lFrFL02e0vjoiCP2qIXCjbCmECSl 5dSN140u30fQ4R3d0hxku1ML+uV/r6UJF0Y5MUvr3XGs+t9c7uBsLXNEfXo8RlEnsRzu WsMhEIhsqtT0j1KS4ArofapDNiT8gWHHckYb/iGhMWFsNdY3yTLXVxYr4VT4YwoTUsP+ kddvEBSXOG2aHMQCk+mpjQV4wlRCFzVvpwBoIGgxgLLWYU7VsskPAwCYaVM2/usimTiQ M5UIKvyO8dEB4eGpuKv7O6iJjgQ3aaAMVmsgdqoGx/dD/Id5CsfG5xZ3cRtlEKSY7DAC LnMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710912927; x=1711517727; h=subject:date:cc:to:from:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zOVOSmqgmZjyb38stmrb/+FvriE9SAmYfY33yzJaL+w=; b=EyghNCaXJ8Wp+eZyvZhDYfnNlIFY7OXxjq3xBF65GuOoR86jhsMKG1ybj5oS2ZrSte uaGyEIejgiGrNFEUgUyn4qbxGjL76YvzBu8pdHQfW2upst0nYjbredY9YKQ91aa2y3xH hhoRMc+2pa+JROKCg/HqvMF9jSwg0V5WdukUd0I+ar2Fk/b6z7uuVh4WVy/xRm1zv+cb sc/oXlIZevXiY44cM2arEEBsst+HuJo+IiH+3t12W+WxqS+we4LPzDXsuconvJdMWXJJ 0gUhxVforwCrRX8V2xIcN4cY4R+7eqUFSIUS7SjfLupPRnMNeMSM2FRzOVFK6I990rJe qiLw== X-Forwarded-Encrypted: i=1; AJvYcCVvZDKdTnCQd1n+zM6Xt64XmDOFvWhvQBv/NzJIURHT1g9NYKjOlARfugazvKjpy35ojM5TzTSDsEqgOYK3mvZSekqKWNQO5bSsaIL2 X-Gm-Message-State: AOJu0Yy1S4SgnMMFcXGrc7ZdCS/WmNhE+XdjsDYI78Hxr3rwmc3E6h+n bPzehJZVkWtM1EgcXBb6VzKeyLdFrxTI6mVtHvYVWgKgRnRnqOhHdtXrE4TD X-Google-Smtp-Source: AGHT+IHxs1oUx433VdN/YpzWP3SocDuuHnAuaIePgkCIooK9PY+kJ8UETBhJB62RA2caJcjs74tRrg== X-Received: by 2002:a6b:c9c7:0:b0:7cb:fb25:270a with SMTP id z190-20020a6bc9c7000000b007cbfb25270amr15296706iof.4.1710912927025; Tue, 19 Mar 2024 22:35:27 -0700 (PDT) Received: from ?IPV6:2001:470:42c4:101:9af9:b18f:3f69:51be? ([2001:470:42c4:101:9af9:b18f:3f69:51be]) by smtp.gmail.com with ESMTPSA id q6-20020a5d9f06000000b007cc6af6686esm1679597iot.30.2024.03.19.22.35.26 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 22:35:26 -0700 (PDT) Message-ID: <65fa759e.5d0a0220.fe5f7.1fa2@mx.google.com> From: Sam Edwards X-Google-Original-From: Sam Edwards To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 19 Mar 2024 16:52:15 -0600 Subject: [RESEND v2 RFC 3/5] i2c: mv64xxx: Refactor FSM Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Conceptually, there are two FSMs here: a hardware FSM in the MV64XXX itself, and a software FSM in the driver. The current software FSM is not a "real" FSM: it is just using the hardware status to decide what to do next, and the `state` is mostly unused. There are two drawbacks to this approach: 1) If the hardware returns an unexpected status, the driver will accept it blindly, allowing bugs to go unnoticed and complicating testing. 2) The driver FSM cannot have states/transitions not represented in hardware. Rework this by making the hardware status decoder state-aware, and introducing an enum of "events" which can be fed to the driver FSM that reflect the hardware events deduced by the status decoder. Any unexpected status results in an "invalid" event, which triggers the driver's error recovery. The state machine logic is otherwise the same: the sequence of actions emitted by the FSM is unchanged by this patch. Note: The meaning of bytes_left in reads is now the number of byte reads left to *start* on the hardware, not the number of bytes left to be read from the data register. Signed-off-by: Sam Edwards --- drivers/i2c/busses/i2c-mv64xxx.c | 270 +++++++++++++++++++++---------- 1 file changed, 185 insertions(+), 85 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bb048e655be7..3ae74160001d 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -4,10 +4,12 @@ * * Author: Mark A. Greer * - * 2005 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2005 (c) MontaVista, Software, Inc. + * Copyright (c) 2024 Turing Machines, Inc. + * + * This file is licensed under the terms of the GNU General Public License v2. + * This program is licensed "as is" without any warranty of any kind, whether + * express or implied. */ #include #include @@ -86,12 +88,24 @@ enum mv64xxx_i2c_state { MV64XXX_I2C_STATE_INVALID, MV64XXX_I2C_STATE_IDLE, - MV64XXX_I2C_STATE_WAITING_FOR_START_COND, - MV64XXX_I2C_STATE_WAITING_FOR_RESTART, - MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, - MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, + MV64XXX_I2C_STATE_START, + MV64XXX_I2C_STATE_RESTART, + MV64XXX_I2C_STATE_SEND_ADDR_1, + MV64XXX_I2C_STATE_SEND_ADDR_2, + MV64XXX_I2C_STATE_WRITE, + MV64XXX_I2C_STATE_READ, +}; + +/* Driver events */ +enum mv64xxx_i2c_event { + MV64XXX_I2C_EVENT_INVALID, + MV64XXX_I2C_EVENT_STARTED, + MV64XXX_I2C_EVENT_ADDR_ACK, + MV64XXX_I2C_EVENT_ADDR_NO_ACK, + MV64XXX_I2C_EVENT_WR_ACK, + MV64XXX_I2C_EVENT_WR_NO_ACK, + MV64XXX_I2C_EVENT_RD_ACKED, + MV64XXX_I2C_EVENT_RD_UNACKED, }; /* Driver actions */ @@ -232,9 +246,73 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) drv_data->state = MV64XXX_I2C_STATE_IDLE; } +static enum mv64xxx_i2c_event +mv64xxx_i2c_decode_status(struct mv64xxx_i2c_data *drv_data, u32 status) +{ + /* Decode status to event (state-driven; catches unexpected status) */ + switch (drv_data->state) { + case MV64XXX_I2C_STATE_RESTART: + case MV64XXX_I2C_STATE_START: + if (status == MV64XXX_I2C_STATUS_MAST_START || + status == MV64XXX_I2C_STATUS_MAST_REPEAT_START) + return MV64XXX_I2C_EVENT_STARTED; + return MV64XXX_I2C_EVENT_INVALID; + + case MV64XXX_I2C_STATE_SEND_ADDR_1: + if (drv_data->msg->flags & I2C_M_RD) { + if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK) + return MV64XXX_I2C_EVENT_ADDR_ACK; + else if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK) + return MV64XXX_I2C_EVENT_ADDR_NO_ACK; + } else { + if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK) + return MV64XXX_I2C_EVENT_ADDR_ACK; + else if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK) + return MV64XXX_I2C_EVENT_ADDR_NO_ACK; + } + return MV64XXX_I2C_EVENT_INVALID; + + case MV64XXX_I2C_STATE_SEND_ADDR_2: + if (drv_data->msg->flags & I2C_M_RD) { + if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK) + return MV64XXX_I2C_EVENT_ADDR_ACK; + else if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK) + return MV64XXX_I2C_EVENT_ADDR_NO_ACK; + } else { + if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK) + return MV64XXX_I2C_EVENT_ADDR_ACK; + else if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK) + return MV64XXX_I2C_EVENT_ADDR_NO_ACK; + } + return MV64XXX_I2C_EVENT_INVALID; + + case MV64XXX_I2C_STATE_WRITE: + if (status == MV64XXX_I2C_STATUS_MAST_WR_ACK) + return MV64XXX_I2C_EVENT_WR_ACK; + else if (status == MV64XXX_I2C_STATUS_MAST_WR_NO_ACK) + return MV64XXX_I2C_EVENT_ADDR_NO_ACK; + return MV64XXX_I2C_EVENT_INVALID; + + case MV64XXX_I2C_STATE_READ: + if (status == MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) + return MV64XXX_I2C_EVENT_RD_ACKED; + else if (status == MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK) + return MV64XXX_I2C_EVENT_RD_UNACKED; + return MV64XXX_I2C_EVENT_INVALID; + + default: + return MV64XXX_I2C_EVENT_INVALID; + } +} + static void mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) { + enum mv64xxx_i2c_event event; + enum mv64xxx_i2c_state prev_state = drv_data->state; + + drv_data->action = MV64XXX_I2C_ACTION_INVALID; + /* * If state is idle, then this is likely the remnants of an old * operation that driver has given up on or the user has killed. @@ -245,99 +323,121 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) return; } - /* The status from the ctlr [mostly] tells us what to do next */ - switch (status) { - /* Start condition interrupt */ - case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */ - case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ - drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; + /* + * The FSM is broken into 3 parts: + * 1) Decode `status` to determine the underlying hardware event + * 2) Handle hardware event driven state transitions + * 3) Perform internal state transitions and action emission + */ + event = mv64xxx_i2c_decode_status(drv_data, status); + + /* Handle event; determine state transition */ + switch (event) { + case MV64XXX_I2C_EVENT_STARTED: + drv_data->state = MV64XXX_I2C_STATE_SEND_ADDR_1; break; - /* Performing a write */ - case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ - if (drv_data->msg->flags & I2C_M_TEN) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; - break; - } - fallthrough; - case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ - case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ - if ((drv_data->bytes_left == 0) - || (drv_data->aborting - && (drv_data->byte_posn != 0))) { - if (drv_data->send_stop || drv_data->aborting) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; - } else { - drv_data->action = - MV64XXX_I2C_ACTION_SEND_RESTART; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_RESTART; - } - } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; - drv_data->bytes_left--; - } + case MV64XXX_I2C_EVENT_ADDR_ACK: + if ((drv_data->state == MV64XXX_I2C_STATE_SEND_ADDR_1) + && (drv_data->msg->flags & I2C_M_TEN)) + drv_data->state = MV64XXX_I2C_STATE_SEND_ADDR_2; + else if (drv_data->msg->flags & I2C_M_RD) + drv_data->state = MV64XXX_I2C_STATE_READ; + else + drv_data->state = MV64XXX_I2C_STATE_WRITE; break; - /* Performing a read */ - case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ - if (drv_data->msg->flags & I2C_M_TEN) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; - break; - } - fallthrough; - case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ - if (drv_data->bytes_left == 0) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; - break; - } - fallthrough; - case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ - if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) - drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; - else { - drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; - drv_data->bytes_left--; - } - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + case MV64XXX_I2C_EVENT_ADDR_NO_ACK: + case MV64XXX_I2C_EVENT_WR_NO_ACK: + /* Doesn't seem to be a device at other end */ + drv_data->state = MV64XXX_I2C_STATE_IDLE; + break; - if ((drv_data->bytes_left == 1) || drv_data->aborting) - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; + case MV64XXX_I2C_EVENT_WR_ACK: break; - case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ - drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; + case MV64XXX_I2C_EVENT_RD_ACKED: + BUG_ON(drv_data->bytes_left == 0); break; - case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ - case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ - case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ - /* Doesn't seem to be a device at other end */ - drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; - drv_data->rc = -ENXIO; + case MV64XXX_I2C_EVENT_RD_UNACKED: + BUG_ON(drv_data->bytes_left != 0); break; + case MV64XXX_I2C_EVENT_INVALID: default: dev_err(&drv_data->adapter.dev, "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " - "status: 0x%x, addr: 0x%x, flags: 0x%x\n", - drv_data->state, status, drv_data->msg->addr, + "status: 0x%x, event: 0x%x, addr: 0x%x, flags: 0x%x\n", + drv_data->state, status, event, drv_data->msg->addr, drv_data->msg->flags); drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; mv64xxx_i2c_hw_init(drv_data); i2c_recover_bus(&drv_data->adapter); drv_data->rc = -EAGAIN; + return; + } + + /* Internal FSM transitions and action emission */ + switch (drv_data->state) { + case MV64XXX_I2C_STATE_IDLE: + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->rc = -ENXIO; + break; + + case MV64XXX_I2C_STATE_SEND_ADDR_1: + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; + break; + + case MV64XXX_I2C_STATE_SEND_ADDR_2: + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; + break; + + case MV64XXX_I2C_STATE_READ: + if (drv_data->bytes_left == 0) { + if (prev_state == MV64XXX_I2C_STATE_READ) + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; + else + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } else { + if (prev_state == MV64XXX_I2C_STATE_READ) + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; + else + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + + /* + * bytes_left counts the remaining read actions to send + * to the hardware, not the remaining bytes to be + * retrieved from the data register + */ + if (drv_data->aborting) + drv_data->bytes_left = 0; + else + drv_data->bytes_left--; + + if (drv_data->bytes_left == 0) + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; + } + break; + + case MV64XXX_I2C_STATE_WRITE: + if ((drv_data->bytes_left == 0) + || (drv_data->aborting && (drv_data->byte_posn != 0))) { + if (drv_data->send_stop || drv_data->aborting) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_RESTART; + drv_data->state = MV64XXX_I2C_STATE_RESTART; + } + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; + drv_data->bytes_left--; + } + break; + + default: } } @@ -611,7 +711,7 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, spin_lock_irqsave(&drv_data->lock, flags); - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + drv_data->state = MV64XXX_I2C_STATE_START; drv_data->send_stop = is_last; drv_data->block = 1; From patchwork Tue Mar 19 22:52:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 1913860 X-Patchwork-Delegate: andi.shyti@kernel.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=DsRYkQ8J; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2604:1380:45e3:2400::1; helo=sv.mirrors.kernel.org; envelope-from=linux-i2c+bounces-2432-incoming=patchwork.ozlabs.org@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org [IPv6:2604:1380:45e3:2400::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Tzy4l3Tcmz1yXD for ; Wed, 20 Mar 2024 16:36:23 +1100 (AEDT) Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id AC92D28398B for ; Wed, 20 Mar 2024 05:36:21 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4033A1EB45; Wed, 20 Mar 2024 05:35:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DsRYkQ8J" X-Original-To: linux-i2c@vger.kernel.org Received: from mail-io1-f51.google.com (mail-io1-f51.google.com [209.85.166.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 579FE1DFC6; Wed, 20 Mar 2024 05:35:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912930; cv=none; b=YLsDBdcDfF+CIVvIqNlj/RNE9OssBS9CVQiq6i9ivc+iKsmcxRreH/VGaaLXI4KxHeqGBwYHc/QbJO4mKO4TBmsvJx4kWoThr2YT7bAOEC6EJNRB4XRw+DVIlT2tXlgaa0p5wA9P8ql7h1f0wPOSSjUDGe43lgnq9fRk0ULra+w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912930; c=relaxed/simple; bh=8+XRLv4yspwrSxXIBKsMaAahMv/pc1nzpXoHyOWLr6E=; h=Message-ID:From:To:Cc:Date:Subject; b=ow4N9lneAfl0kk2fhg2Dt0yg4AT05jEgPc/feNtYFP3RExUxWRnapP28qmXPG1SBYy6hBu1uyWweDIl8WWEa2ZsllZfLw8FWTcNtc2VU2Jga2hT6nA7kDGXcMt2044wUKqI982+d04S5BwJPe5lnlIeqcE1m4ttc3033/ukTgjo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DsRYkQ8J; arc=none smtp.client-ip=209.85.166.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-io1-f51.google.com with SMTP id ca18e2360f4ac-7cc864215caso79707039f.3; Tue, 19 Mar 2024 22:35:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710912928; x=1711517728; darn=vger.kernel.org; h=subject:date:cc:to:from:message-id:from:to:cc:subject:date :message-id:reply-to; bh=IkJly6CToglvrrSNNJ0loQzOxfua+P4wReRnQggto/w=; b=DsRYkQ8Jnam5lUM6cH3WXUfS7osc1aL5BeJtcEPTUWG4/qC7zB/QsUbnYBx7fepvzj xVGqUDvIFZ7YsIM49iGUksoEnSfDwUx1oiKK44qhONFYOIRSlgqtEiK/4oD2bXUbu7I4 mM5EJdbh3GMAB1B2C/CmYJcXulZIEYU37Z6uFufwJS4k4S9H2PpzvRdEpJNFCZrF4BbS +eBzdKake6zocWs4HR/A7Qticd4C/4vE9oeYKAutKzv0b9cvEzoVNIGgMsZfrXCZOiVT yutH+Db830j/mCIB9xr71suYPm23hoF7Bp0okmw9P1THtdVOeKBuM067SE09+UEpSpky 0MJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710912928; x=1711517728; h=subject:date:cc:to:from:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IkJly6CToglvrrSNNJ0loQzOxfua+P4wReRnQggto/w=; b=NE7QscgqWuk/+/rfQW/dzZXyMUhmG2UzRq+1UG+NUMBH/SyvIsoBzCMJh2OuUQFjvJ qzA9lFx/o48Qeb9vlDRQzsvy+4c/YyGW70Gsui3n2iDM0tQnTbuxZIAvKZmc4QmLT5j6 fkzM4YG1Jc05ALbLEA+eZ47/MKY/0KWLcbSB2s7NI+9Jr3vEEOm1KgoQpkHe3VqHjIst r9eAJCqFWy6k3eu/ncy+O+TMPh/yPh9Gt0ngu90UY6qcr4cPo7Xs6OOGvAnnm1hjIzZS 49DCenCiTMp9bEzz/gJOI+Lpq79G4U/tePD/26lp1yjQpaG2Ots2Zwi5G8wWo8yDzmV6 ihdQ== X-Forwarded-Encrypted: i=1; AJvYcCU8oXs9A7xeIyWoVIgF9iIjiJjzd7HIfVmBAcRA0ggfasX/B2vmGoM3ItfiyU2iqn2nJA/3pYFzbRgPa2sMLhlddXt1yHCzRZQ3JwoS X-Gm-Message-State: AOJu0YypVqnPbnT5e8RI0OY5wFjyTCZRh/ijfXOpvxM/u+bYOJf8bJCT 4fizF3Ho53yIhHA8G1LvXJ9GFEGbIA7GWu0VzgIkosRf0ERzKTw7OBz/Vcjt X-Google-Smtp-Source: AGHT+IEZXkMghds1FSnsqYDp4eoun7ENEdWKTUS1VXeqOmcK7Go63JKhsOnbfqX67JeKWmRuCfpSow== X-Received: by 2002:a05:6602:1799:b0:7cc:5e1:5418 with SMTP id y25-20020a056602179900b007cc05e15418mr12463029iox.19.1710912928485; Tue, 19 Mar 2024 22:35:28 -0700 (PDT) Received: from ?IPV6:2001:470:42c4:101:9af9:b18f:3f69:51be? ([2001:470:42c4:101:9af9:b18f:3f69:51be]) by smtp.gmail.com with ESMTPSA id q6-20020a5d9f06000000b007cc6af6686esm1679597iot.30.2024.03.19.22.35.27 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 22:35:28 -0700 (PDT) Message-ID: <65fa75a0.5d0a0220.fe5f7.1fa3@mx.google.com> From: Sam Edwards X-Google-Original-From: Sam Edwards To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 19 Mar 2024 16:52:21 -0600 Subject: [RESEND v2 RFC 4/5] i2c: mv64xxx: Allow continuing after read Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: The current FSM does not check the `send_stop` flag when completing a read message; it just assumes any read message is always the end of the transfer. This means subsequent messages go unprocessed, with no error code to indicate otherwise. Fixing this requires that the FSM check the `send_stop` flag and issue the `SEND_RESTART` action instead of stop, but there are only two RCV_* variants, one for receive-and-continue and one for receive-and-stop. We could add another variant, however, the new FSM from the previous patch makes it pretty clear that the RCV_* variants aren't really full actions in their own respect, since they both implement the same observable functionality as another action, just with an added read from the data register first. Therefore, convert the receive actions to a flag that can be set, allowing any action to have an "...and also read" variant. The FSM can then just use the plain SEND_RESTART action, but OR-in the flag, to represent "read a byte, finish this message, go to the next message." Signed-off-by: Sam Edwards --- drivers/i2c/busses/i2c-mv64xxx.c | 47 +++++++++++--------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 3ae74160001d..6a205cca603a 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -116,9 +116,9 @@ enum mv64xxx_i2c_action { MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_2, MV64XXX_I2C_ACTION_SEND_DATA, - MV64XXX_I2C_ACTION_RCV_DATA, - MV64XXX_I2C_ACTION_RCV_DATA_STOP, MV64XXX_I2C_ACTION_SEND_STOP, + + MV64XXX_I2C_ACTION_RECEIVE = 0x80, }; struct mv64xxx_i2c_regs { @@ -395,16 +395,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) case MV64XXX_I2C_STATE_READ: if (drv_data->bytes_left == 0) { - if (prev_state == MV64XXX_I2C_STATE_READ) - drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; - else + if (drv_data->send_stop || drv_data->aborting) { drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_RESTART; + drv_data->state = MV64XXX_I2C_STATE_RESTART; + } } else { - if (prev_state == MV64XXX_I2C_STATE_READ) - drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; - else - drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; /* * bytes_left counts the remaining read actions to send @@ -419,6 +418,8 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) if (drv_data->bytes_left == 0) drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; } + if (prev_state == MV64XXX_I2C_STATE_READ) + drv_data->action |= MV64XXX_I2C_ACTION_RECEIVE; break; case MV64XXX_I2C_STATE_WRITE: @@ -457,6 +458,11 @@ static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data) static void mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) { + if (drv_data->action & MV64XXX_I2C_ACTION_RECEIVE) + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + drv_data->reg_offsets.data); + drv_data->action &= ~MV64XXX_I2C_ACTION_RECEIVE; + switch(drv_data->action) { case MV64XXX_I2C_ACTION_SEND_RESTART: /* We should only get here if we have further messages */ @@ -503,27 +509,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base + drv_data->reg_offsets.control); break; - case MV64XXX_I2C_ACTION_RCV_DATA: - drv_data->msg->buf[drv_data->byte_posn++] = - readl(drv_data->reg_base + drv_data->reg_offsets.data); - writel(drv_data->cntl_bits, - drv_data->reg_base + drv_data->reg_offsets.control); - break; - - case MV64XXX_I2C_ACTION_RCV_DATA_STOP: - drv_data->msg->buf[drv_data->byte_posn++] = - readl(drv_data->reg_base + drv_data->reg_offsets.data); - if (!drv_data->atomic) - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, - drv_data->reg_base + drv_data->reg_offsets.control); - drv_data->block = 0; - if (drv_data->errata_delay) - udelay(5); - - wake_up(&drv_data->waitq); - break; - case MV64XXX_I2C_ACTION_INVALID: default: dev_err(&drv_data->adapter.dev, From patchwork Tue Mar 19 22:52:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 1913861 X-Patchwork-Delegate: andi.shyti@kernel.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=PIqJiztV; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=147.75.80.249; helo=am.mirrors.kernel.org; envelope-from=linux-i2c+bounces-2433-incoming=patchwork.ozlabs.org@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from am.mirrors.kernel.org (am.mirrors.kernel.org [147.75.80.249]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Tzy5C4MnQz1yXD for ; Wed, 20 Mar 2024 16:36:47 +1100 (AEDT) Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id AE9571F22B99 for ; Wed, 20 Mar 2024 05:36:44 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 45F67241E7; Wed, 20 Mar 2024 05:35:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PIqJiztV" X-Original-To: linux-i2c@vger.kernel.org Received: from mail-io1-f44.google.com (mail-io1-f44.google.com [209.85.166.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 399A020DE5; Wed, 20 Mar 2024 05:35:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912933; cv=none; b=RwU4oscJWczlgm7lyfsL1jHe3ge1OxC0kdxM7RJAOcyESfg04Am6cPTW1YnugqRBFtKeDGzzXDCZWBNPAZt9N7xJqayAfpq4zXpUfKq6pWEA8q/Vz0sySf22JYfMA5WEGTkUF2CeAAMQkjfHQbRegsD8iTRu9R+eue/5ULLTNNE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710912933; c=relaxed/simple; bh=acjNLx8citQNYv7hc9P0dJeaGWmIbEhzPE1To+eghJk=; h=Message-ID:From:To:Cc:Date:Subject; b=Z/ZjAKWqB9z3+BzrFgVUrsz0V3J6PElb9BcPHLcUV8qdthJTJ/TyY+nmNQfGK0f2iwvNMveEHdyeF/T8u3sZ1EGU1QylME5OMQ+wTwDg030Agow/UZVL9vbStYD+RCQy+DuKpw0rQaQctU3E+pSRVg8MBpjdMPfBKcdxOZkAtcc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PIqJiztV; arc=none smtp.client-ip=209.85.166.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-io1-f44.google.com with SMTP id ca18e2360f4ac-7c8060a8489so138882939f.0; Tue, 19 Mar 2024 22:35:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710912930; x=1711517730; darn=vger.kernel.org; h=subject:date:cc:to:from:message-id:from:to:cc:subject:date :message-id:reply-to; bh=J1TVeylraIHS/40ZJpeh/ShzEqQdq14GVcFuMpcFTQQ=; b=PIqJiztVpIAemz0GZ4Q3r4Nu3zBud9gIX4bNTTfIADmVXe6TkQnADoZLxLTh4Z3tas FBy+lmoIUhVHAfVU3MKOSoYrRkdnhH+wKfA44gYH7rZXv3/77gTyXOIPon0Al6JcW0rk jYFMfCa/1WYZWnBXYpIkymz6+5ktXTei1WNxYwGgdSUli/IA6cz6neRFIVQqNK5xlA62 iFpoYvm2IxDSPBdOF8m/T6WYO7grctEDT75cksGIEQfmy2C+K1C8OCAFkxFVkcPi1gHG L1kpA8ARCysfIo95M6JpX5L0g2TsByrM0Tlbf2Vp2cn/a92MX72cv8S5+dDApzUQIaoc K0cQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710912930; x=1711517730; h=subject:date:cc:to:from:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=J1TVeylraIHS/40ZJpeh/ShzEqQdq14GVcFuMpcFTQQ=; b=eLQzyNW+ET8mJC0uNLXN/ialUETfEFUoEUTXPUsfdWgRmc7XkW6cDajv7H6f2Y5IeP FSFL3gepG29pqhKuK1PNrTGtx6SvNhBq+WXfOooAvIezSxPf74SqJQSmByCnRQJM6f5K wYWy3m7KXPiYhjzR86mM+RZ2TXLUA0xNpDEaTLiHPt56h/PqjOqiFfUH+NNnHzNdcKGe C32SkWQcWq4yu14YbbefEdQ/nmxpIzqun93vF9abyuC4HVVGohWn1QkkRa0uwtYzJhsQ k1LH9cBUn/OXDRqlfXwaInv1+XcA5quVJu3LznoBcMk3NlY2+xljTvEomTjCE2GfWh0r rRLA== X-Forwarded-Encrypted: i=1; AJvYcCVxiEbuQSHSBOgX3DPX0YAa5R3LifYLm4Kg23G+dBNQpMBDVBw6dD5bRiVy9MyUYSC4xl4N6bzpfGPdjJLxWEz+tQGHI8w6RGe2Er3s X-Gm-Message-State: AOJu0YyHBSwDRUTaZd4DDsN6En9X5iu0/dcfF3n+EhxLRXhP1JsxI8E5 HnpoF8DZycJAeWtyCkVcCiJZ2lH8tvgCG2oGgbAkBD++MsOP1fhd X-Google-Smtp-Source: AGHT+IF5/q16vRWg25pzVE4/V1Y8i6AaZhh6eyiGEAHYlmU+l+JJS05HF01ZhsjnRmeznpsW1fMviQ== X-Received: by 2002:a5d:8c95:0:b0:7cc:6e18:4627 with SMTP id g21-20020a5d8c95000000b007cc6e184627mr1159899ion.20.1710912930417; Tue, 19 Mar 2024 22:35:30 -0700 (PDT) Received: from ?IPV6:2001:470:42c4:101:9af9:b18f:3f69:51be? ([2001:470:42c4:101:9af9:b18f:3f69:51be]) by smtp.gmail.com with ESMTPSA id q6-20020a5d9f06000000b007cc6af6686esm1679597iot.30.2024.03.19.22.35.29 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 22:35:30 -0700 (PDT) Message-ID: <65fa75a2.5d0a0220.fe5f7.1fa4@mx.google.com> From: Sam Edwards X-Google-Original-From: Sam Edwards To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 19 Mar 2024 16:52:25 -0600 Subject: [RESEND v2 RFC 5/5] i2c: mv64xxx: Implement I2C_FUNC_NOSTART Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: There are certain I2C devices [1] that require some extra parameter bytes in any read operation, after the start byte but before the bus turnaround, in contrast to the "conventional" approach of using a normal write to parameterize the upcoming read. The (Allwinner variant of) mv64xxx supports this kind of transfer, for up to 3 bytes of additional data, through a register called "TWI_EFR" ("Enhance Feature Register"). These devices can be supported by setting this register appropriately when beginning the read operation. In absence of a specialized flag to represent this in Linux's I2C subsystem, clients use I2C_M_NOSTART to achieve this. In fact, this appears to be the most common use of I2C_M_NOSTART in the Linux codebase, with the second most common being to implement "gather" I/O by chaining a series of NOSTART writes. This patch implements both of these use cases when the EFR is present: 1) Continuing a write message with further write bytes, as a sort of "gather" operation. 2) Inserting extra parameter bytes after the address of a read operation, using a zero-byte read, a small (<= 3 bytes) NOSTART write, and then a NOSTART read. ...the hardware is likely too strict to allow any other uses, so the message bundle is checked for proper use of NOSTART before it begins. That being said, there's a good chance that these are the only two uses of NOSTART "in the wild," which would mean that this isn't much of a limitation. The implementation redesigns the hardware event handler slightly, so that the FSM can be invoked in a loop if the do_action function generates follow-up events. The NEXT_MESSAGE (formerly SEND_RESTART) action now results in either a restart, or (for NOSTART) a follow-up NOSTART event to the FSM, which allows it to bypass the entire start sequence and jump straight to the data. [1]: See e.g. `as5011_i2c_read`, `ivch_read`, `maven_get_reg` Signed-off-by: Sam Edwards --- drivers/i2c/busses/i2c-mv64xxx.c | 105 +++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6a205cca603a..f09f23404784 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -100,6 +100,7 @@ enum mv64xxx_i2c_state { enum mv64xxx_i2c_event { MV64XXX_I2C_EVENT_INVALID, MV64XXX_I2C_EVENT_STARTED, + MV64XXX_I2C_EVENT_NOSTART, MV64XXX_I2C_EVENT_ADDR_ACK, MV64XXX_I2C_EVENT_ADDR_NO_ACK, MV64XXX_I2C_EVENT_WR_ACK, @@ -112,7 +113,7 @@ enum mv64xxx_i2c_event { enum mv64xxx_i2c_action { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, - MV64XXX_I2C_ACTION_SEND_RESTART, + MV64XXX_I2C_ACTION_NEXT_MESSAGE, MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_2, MV64XXX_I2C_ACTION_SEND_DATA, @@ -129,6 +130,7 @@ struct mv64xxx_i2c_regs { u8 status; u8 clock; u8 soft_reset; + u8 enh_feat; }; struct mv64xxx_i2c_data { @@ -185,6 +187,7 @@ static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_sun4i = { .status = 0x10, .clock = 0x14, .soft_reset = 0x18, + .enh_feat = 0x1c, }; static void @@ -306,9 +309,9 @@ mv64xxx_i2c_decode_status(struct mv64xxx_i2c_data *drv_data, u32 status) } static void -mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) +mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, + enum mv64xxx_i2c_event event, u32 status) { - enum mv64xxx_i2c_event event; enum mv64xxx_i2c_state prev_state = drv_data->state; drv_data->action = MV64XXX_I2C_ACTION_INVALID; @@ -329,7 +332,6 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) * 2) Handle hardware event driven state transitions * 3) Perform internal state transitions and action emission */ - event = mv64xxx_i2c_decode_status(drv_data, status); /* Handle event; determine state transition */ switch (event) { @@ -337,6 +339,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) drv_data->state = MV64XXX_I2C_STATE_SEND_ADDR_1; break; + case MV64XXX_I2C_EVENT_NOSTART: case MV64XXX_I2C_EVENT_ADDR_ACK: if ((drv_data->state == MV64XXX_I2C_STATE_SEND_ADDR_1) && (drv_data->msg->flags & I2C_M_TEN)) @@ -399,7 +402,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; drv_data->state = MV64XXX_I2C_STATE_IDLE; } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_RESTART; + drv_data->action = MV64XXX_I2C_ACTION_NEXT_MESSAGE; drv_data->state = MV64XXX_I2C_STATE_RESTART; } } else { @@ -429,7 +432,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; drv_data->state = MV64XXX_I2C_STATE_IDLE; } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_RESTART; + drv_data->action = MV64XXX_I2C_ACTION_NEXT_MESSAGE; drv_data->state = MV64XXX_I2C_STATE_RESTART; } } else { @@ -444,18 +447,38 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data) { + u8 extra_bytes; + drv_data->msg = drv_data->msgs; drv_data->byte_posn = 0; drv_data->bytes_left = drv_data->msg->len; drv_data->aborting = 0; drv_data->rc = 0; + if (drv_data->msg->flags & I2C_M_NOSTART) + return; + + /* + * If this is a zero-length read, and the next message is a NOSTART + * write, the client driver is trying to insert extra bytes after the + * address but before the read proper. + */ + if ((drv_data->msg->len == 0) && (drv_data->msg->flags & I2C_M_RD) && + (drv_data->num_msgs > 1) && (drv_data->msgs[1].flags == I2C_M_NOSTART)) + extra_bytes = drv_data->msgs[1].len; + else + extra_bytes = 0; + + if (drv_data->reg_offsets.enh_feat != 0) + writel(extra_bytes, + drv_data->reg_base + drv_data->reg_offsets.enh_feat); + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, drv_data->reg_base + drv_data->reg_offsets.control); } -static void +static enum mv64xxx_i2c_event mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) { if (drv_data->action & MV64XXX_I2C_ACTION_RECEIVE) @@ -464,7 +487,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->action &= ~MV64XXX_I2C_ACTION_RECEIVE; switch(drv_data->action) { - case MV64XXX_I2C_ACTION_SEND_RESTART: + case MV64XXX_I2C_ACTION_NEXT_MESSAGE: /* We should only get here if we have further messages */ BUG_ON(drv_data->num_msgs == 0); @@ -481,6 +504,10 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) * Thankfully, do not advertise support for that feature. */ drv_data->send_stop = drv_data->num_msgs == 1; + + if (drv_data->msg->flags & I2C_M_NOSTART) + return MV64XXX_I2C_EVENT_NOSTART; + break; case MV64XXX_I2C_ACTION_CONTINUE: @@ -525,6 +552,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) wake_up(&drv_data->waitq); break; } + + return MV64XXX_I2C_EVENT_INVALID; } static void @@ -595,6 +624,7 @@ static irqreturn_t mv64xxx_i2c_intr(int irq, void *dev_id) { struct mv64xxx_i2c_data *drv_data = dev_id; + enum mv64xxx_i2c_event event; u32 status; irqreturn_t rc = IRQ_NONE; @@ -617,8 +647,11 @@ mv64xxx_i2c_intr(int irq, void *dev_id) ndelay(100); status = readl(drv_data->reg_base + drv_data->reg_offsets.status); - mv64xxx_i2c_fsm(drv_data, status); - mv64xxx_i2c_do_action(drv_data); + event = mv64xxx_i2c_decode_status(drv_data, status); + do { + mv64xxx_i2c_fsm(drv_data, event, status); + event = mv64xxx_i2c_do_action(drv_data); + } while (event != MV64XXX_I2C_EVENT_INVALID); if (drv_data->irq_clear_inverted) writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_IFLG, @@ -830,7 +863,54 @@ mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data) static u32 mv64xxx_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; + + if (drv_data->reg_offsets.enh_feat != 0) + func |= I2C_FUNC_NOSTART; + + return func; +} + +static bool +mv64xxx_i2c_check_msgs(struct i2c_msg msgs[], int num) +{ + int i; + bool is_write, prev_is_write; + + /* + * The I2C hardware is pretty strict about ensuring that the protocol + * is followed properly, and doesn't allow a lot of "creativity" how + * transfers are composed. This driver advertises I2C_FUNC_NOSTART, but + * can only support the two most common patterns for use of NOSTART: + * 1) Continuing a write message with further write bytes, as a sort of + * "gather" operation. + * 2) Inserting extra parameter bytes after the address of a read + * operation, using a zero-byte read, a small (<= 3 bytes) NOSTART + * write, and then a NOSTART read. + */ + + for (i = 0; i < num; i++) { + /* Check for case 1 */ + if (msgs[i].flags & I2C_M_NOSTART) { + if (i == 0) + return false; + is_write = !(msgs[i].flags & I2C_M_RD); + prev_is_write = !(msgs[i-1].flags & I2C_M_RD); + if (!is_write || !prev_is_write) + return false; + } + + /* Check for case 2 */ + if (i + 2 < num) { + if ((msgs[i].flags == I2C_M_RD) && (msgs[i].len == 0) && + (msgs[i+1].flags == I2C_M_NOSTART) && (msgs[i+1].len <= 3) && + (msgs[i+2].flags == (I2C_M_NOSTART|I2C_M_RD))) + i += 2; + } + } + + return true; } static int @@ -840,6 +920,9 @@ mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int rc, ret = num; u32 status; + if (!mv64xxx_i2c_check_msgs(msgs, num)) + return -ENOTSUPP; + rc = pm_runtime_resume_and_get(&adap->dev); if (rc) return rc;