All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error
@ 2023-07-12 11:47 Naresh Solanki
  2023-07-12 11:47 ` [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973 Naresh Solanki
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Fix whitespace error reported by checkpatch.pl

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 2109b0458a8b..130cfde52e42 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -600,7 +600,7 @@ mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data,
 	if (ret < 0)
 		return ret;
 	thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON :
-	                                               MP2975_PROT_DEV_OV_OFF;
+						       MP2975_PROT_DEV_OV_OFF;
 
 	/* Select the gain of remote sense amplifier. */
 	ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP);

base-commit: 4dbbaf8fbdbd13adc80731b2452257857e4c2d8b
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 11:51   ` Krzysztof Kozlowski
  2023-07-12 11:47 ` [PATCH 3/8] hwmon: (pmbus/mp2975) Prepare for MP2973 and MP2971 Naresh Solanki
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki, Rob Herring

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Add Monolithic Power Systems MP2971 & MP2973 to trivial devices.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 Documentation/devicetree/bindings/trivial-devices.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 246863a9bc7e..f639618508a9 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -119,6 +119,10 @@ properties:
           - fsl,mpr121
             # Monolithic Power Systems Inc. multi-phase controller mp2888
           - mps,mp2888
+            # Monolithic Power Systems Inc. multi-phase controller mp2971
+          - mps,mp2971
+            # Monolithic Power Systems Inc. multi-phase controller mp2973
+          - mps,mp2973
             # Monolithic Power Systems Inc. multi-phase controller mp2975
           - mps,mp2975
             # Honeywell Humidicon HIH-6130 humidity/temperature sensor
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/8] hwmon: (pmbus/mp2975) Prepare for MP2973 and MP2971
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
  2023-07-12 11:47 ` [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973 Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 11:47 ` [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code Naresh Solanki
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Add support for differntiating between the chips.
The following commits will make use of this mechanism.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 130cfde52e42..04778f2dcbdb 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include "pmbus.h"
 
 /* Vendor specific registers. */
@@ -56,8 +57,13 @@
 				 PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
 				 PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
 
+enum chips {
+	mp2975
+};
+
 struct mp2975_data {
 	struct pmbus_driver_info info;
+	enum chips chip_id;
 	int vout_scale;
 	int vid_step[MP2975_PAGE_NUM];
 	int vref[MP2975_PAGE_NUM];
@@ -68,6 +74,13 @@ struct mp2975_data {
 	int curr_sense_gain[MP2975_PAGE_NUM];
 };
 
+static const struct i2c_device_id mp2975_id[] = {
+	{"mp2975", mp2975},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, mp2975_id);
+
 #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
 
 static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
@@ -691,6 +704,11 @@ static int mp2975_probe(struct i2c_client *client)
 	if (!data)
 		return -ENOMEM;
 
+	if (client->dev.of_node)
+		data->chip_id = (enum chips)of_device_get_match_data(&client->dev);
+	else
+		data->chip_id = i2c_match_id(mp2975_id, client)->driver_data;
+
 	memcpy(&data->info, &mp2975_info, sizeof(*info));
 	info = &data->info;
 
@@ -739,15 +757,8 @@ static int mp2975_probe(struct i2c_client *client)
 	return pmbus_do_probe(client, info);
 }
 
-static const struct i2c_device_id mp2975_id[] = {
-	{"mp2975", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, mp2975_id);
-
 static const struct of_device_id __maybe_unused mp2975_of_match[] = {
-	{.compatible = "mps,mp2975"},
+	{.compatible = "mps,mp2975", .data = (void *)mp2975},
 	{}
 };
 MODULE_DEVICE_TABLE(of, mp2975_of_match);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
  2023-07-12 11:47 ` [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973 Naresh Solanki
  2023-07-12 11:47 ` [PATCH 3/8] hwmon: (pmbus/mp2975) Prepare for MP2973 and MP2971 Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 15:49   ` Guenter Roeck
  2023-07-12 11:47 ` [PATCH 5/8] hwmon: (pmbus/mp2975) Make phase count variable Naresh Solanki
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

In order to upstream MP2973/MP2971 simplify the code by removing support
for various VOUT formats. The MP2973 and MP2971 supports all PMBUS
supported formats for VOUT, while the MP2975 only support DIRECT and
VID for VOUT.

In DIRECT mode all chips report the voltage in 1mV/LSB.

Configure the chip to use DIRECT format for VOUT and drop the code
conversion code for other formats. The to be added chips MP2973/MP2971
will be configured to also report VOUT in DIRECT format.

The maximum voltage that can be reported in DIRECT format is 32768mV.
This is sufficient as the maximum output voltage for VR12/VR13 is
3040 mV.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 54 ++++++------------------------------
 1 file changed, 8 insertions(+), 46 deletions(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 04778f2dcbdb..ebc9a84b8ad3 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -70,7 +70,6 @@ struct mp2975_data {
 	int vref_off[MP2975_PAGE_NUM];
 	int vout_max[MP2975_PAGE_NUM];
 	int vout_ov_fixed[MP2975_PAGE_NUM];
-	int vout_format[MP2975_PAGE_NUM];
 	int curr_sense_gain[MP2975_PAGE_NUM];
 };
 
@@ -83,22 +82,6 @@ MODULE_DEVICE_TABLE(i2c, mp2975_id);
 
 #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
 
-static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-	switch (reg) {
-	case PMBUS_VOUT_MODE:
-		/*
-		 * Enforce VOUT direct format, since device allows to set the
-		 * different formats for the different rails. Conversion from
-		 * VID to direct provided by driver internally, in case it is
-		 * necessary.
-		 */
-		return PB_VOUT_MODE_DIRECT;
-	default:
-		return -ENODATA;
-	}
-}
-
 static int
 mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
 			u16 mask)
@@ -273,24 +256,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
 		ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 *
 					(ret + 1) * data->vout_scale, 10);
 		break;
-	case PMBUS_READ_VOUT:
-		ret = mp2975_read_word_helper(client, page, phase, reg,
-					      GENMASK(11, 0));
-		if (ret < 0)
-			return ret;
-
-		/*
-		 * READ_VOUT can be provided in VID or direct format. The
-		 * format type is specified by bit 15 of the register
-		 * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct
-		 * format, since device allows to set the different formats for
-		 * the different rails and also all VOUT limits registers are
-		 * provided in a direct format. In case format is VID - convert
-		 * to direct.
-		 */
-		if (data->vout_format[page] == vid)
-			ret = mp2975_vid2direct(info->vrm_version[page], ret);
-		break;
 	case PMBUS_VIRT_READ_POUT_MAX:
 		ret = mp2975_read_word_helper(client, page, phase,
 					      MP2975_MFR_READ_POUT_PK,
@@ -578,20 +543,18 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
 }
 
 static int
-mp2975_identify_vout_format(struct i2c_client *client,
-			    struct mp2975_data *data, int page)
+mp2975_set_vout_format(struct i2c_client *client,
+		       struct mp2975_data *data, int page)
 {
 	int ret;
 
 	ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
 	if (ret < 0)
 		return ret;
-
-	if (ret & MP2975_VOUT_FORMAT)
-		data->vout_format[page] = vid;
-	else
-		data->vout_format[page] = direct;
-	return 0;
+	/* Enable DIRECT VOUT format 1mV/LSB */
+	ret &= ~MP2975_VOUT_FORMAT;
+	ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
+	return ret;
 }
 
 static int
@@ -650,11 +613,11 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
 			return ret;
 
 		/*
-		 * Get VOUT format for READ_VOUT command : VID or direct.
+		 * Set VOUT format for READ_VOUT command : direct.
 		 * Pages on same device can be configured with different
 		 * formats.
 		 */
-		ret = mp2975_identify_vout_format(client, data, i);
+		ret = mp2975_set_vout_format(client, data, i);
 		if (ret < 0)
 			return ret;
 
@@ -689,7 +652,6 @@ static struct pmbus_driver_info mp2975_info = {
 		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
 		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
 		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
-	.read_byte_data = mp2975_read_byte_data,
 	.read_word_data = mp2975_read_word_data,
 };
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/8] hwmon: (pmbus/mp2975) Make phase count variable
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
                   ` (2 preceding siblings ...)
  2023-07-12 11:47 ` [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 11:47 ` [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973 Naresh Solanki
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

In order to add support for MP2973 and MP2971 replace hardcoded
phase count for both channels by a variable.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index ebc9a84b8ad3..13d8b95eb992 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -61,10 +61,15 @@ enum chips {
 	mp2975
 };
 
+static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
+	[mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
+};
+
 struct mp2975_data {
 	struct pmbus_driver_info info;
 	enum chips chip_id;
 	int vout_scale;
+	int max_phases[MP2975_PAGE_NUM];
 	int vid_step[MP2975_PAGE_NUM];
 	int vref[MP2975_PAGE_NUM];
 	int vref_off[MP2975_PAGE_NUM];
@@ -304,25 +309,25 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
 	return ret;
 }
 
-static int mp2975_identify_multiphase_rail2(struct i2c_client *client)
+static int mp2975_identify_multiphase_rail2(struct i2c_client *client,
+					    struct mp2975_data *data)
 {
 	int ret;
 
 	/*
-	 * Identify multiphase for rail 2 - could be from 0 to 4.
+	 * Identify multiphase for rail 2 - could be from 0 to data->max_phases[1].
 	 * In case phase number is zero – only page zero is supported
 	 */
 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
 	if (ret < 0)
 		return ret;
 
-	/* Identify multiphase for rail 2 - could be from 0 to 4. */
 	ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2);
 	if (ret < 0)
 		return ret;
 
 	ret &= GENMASK(2, 0);
-	return (ret >= 4) ? 4 : ret;
+	return (ret >= data->max_phases[1]) ? data->max_phases[1] : ret;
 }
 
 static void mp2975_set_phase_rail1(struct pmbus_driver_info *info)
@@ -353,7 +358,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
 	if (ret < 0)
 		return ret;
 
-	/* Identify multiphase for rail 1 - could be from 1 to 8. */
+	/* Identify multiphase for rail 1 - could be from 1 to data->max_phases[0]. */
 	ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1);
 	if (ret <= 0)
 		return ret;
@@ -361,19 +366,19 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
 	info->phases[0] = ret & GENMASK(3, 0);
 
 	/*
-	 * The device provides a total of 8 PWM pins, and can be configured
+	 * The device provides a total of $n PWM pins, and can be configured
 	 * to different phase count applications for rail 1 and rail 2.
-	 * Rail 1 can be set to 8 phases, while rail 2 can only be set to 4
-	 * phases at most. When rail 1’s phase count is configured as 0, rail
+	 * Rail 1 can be set to $n phases, while rail 2 can be set to less than
+	 * that. When rail 1’s phase count is configured as 0, rail
 	 * 1 operates with 1-phase DCM. When rail 2 phase count is configured
 	 * as 0, rail 2 is disabled.
 	 */
-	if (info->phases[0] > MP2975_MAX_PHASE_RAIL1)
+	if (info->phases[0] > data->max_phases[0])
 		return -EINVAL;
 
 	mp2975_set_phase_rail1(info);
-	num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0],
-			  MP2975_MAX_PHASE_RAIL2);
+	num_phases2 = min(data->max_phases[0] - info->phases[0],
+			  data->max_phases[1]);
 	if (info->phases[1] && info->phases[1] <= num_phases2)
 		mp2975_set_phase_rail2(info, num_phases2);
 
