blob: fb7b3f010bd8aadf1c44bb201701ae37997120d2 [file] [log] [blame] [edit]
/*
* max31785.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring.
*
* (C) 2016 Raptor Engineering, LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
/* MAX31785 device IDs */
#define MAX31785_MFR_ID 0x4d
#define MAX31785_MFR_MODEL 0x53
/* MAX31785 registers */
#define MAX31785_REG_PAGE 0x00
#define MAX31785_PAGE_FAN_CONFIG(ch) (0x00 + (ch))
#define MAX31785_REG_FAN_CONFIG_1_2 0x3a
#define MAX31785_REG_FAN_COMMAND_1 0x3b
#define MAX31785_REG_STATUS_FANS_1_2 0x81
#define MAX31785_REG_FAN_SPEED_1 0x90
#define MAX31785_REG_MFR_ID 0x99
#define MAX31785_REG_MFR_MODEL 0x9a
#define MAX31785_REG_MFR_FAN_CONFIG 0xf1
#define MAX31785_REG_READ_FAN_PWM 0xf3
/* Fan Config register bits */
#define MAX31785_FAN_CFG_PWM_ENABLE 0x80
#define MAX31785_FAN_CFG_CONTROL_MODE_RPM 0x40
#define MAX31785_FAN_CFG_PULSE_MASK 0x30
#define MAX31785_FAN_CFG_PULSE_SHIFT 4
#define MAX31785_FAN_CFG_PULSE_OFFSET 1
/* Fan Status register bits */
#define MAX31785_FAN_STATUS_FAULT_MASK 0x80
/* Fan Command constants */
#define MAX31785_FAN_COMMAND_PWM_RATIO 40
#define NR_CHANNEL 6
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x52, 0x53, 0x54, 0x55,
I2C_CLIENT_END };
/*
* Client data (each client gets its own)
*/
struct max31785_data {
struct i2c_client *client;
struct mutex device_lock;
bool valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* 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];
};
static int max31785_set_page(struct i2c_client *client,
u8 page)
{
return i2c_smbus_write_byte_data(client,
MAX31785_REG_PAGE,
page);
}
static int max31785_read_fan_data(struct i2c_client *client,
u8 fan, u8 reg, u8 byte_mode)
{
int rv;
rv = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan));
if (rv < 0)
return rv;
if (byte_mode)
rv = i2c_smbus_read_byte_data(client, reg);
else
rv = i2c_smbus_read_word_data(client, reg);
return rv;
}
static int max31785_write_fan_data(struct i2c_client *client,
u8 fan, u8 reg, u16 data,
u8 byte_mode)
{
int err;
err = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan));
if (err < 0)
return err;
if (byte_mode)
err = i2c_smbus_write_byte_data(client, reg, data);
else
err = i2c_smbus_write_word_data(client, reg, data);
if (err < 0)
return err;
return 0;
}
static bool is_automatic_control_mode(struct max31785_data *data,
int index)
{
if (data->fan_command[index] > 0x7fff)
return true;
else
return false;
}
static struct max31785_data *max31785_update_device(struct device *dev)
{
struct max31785_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
struct max31785_data *ret = data;
int i;
int rv;
mutex_lock(&data->device_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (i = 0; i < NR_CHANNEL; i++) {
rv = max31785_read_fan_data(client, i,
MAX31785_REG_STATUS_FANS_1_2, 1);
if (rv < 0)
goto abort;
data->fault_status[i] = rv;
rv = max31785_read_fan_data(client, i,
MAX31785_REG_FAN_SPEED_1, 0);
if (rv < 0)
goto abort;
data->tach_rpm[i] = rv;
if ((data->fan_config[i]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
|| is_automatic_control_mode(data, i)) {
rv = max31785_read_fan_data(client, i,
MAX31785_REG_READ_FAN_PWM, 0);
if (rv < 0)
goto abort;
data->pwm[i] = rv;
}
if (!is_automatic_control_mode(data, i)) {
/* Poke watchdog for manual fan control */
rv = max31785_write_fan_data(client,
i, MAX31785_REG_FAN_COMMAND_1,
data->fan_command[i], 0);
if (rv < 0)
goto abort;
}
}
data->last_updated = jiffies;
data->valid = true;
}
goto done;
abort:
data->valid = false;
ret = ERR_PTR(rv);
done:
mutex_unlock(&data->device_lock);
return ret;
}
static ssize_t get_fan(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->tach_rpm[attr->index]);
}
static ssize_t get_fan_target(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
int rpm;
if (IS_ERR(data))
return PTR_ERR(data);
if (data->fan_config[attr->index]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
rpm = data->fan_command[attr->index];
else
rpm = data->fan_command[attr->index]
/ MAX31785_FAN_COMMAND_PWM_RATIO;
return sprintf(buf, "%d\n", rpm);
}
static ssize_t set_fan_target(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long rpm;
int err;
err = kstrtoul(buf, 10, &rpm);
if (err)
return err;
if (rpm > 0x7fff)
return -EINVAL;
mutex_lock(&data->device_lock);
/* Write new RPM value */
data->fan_command[attr->index] = rpm;
err = max31785_write_fan_data(client, attr->index,
MAX31785_REG_FAN_COMMAND_1,
data->fan_command[attr->index], 0);
mutex_unlock(&data->device_lock);
if (err < 0)
return err;
return count;
}
static ssize_t get_fan_pulses(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
int pulses;
if (IS_ERR(data))
return PTR_ERR(data);
pulses = ((data->fan_config[attr->index] & MAX31785_FAN_CFG_PULSE_MASK)
>> MAX31785_FAN_CFG_PULSE_SHIFT)
+ MAX31785_FAN_CFG_PULSE_OFFSET;
return sprintf(buf, "%d\n", pulses);
}
static ssize_t set_fan_pulses(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long pulses;
int err;
err = kstrtoul(buf, 10, &pulses);
if (err)
return err;
if (pulses > 4)
return -EINVAL;
data->fan_config[attr->index] &= MAX31785_FAN_CFG_PULSE_MASK;
data->fan_config[attr->index] |=
((pulses - MAX31785_FAN_CFG_PULSE_OFFSET)
<< MAX31785_FAN_CFG_PULSE_SHIFT);
mutex_lock(&data->device_lock);
/* Write new pulse value */
data->fan_command[attr->index] = pulses;
err = max31785_write_fan_data(client, attr->index,
MAX31785_REG_FAN_CONFIG_1_2,
data->fan_config[attr->index], 1);
mutex_unlock(&data->device_lock);
if (err < 0)
return err;
return count;
}
static ssize_t get_pwm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
int pwm;
if (IS_ERR(data))
return PTR_ERR(data);
if ((data->fan_config[attr->index]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
|| is_automatic_control_mode(data, attr->index))
pwm = data->pwm[attr->index] / 100;
else
pwm = data->fan_command[attr->index]
/ MAX31785_FAN_COMMAND_PWM_RATIO;
return sprintf(buf, "%d\n", pwm);
}
static ssize_t set_pwm(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long pwm;
int err;
err = kstrtoul(buf, 10, &pwm);
if (err)
return err;
if (pwm > 255)
return -EINVAL;
mutex_lock(&data->device_lock);
/* Write new PWM value */
data->fan_command[attr->index] = pwm * MAX31785_FAN_COMMAND_PWM_RATIO;
err = max31785_write_fan_data(client, attr->index,
MAX31785_REG_FAN_COMMAND_1,
data->fan_command[attr->index], 0);
mutex_unlock(&data->device_lock);
if (err < 0)
return err;
return count;
}
static ssize_t get_pwm_enable(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
int mode;
if (IS_ERR(data))
return PTR_ERR(data);
if (!(data->fan_config[attr->index] & MAX31785_FAN_CFG_PWM_ENABLE))
mode = 0;
else if (is_automatic_control_mode(data, attr->index))
mode = 3;
else if (data->fan_config[attr->index]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
mode = 2;
else
mode = 1;
return sprintf(buf, "%d\n", mode);
}
static ssize_t set_pwm_enable(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long mode;
int err;
err = kstrtoul(buf, 10, &mode);
if (err)
return err;
switch (mode) {
case 0:
data->fan_config[attr->index] =
data->fan_config[attr->index]
& ~MAX31785_FAN_CFG_PWM_ENABLE;
break;
case 1:
case 2:
case 3:
data->fan_config[attr->index] =
data->fan_config[attr->index]
| MAX31785_FAN_CFG_PWM_ENABLE;
break;
default:
return -EINVAL;
}
switch (mode) {
case 0:
break;
case 1:
data->fan_config[attr->index] =
data->fan_config[attr->index]
& ~MAX31785_FAN_CFG_CONTROL_MODE_RPM;
break;
case 2:
data->fan_config[attr->index] =
data->fan_config[attr->index]
| MAX31785_FAN_CFG_CONTROL_MODE_RPM;
break;
case 3:
data->fan_command[attr->index] = 0xffff;
break;
default:
return -EINVAL;
}
mutex_lock(&data->device_lock);
err = max31785_write_fan_data(client, attr->index,
MAX31785_REG_FAN_CONFIG_1_2,
data->fan_config[attr->index], 1);
if (err < 0)
goto abort;
err = max31785_write_fan_data(client, attr->index,
MAX31785_REG_FAN_COMMAND_1,
data->fan_command[attr->index], 0);
abort:
mutex_unlock(&data->device_lock);
if (err < 0)
return err;
return count;
}
static ssize_t get_fan_fault(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max31785_data *data = max31785_update_device(dev);
int fault;
if (IS_ERR(data))
return PTR_ERR(data);
fault = !!(data->fault_status[attr->index]
& MAX31785_FAN_STATUS_FAULT_MASK);
return sprintf(buf, "%d\n", fault);
}
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, get_fan, NULL, 4);
static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, get_fan, NULL, 5);
static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_fault, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, get_fan_fault, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, get_fan_fault, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, get_fan_fault, NULL, 3);
static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, get_fan_fault, NULL, 4);
static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, get_fan_fault, NULL, 5);
static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 0);
static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 1);
static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 2);
static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 3);
static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 4);
static SENSOR_DEVICE_ATTR(fan6_target, S_IWUSR | S_IRUGO,
get_fan_target, set_fan_target, 5);
static SENSOR_DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 0);
static SENSOR_DEVICE_ATTR(fan2_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 1);
static SENSOR_DEVICE_ATTR(fan3_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 2);
static SENSOR_DEVICE_ATTR(fan4_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 3);
static SENSOR_DEVICE_ATTR(fan5_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 4);
static SENSOR_DEVICE_ATTR(fan6_pulses, S_IWUSR | S_IRUGO,
get_fan_pulses, set_fan_pulses, 5);
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2);
static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 4);
static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 5);
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 0);
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 2);
static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 3);
static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 4);
static SENSOR_DEVICE_ATTR(pwm6_enable, S_IWUSR | S_IRUGO,
get_pwm_enable, set_pwm_enable, 5);
static struct attribute *max31785_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan1_fault.dev_attr.attr,
&sensor_dev_attr_fan2_fault.dev_attr.attr,
&sensor_dev_attr_fan3_fault.dev_attr.attr,
&sensor_dev_attr_fan4_fault.dev_attr.attr,
&sensor_dev_attr_fan5_fault.dev_attr.attr,
&sensor_dev_attr_fan6_fault.dev_attr.attr,
&sensor_dev_attr_fan1_target.dev_attr.attr,
&sensor_dev_attr_fan2_target.dev_attr.attr,
&sensor_dev_attr_fan3_target.dev_attr.attr,
&sensor_dev_attr_fan4_target.dev_attr.attr,
&sensor_dev_attr_fan5_target.dev_attr.attr,
&sensor_dev_attr_fan6_target.dev_attr.attr,
&sensor_dev_attr_fan1_pulses.dev_attr.attr,
&sensor_dev_attr_fan2_pulses.dev_attr.attr,
&sensor_dev_attr_fan3_pulses.dev_attr.attr,
&sensor_dev_attr_fan4_pulses.dev_attr.attr,
&sensor_dev_attr_fan5_pulses.dev_attr.attr,
&sensor_dev_attr_fan6_pulses.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm4_enable.dev_attr.attr,
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
NULL
};
static umode_t max31785_attrs_visible(struct kobject *kobj,
struct attribute *a, int n)
{
return a->mode;
}
static const struct attribute_group max31785_group = {
.attrs = max31785_attrs,
.is_visible = max31785_attrs_visible,
};
__ATTRIBUTE_GROUPS(max31785);
static int max31785_init_client(struct i2c_client *client,
struct max31785_data *data)
{
int i, rv;
for (i = 0; i < NR_CHANNEL; i++) {
rv = max31785_read_fan_data(client, i,
MAX31785_REG_FAN_CONFIG_1_2, 1);
if (rv < 0)
return rv;
data->fan_config[i] = rv;
rv = max31785_read_fan_data(client, i,
MAX31785_REG_FAN_COMMAND_1, 0);
if (rv < 0)
return rv;
data->fan_command[i] = rv;
rv = max31785_read_fan_data(client, i,
MAX31785_REG_MFR_FAN_CONFIG, 1);
if (rv < 0)
return rv;
data->mfr_fan_config[i] = rv;
if (!((data->fan_config[i]
& MAX31785_FAN_CFG_CONTROL_MODE_RPM)
|| is_automatic_control_mode(data, i))) {
data->pwm[i] = 0;
}
}
return rv;
}
/* Return 0 if detection is successful, -ENODEV otherwise */
static int max31785_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int rv;
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
/* Probe manufacturer / model registers */
rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_ID);
if (rv < 0)
return -ENODEV;
if (rv != MAX31785_MFR_ID)
return -ENODEV;
rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_MODEL);
if (rv < 0)
return -ENODEV;
if (rv != MAX31785_MFR_MODEL)
return -ENODEV;
strlcpy(info->type, "max31785", I2C_NAME_SIZE);
return 0;
}
static int max31785_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct max31785_data *data;
struct device *hwmon_dev;
int err;
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
data = devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->device_lock);
/*
* Initialize the max31785 chip
*/
err = max31785_init_client(client, data);
if (err)
return err;
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
client->name, data, max31785_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max31785_id[] = {
{ "max31785", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31785_id);
static struct i2c_driver max31785_driver = {
.class = I2C_CLASS_HWMON,
.probe = max31785_probe,
.driver = {
.name = "max31785",
},
.id_table = max31785_id,
.detect = max31785_detect,
.address_list = normal_i2c,
};
module_i2c_driver(max31785_driver);
MODULE_AUTHOR("Timothy Pearson <tpearson@raptorengineering.com>");
MODULE_DESCRIPTION("MAX31785 sensor driver");
MODULE_LICENSE("GPL");