From nobody Thu Apr 9 12:50:36 2026 Received: from mail-dy1-f180.google.com (mail-dy1-f180.google.com [74.125.82.180]) (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 EFCE81D5ABA for ; Mon, 9 Mar 2026 00:46:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773017187; cv=none; b=k8f9wUKEN3XAVZJ8RnHQHDEBjpbyNh/TDQLTHWNxolvajYALkWPtgy2KCkCttbY7XgoK+tPnWgOlwY8ulFvr4zBP7Jk/+w6C/RXiCsvmSkwyyoVDGGLq/9yFNvI93czXZPSilrSLdMuuN6vUyYNCCdPiTMPCR4MWl8hNUhT4E10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773017187; c=relaxed/simple; bh=tHoeMFRi6s6I6LRKk8F/SrOG3eKQxuLtAy2rH6tfvWs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=H3+y0+Syf9nyTZcbqhH7OjEIMteM8aQYyDiUhzhF8m34fm8HAk7DijRkAuwFvsDMWiIMQ8mjfyq0AG1XOFRNRpgx94o9qgq7Ob4815MwLJQfw9PDjrbb6tjsJ1MmV7T/0xVVuFkYqK5qvUEtY4xzxHvfA51SH1BKZ19QvF04jE8= 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=RA0lnivn; arc=none smtp.client-ip=74.125.82.180 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RA0lnivn" Received: by mail-dy1-f180.google.com with SMTP id 5a478bee46e88-2be3bdfda8eso4129677eec.1 for ; Sun, 08 Mar 2026 17:46:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773017185; x=1773621985; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=cxW4Is3pvycjCruApvPYUDJnnf0G3HJdKTnyBvELzWs=; b=RA0lnivnhQYoOfESDHVp9EogGPXieqJ5+UYXY0DUuVZmZwV8MMihWaEL08yU3xrKjM u7vScGllQHHsrr03MGXHXA9dJoXhZSDSLABUaLmRrwnKJxAeOlMG2Kk6iUhX38bjaPgU 3zg/LbLF9wJnPGO7TUpEXhG7vXjLmcQKN4XCjQKmuwxHhzbLGsCeyohdqiaAa6GcmlMW jcI47pZyLWYUyNUsS+noA1lVLL6T9+kEBwXqmxrBT/4XvFSHAw58XQBjy2miV+CNQI6i cmcz6LdN8iJLtnuo11qH8a6dofH9CvCYg+ICExjq0QSF57zw5orFEwdTZbm/CtF3jznu nypw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773017185; x=1773621985; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=cxW4Is3pvycjCruApvPYUDJnnf0G3HJdKTnyBvELzWs=; b=D4rXKa4wJF/d2+6wFnhguSbWQSF3p1bnWFNxFOsVBBKbz/6Dg4xdGk+SyAYY+tgXDp Veg5KzMfNGownxVNKf/BSWtyykj0i14Fsnay4w0sw58pYmjuUS7+1BjaW6mQ1VqL5i+j 2wcqix0DisBxnd65xMi+M3GH0MK4R8oCPW1rpD6HcWt8PEppnN9LWZpjf7+fpzmPhspY 8f46DdQ9HzJEB+xK4AZKfWOyySTrX5TQ4e2PnDdXmFW2zyxUWwuW5L7RH6KdyjX/Upig 1+kqKBMeACeO0OTaH31jD9qiQf9f/mxYIpKcgCVfCD8KKgQGyKmHyRGeDhhLQnAJ8nTU zN/Q== X-Forwarded-Encrypted: i=1; AJvYcCUu05zzn29iVGtIIuy1mbO7v5YikSijLUbgXdkm/6LXOdaP/xC5t5gNKBb/seM6sV52wnW2FhIvxar6JSQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yyrg1/Zrjx7DWPn8bPACuwYC9ebAXa/YBi4SeDOW91g0ZfPe4LC /q8H4r+CQBxtt4nZvLY5f4XzMXI4cHMug3MtMUbsncKV7PIIF8Vi5iCHmFLfM9QX X-Gm-Gg: ATEYQzwNp6A7kuiI1EoORu9r8BLrLzTqDURwzuyjC2A13JjRATW8Yx8R8xBhhB9aCyY 1kbYzKfeYmbBz9dJwCuMJowCTxYROx872jrzibcjLpZJaJj94/ZqYDUaA1D37v3FD3+hXq2j9Qm QrsKJJuyEYXGZhu9dyiE4WqDqJunSvZD2acuwIgJxhdeK234rLjfDYpdjutrCrXZsYxLKYhu4nm uLHbus7Bki/hhMRYvuDV2lmztdxydUp/H6+bfuxNu6jREJcPdzPtxRaWxxqijjxCm8s+zBw/blJ I4L9L2Vh2Li6FK2AaXUMIdyHoaVtG8umNO6sbUf/yQTC6gelYSmPvpfiVYSahVA4TnPhFjIpu+a SRk6u5IMK3emoOLEL9Y/oxs/P/AiQ/DmjK1RprbPT//xeQJcxBG6MDn4HyWUY7WG3TS2R/yYOay YTYq+qrlkIvYwTIFJnHPrvtLxbo4+zvAsFYxtF5Vg19oRLJIIHY/I0qI3fodUZZ7sq6U2hO4xZk Fr2YDI= X-Received: by 2002:a05:7300:cd90:b0:2be:2b16:b99f with SMTP id 5a478bee46e88-2be4de928fcmr3334893eec.13.1773017184928; Sun, 08 Mar 2026 17:46:24 -0700 (PDT) Received: from localhost.localdomain (c-67-164-93-214.hsd1.ca.comcast.net. [67.164.93.214]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2be4f948631sm7240105eec.19.2026.03.08.17.46.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 08 Mar 2026 17:46:24 -0700 (PDT) From: Sanman Pradhan To: Sanman Pradhan , Guenter Roeck Cc: Sanman Pradhan , linux-hwmon , linux-kernel Subject: [PATCH v2 1/2] hwmon: (pmbus) export pmbus_wait and pmbus_update_ts Date: Sun, 8 Mar 2026 17:45:07 -0700 Message-Id: <20260309004508.78609-2-sanman.p211993@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260309004508.78609-1-sanman.p211993@gmail.com> References: <20260309004508.78609-1-sanman.p211993@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sanman Pradhan Some PMBus devices require strict inter-transaction delays to avoid NACKs or communication faults. The PMBus core manages this automatically for standard PMBus accesses via pmbus_wait() and pmbus_update_ts(). However, when a device driver performs raw I2C/SMBus transfers (e.g., for long reads or custom commands) that bypass the PMBus core, the core's timing state machine is unaware of the transaction. This can cause the next core-mediated PMBus access to violate the device's required delay. Export pmbus_wait() and pmbus_update_ts() to the PMBUS namespace so device-specific drivers can explicitly synchronize their raw transfers with the core's delay management. Additionally, move the PMBUS_OP_WRITE and PMBUS_OP_PAGE_CHANGE bitmasks into the drivers/hwmon/pmbus/pmbus.h header so callers can accurately report the nature of their raw transactions. Signed-off-by: Sanman Pradhan --- drivers/hwmon/pmbus/pmbus.h | 9 +++++++++ drivers/hwmon/pmbus/pmbus_core.c | 13 ++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index d2e9bfb5320f..afd58128b37e 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -424,6 +424,13 @@ enum vrm_version { vr11 =3D 0, vr12, vr13, imvp9, amd6= 25mv }; #define PMBUS_REV_12 0x22 /* PMBus revision 1.2 */ #define PMBUS_REV_13 0x33 /* PMBus revision 1.3 */ =20 +/* + * The type of operation used for picking the delay between + * successive pmbus operations. + */ +#define PMBUS_OP_WRITE BIT(0) +#define PMBUS_OP_PAGE_CHANGE BIT(1) + struct pmbus_driver_info { int pages; /* Total number of pages */ u8 phases[PMBUS_PAGES]; /* Number of phases per page */ @@ -555,6 +562,8 @@ int pmbus_update_byte_data(struct i2c_client *client, i= nt page, u8 reg, void pmbus_clear_faults(struct i2c_client *client); bool pmbus_check_byte_register(struct i2c_client *client, int page, int re= g); bool pmbus_check_word_register(struct i2c_client *client, int page, int re= g); +void pmbus_wait(struct i2c_client *client); +void pmbus_update_ts(struct i2c_client *client, int op); int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *in= fo); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_c= ore.c index be6d05def115..4864a30988bf 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -32,13 +32,6 @@ #define PMBUS_ATTR_ALLOC_SIZE 32 #define PMBUS_NAME_SIZE 24 =20 -/* - * The type of operation used for picking the delay between - * successive pmbus operations. - */ -#define PMBUS_OP_WRITE BIT(0) -#define PMBUS_OP_PAGE_CHANGE BIT(1) - static int wp =3D -1; module_param(wp, int, 0444); =20 @@ -173,7 +166,7 @@ void pmbus_set_update(struct i2c_client *client, u8 reg= , bool update) EXPORT_SYMBOL_NS_GPL(pmbus_set_update, "PMBUS"); =20 /* Some chips need a delay between accesses. */ -static void pmbus_wait(struct i2c_client *client) +void pmbus_wait(struct i2c_client *client) { struct pmbus_data *data =3D i2c_get_clientdata(client); s64 delay =3D ktime_us_delta(data->next_access_backoff, ktime_get()); @@ -181,9 +174,10 @@ static void pmbus_wait(struct i2c_client *client) if (delay > 0) fsleep(delay); } +EXPORT_SYMBOL_NS_GPL(pmbus_wait, "PMBUS"); =20 /* Sets the last operation timestamp for pmbus_wait */ -static void pmbus_update_ts(struct i2c_client *client, int op) +void pmbus_update_ts(struct i2c_client *client, int op) { struct pmbus_data *data =3D i2c_get_clientdata(client); const struct pmbus_driver_info *info =3D data->info; @@ -197,6 +191,7 @@ static void pmbus_update_ts(struct i2c_client *client, = int op) if (delay > 0) data->next_access_backoff =3D ktime_add_us(ktime_get(), delay); } +EXPORT_SYMBOL_NS_GPL(pmbus_update_ts, "PMBUS"); =20 int pmbus_set_page(struct i2c_client *client, int page, int phase) { --=20 2.34.1 From nobody Thu Apr 9 12:50:36 2026 Received: from mail-dy1-f181.google.com (mail-dy1-f181.google.com [74.125.82.181]) (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 378AF22D7B5 for ; Mon, 9 Mar 2026 00:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773017189; cv=none; b=rA3XIJ2VwkzmWNoHlF7tgW79O+VEa9WqXBZ/p1IgngN6AIEdKivVHzpz8GVjn1srkx5abDoV6UWEaj2+D2BmkUVFtf/1WU4rLRMUM9koHr7Mm6Twt/M/WhS05HCgheAeQlfak3TeoIBdHUsuRvlKtYBuqVaXawCWSQt4uJnchnU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773017189; c=relaxed/simple; bh=X2q0K7KXeQr+i/EiogY7plkuwkb2uPhRevC2mCm6jRk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=G3T27GX0sVsqxX4mYzX5QhGdLMIOE2kNPmHvw7qsyROTTTLfXKB/aUAdtnU7XQOtU0TCvZrXu4BrjIiG68NDoDm+gjQ2cQ0Kqgi8ZZ2Rw6gS0oalXu2ML6g46j24KKbKtkLS75J2QsRqeJXuKIfUctO56BQ3XzJcMG2kACNIMPY= 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=KHhscEuc; arc=none smtp.client-ip=74.125.82.181 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KHhscEuc" Received: by mail-dy1-f181.google.com with SMTP id 5a478bee46e88-2be3bdfda8eso4129695eec.1 for ; Sun, 08 Mar 2026 17:46:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773017187; x=1773621987; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uY5sNjIhX7Zl6yY6urvp7Znt7FvylVOGJgh7rxozuas=; b=KHhscEucFjjyJINHbcDwbCLSs+nIt3WTaxe7jWOyz7Z4BkVcqA15Xb1xswHvrxXWSS BJAwXid0cdUGiJpz8pLcLFv0emQzWDFFkbUXtaMqQDUaJrnmRfeFFldgrplofRuGcxNt UE7zI8fEnhic+POHHd7STXjQlF8FzcXTo5kbI/mnYLUCxFLk6FTXP6uCASRoXPf8Rqik nFLV2X46PKajjBEkX5yJb1YhpnCbP6TguLlheHW3M98IONouzS5aUwcUiz8YBZyazkQf iyiNJbnrpAWb16tbbPiy31bA7wnOxPZrCX1EpialFcRYzu94x0ZZ31mSe2WGaIDgZM3/ E8/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773017187; x=1773621987; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=uY5sNjIhX7Zl6yY6urvp7Znt7FvylVOGJgh7rxozuas=; b=RyD5ohCbs913rBlTFTW2wTD0UnAtc3icAHINwuNapZ5kaQjmLTLhX4sXavcFqjuQMH F3Am9iHJ9HPQiyTOwPmwxqHkryFSsp1KnnW3H5Q6H9AQs/ppEjGXksvO7tnegIO11IuN JBCTCeWlg+bszYqnURvusze2xXoSsqSrR8uGgH7VXOkWA6hRseHVTOdmXxrS4uuy5yOf hnaOqi/g9bLv14ZAH4gE3+hn2JGqB+xBJBDbC77lmqO7G8TTNUQPlClRJCnRXWRN8VaA xePyKhHwgL08mREzoAGCall3CUQwdQMcJueiWIUFzf7N+ZARN+m2/9ToHkXSXpV+EA2Z ajUg== X-Forwarded-Encrypted: i=1; AJvYcCU8AU9jIk0xZDEBMYxyDohNL6rJ95g7lKsy500j+cD8RpqG1fwJT/kIiGCF3phaOq86rMFiTm//iB/8m44=@vger.kernel.org X-Gm-Message-State: AOJu0YxG+NGU9S1iE1RxDtTSECCwtl8J8w+1KfUwqCboW2XkmALTBJ7A OYx00zyU6khHMFtxa8+lfuF/lhcSRk+quxZx9VGF5pQ3XwUgJSaDjAJD X-Gm-Gg: ATEYQzxunO+j3qQUFIE1k01BPnJ30Vr8/xRrg7xmTOrZMlbR3Wa6WXAkgGF0OwmMNED lRb9/XJKgLu65rH2+eT8kw+3gqbee/837nFgVk8hS87TLy8IaHCjX/pfQE5qvTFkAc+Pg1nRMR5 L6Gi7oTQW9blsAISI4uyRbSd+zQbnq59Q0M47hj8xX3B5fv/pKfYLDb/rBt0paH2zDpUTJ7lWJH pTtKnHsBIx6xINU0+MK7UmhOxcrks5+x8c2eUYphq62BbQPUyq+R+pmkhWQwu9N5FjP0/tYoX/U D77q7zVsMQJ+qnaDKqGqgciq0W4hhezs5FvPlKkaH0813JE81S6eHju5tj1QEqo0Z4/rJlYCk/0 f4QuUgowCn2D/jpvVxG340nPQeKbIKsAyS47H7ii6KMB/VYSLBUCnbRzXaHcLPzeCycFvGGD1mO VQyD6Kk2bBf6Yrnu3S4BvUh8peh3HTNKrPjMcSo9iwEZ7aNVw1y4VBqoXlwFYurONgqfAqURO81 kTTglk= X-Received: by 2002:a05:7300:a10b:b0:2be:1779:3289 with SMTP id 5a478bee46e88-2be4e062b68mr3535871eec.35.1773017187276; Sun, 08 Mar 2026 17:46:27 -0700 (PDT) Received: from localhost.localdomain (c-67-164-93-214.hsd1.ca.comcast.net. [67.164.93.214]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2be4f948631sm7240105eec.19.2026.03.08.17.46.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 08 Mar 2026 17:46:26 -0700 (PDT) From: Sanman Pradhan To: Sanman Pradhan , Guenter Roeck Cc: Sanman Pradhan , linux-hwmon , linux-kernel Subject: [PATCH v2 2/2] hwmon: (pmbus/max31785) use access_delay for PMBus-mediated accesses Date: Sun, 8 Mar 2026 17:45:08 -0700 Message-Id: <20260309004508.78609-3-sanman.p211993@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260309004508.78609-1-sanman.p211993@gmail.com> References: <20260309004508.78609-1-sanman.p211993@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sanman Pradhan The MAX31785 fan controller occasionally NACKs master transactions if accesses are too tightly spaced. To avoid this, the driver currently enforces a 250us inter-access delay with a private timestamp and wrapper functions around both raw SMBus accesses and PMBus helper paths. Simplify the driver by using pmbus_driver_info.access_delay for normal PMBus-mediated accesses instead, and remove the driver-local PMBus read/write wrappers. Keep local delay handling for raw SMBus accesses used before pmbus_do_probe(). For the raw i2c_transfer() long-read path, which bypasses PMBus core timing, leverage the newly exported pmbus_wait() and pmbus_update_ts() core functions. This replaces hardcoded usleep_range() calls and ensures the PMBus core tracks the raw transaction. Placing pmbus_update_ts() before the error check fixes a bug where a failed i2c_transfer() would skip the delay and impact subsequent PMBus commands. Additionally, update max31785_read_byte_data() so PMBUS_FAN_CONFIG_12 accesses are only remapped for virtual pages, allowing physical-page accesses to fall back to the PMBus core. With that change, we can safely drop the custom max31785_update_fan() wrapper in favor of the core pmbus_update_fan() helper. Also use the delayed raw read helper for MFR_REVISION during probe, drop the unused to_max31785_data() macro, and rename the local variable "virtual" to "vpage". Signed-off-by: Sanman Pradhan --- drivers/hwmon/pmbus/max31785.c | 187 +++++++++++---------------------- 1 file changed, 59 insertions(+), 128 deletions(-) diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 50073fe0c5e8..098f43486c45 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -31,8 +31,6 @@ struct max31785_data { struct pmbus_driver_info info; }; =20 -#define to_max31785_data(x) container_of(x, struct max31785_data, info) - /* * MAX31785 Driver Workaround * @@ -40,9 +38,8 @@ struct max31785_data { * These issues are not indicated by the device itself, except for occasio= nal * NACK responses during master transactions. No error bits are set in STA= TUS_BYTE. * - * To address this, we introduce a delay of 250us between consecutive acce= sses - * to the fan controller. This delay helps mitigate communication problems= by - * allowing sufficient time between accesses. + * Keep minimal local delay handling for raw pre-probe SMBus accesses. + * Normal PMBus-mediated accesses use pmbus_driver_info.access_delay inste= ad. */ static inline void max31785_wait(const struct max31785_data *data) { @@ -54,89 +51,42 @@ static inline void max31785_wait(const struct max31785_= data *data) } =20 static int max31785_i2c_write_byte_data(struct i2c_client *client, - struct max31785_data *driver_data, - int command, u8 data) + struct max31785_data *data, + int command, u8 value) { int rc; =20 - max31785_wait(driver_data); - rc =3D i2c_smbus_write_byte_data(client, command, data); - driver_data->access =3D ktime_get(); + max31785_wait(data); + rc =3D i2c_smbus_write_byte_data(client, command, value); + data->access =3D ktime_get(); return rc; } =20 static int max31785_i2c_read_word_data(struct i2c_client *client, - struct max31785_data *driver_data, + struct max31785_data *data, int command) { int rc; =20 - max31785_wait(driver_data); + max31785_wait(data); rc =3D i2c_smbus_read_word_data(client, command); - driver_data->access =3D ktime_get(); - return rc; -} - -static int _max31785_read_byte_data(struct i2c_client *client, - struct max31785_data *driver_data, - int page, int command) -{ - int rc; - - max31785_wait(driver_data); - rc =3D pmbus_read_byte_data(client, page, command); - driver_data->access =3D ktime_get(); - return rc; -} - -static int _max31785_write_byte_data(struct i2c_client *client, - struct max31785_data *driver_data, - int page, int command, u16 data) -{ - int rc; - - max31785_wait(driver_data); - rc =3D pmbus_write_byte_data(client, page, command, data); - driver_data->access =3D ktime_get(); - return rc; -} - -static int _max31785_read_word_data(struct i2c_client *client, - struct max31785_data *driver_data, - int page, int phase, int command) -{ - int rc; - - max31785_wait(driver_data); - rc =3D pmbus_read_word_data(client, page, phase, command); - driver_data->access =3D ktime_get(); - return rc; -} - -static int _max31785_write_word_data(struct i2c_client *client, - struct max31785_data *driver_data, - int page, int command, u16 data) -{ - int rc; - - max31785_wait(driver_data); - rc =3D pmbus_write_word_data(client, page, command, data); - driver_data->access =3D ktime_get(); + data->access =3D ktime_get(); return rc; } =20 static int max31785_read_byte_data(struct i2c_client *client, int page, in= t reg) { - const struct pmbus_driver_info *info =3D pmbus_get_driver_info(client); - struct max31785_data *driver_data =3D to_max31785_data(info); =20 switch (reg) { case PMBUS_VOUT_MODE: return -ENOTSUPP; case PMBUS_FAN_CONFIG_12: - return _max31785_read_byte_data(client, driver_data, - page - MAX31785_NR_PAGES, - reg); + if (page < MAX31785_NR_PAGES) + return -ENODATA; + + return pmbus_read_byte_data(client, + page - MAX31785_NR_PAGES, + reg); } =20 return -ENODATA; @@ -178,7 +128,20 @@ static int max31785_read_long_data(struct i2c_client *= client, int page, if (rc < 0) return rc; =20 + /* Ensure the raw transfer is properly spaced from the + * preceding PMBus transaction. + */ + pmbus_wait(client); + rc =3D i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + + /* + * Update PMBus core timing state for the raw transfer, even on error. + * Pass 0 as the operation mask since this is a raw read, intentionally + * neither PMBUS_OP_WRITE nor PMBUS_OP_PAGE_CHANGE. + */ + pmbus_update_ts(client, 0); + if (rc < 0) return rc; =20 @@ -203,19 +166,18 @@ static int max31785_get_pwm(struct i2c_client *client= , int page) return rv; } =20 -static int max31785_get_pwm_mode(struct i2c_client *client, - struct max31785_data *driver_data, int page) +static int max31785_get_pwm_mode(struct i2c_client *client, int page) { int config; int command; =20 - config =3D _max31785_read_byte_data(client, driver_data, page, - PMBUS_FAN_CONFIG_12); + config =3D pmbus_read_byte_data(client, page, + PMBUS_FAN_CONFIG_12); if (config < 0) return config; =20 - command =3D _max31785_read_word_data(client, driver_data, page, 0xff, - PMBUS_FAN_COMMAND_1); + command =3D pmbus_read_word_data(client, page, 0xff, + PMBUS_FAN_COMMAND_1); if (command < 0) return command; =20 @@ -233,8 +195,6 @@ static int max31785_get_pwm_mode(struct i2c_client *cli= ent, static int max31785_read_word_data(struct i2c_client *client, int page, int phase, int reg) { - const struct pmbus_driver_info *info =3D pmbus_get_driver_info(client); - struct max31785_data *driver_data =3D to_max31785_data(info); u32 val; int rv; =20 @@ -263,7 +223,7 @@ static int max31785_read_word_data(struct i2c_client *c= lient, int page, rv =3D max31785_get_pwm(client, page); break; case PMBUS_VIRT_PWM_ENABLE_1: - rv =3D max31785_get_pwm_mode(client, driver_data, page); + rv =3D max31785_get_pwm_mode(client, page); break; default: rv =3D -ENODATA; @@ -294,35 +254,7 @@ static inline u32 max31785_scale_pwm(u32 sensor_val) return (sensor_val * 100) / 255; } =20 -static int max31785_update_fan(struct i2c_client *client, - struct max31785_data *driver_data, int page, - u8 config, u8 mask, u16 command) -{ - int from, rv; - u8 to; - - from =3D _max31785_read_byte_data(client, driver_data, page, - PMBUS_FAN_CONFIG_12); - if (from < 0) - return from; - - to =3D (from & ~mask) | (config & mask); - - if (to !=3D from) { - rv =3D _max31785_write_byte_data(client, driver_data, page, - PMBUS_FAN_CONFIG_12, to); - if (rv < 0) - return rv; - } - - rv =3D _max31785_write_word_data(client, driver_data, page, - PMBUS_FAN_COMMAND_1, command); - - return rv; -} - -static int max31785_pwm_enable(struct i2c_client *client, - struct max31785_data *driver_data, int page, +static int max31785_pwm_enable(struct i2c_client *client, int page, u16 word) { int config =3D 0; @@ -351,23 +283,21 @@ static int max31785_pwm_enable(struct i2c_client *cli= ent, return -EINVAL; } =20 - return max31785_update_fan(client, driver_data, page, config, + return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate); } =20 static int max31785_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { - const struct pmbus_driver_info *info =3D pmbus_get_driver_info(client); - struct max31785_data *driver_data =3D to_max31785_data(info); =20 switch (reg) { case PMBUS_VIRT_PWM_1: - return max31785_update_fan(client, driver_data, page, 0, - PB_FAN_1_RPM, - max31785_scale_pwm(word)); + return pmbus_update_fan(client, page, 0, 0, + PB_FAN_1_RPM, + max31785_scale_pwm(word)); case PMBUS_VIRT_PWM_ENABLE_1: - return max31785_pwm_enable(client, driver_data, page, word); + return max31785_pwm_enable(client, page, word); default: break; } @@ -391,6 +321,7 @@ static const struct pmbus_driver_info max31785_info =3D= { .read_byte_data =3D max31785_read_byte_data, .read_word_data =3D max31785_read_word_data, .write_byte =3D max31785_write_byte, + .access_delay =3D MAX31785_WAIT_DELAY_US, =20 /* RPM */ .format[PSC_FAN] =3D direct, @@ -438,29 +369,29 @@ static const struct pmbus_driver_info max31785_info = =3D { }; =20 static int max31785_configure_dual_tach(struct i2c_client *client, - struct pmbus_driver_info *info) + struct max31785_data *data) { + struct pmbus_driver_info *info =3D &data->info; int ret; int i; - struct max31785_data *driver_data =3D to_max31785_data(info); =20 for (i =3D 0; i < MAX31785_NR_FAN_PAGES; i++) { - ret =3D max31785_i2c_write_byte_data(client, driver_data, + ret =3D max31785_i2c_write_byte_data(client, data, PMBUS_PAGE, i); if (ret < 0) return ret; =20 - ret =3D max31785_i2c_read_word_data(client, driver_data, + ret =3D max31785_i2c_read_word_data(client, data, MFR_FAN_CONFIG); if (ret < 0) return ret; =20 if (ret & MFR_FAN_CONFIG_DUAL_TACH) { - int virtual =3D MAX31785_NR_PAGES + i; + int vpage =3D MAX31785_NR_PAGES + i; =20 - info->pages =3D virtual + 1; - info->func[virtual] |=3D PMBUS_HAVE_FAN12; - info->func[virtual] |=3D PMBUS_PAGE_VIRTUAL; + info->pages =3D vpage + 1; + info->func[vpage] |=3D PMBUS_HAVE_FAN12; + info->func[vpage] |=3D PMBUS_PAGE_VIRTUAL; } } =20 @@ -471,7 +402,7 @@ static int max31785_probe(struct i2c_client *client) { struct device *dev =3D &client->dev; struct pmbus_driver_info *info; - struct max31785_data *driver_data; + struct max31785_data *data; bool dual_tach =3D false; int ret; =20 @@ -480,20 +411,20 @@ static int max31785_probe(struct i2c_client *client) I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; =20 - driver_data =3D devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNE= L); - if (!driver_data) + data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; =20 - info =3D &driver_data->info; - driver_data->access =3D ktime_get(); + data->access =3D ktime_get(); + info =3D &data->info; *info =3D max31785_info; =20 - ret =3D max31785_i2c_write_byte_data(client, driver_data, - PMBUS_PAGE, 255); + ret =3D max31785_i2c_write_byte_data(client, data, + PMBUS_PAGE, 0xff); if (ret < 0) return ret; =20 - ret =3D i2c_smbus_read_word_data(client, MFR_REVISION); + ret =3D max31785_i2c_read_word_data(client, data, MFR_REVISION); if (ret < 0) return ret; =20 @@ -509,7 +440,7 @@ static int max31785_probe(struct i2c_client *client) } =20 if (dual_tach) { - ret =3D max31785_configure_dual_tach(client, info); + ret =3D max31785_configure_dual_tach(client, data); if (ret < 0) return ret; } --=20 2.34.1