@@ -671,11 +676,13 @@ static int mp2975_probe(struct i2c_client *client)
 	else
 		data->chip_id = i2c_match_id(mp2975_id, client)->driver_data;
 
-	memcpy(&data->info, &mp2975_info, sizeof(*info));
+	memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
+	       sizeof(data->max_phases));
+
 	info = &data->info;
 
 	/* Identify multiphase configuration for rail 2. */
-	ret = mp2975_identify_multiphase_rail2(client);
+	ret = mp2975_identify_multiphase_rail2(client, data);
 	if (ret < 0)
 		return ret;
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
                   ` (3 preceding siblings ...)
  2023-07-12 11:47 ` [PATCH 5/8] hwmon: (pmbus/mp2975) Make phase count variable Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 17:58   ` Guenter Roeck
  2023-07-12 11:47 ` [PATCH 7/8] hwmon: (pmbus/mp2975) Add regulator support Naresh Solanki
  2023-07-12 11:47 ` [PATCH 8/8] hwmon: (pmbus/mp2975) Add OCP limit Naresh Solanki
  6 siblings, 1 reply; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Add support for MP2971 and MP2973, the successor of MP2975.

The major differences are:
 - On MP2973 and MP2971 the Vref cannot be read and thus most of
   the OVP/current calculations won't work.
 - MP2973 and MP2971 also support LINEAR format for VOUT
 - MP2973 and MP2971 do not support OVP2
 - On MP2973 and MP2971 most registers are in LINEAR format
 - The IMVP9_EN bit has a different position
 - Per phase current sense haven't been implemented.

As on MP2975 most of the FAULT_LIMIT and WARN_LIMIT registers
have been redefined and doesn't provide the functionality as
defined in PMBUS spec.

Tested on MP2973 and MP2971.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 262 +++++++++++++++++++++++++++++------
 1 file changed, 221 insertions(+), 41 deletions(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 13d8b95eb992..83242595ccbe 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -35,6 +35,8 @@
 #define MP2975_MFR_OVP_TH_SET		0xe5
 #define MP2975_MFR_UVP_SET		0xe6
 
+#define MP2973_MFR_RESO_SET		0xc7
+
 #define MP2975_VOUT_FORMAT		BIT(15)
 #define MP2975_VID_STEP_SEL_R1		BIT(4)
 #define MP2975_IMVP9_EN_R1		BIT(13)
@@ -49,8 +51,32 @@
 #define MP2975_SENSE_AMPL_HALF		2
 #define MP2975_VIN_UV_LIMIT_UNIT	8
 
+#define MP2973_VOUT_FORMAT_R1		GENMASK(7, 6)
+#define MP2973_VOUT_FORMAT_R2		GENMASK(4, 3)
+#define MP2973_VOUT_FORMAT_DIRECT_R1	BIT(7)
+#define MP2973_VOUT_FORMAT_LINEAR_R1	BIT(6)
+#define MP2973_VOUT_FORMAT_DIRECT_R2	BIT(4)
+#define MP2973_VOUT_FORMAT_LINEAR_R2	BIT(3)
+
+#define MP2973_MFR_VR_MULTI_CONFIG_R1	0x0d
+#define MP2973_MFR_VR_MULTI_CONFIG_R2	0x1d
+#define MP2973_VID_STEP_SEL_R1		BIT(4)
+#define MP2973_IMVP9_EN_R1		BIT(14)
+#define MP2973_VID_STEP_SEL_R2		BIT(3)
+#define MP2973_IMVP9_EN_R2		BIT(13)
+
+#define MP2973_MFR_READ_IOUT_PK		0x90
+#define MP2973_MFR_READ_POUT_PK		0x91
+
 #define MP2975_MAX_PHASE_RAIL1	8
 #define MP2975_MAX_PHASE_RAIL2	4
+
+#define MP2973_MAX_PHASE_RAIL1	14
+#define MP2973_MAX_PHASE_RAIL2	6
+
+#define MP2971_MAX_PHASE_RAIL1	8
+#define MP2971_MAX_PHASE_RAIL2	3
+
 #define MP2975_PAGE_NUM		2
 
 #define MP2975_RAIL2_FUNC	(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
@@ -58,11 +84,13 @@
 				 PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
 
 enum chips {
-	mp2975
+	mp2971, mp2973, mp2975
 };
 
 static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
 	[mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
+	[mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 },
+	[mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 },
 };
 
 struct mp2975_data {
@@ -79,6 +107,8 @@ struct mp2975_data {
 };
 
 static const struct i2c_device_id mp2975_id[] = {
+	{"mp2971", mp2971},
+	{"mp2973", mp2973},
 	{"mp2975", mp2975},
 	{}
 };
@@ -215,6 +245,76 @@ mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data,
 	return ret;
 }
 
+static int mp2973_read_word_data(struct i2c_client *client, int page,
+				 int phase, int reg)
+{
+	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+	struct mp2975_data *data = to_mp2975_data(info);
+	int ret;
+
+	switch (reg) {
+	case PMBUS_OT_FAULT_LIMIT:
+		ret = mp2975_read_word_helper(client, page, phase, reg,
+					      GENMASK(7, 0));
+		break;
+	case PMBUS_VIN_OV_FAULT_LIMIT:
+		ret = mp2975_read_word_helper(client, page, phase, reg,
+					      GENMASK(7, 0));
+		if (ret < 0)
+			return ret;
+
+		ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT);
+		break;
+	case PMBUS_VOUT_OV_FAULT_LIMIT:
+		/*
+		 * MP2971 and mp2973 only supports tracking (ovp1) mode.
+		 */
+		ret = mp2975_read_word_helper(client, page, phase,
+					      MP2975_MFR_OVP_TH_SET,
+					      GENMASK(2, 0));
+		if (ret < 0)
+			return ret;
+
+		ret = data->vout_max[page] + 50 * (ret + 1);
+		break;
+	case PMBUS_VOUT_UV_FAULT_LIMIT:
+		ret = mp2975_read_word_helper(client, page, phase, reg,
+					      GENMASK(8, 0));
+		if (ret < 0)
+			return ret;
+		ret = mp2975_vid2direct(info->vrm_version[page], ret);
+		break;
+	case PMBUS_VIRT_READ_POUT_MAX:
+		ret = pmbus_read_word_data(client, page, phase,
+					   MP2973_MFR_READ_POUT_PK);
+		break;
+	case PMBUS_VIRT_READ_IOUT_MAX:
+		ret = pmbus_read_word_data(client, page, phase,
+					   MP2973_MFR_READ_IOUT_PK);
+		break;
+	case PMBUS_UT_WARN_LIMIT:
+	case PMBUS_UT_FAULT_LIMIT:
+	case PMBUS_VIN_UV_WARN_LIMIT:
+	case PMBUS_VIN_UV_FAULT_LIMIT:
+	case PMBUS_VOUT_UV_WARN_LIMIT:
+	case PMBUS_VOUT_OV_WARN_LIMIT:
+	case PMBUS_VIN_OV_WARN_LIMIT:
+	case PMBUS_IIN_OC_FAULT_LIMIT:
+	case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
+	case PMBUS_IOUT_OC_WARN_LIMIT:
+	case PMBUS_IOUT_OC_FAULT_LIMIT:
+	case PMBUS_IOUT_UC_FAULT_LIMIT:
+	case PMBUS_POUT_OP_FAULT_LIMIT:
+	case PMBUS_POUT_OP_WARN_LIMIT:
+	case PMBUS_PIN_OP_WARN_LIMIT:
+		return -ENXIO;
+	default:
+		return -ENODATA;
+	}
+
+	return ret;
+}
+
 static int mp2975_read_word_data(struct i2c_client *client, int page,
 				 int phase, int reg)
 {
@@ -386,7 +486,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
 }
 
 static int
-mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data,
+mp297x_identify_vid(struct i2c_client *client, struct mp2975_data *data,
 		    struct pmbus_driver_info *info, u32 reg, int page,
 		    u32 imvp_bit, u32 vr_bit)
 {
@@ -422,7 +522,7 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
 		return ret;
 
 	/* Identify VID mode for rail 1. */
-	ret = mp2975_identify_vid(client, data, info,
+	ret = mp297x_identify_vid(client, data, info,
 				  MP2975_MFR_VR_MULTI_CONFIG_R1, 0,
 				  MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1);
 	if (ret < 0)
@@ -430,10 +530,39 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
 
 	/* Identify VID mode for rail 2, if connected. */
 	if (info->phases[1])
-		ret = mp2975_identify_vid(client, data, info,
+		ret = mp297x_identify_vid(client, data, info,
 					  MP2975_MFR_VR_MULTI_CONFIG_R2, 1,
 					  MP2975_IMVP9_EN_R2,
 					  MP2975_VID_STEP_SEL_R2);
+
+	return ret;
+}
+
+static int
+mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
+			  struct pmbus_driver_info *info)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
+	if (ret < 0)
+		return ret;
+
+	/* Identify VID mode for rail 1. */
+	ret = mp297x_identify_vid(client, data, info,
+				  MP2973_MFR_VR_MULTI_CONFIG_R1, 0,
+				  MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1);
+
+	if (ret < 0)
+		return ret;
+
+	/* Identify VID mode for rail 2, if connected. */
+	if (info->phases[1])
+		ret = mp297x_identify_vid(client, data, info,
+					  MP2973_MFR_VR_MULTI_CONFIG_R2, 1,
+					  MP2973_IMVP9_EN_R2,
+					  MP2973_VID_STEP_SEL_R2);
+
 	return ret;
 }
 
@@ -532,7 +661,7 @@ mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data,
 }
 
 static int
-mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
+mp297x_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
 		    struct pmbus_driver_info *info, int page)
 {
 	int ret;
@@ -548,17 +677,33 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
 }
 
 static int
-mp2975_set_vout_format(struct i2c_client *client,
+mp297x_set_vout_format(struct i2c_client *client,
 		       struct mp2975_data *data, int page)
 {
 	int ret;
 
-	ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
-	if (ret < 0)
-		return ret;
 	/* Enable DIRECT VOUT format 1mV/LSB */
-	ret &= ~MP2975_VOUT_FORMAT;
-	ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
+	if (data->chip_id == mp2975) {
+		ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
+		if (ret < 0)
+			return ret;
+		ret &= ~MP2975_VOUT_FORMAT;
+		ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
+	} else {
+		ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET);
+		if (ret < 0)
+			return ret;
+
+		if (page == 0) {
+			ret &= ~MP2973_VOUT_FORMAT_R1;
+			ret |= MP2973_VOUT_FORMAT_DIRECT_R1;
+		} else {
+			ret &= ~MP2973_VOUT_FORMAT_R2;
+			ret |= MP2973_VOUT_FORMAT_DIRECT_R2;
+		}
+
+		ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, ret);
+	}
 	return ret;
 }
 
@@ -605,24 +750,28 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
 	for (i = 0; i < data->info.pages; i++) {
 		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
 		if (ret < 0)
-			return ret;
+			continue;
 
-		/* Obtain voltage reference offsets. */
-		ret = mp2975_vref_offset_get(client, data, i);
+		/*
+		 * Set VOUT format for READ_VOUT command : direct.
+		 * Pages on same device can be configured with different
+		 * formats.
+		 */
+		ret = mp297x_set_vout_format(client, data, i);
 		if (ret < 0)
 			return ret;
 
 		/* Obtain maximum voltage values. */
-		ret = mp2975_vout_max_get(client, data, info, i);
+		ret = mp297x_vout_max_get(client, data, info, i);
 		if (ret < 0)
 			return ret;
 
-		/*
-		 * Set VOUT format for READ_VOUT command : direct.
-		 * Pages on same device can be configured with different
-		 * formats.
-		 */
-		ret = mp2975_set_vout_format(client, data, i);
+		/* Skip if reading Vref is unsupported */
+		if (data->chip_id != mp2975)
+			continue;
+
+		/* Obtain voltage reference offsets. */
+		ret = mp2975_vref_offset_get(client, data, i);
 		if (ret < 0)
 			return ret;
 
@@ -660,6 +809,23 @@ static struct pmbus_driver_info mp2975_info = {
 	.read_word_data = mp2975_read_word_data,
 };
 
+static struct pmbus_driver_info mp2973_info = {
+	.pages = 1,
+	.format[PSC_VOLTAGE_IN] = linear,
+	.format[PSC_VOLTAGE_OUT] = direct,
+	.format[PSC_TEMPERATURE] = linear,
+	.format[PSC_CURRENT_IN] = linear,
+	.format[PSC_CURRENT_OUT] = linear,
+	.format[PSC_POWER] = linear,
+	.m[PSC_VOLTAGE_OUT] = 1,
+	.R[PSC_VOLTAGE_OUT] = 3,
+	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
+		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
+	.read_word_data = mp2973_read_word_data,
+};
+
 static int mp2975_probe(struct i2c_client *client)
 {
 	struct pmbus_driver_info *info;
@@ -679,6 +845,11 @@ static int mp2975_probe(struct i2c_client *client)
 	memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
 	       sizeof(data->max_phases));
 
+	if (data->chip_id == mp2975)
+		memcpy(&data->info, &mp2975_info, sizeof(*info));
+	else
+		memcpy(&data->info, &mp2973_info, sizeof(*info));
+
 	info = &data->info;
 
 	/* Identify multiphase configuration for rail 2. */
@@ -693,30 +864,37 @@ static int mp2975_probe(struct i2c_client *client)
 		data->info.func[1] = MP2975_RAIL2_FUNC;
 	}
 
-	/* Identify multiphase configuration. */
-	ret = mp2975_identify_multiphase(client, data, info);
-	if (ret)
-		return ret;
+	if (data->chip_id == mp2975) {
+		/* Identify multiphase configuration. */
+		ret = mp2975_identify_multiphase(client, data, info);
+		if (ret)
+			return ret;
 
-	/* Identify VID setting per rail. */
-	ret = mp2975_identify_rails_vid(client, data, info);
-	if (ret < 0)
-		return ret;
+		/* Identify VID setting per rail. */
+		ret = mp2975_identify_rails_vid(client, data, info);
+		if (ret < 0)
+			return ret;
 
-	/* Obtain current sense gain of power stage. */
-	ret = mp2975_current_sense_gain_get(client, data);
-	if (ret)
-		return ret;
+		/* Obtain current sense gain of power stage. */
+		ret = mp2975_current_sense_gain_get(client, data);
+		if (ret)
+			return ret;
 
-	/* Obtain voltage reference values. */
-	ret = mp2975_vref_get(client, data, info);
-	if (ret)
-		return ret;
+		/* Obtain voltage reference values. */
+		ret = mp2975_vref_get(client, data, info);
+		if (ret)
+			return ret;
 
-	/* Obtain vout over-voltage scales. */
-	ret = mp2975_vout_ov_scale_get(client, data, info);
-	if (ret < 0)
-		return ret;
+		/* Obtain vout over-voltage scales. */
+		ret = mp2975_vout_ov_scale_get(client, data, info);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* Identify VID setting per rail. */
+		ret = mp2973_identify_rails_vid(client, data, info);
+		if (ret < 0)
+			return ret;
+	}
 
 	/* Obtain offsets, maximum and format for vout. */
 	ret = mp2975_vout_per_rail_config_get(client, data, info);
@@ -727,6 +905,8 @@ static int mp2975_probe(struct i2c_client *client)
 }
 
 static const struct of_device_id __maybe_unused mp2975_of_match[] = {
+	{.compatible = "mps,mp2971", .data = (void *)mp2971},
+	{.compatible = "mps,mp2973", .data = (void *)mp2973},
 	{.compatible = "mps,mp2975", .data = (void *)mp2975},
 	{}
 };
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/8] hwmon: (pmbus/mp2975) Add regulator support
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
                   ` (4 preceding siblings ...)
  2023-07-12 11:47 ` [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973 Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  2023-07-12 11:47 ` [PATCH 8/8] hwmon: (pmbus/mp2975) Add OCP limit Naresh Solanki
  6 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Add support to expose the PMBUS regulator.

