All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexandru Ardelean <alexandru.ardelean@analog.com>
To: <linux-hwmon@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>
Cc: <robh+dt@kernel.org>, <linux@roeck-us.net>, <jdelvare@suse.com>,
	<mark.thoren@analog.com>, <ardeleanalex@gmail.com>,
	Alexandru Ardelean <alexandru.ardelean@analog.com>
Subject: [PATCH v3 3/4] hwmon: (ltc2945): add support for sense resistor
Date: Thu, 7 Jan 2021 12:34:16 +0200	[thread overview]
Message-ID: <20210107103417.16010-4-alexandru.ardelean@analog.com> (raw)
In-Reply-To: <20210107103417.16010-1-alexandru.ardelean@analog.com>

The sense resistor is a parameter of the board. It should be configured in
the driver via a device-tree / ACPI property, so that the proper current
measurements can be done in the driver.

It shouldn't be necessary that userspace need to know about the value of
the resistor. It makes things a bit harder to make the application code
portable from one board to another.

This change implements support for the sense resistor to be configured from
DT/ACPI and used in current calculations.
Also, the maximum power and current that can be represented by the driver
are scaled with the value of the sense resistor.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
 drivers/hwmon/ltc2945.c | 60 ++++++++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
index 41df2c8b7673..e60b15832b0e 100644
--- a/drivers/hwmon/ltc2945.c
+++ b/drivers/hwmon/ltc2945.c
@@ -70,9 +70,15 @@
 /**
  * struct ltc2945_state - driver instance specific data
  * @regmap:		regmap object to access device registers
+ * @max_power_uw:	maximum power that can be represented based on sense resistor
+ * @max_current_ma:	maximum current that can be represented based on sense resistor
+ * @r_sense_mohm:	current sense resistor value
  */
 struct ltc2945_state {
 	struct regmap		*regmap;
+	u32			max_power_uw;
+	u32			max_current_ma;
+	u32			r_sense_mohm;
 };
 
 static inline bool is_power_reg(u8 reg)
@@ -110,9 +116,8 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
 	case LTC2945_MAX_POWER_THRES_H:
 	case LTC2945_MIN_POWER_THRES_H:
 		/*
-		 * Convert to uW by assuming current is measured with
-		 * an 1mOhm sense resistor, similar to current
-		 * measurements.
+		 * Convert to uW by and scale it with the configured
+		 * sense resistor, similar to current measurements.
 		 * Control register bit 0 selects if voltage at SENSE+/VDD
 		 * or voltage at ADIN is used to measure power.
 		 */
@@ -126,6 +131,7 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
 			/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
 			val = (val * 25LL) >> 1;
 		}
+		val /= st->r_sense_mohm;
 		break;
 	case LTC2945_VIN_H:
 	case LTC2945_MAX_VIN_H:
@@ -149,13 +155,11 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
 	case LTC2945_MAX_SENSE_THRES_H:
 	case LTC2945_MIN_SENSE_THRES_H:
 		/*
-		 * 25 uV resolution. Convert to current as measured with
-		 * an 1 mOhm sense resistor, in mA. If a different sense
-		 * resistor is installed, calculate the actual current by
-		 * dividing the reported current by the sense resistor value
-		 * in mOhm.
+		 * 25 uV resolution. Convert to current and scale it
+		 * with the value of the sense resistor.
 		 */
 		val *= 25;
+		val /= st->r_sense_mohm;
 		break;
 	default:
 		return -EINVAL;
@@ -163,7 +167,8 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
 	return val;
 }
 
