Skip to contentSkip to conversation

Add max6639 regulator and devicetree support

PATCH Applied Marcello Sylvester Bauer 3 participants 13 messages Jan 27, 2022 – May 19, 2022

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v4 cover Add max6639 regulator and devicetree support

these patches add devicetree support for the Maxim MAX6639.
In addition, it includes optional regulator support for the fan-supply and updates the URL to the datasheet.

Changes in v4:
- dt: rename rpm-range property to rpm-max
- dt: make rpm-max, pulses-per-revolution, and pwm-polarity optional

Changes in v3:
- Remove warning if devm_regulator_get_optional returns an error.

Changes in v2:
- dt: Rename polarity to pwm-polarity.
- Remove unused platform_data header.
- Remove regulator enable/disable calls in pwm_store due to imbalance of calls.
- Move to strict per channel dt configuration without defaults.

Marcello Sylvester Bauer (4):
hwmon: (max6639) Update Datasheet URL
hwmon: (max6639) Add regulator support
dt-bindings: hwmon: Add binding for max6639
hwmon: (max6639) Change from pdata to dt configuration

 .../bindings/hwmon/maxim,max6639.yaml         | 112 +++++++++
 Documentation/hwmon/max6639.rst               |   2 +-
 drivers/hwmon/max6639.c                       | 224 ++++++++++++++----
 include/linux/platform_data/max6639.h         |  15 --
 4 files changed, 286 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
 delete mode 100644 include/linux/platform_data/max6639.h
Signature · 1 line
2.34.1
#1 lore raw

PATCH v4 1/4 hwmon: (max6639) Update Datasheet URL

The old Datasheet does not exist anymore.

---
 Documentation/hwmon/max6639.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/hwmon/max6639.rst +1 -1
index 3da54225f83c..c85d285a3489 100644
@@ -9,7 +9,7 @@ Supported chips:
 
     Addresses scanned: I2C 0x2c, 0x2e, 0x2f
 
-    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6639.pdf
+    Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
 
 Authors:
     - He Changqing <[email protected]>
Signature · 1 line
2.34.1
maintainer Applied
#2 lore raw

Re: [PATCH v4 1/4] hwmon: (max6639) Update Datasheet URL

Quoted 3 lines · Marcello Sylvester Bauer

The old Datasheet does not exist anymore.

Applied.

Thanks,
Guenter

Quoted 17 lines
---
 Documentation/hwmon/max6639.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/hwmon/max6639.rst +1 -1
index 3da54225f83c..c85d285a3489 100644
@@ -9,7 +9,7 @@ Supported chips:
 
     Addresses scanned: I2C 0x2c, 0x2e, 0x2f
 
-    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6639.pdf
+    Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
 
 Authors:
     - He Changqing <[email protected]>
#3 lore raw

PATCH v4 2/4 hwmon: (max6639) Add regulator support

In reply to Marcello Sylvester Bauer

Add regulator support for boards where the fan-supply have to be powered up before it can be used.

---
 drivers/hwmon/max6639.c | 62 +++++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 8 deletions(-)
drivers/hwmon/max6639.c +54 -8
index ccc0f047bd44..14bb7726f8d7 100644
@@ -87,6 +87,9 @@ struct max6639_data {
 	/* Register values initialized only once */
 	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
 	u8 rpm_range;		/* Index in above rpm_ranges table */
+
+	/* Optional regulator for FAN supply */
+	struct regulator *reg;
 };
 
 static struct max6639_data *max6639_update_device(struct device *dev)
@@ -516,6 +519,11 @@ static int max6639_detect(struct i2c_client *client,
 	return 0;
 }
 
+static void max6639_regulator_disable(void *data)
+{
+	regulator_disable(data);
+}
+
 static int max6639_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@@ -528,6 +536,28 @@ static int max6639_probe(struct i2c_client *client)
 		return -ENOMEM;
 
 	data->client = client;
+
+	data->reg = devm_regulator_get_optional(dev, "fan");
+	if (IS_ERR(data->reg)) {
+		if (PTR_ERR(data->reg) != -ENODEV)
+			return PTR_ERR(data->reg);
+
+		data->reg = NULL;
+	} else {
+		/* Spin up fans */
+		err = regulator_enable(data->reg);
+		if (err) {
+			dev_err(dev, "Failed to enable fan supply: %d\n", err);
+			return err;
+		}
+		err = devm_add_action_or_reset(dev, max6639_regulator_disable,
+					       data->reg);
+		if (err) {
+			dev_err(dev, "Failed to register action: %d\n", err);
+			return err;
+		}
+	}
+
 	mutex_init(&data->update_lock);
 
 	/* Initialize the max6639 chip */
@@ -545,23 +575,39 @@ static int max6639_probe(struct i2c_client *client)
 static int max6639_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
-	if (data < 0)
-		return data;
+	struct max6639_data *data = dev_get_drvdata(dev);
+	int ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+
+	if (ret < 0)
+		return ret;
+
+	if (data->reg)
+		regulator_disable(data->reg);
 
 	return i2c_smbus_write_byte_data(client,
-			MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
+			MAX6639_REG_GCONFIG, ret | MAX6639_GCONFIG_STANDBY);
 }
 
 static int max6639_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