Tested on MP2973 and MP2971.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/Kconfig  |  7 +++++++
 drivers/hwmon/pmbus/mp2975.c | 15 +++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 270b6336b76d..b4e93bd5835e 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -317,6 +317,13 @@ config SENSORS_MP2975
 	  This driver can also be built as a module. If so, the module will
 	  be called mp2975.
 
+config SENSORS_MP2975_REGULATOR
+	depends on SENSORS_MP2975 && REGULATOR
+	bool "Regulator support for MPS MP2975"
+	help
+	  If you say yes here you get regulator support for MPS MP2975
+	  Dual Loop Digital Multi-Phase Controller.
+
 config SENSORS_MP5023
 	tristate "MPS MP5023"
 	help
diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 83242595ccbe..27a9724aed68 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -115,6 +115,11 @@ static const struct i2c_device_id mp2975_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, mp2975_id);
 
+static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = {
+	PMBUS_REGULATOR("vout", 0),
+	PMBUS_REGULATOR("vout", 1),
+};
+
 #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
 
 static int
@@ -807,6 +812,10 @@ static struct pmbus_driver_info mp2975_info = {
 		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
 		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
 	.read_word_data = mp2975_read_word_data,
+#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
+	.num_regulators = 1,
+	.reg_desc = mp2975_reg_desc,
+#endif
 };
 
 static struct pmbus_driver_info mp2973_info = {
@@ -824,6 +833,10 @@ static struct pmbus_driver_info mp2973_info = {
 		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
 		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
 	.read_word_data = mp2973_read_word_data,
+#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
+	.num_regulators = 1,
+	.reg_desc = mp2975_reg_desc,
+#endif
 };
 
 static int mp2975_probe(struct i2c_client *client)
@@ -862,6 +875,8 @@ static int mp2975_probe(struct i2c_client *client)
 		data->info.pages = MP2975_PAGE_NUM;
 		data->info.phases[1] = ret;
 		data->info.func[1] = MP2975_RAIL2_FUNC;
+		if (CONFIG_SENSORS_MP2975_REGULATOR)
+			data->info.num_regulators = MP2975_PAGE_NUM;
 	}
 
 	if (data->chip_id == mp2975) {
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/8] hwmon: (pmbus/mp2975) Add OCP limit
  2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
                   ` (5 preceding siblings ...)
  2023-07-12 11:47 ` [PATCH 7/8] hwmon: (pmbus/mp2975) Add regulator support Naresh Solanki
