linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/4] hwmon: (pmbus/core): Generalize pmbus status flag map
@ 2023-02-07 12:02 Naresh Solanki
  2023-02-07 12:02 ` [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status Naresh Solanki
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Naresh Solanki @ 2023-02-07 12:02 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare; +Cc: linux-hwmon, Naresh Solanki, linux-kernel

The PMBus status flag map(pmbus_regulator_status_flag_map) is moved
outside of the regulator #if block and the associated variable/struct
name updated to reflect as generic PMBus status.

This will make the PMBus status flag map more versatile and easier to
incorporate into different contexts and functions.

Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/pmbus_core.c | 94 ++++++++++++++++----------------
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 95e95783972a..1b70cf3be313 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2692,6 +2692,49 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
 	return 0;
 }
 
+/* A PMBus status flag and the corresponding REGULATOR_ERROR_* flag */
+struct pmbus_status_assoc {
+	int pflag, rflag;
+};
+
+/* PMBus->regulator bit mappings for a PMBus status register */
+struct pmbus_status_category {
+	int func;
+	int reg;
+	const struct pmbus_status_assoc *bits; /* zero-terminated */
+};
+
+static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[] = {
+	{
+		.func = PMBUS_HAVE_STATUS_VOUT,
+		.reg = PMBUS_STATUS_VOUT,
+		.bits = (const struct pmbus_status_assoc[]) {
+			{ PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN },
+			{ PB_VOLTAGE_UV_FAULT,   REGULATOR_ERROR_UNDER_VOLTAGE },
+			{ PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN },
+			{ PB_VOLTAGE_OV_FAULT,   REGULATOR_ERROR_REGULATION_OUT },
+			{ },
+		},
+	}, {
+		.func = PMBUS_HAVE_STATUS_IOUT,
+		.reg = PMBUS_STATUS_IOUT,
+		.bits = (const struct pmbus_status_assoc[]) {
+			{ PB_IOUT_OC_WARNING,    REGULATOR_ERROR_OVER_CURRENT_WARN },
+			{ PB_IOUT_OC_FAULT,      REGULATOR_ERROR_OVER_CURRENT },
+			{ PB_IOUT_OC_LV_FAULT,   REGULATOR_ERROR_OVER_CURRENT },
+			{ },
+		},
+	}, {
+		.func = PMBUS_HAVE_STATUS_TEMP,
+		.reg = PMBUS_STATUS_TEMPERATURE,
+		.bits = (const struct pmbus_status_assoc[]) {
+			{ PB_TEMP_OT_WARNING,    REGULATOR_ERROR_OVER_TEMP_WARN },
+			{ PB_TEMP_OT_FAULT,      REGULATOR_ERROR_OVER_TEMP },
+			{ },
+		},
+	},
+};
+
 #if IS_ENABLED(CONFIG_REGULATOR)
 static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
 {
@@ -2738,54 +2781,11 @@ static int pmbus_regulator_disable(struct regulator_dev *rdev)
 	return _pmbus_regulator_on_off(rdev, 0);
 }
 
-/* A PMBus status flag and the corresponding REGULATOR_ERROR_* flag */
-struct pmbus_regulator_status_assoc {
-	int pflag, rflag;
-};
-
-/* PMBus->regulator bit mappings for a PMBus status register */
-struct pmbus_regulator_status_category {
-	int func;
-	int reg;
-	const struct pmbus_regulator_status_assoc *bits; /* zero-terminated */
-};
-
-static const struct pmbus_regulator_status_category pmbus_regulator_flag_map[] = {
-	{
-		.func = PMBUS_HAVE_STATUS_VOUT,
-		.reg = PMBUS_STATUS_VOUT,
-		.bits = (const struct pmbus_regulator_status_assoc[]) {
-			{ PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN },
-			{ PB_VOLTAGE_UV_FAULT,   REGULATOR_ERROR_UNDER_VOLTAGE },
-			{ PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN },
-			{ PB_VOLTAGE_OV_FAULT,   REGULATOR_ERROR_REGULATION_OUT },
-			{ },
-		},
-	}, {
-		.func = PMBUS_HAVE_STATUS_IOUT,
-		.reg = PMBUS_STATUS_IOUT,
-		.bits = (const struct pmbus_regulator_status_assoc[]) {
-			{ PB_IOUT_OC_WARNING,    REGULATOR_ERROR_OVER_CURRENT_WARN },
-			{ PB_IOUT_OC_FAULT,      REGULATOR_ERROR_OVER_CURRENT },
-			{ PB_IOUT_OC_LV_FAULT,   REGULATOR_ERROR_OVER_CURRENT },
-			{ },
-		},
-	}, {
-		.func = PMBUS_HAVE_STATUS_TEMP,
-		.reg = PMBUS_STATUS_TEMPERATURE,
-		.bits = (const struct pmbus_regulator_status_assoc[]) {
-			{ PB_TEMP_OT_WARNING,    REGULATOR_ERROR_OVER_TEMP_WARN },
-			{ PB_TEMP_OT_FAULT,      REGULATOR_ERROR_OVER_TEMP },
-			{ },
-		},
-	},
-};
-
 static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
 {
 	int i, status;
-	const struct pmbus_regulator_status_category *cat;
-	const struct pmbus_regulator_status_assoc *bit;
+	const struct pmbus_status_category *cat;
+	const struct pmbus_status_assoc *bit;
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_data *data = i2c_get_clientdata(client);
@@ -2796,8 +2796,8 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 
 	mutex_lock(&data->update_lock);
 
-	for (i = 0; i < ARRAY_SIZE(pmbus_regulator_flag_map); i++) {
-		cat = &pmbus_regulator_flag_map[i];
+	for (i = 0; i < ARRAY_SIZE(pmbus_status_flag_map); i++) {
+		cat = &pmbus_status_flag_map[i];
 		if (!(func & cat->func))
 			continue;
 

base-commit: 7505dab78f58c953b863753208eeca682e8126ff
-- 
2.39.1


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

* [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status
  2023-02-07 12:02 [PATCH v2 1/4] hwmon: (pmbus/core): Generalize pmbus status flag map Naresh Solanki
@ 2023-02-07 12:02 ` Naresh Solanki
  2023-02-11 15:07   ` Guenter Roeck
  2023-02-07 12:02 ` [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support Naresh Solanki
  2023-02-07 12:02 ` [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events Naresh Solanki
  2 siblings, 1 reply; 12+ messages in thread
From: Naresh Solanki @ 2023-02-07 12:02 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare; +Cc: linux-hwmon, Naresh Solanki, linux-kernel

Add function pmbus get status that can be used to get both pmbus
specific status & regulator status

Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
...
Changes in V2:
- Add __maybe_unused attribute for pmbus_get_status function
- Remove unrelated changes
---
 drivers/hwmon/pmbus/pmbus_core.c | 118 +++++++++++++++++--------------
 1 file changed, 66 insertions(+), 52 deletions(-)

diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 1b70cf3be313..5ccae8126a56 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2735,61 +2735,14 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
 	},
 };
 
-#if IS_ENABLED(CONFIG_REGULATOR)
-static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
-{
-	struct device *dev = rdev_get_dev(rdev);
-	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
-	u8 page = rdev_get_id(rdev);
-	int ret;
-
-	mutex_lock(&data->update_lock);
-	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
-	mutex_unlock(&data->update_lock);
-
-	if (ret < 0)
-		return ret;
-
-	return !!(ret & PB_OPERATION_CONTROL_ON);
-}
-
-static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
-{
-	struct device *dev = rdev_get_dev(rdev);
-	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
-	u8 page = rdev_get_id(rdev);
-	int ret;
-
-	mutex_lock(&data->update_lock);
-	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
-				     PB_OPERATION_CONTROL_ON,
-				     enable ? PB_OPERATION_CONTROL_ON : 0);
-	mutex_unlock(&data->update_lock);
-
-	return ret;
-}
-
-static int pmbus_regulator_enable(struct regulator_dev *rdev)
-{
-	return _pmbus_regulator_on_off(rdev, 1);
-}
-
-static int pmbus_regulator_disable(struct regulator_dev *rdev)
-{
-	return _pmbus_regulator_on_off(rdev, 0);
-}
 
-static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
+static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
 {
-	int i, status;
+	int i, status, ret;
 	const struct pmbus_status_category *cat;
 	const struct pmbus_status_assoc *bit;
-	struct device *dev = rdev_get_dev(rdev);
-	struct i2c_client *client = to_i2c_client(dev->parent);
-	struct pmbus_data *data = i2c_get_clientdata(client);
-	u8 page = rdev_get_id(rdev);
+	struct device *dev = data->dev;
+	struct i2c_client *client = to_i2c_client(dev);
 	int func = data->info->func[page];
 
 	*flags = 0;
@@ -2827,7 +2780,13 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 	if (status < 0)
 		return status;
 
-	if (pmbus_regulator_is_enabled(rdev)) {
+	mutex_lock(&data->update_lock);
+	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+	mutex_unlock(&data->update_lock);
+	if (ret < 0)
+		return status;
+
+	if (ret & PB_OPERATION_CONTROL_ON) {
 		if (status & PB_STATUS_OFF)
 			*flags |= REGULATOR_ERROR_FAIL;
 
@@ -2855,6 +2814,61 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_REGULATOR)
+static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct device *dev = rdev_get_dev(rdev);
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	u8 page = rdev_get_id(rdev);
+	int ret;
+
+	mutex_lock(&data->update_lock);
+	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+	mutex_unlock(&data->update_lock);
+
+	if (ret < 0)
+		return ret;
+
+	return !!(ret & PB_OPERATION_CONTROL_ON);
+}
+
+static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
+{
+	struct device *dev = rdev_get_dev(rdev);
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
+	u8 page = rdev_get_id(rdev);
+	int ret;
+
+	mutex_lock(&data->update_lock);
+	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+				     PB_OPERATION_CONTROL_ON,
+				     enable ? PB_OPERATION_CONTROL_ON : 0);
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static int pmbus_regulator_enable(struct regulator_dev *rdev)
+{
+	return _pmbus_regulator_on_off(rdev, 1);
+}
+
+static int pmbus_regulator_disable(struct regulator_dev *rdev)
+{
+	return _pmbus_regulator_on_off(rdev, 0);
+}
+
+static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
+{
+	struct device *dev = rdev_get_dev(rdev);
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
+
+	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
+}
+
 static int pmbus_regulator_get_status(struct regulator_dev *rdev)
 {
 	struct device *dev = rdev_get_dev(rdev);
-- 
2.39.1


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

* [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support
  2023-02-07 12:02 [PATCH v2 1/4] hwmon: (pmbus/core): Generalize pmbus status flag map Naresh Solanki
  2023-02-07 12:02 ` [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status Naresh Solanki
@ 2023-02-07 12:02 ` Naresh Solanki
  2023-02-11 15:37   ` Guenter Roeck
  2023-02-07 12:02 ` [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events Naresh Solanki
  2 siblings, 1 reply; 12+ messages in thread
From: Naresh Solanki @ 2023-02-07 12:02 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare
  Cc: linux-hwmon, Patrick Rudolph, Naresh Solanki, linux-kernel

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

Implement PMBUS irq handler.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/hwmon/pmbus/pmbus.h      |  2 +-
 drivers/hwmon/pmbus/pmbus_core.c | 85 ++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 713ea7915425..11e84e141126 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -26,7 +26,7 @@ enum pmbus_regs {
 
 	PMBUS_CAPABILITY		= 0x19,
 	PMBUS_QUERY			= 0x1A,
-
+	PMBUS_SMBALERT_MASK		= 0x1B,
 	PMBUS_VOUT_MODE			= 0x20,
 	PMBUS_VOUT_COMMAND		= 0x21,
 	PMBUS_VOUT_TRIM			= 0x22,
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 5ccae8126a56..d5403baad60a 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -3093,6 +3093,85 @@ static int pmbus_regulator_register(struct pmbus_data *data)
 }
 #endif
 
+static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val)
+{
+	int err;
+
+	err = pmbus_check_word_register(client, page, reg | (val << 8));
+	if (err)
+		return err;
+
+	return pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
+}
+
+static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
+{
+	struct pmbus_data *data = pdata;
+	struct i2c_client *client = to_i2c_client(data->dev);
+	int i, status;
+
+	mutex_lock(&data->update_lock);
+	for (i = 0; i < data->info->pages; i++) {
+		status = pmbus_read_status_word(client, i);
+		if (status < 0) {
+			mutex_unlock(&data->update_lock);
+			return status;
+		}
+
+		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
+			pmbus_clear_fault_page(client, i);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data)
+{
+	struct device *dev = &client->dev;
+	const struct pmbus_status_category *cat;
+	const struct pmbus_status_assoc *bit;
+	int i, j, err, ret, func;
+	u8 mask;
+	u8 misc_status[] = {PMBUS_STATUS_CML, PMBUS_STATUS_OTHER, PMBUS_STATUS_MFR_SPECIFIC,
+			    PMBUS_STATUS_FAN_12, PMBUS_STATUS_FAN_34};
+
+	for (i = 0; i < data->info->pages; i++) {
+		func = data->info->func[i];
+
+		for (j = 0; j < ARRAY_SIZE(pmbus_status_flag_map); j++) {
+			cat = &pmbus_status_flag_map[j];
+			if (!(func & cat->func))
+				continue;
+			mask = 0;
+			for (bit = cat->bits; bit->pflag; bit++)
+				mask |= bit->pflag;
+
+			err = pmbus_write_smbalert_mask(client, i, cat->reg, ~mask);
+			if (err)
+				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
+					     cat->reg);
+		}
+
+		for (j = 0; j < ARRAY_SIZE(misc_status); j++) {
+			err = pmbus_write_smbalert_mask(client, i, misc_status[j], 0xff);
+			if (err)
+				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
+					     misc_status[j]);
+		}
+	}
+
+	/* Register notifiers - can fail if IRQ is not given */
+	ret = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler, 0,
+					"pmbus-irq", data);
+	if (ret) {
+		dev_warn(dev, "IRQ disabled %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static struct dentry *pmbus_debugfs_dir;	/* pmbus debugfs directory */
 
 #if IS_ENABLED(CONFIG_DEBUG_FS)
@@ -3455,6 +3534,12 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
 	if (ret)
 		return ret;
 
+	if (client->irq > 0) {
+		ret = pmbus_irq_setup(client, data);
+		if (ret)
+			return ret;
+	}
+
 	ret = pmbus_init_debugfs(client, data);
 	if (ret)
 		dev_warn(dev, "Failed to register debugfs\n");
-- 
2.39.1


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

* [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events
  2023-02-07 12:02 [PATCH v2 1/4] hwmon: (pmbus/core): Generalize pmbus status flag map Naresh Solanki
  2023-02-07 12:02 ` [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status Naresh Solanki
  2023-02-07 12:02 ` [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support Naresh Solanki
@ 2023-02-07 12:02 ` Naresh Solanki
  2023-02-11 15:46   ` Guenter Roeck
  2 siblings, 1 reply; 12+ messages in thread
From: Naresh Solanki @ 2023-02-07 12:02 UTC (permalink / raw)
  To: Guenter Roeck, Jean Delvare
  Cc: linux-hwmon, Patrick Rudolph, Naresh Solanki, linux-kernel

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

Notify hwmon events using the pmbus irq handler.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
...
Changes in V2
- Remove __maybe_unsed attribute as its not needed.
---
 drivers/hwmon/pmbus/pmbus_core.c | 48 ++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index d5403baad60a..f6778a9c7126 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2735,8 +2735,36 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
 	},
 };
 
+#define to_dev_attr(_dev_attr) \
+	container_of(_dev_attr, struct device_attribute, attr)
+
+static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
+{
+	int i;
+
+	for (i = 0; i < data->num_attributes; i++) {
+		struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
+		struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+		int index = attr->index;
+		u16 smask = pb_index_to_mask(index);
+		u8 spage = pb_index_to_page(index);
+		u16 sreg = pb_index_to_reg(index);
+
+		if (reg == sreg && page == spage && (smask & flags)) {
+			dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
+			sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
+			kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
+			flags &= ~smask;
+		}
+
+		if (!flags)
+			break;
+	}
+}
+
+static int pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
+			   bool notify)
 
-static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
 {
 	int i, status, ret;
 	const struct pmbus_status_category *cat;
@@ -2764,6 +2792,10 @@ static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsi
 			if (status & bit->pflag)
 				*flags |= bit->rflag;
 		}
+
+		if (notify && status)
+			pmbus_notify(data, page, cat->reg, status);
+
 	}
 
 	/*
@@ -2866,7 +2898,7 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
 	struct i2c_client *client = to_i2c_client(dev->parent);
 	struct pmbus_data *data = i2c_get_clientdata(client);
 
-	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
+	return pmbus_get_flags(data, rdev_get_id(rdev), flags, false);
 }
 
 static int pmbus_regulator_get_status(struct regulator_dev *rdev)
@@ -3108,10 +3140,14 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
 {
 	struct pmbus_data *data = pdata;
 	struct i2c_client *client = to_i2c_client(data->dev);
-	int i, status;
+	int i, status, ret;
 
-	mutex_lock(&data->update_lock);
 	for (i = 0; i < data->info->pages; i++) {
+		ret = pmbus_get_flags(data, i, &status, true);
+		if (ret)
+			return ret;
+
+		mutex_lock(&data->update_lock);
 		status = pmbus_read_status_word(client, i);
 		if (status < 0) {
 			mutex_unlock(&data->update_lock);
@@ -3120,8 +3156,10 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
 
 		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
 			pmbus_clear_fault_page(client, i);
+
+		mutex_unlock(&data->update_lock);
 	}
-	mutex_unlock(&data->update_lock);
+
 
 	return IRQ_HANDLED;
 }
-- 
2.39.1


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

* Re: [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status
  2023-02-07 12:02 ` [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status Naresh Solanki
@ 2023-02-11 15:07   ` Guenter Roeck
  2023-02-14 14:10     ` Naresh Solanki
  0 siblings, 1 reply; 12+ messages in thread
From: Guenter Roeck @ 2023-02-11 15:07 UTC (permalink / raw)
  To: Naresh Solanki; +Cc: Jean Delvare, linux-hwmon, linux-kernel

On Tue, Feb 07, 2023 at 01:02:39PM +0100, Naresh Solanki wrote:
> Add function pmbus get status that can be used to get both pmbus
> specific status & regulator status
> 
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ...
> Changes in V2:
> - Add __maybe_unused attribute for pmbus_get_status function
> - Remove unrelated changes
> ---
>  drivers/hwmon/pmbus/pmbus_core.c | 118 +++++++++++++++++--------------
>  1 file changed, 66 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index 1b70cf3be313..5ccae8126a56 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c
> @@ -2735,61 +2735,14 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
>  	},
>  };
>  
> -#if IS_ENABLED(CONFIG_REGULATOR)
> -static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
> -{
> -	struct device *dev = rdev_get_dev(rdev);
> -	struct i2c_client *client = to_i2c_client(dev->parent);
> -	struct pmbus_data *data = i2c_get_clientdata(client);
> -	u8 page = rdev_get_id(rdev);
> -	int ret;
> -
> -	mutex_lock(&data->update_lock);
> -	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
> -	mutex_unlock(&data->update_lock);
> -
> -	if (ret < 0)
> -		return ret;
> -
> -	return !!(ret & PB_OPERATION_CONTROL_ON);
> -}
> -
> -static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
> -{
> -	struct device *dev = rdev_get_dev(rdev);
> -	struct i2c_client *client = to_i2c_client(dev->parent);
> -	struct pmbus_data *data = i2c_get_clientdata(client);
> -	u8 page = rdev_get_id(rdev);
> -	int ret;
> -
> -	mutex_lock(&data->update_lock);
> -	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
> -				     PB_OPERATION_CONTROL_ON,
> -				     enable ? PB_OPERATION_CONTROL_ON : 0);
> -	mutex_unlock(&data->update_lock);
> -
> -	return ret;
> -}
> -
> -static int pmbus_regulator_enable(struct regulator_dev *rdev)
> -{
> -	return _pmbus_regulator_on_off(rdev, 1);
> -}
> -
> -static int pmbus_regulator_disable(struct regulator_dev *rdev)
> -{
> -	return _pmbus_regulator_on_off(rdev, 0);
> -}
>  
> -static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
> +static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
>  {
> -	int i, status;
> +	int i, status, ret;
>  	const struct pmbus_status_category *cat;
>  	const struct pmbus_status_assoc *bit;
> -	struct device *dev = rdev_get_dev(rdev);
> -	struct i2c_client *client = to_i2c_client(dev->parent);
> -	struct pmbus_data *data = i2c_get_clientdata(client);
> -	u8 page = rdev_get_id(rdev);
> +	struct device *dev = data->dev;
> +	struct i2c_client *client = to_i2c_client(dev);
>  	int func = data->info->func[page];
>  
>  	*flags = 0;
> @@ -2827,7 +2780,13 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>  	if (status < 0)
>  		return status;
>  
> -	if (pmbus_regulator_is_enabled(rdev)) {
> +	mutex_lock(&data->update_lock);
> +	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
> +	mutex_unlock(&data->update_lock);
> +	if (ret < 0)
> +		return status;
> +
> +	if (ret & PB_OPERATION_CONTROL_ON) {

This code is now executed twice. Please keep the original function,
just rename it to pmbus_is_enabled() or similar, then call it from
pmbus_regulator_is_enabled() which then just needs to adjust the
parameter (and maybe pass 'dev' as argument).

>  		if (status & PB_STATUS_OFF)
>  			*flags |= REGULATOR_ERROR_FAIL;
>  
> @@ -2855,6 +2814,61 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>  	return 0;
>  }
>  
> +#if IS_ENABLED(CONFIG_REGULATOR)
> +static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
> +{
> +	struct device *dev = rdev_get_dev(rdev);
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct pmbus_data *data = i2c_get_clientdata(client);
> +	u8 page = rdev_get_id(rdev);
> +	int ret;
> +
> +	mutex_lock(&data->update_lock);
> +	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
> +	mutex_unlock(&data->update_lock);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return !!(ret & PB_OPERATION_CONTROL_ON);

This could then be as simple as

	return pmbus_is_enabled(rdev_get_dev(rdev));

Thanks,
Guenter

> +}
> +
> +static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
> +{
> +	struct device *dev = rdev_get_dev(rdev);
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct pmbus_data *data = i2c_get_clientdata(client);
> +	u8 page = rdev_get_id(rdev);
> +	int ret;
> +
> +	mutex_lock(&data->update_lock);
> +	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
> +				     PB_OPERATION_CONTROL_ON,
> +				     enable ? PB_OPERATION_CONTROL_ON : 0);
> +	mutex_unlock(&data->update_lock);
> +
> +	return ret;
> +}
> +
> +static int pmbus_regulator_enable(struct regulator_dev *rdev)
> +{
> +	return _pmbus_regulator_on_off(rdev, 1);
> +}
> +
> +static int pmbus_regulator_disable(struct regulator_dev *rdev)
> +{
> +	return _pmbus_regulator_on_off(rdev, 0);
> +}
> +
> +static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
> +{
> +	struct device *dev = rdev_get_dev(rdev);
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct pmbus_data *data = i2c_get_clientdata(client);
> +
> +	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
> +}
> +
>  static int pmbus_regulator_get_status(struct regulator_dev *rdev)
>  {
>  	struct device *dev = rdev_get_dev(rdev);

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

* Re: [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support
  2023-02-07 12:02 ` [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support Naresh Solanki
@ 2023-02-11 15:37   ` Guenter Roeck
  2023-02-14 14:10     ` Naresh Solanki
  0 siblings, 1 reply; 12+ messages in thread
From: Guenter Roeck @ 2023-02-11 15:37 UTC (permalink / raw)
  To: Naresh Solanki; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

On Tue, Feb 07, 2023 at 01:02:40PM +0100, Naresh Solanki wrote:
> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> Implement PMBUS irq handler.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ---
>  drivers/hwmon/pmbus/pmbus.h      |  2 +-
>  drivers/hwmon/pmbus/pmbus_core.c | 85 ++++++++++++++++++++++++++++++++
>  2 files changed, 86 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
> index 713ea7915425..11e84e141126 100644
> --- a/drivers/hwmon/pmbus/pmbus.h
> +++ b/drivers/hwmon/pmbus/pmbus.h
> @@ -26,7 +26,7 @@ enum pmbus_regs {
>  
>  	PMBUS_CAPABILITY		= 0x19,
>  	PMBUS_QUERY			= 0x1A,
> -
> +	PMBUS_SMBALERT_MASK		= 0x1B,
>  	PMBUS_VOUT_MODE			= 0x20,
>  	PMBUS_VOUT_COMMAND		= 0x21,
>  	PMBUS_VOUT_TRIM			= 0x22,
> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index 5ccae8126a56..d5403baad60a 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c
> @@ -3093,6 +3093,85 @@ static int pmbus_regulator_register(struct pmbus_data *data)
>  }
>  #endif
>  
> +static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val)
> +{
> +	int err;
> +
> +	err = pmbus_check_word_register(client, page, reg | (val << 8));
> +	if (err)
> +		return err;

I am not convinced that this is necessary. The next command will return an
error anyway if the register or the specific mask is not supported, so what
is the point ?

> +
> +	return pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
> +}
> +
> +static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
> +{
> +	struct pmbus_data *data = pdata;
> +	struct i2c_client *client = to_i2c_client(data->dev);
> +	int i, status;
> +
> +	mutex_lock(&data->update_lock);
> +	for (i = 0; i < data->info->pages; i++) {
> +		status = pmbus_read_status_word(client, i);
> +		if (status < 0) {
> +			mutex_unlock(&data->update_lock);
> +			return status;
> +		}
> +
> +		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
> +			pmbus_clear_fault_page(client, i);
> +	}
> +	mutex_unlock(&data->update_lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data)
> +{
> +	struct device *dev = &client->dev;
> +	const struct pmbus_status_category *cat;
> +	const struct pmbus_status_assoc *bit;
> +	int i, j, err, ret, func;
> +	u8 mask;
> +	u8 misc_status[] = {PMBUS_STATUS_CML, PMBUS_STATUS_OTHER, PMBUS_STATUS_MFR_SPECIFIC,
> +			    PMBUS_STATUS_FAN_12, PMBUS_STATUS_FAN_34};

static const u8 ... 

> +
> +	for (i = 0; i < data->info->pages; i++) {
> +		func = data->info->func[i];
> +
> +		for (j = 0; j < ARRAY_SIZE(pmbus_status_flag_map); j++) {
> +			cat = &pmbus_status_flag_map[j];
> +			if (!(func & cat->func))
> +				continue;
> +			mask = 0;
> +			for (bit = cat->bits; bit->pflag; bit++)
> +				mask |= bit->pflag;
> +
> +			err = pmbus_write_smbalert_mask(client, i, cat->reg, ~mask);
> +			if (err)
> +				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
> +					     cat->reg);

dev_err implies an error. This is ignored and thus not an error. On top of that,
not all chips support PMBUS_SMBALERT_MASK. All of those would see this message.
We can't have that. At best make it a dev_dbg.

> +		}
> +
> +		for (j = 0; j < ARRAY_SIZE(misc_status); j++) {
> +			err = pmbus_write_smbalert_mask(client, i, misc_status[j], 0xff);
> +			if (err)
> +				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
> +					     misc_status[j]);

We definitely can't have a message here; that would fire for almost
every chip.

> +		}
> +	}
> +
> +	/* Register notifiers - can fail if IRQ is not given */

If there is no irq, what is the point of executing this code in the first
place ? No, wait, in that case the function isn't called in the first place.
I think the comment doesn't add any value and is just confusing.

> +	ret = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler, 0,
> +					"pmbus-irq", data);
> +	if (ret) {

Why both "err" and "ret" ?

> +		dev_warn(dev, "IRQ disabled %d\n", ret);

The calling code aborts, so this should be dev_err() and say something
better than "IRQ disabled"; It should be something like "failed to
request irq".

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static struct dentry *pmbus_debugfs_dir;	/* pmbus debugfs directory */
>  
>  #if IS_ENABLED(CONFIG_DEBUG_FS)
> @@ -3455,6 +3534,12 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
>  	if (ret)
>  		return ret;
>  
> +	if (client->irq > 0) {
> +		ret = pmbus_irq_setup(client, data);
> +		if (ret)
> +			return ret;
> +	}
> +

I think it would be better to have the check in pmbus_irq_setup():

pmbus_irq_setup()
{
	if (!client->irq)
		return 0;
	
	...
}

and here
	ret = pmbus_irq_setup(client, data);
	if (ret)
		return ret;


>  	ret = pmbus_init_debugfs(client, data);
>  	if (ret)
>  		dev_warn(dev, "Failed to register debugfs\n");

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

* Re: [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events
  2023-02-07 12:02 ` [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events Naresh Solanki
@ 2023-02-11 15:46   ` Guenter Roeck
  2023-02-14 14:11     ` Naresh Solanki
  0 siblings, 1 reply; 12+ messages in thread
From: Guenter Roeck @ 2023-02-11 15:46 UTC (permalink / raw)
  To: Naresh Solanki; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

On Tue, Feb 07, 2023 at 01:02:41PM +0100, Naresh Solanki wrote:
> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> Notify hwmon events using the pmbus irq handler.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ...
> Changes in V2
> - Remove __maybe_unsed attribute as its not needed.
> ---
>  drivers/hwmon/pmbus/pmbus_core.c | 48 ++++++++++++++++++++++++++++----
>  1 file changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index d5403baad60a..f6778a9c7126 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c
> @@ -2735,8 +2735,36 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
>  	},
>  };
>  
> +#define to_dev_attr(_dev_attr) \
> +	container_of(_dev_attr, struct device_attribute, attr)
> +
> +static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
> +{
> +	int i;
> +
> +	for (i = 0; i < data->num_attributes; i++) {
> +		struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
> +		struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +		int index = attr->index;
> +		u16 smask = pb_index_to_mask(index);
> +		u8 spage = pb_index_to_page(index);
> +		u16 sreg = pb_index_to_reg(index);
> +
> +		if (reg == sreg && page == spage && (smask & flags)) {
> +			dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
> +			sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
> +			kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
> +			flags &= ~smask;
> +		}
> +
> +		if (!flags)
> +			break;
> +	}
> +}
> +
> +static int pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
> +			   bool notify)
>  
> -static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
>  {
>  	int i, status, ret;
>  	const struct pmbus_status_category *cat;
> @@ -2764,6 +2792,10 @@ static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsi
>  			if (status & bit->pflag)
>  				*flags |= bit->rflag;
>  		}
> +
> +		if (notify && status)
> +			pmbus_notify(data, page, cat->reg, status);
> +
>  	}
>  
>  	/*
> @@ -2866,7 +2898,7 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>  	struct i2c_client *client = to_i2c_client(dev->parent);
>  	struct pmbus_data *data = i2c_get_clientdata(client);
>  
> -	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
> +	return pmbus_get_flags(data, rdev_get_id(rdev), flags, false);
>  }
>  
>  static int pmbus_regulator_get_status(struct regulator_dev *rdev)
> @@ -3108,10 +3140,14 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>  {
>  	struct pmbus_data *data = pdata;
>  	struct i2c_client *client = to_i2c_client(data->dev);
> -	int i, status;
> +	int i, status, ret;
>  
> -	mutex_lock(&data->update_lock);
>  	for (i = 0; i < data->info->pages; i++) {
> +		ret = pmbus_get_flags(data, i, &status, true);
> +		if (ret)
> +			return ret;
> +
> +		mutex_lock(&data->update_lock);

You should introduce a locked version of pmbus_get_flags() and call
that function, and keep the existing locking in place.

>  		status = pmbus_read_status_word(client, i);
>  		if (status < 0) {
>  			mutex_unlock(&data->update_lock);
> @@ -3120,8 +3156,10 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>  
>  		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
>  			pmbus_clear_fault_page(client, i);
> +
> +		mutex_unlock(&data->update_lock);
>  	}
> -	mutex_unlock(&data->update_lock);
> +

This would add a second empty line (not that it matters because the code
should not change the locking in the first place).

>  
>  	return IRQ_HANDLED;
>  }

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

* Re: [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status
  2023-02-11 15:07   ` Guenter Roeck
@ 2023-02-14 14:10     ` Naresh Solanki
  0 siblings, 0 replies; 12+ messages in thread
From: Naresh Solanki @ 2023-02-14 14:10 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Jean Delvare, linux-hwmon, linux-kernel

Hi

On 11-02-2023 08:37 pm, Guenter Roeck wrote:
> On Tue, Feb 07, 2023 at 01:02:39PM +0100, Naresh Solanki wrote:
>> Add function pmbus get status that can be used to get both pmbus
>> specific status & regulator status
>>
>> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
>> ...
>> Changes in V2:
>> - Add __maybe_unused attribute for pmbus_get_status function
>> - Remove unrelated changes
>> ---
>>   drivers/hwmon/pmbus/pmbus_core.c | 118 +++++++++++++++++--------------
>>   1 file changed, 66 insertions(+), 52 deletions(-)
>>
>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
>> index 1b70cf3be313..5ccae8126a56 100644
>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>> @@ -2735,61 +2735,14 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
>>   	},
>>   };
>>   
>> -#if IS_ENABLED(CONFIG_REGULATOR)
>> -static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
>> -{
>> -	struct device *dev = rdev_get_dev(rdev);
>> -	struct i2c_client *client = to_i2c_client(dev->parent);
>> -	struct pmbus_data *data = i2c_get_clientdata(client);
>> -	u8 page = rdev_get_id(rdev);
>> -	int ret;
>> -
>> -	mutex_lock(&data->update_lock);
>> -	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
>> -	mutex_unlock(&data->update_lock);
>> -
>> -	if (ret < 0)
>> -		return ret;
>> -
>> -	return !!(ret & PB_OPERATION_CONTROL_ON);
>> -}
>> -
>> -static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
>> -{
>> -	struct device *dev = rdev_get_dev(rdev);
>> -	struct i2c_client *client = to_i2c_client(dev->parent);
>> -	struct pmbus_data *data = i2c_get_clientdata(client);
>> -	u8 page = rdev_get_id(rdev);
>> -	int ret;
>> -
>> -	mutex_lock(&data->update_lock);
>> -	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
>> -				     PB_OPERATION_CONTROL_ON,
>> -				     enable ? PB_OPERATION_CONTROL_ON : 0);
>> -	mutex_unlock(&data->update_lock);
>> -
>> -	return ret;
>> -}
>> -
>> -static int pmbus_regulator_enable(struct regulator_dev *rdev)
>> -{
>> -	return _pmbus_regulator_on_off(rdev, 1);
>> -}
>> -
>> -static int pmbus_regulator_disable(struct regulator_dev *rdev)
>> -{
>> -	return _pmbus_regulator_on_off(rdev, 0);
>> -}
>>   
>> -static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
>> +static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
>>   {
>> -	int i, status;
>> +	int i, status, ret;
>>   	const struct pmbus_status_category *cat;
>>   	const struct pmbus_status_assoc *bit;
>> -	struct device *dev = rdev_get_dev(rdev);
>> -	struct i2c_client *client = to_i2c_client(dev->parent);
>> -	struct pmbus_data *data = i2c_get_clientdata(client);
>> -	u8 page = rdev_get_id(rdev);
>> +	struct device *dev = data->dev;
>> +	struct i2c_client *client = to_i2c_client(dev);
>>   	int func = data->info->func[page];
>>   
>>   	*flags = 0;
>> @@ -2827,7 +2780,13 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>>   	if (status < 0)
>>   		return status;
>>   
>> -	if (pmbus_regulator_is_enabled(rdev)) {
>> +	mutex_lock(&data->update_lock);
>> +	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
>> +	mutex_unlock(&data->update_lock);
>> +	if (ret < 0)
>> +		return status;
>> +
>> +	if (ret & PB_OPERATION_CONTROL_ON) {
> 
> This code is now executed twice. Please keep the original function,
> just rename it to pmbus_is_enabled() or similar, then call it from
> pmbus_regulator_is_enabled() which then just needs to adjust the
> parameter (and maybe pass 'dev' as argument).
> 
Sure
>>   		if (status & PB_STATUS_OFF)
>>   			*flags |= REGULATOR_ERROR_FAIL;
>>   
>> @@ -2855,6 +2814,61 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>>   	return 0;
>>   }
>>   
>> +#if IS_ENABLED(CONFIG_REGULATOR)
>> +static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
>> +{
>> +	struct device *dev = rdev_get_dev(rdev);
>> +	struct i2c_client *client = to_i2c_client(dev->parent);
>> +	struct pmbus_data *data = i2c_get_clientdata(client);
>> +	u8 page = rdev_get_id(rdev);
>> +	int ret;
>> +
>> +	mutex_lock(&data->update_lock);
>> +	ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
>> +	mutex_unlock(&data->update_lock);
>> +
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return !!(ret & PB_OPERATION_CONTROL_ON);
> 
> This could then be as simple as
> 
> 	return pmbus_is_enabled(rdev_get_dev(rdev));
> 
Sure
> Thanks,
> Guenter
> 
>> +}
>> +
>> +static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
>> +{
>> +	struct device *dev = rdev_get_dev(rdev);
>> +	struct i2c_client *client = to_i2c_client(dev->parent);
>> +	struct pmbus_data *data = i2c_get_clientdata(client);
>> +	u8 page = rdev_get_id(rdev);
>> +	int ret;
>> +
>> +	mutex_lock(&data->update_lock);
>> +	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
>> +				     PB_OPERATION_CONTROL_ON,
>> +				     enable ? PB_OPERATION_CONTROL_ON : 0);
>> +	mutex_unlock(&data->update_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int pmbus_regulator_enable(struct regulator_dev *rdev)
>> +{
>> +	return _pmbus_regulator_on_off(rdev, 1);
>> +}
>> +
>> +static int pmbus_regulator_disable(struct regulator_dev *rdev)
>> +{
>> +	return _pmbus_regulator_on_off(rdev, 0);
>> +}
>> +
>> +static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
>> +{
>> +	struct device *dev = rdev_get_dev(rdev);
>> +	struct i2c_client *client = to_i2c_client(dev->parent);
>> +	struct pmbus_data *data = i2c_get_clientdata(client);
>> +
>> +	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
>> +}
>> +
>>   static int pmbus_regulator_get_status(struct regulator_dev *rdev)
>>   {
>>   	struct device *dev = rdev_get_dev(rdev);

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

* Re: [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support
  2023-02-11 15:37   ` Guenter Roeck
@ 2023-02-14 14:10     ` Naresh Solanki
  0 siblings, 0 replies; 12+ messages in thread
From: Naresh Solanki @ 2023-02-14 14:10 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

Hi

On 11-02-2023 09:07 pm, Guenter Roeck wrote:
> On Tue, Feb 07, 2023 at 01:02:40PM +0100, Naresh Solanki wrote:
>> From: Patrick Rudolph <patrick.rudolph@9elements.com>
>>
>> Implement PMBUS irq handler.
>>
>> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
>> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
>> ---
>>   drivers/hwmon/pmbus/pmbus.h      |  2 +-
>>   drivers/hwmon/pmbus/pmbus_core.c | 85 ++++++++++++++++++++++++++++++++
>>   2 files changed, 86 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
>> index 713ea7915425..11e84e141126 100644
>> --- a/drivers/hwmon/pmbus/pmbus.h
>> +++ b/drivers/hwmon/pmbus/pmbus.h
>> @@ -26,7 +26,7 @@ enum pmbus_regs {
>>   
>>   	PMBUS_CAPABILITY		= 0x19,
>>   	PMBUS_QUERY			= 0x1A,
>> -
>> +	PMBUS_SMBALERT_MASK		= 0x1B,
>>   	PMBUS_VOUT_MODE			= 0x20,
>>   	PMBUS_VOUT_COMMAND		= 0x21,
>>   	PMBUS_VOUT_TRIM			= 0x22,
>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
>> index 5ccae8126a56..d5403baad60a 100644
>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>> @@ -3093,6 +3093,85 @@ static int pmbus_regulator_register(struct pmbus_data *data)
>>   }
>>   #endif
>>   
>> +static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val)
>> +{
>> +	int err;
>> +
>> +	err = pmbus_check_word_register(client, page, reg | (val << 8));
>> +	if (err)
>> +		return err;
> 
> I am not convinced that this is necessary. The next command will return an
> error anyway if the register or the specific mask is not supported, so what
> is the point ?
> 
Sure. will remove.
>> +
>> +	return pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
>> +}
>> +
>> +static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>> +{
>> +	struct pmbus_data *data = pdata;
>> +	struct i2c_client *client = to_i2c_client(data->dev);
>> +	int i, status;
>> +
>> +	mutex_lock(&data->update_lock);
>> +	for (i = 0; i < data->info->pages; i++) {
>> +		status = pmbus_read_status_word(client, i);
>> +		if (status < 0) {
>> +			mutex_unlock(&data->update_lock);
>> +			return status;
>> +		}
>> +
>> +		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
>> +			pmbus_clear_fault_page(client, i);
>> +	}
>> +	mutex_unlock(&data->update_lock);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data)
>> +{
>> +	struct device *dev = &client->dev;
>> +	const struct pmbus_status_category *cat;
>> +	const struct pmbus_status_assoc *bit;
>> +	int i, j, err, ret, func;
>> +	u8 mask;
>> +	u8 misc_status[] = {PMBUS_STATUS_CML, PMBUS_STATUS_OTHER, PMBUS_STATUS_MFR_SPECIFIC,
>> +			    PMBUS_STATUS_FAN_12, PMBUS_STATUS_FAN_34};
> 
> static const u8 ...
> 
Done
>> +
>> +	for (i = 0; i < data->info->pages; i++) {
>> +		func = data->info->func[i];
>> +
>> +		for (j = 0; j < ARRAY_SIZE(pmbus_status_flag_map); j++) {
>> +			cat = &pmbus_status_flag_map[j];
>> +			if (!(func & cat->func))
>> +				continue;
>> +			mask = 0;
>> +			for (bit = cat->bits; bit->pflag; bit++)
>> +				mask |= bit->pflag;
>> +
>> +			err = pmbus_write_smbalert_mask(client, i, cat->reg, ~mask);
>> +			if (err)
>> +				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
>> +					     cat->reg);
> 
> dev_err implies an error. This is ignored and thus not an error. On top of that,
> not all chips support PMBUS_SMBALERT_MASK. All of those would see this message.
> We can't have that. At best make it a dev_dbg.
> 
Sure. Will make it dev_dbg_once.
>> +		}
>> +
>> +		for (j = 0; j < ARRAY_SIZE(misc_status); j++) {
>> +			err = pmbus_write_smbalert_mask(client, i, misc_status[j], 0xff);
>> +			if (err)
>> +				dev_err_once(dev, "Failed to set smbalert for reg 0x%02x\n",
>> +					     misc_status[j]);
> 
> We definitely can't have a message here; that would fire for almost
> every chip.
> 
Sure. Will remove printing of error here.
>> +		}
>> +	}
>> +
>> +	/* Register notifiers - can fail if IRQ is not given */
> 
> If there is no irq, what is the point of executing this code in the first
> place ? No, wait, in that case the function isn't called in the first place.
> I think the comment doesn't add any value and is just confusing.
> 
Will clean this comment.
>> +	ret = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler, 0,
>> +					"pmbus-irq", data);
>> +	if (ret) {
> 
> Why both "err" and "ret" ?
> 
Will replace ret with err.
>> +		dev_warn(dev, "IRQ disabled %d\n", ret);
> 
> The calling code aborts, so this should be dev_err() and say something
> better than "IRQ disabled"; It should be something like "failed to
> request irq".
> 
Sure. Will update to "failed to request an irq"
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   static struct dentry *pmbus_debugfs_dir;	/* pmbus debugfs directory */
>>   
>>   #if IS_ENABLED(CONFIG_DEBUG_FS)
>> @@ -3455,6 +3534,12 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
>>   	if (ret)
>>   		return ret;
>>   
>> +	if (client->irq > 0) {
>> +		ret = pmbus_irq_setup(client, data);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
> 
> I think it would be better to have the check in pmbus_irq_setup():
> 
> pmbus_irq_setup()
> {
> 	if (!client->irq)
> 		return 0;
> 	
> 	...
> }
> 
> and here
> 	ret = pmbus_irq_setup(client, data);
> 	if (ret)
> 		return ret;
> 
> 
Sure
>>   	ret = pmbus_init_debugfs(client, data);
>>   	if (ret)
>>   		dev_warn(dev, "Failed to register debugfs\n");

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

* Re: [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events
  2023-02-11 15:46   ` Guenter Roeck
@ 2023-02-14 14:11     ` Naresh Solanki
  2023-02-14 14:54       ` Guenter Roeck
  0 siblings, 1 reply; 12+ messages in thread
From: Naresh Solanki @ 2023-02-14 14:11 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

Hi,

On 11-02-2023 09:16 pm, Guenter Roeck wrote:
> On Tue, Feb 07, 2023 at 01:02:41PM +0100, Naresh Solanki wrote:
>> From: Patrick Rudolph <patrick.rudolph@9elements.com>
>>
>> Notify hwmon events using the pmbus irq handler.
>>
>> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
>> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
>> ...
>> Changes in V2
>> - Remove __maybe_unsed attribute as its not needed.
>> ---
>>   drivers/hwmon/pmbus/pmbus_core.c | 48 ++++++++++++++++++++++++++++----
>>   1 file changed, 43 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
>> index d5403baad60a..f6778a9c7126 100644
>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>> @@ -2735,8 +2735,36 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
>>   	},
>>   };
>>   
>> +#define to_dev_attr(_dev_attr) \
>> +	container_of(_dev_attr, struct device_attribute, attr)
>> +
>> +static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < data->num_attributes; i++) {
>> +		struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
>> +		struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +		int index = attr->index;
>> +		u16 smask = pb_index_to_mask(index);
>> +		u8 spage = pb_index_to_page(index);
>> +		u16 sreg = pb_index_to_reg(index);
>> +
>> +		if (reg == sreg && page == spage && (smask & flags)) {
>> +			dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
>> +			sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
>> +			kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
>> +			flags &= ~smask;
>> +		}
>> +
>> +		if (!flags)
>> +			break;
>> +	}
>> +}
>> +
>> +static int pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
>> +			   bool notify)
>>   
>> -static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
>>   {
>>   	int i, status, ret;
>>   	const struct pmbus_status_category *cat;
>> @@ -2764,6 +2792,10 @@ static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsi
>>   			if (status & bit->pflag)
>>   				*flags |= bit->rflag;
>>   		}
>> +
>> +		if (notify && status)
>> +			pmbus_notify(data, page, cat->reg, status);
>> +
>>   	}
>>   
>>   	/*
>> @@ -2866,7 +2898,7 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>>   	struct i2c_client *client = to_i2c_client(dev->parent);
>>   	struct pmbus_data *data = i2c_get_clientdata(client);
>>   
>> -	return pmbus_get_flags(data, rdev_get_id(rdev), flags);
>> +	return pmbus_get_flags(data, rdev_get_id(rdev), flags, false);
>>   }
>>   
>>   static int pmbus_regulator_get_status(struct regulator_dev *rdev)
>> @@ -3108,10 +3140,14 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>>   {
>>   	struct pmbus_data *data = pdata;
>>   	struct i2c_client *client = to_i2c_client(data->dev);
>> -	int i, status;
>> +	int i, status, ret;
>>   
>> -	mutex_lock(&data->update_lock);
>>   	for (i = 0; i < data->info->pages; i++) {
>> +		ret = pmbus_get_flags(data, i, &status, true);
>> +		if (ret)
>> +			return ret;
>> +
>> +		mutex_lock(&data->update_lock);
> 
> You should introduce a locked version of pmbus_get_flags() and call
> that function, and keep the existing locking in place.
> 
I'm not sure if you meant to have pmbus_get_flags that wont use lock?

>>   		status = pmbus_read_status_word(client, i);
>>   		if (status < 0) {
>>   			mutex_unlock(&data->update_lock);
>> @@ -3120,8 +3156,10 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>>   
>>   		if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
>>   			pmbus_clear_fault_page(client, i);
>> +
>> +		mutex_unlock(&data->update_lock);
>>   	}
>> -	mutex_unlock(&data->update_lock);
>> +
> 
> This would add a second empty line (not that it matters because the code
> should not change the locking in the first place).
> 
Will remove the new line
>>   
>>   	return IRQ_HANDLED;
>>   }

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

* Re: [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events
  2023-02-14 14:11     ` Naresh Solanki
@ 2023-02-14 14:54       ` Guenter Roeck
  2023-02-14 15:22         ` Naresh Solanki
  0 siblings, 1 reply; 12+ messages in thread
From: Guenter Roeck @ 2023-02-14 14:54 UTC (permalink / raw)
  To: Naresh Solanki; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

On 2/14/23 06:11, Naresh Solanki wrote:
> Hi,
> 
> On 11-02-2023 09:16 pm, Guenter Roeck wrote:
>> On Tue, Feb 07, 2023 at 01:02:41PM +0100, Naresh Solanki wrote:
>>> From: Patrick Rudolph <patrick.rudolph@9elements.com>
>>>
>>> Notify hwmon events using the pmbus irq handler.
>>>
>>> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
>>> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
>>> ...
>>> Changes in V2
>>> - Remove __maybe_unsed attribute as its not needed.
>>> ---
>>>   drivers/hwmon/pmbus/pmbus_core.c | 48 ++++++++++++++++++++++++++++----
>>>   1 file changed, 43 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
>>> index d5403baad60a..f6778a9c7126 100644
>>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>>> @@ -2735,8 +2735,36 @@ static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[]
>>>       },
>>>   };
>>> +#define to_dev_attr(_dev_attr) \
>>> +    container_of(_dev_attr, struct device_attribute, attr)
>>> +
>>> +static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
>>> +{
>>> +    int i;
>>> +
>>> +    for (i = 0; i < data->num_attributes; i++) {
>>> +        struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
>>> +        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>> +        int index = attr->index;
>>> +        u16 smask = pb_index_to_mask(index);
>>> +        u8 spage = pb_index_to_page(index);
>>> +        u16 sreg = pb_index_to_reg(index);
>>> +
>>> +        if (reg == sreg && page == spage && (smask & flags)) {
>>> +            dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
>>> +            sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
>>> +            kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
>>> +            flags &= ~smask;
>>> +        }
>>> +
>>> +        if (!flags)
>>> +            break;
>>> +    }
>>> +}
>>> +
>>> +static int pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
>>> +               bool notify)
>>> -static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags)
>>>   {
>>>       int i, status, ret;
>>>       const struct pmbus_status_category *cat;
>>> @@ -2764,6 +2792,10 @@ static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsi
>>>               if (status & bit->pflag)
>>>                   *flags |= bit->rflag;
>>>           }
>>> +
>>> +        if (notify && status)
>>> +            pmbus_notify(data, page, cat->reg, status);
>>> +
>>>       }
>>>       /*
>>> @@ -2866,7 +2898,7 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>>>       struct i2c_client *client = to_i2c_client(dev->parent);
>>>       struct pmbus_data *data = i2c_get_clientdata(client);
>>> -    return pmbus_get_flags(data, rdev_get_id(rdev), flags);
>>> +    return pmbus_get_flags(data, rdev_get_id(rdev), flags, false);
>>>   }
>>>   static int pmbus_regulator_get_status(struct regulator_dev *rdev)
>>> @@ -3108,10 +3140,14 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>>>   {
>>>       struct pmbus_data *data = pdata;
>>>       struct i2c_client *client = to_i2c_client(data->dev);
>>> -    int i, status;
>>> +    int i, status, ret;
>>> -    mutex_lock(&data->update_lock);
>>>       for (i = 0; i < data->info->pages; i++) {
>>> +        ret = pmbus_get_flags(data, i, &status, true);
>>> +        if (ret)
>>> +            return ret;
>>> +
>>> +        mutex_lock(&data->update_lock);
>>
>> You should introduce a locked version of pmbus_get_flags() and call
>> that function, and keep the existing locking in place.
>>
> I'm not sure if you meant to have pmbus_get_flags that wont use lock?
> 


__pmbus_get_flags(...)
{
	/* no lock acquired here */
}