-	if (data < 0)
-		return data;
+	struct max6639_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	if (data->reg) {
+		ret = regulator_enable(data->reg);
+		if (ret) {
+			dev_err(dev, "Failed to enable fan supply: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+	if (ret < 0)
+		return ret;
 
 	return i2c_smbus_write_byte_data(client,
-			MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
+			MAX6639_REG_GCONFIG, ret & ~MAX6639_GCONFIG_STANDBY);
 }
 #endif /* CONFIG_PM_SLEEP */
 
Signature · 1 line
2.34.1
maintainer Applied
#4 lore raw

Re: [PATCH v4 2/4] hwmon: (max6639) Add regulator support

Quoted 5 lines · Marcello Sylvester Bauer

Add regulator support for boards where the fan-supply have to be powered up before it can be used.

Applied.

Thanks,
Guenter

Quoted 107 lines
---
 drivers/hwmon/max6639.c | 62 +++++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 8 deletions(-)
drivers/hwmon/max6639.c +54 -8
index ccc0f047bd44..14bb7726f8d7 100644
@@ -87,6 +87,9 @@ struct max6639_data {
 	/* Register values initialized only once */
 	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
 	u8 rpm_range;		/* Index in above rpm_ranges table */
+
+	/* Optional regulator for FAN supply */
+	struct regulator *reg;
 };
 
 static struct max6639_data *max6639_update_device(struct device *dev)
@@ -516,6 +519,11 @@ static int max6639_detect(struct i2c_client *client,
 	return 0;
 }
 
+static void max6639_regulator_disable(void *data)
+{
+	regulator_disable(data);
+}
+
 static int max6639_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@@ -528,6 +536,28 @@ static int max6639_probe(struct i2c_client *client)
 		return -ENOMEM;
 
 	data->client = client;
+
+	data->reg = devm_regulator_get_optional(dev, "fan");
+	if (IS_ERR(data->reg)) {
+		if (PTR_ERR(data->reg) != -ENODEV)
+			return PTR_ERR(data->reg);
+
+		data->reg = NULL;
+	} else {
+		/* Spin up fans */
+		err = regulator_enable(data->reg);
+		if (err) {
+			dev_err(dev, "Failed to enable fan supply: %d\n", err);
+			return err;
+		}
+		err = devm_add_action_or_reset(dev, max6639_regulator_disable,
+					       data->reg);
+		if (err) {
+			dev_err(dev, "Failed to register action: %d\n", err);
+			return err;
+		}
+	}
+
 	mutex_init(&data->update_lock);
 
 	/* Initialize the max6639 chip */
@@ -545,23 +575,39 @@ static int max6639_probe(struct i2c_client *client)
 static int max6639_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
-	if (data < 0)
-		return data;
+	struct max6639_data *data = dev_get_drvdata(dev);
+	int ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+
+	if (ret < 0)
+		return ret;
+
+	if (data->reg)
+		regulator_disable(data->reg);
 
 	return i2c_smbus_write_byte_data(client,
-			MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
+			MAX6639_REG_GCONFIG, ret | MAX6639_GCONFIG_STANDBY);
 }
 
 static int max6639_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
-	if (data < 0)
-		return data;
+	struct max6639_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	if (data->reg) {
+		ret = regulator_enable(data->reg);
+		if (ret) {
+			dev_err(dev, "Failed to enable fan supply: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+	if (ret < 0)
+		return ret;
 
 	return i2c_smbus_write_byte_data(client,
-			MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
+			MAX6639_REG_GCONFIG, ret & ~MAX6639_GCONFIG_STANDBY);
 }
 #endif /* CONFIG_PM_SLEEP */
 
#5 lore raw

PATCH v4 3/4 dt-bindings: hwmon: Add binding for max6639

In reply to Marcello Sylvester Bauer

Add Devicetree binding documentation for Maxim MAX6639 temperature monitor with PWM fan-speed controller.

The devicetree documentation for the SD3078 device tree.

---
 .../bindings/hwmon/maxim,max6639.yaml         | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +112 -0
new file mode 100644
index 000000000000..570e9fe07503
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max6639
+
+maintainers:
+  - Roland Stigge <[email protected]>
+
+description: |
+  The MAX6639 is a 2-channel temperature monitor with dual, automatic, PWM
+  fan-speed controller.  It monitors its own temperature and one external
+  diode-connected transistor or the temperatures of two external diode-connected
+  transistors, typically available in CPUs, FPGAs, or GPUs.
+
+  Datasheets:
+    https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
+
+properties:
+  compatible:
+    enum:
+      - maxim,max6639
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "channel@0"
+  - "channel@1"
+
+additionalProperties: false
+
+patternProperties:
+  "^channel@[0-1]$":
+    type: object
+    description: |
+      Represents the two fans and their specific configuration.
+
+    properties:
+      reg:
+        description: |
+          The fan number.
+        items:
+          minimum: 0
+          maximum: 1
+
+      pwm-polarity:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        default: 1
+        description:
+          PWM output is low at 100% duty cycle when this bit is set to zero. PWM
+          output is high at 100% duty cycle when this bit is set to 1.
+
+      pulses-per-revolution:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [1, 2, 3, 4]
+        default: 2
+        description:
+          Value specifying the number of pulses per revolution of the controlled
+          FAN.
+
+      rpm-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [2000, 4000, 8000, 16000]
+        default: 4000
+        description:
+          Scales the tachometer counter by setting the maximum (full-scale) value
+          of the RPM range.
+
+    required:
+      - reg
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      max6639@10 {
+        compatible = "maxim,max6639";
+        reg = <0x10>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0x0>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+
+        channel@1 {
+          reg = <0x1>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+      };
+    };
+...
Signature · 1 line
2.34.1
maintainer
#6 lore raw

Re: [PATCH v4 3/4] dt-bindings: hwmon: Add binding for max6639

Quoted 6 lines · Marcello Sylvester Bauer

Add Devicetree binding documentation for Maxim MAX6639 temperature monitor with PWM fan-speed controller.

The devicetree documentation for the SD3078 device tree.

lgtm, but we'll have to wait for dt review.

Guenter

Quoted 123 lines
---
 .../bindings/hwmon/maxim,max6639.yaml         | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +112 -0
new file mode 100644
index 000000000000..570e9fe07503
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max6639
+
+maintainers:
+  - Roland Stigge <[email protected]>
+
+description: |
+  The MAX6639 is a 2-channel temperature monitor with dual, automatic, PWM
+  fan-speed controller.  It monitors its own temperature and one external
+  diode-connected transistor or the temperatures of two external diode-connected
+  transistors, typically available in CPUs, FPGAs, or GPUs.
+
+  Datasheets:
+    https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
+
+properties:
+  compatible:
+    enum:
+      - maxim,max6639
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "channel@0"
+  - "channel@1"
+
+additionalProperties: false
+
+patternProperties:
+  "^channel@[0-1]$":
+    type: object
+    description: |
+      Represents the two fans and their specific configuration.
+
+    properties:
+      reg:
+        description: |
+          The fan number.
+        items:
+          minimum: 0
+          maximum: 1
+
+      pwm-polarity:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        default: 1
+        description:
+          PWM output is low at 100% duty cycle when this bit is set to zero. PWM
+          output is high at 100% duty cycle when this bit is set to 1.
+
+      pulses-per-revolution:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [1, 2, 3, 4]
+        default: 2
+        description:
+          Value specifying the number of pulses per revolution of the controlled
+          FAN.
+
+      rpm-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [2000, 4000, 8000, 16000]
+        default: 4000
+        description:
+          Scales the tachometer counter by setting the maximum (full-scale) value
+          of the RPM range.
+
+    required:
+      - reg
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      max6639@10 {
+        compatible = "maxim,max6639";
+        reg = <0x10>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0x0>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+
+        channel@1 {
+          reg = <0x1>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+      };
+    };
+...
maintainer
#7 lore raw

Re: [PATCH v4 3/4] dt-bindings: hwmon: Add binding for max6639

In reply to Marcello Sylvester Bauer
Quoted 52 lines · Marcello Sylvester Bauer

Add Devicetree binding documentation for Maxim MAX6639 temperature monitor with PWM fan-speed controller.

The devicetree documentation for the SD3078 device tree.

---
 .../bindings/hwmon/maxim,max6639.yaml         | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +35 -0
new file mode 100644
index 000000000000..570e9fe07503
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max6639
+
+maintainers:
+  - Roland Stigge <[email protected]>
+
+description: |
+  The MAX6639 is a 2-channel temperature monitor with dual, automatic, PWM
+  fan-speed controller.  It monitors its own temperature and one external
+  diode-connected transistor or the temperatures of two external diode-connected
+  transistors, typically available in CPUs, FPGAs, or GPUs.
+
+  Datasheets:
+    https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
+
+properties:
+  compatible:
+    enum:
+      - maxim,max6639
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 45

Quoted 10 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +10 -0
+required:
+  - compatible
+  - reg
+  - "channel@0"
+  - "channel@1"
+
+additionalProperties: false
+
+patternProperties:
+  "^channel@[0-1]$":

fan@...

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 58

Quoted 13 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +13 -0
+    type: object
+    description: |
+      Represents the two fans and their specific configuration.
+
+    properties:
+      reg:
+        description: |
+          The fan number.
+        items:
+          minimum: 0
+          maximum: 1
+
+      pwm-polarity:

See PWM_POLARITY_INVERTED

Quoted 12 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +12 -0
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        default: 1
+        description:
+          PWM output is low at 100% duty cycle when this bit is set to zero. PWM
+          output is high at 100% duty cycle when this bit is set to 1.
+
+      pulses-per-revolution:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [1, 2, 3, 4]
+        default: 2
+        description:

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 80

Quoted 10 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +10 -0
+          Value specifying the number of pulses per revolution of the controlled
+          FAN.
+
+      rpm-max:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [2000, 4000, 8000, 16000]
+        default: 4000
+        description:
+          Scales the tachometer counter by setting the maximum (full-scale) value
+          of the RPM range.

Why do you need to know the max? I don't recall needing this for other fan controller bindings.

All this needs to be pulled out to a common schema fan that is referenced.

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 38

Quoted 3 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +3 -0
+
+    required:
+      - reg

This should all be in a common fan schema that can be re

Quoted 33 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +29 -0
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      max6639@10 {
+        compatible = "maxim,max6639";
+        reg = <0x10>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0x0>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+
+        channel@1 {
+          reg = <0x1>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+      };
+    };
+...
Signature · 1 line
2.34.1
author
#8 lore raw

Re: [PATCH v4 3/4] dt-bindings: hwmon: Add binding for max6639

Quoted 66 lines · Rob Herring
Quoted 64 lines · Marcello Sylvester Bauer

Add Devicetree binding documentation for Maxim MAX6639 temperature monitor with PWM fan-speed controller.

The devicetree documentation for the SD3078 device tree.

---
 .../bindings/hwmon/maxim,max6639.yaml         | 112
++++++++++++++++++

 1 file changed, 112 insertions(+)

 create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml

diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file mode 100644
index 000000000000..570e9fe07503

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +14 -0
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max6639
+
+maintainers:
+  - Roland Stigge <[email protected]>
+
+description: |
+  The MAX6639 is a 2-channel temperature monitor with dual,

automatic, PWM
+  fan-speed controller.  It monitors its own temperature and one external
+  diode-connected transistor or the temperatures of two external diode-connected
+  transistors, typically available in CPUs, FPGAs, or GPUs. +
+  Datasheets:
+
https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +19 -0
+
+properties:
+  compatible:
+    enum:
+      - maxim,max6639
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "channel@0"
Quoted 8 lines

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 45

Quoted 6 lines

+  - "channel@1"

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +5 -0
+
+additionalProperties: false
+
+patternProperties:
+  "^channel@[0-1]$":

fan@...

Makes sense. Looks like i have to adapt the driver code too.

Quoted 17 lines
Quoted 4 lines

+    type: object
+    description: |
+      Represents the two fans and their specific configuration.

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 58

Quoted 10 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +10 -0
+
+    properties:
+      reg:
+        description: |
+          The fan number.
+        items:
+          minimum: 0
+          maximum: 1
+
+      pwm-polarity:

See PWM_POLARITY_INVERTED

Indeed, Thanks.

Quoted 23 lines
Quoted 23 lines

+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [0, 1]
+        default: 1
+        description:
+          PWM output is low at 100% duty cycle when this bit is set to zero. PWM
+          output is high at 100% duty cycle when this bit is set to 1.
+
+      pulses-per-revolution:
+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [1, 2, 3, 4]
+        default: 2
+        description:
+          Value specifying the number of pulses per revolution of the controlled
+          FAN.
+
+      rpm-max:
+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [2000, 4000, 8000, 16000]
+        default: 4000

Quoted 8 lines
Quoted 4 lines

+        description:
+          Scales the tachometer counter by setting the maximum (full-scale) value
+          of the RPM range.

Why do you need to know the max? I don't recall needing this for other
fan controller bindings.

This information is required for setting the internal clock of the tachometer. (See: page 8 table 3). However, we could make it a vendor specific property. In this case i would rather call it "maxim,rpm- range", since this is how it is referred to.

Or is there a better how to define this information inside dt?

Quoted 3 lines

All this needs to be pulled out to a common schema fan that is referenced.

Ack

thanks,
Marcello

Quoted 39 lines
Quoted 4 lines

+
+    required:
+      - reg

This should all be in a common fan schema that can be re

Quoted 33 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +29 -0
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      max6639@10 {
+        compatible = "maxim,max6639";
+        reg = <0x10>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0x0>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+
+        channel@1 {
+          reg = <0x1>;
+          pwm-polarity = <1>;
+          pulses-per-revolution = <2>;
+          rpm-range = <4000>;
+        };
+      };
+    };
+...
Signature · 1 line
2.34.1
maintainer
#9 lore raw

Re: [PATCH v4 3/4] dt-bindings: hwmon: Add binding for max6639

Quoted 130 lines · sylv
Quoted 66 lines · Rob Herring
Quoted 64 lines · Marcello Sylvester Bauer

Add Devicetree binding documentation for Maxim MAX6639 temperature monitor with PWM fan-speed controller.

The devicetree documentation for the SD3078 device tree.

---
  .../bindings/hwmon/maxim,max6639.yaml         | 112
++++++++++++++++++
  1 file changed, 112 insertions(+)

 create mode 100644
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml

diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file mode 100644
index 000000000000..570e9fe07503

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +14 -0
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim max6639
+
+maintainers:
+  - Roland Stigge <[email protected]>
+
+description: |
+  The MAX6639 is a 2-channel temperature monitor with dual,

automatic, PWM
+  fan-speed controller.  It monitors its own temperature and one external
+  diode-connected transistor or the temperatures of two external diode-connected
+  transistors, typically available in CPUs, FPGAs, or GPUs.

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +3 -0
+
+  Datasheets:
+

https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +19 -0
+
+properties:
+  compatible:
+    enum:
+      - maxim,max6639
+
+  reg:
+    maxItems: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "channel@0"
Quoted 8 lines

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 45

Quoted 6 lines

+  - "channel@1"

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +5 -0
+
+additionalProperties: false
+
+patternProperties:
+  "^channel@[0-1]$":

fan@...

Makes sense. Looks like i have to adapt the driver code too.

Quoted 17 lines
Quoted 4 lines

+    type: object
+    description: |
+      Represents the two fans and their specific configuration.

Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml line 58

Quoted 10 lines
Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml new file +10 -0
+
+    properties:
+      reg:
+        description: |
+          The fan number.
+        items:
+          minimum: 0
+          maximum: 1
+
+      pwm-polarity:

See PWM_POLARITY_INVERTED

Indeed, Thanks.

Quoted 23 lines
Quoted 23 lines

+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [0, 1]
+        default: 1
+        description:
+          PWM output is low at 100% duty cycle when this bit is set to zero. PWM
+          output is high at 100% duty cycle when this bit is set to 1.
+
+      pulses-per-revolution:
+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [1, 2, 3, 4]
+        default: 2
+        description:
+          Value specifying the number of pulses per revolution of the controlled
+          FAN.
+
+      rpm-max:
+        $ref: /schemas/types.yaml#/definitions/uint32 +        enum: [2000, 4000, 8000, 16000]
+        default: 4000

Quoted 8 lines
Quoted 4 lines

+        description:
+          Scales the tachometer counter by setting the maximum (full-scale) value
+          of the RPM range.

Why do you need to know the max? I don't recall needing this for other
fan controller bindings.

Quoted 5 lines

This information is required for setting the internal clock of the tachometer. (See: page 8 table 3). However, we could make it a vendor specific property. In this case i would rather call it "maxim,rpm- range", since this is how it is referred to.

The maximum fan speed is a common property of fan controllers. Exceeding the configured value would typically generate an alarm. The same applies to minimum fan speed. As an example, ADT7470 supports both minimum and maximum fan speed and generates an alarm if the fan speed is too low and if it is too high.

At some point we will need properties for both the minimum and for the maximum fan speed. Seems to me we might as well define it now.

Guenter

#10 lore raw

PATCH v4 4/4 hwmon: (max6639) Change from pdata to dt configuration

In reply to Marcello Sylvester Bauer

max6639_platform_data is not used by any in-kernel driver and does not address the MAX6639 channels separately. Move to device tree configuration with explicit properties to configure each channel.

Non-DT platform can still use this module with its default configuration.

---
 drivers/hwmon/max6639.c               | 162 +++++++++++++++++++-------
 include/linux/platform_data/max6639.h |  15 ---
 2 files changed, 119 insertions(+), 58 deletions(-)
 delete mode 100644 include/linux/platform_data/max6639.h
drivers/hwmon/max6639.c +119 -43
index 14bb7726f8d7..717bde3392bd 100644
@@ -19,7 +19,6 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
-#include <linux/platform_data/max6639.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
@@ -85,8 +84,9 @@ struct max6639_data {
 	u8 temp_ot[2];		/* OT Temperature, 0..255 C (->_emergency) */
 
 	/* Register values initialized only once */
-	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
-	u8 rpm_range;		/* Index in above rpm_ranges table */
+	u8 ppr[2];		/* Pulses per rotation 0..3 for 1..4 ppr */
+	u8 rpm_range[2];	/* Index in above rpm_ranges table */
+	u8 pwm_polarity[2];	/* Fans PWM polarity, 0..1 */
 
 	/* Optional regulator for FAN supply */
 	struct regulator *reg;
@@ -319,7 +319,7 @@ static ssize_t fan_input_show(struct device *dev,
 		return PTR_ERR(data);
 
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
-		       data->rpm_range));
+		       data->rpm_range[attr->index]));
 }
 
 static ssize_t alarm_show(struct device *dev,
@@ -386,28 +386,26 @@ static struct attribute *max6639_attrs[] = {
 ATTRIBUTE_GROUPS(max6639);
 
 /*
- *  returns respective index in rpm_ranges table
- *  1 by default on invalid range
+ *  Get respective index in rpm_ranges table
  */
-static int rpm_range_to_reg(int range)
+static int rpm_range_to_index(u8 *index, int range)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
-		if (rpm_ranges[i] == range)
-			return i;
+		if (rpm_ranges[i] == range) {
+			*index = i;
+			return 0;
+		}
 	}
 
-	return 1; /* default: 4000 RPM */
+	return -EINVAL;
 }
 
 static int max6639_init_client(struct i2c_client *client,
 			       struct max6639_data *data)
 {
-	struct max6639_platform_data *max6639_info =
-		dev_get_platdata(&client->dev);
 	int i;
-	int rpm_range = 1; /* default: 4000 RPM */
 	int err;
 
 	/* Reset chip to default values, see below for GCONFIG setup */
@@ -416,43 +414,25 @@ static int max6639_init_client(struct i2c_client *client,
 	if (err)
 		goto exit;
 
-	/* Fans pulse per revolution is 2 by default */
-	if (max6639_info && max6639_info->ppr > 0 &&
-			max6639_info->ppr < 5)
-		data->ppr = max6639_info->ppr;
-	else
-		data->ppr = 2;
-	data->ppr -= 1;
-
-	if (max6639_info)
-		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
-	data->rpm_range = rpm_range;
-
 	for (i = 0; i < 2; i++) {
 
 		/* Set Fan pulse per revolution */
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_FAN_PPR(i),
-				data->ppr << 6);
+				data->ppr[i] << 6);
 		if (err)
 			goto exit;
 
 		/* Fans config PWM, RPM */
 		err = i2c_smbus_write_byte_data(client,
 			MAX6639_REG_FAN_CONFIG1(i),
-			MAX6639_FAN_CONFIG1_PWM | rpm_range);
+			MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]);
 		if (err)
 			goto exit;
 