@ 2023-07-12 11:47 ` Naresh Solanki
  6 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-12 11:47 UTC (permalink / raw)
  To: devicetree, Guenter Roeck, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Naresh Solanki

From: Patrick Rudolph <patrick.rudolph@9elements.com>

Add support for PMBUS_IOUT_OC_FAULT_LIMIT.
Add a helper function to convert the limit to LINEAR11 format
and read data->info.phases[0] on MP2971 and MP2973 as well.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/mp2975.c | 76 ++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 11 deletions(-)

diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 27a9724aed68..0a6669f865f6 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -65,6 +65,10 @@
 #define MP2973_VID_STEP_SEL_R2		BIT(3)
 #define MP2973_IMVP9_EN_R2		BIT(13)
 
+#define MP2973_MFR_OCP_TOTAL_SET	0x5f
+#define MP2973_OCP_TOTAL_CUR_MASK	GENMASK(6, 0)
+#define MP2973_MFR_OCP_LEVEL_RES	BIT(15)
+
 #define MP2973_MFR_READ_IOUT_PK		0x90
 #define MP2973_MFR_READ_POUT_PK		0x91
 
@@ -153,6 +157,41 @@ mp2975_vid2direct(int vrf, int val)
 	return 0;
 }
 
+#define MAX_LIN_MANTISSA	(1023 * 1000)
+#define MIN_LIN_MANTISSA	(511 * 1000)
+
+/* Converts a milli-unit DIRECT value to LINEAR11 format */
+static u16 mp2975_data2reg_linear11(s64 val)
+{
+	s16 exponent = 0, mantissa;
+	bool negative = false;
+
+	/* simple case */
+	if (val == 0)
+		return 0;
+
+	/* Reduce large mantissa until it fits into 10 bit */
+	while (val >= MAX_LIN_MANTISSA && exponent < 15) {
+		exponent++;
+		val >>= 1;
+	}
+	/* Increase small mantissa to improve precision */
+	while (val < MIN_LIN_MANTISSA && exponent > -15) {
+		exponent--;
+		val <<= 1;
+	}
+
+	/* Convert mantissa from milli-units to units */
+	mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff);
+
+	/* restore sign */
+	if (negative)
+		mantissa = -mantissa;
+
+	/* Convert to 5 bit exponent, 11 bit mantissa */
+	return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
 static int
 mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data,
 		  int page, int phase, u8 reg)
@@ -297,6 +336,20 @@ static int mp2973_read_word_data(struct i2c_client *client, int page,
 		ret = pmbus_read_word_data(client, page, phase,
 					   MP2973_MFR_READ_IOUT_PK);
 		break;
+	case PMBUS_IOUT_OC_FAULT_LIMIT:
+		ret = mp2975_read_word_helper(client, page, phase,
+					      MP2973_MFR_OCP_TOTAL_SET,
+					      GENMASK(15, 0));
+		if (ret < 0)
+			return ret;
+
+		if (ret & MP2973_MFR_OCP_LEVEL_RES)
+			ret = 2 * (ret & MP2973_OCP_TOTAL_CUR_MASK);
+		else
+			ret = ret & MP2973_OCP_TOTAL_CUR_MASK;
+
+		ret = mp2975_data2reg_linear11(ret * info->phases[page] * 1000);
+		break;
 	case PMBUS_UT_WARN_LIMIT:
 	case PMBUS_UT_FAULT_LIMIT:
 	case PMBUS_VIN_UV_WARN_LIMIT:
@@ -307,7 +360,6 @@ static int mp2973_read_word_data(struct i2c_client *client, int page,
 	case PMBUS_IIN_OC_FAULT_LIMIT:
 	case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
 	case PMBUS_IOUT_OC_WARN_LIMIT:
-	case PMBUS_IOUT_OC_FAULT_LIMIT:
 	case PMBUS_IOUT_UC_FAULT_LIMIT:
 	case PMBUS_POUT_OP_FAULT_LIMIT:
 	case PMBUS_POUT_OP_WARN_LIMIT:
@@ -481,11 +533,13 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
 	if (info->phases[0] > data->max_phases[0])
 		return -EINVAL;
 
-	mp2975_set_phase_rail1(info);
-	num_phases2 = min(data->max_phases[0] - info->phases[0],
-			  data->max_phases[1]);
-	if (info->phases[1] && info->phases[1] <= num_phases2)
-		mp2975_set_phase_rail2(info, num_phases2);
+	if (data->chip_id == mp2975) {
+		mp2975_set_phase_rail1(info);
+		num_phases2 = min(data->max_phases[0] - info->phases[0],
+				  data->max_phases[1]);
+		if (info->phases[1] && info->phases[1] <= num_phases2)
+			mp2975_set_phase_rail2(info, num_phases2);
+	}
 
 	return 0;
 }
@@ -879,12 +933,12 @@ static int mp2975_probe(struct i2c_client *client)
 			data->info.num_regulators = MP2975_PAGE_NUM;
 	}
 
-	if (data->chip_id == mp2975) {
-		/* Identify multiphase configuration. */
-		ret = mp2975_identify_multiphase(client, data, info);
-		if (ret)
-			return ret;
+	/* Identify multiphase configuration. */
+	ret = mp2975_identify_multiphase(client, data, info);
+	if (ret)
+		return ret;
 
+	if (data->chip_id == mp2975) {
 		/* Identify VID setting per rail. */
 		ret = mp2975_identify_rails_vid(client, data, info);
 		if (ret < 0)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973
  2023-07-12 11:47 ` [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973 Naresh Solanki
@ 2023-07-12 11:51   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 13+ messages in thread
From: Krzysztof Kozlowski @ 2023-07-12 11:51 UTC (permalink / raw)
  To: Naresh Solanki, devicetree, Guenter Roeck, Jean Delvare,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph, Rob Herring

On 12/07/2023 13:47, Naresh Solanki wrote:
> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> Add Monolithic Power Systems MP2971 & MP2973 to trivial devices.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code
  2023-07-12 11:47 ` [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code Naresh Solanki
@ 2023-07-12 15:49   ` Guenter Roeck
  2023-07-14 11:23     ` Naresh Solanki
  0 siblings, 1 reply; 13+ messages in thread
From: Guenter Roeck @ 2023-07-12 15:49 UTC (permalink / raw)
  To: Naresh Solanki, devicetree, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph

On 7/12/23 04:47, Naresh Solanki wrote:
> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> In order to upstream MP2973/MP2971 simplify the code by removing support
> for various VOUT formats. The MP2973 and MP2971 supports all PMBUS
> supported formats for VOUT, while the MP2975 only support DIRECT and
> VID for VOUT.
> 
> In DIRECT mode all chips report the voltage in 1mV/LSB.
> 
> Configure the chip to use DIRECT format for VOUT and drop the code
> conversion code for other formats. The to be added chips MP2973/MP2971
> will be configured to also report VOUT in DIRECT format.
> 
> The maximum voltage that can be reported in DIRECT format is 32768mV.
> This is sufficient as the maximum output voltage for VR12/VR13 is
> 3040 mV.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ---
>   drivers/hwmon/pmbus/mp2975.c | 54 ++++++------------------------------
>   1 file changed, 8 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
> index 04778f2dcbdb..ebc9a84b8ad3 100644
> --- a/drivers/hwmon/pmbus/mp2975.c
> +++ b/drivers/hwmon/pmbus/mp2975.c
> @@ -70,7 +70,6 @@ struct mp2975_data {
>   	int vref_off[MP2975_PAGE_NUM];
>   	int vout_max[MP2975_PAGE_NUM];
>   	int vout_ov_fixed[MP2975_PAGE_NUM];
> -	int vout_format[MP2975_PAGE_NUM];
>   	int curr_sense_gain[MP2975_PAGE_NUM];
>   };
>   
> @@ -83,22 +82,6 @@ MODULE_DEVICE_TABLE(i2c, mp2975_id);
>   
>   #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
>   
> -static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
> -{
> -	switch (reg) {
> -	case PMBUS_VOUT_MODE:
> -		/*
> -		 * Enforce VOUT direct format, since device allows to set the
> -		 * different formats for the different rails. Conversion from
> -		 * VID to direct provided by driver internally, in case it is
> -		 * necessary.
> -		 */
> -		return PB_VOUT_MODE_DIRECT;
> -	default:
> -		return -ENODATA;
> -	}
> -}
> -
>   static int
>   mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
>   			u16 mask)
> @@ -273,24 +256,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
>   		ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 *
>   					(ret + 1) * data->vout_scale, 10);
>   		break;
> -	case PMBUS_READ_VOUT:
> -		ret = mp2975_read_word_helper(client, page, phase, reg,
> -					      GENMASK(11, 0));
> -		if (ret < 0)
> -			return ret;
> -
> -		/*
> -		 * READ_VOUT can be provided in VID or direct format. The
> -		 * format type is specified by bit 15 of the register
> -		 * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct
> -		 * format, since device allows to set the different formats for
> -		 * the different rails and also all VOUT limits registers are
> -		 * provided in a direct format. In case format is VID - convert
> -		 * to direct.
> -		 */
> -		if (data->vout_format[page] == vid)
> -			ret = mp2975_vid2direct(info->vrm_version[page], ret);
> -		break;
>   	case PMBUS_VIRT_READ_POUT_MAX:
>   		ret = mp2975_read_word_helper(client, page, phase,
>   					      MP2975_MFR_READ_POUT_PK,
> @@ -578,20 +543,18 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
>   }
>   
>   static int
> -mp2975_identify_vout_format(struct i2c_client *client,
> -			    struct mp2975_data *data, int page)
> +mp2975_set_vout_format(struct i2c_client *client,
> +		       struct mp2975_data *data, int page)
>   {
>   	int ret;
>   
>   	ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
>   	if (ret < 0)
>   		return ret;
> -
> -	if (ret & MP2975_VOUT_FORMAT)
> -		data->vout_format[page] = vid;
> -	else
> -		data->vout_format[page] = direct;
> -	return 0;
> +	/* Enable DIRECT VOUT format 1mV/LSB */
> +	ret &= ~MP2975_VOUT_FORMAT;
> +	ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);

Writing this back is only needed if MP2975_VOUT_FORMAT was not already cleared.

> +	return ret;
>   }
>   
>   static int
> @@ -650,11 +613,11 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
>   			return ret;
>   
>   		/*
> -		 * Get VOUT format for READ_VOUT command : VID or direct.
> +		 * Set VOUT format for READ_VOUT command : direct.
>   		 * Pages on same device can be configured with different
>   		 * formats.

Not sure if this comment still makes sense.

>   		 */
> -		ret = mp2975_identify_vout_format(client, data, i);
> +		ret = mp2975_set_vout_format(client, data, i);
>   		if (ret < 0)
>   			return ret;
>   
> @@ -689,7 +652,6 @@ static struct pmbus_driver_info mp2975_info = {
>   		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
>   		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
>   		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
> -	.read_byte_data = mp2975_read_byte_data,
>   	.read_word_data = mp2975_read_word_data,
>   };
>   


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973
  2023-07-12 11:47 ` [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973 Naresh Solanki
@ 2023-07-12 17:58   ` Guenter Roeck
  2023-07-14 12:25     ` Naresh Solanki
  0 siblings, 1 reply; 13+ messages in thread
From: Guenter Roeck @ 2023-07-12 17:58 UTC (permalink / raw)
  To: Naresh Solanki, devicetree, Jean Delvare
  Cc: linux-kernel, linux-hwmon, Patrick Rudolph

On 7/12/23 04:47, Naresh Solanki wrote:
> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> Add support for MP2971 and MP2973, the successor of MP2975.
> 
> The major differences are:
>   - On MP2973 and MP2971 the Vref cannot be read and thus most of
>     the OVP/current calculations won't work.
>   - MP2973 and MP2971 also support LINEAR format for VOUT
>   - MP2973 and MP2971 do not support OVP2
>   - On MP2973 and MP2971 most registers are in LINEAR format
>   - The IMVP9_EN bit has a different position
>   - Per phase current sense haven't been implemented.
> 
> As on MP2975 most of the FAULT_LIMIT and WARN_LIMIT registers
> have been redefined and doesn't provide the functionality as
> defined in PMBUS spec.
> 
> Tested on MP2973 and MP2971.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ---
>   drivers/hwmon/pmbus/mp2975.c | 262 +++++++++++++++++++++++++++++------
>   1 file changed, 221 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
> index 13d8b95eb992..83242595ccbe 100644
> --- a/drivers/hwmon/pmbus/mp2975.c
> +++ b/drivers/hwmon/pmbus/mp2975.c
> @@ -35,6 +35,8 @@
>   #define MP2975_MFR_OVP_TH_SET		0xe5
>   #define MP2975_MFR_UVP_SET		0xe6
>   
> +#define MP2973_MFR_RESO_SET		0xc7
> +
>   #define MP2975_VOUT_FORMAT		BIT(15)
>   #define MP2975_VID_STEP_SEL_R1		BIT(4)
>   #define MP2975_IMVP9_EN_R1		BIT(13)
> @@ -49,8 +51,32 @@
>   #define MP2975_SENSE_AMPL_HALF		2
>   #define MP2975_VIN_UV_LIMIT_UNIT	8
>   
> +#define MP2973_VOUT_FORMAT_R1		GENMASK(7, 6)
> +#define MP2973_VOUT_FORMAT_R2		GENMASK(4, 3)
> +#define MP2973_VOUT_FORMAT_DIRECT_R1	BIT(7)
> +#define MP2973_VOUT_FORMAT_LINEAR_R1	BIT(6)
> +#define MP2973_VOUT_FORMAT_DIRECT_R2	BIT(4)
> +#define MP2973_VOUT_FORMAT_LINEAR_R2	BIT(3)
> +
> +#define MP2973_MFR_VR_MULTI_CONFIG_R1	0x0d
> +#define MP2973_MFR_VR_MULTI_CONFIG_R2	0x1d
> +#define MP2973_VID_STEP_SEL_R1		BIT(4)
> +#define MP2973_IMVP9_EN_R1		BIT(14)
> +#define MP2973_VID_STEP_SEL_R2		BIT(3)
> +#define MP2973_IMVP9_EN_R2		BIT(13)
> +
> +#define MP2973_MFR_READ_IOUT_PK		0x90
> +#define MP2973_MFR_READ_POUT_PK		0x91
> +
>   #define MP2975_MAX_PHASE_RAIL1	8
>   #define MP2975_MAX_PHASE_RAIL2	4
> +
> +#define MP2973_MAX_PHASE_RAIL1	14
> +#define MP2973_MAX_PHASE_RAIL2	6
> +
> +#define MP2971_MAX_PHASE_RAIL1	8
> +#define MP2971_MAX_PHASE_RAIL2	3
> +
>   #define MP2975_PAGE_NUM		2
>   
>   #define MP2975_RAIL2_FUNC	(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
> @@ -58,11 +84,13 @@
>   				 PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
>   
>   enum chips {
> -	mp2975
> +	mp2971, mp2973, mp2975
>   };
>   
>   static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
>   	[mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
> +	[mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 },
> +	[mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 },
>   };
>   
>   struct mp2975_data {
> @@ -79,6 +107,8 @@ struct mp2975_data {
>   };
>   
>   static const struct i2c_device_id mp2975_id[] = {
> +	{"mp2971", mp2971},
> +	{"mp2973", mp2973},
>   	{"mp2975", mp2975},
>   	{}
>   };
> @@ -215,6 +245,76 @@ mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data,
>   	return ret;
>   }
>   
> +static int mp2973_read_word_data(struct i2c_client *client, int page,
> +				 int phase, int reg)
> +{
> +	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
> +	struct mp2975_data *data = to_mp2975_data(info);
> +	int ret;
> +
> +	switch (reg) {
> +	case PMBUS_OT_FAULT_LIMIT:
> +		ret = mp2975_read_word_helper(client, page, phase, reg,
> +					      GENMASK(7, 0));
> +		break;
> +	case PMBUS_VIN_OV_FAULT_LIMIT:
> +		ret = mp2975_read_word_helper(client, page, phase, reg,
> +					      GENMASK(7, 0));
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT);
> +		break;
> +	case PMBUS_VOUT_OV_FAULT_LIMIT:
> +		/*
> +		 * MP2971 and mp2973 only supports tracking (ovp1) mode.
> +		 */
> +		ret = mp2975_read_word_helper(client, page, phase,
> +					      MP2975_MFR_OVP_TH_SET,
> +					      GENMASK(2, 0));
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = data->vout_max[page] + 50 * (ret + 1);
> +		break;
> +	case PMBUS_VOUT_UV_FAULT_LIMIT:
> +		ret = mp2975_read_word_helper(client, page, phase, reg,
> +					      GENMASK(8, 0));
> +		if (ret < 0)
> +			return ret;
> +		ret = mp2975_vid2direct(info->vrm_version[page], ret);
> +		break;
> +	case PMBUS_VIRT_READ_POUT_MAX:
> +		ret = pmbus_read_word_data(client, page, phase,
> +					   MP2973_MFR_READ_POUT_PK);
> +		break;
> +	case PMBUS_VIRT_READ_IOUT_MAX:
> +		ret = pmbus_read_word_data(client, page, phase,
> +					   MP2973_MFR_READ_IOUT_PK);
> +		break;
> +	case PMBUS_UT_WARN_LIMIT:
> +	case PMBUS_UT_FAULT_LIMIT:
> +	case PMBUS_VIN_UV_WARN_LIMIT:
> +	case PMBUS_VIN_UV_FAULT_LIMIT:
> +	case PMBUS_VOUT_UV_WARN_LIMIT:
> +	case PMBUS_VOUT_OV_WARN_LIMIT:
> +	case PMBUS_VIN_OV_WARN_LIMIT:
> +	case PMBUS_IIN_OC_FAULT_LIMIT:
> +	case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
> +	case PMBUS_IOUT_OC_WARN_LIMIT:
> +	case PMBUS_IOUT_OC_FAULT_LIMIT:
> +	case PMBUS_IOUT_UC_FAULT_LIMIT:
> +	case PMBUS_POUT_OP_FAULT_LIMIT:
> +	case PMBUS_POUT_OP_WARN_LIMIT:
> +	case PMBUS_PIN_OP_WARN_LIMIT:
> +		return -ENXIO;
> +	default:
> +		return -ENODATA;
> +	}
> +
> +	return ret;
> +}
> +
>   static int mp2975_read_word_data(struct i2c_client *client, int page,
>   				 int phase, int reg)
>   {
> @@ -386,7 +486,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
>   }
>   
>   static int
> -mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data,
> +mp297x_identify_vid(struct i2c_client *client, struct mp2975_data *data,

Please refrain from such cosmetic changes. It is perfectly fine to keep
calling the function mp2975_identify_vid() even if it is called for
other chips.

Those changes only make it more difficult to review your patch and,
on top of that, are not really related to introducing support for
the new chips.

>   		    struct pmbus_driver_info *info, u32 reg, int page,
>   		    u32 imvp_bit, u32 vr_bit)
>   {
> @@ -422,7 +522,7 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
>   		return ret;
>   
>   	/* Identify VID mode for rail 1. */
> -	ret = mp2975_identify_vid(client, data, info,
> +	ret = mp297x_identify_vid(client, data, info,
>   				  MP2975_MFR_VR_MULTI_CONFIG_R1, 0,
>   				  MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1);
>   	if (ret < 0)
> @@ -430,10 +530,39 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
>   
>   	/* Identify VID mode for rail 2, if connected. */
>   	if (info->phases[1])
> -		ret = mp2975_identify_vid(client, data, info,
> +		ret = mp297x_identify_vid(client, data, info,
>   					  MP2975_MFR_VR_MULTI_CONFIG_R2, 1,
>   					  MP2975_IMVP9_EN_R2,
>   					  MP2975_VID_STEP_SEL_R2);
> +
> +	return ret;
> +}
> +
> +static int
> +mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
> +			  struct pmbus_driver_info *info)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Identify VID mode for rail 1. */
> +	ret = mp297x_identify_vid(client, data, info,
> +				  MP2973_MFR_VR_MULTI_CONFIG_R1, 0,
> +				  MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Identify VID mode for rail 2, if connected. */
> +	if (info->phases[1])
> +		ret = mp297x_identify_vid(client, data, info,
> +					  MP2973_MFR_VR_MULTI_CONFIG_R2, 1,
> +					  MP2973_IMVP9_EN_R2,
> +					  MP2973_VID_STEP_SEL_R2);
> +
>   	return ret;
>   }
>   
> @@ -532,7 +661,7 @@ mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data,
>   }
>   
>   static int
> -mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
> +mp297x_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
>   		    struct pmbus_driver_info *info, int page)
>   {
>   	int ret;
> @@ -548,17 +677,33 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
>   }
>   
>   static int
> -mp2975_set_vout_format(struct i2c_client *client,
> +mp297x_set_vout_format(struct i2c_client *client,
>   		       struct mp2975_data *data, int page)
>   {
>   	int ret;
>   
> -	ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
> -	if (ret < 0)
> -		return ret;
>   	/* Enable DIRECT VOUT format 1mV/LSB */
> -	ret &= ~MP2975_VOUT_FORMAT;
> -	ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
> +	if (data->chip_id == mp2975) {
> +		ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
> +		if (ret < 0)
> +			return ret;
> +		ret &= ~MP2975_VOUT_FORMAT;
> +		ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
> +	} else {
> +		ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET);
> +		if (ret < 0)
> +			return ret;
> +
> +		if (page == 0) {
> +			ret &= ~MP2973_VOUT_FORMAT_R1;
> +			ret |= MP2973_VOUT_FORMAT_DIRECT_R1;
> +		} else {
> +			ret &= ~MP2973_VOUT_FORMAT_R2;
> +			ret |= MP2973_VOUT_FORMAT_DIRECT_R2;
> +		}
> +
> +		ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, ret);

Same as with the previous patch: The value only needs to be written back if it differs
from the value already configured in the chip.

> +	}
>   	return ret;
>   }
>   
> @@ -605,24 +750,28 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
>   	for (i = 0; i < data->info.pages; i++) {
>   		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
>   		if (ret < 0)
> -			return ret;
> +			continue;
>   
> -		/* Obtain voltage reference offsets. */
> -		ret = mp2975_vref_offset_get(client, data, i);
> +		/*
> +		 * Set VOUT format for READ_VOUT command : direct.
> +		 * Pages on same device can be configured with different
> +		 * formats.
> +		 */
> +		ret = mp297x_set_vout_format(client, data, i);
>   		if (ret < 0)
>   			return ret;
>   
>   		/* Obtain maximum voltage values. */
> -		ret = mp2975_vout_max_get(client, data, info, i);
> +		ret = mp297x_vout_max_get(client, data, info, i);
>   		if (ret < 0)
>   			return ret;
>   
> -		/*
> -		 * Set VOUT format for READ_VOUT command : direct.
> -		 * Pages on same device can be configured with different
> -		 * formats.
> -		 */
> -		ret = mp2975_set_vout_format(client, data, i);
> +		/* Skip if reading Vref is unsupported */
> +		if (data->chip_id != mp2975)
> +			continue;
> +
> +		/* Obtain voltage reference offsets. */
> +		ret = mp2975_vref_offset_get(client, data, i);
>   		if (ret < 0)
>   			return ret;
>   
> @@ -660,6 +809,23 @@ static struct pmbus_driver_info mp2975_info = {
>   	.read_word_data = mp2975_read_word_data,
>   };
>   
> +static struct pmbus_driver_info mp2973_info = {
> +	.pages = 1,
> +	.format[PSC_VOLTAGE_IN] = linear,
> +	.format[PSC_VOLTAGE_OUT] = direct,
> +	.format[PSC_TEMPERATURE] = linear,
> +	.format[PSC_CURRENT_IN] = linear,
> +	.format[PSC_CURRENT_OUT] = linear,
> +	.format[PSC_POWER] = linear,
> +	.m[PSC_VOLTAGE_OUT] = 1,
> +	.R[PSC_VOLTAGE_OUT] = 3,
> +	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
> +		PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
> +		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
> +		PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
> +	.read_word_data = mp2973_read_word_data,
> +};
> +
>   static int mp2975_probe(struct i2c_client *client)
>   {
>   	struct pmbus_driver_info *info;
> @@ -679,6 +845,11 @@ static int mp2975_probe(struct i2c_client *client)
>   	memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
>   	       sizeof(data->max_phases));
>   
> +	if (data->chip_id == mp2975)
> +		memcpy(&data->info, &mp2975_info, sizeof(*info));
> +	else
> +		memcpy(&data->info, &mp2973_info, sizeof(*info));
> +
>   	info = &data->info;
>   
>   	/* Identify multiphase configuration for rail 2. */
> @@ -693,30 +864,37 @@ static int mp2975_probe(struct i2c_client *client)
>   		data->info.func[1] = MP2975_RAIL2_FUNC;
>   	}
>   
> -	/* Identify multiphase configuration. */
> -	ret = mp2975_identify_multiphase(client, data, info);
> -	if (ret)
> -		return ret;
> +	if (data->chip_id == mp2975) {
> +		/* Identify multiphase configuration. */
> +		ret = mp2975_identify_multiphase(client, data, info);
> +		if (ret)
> +			return ret;
>   
> -	/* Identify VID setting per rail. */
> -	ret = mp2975_identify_rails_vid(client, data, info);
> -	if (ret < 0)
> -		return ret;
> +		/* Identify VID setting per rail. */
> +		ret = mp2975_identify_rails_vid(client, data, info);
> +		if (ret < 0)
> +			return ret;
>   
> -	/* Obtain current sense gain of power stage. */
> -	ret = mp2975_current_sense_gain_get(client, data);
> -	if (ret)
> -		return ret;
> +		/* Obtain current sense gain of power stage. */
> +		ret = mp2975_current_sense_gain_get(client, data);
> +		if (ret)
> +			return ret;
>   
> -	/* Obtain voltage reference values. */
> -	ret = mp2975_vref_get(client, data, info);
> -	if (ret)
> -		return ret;
> +		/* Obtain voltage reference values. */
> +		ret = mp2975_vref_get(client, data, info);
> +		if (ret)
> +			return ret;
>   
> -	/* Obtain vout over-voltage scales. */
> -	ret = mp2975_vout_ov_scale_get(client, data, info);
> -	if (ret < 0)
> -		return ret;
> +		/* Obtain vout over-voltage scales. */
> +		ret = mp2975_vout_ov_scale_get(client, data, info);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		/* Identify VID setting per rail. */
> +		ret = mp2973_identify_rails_vid(client, data, info);
> +		if (ret < 0)
> +			return ret;
> +	}
>   
>   	/* Obtain offsets, maximum and format for vout. */
>   	ret = mp2975_vout_per_rail_config_get(client, data, info);
> @@ -727,6 +905,8 @@ static int mp2975_probe(struct i2c_client *client)
>   }
>   
>   static const struct of_device_id __maybe_unused mp2975_of_match[] = {
> +	{.compatible = "mps,mp2971", .data = (void *)mp2971},
> +	{.compatible = "mps,mp2973", .data = (void *)mp2973},
>   	{.compatible = "mps,mp2975", .data = (void *)mp2975},
>   	{}
>   };


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code
  2023-07-12 15:49   ` Guenter Roeck
@ 2023-07-14 11:23     ` Naresh Solanki
  0 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-14 11:23 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: devicetree, Jean Delvare, linux-kernel, linux-hwmon, Patrick Rudolph

