From nobody Tue Nov 11 13:08:35 2025 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A87D02FE048; Tue, 11 Nov 2025 08:06:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762848418; cv=none; b=VfOZlK0yYa83BkWxaN40Ri4FkSGQU0PdXiVLYdVPTkGZHudiQ568mcLRF0AXVBN/mH+AW7scqAXhvmHGR3sQclosqSRAEIVT2DPT948P32YrCwDn2DouPdzoVt1qvB7Wwt0OoQgIYgn7iyju1oWN05nJEM7HuZgUmMypAs2v6TY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762848418; c=relaxed/simple; bh=/CQD0JuXmJsLneSrO8cvd0Zi3WkiFrrhr9la3zE8qpE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=SF88ydUY4tlJ9QKEiNk9HxjODEj+Co1hAj9xpwrvklDD/HXCQKvMK3zjBHfCpPBlDDcsnsfH7ahPvOBwlGHoIP2Qc3hFqYKkHSdk0M7Ay7JKXE2H1DfGensNubbVyot6gIZHIz3HwxF6/KHjtbFUH0HduT9oaIthafZzw1+xPBg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=BhF6FnYV; arc=none smtp.client-ip=220.197.31.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="BhF6FnYV" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-Id; bh=uIk9YEbVqKa78zM 3O+6rXPgrFM9bXFI0U3T7LjIm8UI=; b=BhF6FnYV4oz1h5x59flWJGMnZkNRABG UN53Z4JYCLJ4gzD0Ggq+al9i9o7sXm2NoYZMX8+i7U1fVg4sARPqLbidIFBgvaxf H4sfX1/DkIB0FN2ccjrx0/85Y7XioLKbxI47tiFhUu9xE8L41NU6CCT+xJ/Pxo22 V9rhWdGfGv40= Received: from localhost.localdomain (unknown []) by gzga-smtp-mtada-g1-4 (Coremail) with SMTP id _____wCnq6ln7hJpK0KCDA--.117S8; Tue, 11 Nov 2025 16:06:14 +0800 (CST) From: Wenliang Yan To: linux@roeck-us.net, Jean Delvare Cc: christophe.jaillet@wanadoo.fr, conor+dt@kernel.org, corbet@lwn.net, devicetree@vger.kernel.org, krzk+dt@kernel.org, linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, robh@kernel.org, wenliang202407@163.com Subject: [PATCH 6/8] hwmon:(ina3221)Modify read/write functions for 'in' attribute Date: Tue, 11 Nov 2025 03:05:44 -0500 Message-Id: <20251111080546.32421-7-wenliang202407@163.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20251111080546.32421-1-wenliang202407@163.com> References: <20251111080546.32421-1-wenliang202407@163.com> X-CM-TRANSID: _____wCnq6ln7hJpK0KCDA--.117S8 X-Coremail-Antispam: 1Uf129KBjvJXoW3ArW3tr1DtrW5Cr45ArW5ZFb_yoW3ZryUp3 yfCFWrtr17tr1S9rs7KFs5Gr1FyrZ7W3y2yr9rK3sava1UAFyku348Ja9Yvry5CryfXan2 q3y7AFyUCanrJFUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x0JUX0ePUUUUU= X-CM-SenderInfo: xzhqzxhdqjjiisuqlqqrwthudrp/xtbCvxa3i2kS7nZY9wAA3Z Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" SQ52210 adds current, power, and alert-limit sensors, with read/write functions modified to accommodate these new changes. The ina3221_read_value function has been rewritten to adapt to the new register format for data reading. The sq52210_alert_to_reg function has been added to handle reading of different data types. Each channel supports four new alert trigger modes, with only one trigger active at any given time. Alert values are stored in the same register. The sq52210_alert_limit_write function has been implemented for writing alert threshold values. The 'in' read/write functions have been modified to add crit, lcrit, crit_alarm, and lcrit_alarm characteristics. Signed-off-by: Wenliang Yan --- drivers/hwmon/ina3221.c | 182 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 77b2505a49a2..abb6049c8eab 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -66,6 +66,9 @@ #define INA3221_MASK_ENABLE_SCC_MASK GENMASK(14, 12) =20 #define SQ52210_ALERT_CONFIG_MASK GENMASK(15, 4) +#define SQ52210_MASK_ALERT_CHANNEL1 (BIT(15) | BIT(12) | BIT(9) | BIT(6)) +#define SQ52210_MASK_ALERT_CHANNEL2 (BIT(14) | BIT(11) | BIT(8) | BIT(5)) +#define SQ52210_MASK_ALERT_CHANNEL3 (BIT(13) | BIT(10) | BIT(7) | BIT(4)) =20 #define INA3221_CONFIG_DEFAULT 0x7127 #define INA3221_RSHUNT_DEFAULT 10000 @@ -84,6 +87,9 @@ enum ina3221_fields { /* Alert Flags: SF is the summation-alert flag */ F_SF, F_CF3, F_CF2, F_CF1, =20 + /* Alert Flags: AFF is the alert function flag */ + F_AFF3, F_AFF2, F_AFF1, + /* sentinel */ F_MAX_FIELDS }; @@ -99,6 +105,10 @@ static const struct reg_field ina3221_reg_fields[] =3D { [F_CF3] =3D REG_FIELD(INA3221_MASK_ENABLE, 7, 7), [F_CF2] =3D REG_FIELD(INA3221_MASK_ENABLE, 8, 8), [F_CF1] =3D REG_FIELD(INA3221_MASK_ENABLE, 9, 9), + + [F_AFF3] =3D REG_FIELD(SQ52210_ALERT_CONFIG, 1, 1), + [F_AFF2] =3D REG_FIELD(SQ52210_ALERT_CONFIG, 2, 2), + [F_AFF1] =3D REG_FIELD(SQ52210_ALERT_CONFIG, 3, 3), }; =20 enum ina3221_channels { @@ -293,11 +303,39 @@ static int ina3221_read_value(struct ina3221_data *in= a, unsigned int reg, * Shunt Voltage Sum register has 14-bit value with 1-bit shift * Other Shunt Voltage registers have 12 bits with 3-bit shift */ - if (reg =3D=3D INA3221_SHUNT_SUM || reg =3D=3D INA3221_CRIT_SUM) + switch (reg) { + case INA3221_SHUNT_SUM: + case INA3221_CRIT_SUM: *val =3D sign_extend32(regval >> 1, 14); - else + break; + case SQ52210_CURRENT1: + case SQ52210_CURRENT2: + case SQ52210_CURRENT3: + case SQ52210_POWER1: + case SQ52210_POWER2: + case SQ52210_POWER3: + *val =3D regval; + break; + case INA3221_BUS1: + case INA3221_BUS2: + case INA3221_BUS3: + case INA3221_SHUNT1: + case INA3221_SHUNT2: + case INA3221_SHUNT3: + case INA3221_WARN1: + case INA3221_WARN2: + case INA3221_WARN3: + case INA3221_CRIT1: + case INA3221_CRIT2: + case INA3221_CRIT3: *val =3D sign_extend32(regval >> 3, 12); - + break; + case SQ52210_ALERT_LIMIT1: + case SQ52210_ALERT_LIMIT2: + case SQ52210_ALERT_LIMIT3: + *val =3D regval >> 3; + break; + }; return 0; } =20 @@ -311,6 +349,56 @@ static const u8 ina3221_in_reg[] =3D { INA3221_SHUNT_SUM, }; =20 +static const u8 alert_limit_reg[] =3D { + SQ52210_ALERT_LIMIT1, + SQ52210_ALERT_LIMIT2, + SQ52210_ALERT_LIMIT3, +}; + +static const u8 alert_flag[] =3D { + F_AFF1, + F_AFF2, + F_AFF3, +}; + +/* + * Turns alert limit values into register values. + * Opposite of the formula in ina3221_read_value(). + */ +static u16 sq52210_alert_to_reg(struct ina3221_data *ina, int reg, long va= l) +{ + int regval; + /* + * Formula to convert voltage_uv to register value: + * regval =3D (voltage_mv / scale) << shift + * Results: + * bus_voltage: (1 / 8mV) << 3 =3D 1 mV + */ + switch (reg) { + case INA3221_BUS1: + case INA3221_BUS2: + case INA3221_BUS3: + /* clamp voltage */ + regval =3D clamp_val(val, -32760, 32760); + return regval; + case SQ52210_CURRENT1: + case SQ52210_CURRENT2: + case SQ52210_CURRENT3: + /* signed register, result in mA */ + regval =3D DIV_ROUND_CLOSEST(val * 8000, ina->current_lsb_uA); + return clamp_val(regval, -32760, 32760); + case SQ52210_POWER1: + case SQ52210_POWER2: + case SQ52210_POWER3: + regval =3D DIV_ROUND_CLOSEST(val * 8000, ina->power_lsb_uW); + return clamp_val(regval, 0, 65528); + default: + /* programmer goofed */ + WARN_ON_ONCE(1); + return 0; + } +} + static int ina3221_read_chip(struct device *dev, u32 attr, long *val) { struct ina3221_data *ina =3D dev_get_drvdata(dev); @@ -373,6 +461,25 @@ static int ina3221_read_in(struct device *dev, u32 att= r, int channel, long *val) case hwmon_in_enable: *val =3D ina3221_is_enabled(ina, channel); return 0; + case hwmon_in_crit: + case hwmon_in_lcrit: + reg =3D alert_limit_reg[channel]; + ret =3D ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + /* + * Scale of bus voltage (mV): LSB is 8mV + */ + *val =3D regval * 8; + return 0; + case hwmon_in_crit_alarm: + case hwmon_in_lcrit_alarm: + reg =3D alert_flag[channel]; + ret =3D regmap_field_read(ina->fields[reg], ®val); + if (ret) + return ret; + *val =3D regval; + return 0; default: return -EOPNOTSUPP; } @@ -450,6 +557,58 @@ static int ina3221_read_curr(struct device *dev, u32 a= ttr, } } =20 +static const u32 sq52210_alert_mask[][INA3221_NUM_CHANNELS] =3D { + [hwmon_curr_lcrit] =3D { BIT(15), BIT(14), BIT(13) }, + [hwmon_in_crit] =3D { BIT(12), BIT(11), BIT(10) }, + [hwmon_in_lcrit] =3D { BIT(9), BIT(8), BIT(7) }, + [hwmon_power_crit] =3D { BIT(6), BIT(5), BIT(4) }, +}; + +static int sq52210_alert_limit_write(struct ina3221_data *ina, u32 attr, i= nt channel, long val) +{ + struct regmap *regmap =3D ina->regmap; + int ret, limit_reg, item; + u32 alert_group; + + if (val < 0) + return -EINVAL; + item =3D channel % INA3221_NUM_CHANNELS; + switch (item) { + case 0: + alert_group =3D SQ52210_MASK_ALERT_CHANNEL1; + limit_reg =3D SQ52210_ALERT_LIMIT1; + break; + case 1: + alert_group =3D SQ52210_MASK_ALERT_CHANNEL2; + limit_reg =3D SQ52210_ALERT_LIMIT2; + break; + case 2: + alert_group =3D SQ52210_MASK_ALERT_CHANNEL3; + limit_reg =3D SQ52210_ALERT_LIMIT3; + break; + default: + break; + } + /* + * Clear all alerts first to avoid accidentally triggering ALERT pin + * due to register write sequence. Then, only enable the alert + * if the value is non-zero. + */ + ret =3D regmap_update_bits(regmap, SQ52210_ALERT_CONFIG, + alert_group, 0); + if (ret < 0) + return ret; + ret =3D regmap_write(regmap, limit_reg, + sq52210_alert_to_reg(ina, ina3221_curr_reg[attr][item], val)); + if (ret < 0) + return ret; + + if (val) + return regmap_update_bits(regmap, SQ52210_ALERT_CONFIG, + alert_group, sq52210_alert_mask[attr][item]); + return 0; +} + static int ina3221_write_chip(struct device *dev, u32 attr, long val) { struct ina3221_data *ina =3D dev_get_drvdata(dev); @@ -586,6 +745,21 @@ static int ina3221_write_enable(struct device *dev, in= t channel, bool enable) return ret; } =20 +static int ina3221_write_in(struct device *dev, u32 attr, int channel, lon= g val) +{ + struct ina3221_data *ina =3D dev_get_drvdata(dev); + + switch (attr) { + case hwmon_in_lcrit: + return sq52210_alert_limit_write(ina, attr, channel, val); + case hwmon_in_crit: + return sq52210_alert_limit_write(ina, attr, channel, val); + case hwmon_in_enable: + return ina3221_write_enable(dev, channel, val); + default: + return 0; + } +} static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -620,7 +794,7 @@ static int ina3221_write(struct device *dev, enum hwmon= _sensor_types type, break; case hwmon_in: /* 0-align channel ID */ - ret =3D ina3221_write_enable(dev, channel - 1, val); + ret =3D ina3221_write_in(dev, attr, channel - 1, val); break; case hwmon_curr: ret =3D ina3221_write_curr(dev, attr, channel, val); --=20 2.17.1