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 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 | 235 ++++++++++++++----
include/linux/platform_data/max6639.h | 15 --
4 files changed, 297 insertions(+), 67 deletions(-)
create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
delete mode 100644 include/linux/platform_data/max6639.h
--
2.33.1
Add regulator support for boards where the fan-supply have to be
powered up before it can be used.
Signed-off-by: Patrick Rudolph <[email protected]>
Signed-off-by: Marcello Sylvester Bauer <[email protected]>
---
drivers/hwmon/max6639.c | 64 +++++++++++++++++++++++++++++++++++------
1 file changed, 56 insertions(+), 8 deletions(-)
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index ccc0f047bd44..0b241f029229 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -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,30 @@ 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) {
+ err = (int)PTR_ERR(data->reg);
+ dev_warn(dev, "Failed looking up fan supply: %d\n", err);
+ return err;
+ }
+ 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 +577,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 */
--
2.33.1
max6639_platform_data is not used by any in-kernel driver and does not
address the MAX6639 channels separately. Move to a strict device tree
configuration with explicit properties to configure each channel.
Non-DT platform can still use this module with its default
configuration.
Signed-off-by: Marcello Sylvester Bauer <[email protected]>
---
drivers/hwmon/max6639.c | 171 +++++++++++++++++++-------
include/linux/platform_data/max6639.h | 15 ---
2 files changed, 128 insertions(+), 58 deletions(-)
delete mode 100644 include/linux/platform_data/max6639.h
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 0b241f029229..26772532bce4 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -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,96 @@ 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) {
+ dev_err(dev, "missing pulses-per-revolution property of %pOFn\n", child);
+ return 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-range", &val);
+ if (err) {
+ dev_err(dev, "missing rpm-range property of %pOFn\n", child);
+ return err;
+ }
+
+ err = rpm_range_to_index(&data->rpm_range[i], val);
+ if (err) {
+ dev_err(dev, "invalid rpm-range %d of %pOFn\n", val, child);
+ return err;
+ }
+
+ err = of_property_read_u32(child, "pwm-polarity", &val);
+ if (err) {
+ dev_err(dev, "missing pwm-polarity property of %pOFn\n", child);
+ return 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)
@@ -562,6 +620,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)
@@ -620,6 +696,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 = {
@@ -627,6 +711,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,
diff --git a/include/linux/platform_data/max6639.h b/include/linux/platform_data/max6639.h
deleted file mode 100644
index 65bfdb4fdc15..000000000000
--- a/include/linux/platform_data/max6639.h
+++ /dev/null
@@ -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 */
--
2.33.1
Add Devicetree binding documentation for Maxim MAX6639 temperature
monitor with PWM fan-speed controller.
The devicetree documentation for the SD3078 device tree.
Signed-off-by: Marcello Sylvester Bauer <[email protected]>
---
.../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..7093cbeba44b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
@@ -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]
+ 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]
+ description:
+ Value specifying the number of pulses per revolution of the controlled
+ FAN.
+
+ rpm-range:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [2000, 4000, 8000, 16000]
+ description:
+ Scales the tachometer counter by setting the maximum (full-scale) value
+ of the RPM range.
+
+ required:
+ - reg
+ - pwm-polarity
+ - pulses-per-revolution
+ - rpm-range
+
+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>;
+ };
+ };
+ };
+...
--
2.33.1
The old Datasheet does not exist anymore.
Signed-off-by: Marcello Sylvester Bauer <[email protected]>
---
Documentation/hwmon/max6639.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/hwmon/max6639.rst b/Documentation/hwmon/max6639.rst
index 3da54225f83c..c85d285a3489 100644
--- a/Documentation/hwmon/max6639.rst
+++ b/Documentation/hwmon/max6639.rst
@@ -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]>
--
2.33.1
On Mon, Jan 17, 2022 at 11:40:24AM +0100, Marcello Sylvester Bauer wrote:
> Add regulator support for boards where the fan-supply have to be
> powered up before it can be used.
>
> Signed-off-by: Patrick Rudolph <[email protected]>
> Signed-off-by: Marcello Sylvester Bauer <[email protected]>
> ---
> drivers/hwmon/max6639.c | 64 +++++++++++++++++++++++++++++++++++------
> 1 file changed, 56 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
> index ccc0f047bd44..0b241f029229 100644
> --- a/drivers/hwmon/max6639.c
> +++ b/drivers/hwmon/max6639.c
> @@ -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,30 @@ 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) {
> + err = (int)PTR_ERR(data->reg);
> + dev_warn(dev, "Failed looking up fan supply: %d\n", err);
This could be -EPROBE_DEFER. I do not think that warrants
an error message.
> + return err;
> + }
> + 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 +577,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 */
>
On Tue, 2022-01-18 at 08:11 -0800, Guenter Roeck wrote:
> On Mon, Jan 17, 2022 at 11:40:24AM +0100, Marcello Sylvester Bauer wrote:
> > Add regulator support for boards where the fan-supply have to be
> > powered up before it can be used.
> >
> > Signed-off-by: Patrick Rudolph <[email protected]>
> > Signed-off-by: Marcello Sylvester Bauer <[email protected]>
> > ---
> > drivers/hwmon/max6639.c | 64 +++++++++++++++++++++++++++++++++++------
> > 1 file changed, 56 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
> > index ccc0f047bd44..0b241f029229 100644
> > --- a/drivers/hwmon/max6639.c
> > +++ b/drivers/hwmon/max6639.c
> > @@ -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,30 @@ 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) {
> > + err = (int)PTR_ERR(data->reg);
> > + dev_warn(dev, "Failed looking up fan supply: %d\n", err);
>
> This could be -EPROBE_DEFER. I do not think that warrants
> an error message.
I see. I'll adapt it analog to: drivers/hwmon/pwm-fan.c:323
>
> > + return err;
> > + }
> > + 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 +577,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 */
> >