Hi Guenter,

On Wed, 12 Jul 2023 at 17:50, Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 7/12/23 04:47, Naresh Solanki wrote:
> > From: Patrick Rudolph <patrick.rudolph@9elements.com>
> >
> > In order to upstream MP2973/MP2971 simplify the code by removing support
> > for various VOUT formats. The MP2973 and MP2971 supports all PMBUS
> > supported formats for VOUT, while the MP2975 only support DIRECT and
> > VID for VOUT.
> >
> > In DIRECT mode all chips report the voltage in 1mV/LSB.
> >
> > Configure the chip to use DIRECT format for VOUT and drop the code
> > conversion code for other formats. The to be added chips MP2973/MP2971
> > will be configured to also report VOUT in DIRECT format.
> >
> > The maximum voltage that can be reported in DIRECT format is 32768mV.
> > This is sufficient as the maximum output voltage for VR12/VR13 is
> > 3040 mV.
> >
> > Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> > Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> > ---
> >   drivers/hwmon/pmbus/mp2975.c | 54 ++++++------------------------------
> >   1 file changed, 8 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
> > index 04778f2dcbdb..ebc9a84b8ad3 100644
> > --- a/drivers/hwmon/pmbus/mp2975.c
> > +++ b/drivers/hwmon/pmbus/mp2975.c
> > @@ -70,7 +70,6 @@ struct mp2975_data {
> >       int vref_off[MP2975_PAGE_NUM];
> >       int vout_max[MP2975_PAGE_NUM];
> >       int vout_ov_fixed[MP2975_PAGE_NUM];
> > -     int vout_format[MP2975_PAGE_NUM];
> >       int curr_sense_gain[MP2975_PAGE_NUM];
> >   };
> >
> > @@ -83,22 +82,6 @@ MODULE_DEVICE_TABLE(i2c, mp2975_id);
> >
> >   #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
> >
> > -static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
> > -{
> > -     switch (reg) {
> > -     case PMBUS_VOUT_MODE:
> > -             /*
> > -              * Enforce VOUT direct format, since device allows to set the
> > -              * different formats for the different rails. Conversion from
> > -              * VID to direct provided by driver internally, in case it is
> > -              * necessary.
> > -              */
> > -             return PB_VOUT_MODE_DIRECT;
> > -     default:
> > -             return -ENODATA;
> > -     }
> > -}
> > -
> >   static int
> >   mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
> >                       u16 mask)
> > @@ -273,24 +256,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
> >               ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 *
> >                                       (ret + 1) * data->vout_scale, 10);
> >               break;
> > -     case PMBUS_READ_VOUT:
> > -             ret = mp2975_read_word_helper(client, page, phase, reg,
> > -                                           GENMASK(11, 0));
> > -             if (ret < 0)
> > -                     return ret;
> > -
> > -             /*
> > -              * READ_VOUT can be provided in VID or direct format. The
> > -              * format type is specified by bit 15 of the register
> > -              * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct
> > -              * format, since device allows to set the different formats for
> > -              * the different rails and also all VOUT limits registers are
> > -              * provided in a direct format. In case format is VID - convert
> > -              * to direct.
> > -              */
> > -             if (data->vout_format[page] == vid)
> > -                     ret = mp2975_vid2direct(info->vrm_version[page], ret);
> > -             break;
> >       case PMBUS_VIRT_READ_POUT_MAX:
> >               ret = mp2975_read_word_helper(client, page, phase,
> >                                             MP2975_MFR_READ_POUT_PK,
> > @@ -578,20 +543,18 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
> >   }
> >
> >   static int
> > -mp2975_identify_vout_format(struct i2c_client *client,
> > -                         struct mp2975_data *data, int page)
> > +mp2975_set_vout_format(struct i2c_client *client,
> > +                    struct mp2975_data *data, int page)
> >   {
> >       int ret;
> >
> >       ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
> >       if (ret < 0)
> >               return ret;
> > -
> > -     if (ret & MP2975_VOUT_FORMAT)
> > -             data->vout_format[page] = vid;
> > -     else
> > -             data->vout_format[page] = direct;
> > -     return 0;
> > +     /* Enable DIRECT VOUT format 1mV/LSB */
> > +     ret &= ~MP2975_VOUT_FORMAT;
> > +     ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
>
> Writing this back is only needed if MP2975_VOUT_FORMAT was not already cleared.
Yes. Will optimize it as:
if (ret & MP2975_VOUT_FORMAT) {
ret &= ~MP2975_VOUT_FORMAT;
ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
}


>
> > +     return ret;
> >   }
> >
> >   static int
> > @@ -650,11 +613,11 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
> >                       return ret;
> >
> >               /*
> > -              * Get VOUT format for READ_VOUT command : VID or direct.
> > +              * Set VOUT format for READ_VOUT command : direct.
> >                * Pages on same device can be configured with different
> >                * formats.
>
> Not sure if this comment still makes sense.
Yes. Updated the comment as below:
/* Set VOUT format for READ_VOUT command : direct. */
ret = mp2975_set_vout_format(....

>
> >                */
> > -             ret = mp2975_identify_vout_format(client, data, i);
> > +             ret = mp2975_set_vout_format(client, data, i);
> >               if (ret < 0)
> >                       return ret;
> >
> > @@ -689,7 +652,6 @@ static struct pmbus_driver_info mp2975_info = {
> >               PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
> >               PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
> >               PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
> > -     .read_byte_data = mp2975_read_byte_data,
> >       .read_word_data = mp2975_read_word_data,
> >   };
> >
>

Regards,
Naresh Solanki

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973
  2023-07-12 17:58   ` Guenter Roeck
@ 2023-07-14 12:25     ` Naresh Solanki
  0 siblings, 0 replies; 13+ messages in thread
From: Naresh Solanki @ 2023-07-14 12:25 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: devicetree, Jean Delvare, linux-kernel, linux-hwmon, Patrick Rudolph

Hi Guenter,


On Wed, 12 Jul 2023 at 19:58, Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 7/12/23 04:47, Naresh Solanki wrote:
> > From: Patrick Rudolph <patrick.rudolph@9elements.com>
> >
> > Add support for MP2971 and MP2973, the successor of MP2975.
> >
> > The major differences are:
> >   - On MP2973 and MP2971 the Vref cannot be read and thus most of
> >     the OVP/current calculations won't work.
> >   - MP2973 and MP2971 also support LINEAR format for VOUT
> >   - MP2973 and MP2971 do not support OVP2
> >   - On MP2973 and MP2971 most registers are in LINEAR format
> >   - The IMVP9_EN bit has a different position
> >   - Per phase current sense haven't been implemented.
> >
> > As on MP2975 most of the FAULT_LIMIT and WARN_LIMIT registers
> > have been redefined and doesn't provide the functionality as
> > defined in PMBUS spec.
> >
> > Tested on MP2973 and MP2971.
> >
> > Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> > Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> > ---
> >   drivers/hwmon/pmbus/mp2975.c | 262 +++++++++++++++++++++++++++++------
> >   1 file changed, 221 insertions(+), 41 deletions(-)
> >
> > diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
> > index 13d8b95eb992..83242595ccbe 100644
> > --- a/drivers/hwmon/pmbus/mp2975.c
> > +++ b/drivers/hwmon/pmbus/mp2975.c
> > @@ -35,6 +35,8 @@
> >   #define MP2975_MFR_OVP_TH_SET               0xe5
> >   #define MP2975_MFR_UVP_SET          0xe6
> >
> > +#define MP2973_MFR_RESO_SET          0xc7
> > +
> >   #define MP2975_VOUT_FORMAT          BIT(15)
> >   #define MP2975_VID_STEP_SEL_R1              BIT(4)
> >   #define MP2975_IMVP9_EN_R1          BIT(13)
> > @@ -49,8 +51,32 @@
> >   #define MP2975_SENSE_AMPL_HALF              2
> >   #define MP2975_VIN_UV_LIMIT_UNIT    8
> >
> > +#define MP2973_VOUT_FORMAT_R1                GENMASK(7, 6)
> > +#define MP2973_VOUT_FORMAT_R2                GENMASK(4, 3)
> > +#define MP2973_VOUT_FORMAT_DIRECT_R1 BIT(7)
> > +#define MP2973_VOUT_FORMAT_LINEAR_R1 BIT(6)
> > +#define MP2973_VOUT_FORMAT_DIRECT_R2 BIT(4)
> > +#define MP2973_VOUT_FORMAT_LINEAR_R2 BIT(3)
> > +
> > +#define MP2973_MFR_VR_MULTI_CONFIG_R1        0x0d
> > +#define MP2973_MFR_VR_MULTI_CONFIG_R2        0x1d
> > +#define MP2973_VID_STEP_SEL_R1               BIT(4)
> > +#define MP2973_IMVP9_EN_R1           BIT(14)
> > +#define MP2973_VID_STEP_SEL_R2               BIT(3)
> > +#define MP2973_IMVP9_EN_R2           BIT(13)
> > +
> > +#define MP2973_MFR_READ_IOUT_PK              0x90
> > +#define MP2973_MFR_READ_POUT_PK              0x91
> > +
> >   #define MP2975_MAX_PHASE_RAIL1      8
> >   #define MP2975_MAX_PHASE_RAIL2      4
> > +
> > +#define MP2973_MAX_PHASE_RAIL1       14
> > +#define MP2973_MAX_PHASE_RAIL2       6
> > +
> > +#define MP2971_MAX_PHASE_RAIL1       8
> > +#define MP2971_MAX_PHASE_RAIL2       3
> > +
> >   #define MP2975_PAGE_NUM             2
> >
> >   #define MP2975_RAIL2_FUNC   (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
> > @@ -58,11 +84,13 @@
> >                                PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
> >
> >   enum chips {
> > -     mp2975
> > +     mp2971, mp2973, mp2975
> >   };
> >
> >   static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
> >       [mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
> > +     [mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 },
> > +     [mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 },
> >   };
> >
> >   struct mp2975_data {
> > @@ -79,6 +107,8 @@ struct mp2975_data {
> >   };
> >
> >   static const struct i2c_device_id mp2975_id[] = {
> > +     {"mp2971", mp2971},
> > +     {"mp2973", mp2973},
> >       {"mp2975", mp2975},
> >       {}
> >   };
> > @@ -215,6 +245,76 @@ mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data,
> >       return ret;
> >   }
> >
> > +static int mp2973_read_word_data(struct i2c_client *client, int page,
> > +                              int phase, int reg)
> > +{
> > +     const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
> > +     struct mp2975_data *data = to_mp2975_data(info);
> > +     int ret;
> > +
> > +     switch (reg) {
> > +     case PMBUS_OT_FAULT_LIMIT:
> > +             ret = mp2975_read_word_helper(client, page, phase, reg,
> > +                                           GENMASK(7, 0));
> > +             break;
> > +     case PMBUS_VIN_OV_FAULT_LIMIT:
> > +             ret = mp2975_read_word_helper(client, page, phase, reg,
> > +                                           GENMASK(7, 0));
> > +             if (ret < 0)
> > +                     return ret;
> > +
> > +             ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT);
> > +             break;
> > +     case PMBUS_VOUT_OV_FAULT_LIMIT:
> > +             /*
> > +              * MP2971 and mp2973 only supports tracking (ovp1) mode.
> > +              */
> > +             ret = mp2975_read_word_helper(client, page, phase,
> > +                                           MP2975_MFR_OVP_TH_SET,
> > +                                           GENMASK(2, 0));
> > +             if (ret < 0)
> > +                     return ret;
> > +
> > +             ret = data->vout_max[page] + 50 * (ret + 1);
> > +             break;
> > +     case PMBUS_VOUT_UV_FAULT_LIMIT:
> > +             ret = mp2975_read_word_helper(client, page, phase, reg,
> > +                                           GENMASK(8, 0));
> > +             if (ret < 0)
> > +                     return ret;
> > +             ret = mp2975_vid2direct(info->vrm_version[page], ret);
> > +             break;
> > +     case PMBUS_VIRT_READ_POUT_MAX:
> > +             ret = pmbus_read_word_data(client, page, phase,
> > +                                        MP2973_MFR_READ_POUT_PK);
> > +             break;
> > +     case PMBUS_VIRT_READ_IOUT_MAX:
> > +             ret = pmbus_read_word_data(client, page, phase,
> > +                                        MP2973_MFR_READ_IOUT_PK);
> > +             break;
> > +     case PMBUS_UT_WARN_LIMIT:
> > +     case PMBUS_UT_FAULT_LIMIT:
> > +     case PMBUS_VIN_UV_WARN_LIMIT:
> > +     case PMBUS_VIN_UV_FAULT_LIMIT:
> > +     case PMBUS_VOUT_UV_WARN_LIMIT:
> > +     case PMBUS_VOUT_OV_WARN_LIMIT:
> > +     case PMBUS_VIN_OV_WARN_LIMIT:
> > +     case PMBUS_IIN_OC_FAULT_LIMIT:
> > +     case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
> > +     case PMBUS_IOUT_OC_WARN_LIMIT:
> > +     case PMBUS_IOUT_OC_FAULT_LIMIT:
> > +     case PMBUS_IOUT_UC_FAULT_LIMIT:
> > +     case PMBUS_POUT_OP_FAULT_LIMIT:
> > +     case PMBUS_POUT_OP_WARN_LIMIT:
> > +     case PMBUS_PIN_OP_WARN_LIMIT:
> > +             return -ENXIO;
> > +     default:
> > +             return -ENODATA;
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> >   static int mp2975_read_word_data(struct i2c_client *client, int page,
> >                                int phase, int reg)
> >   {
> > @@ -386,7 +486,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
> >   }
> >
> >   static int
> > -mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data,
> > +mp297x_identify_vid(struct i2c_client *client, struct mp2975_data *data,
>
> Please refrain from such cosmetic changes. It is perfectly fine to keep
> calling the function mp2975_identify_vid() even if it is called for
> other chips.
>
> Those changes only make it more difficult to review your patch and,
> on top of that, are not really related to introducing support for
> the new chips.
Yes. I agree with you.
I've removed cosmetic changes & diff looks better now.
Will follow this way for future patch.
Thanks.
>
> >                   struct pmbus_driver_info *info, u32 reg, int page,
> >                   u32 imvp_bit, u32 vr_bit)
> >   {
> > @@ -422,7 +522,7 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
> >               return ret;
> >
> >       /* Identify VID mode for rail 1. */
> > -     ret = mp2975_identify_vid(client, data, info,
> > +     ret = mp297x_identify_vid(client, data, info,
> >                                 MP2975_MFR_VR_MULTI_CONFIG_R1, 0,
> >                                 MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1);
> >       if (ret < 0)
> > @@ -430,10 +530,39 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
> >
> >       /* Identify VID mode for rail 2, if connected. */
> >       if (info->phases[1])
> > -             ret = mp2975_identify_vid(client, data, info,
> > +             ret = mp297x_identify_vid(client, data, info,
> >                                         MP2975_MFR_VR_MULTI_CONFIG_R2, 1,
> >                                         MP2975_IMVP9_EN_R2,
> >                                         MP2975_VID_STEP_SEL_R2);
> > +
> > +     return ret;
> > +}
> > +
> > +static int
> > +mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
> > +                       struct pmbus_driver_info *info)
> > +{
> > +     int ret;
> > +
> > +     ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* Identify VID mode for rail 1. */
> > +     ret = mp297x_identify_vid(client, data, info,
> > +                               MP2973_MFR_VR_MULTI_CONFIG_R1, 0,
> > +                               MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1);
> > +
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* Identify VID mode for rail 2, if connected. */
> > +     if (info->phases[1])
> > +             ret = mp297x_identify_vid(client, data, info,
> > +                                       MP2973_MFR_VR_MULTI_CONFIG_R2, 1,
> > +                                       MP2973_IMVP9_EN_R2,
> > +                                       MP2973_VID_STEP_SEL_R2);
> > +
> >       return ret;
> >   }
> >
> > @@ -532,7 +661,7 @@ mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data,
> >   }
> >
> >   static int
> > -mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
> > +mp297x_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
> >                   struct pmbus_driver_info *info, int page)
> >   {
> >       int ret;
> > @@ -548,17 +677,33 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
> >   }
> >
> >   static int
> > -mp2975_set_vout_format(struct i2c_client *client,
> > +mp297x_set_vout_format(struct i2c_client *client,
> >                      struct mp2975_data *data, int page)
> >   {
> >       int ret;
> >
> > -     ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
> > -     if (ret < 0)
> > -             return ret;
> >       /* Enable DIRECT VOUT format 1mV/LSB */
> > -     ret &= ~MP2975_VOUT_FORMAT;
> > -     ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
> > +     if (data->chip_id == mp2975) {
> > +             ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
> > +             if (ret < 0)
> > +                     return ret;
> > +             ret &= ~MP2975_VOUT_FORMAT;
> > +             ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
> > +     } else {
> > +             ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET);
> > +             if (ret < 0)
> > +                     return ret;
> > +
> > +             if (page == 0) {
> > +                     ret &= ~MP2973_VOUT_FORMAT_R1;
> > +                     ret |= MP2973_VOUT_FORMAT_DIRECT_R1;
> > +             } else {
> > +                     ret &= ~MP2973_VOUT_FORMAT_R2;
> > +                     ret |= MP2973_VOUT_FORMAT_DIRECT_R2;
> > +             }
> > +
> > +             ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, ret);
>
> Same as with the previous patch: The value only needs to be written back if it differs
> from the value already configured in the chip.
Yes. I that's efficient approach.
Will introduce a variable 'i' & check for difference at the end & do
i2c write if needed.

>
> > +     }
> >       return ret;
> >   }
> >
> > @@ -605,24 +750,28 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
> >       for (i = 0; i < data->info.pages; i++) {
> >               ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
> >               if (ret < 0)
> > -                     return ret;
> > +                     continue;
> >
> > -             /* Obtain voltage reference offsets. */
> > -             ret = mp2975_vref_offset_get(client, data, i);
> > +             /*
> > +              * Set VOUT format for READ_VOUT command : direct.
> > +              * Pages on same device can be configured with different
> > +              * formats.
> > +              */
> > +             ret = mp297x_set_vout_format(client, data, i);
> >               if (ret < 0)
> >                       return ret;
> >
> >               /* Obtain maximum voltage values. */
> > -             ret = mp2975_vout_max_get(client, data, info, i);
> > +             ret = mp297x_vout_max_get(client, data, info, i);
> >               if (ret < 0)
> >                       return ret;
> >
> > -             /*
> > -              * Set VOUT format for READ_VOUT command : direct.
> > -              * Pages on same device can be configured with different
> > -              * formats.
> > -              */
> > -             ret = mp2975_set_vout_format(client, data, i);
> > +             /* Skip if reading Vref is unsupported */
> > +             if (data->chip_id != mp2975)
> > +                     continue;
> > +
> > +             /* Obtain voltage reference offsets. */
> > +             ret = mp2975_vref_offset_get(client, data, i);
> >               if (ret < 0)
> >                       return ret;
> >
> > @@ -660,6 +809,23 @@ static struct pmbus_driver_info mp2975_info = {
> >       .read_word_data = mp2975_read_word_data,
> >   };
> >
> > +static struct pmbus_driver_info mp2973_info = {
> > +     .pages = 1,
> > +     .format[PSC_VOLTAGE_IN] = linear,
> > +     .format[PSC_VOLTAGE_OUT] = direct,
> > +     .format[PSC_TEMPERATURE] = linear,
> > +     .format[PSC_CURRENT_IN] = linear,
> > +     .format[PSC_CURRENT_OUT] = linear,
> > +     .format[PSC_POWER] = linear,
> > +     .m[PSC_VOLTAGE_OUT] = 1,
> > +     .R[PSC_VOLTAGE_OUT] = 3,
> > +     .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
> > +             PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
> > +             PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
> > +             PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
> > +     .read_word_data = mp2973_read_word_data,
> > +};
> > +
> >   static int mp2975_probe(struct i2c_client *client)
> >   {
> >       struct pmbus_driver_info *info;
> > @@ -679,6 +845,11 @@ static int mp2975_probe(struct i2c_client *client)
> >       memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
> >              sizeof(data->max_phases));
> >
> > +     if (data->chip_id == mp2975)
> > +             memcpy(&data->info, &mp2975_info, sizeof(*info));
> > +     else
> > +             memcpy(&data->info, &mp2973_info, sizeof(*info));
> > +
> >       info = &data->info;
> >
> >       /* Identify multiphase configuration for rail 2. */
> > @@ -693,30 +864,37 @@ static int mp2975_probe(struct i2c_client *client)
> >               data->info.func[1] = MP2975_RAIL2_FUNC;
> >       }
> >
> > -     /* Identify multiphase configuration. */
> > -     ret = mp2975_identify_multiphase(client, data, info);
> > -     if (ret)
> > -             return ret;
> > +     if (data->chip_id == mp2975) {
> > +             /* Identify multiphase configuration. */
> > +             ret = mp2975_identify_multiphase(client, data, info);
> > +             if (ret)
> > +                     return ret;
> >
> > -     /* Identify VID setting per rail. */
> > -     ret = mp2975_identify_rails_vid(client, data, info);
> > -     if (ret < 0)
> > -             return ret;
> > +             /* Identify VID setting per rail. */
> > +             ret = mp2975_identify_rails_vid(client, data, info);
> > +             if (ret < 0)
> > +                     return ret;
> >
> > -     /* Obtain current sense gain of power stage. */
> > -     ret = mp2975_current_sense_gain_get(client, data);
> > -     if (ret)
> > -             return ret;
> > +             /* Obtain current sense gain of power stage. */
> > +             ret = mp2975_current_sense_gain_get(client, data);
> > +             if (ret)
> > +                     return ret;
> >
> > -     /* Obtain voltage reference values. */
> > -     ret = mp2975_vref_get(client, data, info);
> > -     if (ret)
> > -             return ret;
> > +             /* Obtain voltage reference values. */
> > +             ret = mp2975_vref_get(client, data, info);
> > +             if (ret)
> > +                     return ret;
> >
> > -     /* Obtain vout over-voltage scales. */
> > -     ret = mp2975_vout_ov_scale_get(client, data, info);
> > -     if (ret < 0)
> > -             return ret;
> > +             /* Obtain vout over-voltage scales. */
> > +             ret = mp2975_vout_ov_scale_get(client, data, info);
> > +             if (ret < 0)
> > +                     return ret;
> > +     } else {
> > +             /* Identify VID setting per rail. */
> > +             ret = mp2973_identify_rails_vid(client, data, info);
> > +             if (ret < 0)
> > +                     return ret;
> > +     }
> >
> >       /* Obtain offsets, maximum and format for vout. */
> >       ret = mp2975_vout_per_rail_config_get(client, data, info);
> > @@ -727,6 +905,8 @@ static int mp2975_probe(struct i2c_client *client)
> >   }
> >
> >   static const struct of_device_id __maybe_unused mp2975_of_match[] = {
> > +     {.compatible = "mps,mp2971", .data = (void *)mp2971},
> > +     {.compatible = "mps,mp2973", .data = (void *)mp2973},
> >       {.compatible = "mps,mp2975", .data = (void *)mp2975},
> >       {}
> >   };
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-07-14 13:23 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-12 11:47 [PATCH 1/8] hwmon: (pmbus/mp2975) Fix whitespace error Naresh Solanki
2023-07-12 11:47 ` [PATCH 2/8] dt-bindings: trivial-devices: Add MPS MP2971 and MP2973 Naresh Solanki
2023-07-12 11:51   ` Krzysztof Kozlowski
2023-07-12 11:47 ` [PATCH 3/8] hwmon: (pmbus/mp2975) Prepare for MP2973 and MP2971 Naresh Solanki
2023-07-12 11:47 ` [PATCH 4/8] hwmon: (pmbus/mp2975) Simplify VOUT code Naresh Solanki
2023-07-12 15:49   ` Guenter Roeck
2023-07-14 11:23     ` Naresh Solanki
2023-07-12 11:47 ` [PATCH 5/8] hwmon: (pmbus/mp2975) Make phase count variable Naresh Solanki
2023-07-12 11:47 ` [PATCH 6/8] hwmon: (pmbus/mp2975) Add support for MP2971 and MP2973 Naresh Solanki
2023-07-12 17:58   ` Guenter Roeck
2023-07-14 12:25     ` Naresh Solanki
2023-07-12 11:47 ` [PATCH 7/8] hwmon: (pmbus/mp2975) Add regulator support Naresh Solanki
2023-07-12 11:47 ` [PATCH 8/8] hwmon: (pmbus/mp2975) Add OCP limit Naresh Solanki

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.