From patchwork Wed Mar 20 01:41:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 781699 Received: from mail-io1-f43.google.com (mail-io1-f43.google.com [209.85.166.43]) (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 3710D8F5A for ; Wed, 20 Mar 2024 01:41:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898863; cv=none; b=ILluOCeupYS/lG4TqT9E6rGFxXIbr8CtRKQm20h1XdSHN6NOv7IEwEWGhlv42zbuIIciaBiWO8nZgKMvoXAFgCSoA0TELCFsYSTKB/UTy6DIloJALjWQnf9FFTNbRCzQJU4HrlHzgjoApC5UB9IUIoKSmM9/GHJ99o4yDnrRnqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898863; c=relaxed/simple; bh=bQ0po2DVBNuqocv/+6T7JzlVaV/yk5Nv6pHDeE2NkiE=; h=Message-ID:Date:MIME-Version:From:Subject:To:Cc:Content-Type; b=ZkFDUoN5131OIYEjA31M7XmKLFrrvBpDGfrSi3SoT0bICxmd39x4jsp5reEULK1CuHm4aCo/2I0EqpcabwzHjkPpkzyaUQsuvPhcNJsroT70APMW5ie7Pl9e8ofCDUbGcHJZuU8LO0zDJF4By8ZXg7zwOvYsNBR3yGa5wmESONM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com; spf=pass smtp.mailfrom=turingpi.com; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b=mIrlVoSd; arc=none smtp.client-ip=209.85.166.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=turingpi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b="mIrlVoSd" Received: by mail-io1-f43.google.com with SMTP id ca18e2360f4ac-7c897ac777aso140999139f.2 for ; Tue, 19 Mar 2024 18:41:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=turingpi.com; s=google; t=1710898861; x=1711503661; darn=vger.kernel.org; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=4lqTTeu70Rhb3yt+ddX2qWBVOcmCNDQFJSvun7EAf10=; b=mIrlVoSdeSIG8nl3+yYYslq59HKJQZCe5WPkHSqSSv2jRcGtvYSU+NmCCK9xff5yVD 0ij44GD+qJHU3JtO5Z5njvllHDw3LfIGNP8YoXDeQYNr6QuoMpFl/Ssm/JahSUJa3DZG gmJk3KlFbi/hmhi23aoSwCxVb4VYsiD1OVgNL07xzT6EWfcbo0aeQZwAYU6Yoxn6UIIJ O16jSnaeyuWDy4mRW1ATUUo4dw9Y+g7+xh3AXkIcqxk3EvfcRe6GRMtRITBoBXZPdFx8 sbM7s5ishmlMPg6dSJuHLIaYVlVF+p/dAjqyyHs8FVmJ27QbK2XXmsWlTEyy+p1A2y6S pSvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710898861; x=1711503661; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=4lqTTeu70Rhb3yt+ddX2qWBVOcmCNDQFJSvun7EAf10=; b=u+Z5fbLuabqEpwggvPMAGAlh+9B4s+5MYzJZXIVHI6kntvOCTqUGPAljxlzKgNYFnL zD/bUz6zkfe71H/YwzLOaOlCAJQnseQimPMdqUsWlYff0XLa7jgNIhIdfn8PfyDYrQ1D oBRbahZvYwxCLRpe9Vuffez6uUtepLuXe8Ki+0P82kDo53g+/GgGSiRlKn/cmmgmmWyc aPqk1g1504400Kq/5FtMBbGyPKTGXu5R36zLPpV0t3zxHT8uuaCLvLOxXx4dWLXMBZ0s jAh8npzgoj6pL4XoRwyQawqt/KMxGaAr1XlfS5QDqeRIWgYyMcGsBz3RbH9JXJMzkbZl dboQ== X-Gm-Message-State: AOJu0YzPlvDxGnVe6DrqG9cDLBVdLWvtUWtslot1Li/Z/s1zTEflv9Lj xzObE+FRyKFflKYqJAMiVstL7tHcuSXdnRNOQR1tYRFHh2dKrtFTvFKNMHAnSUmPe0kUWAnhyjC Gkbs= X-Google-Smtp-Source: AGHT+IFXJTv7mzmrdW4Qn7wZJddJo94O9faxOHExq3t8uNKkxZHnlGuRAc3hn5YJLCVQqvyXiGhmrQ== X-Received: by 2002:a5d:9619:0:b0:7c8:60a6:5bda with SMTP id w25-20020a5d9619000000b007c860a65bdamr4653730iol.17.1710898861395; Tue, 19 Mar 2024 18:41:01 -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 y19-20020a6bc813000000b007cc028ce258sm2632845iof.36.2024.03.19.18.41.00 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 18:41:00 -0700 (PDT) Message-ID: <7bde2b76-ff6e-4cf4-9c23-7b831631ce09@turingpi.com> Date: Tue, 19 Mar 2024 19:41:00 -0600 Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Sam Edwards Subject: [RFC PATCH 1/5] i2c: mv64xxx: Clear bus errors before transfer To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Content-Language: en-US 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 Wed Mar 20 01:41:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 781435 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 5CBCCF512 for ; Wed, 20 Mar 2024 01:41:10 +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=1710898871; cv=none; b=IG0jtXjMxGyn4HWHrk98tge/gMJH8XH+1LgzU7mCIBNAuvyH9k2NC34/PeEP3craWfasszJyscBabFVOLxJUZSU90MK0f+rcNiELh/F1tBlpWtWX2LzqZpx4zUclOaOFZ9Bs08sWSsWR9+rsEc4qdZy8YSER0N5naFoBMctGrPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898871; c=relaxed/simple; bh=f7/xT0HG08QEqOPnvs8BXxOk8KFC9FV9qyN7MsCYleI=; h=Message-ID:Date:MIME-Version:From:Subject:To:Cc:Content-Type; b=WY/PnxLE0vKBVVeL0y+ZQ1RTZ7sFC7xNrxthXJ3GVxaOLn0fzugD8UTSF0LBe38JyCMe6L71ouaRw17dY7ixFAqT+7ZINlaFS6aMFQTXq0ROuz49c2e/T5DXO61q14cqRAIvLV3GhsX5m+eKGVZXOeb2hjZHrE0qMqrSRvo4wZk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com; spf=pass smtp.mailfrom=turingpi.com; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b=VqtpnkG0; arc=none smtp.client-ip=209.85.166.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=turingpi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b="VqtpnkG0" Received: by mail-io1-f54.google.com with SMTP id ca18e2360f4ac-7cc05ce3c70so17572339f.0 for ; Tue, 19 Mar 2024 18:41:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=turingpi.com; s=google; t=1710898869; x=1711503669; darn=vger.kernel.org; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=B7/hpV+Em3BoTxGrwIgXkepVh1gS44KxoPqnDURnUx4=; b=VqtpnkG0J07hPgvkv3N7TGPaGROui2Bf36TyzLVYZIWpJrJipdM7/MtBu2HMFq1deF 1rND9RTmtAcS2KCr1GXl5OvTPRq+05RF23xDg/DzDFTRTY8ESgGla9gByQe6WrDAec88 OKW6/W7Pfzz+xrQLEF7wJ3D7XlQUL/yIdCe5SgPEJk+FJQWjxgtPfVOSyrS3mmoZ4XZi SQbVMDOSZSUi01JClGHWzFTK639G47Iykiie2+Xy2PWghlnq1Gxe6ZhRrflbeKhJsDEj np//k9vq/8zZc9AD1eGKN+e3l0PMrQ8Ya9S2WYOiQKASdfJ2ibsTsG4rnYRqMdmYYqqE k7Sg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710898869; x=1711503669; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=B7/hpV+Em3BoTxGrwIgXkepVh1gS44KxoPqnDURnUx4=; b=BXCa/X24dR0O/IgTThKqqiYTvpR7Xze97UJoSzdRW6vVI0HynRBn2Nt0Jaw4b78kTN X9qhnyqc+tdMSEX09AuAt43R87L9We9HU2t93DHmtWcQ6cGha0HLdLntIcqTvAHzDF4E Q7zTYMEEoRwrho01P2G3ase7f+KyDfLRisHTn8GNhIG7Hdr9nKA1vVVFO6mLEX3r7Glf 6GMxgcJNvHbohzq7I59LWEDPknTgd9GzpKgjLyp6dkMRj2A94XM3DQqJ8tkPRaEKz0Ij hURpWaXls6um0pwq2fGJ0S6I/lhAagkoJss/6gvegdIHBNDnVasbOiZkxsmTaM59GvFJ VFaw== X-Gm-Message-State: AOJu0Yz2vaiucVA9Z3LVTCgqk/1CrUOLYnzK5ZYWfQMrIBZI4lJnh1Fy YL9Z0zfNmgKFno3+a8/mL2wgoASGp6SNZZD7w6LYzaVCUPMhMrNpvLY8yNKqqPM= X-Google-Smtp-Source: AGHT+IGwQeKnJcyeErAbxGtlVeA82Y4WSUEEyptuh/wKhEvsl72/dYks8R4YK7tFt9GH2gjTkU7Mow== X-Received: by 2002:a05:6602:e13:b0:7cb:fdca:e4b9 with SMTP id gp19-20020a0566020e1300b007cbfdcae4b9mr1320643iob.3.1710898869471; Tue, 19 Mar 2024 18:41:09 -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 y19-20020a6bc813000000b007cc028ce258sm2632845iof.36.2024.03.19.18.41.09 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 18:41:09 -0700 (PDT) Message-ID: Date: Tue, 19 Mar 2024 19:41:09 -0600 Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Sam Edwards Subject: [RFC PATCH 2/5] i2c: mv64xxx: Clean up the private data struct To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Content-Language: en-US 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(-) }; /* 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; 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 { From patchwork Wed Mar 20 01:41:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 781698 Received: from mail-io1-f52.google.com (mail-io1-f52.google.com [209.85.166.52]) (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 830DA125A9 for ; Wed, 20 Mar 2024 01:41:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898921; cv=none; b=I6W5tfqYr5IjuwAI1/EgD4C15q4l9xuJx0IxPr5rgNO3vZXtux/sD9GShHqQDjCG3UOyu5xI93yAuAVnT+J7zkQbADhPa4AJAIWYqe8/fu64IL+WjisJLhO9JUTp8mq3Cl2lhJxGScPOGkWxid2+wRilG1fCBbJar8+GtNH/CL0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898921; c=relaxed/simple; bh=MStPja89ObxZXXeU4b4lVLkUj/CkOnw+qYuus9zGsrs=; h=Message-ID:Date:MIME-Version:From:Subject:To:Cc:Content-Type; b=Ijip843X4YdjsrAubSf1OQFcrQ//r8ldJE1+cJPE+PowA4+1bYx042+ZJhPVuwco2ufCVu08eMNeRCyqEHAICut15RC7tfssfN3n9iIi73p6LqbuQbkeAbwFeptYlPhSB43Uw1lB9x3OyAYXbLtL9ye7mnsJxrPcrmH04KM8dLA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com; spf=pass smtp.mailfrom=turingpi.com; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b=sVzTOqwE; arc=none smtp.client-ip=209.85.166.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=turingpi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b="sVzTOqwE" Received: by mail-io1-f52.google.com with SMTP id ca18e2360f4ac-7c7476a11e0so180603739f.3 for ; Tue, 19 Mar 2024 18:41:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=turingpi.com; s=google; t=1710898919; x=1711503719; darn=vger.kernel.org; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=m6Yma9553umU6CRbnvbx3EkCKMxLDNHzJJu+G+lgZ4E=; b=sVzTOqwEePiyWrC/HjXEN7I6vY+fNR8s2JpXacLYPyRV/xzHjmGIJZyqOfGknBWQOc xEBTnJ4T7JxRZg27S5H20OZ6n8gdIqWgpSvxwloP2uuBTdIZIWqp8fvg7/ULTBiykOla GQ86ZipPX3mczj28Bhn0/3SyIBMSJ8lj/y9ai9W9cjUZl8UXwpCjNHQ8Psc4aClly8lR y/3VziK14aVvvpdQR8WGZjPBEk24psD17cIQdHKW5MVVsTOLCDJW0arhol9Jhb38qPYd 5vUdCEeN9kAPXvoiy5Z+ELVgPvW7nrHptBh3BPBpBuHBZy/ozVACcRP61422HEYvK7gu ZGmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710898919; x=1711503719; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=m6Yma9553umU6CRbnvbx3EkCKMxLDNHzJJu+G+lgZ4E=; b=FxKB/kKSGG3Mnd6QBYW5bMpM2taU8WqEgW5qn3RqbwEcuexrfNr1Fm+AES605efIQ3 /YyMbC8RQl0eUMzaPxZDo6VjjHf2VEQH0PHK+7bE4LIxj/FHetCxiGmsPQLj7qF/3hda 84Wi5//1wrZbAd7e5x972jwxMVihd8xvD3N+SPF6CYj+hKlz7B8Y+rYgzuI7xzfyFSWC 3O24c1z14v9zv2w0afWqQHBaZ/J6jG04L2nwqKYkqTHJU7uAErkXKEJRAcNPhGjb+JNY UANFs/kdkbUawujpJ1+GnMMfKj6dPQosDpGSnJkTkkPIoIREJTy1C9m9D5KTMMvQ6t31 P4/w== X-Gm-Message-State: AOJu0Yz5XOGqQBzlcoX43HDmgsgfmInaVeFeFjzEWt1uIFe5EFezbhMV zSI/JwRXzjbyCFbsKN3j9jxCFGUnYyFUdSnis6O2oV5csD/u4PJRD2sO9QQJ8VQ= X-Google-Smtp-Source: AGHT+IF8PWqBVNUTVdv1H6sqQcmfhaHlA59RJsL3qqvXJz7CZr2P6TZTb+R9x0W9EMQ0nGTIzUtxmQ== X-Received: by 2002:a5e:c248:0:b0:7cb:fdd7:8de with SMTP id w8-20020a5ec248000000b007cbfdd708demr14357252iop.0.1710898918689; Tue, 19 Mar 2024 18:41:58 -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 y19-20020a6bc813000000b007cc028ce258sm2632845iof.36.2024.03.19.18.41.58 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 18:41:58 -0700 (PDT) Message-ID: <6c6042bb-456b-4888-8a42-de79c92b2701@turingpi.com> Date: Tue, 19 Mar 2024 19:41:58 -0600 Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Sam Edwards Subject: [RFC PATCH 3/5] i2c: mv64xxx: Refactor FSM To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Content-Language: en-US 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(-) #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; 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. */ From patchwork Wed Mar 20 01:42:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 781434 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 19D9713AC4 for ; Wed, 20 Mar 2024 01:42:12 +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=1710898934; cv=none; b=BU8ZnUoA0YSJomx1XUeFflW/9qK4V6D8p8OR37+n0lxCyzUmAxHVVck9JymN9KJ/AZfkGrOkqcvDeFi4Rm1bRyCCZj5jNHESYPoEqSlz0q0strdeaOYW5Q4dTnE5MSp8OY9dQp2+GzjJ6Q568RCmmsDhtrTTnQtEgEHo2KuJh50= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898934; c=relaxed/simple; bh=JJp5BjVgwceJSsUFmj642CkDTMAZWthXZgqfDWfpTHI=; h=Message-ID:Date:MIME-Version:From:Subject:To:Cc:Content-Type; b=dQXvJDqAKHthP66seh5nAKtD8SvA2eWGa6yv3AMt2HFAFRwHogbSGgaMCJOYgGZsBSnWVctifOGY/wxnWzq/v1NEEeGWboQPv6n3dWmsgimB+ohFGIyXTe+FUXaCvwP7kkeEKEp7pQ2dzUv0NiqPIb/zLUTWWZSZH/onANuPmbM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com; spf=pass smtp.mailfrom=turingpi.com; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b=k1F/4DvN; arc=none smtp.client-ip=209.85.166.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=turingpi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b="k1F/4DvN" Received: by mail-io1-f44.google.com with SMTP id ca18e2360f4ac-7cef30fbc5aso52520639f.0 for ; Tue, 19 Mar 2024 18:42:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=turingpi.com; s=google; t=1710898932; x=1711503732; darn=vger.kernel.org; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=dJzgiStFUlr1nxSqxAj64/hVS0Fow/+7dcCq3KkYmS0=; b=k1F/4DvNTb72BXfwjGLhVPkv/9DOklOCCJY7H+/PN9eq98k0dkzZJuiaWu3Z2cq10u L8euZ0KTFwY4jqRsgdWkOBYQ246oIF9IFxLReYXCBbIrqW/Mn3MCym6DGOlC9tBiAkgH W6oJtFGuOTYELD5hU+jJbAw9mNhMrGc+PWiAz5qKDSMq52bmJWfpbYBZLqKYklcEk3Ug ww+0BNXs4JvToGPK6XLuQlq8sEXoMkfU/M0q3QPuh2T8cTwB4C3FtEM7noqDTpSraF+1 xhvkFUXbkkRSC+HAC43/udqmIihFNt9HW83yAm4/4HdNapApDcigzeKMTOSMcoLJ9dLt 8n5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710898932; x=1711503732; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=dJzgiStFUlr1nxSqxAj64/hVS0Fow/+7dcCq3KkYmS0=; b=gEv4nM5AZVuycfyrKftWYUYnBmHMrB6QeYH2VlUGlf4B90eB9GnBQ8Yhkpp5Ic2B2E j3V8ersIPH2cFdyOw1yR4a7neH0YtbLu+Q4v8phw1mDLpi2IeMAy24QfXDQm92m/jcUz 4ydGTh5RD+o/cV5WrQhMsrHcXK+a1jj+DUXH1SUnBRM4xk5o/wrhCRaDkiJ+dHGUrmTi m98YGUOtpzoCFN8SDxIKK34jxWwr+FZ9YGfjBvurY+CLGEVcmUa7dfK2t0wx5z1xOXuS dsRj4TdsF195WrTobhNAjdsjb9+EQOU68fMXP82T6SemN7Ai3v4qNhqF5BcwfF5ASY0L 3HFw== X-Gm-Message-State: AOJu0Yy0Bg6wI/+p8CqKjSi8QBlRRYGGC4veEan8VNiasr70FlVMZ2d9 S00Mni19acNHaHaC6WTI//6TCRQ/MPwOC5vwVWyH32qGrLcfo7kTvejHJNiQw1KCA5/5THJQTlM oDSQ= X-Google-Smtp-Source: AGHT+IHZ0Akvv10k6gATwoQFeaRxwKlPggp2ClvESjcX3me4odqczTr69IWhpdbBDKqUg1TmNabmWg== X-Received: by 2002:a5d:8491:0:b0:7c8:b7ac:23b with SMTP id t17-20020a5d8491000000b007c8b7ac023bmr19469582iom.4.1710898932311; Tue, 19 Mar 2024 18:42:12 -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 y19-20020a6bc813000000b007cc028ce258sm2632845iof.36.2024.03.19.18.42.11 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 18:42:12 -0700 (PDT) Message-ID: <26aa2bec-8d60-4b01-a6a3-013a50d70330@turingpi.com> Date: Tue, 19 Mar 2024 19:42:11 -0600 Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Sam Edwards Subject: [RFC PATCH 4/5] i2c: mv64xxx: Allow continuing after read To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Content-Language: en-US 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(-) 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, 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, From patchwork Wed Mar 20 01:42:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Edwards X-Patchwork-Id: 781697 Received: from mail-io1-f41.google.com (mail-io1-f41.google.com [209.85.166.41]) (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 3C8E520DE5 for ; Wed, 20 Mar 2024 01:42:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898952; cv=none; b=lPVi7hnxWTjU/vuzZfWl0O0eWF37q7ESKcH5JtESy6y/wcnXNtGwR3L1APu4XNu5VQ/Qlar3zLHqrzsz4PGlArBF631hlURTWvfkcZLonGOMDvFrSqgcDE/99ANx7RUWO4M741ujtUoIFiDAuFW5sO/l0r6sv87II0xvdSUbr8A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710898952; c=relaxed/simple; bh=gRhTT81m5w3zmkRy7+hU7ZO5W0SYFGJYswPUuXwVPvE=; h=Message-ID:Date:MIME-Version:From:Subject:To:Cc:Content-Type; b=dWewq4ZNoLv7qyGbD0lxgwd6OG8a9VCWo5Fpvees7pQBEzrAQLYnNSvwWTzQvnGhYcT/x2aBkWlV/Ula57qwrGzeUwacgdyXt32l/Ucq2c06R11fx17U4QWHHkJIrRHORa8r03kffUCpAsBtuFWneBbmuIm1hjKWCnevtzq8YGw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com; spf=pass smtp.mailfrom=turingpi.com; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b=apvoJnmx; arc=none smtp.client-ip=209.85.166.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=turingpi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=turingpi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=turingpi.com header.i=@turingpi.com header.b="apvoJnmx" Received: by mail-io1-f41.google.com with SMTP id ca18e2360f4ac-7c7476a11e0so180610039f.3 for ; Tue, 19 Mar 2024 18:42:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=turingpi.com; s=google; t=1710898949; x=1711503749; darn=vger.kernel.org; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=pLgTdJH36mvwr2T0MphzrxnMySGTTW/Hx4ZBpDccgyA=; b=apvoJnmxXWN3EMqtVqRN8a8JTg185YBi1rt5o60QP0xqUr2Inx0lnieoynfDb9qpAR sqSlAXebWSeqkjkRoRAc+i3mggqCYR7R8PK4W6+8yWPo9j4wiKDhtbTgwP7N8aEdnDl3 3LvcgXiSs+SdW8vpzjVm1fR0aDRio9i9Sv2bXLs9yPYfJQJmkHss3yDy+/1su+M1KMM1 gecgaQmi279kVqjuIpfKPPBancqpsSVHjvA5+/XGfXYTXzS0fCIO77GP8f0x9tlQkLTJ A+03rmJ9Rkt/wzBRFu/5Z85aire3MH6Daz33aa8hhD+JiGbbWksjwc2Ei7lBEO0tM6S4 +Jjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710898949; x=1711503749; h=content-transfer-encoding:content-language:cc:to:subject:from :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=pLgTdJH36mvwr2T0MphzrxnMySGTTW/Hx4ZBpDccgyA=; b=hsv5Zf7FtB3IJM11ft7Hk5CgZseeYuKB+hF9fOEoMlhNfr6gGehwYd5/MVr/0JKSMb C+ce5gBHITDpnQYXycBj3+WkOht/m8OPK59SR+1EhFmT7lVarl3LNRzLnX2S3yxuMDqX mju2WKNb5T3hvtylavpr/9v9QhmEpqucnQYL1lBiPP0ee5C5avIogUpXg/xHfMxNr6Gc 9zDh/PCM0QUfrQxyeK7hnASYJwriRQEnTge6+dyK2C5AEzh8w6B6IDD1RWCJRbiC7BOZ 4Z/uzsNezcl8AGSPHEJzoSxrFsxurkTgfGF3uWMHO/iOE98P/X6F/82kSc4sGjv4lCiC a0aQ== X-Gm-Message-State: AOJu0YxUCNgLWQWspWmx4pbpm7UEdbbPo6zMZevWfZgXuY9hCvfflTOf Cx1Xx/XkZTrRk1RRpg2UVVHqJiRFq40UnK89G3y9zvoimKEH0Xnv3rP1ZjqP5xx745GpbVQhMA5 3CpE= X-Google-Smtp-Source: AGHT+IFeTXuAPeXLWOVlq0s9pDmy1UbOozTVrwXXAc2vOXvnntIM64WhUsakNOGV6i1W8aOWWdyufg== X-Received: by 2002:a05:6602:5ce:b0:7c8:b447:c3e9 with SMTP id w14-20020a05660205ce00b007c8b447c3e9mr18716646iox.7.1710898949393; Tue, 19 Mar 2024 18:42:29 -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 y19-20020a6bc813000000b007cc028ce258sm2632845iof.36.2024.03.19.18.42.28 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 19 Mar 2024 18:42:29 -0700 (PDT) Message-ID: <82dd7a07-dd9a-46d1-989f-ea3be7c16c46@turingpi.com> Date: Tue, 19 Mar 2024 19:42:28 -0600 Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Sam Edwards Subject: [RFC PATCH 5/5] i2c: mv64xxx: Implement I2C_FUNC_NOSTART To: Gregory CLEMENT , Andi Shyti Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Content-Language: en-US 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(-) 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; 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