pmbus_get_flags(...)
{
	int ret;

	mutex_lock(&data->update_lock);
	ret = __pmbus_get_flags(...);
	mutex_unlock(&data->update_lock);
	return ret;
}

Then call __pmbus_get_flags() from above code.

Guenter

>>>           status = pmbus_read_status_word(client, i);
>>>           if (status < 0) {
>>>               mutex_unlock(&data->update_lock);
>>> @@ -3120,8 +3156,10 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
>>>           if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | PB_STATUS_POWER_GOOD_N))
>>>               pmbus_clear_fault_page(client, i);
>>> +
>>> +        mutex_unlock(&data->update_lock);
>>>       }
>>> -    mutex_unlock(&data->update_lock);
>>> +
>>
>> This would add a second empty line (not that it matters because the code
>> should not change the locking in the first place).
>>
> Will remove the new line
>>>       return IRQ_HANDLED;
>>>   }


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

* Re: [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events
  2023-02-14 14:54       ` Guenter Roeck
@ 2023-02-14 15:22         ` Naresh Solanki
  0 siblings, 0 replies; 12+ messages in thread
From: Naresh Solanki @ 2023-02-14 15:22 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Jean Delvare, linux-hwmon, Patrick Rudolph, linux-kernel

Hi

On 14-02-2023 08:24 pm, Guenter Roeck wrote:
> On 2/14/23 06:11, Naresh Solanki wrote:
>> Hi,
>>
>> On 11-02-2023 09:16 pm, Guenter Roeck wrote:
>>> On Tue, Feb 07, 2023 at 01:02:41PM +0100, Naresh Solanki wrote:
>>>> From: Patrick Rudolph <patrick.rudolph@9elements.com>
>>>>
>>>> Notify hwmon events using the pmbus irq handler.
>>>>
>>>> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
>>>> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
>>>> ...
>>>> Changes in V2
>>>> - Remove __maybe_unsed attribute as its not needed.
>>>> ---
>>>>   drivers/hwmon/pmbus/pmbus_core.c | 48 
>>>> ++++++++++++++++++++++++++++----
>>>>   1 file changed, 43 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c 
>>>> b/drivers/hwmon/pmbus/pmbus_core.c
>>>> index d5403baad60a..f6778a9c7126 100644
>>>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>>>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>>>> @@ -2735,8 +2735,36 @@ static const struct pmbus_status_category 
>>>> __maybe_unused pmbus_status_flag_map[]
>>>>       },
>>>>   };
>>>> +#define to_dev_attr(_dev_attr) \
>>>> +    container_of(_dev_attr, struct device_attribute, attr)
>>>> +
>>>> +static void pmbus_notify(struct pmbus_data *data, int page, int 
>>>> reg, int flags)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < data->num_attributes; i++) {
>>>> +        struct device_attribute *da = 
>>>> to_dev_attr(data->group.attrs[i]);
>>>> +        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>>> +        int index = attr->index;
>>>> +        u16 smask = pb_index_to_mask(index);
>>>> +        u8 spage = pb_index_to_page(index);
>>>> +        u16 sreg = pb_index_to_reg(index);
>>>> +
>>>> +        if (reg == sreg && page == spage && (smask & flags)) {
>>>> +            dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
>>>> +            sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
>>>> +            kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
>>>> +            flags &= ~smask;
>>>> +        }
>>>> +
>>>> +        if (!flags)
>>>> +            break;
>>>> +    }
>>>> +}
>>>> +
>>>> +static int pmbus_get_flags(struct pmbus_data *data, u8 page, 
>>>> unsigned int *flags,
>>>> +               bool notify)
>>>> -static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, 
>>>> u8 page, unsigned int *flags)
>>>>   {
>>>>       int i, status, ret;
>>>>       const struct pmbus_status_category *cat;
>>>> @@ -2764,6 +2792,10 @@ static int __maybe_unused 
>>>> pmbus_get_flags(struct pmbus_data *data, u8 page, unsi
>>>>               if (status & bit->pflag)
>>>>                   *flags |= bit->rflag;
>>>>           }
>>>> +
>>>> +        if (notify && status)
>>>> +            pmbus_notify(data, page, cat->reg, status);
>>>> +
>>>>       }
>>>>       /*
>>>> @@ -2866,7 +2898,7 @@ static int 
>>>> pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
>>>>       struct i2c_client *client = to_i2c_client(dev->parent);
>>>>       struct pmbus_data *data = i2c_get_clientdata(client);
>>>> -    return pmbus_get_flags(data, rdev_get_id(rdev), flags);
>>>> +    return pmbus_get_flags(data, rdev_get_id(rdev), flags, false);
>>>>   }
>>>>   static int pmbus_regulator_get_status(struct regulator_dev *rdev)
>>>> @@ -3108,10 +3140,14 @@ static irqreturn_t pmbus_fault_handler(int 
>>>> irq, void *pdata)
>>>>   {
>>>>       struct pmbus_data *data = pdata;
>>>>       struct i2c_client *client = to_i2c_client(data->dev);
>>>> -    int i, status;
>>>> +    int i, status, ret;
>>>> -    mutex_lock(&data->update_lock);
>>>>       for (i = 0; i < data->info->pages; i++) {
>>>> +        ret = pmbus_get_flags(data, i, &status, true);
>>>> +        if (ret)
>>>> +            return ret;
>>>> +
>>>> +        mutex_lock(&data->update_lock);
>>>
>>> You should introduce a locked version of pmbus_get_flags() and call
>>> that function, and keep the existing locking in place.
>>>
>> I'm not sure if you meant to have pmbus_get_flags that wont use lock?
>>
> 
> 
> __pmbus_get_flags(...)
> {
>      /* no lock acquired here */
> }
> 
> pmbus_get_flags(...)
> {
>      int ret;
> 
>      mutex_lock(&data->update_lock);
>      ret = __pmbus_get_flags(...);
>      mutex_unlock(&data->update_lock);
>      return ret;
> }
> 
> Then call __pmbus_get_flags() from above code.
Sure. Will add that change.
> 
> Guenter
> 
>>>>           status = pmbus_read_status_word(client, i);
>>>>           if (status < 0) {
>>>>               mutex_unlock(&data->update_lock);
>>>> @@ -3120,8 +3156,10 @@ static irqreturn_t pmbus_fault_handler(int 
>>>> irq, void *pdata)
>>>>           if (status & ~(PB_STATUS_OFF | PB_STATUS_BUSY | 
>>>> PB_STATUS_POWER_GOOD_N))
>>>>               pmbus_clear_fault_page(client, i);
>>>> +
>>>> +        mutex_unlock(&data->update_lock);
>>>>       }
>>>> -    mutex_unlock(&data->update_lock);
>>>> +
>>>
>>> This would add a second empty line (not that it matters because the code
>>> should not change the locking in the first place).
>>>
>> Will remove the new line
>>>>       return IRQ_HANDLED;
>>>>   }
> 

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

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

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-07 12:02 [PATCH v2 1/4] hwmon: (pmbus/core): Generalize pmbus status flag map Naresh Solanki
2023-02-07 12:02 ` [PATCH v2 2/4] hwmon: (pmbus/core) Generalise pmbus get status Naresh Solanki
2023-02-11 15:07   ` Guenter Roeck
2023-02-14 14:10     ` Naresh Solanki
2023-02-07 12:02 ` [PATCH v2 3/4] hwmon: (pmbus/core): Add interrupt support Naresh Solanki
2023-02-11 15:37   ` Guenter Roeck
2023-02-14 14:10     ` Naresh Solanki
2023-02-07 12:02 ` [PATCH v2 4/4] hwmon: (pmbus/core): Notify hwmon events Naresh Solanki
2023-02-11 15:46   ` Guenter Roeck
2023-02-14 14:11     ` Naresh Solanki
2023-02-14 14:54       ` Guenter Roeck
2023-02-14 15:22         ` Naresh Solanki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).