-		/* Fans PWM polarity high by default */
-		if (max6639_info && max6639_info->pwm_polarity == 0)
-			err = i2c_smbus_write_byte_data(client,
-				MAX6639_REG_FAN_CONFIG2a(i), 0x00);
-		else
-			err = i2c_smbus_write_byte_data(client,
-				MAX6639_REG_FAN_CONFIG2a(i), 0x02);
-		if (err)
-			goto exit;
+		/* Fans PWM polarity */
+		err = i2c_smbus_write_byte_data(client,
+			MAX6639_REG_FAN_CONFIG2a(i), data->pwm_polarity[i] ? 0x00 : 0x02);
 
 		/*
 		 * /THERM full speed enable,
@@ -464,10 +444,6 @@ static int max6639_init_client(struct i2c_client *client,
 		if (err)
 			goto exit;
 
-		/* Max. temp. 80C/90C/100C */
-		data->temp_therm[i] = 80;
-		data->temp_alert[i] = 90;
-		data->temp_ot[i] = 100;
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_THERM_LIMIT(i),
 				data->temp_therm[i]);
@@ -483,8 +459,6 @@ static int max6639_init_client(struct i2c_client *client,
 		if (err)
 			goto exit;
 
-		/* PWM 120/120 (i.e. 100%) */
-		data->pwm[i] = 120;
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
 		if (err)
@@ -524,12 +498,87 @@ static void max6639_regulator_disable(void *data)
 	regulator_disable(data);
 }
 
