forked from Minki/linux
4d420a6a9d
The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan management with temperature and remote voltage sensing. It supports various fan control features, including PWM frequency control, temperature hysteresis, dual tachometer measurements, and fan health monitoring. This patch presents a basic driver using only the existing features of the PMBus subsystem. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> [groeck: Modified description to clarify that fan control is not yet provided] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
117 lines
2.8 KiB
C
117 lines
2.8 KiB
C
/*
|
|
* Copyright (C) 2017 IBM Corp.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/err.h>
|
|
#include <linux/i2c.h>
|
|
#include "pmbus.h"
|
|
|
|
enum max31785_regs {
|
|
MFR_REVISION = 0x9b,
|
|
};
|
|
|
|
#define MAX31785_NR_PAGES 23
|
|
|
|
#define MAX31785_FAN_FUNCS \
|
|
(PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12)
|
|
|
|
#define MAX31785_TEMP_FUNCS \
|
|
(PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
|
|
|
|
#define MAX31785_VOUT_FUNCS \
|
|
(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
|
|
|
|
static const struct pmbus_driver_info max31785_info = {
|
|
.pages = MAX31785_NR_PAGES,
|
|
|
|
/* RPM */
|
|
.format[PSC_FAN] = direct,
|
|
.m[PSC_FAN] = 1,
|
|
.b[PSC_FAN] = 0,
|
|
.R[PSC_FAN] = 0,
|
|
.func[0] = MAX31785_FAN_FUNCS,
|
|
.func[1] = MAX31785_FAN_FUNCS,
|
|
.func[2] = MAX31785_FAN_FUNCS,
|
|
.func[3] = MAX31785_FAN_FUNCS,
|
|
.func[4] = MAX31785_FAN_FUNCS,
|
|
.func[5] = MAX31785_FAN_FUNCS,
|
|
|
|
.format[PSC_TEMPERATURE] = direct,
|
|
.m[PSC_TEMPERATURE] = 1,
|
|
.b[PSC_TEMPERATURE] = 0,
|
|
.R[PSC_TEMPERATURE] = 2,
|
|
.func[6] = MAX31785_TEMP_FUNCS,
|
|
.func[7] = MAX31785_TEMP_FUNCS,
|
|
.func[8] = MAX31785_TEMP_FUNCS,
|
|
.func[9] = MAX31785_TEMP_FUNCS,
|
|
.func[10] = MAX31785_TEMP_FUNCS,
|
|
.func[11] = MAX31785_TEMP_FUNCS,
|
|
.func[12] = MAX31785_TEMP_FUNCS,
|
|
.func[13] = MAX31785_TEMP_FUNCS,
|
|
.func[14] = MAX31785_TEMP_FUNCS,
|
|
.func[15] = MAX31785_TEMP_FUNCS,
|
|
.func[16] = MAX31785_TEMP_FUNCS,
|
|
|
|
.format[PSC_VOLTAGE_OUT] = direct,
|
|
.m[PSC_VOLTAGE_OUT] = 1,
|
|
.b[PSC_VOLTAGE_OUT] = 0,
|
|
.R[PSC_VOLTAGE_OUT] = 0,
|
|
.func[17] = MAX31785_VOUT_FUNCS,
|
|
.func[18] = MAX31785_VOUT_FUNCS,
|
|
.func[19] = MAX31785_VOUT_FUNCS,
|
|
.func[20] = MAX31785_VOUT_FUNCS,
|
|
.func[21] = MAX31785_VOUT_FUNCS,
|
|
.func[22] = MAX31785_VOUT_FUNCS,
|
|
};
|
|
|
|
static int max31785_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct device *dev = &client->dev;
|
|
struct pmbus_driver_info *info;
|
|
s64 ret;
|
|
|
|
info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
|
|
if (!info)
|
|
return -ENOMEM;
|
|
|
|
*info = max31785_info;
|
|
|
|
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return pmbus_do_probe(client, id, info);
|
|
}
|
|
|
|
static const struct i2c_device_id max31785_id[] = {
|
|
{ "max31785", 0 },
|
|
{ "max31785a", 0 },
|
|
{ },
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, max31785_id);
|
|
|
|
static struct i2c_driver max31785_driver = {
|
|
.driver = {
|
|
.name = "max31785",
|
|
},
|
|
.probe = max31785_probe,
|
|
.remove = pmbus_do_remove,
|
|
.id_table = max31785_id,
|
|
};
|
|
|
|
module_i2c_driver(max31785_driver);
|
|
|
|
MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
|
|
MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
|
|
MODULE_LICENSE("GPL");
|