From: <Victor.Duicu@microchip.com>
To: <linux@roeck-us.net>, <robh@kernel.org>, <krzk+dt@kernel.org>,
<conor+dt@kernel.org>, <corbet@lwn.net>
Cc: <Marius.Cristea@microchip.com>, <linux-hwmon@vger.kernel.org>,
<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linux-doc@vger.kernel.org>
Subject: Re: [PATCH v3 2/2] hwmon: add support for MCP998X
Date: Mon, 2 Feb 2026 08:15:55 +0000 [thread overview]
Message-ID: <da5b2f992a430d30efb558502aec7dc6f6769b0d.camel@microchip.com> (raw)
In-Reply-To: <491bd9ec-d6b7-4f1a-877b-67ffbc658ba8@roeck-us.net>
Hi Guenter,
> > +static int mcp9982_read_limit(struct mcp9982_priv *priv, u8
> > address, long *val)
> > +{
> > + unsigned int limit, reg_high, reg_low;
> > + int ret;
> > +
> > + switch (address) {
> > + case MCP9982_INTERNAL_HIGH_LIMIT_ADDR:
> > + case MCP9982_INTERNAL_LOW_LIMIT_ADDR:
> > + case MCP9982_THERM_LIMIT_ADDR(0):
> > + case MCP9982_THERM_LIMIT_ADDR(1):
> > + case MCP9982_THERM_LIMIT_ADDR(2):
> > + case MCP9982_THERM_LIMIT_ADDR(3):
> > + case MCP9982_THERM_LIMIT_ADDR(4):
> > + ret = regmap_read(priv->regmap, address, &limit);
> > + if (ret)
> > + return ret;
> > +
> > + *val = limit & 0xFF;
> > + *val = (*val - MCP9982_OFFSET) * 1000;
> > +
> > + return 0;
> > + case MCP9982_EXT_HIGH_LIMIT_ADDR(1):
> > + case MCP9982_EXT_HIGH_LIMIT_ADDR(2):
> > + case MCP9982_EXT_HIGH_LIMIT_ADDR(3):
> > + case MCP9982_EXT_HIGH_LIMIT_ADDR(4):
> > + case MCP9982_EXT_LOW_LIMIT_ADDR(1):
> > + case MCP9982_EXT_LOW_LIMIT_ADDR(2):
> > + case MCP9982_EXT_LOW_LIMIT_ADDR(3):
> > + case MCP9982_EXT_LOW_LIMIT_ADDR(4):
> > + /*
> > + * The register address determines whether a single
> > byte or
> > + * multiple byte (block) operation is run. For a
> > single byte
> > + * operation, the MSB of the register address is set
> > to "0".
> > + * For a multiple byte operation, it is set to "1".
> > The addresses
> > + * quoted in the register map and throughout the data
> > sheet assume
> > + * single byte operation. For multiple byte
> > operations, the user
> > + * must set the MSB of each register address to "1".
> > + */
> > + ret = regmap_read(priv->regmap, address, ®_high);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_read(priv->regmap, address + 1,
> > ®_low);
> > + if (ret)
> > + return ret;
> > +
> Consider using regmap_bulk_read().
The MCP998X family is designed so that block reading is allowed only
on the dedicated temperature and memory blocks. Reading from
those memory areas uses the SMBus protocol, which returns count
and the data. From any other memory region, reading only one byte
is allowed. This behavior is described in the documentation at page 26.
In V2 patch, block reading was used in this function, however this
was an exploit. After reading one byte the chip returns NACK to finish
the read, that will force the Linux driver to issue another 1 byte read
for the second byte, which will return the value and stop.
For the addresses 0x00 to 0x09 (temperature registers) the chip will
not return NACK after the first byte, it will just go to sleep and
return invalid data 0xff. That was a design choice to be backwards
compatible with older parts.
...
> >
> > + switch (attr) {
> > + case hwmon_temp_input:
> > + /*
> > + * The chips support block reading only on
> > the temperature and
> > + * status memory blocks. The driver uses only
> > individual read commands.
> > + */
> > + ret = regmap_read(priv->regmap,
> > MCP9982_HIGH_BYTE_ADDR(channel), ®_high);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_read(priv->regmap,
> > MCP9982_HIGH_BYTE_ADDR(channel) + 1,
> > + ®_low);
> > + if (ret)
> > + return ret;
> > +
>
> Consider using regmap_bulk_read().
In V2 patch, block reading was used to read the temperatures from the
dedicated memory. However, the operation would use SMBus protocol
and return count alongside the data.
Regmap_bulk_read() in this context uses SMBus protocol, while in the
context of reading the temperature limits uses I2C protocol(and is an
invalid request).
In order to avoid having one function with multiple behaviors and
to keep the driver more generic all block reads were removed.
> > + *val = ((reg_high << 8) + reg_low) >> 5;
> > + *val = (*val - (MCP9982_OFFSET << 3)) * 125;
> > +
> > + return 0;
> > + case hwmon_temp_max:
> > + if (channel)
> > + addr =
> > MCP9982_EXT_HIGH_LIMIT_ADDR(channel);
> > + else
> > + addr =
> > MCP9982_INTERNAL_HIGH_LIMIT_ADDR;
> > +
> > + return mcp9982_read_limit(priv, addr, val);
> > + case hwmon_temp_max_alarm:
> > + *val = regmap_test_bits(priv->regmap,
> > MCP9982_HIGH_LIMIT_STATUS_ADDR,
> > + BIT(channel));
> > + if (*val < 0)
> > + return *val;
> > +
> > + return 0;
> > + case hwmon_temp_max_hyst:
> > + if (channel)
> > + addr =
> > MCP9982_EXT_HIGH_LIMIT_ADDR(channel);
> > + else
> > + addr =
> > MCP9982_INTERNAL_HIGH_LIMIT_ADDR;
> > + ret = mcp9982_read_limit(priv, addr, val);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_read(priv->regmap,
> > MCP9982_HYS_ADDR, &hyst);
> > + if (ret)
> > + return ret;
> > +
> > + *val -= (hyst & 0xFF) * 1000;
>
> What is the mask for ? The chip registers are 8 bit wide.
>
> > + *val = clamp_val(*val, -64000, 191875);
>
> Clamping on reads is highly unusual. Why is this needed ?
There are instances when the hysteresis limit could be outside
the range of temperatures.
For example, if the high limit is set to -45000 and the hysteresis
is set to 20000, the high limit hysteresis is -65000 which is outside
the range of supported temperatures.
The hysteresis is set related to the critical temperature (that is
higher then the "high limit") but it will be applied also to the "high
temperature". In this case the hysteresis is valid for critical but it
will be out of range for the "high temp".
>
next prev parent reply other threads:[~2026-02-02 8:15 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-27 15:18 [PATCH v3 0/2] add support in hwmon for MCP998X victor.duicu
2026-01-27 15:18 ` [PATCH v3 1/2] dt-bindings: hwmon: add support " victor.duicu
2026-02-03 19:15 ` Guenter Roeck
2026-02-06 14:17 ` Victor.Duicu
2026-02-06 16:49 ` Krzysztof Kozlowski
2026-02-06 16:51 ` Krzysztof Kozlowski
2026-02-06 16:47 ` Krzysztof Kozlowski
2026-02-09 14:46 ` Victor.Duicu
2026-01-27 15:18 ` [PATCH v3 2/2] " victor.duicu
2026-01-27 18:51 ` Guenter Roeck
2026-02-02 8:15 ` Victor.Duicu [this message]
2026-02-02 15:18 ` Guenter Roeck
2026-02-03 13:31 ` Victor.Duicu
2026-01-27 22:23 ` kernel test robot
2026-02-03 19:45 ` Guenter Roeck
2026-02-03 20:09 ` Guenter Roeck
2026-02-03 20:45 ` Guenter Roeck
2026-02-06 16:55 ` [PATCH v3 0/2] add support in hwmon " Krzysztof Kozlowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=da5b2f992a430d30efb558502aec7dc6f6769b0d.camel@microchip.com \
--to=victor.duicu@microchip.com \
--cc=Marius.Cristea@microchip.com \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox