[RFC PATCH linux dev-4.10 6/7] hwmon: max31785: Enable fast rotor measurement feature
Andrew Jeffery
andrew at aj.id.au
Fri Jun 2 16:22:06 AEST 2017
MFR_REVISION 0x3040 of the max31785 chip provides two rotor readings
for READ_FAN_SPEED_1, with an extra 16 bits after the original
READ_FAN_SPEED_1 response. For this firmware revision, the first result
represents the 'slow' rotor reading whilst the second represents the
'fast' rotor reading.
Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
Documentation/hwmon/max31785 | 8 +++
drivers/hwmon/max31785.c | 115 ++++++++++++++++++++++++++++++++++++++-----
2 files changed, 112 insertions(+), 11 deletions(-)
diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785
index 0911d204547e..f0d0e54d9a9f 100644
--- a/Documentation/hwmon/max31785
+++ b/Documentation/hwmon/max31785
@@ -34,3 +34,11 @@ fan[1-6]_pulses RW tachometer pulses per fan revolution
fan[1-6]_target RW desired fan speed in RPM
pwm[1-6]_enable RW pwm mode, 0=disabled, 1=pwm, 2=rpm, 3=automatic
pwm[1-6] RW fan target duty cycle (0-255)
+
+Dynamic syfs entries
+--------------------
+
+Whether these entries are present depends on the firmware features detected on
+the device during probe.
+
+fan[1-6]_input_fast RO fan tachometer speed in RPM (fast rotor measurement)
diff --git a/drivers/hwmon/max31785.c b/drivers/hwmon/max31785.c
index d1feb73d08f1..fb971277165c 100644
--- a/drivers/hwmon/max31785.c
+++ b/drivers/hwmon/max31785.c
@@ -37,6 +37,7 @@
#define MAX31785_REG_FAN_SPEED_1 0x90
#define MAX31785_REG_MFR_ID 0x99
#define MAX31785_REG_MFR_MODEL 0x9a
+#define MAX31785_REG_MFR_REVISION 0x9b
#define MAX31785_REG_MFR_FAN_CONFIG 0xf1
#define MAX31785_REG_READ_FAN_PWM 0xf3
@@ -59,6 +60,8 @@
static const unsigned short normal_i2c[] = { 0x52, 0x53, 0x54, 0x55,
I2C_CLIENT_END };
+#define MAX31785_CAP_FAST_ROTOR BIT(0)
+
/*
* Client data (each client gets its own)
*/
@@ -67,14 +70,17 @@ struct max31785 {
struct mutex device_lock;
bool valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
+ u32 capabilities;
/* register values */
u8 fan_config[NR_CHANNEL];
u16 fan_command[NR_CHANNEL];
u8 mfr_fan_config[NR_CHANNEL];
u8 fault_status[NR_CHANNEL];
- u16 tach_rpm[NR_CHANNEL];
u16 pwm[NR_CHANNEL];
+ u16 tach_rpm[NR_CHANNEL];
+ /* Fast rotor measurement */
+ u16 tach_rpm_fast[NR_CHANNEL];
};
static int max31785_set_page(struct i2c_client *client,
@@ -123,6 +129,35 @@ static int max31785_write_fan_data(struct i2c_client *client,
return 0;
}
+static int max31785_update_fan_speed(struct max31785 *data, u8 fan)
+{
+ s64 rc;
+
+ rc = max31785_set_page(data->client, MAX31785_PAGE_FAN_CONFIG(fan));
+ if (rc)
+ return rc;
+
+ if (data->capabilities & MAX31785_CAP_FAST_ROTOR) {
+ rc = i2c_smbus_read_dword_data(data->client,
+ MAX31785_REG_FAN_SPEED_1);
+ if (rc < 0)
+ return rc;
+
+ data->tach_rpm[fan] = rc & 0xffff;
+ data->tach_rpm_fast[fan] = (rc >> 16) & 0xffff;
+
+ return rc;
+ }
+
+ rc = i2c_smbus_read_dword_data(data->client, MAX31785_REG_FAN_SPEED_1);
+ if (rc < 0)
+ return rc;
+
+ data->tach_rpm[fan] = rc;
+
+ return rc;
+}
+
static bool is_automatic_control_mode(struct max31785 *data,
int index)
{
@@ -134,8 +169,8 @@ static struct max31785 *max31785_update_device(struct device *dev)
struct max31785 *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
struct max31785 *ret = data;
+ int rv;
int i;
- int rv;
mutex_lock(&data->device_lock);
@@ -147,11 +182,9 @@ static struct max31785 *max31785_update_device(struct device *dev)
goto abort;
data->fault_status[i] = rv;
- rv = max31785_read_fan_data(client, i,
- MAX31785_REG_FAN_SPEED_1, 0);
+ rv = max31785_update_fan_speed(data, i);
if (rv < 0)
goto abort;
- data->tach_rpm[i] = rv;
if ((data->fan_config[i]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
@@ -478,6 +511,20 @@ static int max31785_read_fan(struct max31785 *data, u32 attr, int channel,
return rc;
}
+static int max31785_fan_get_fast(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+ struct max31785 *data = dev_get_drvdata(dev);
+
+ int ret = i2c_smbus_read_byte_data(data->client, attr2->index);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", data->tach_rpm_fast[attr2->index]);
+}
+
static int max31785_read_pwm(struct max31785 *data, u32 attr, int channel,
long *val)
{
@@ -631,14 +678,53 @@ static const struct hwmon_chip_info max31785_chip_info = {
.info = max31785_info,
};
+static SENSOR_DEVICE_ATTR(fan1_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input_fast, 0444, max31785_fan_get_fast,
+ NULL, 5);
+
+static struct attribute *max31785_attrs[] = {
+ &sensor_dev_attr_fan1_input_fast.dev_attr.attr,
+ &sensor_dev_attr_fan2_input_fast.dev_attr.attr,
+ &sensor_dev_attr_fan3_input_fast.dev_attr.attr,
+ &sensor_dev_attr_fan4_input_fast.dev_attr.attr,
+ &sensor_dev_attr_fan5_input_fast.dev_attr.attr,
+ &sensor_dev_attr_fan6_input_fast.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(max31785);
+
+static int max31785_get_capabilities(struct max31785 *data)
+{
+ s32 rc;
+
+ rc = i2c_smbus_read_word_data(data->client, MAX31785_REG_MFR_REVISION);
+ if (rc < 0)
+ return rc;
+
+ if (rc == 0x3040)
+ data->capabilities |= MAX31785_CAP_FAST_ROTOR;
+
+ return 0;
+}
+
static int max31785_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ const struct attribute_group **extra_groups;
struct device *dev = &client->dev;
- struct max31785 *data;
struct device *hwmon_dev;
- int err;
+ struct max31785 *data;
+ int rc;
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
@@ -654,12 +740,19 @@ static int max31785_probe(struct i2c_client *client,
/*
* Initialize the max31785 chip
*/
- err = max31785_init_client(client, data);
- if (err)
- return err;
+ rc = max31785_init_client(client, data);
+ if (rc)
+ return rc;
+
+ rc = max31785_get_capabilities(data);
+ if (rc < 0)
+ return rc;
+
+ if (data->capabilities & MAX31785_CAP_FAST_ROTOR)
+ extra_groups = max31785_groups;
hwmon_dev = devm_hwmon_device_register_with_info(dev,
- client->name, data, &max31785_chip_info, NULL);
+ client->name, data, &max31785_chip_info, extra_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
--
2.11.0
More information about the openbmc
mailing list