+static int max6639_probe_child_from_dt(struct i2c_client *client,
+				      struct device_node *child,
+				      struct max6639_data *data)
+
+{
+	struct device *dev = &client->dev;
+	u32 i, val;
+	int err;
+
+	err = of_property_read_u32(child, "reg", &i);
+	if (err) {
+		dev_err(dev, "missing reg property of %pOFn\n", child);
+		return err;
+	}
+
+	if (i >= 2) {
+		dev_err(dev, "invalid reg %d of %pOFn\n", i, child);
+		return -EINVAL;
+	}
+
+	err = of_property_read_u32(child, "pulses-per-revolution", &val);
+	if (!err) {
+		if (val < 0 || val > 5) {
+			dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child);
+			return -EINVAL;
+		}
+		data->ppr[i] = val;
+	}
+
+	err = of_property_read_u32(child, "rpm-max", &val);
+	if (!err) {
+		err = rpm_range_to_index(&data->rpm_range[i], val);
+		if (err) {
+			dev_err(dev, "invalid rpm-max %d of %pOFn\n", val, child);
+			return err;
+		}
+	}
+
+	err = of_property_read_u32(child, "pwm-polarity", &val);
+	if (!err) {
+		if (val > 1) {
+			dev_err(dev, "invalid pwm-polarity %d of %pOFn\n", val, child);
+			return -EINVAL;
+		}
+		data->pwm_polarity[i] = val;
+	}
+
+	return 0;
+}
+
+static int max6639_probe_from_dt(struct i2c_client *client, struct max6639_data *data)
+{
+	struct device *dev = &client->dev;
+	const struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int err;
+
+	/* Compatible with non-DT platforms */
+	if (!np)
+		return 0;
+
+	for_each_child_of_node(np, child) {
+		if (strcmp(child->name, "channel"))
+			continue;
+
+		err = max6639_probe_child_from_dt(client, child, data);
+		if (err) {
+			of_node_put(child);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
 static int max6639_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
 	struct max6639_data *data;
 	struct device *hwmon_dev;
-	int err;
+	int err, i;
 
 	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
 	if (!data)
@@ -560,6 +609,24 @@ static int max6639_probe(struct i2c_client *client)
 
 	mutex_init(&data->update_lock);
 
+	/* default values */
+	for (i = 0; i < 2; i++) {
+		/* 4000 RPM */
+		data->rpm_range[i] = 1;
+		data->ppr[i] = 2;
+		data->pwm_polarity[i] = 1;
+		/* Max. temp. 80C/90C/100C */
+		data->temp_therm[i] = 80;
+		data->temp_alert[i] = 90;
+		data->temp_ot[i] = 100;
+		/* PWM 120/120 (i.e. 100%) */
+		data->pwm[i] = 120;
+	}
+
+	err = max6639_probe_from_dt(client, data);
+	if (err)
+		return err;
+
 	/* Initialize the max6639 chip */
 	err = max6639_init_client(client, data);
 	if (err < 0)
@@ -618,6 +685,14 @@ static const struct i2c_device_id max6639_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, max6639_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id maxim_of_platform_match[] = {
+	{.compatible = "maxim,max6639"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, maxim_of_platform_match);
+#endif
+
 static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
 
 static struct i2c_driver max6639_driver = {
@@ -625,6 +700,7 @@ static struct i2c_driver max6639_driver = {
 	.driver = {
 		   .name = "max6639",
 		   .pm = &max6639_pm_ops,
+		   .of_match_table = of_match_ptr(maxim_of_platform_match),
 		   },
 	.probe_new = max6639_probe,
 	.id_table = max6639_id,
include/linux/platform_data/max6639.h deleted +0 -15
deleted file mode 100644
index 65bfdb4fdc15..000000000000
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_MAX6639_H
-#define _LINUX_MAX6639_H
-
-#include <linux/types.h>
-
-/* platform data for the MAX6639 temperature sensor and fan control */
-
-struct max6639_platform_data {
-	bool pwm_polarity;	/* Polarity low (0) or high (1, default) */
-	int ppr;		/* Pulses per rotation 1..4 (default == 2) */
-	int rpm_range;		/* 2000, 4000 (default), 8000 or 16000 */
-};
-
-#endif /* _LINUX_MAX6639_H */
Signature · 1 line
2.34.1
maintainer
#11 lore raw

Re: [PATCH v4 4/4] hwmon: (max6639) Change from pdata to dt configuration

Quoted 48 lines · Marcello Sylvester Bauer

max6639_platform_data is not used by any in-kernel driver and does not address the MAX6639 channels separately. Move to device tree configuration with explicit properties to configure each channel.

Non-DT platform can still use this module with its default configuration.

---
 drivers/hwmon/max6639.c               | 162 +++++++++++++++++++-------
 include/linux/platform_data/max6639.h |  15 ---
 2 files changed, 119 insertions(+), 58 deletions(-)
 delete mode 100644 include/linux/platform_data/max6639.h
drivers/hwmon/max6639.c +4 -4
index 14bb7726f8d7..717bde3392bd 100644
@@ -19,7 +19,6 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
-#include <linux/platform_data/max6639.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
@@ -85,8 +84,9 @@ struct max6639_data {
 	u8 temp_ot[2];		/* OT Temperature, 0..255 C (->_emergency) */
 
 	/* Register values initialized only once */
-	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
-	u8 rpm_range;		/* Index in above rpm_ranges table */
+	u8 ppr[2];		/* Pulses per rotation 0..3 for 1..4 ppr */
+	u8 rpm_range[2];	/* Index in above rpm_ranges table */
+	u8 pwm_polarity[2];	/* Fans PWM polarity, 0..1 */
 
 	/* Optional regulator for FAN supply */
 	struct regulator *reg;
@@ -319,7 +319,7 @@ static ssize_t fan_input_show(struct device *dev,
 		return PTR_ERR(data);
 
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
-		       data->rpm_range));
+		       data->rpm_range[attr->index]));
 }
 
 static ssize_t alarm_show(struct device *dev,

drivers/hwmon/max6639.c static struct attribute *max6639_attrs[] = { · line 391

Quoted 9 lines
drivers/hwmon/max6639.c +2 -3
@@ -386,28 +386,26 @@ static struct attribute *max6639_attrs[] = {
 ATTRIBUTE_GROUPS(max6639);
 
 /*
- *  returns respective index in rpm_ranges table
- *  1 by default on invalid range
+ *  Get respective index in rpm_ranges table
  */
-static int rpm_range_to_reg(int range)
+static int rpm_range_to_index(u8 *index, int range)

That doesn't reauire an extra parameter; the return value can be used both as index and error return value.

drivers/hwmon/max6639.c static struct attribute *max6639_attrs[] = { · line 396

Quoted 7 lines
drivers/hwmon/max6639.c +1 -2
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
-		if (rpm_ranges[i] == range)
-			return i;
+		if (rpm_ranges[i] == range) {

Keep

			return i;
Quoted 118 lines
drivers/hwmon/max6639.c +35 -33
+			*index = i;
+			return 0;
+		}
 	}
 
-	return 1; /* default: 4000 RPM */
+	return -EINVAL;
 }
 
 static int max6639_init_client(struct i2c_client *client,
 			       struct max6639_data *data)
 {
-	struct max6639_platform_data *max6639_info =
-		dev_get_platdata(&client->dev);
 	int i;
-	int rpm_range = 1; /* default: 4000 RPM */
 	int err;
 
 	/* Reset chip to default values, see below for GCONFIG setup */
@@ -416,43 +414,25 @@ static int max6639_init_client(struct i2c_client *client,
 	if (err)
 		goto exit;
 
-	/* Fans pulse per revolution is 2 by default */
-	if (max6639_info && max6639_info->ppr > 0 &&
-			max6639_info->ppr < 5)
-		data->ppr = max6639_info->ppr;
-	else
-		data->ppr = 2;
-	data->ppr -= 1;
-
-	if (max6639_info)
-		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
-	data->rpm_range = rpm_range;
-
 	for (i = 0; i < 2; i++) {
 
 		/* Set Fan pulse per revolution */
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_FAN_PPR(i),
-				data->ppr << 6);
+				data->ppr[i] << 6);
 		if (err)
 			goto exit;
 
 		/* Fans config PWM, RPM */
 		err = i2c_smbus_write_byte_data(client,
 			MAX6639_REG_FAN_CONFIG1(i),
-			MAX6639_FAN_CONFIG1_PWM | rpm_range);
+			MAX6639_FAN_CONFIG1_PWM | data->rpm_range[i]);
 		if (err)
 			goto exit;
 
-		/* Fans PWM polarity high by default */
-		if (max6639_info && max6639_info->pwm_polarity == 0)
-			err = i2c_smbus_write_byte_data(client,
-				MAX6639_REG_FAN_CONFIG2a(i), 0x00);
-		else
-			err = i2c_smbus_write_byte_data(client,
-				MAX6639_REG_FAN_CONFIG2a(i), 0x02);
-		if (err)
-			goto exit;
+		/* Fans PWM polarity */
+		err = i2c_smbus_write_byte_data(client,
+			MAX6639_REG_FAN_CONFIG2a(i), data->pwm_polarity[i] ? 0x00 : 0x02);
 
 		/*
 		 * /THERM full speed enable,
@@ -464,10 +444,6 @@ static int max6639_init_client(struct i2c_client *client,
 		if (err)
 			goto exit;
 
-		/* Max. temp. 80C/90C/100C */
-		data->temp_therm[i] = 80;
-		data->temp_alert[i] = 90;
-		data->temp_ot[i] = 100;
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_THERM_LIMIT(i),
 				data->temp_therm[i]);
@@ -483,8 +459,6 @@ static int max6639_init_client(struct i2c_client *client,
 		if (err)
 			goto exit;
 
-		/* PWM 120/120 (i.e. 100%) */
-		data->pwm[i] = 120;
 		err = i2c_smbus_write_byte_data(client,
 				MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
 		if (err)
@@ -524,12 +498,87 @@ static void max6639_regulator_disable(void *data)
 	regulator_disable(data);
 }
 
+static int max6639_probe_child_from_dt(struct i2c_client *client,
+				      struct device_node *child,
+				      struct max6639_data *data)
+
+{
+	struct device *dev = &client->dev;
+	u32 i, val;
+	int err;
+
+	err = of_property_read_u32(child, "reg", &i);
+	if (err) {
+		dev_err(dev, "missing reg property of %pOFn\n", child);
+		return err;
+	}
+
+	if (i >= 2) {
+		dev_err(dev, "invalid reg %d of %pOFn\n", i, child);
+		return -EINVAL;
+	}
+
+	err = of_property_read_u32(child, "pulses-per-revolution", &val);
+	if (!err) {
+		if (val < 0 || val > 5) {
+			dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child);
+			return -EINVAL;
+		}

drivers/hwmon/max6639.c static void max6639_regulator_disable(void *data) · line 536

Quoted 10 lines
drivers/hwmon/max6639.c +10 -0
+		data->ppr[i] = val;
+	}
+
+	err = of_property_read_u32(child, "rpm-max", &val);
+	if (!err) {
+		err = rpm_range_to_index(&data->rpm_range[i], val);
+		if (err) {
+			dev_err(dev, "invalid rpm-max %d of %pOFn\n", val, child);
+			return err;
+		}
		err = rpm_range_to_index(val);
		if (err < 0) {
			dev_err(dev, "invalid rpm-max %d of %pOFn\n", val, child);
			return err;
		}
		data->rpm_range[i] = err;
Quoted 118 lines
drivers/hwmon/max6639.c +67 -1
+	}
+
+	err = of_property_read_u32(child, "pwm-polarity", &val);
+	if (!err) {
+		if (val > 1) {
+			dev_err(dev, "invalid pwm-polarity %d of %pOFn\n", val, child);
+			return -EINVAL;
+		}
+		data->pwm_polarity[i] = val;
+	}
+
+	return 0;
+}
+
+static int max6639_probe_from_dt(struct i2c_client *client, struct max6639_data *data)
+{
+	struct device *dev = &client->dev;
+	const struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int err;
+
+	/* Compatible with non-DT platforms */
+	if (!np)
+		return 0;
+
+	for_each_child_of_node(np, child) {
+		if (strcmp(child->name, "channel"))
+			continue;
+
+		err = max6639_probe_child_from_dt(client, child, data);
+		if (err) {
+			of_node_put(child);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
 static int max6639_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
 	struct max6639_data *data;
 	struct device *hwmon_dev;
-	int err;
+	int err, i;
 
 	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
 	if (!data)
@@ -560,6 +609,24 @@ static int max6639_probe(struct i2c_client *client)
 
 	mutex_init(&data->update_lock);
 
+	/* default values */
+	for (i = 0; i < 2; i++) {
+		/* 4000 RPM */
+		data->rpm_range[i] = 1;
+		data->ppr[i] = 2;
+		data->pwm_polarity[i] = 1;
+		/* Max. temp. 80C/90C/100C */
+		data->temp_therm[i] = 80;
+		data->temp_alert[i] = 90;
+		data->temp_ot[i] = 100;
+		/* PWM 120/120 (i.e. 100%) */
+		data->pwm[i] = 120;
+	}
+
+	err = max6639_probe_from_dt(client, data);
+	if (err)
+		return err;
+
 	/* Initialize the max6639 chip */
 	err = max6639_init_client(client, data);
 	if (err < 0)
@@ -618,6 +685,14 @@ static const struct i2c_device_id max6639_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, max6639_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id maxim_of_platform_match[] = {
+	{.compatible = "maxim,max6639"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, maxim_of_platform_match);
+#endif
+
 static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
 
 static struct i2c_driver max6639_driver = {
@@ -625,6 +700,7 @@ static struct i2c_driver max6639_driver = {
 	.driver = {
 		   .name = "max6639",
 		   .pm = &max6639_pm_ops,
+		   .of_match_table = of_match_ptr(maxim_of_platform_match),
 		   },
 	.probe_new = max6639_probe,
 	.id_table = max6639_id,
include/linux/platform_data/max6639.h deleted +0 -15
deleted file mode 100644
index 65bfdb4fdc15..000000000000
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_MAX6639_H
-#define _LINUX_MAX6639_H
-
-#include <linux/types.h>
-
-/* platform data for the MAX6639 temperature sensor and fan control */
-
-struct max6639_platform_data {
-	bool pwm_polarity;	/* Polarity low (0) or high (1, default) */
-	int ppr;		/* Pulses per rotation 1..4 (default == 2) */
-	int rpm_range;		/* 2000, 4000 (default), 8000 or 16000 */
-};
-
-#endif /* _LINUX_MAX6639_H */
#12 lore raw

Re: [PATCH v4 4/4] hwmon: (max6639) Change from pdata to dt configuration

Quoted 65 lines · Guenter Roeck
Quoted 63 lines · Marcello Sylvester Bauer

max6639_platform_data is not used by any in-kernel driver and does not
address the MAX6639 channels separately. Move to device tree configuration with explicit properties to configure each channel.

Non-DT platform can still use this module with its default configuration.

---
 drivers/hwmon/max6639.c               | 162 +++++++++++++++++++---
----
 include/linux/platform_data/max6639.h |  15 ---

 2 files changed, 119 insertions(+), 58 deletions(-)

 delete mode 100644 include/linux/platform_data/max6639.h

drivers/hwmon/max6639.c +0 -1
index 14bb7726f8d7..717bde3392bd 100644
@@ -19,7 +19,6 @@
  #include <linux/hwmon-sysfs.h>
  #include <linux/err.h>
  #include <linux/mutex.h>
-#include <linux/platform_data/max6639.h>


 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };

drivers/hwmon/max6639.c +0 -0
@@ -85,8 +84,9 @@ struct max6639_data {

        u8 temp_ot[2];          /* OT Temperature, 0..255 C (-

Quoted 1 line

_emergency) */


        /* Register values initialized only once */
-       u8 ppr;                 /* Pulses per rotation 0..3 for 1..4 ppr */
-       u8 rpm_range;           /* Index in above rpm_ranges table */
+       u8 ppr[2];              /* Pulses per rotation 0..3 for 1..4 ppr */
+       u8 rpm_range[2];        /* Index in above rpm_ranges table */
+       u8 pwm_polarity[2];     /* Fans PWM polarity, 0..1 */
        /* Optional regulator for FAN supply */
        struct regulator *reg;

drivers/hwmon/max6639.c +0 -0
@@ -319,7 +319,7 @@ static ssize_t fan_input_show(struct device
 *dev,
                 return PTR_ERR(data);


        return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr-

Quoted 1 line

index],

-                      data->rpm_range));
+                      data->rpm_range[attr->index])); }

 static ssize_t alarm_show(struct device *dev,

drivers/hwmon/max6639.c +0 -0
@@ -386,28 +386,26 @@ static struct attribute *max6639_attrs[] = {
  ATTRIBUTE_GROUPS(max6639);


 /*
- *  returns respective index in rpm_ranges table
- *  1 by default on invalid range

Quoted 8 lines

drivers/hwmon/max6639.c static struct attribute *max6639_attrs[] = { · line 391

Quoted 4 lines

+ *  Get respective index in rpm_ranges table
  */

drivers/hwmon/max6639.c +1 -1
-static int rpm_range_to_reg(int range)
+static int rpm_range_to_index(u8 *index, int range)

That doesn't reauire an extra parameter; the return value can be used both
as index and error return value.

makes sense. ack

Quoted 10 lines
Quoted 8 lines

 {
        int i;

        for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) { -               if (rpm_ranges[i] == range)
-                       return i;
+               if (rpm_ranges[i] == range) {

Keep

ack

Quoted 146 lines

                        return i;

Quoted 135 lines

+                       *index = i;
+                       return 0;
+               }
        }

-       return 1; /* default: 4000 RPM */
+       return -EINVAL;
 }

 static int max6639_init_client(struct i2c_client *client, struct max6639_data *data) {
-       struct max6639_platform_data *max6639_info = -               dev_get_platdata(&client->dev);
        int i;
-       int rpm_range = 1; /* default: 4000 RPM */ int err;

        /* Reset chip to default values, see below for GCONFIG setup */

drivers/hwmon/max6639.c +0 -0
@@ -416,43 +414,25 @@ static int max6639_init_client(struct
 i2c_client *client,
         if (err)
                 goto exit;


-       /* Fans pulse per revolution is 2 by default */ -       if (max6639_info && max6639_info->ppr > 0 && -                       max6639_info->ppr < 5)
-               data->ppr = max6639_info->ppr;
-       else
-               data->ppr = 2;
-       data->ppr -= 1;
-
-       if (max6639_info)
-               rpm_range = rpm_range_to_reg(max6639_info-

Quoted 1 line

rpm_range);

-       data->rpm_range = rpm_range;
-
        for (i = 0; i < 2; i++) {

                /* Set Fan pulse per revolution */ err = i2c_smbus_write_byte_data(client, MAX6639_REG_FAN_PPR(i), -                               data->ppr << 6);
+                               data->ppr[i] << 6); if (err)
                        goto exit;

                /* Fans config PWM, RPM */
                err = i2c_smbus_write_byte_data(client, MAX6639_REG_FAN_CONFIG1(i), -                       MAX6639_FAN_CONFIG1_PWM | rpm_range); +                       MAX6639_FAN_CONFIG1_PWM | data-

Quoted 1 line

rpm_range[i]);

                if (err)
                        goto exit;

-               /* Fans PWM polarity high by default */ -               if (max6639_info && max6639_info->pwm_polarity ==
0)
-                       err = i2c_smbus_write_byte_data(client, -                               MAX6639_REG_FAN_CONFIG2a(i), 0x00); -               else
-                       err = i2c_smbus_write_byte_data(client, -                               MAX6639_REG_FAN_CONFIG2a(i), 0x02); -               if (err)
-                       goto exit;
+               /* Fans PWM polarity */
+               err = i2c_smbus_write_byte_data(client, +                       MAX6639_REG_FAN_CONFIG2a(i), data-

Quoted 1 line

pwm_polarity[i] ? 0x00 : 0x02);


                /*
                 * /THERM full speed enable,

drivers/hwmon/max6639.c +0 -0
@@ -464,10 +444,6 @@ static int max6639_init_client(struct
 i2c_client *client,
                 if (err)
                         goto exit;


-               /* Max. temp. 80C/90C/100C */
-               data->temp_therm[i] = 80;
-               data->temp_alert[i] = 90;
-               data->temp_ot[i] = 100;
                err = i2c_smbus_write_byte_data(client, MAX6639_REG_THERM_LIMIT(i), data->temp_therm[i]);

drivers/hwmon/max6639.c +0 -0
@@ -483,8 +459,6 @@ static int max6639_init_client(struct
 i2c_client *client,
                 if (err)
                         goto exit;


-               /* PWM 120/120 (i.e. 100%) */
-               data->pwm[i] = 120;
                err = i2c_smbus_write_byte_data(client, MAX6639_REG_TARGTDUTY(i), data-

Quoted 1 line

pwm[i]);

                if (err)

drivers/hwmon/max6639.c +0 -0
@@ -524,12 +498,87 @@ static void max6639_regulator_disable(void
 *data)
         regulator_disable(data);
  }

drivers/hwmon/max6639.c +12 -0
+static int max6639_probe_child_from_dt(struct i2c_client *client,
+                                     struct device_node *child,
+                                     struct max6639_data *data)
+
+{
+       struct device *dev = &client->dev;
+       u32 i, val;
+       int err;
+
+       err = of_property_read_u32(child, "reg", &i);
+       if (err) {
+               dev_err(dev, "missing reg property of %pOFn\n",

child);
+               return err;
+       }
+
+       if (i >= 2) {
+               dev_err(dev, "invalid reg %d of %pOFn\n", i, child);
+               return -EINVAL;
+       }
+
+       err = of_property_read_u32(child, "pulses-per-revolution", &val);
+       if (!err) {
+               if (val < 0 || val > 5) {
+                       dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child);
+                       return -EINVAL;
+               }
+               data->ppr[i] = val;
+       }
+

Quoted 8 lines

+       err = of_property_read_u32(child, "rpm-max", &val); +       if (!err) {
+               err = rpm_range_to_index(&data->rpm_range[i], val); +               if (err) {
+                       dev_err(dev, "invalid rpm-max %d of %pOFn\n", val, child);
+                       return err;
+               }

Quoted 7 lines

                err = rpm_range_to_index(val);
                if (err < 0) {
                        dev_err(dev, "invalid rpm-max %d of %pOFn\n", val, child);
                        return err;
                }
                data->rpm_range[i] = err;

thanks. ack

Quoted 132 lines
Quoted 132 lines

+       }
+
+       err = of_property_read_u32(child, "pwm-polarity", &val); +       if (!err) {
+               if (val > 1) {
+                       dev_err(dev, "invalid pwm-polarity %d of %pOFn\n", val, child);
+                       return -EINVAL;
+               }
+               data->pwm_polarity[i] = val;
+       }

drivers/hwmon/max6639.c +5 -0
+
+       return 0;
+}
+
+static int max6639_probe_from_dt(struct i2c_client *client, struct

max6639_data *data)

drivers/hwmon/max6639.c +15 -0
+{
+       struct device *dev = &client->dev;
+       const struct device_node *np = dev->of_node;
+       struct device_node *child;
+       int err;
+
+       /* Compatible with non-DT platforms */
+       if (!np)
+               return 0;
+
+       for_each_child_of_node(np, child) {
+               if (strcmp(child->name, "channel"))
+                       continue;
+
+               err = max6639_probe_child_from_dt(client, child,

data);
+               if (err) {
+                       of_node_put(child);
+                       return err;
+               }
+       }

drivers/hwmon/max6639.c +4 -0
+
+       return 0;
+}
+

 static int max6639_probe(struct i2c_client *client) {
        struct device *dev = &client->dev;
        struct max6639_data *data;
        struct device *hwmon_dev;
-       int err;
+       int err, i;

        data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
        if (!data)

drivers/hwmon/max6639.c +0 -0
@@ -560,6 +609,24 @@ static int max6639_probe(struct i2c_client
 *client)


        mutex_init(&data->update_lock);

+       /* default values */
+       for (i = 0; i < 2; i++) {
+               /* 4000 RPM */
+               data->rpm_range[i] = 1;
+               data->ppr[i] = 2;
+               data->pwm_polarity[i] = 1;
+               /* Max. temp. 80C/90C/100C */
+               data->temp_therm[i] = 80;
+               data->temp_alert[i] = 90;
+               data->temp_ot[i] = 100;
+               /* PWM 120/120 (i.e. 100%) */
+               data->pwm[i] = 120;
+       }

drivers/hwmon/max6639.c +5 -0
+
+       err = max6639_probe_from_dt(client, data);
+       if (err)
+               return err;
+

        /* Initialize the max6639 chip */
        err = max6639_init_client(client, data);
        if (err < 0)

drivers/hwmon/max6639.c +0 -0
@@ -618,6 +685,14 @@ static const struct i2c_device_id max6639_id[]
 = {


 MODULE_DEVICE_TABLE(i2c, max6639_id);

drivers/hwmon/max6639.c +8 -0
+#ifdef CONFIG_OF
+static const struct of_device_id maxim_of_platform_match[] = {
+       {.compatible = "maxim,max6639"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, maxim_of_platform_match);
+#endif
+

 static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);

 static struct i2c_driver max6639_driver = {

drivers/hwmon/max6639.c +1 -0
@@ -625,6 +700,7 @@ static struct i2c_driver max6639_driver = {
         .driver = {
                    .name = "max6639",
                    .pm = &max6639_pm_ops,
+                  .of_match_table =
 of_match_ptr(maxim_of_platform_match),
                    },
         .probe_new = max6639_probe,

        .id_table = max6639_id,

include/linux/platform_data/max6639.h deleted +0 -7
deleted file mode 100644
index 65bfdb4fdc15..000000000000
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_MAX6639_H
-#define _LINUX_MAX6639_H
-
-#include <linux/types.h>
-
-/* platform data for the MAX6639 temperature sensor and fan

control */

include/linux/platform_data/max6639.h deleted +0 -3
-
-struct max6639_platform_data {
-       bool pwm_polarity;      /* Polarity low (0) or high (1,

default) */
-       int ppr;                /* Pulses per rotation 1..4 (default == 2) */
-       int rpm_range;          /* 2000, 4000 (default), 8000 or 16000 */

include/linux/platform_data/max6639.h deleted +0 -3
-};
-
-#endif /* _LINUX_MAX6639_H */