-static unsigned long ltc2945_val_clamp(u8 reg, unsigned long val)
+static unsigned long ltc2945_val_clamp(struct ltc2945_state *st, u8 reg,
+				       unsigned long val)
 {
 	switch (reg) {
 	case LTC2945_POWER_H:
@@ -171,8 +176,7 @@ static unsigned long ltc2945_val_clamp(u8 reg, unsigned long val)
 	case LTC2945_MIN_POWER_H:
 	case LTC2945_MAX_POWER_THRES_H:
 	case LTC2945_MIN_POWER_THRES_H:
-		/* No sense in clamping now, LTC2945_POWER_FULL_SCALE_UW is larger than UINT32_MAX */
-		return val;
+		return clamp_val(val, 0, st->max_power_uw);
 	case LTC2945_VIN_H:
 	case LTC2945_MAX_VIN_H:
 	case LTC2945_MIN_VIN_H:
@@ -190,7 +194,7 @@ static unsigned long ltc2945_val_clamp(u8 reg, unsigned long val)
 	case LTC2945_MIN_SENSE_H:
 	case LTC2945_MAX_SENSE_THRES_H:
 	case LTC2945_MIN_SENSE_THRES_H:
-		return clamp_val(val, 0, LTC2945_SENSE_FULL_SCALE_MA);
+		return clamp_val(val, 0, st->max_current_ma);
 	default:
 		/*
 		 * This is unlikely to happen, and if it does, it should
@@ -215,9 +219,8 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
 	case LTC2945_MAX_POWER_THRES_H:
 	case LTC2945_MIN_POWER_THRES_H:
 		/*
-		 * Convert to register value by assuming current is measured
-		 * with an 1mOhm sense resistor, similar to current
-		 * measurements.
+		 * Convert to register value, scale it with the configured sense
+		 * resistor value, similar to current measurements.
 		 * Control register bit 0 selects if voltage at SENSE+/VDD
 		 * or voltage at ADIN is used to measure power, which in turn
 		 * determines register calculations.
@@ -236,6 +239,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
 			 */
 			val = DIV_ROUND_CLOSEST(val, 25) * 2;
 		}
+		val *= st->r_sense_mohm;
 		break;
 	case LTC2945_VIN_H:
 	case LTC2945_MAX_VIN_H:
@@ -259,12 +263,10 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
 	case LTC2945_MAX_SENSE_THRES_H:
 	case LTC2945_MIN_SENSE_THRES_H:
 		/*
-		 * 25 uV resolution. Convert to current as measured with
-		 * an 1 mOhm sense resistor, in mA. If a different sense
-		 * resistor is installed, calculate the actual current by
-		 * dividing the reported current by the sense resistor value
-		 * in mOhm.
+		 * 25 uV resolution. Convert to current and scale it
+		 * with the value of the sense resistor, in mA.
 		 */
+		val *= st->r_sense_mohm;
 		val = DIV_ROUND_CLOSEST(val, 25);
 		break;
 	default:
@@ -303,7 +305,7 @@ static ssize_t ltc2945_value_store(struct device *dev,
 	if (ret)
 		return ret;
 
-	val = ltc2945_val_clamp(reg, val);
+	val = ltc2945_val_clamp(st, reg, val);
 
 	/* convert to register value, then clamp and write result */
 	regval = ltc2945_val_to_reg(dev, reg, val);
@@ -512,6 +514,7 @@ static int ltc2945_probe(struct i2c_client *client)
 	struct ltc2945_state *st;
 	struct device *hwmon_dev;
 	struct regmap *regmap;
+	u64 val64;
 
 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
 	if (!st)
@@ -523,7 +526,22 @@ static int ltc2945_probe(struct i2c_client *client)
 		return PTR_ERR(regmap);
 	}
 
+	if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
+				     &st->r_sense_mohm))
+		st->r_sense_mohm = 1000;
+
+	if (st->r_sense_mohm < 1000) {
+		dev_err(dev, "Value too small for sense resistor, minimum 1000\n");
+		return -EINVAL;
+	}
+	st->r_sense_mohm /= 1000;
+
 	st->regmap = regmap;
+	val64 = LTC2945_POWER_FULL_SCALE_UW / st->r_sense_mohm;
+	/* clamp power to ULONG_MAX, since we represent it on 32 bits */
+	st->max_power_uw = clamp_val(val64, 0, ULONG_MAX);
+
+	st->max_current_ma = LTC2945_SENSE_FULL_SCALE_MA / st->r_sense_mohm;
 
 	/* Clear faults */
 	regmap_write(regmap, LTC2945_FAULT, 0x00);
-- 
2.17.1


  parent reply	other threads:[~2021-01-07 10:32 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-07 10:34 [PATCH v3 0/4] hwmon: (ltc2945): add support for sense resistor Alexandru Ardelean
2021-01-07 10:34 ` [PATCH v3 1/4] hwmon: (ltc2945): wrap regmap into an ltc2945_state struct Alexandru Ardelean
2021-01-07 10:34 ` [PATCH v3 2/4] hwmon: (ltc2945): clamp values before converting Alexandru Ardelean
2021-01-07 10:34 ` Alexandru Ardelean [this message]
2021-01-07 13:28   ` [PATCH v3 3/4] hwmon: (ltc2945): add support for sense resistor kernel test robot
2021-01-07 13:28     ` kernel test robot
2021-01-07 14:10     ` Alexandru Ardelean
2021-01-07 14:23   ` kernel test robot
2021-01-07 14:23     ` kernel test robot
2021-01-07 15:25   ` Guenter Roeck
2021-01-07 15:44     ` Alexandru Ardelean
2021-01-07 17:35       ` Guenter Roeck
2021-01-08  9:18         ` Alexandru Ardelean
2021-01-07 10:34 ` [PATCH v3 4/4] dt-bindings: hwmon: ltc2945: add device tree doc for ltc2945 Alexandru Ardelean
2021-01-07 15:28 ` [PATCH v3 0/4] hwmon: (ltc2945): add support for sense resistor Guenter Roeck

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=20210107103417.16010-4-alexandru.ardelean@analog.com \
    --to=alexandru.ardelean@analog.com \
    --cc=ardeleanalex@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=jdelvare@suse.com \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mark.thoren@analog.com \
    --cc=robh+dt@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.