hwmon updates for v5.3

New drivers for Infineon PXE1610 and IRPS5401
 Minor improvements, cleanup, and fixes in several drivers
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJdJNpEAAoJEMsfJm/On5mBjlkP/1DEAEtL6pJYyl0zmyR3QrUN
 CAkSvvH46ZFGLbZb/ZC3XuXTaBbxFmZxeZP0NLSoOh45zmNoo0IjPzmSBHpm9R+7
 ENZBLlMhtbR3M7zJO5kEb5kgOpnzf46KqEfOi72J51lZx+aabepSfkvzV1Zqf6TY
 PjuXwYG+VhhBobpwVNe2qixoQcHxhKbhheYvwbvfVjCA8YFqa08MkzbXjqHGcGwP
 mNKko/okRlLf1Qqq4rONlfixfO6rorKKN1oiDihFFRrNmJoT5n92jGaB+RLx2sHY
 pC8iHrOCnbe8iXXKYg8cwEVZ8OKUDfOSGL3RX2yVk6ZF7B13QZjqX7t437h3hAyD
 i0rWUyolKxwapAr2yUgO8QhHun6Zx/oOzpBPdGIdy0yhsbas9f9e5unGm9rSEWHh
 2aIMUED5YKtXqdujos05AYaw9GgQVPEbr16xkjU8DGc/qtWrWUFeER0dJDNDnduO
 yLl9yDwwq0bSoSEg54bA6ib4CPHyKtD8ZNrYDfGiTMO9xZqrwWssFMguvYnWbuNZ
 cAh6lEQODL5bhg4vGIMfqt3Ub7EoTzjCCOnQRrOU4ERbxazaB56+A2VyYv+7LwLd
 sPfxldSMjyUYrnyDk+WQkTgRl0WsV/Sr4FS6Z4NOjZWyGoTCsjB8Z/m/5eEydIas
 VbeuAQEKoxvvJOWaRu00
 =G/oG
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:

 - New drivers for Infineon PXE1610 and IRPS5401

 - Minor improvements, cleanup, and fixes in several drivers

* tag 'hwmon-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (33 commits)
  hwmon: (ina3221) Add of_node_put() before return
  hwmon: (gpio-fan) fix sysfs notifications and udev events for gpio-fan alarms
  hwmon: (gpio-fan) move fan_alarm_init after devm_hwmon_device_register_with_groups
  hwmon: (lm90) Introduce function to update configuration register
  hwmon: (lm90) Cache configuration register value
  hwmon: (lm90) Fix max6658 sporadic wrong temperature reading
  hwmon: (nct7904) Changes comments in probe function.
  hwmon: (nct7904) Add error handling in probe function.
  hwmon: Convert remaining drivers to use SPDX identifier
  hwmon: (max6650) Fix unused variable warning
  hwmon: (pmbus/adm1275) Fix power sampling support
  hwmon: (lm90) simplify getting the adapter of a client
  hwmon: (asus_atk0110) no need to check return value of debugfs_create functions
  hwmon: (max6650) Fix minor formatting issues
  hwmon: (max6650) Improve error handling in max6650_update_device
  hwmon: (max6650) Read non-volatile registers only once
  hwmon: (max6650) Convert to use devm_hwmon_device_register_with_info
  hwmon: (max6650) Simplify alarm handling
  hwmon: (max6650) Cache alarm_en register
  hwmon: (max6650) Declare valid as boolean
  ...
This commit is contained in:
Linus Torvalds 2019-07-11 14:44:13 -07:00
commit 64b08df460
18 changed files with 954 additions and 457 deletions

View File

@ -0,0 +1,90 @@
Kernel driver pxe1610
=====================
Supported chips:
* Infineon PXE1610
Prefix: 'pxe1610'
Addresses scanned: -
Datasheet: Datasheet is not publicly available.
* Infineon PXE1110
Prefix: 'pxe1110'
Addresses scanned: -
Datasheet: Datasheet is not publicly available.
* Infineon PXM1310
Prefix: 'pxm1310'
Addresses scanned: -
Datasheet: Datasheet is not publicly available.
Author: Vijay Khemka <vijaykhemka@fb.com>
Description
-----------
PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
and compliant to
-- Intel VR13 DC-DC converter specifications.
-- Intel SVID protocol.
Used for Vcore power regulation for Intel VR13 based microprocessors
-- Servers, Workstations, and High-end desktops
PXM1310 is a Multi-rail Controller and it is compliant to
-- Intel VR13 DC-DC converter specifications.
-- Intel SVID protocol.
Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
IMVP8 based systems
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have
to instantiate devices explicitly.
Example: the following commands will load the driver for an PXE1610
at address 0x70 on I2C bus #4:
# modprobe pxe1610
# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
It can also be instantiated by declaring in device tree
Sysfs attributes
----------------
curr1_label "iin"
curr1_input Measured input current
curr1_alarm Current high alarm
curr[2-4]_label "iout[1-3]"
curr[2-4]_input Measured output current
curr[2-4]_crit Critical maximum current
curr[2-4]_crit_alarm Current critical high alarm
in1_label "vin"
in1_input Measured input voltage
in1_crit Critical maximum input voltage
in1_crit_alarm Input voltage critical high alarm
in[2-4]_label "vout[1-3]"
in[2-4]_input Measured output voltage
in[2-4]_lcrit Critical minimum output voltage
in[2-4]_lcrit_alarm Output voltage critical low alarm
in[2-4]_crit Critical maximum output voltage
in[2-4]_crit_alarm Output voltage critical high alarm
power1_label "pin"
power1_input Measured input power
power1_alarm Input power high alarm
power[2-4]_label "pout[1-3]"
power[2-4]_input Measured output power
temp[1-3]_input Measured temperature
temp[1-3]_crit Critical high temperature
temp[1-3]_crit_alarm Chip temperature critical high alarm
temp[1-3]_max Maximum temperature
temp[1-3]_max_alarm Chip temperature high alarm

View File

@ -10,16 +10,6 @@
* Very rare chip please let me know if you use it
*
* http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
*
*
* 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 version 2 of the License
*
* 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/module.h>

View File

@ -789,33 +789,16 @@ static const struct file_operations atk_debugfs_ggrp_fops = {
static void atk_debugfs_init(struct atk_data *data)
{
struct dentry *d;
struct dentry *f;
data->debugfs.id = 0;
d = debugfs_create_dir("asus_atk0110", NULL);
if (!d || IS_ERR(d))
return;
f = debugfs_create_x32("id", 0600, d, &data->debugfs.id);
if (!f || IS_ERR(f))
goto cleanup;
f = debugfs_create_file_unsafe("gitm", 0400, d, data,
&atk_debugfs_gitm);
if (!f || IS_ERR(f))
goto cleanup;
f = debugfs_create_file("ggrp", 0400, d, data,
&atk_debugfs_ggrp_fops);
if (!f || IS_ERR(f))
goto cleanup;
debugfs_create_x32("id", 0600, d, &data->debugfs.id);
debugfs_create_file_unsafe("gitm", 0400, d, data, &atk_debugfs_gitm);
debugfs_create_file("ggrp", 0400, d, data, &atk_debugfs_ggrp_fops);
data->debugfs.root = d;
return;
cleanup:
debugfs_remove_recursive(d);
}
static void atk_debugfs_cleanup(struct atk_data *data)

View File

@ -54,8 +54,8 @@ static void fan_alarm_notify(struct work_struct *ws)
struct gpio_fan_data *fan_data =
container_of(ws, struct gpio_fan_data, alarm_work);
sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
sysfs_notify(&fan_data->hwmon_dev->kobj, NULL, "fan1_alarm");
kobject_uevent(&fan_data->hwmon_dev->kobj, KOBJ_CHANGE);
}
static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
@ -510,13 +510,6 @@ static int gpio_fan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fan_data);
mutex_init(&fan_data->lock);
/* Configure alarm GPIO if available. */
if (fan_data->alarm_gpio) {
err = fan_alarm_init(fan_data);
if (err)
return err;
}
/* Configure control GPIOs if available. */
if (fan_data->gpios && fan_data->num_gpios > 0) {
if (!fan_data->speed || fan_data->num_speed <= 1)
@ -524,7 +517,9 @@ static int gpio_fan_probe(struct platform_device *pdev)
err = fan_ctrl_init(fan_data);
if (err)
return err;
devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
if (err)
return err;
}
/* Make this driver part of hwmon class. */
@ -535,6 +530,13 @@ static int gpio_fan_probe(struct platform_device *pdev)
if (IS_ERR(fan_data->hwmon_dev))
return PTR_ERR(fan_data->hwmon_dev);
/* Configure alarm GPIO if available. */
if (fan_data->alarm_gpio) {
err = fan_alarm_init(fan_data);
if (err)
return err;
}
/* Optional cooling device register for Device tree platforms */
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
"gpio-fan", fan_data, &gpio_fan_cool_ops);

View File

@ -651,6 +651,12 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hwdev, j);
if (err) {
device_unregister(hdev);
/*
* Don't worry about hwdev;
* hwmon_dev_release(), called
* from device_unregister(),
* will free it.
*/
goto ida_remove;
}
}

View File

@ -713,8 +713,10 @@ static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
for_each_child_of_node(np, child) {
ret = ina3221_probe_child_from_dt(dev, child, ina);
if (ret)
if (ret) {
of_node_put(child);
return ret;
}
}
return 0;

View File

@ -174,6 +174,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm */
#define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */
#define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */
#define LM90_PAUSE_FOR_CONFIG (1 << 8) /* Pause conversion for config */
/* LM90 status */
#define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */
@ -367,6 +368,7 @@ static const struct lm90_params lm90_params[] = {
.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
},
[max6657] = {
.flags = LM90_PAUSE_FOR_CONFIG,
.alert_alarms = 0x7c,
.max_convrate = 8,
.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@ -457,6 +459,7 @@ struct lm90_data {
unsigned int update_interval; /* in milliseconds */
u8 config; /* Current configuration register value */
u8 config_orig; /* Original configuration register value */
u8 convrate_orig; /* Original conversion rate register value */
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
@ -540,6 +543,21 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
return (newh << 8) | l;
}
static int lm90_update_confreg(struct lm90_data *data, u8 config)
{
if (data->config != config) {
int err;
err = i2c_smbus_write_byte_data(data->client,
LM90_REG_W_CONFIG1,
config);
if (err)
return err;
data->config = config;
}
return 0;
}
/*
* client->update_lock must be held when calling this function (unless we are
* in detection or initialization steps), and while a remote channel other
@ -548,23 +566,39 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
* various registers have different meanings as a result of selecting a
* non-default remote channel.
*/
static inline int lm90_select_remote_channel(struct i2c_client *client,
struct lm90_data *data,
int channel)
static int lm90_select_remote_channel(struct lm90_data *data, int channel)
{
int config;
int err = 0;
if (data->kind == max6696) {
config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
if (config < 0)
return config;
config &= ~0x08;
u8 config = data->config & ~0x08;
if (channel)
config |= 0x08;
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
config);
err = lm90_update_confreg(data, config);
}
return 0;
return err;
}
static int lm90_write_convrate(struct lm90_data *data, int val)
{
u8 config = data->config;
int err;
/* Save config and pause conversion */
if (data->flags & LM90_PAUSE_FOR_CONFIG) {
err = lm90_update_confreg(data, config | 0x40);
if (err < 0)
return err;
}
/* Set conv rate */
err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val);
/* Revert change to config */
lm90_update_confreg(data, config);
return err;
}
/*
@ -587,7 +621,7 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
if (interval >= update_interval * 3 / 4)
break;
err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
err = lm90_write_convrate(data, i);
data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
return err;
}
@ -658,7 +692,7 @@ static int lm90_update_limits(struct device *dev)
}
if (data->kind == max6696) {
val = lm90_select_remote_channel(client, data, 1);
val = lm90_select_remote_channel(data, 1);
if (val < 0)
return val;
@ -682,7 +716,7 @@ static int lm90_update_limits(struct device *dev)
return val;
data->temp11[REMOTE2_HIGH] = val << 8;
lm90_select_remote_channel(client, data, 0);
lm90_select_remote_channel(data, 0);
}
return 0;
@ -742,19 +776,19 @@ static int lm90_update_device(struct device *dev)
data->alarms = val; /* lower 8 bit of alarms */
if (data->kind == max6696) {
val = lm90_select_remote_channel(client, data, 1);
val = lm90_select_remote_channel(data, 1);
if (val < 0)
return val;
val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
LM90_REG_R_REMOTE_TEMPL);
if (val < 0) {
lm90_select_remote_channel(client, data, 0);
lm90_select_remote_channel(data, 0);
return val;
}
data->temp11[REMOTE2_TEMP] = val;
lm90_select_remote_channel(client, data, 0);
lm90_select_remote_channel(data, 0);
val = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
if (val < 0)
@ -768,15 +802,9 @@ static int lm90_update_device(struct device *dev)
*/
if (!(data->config_orig & 0x80) &&
!(data->alarms & data->alert_alarms)) {
val = lm90_read_reg(client, LM90_REG_R_CONFIG1);
if (val < 0)
return val;
if (val & 0x80) {
if (data->config & 0x80) {
dev_dbg(&client->dev, "Re-enabling ALERT#\n");
i2c_smbus_write_byte_data(client,
LM90_REG_W_CONFIG1,
val & ~0x80);
lm90_update_confreg(data, data->config & ~0x80);
}
}
@ -994,7 +1022,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
else
data->temp11[index] = temp_to_s8(val) << 8;
lm90_select_remote_channel(client, data, index >= 3);
lm90_select_remote_channel(data, index >= 3);
err = i2c_smbus_write_byte_data(client, regp->high,
data->temp11[index] >> 8);
if (err < 0)
@ -1003,7 +1031,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
err = i2c_smbus_write_byte_data(client, regp->low,
data->temp11[index] & 0xff);
lm90_select_remote_channel(client, data, 0);
lm90_select_remote_channel(data, 0);
return err;
}
@ -1052,9 +1080,9 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
else
data->temp8[index] = temp_to_s8(val);
lm90_select_remote_channel(client, data, index >= 6);
lm90_select_remote_channel(data, index >= 6);
err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]);
lm90_select_remote_channel(client, data, 0);
lm90_select_remote_channel(data, 0);
return err;
}
@ -1593,8 +1621,7 @@ static void lm90_restore_conf(void *_data)
struct i2c_client *client = data->client;
/* Restore initial configuration */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
data->convrate_orig);
lm90_write_convrate(data, data->convrate_orig);
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
data->config_orig);
}
@ -1611,11 +1638,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
/*
* Start the conversions.
*/
lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
if (config < 0)
return config;
data->config_orig = config;
data->config = config;
lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
/* Check Temperature Range Select */
if (data->kind == adt7461 || data->kind == tmp451) {
@ -1638,8 +1667,7 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
config &= ~0x08;
config &= 0xBF; /* run */
if (config != data->config_orig) /* Only write if changed */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
lm90_update_confreg(data, config);
return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data);
}
@ -1718,7 +1746,7 @@ static int lm90_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct i2c_adapter *adapter = to_i2c_adapter(dev->parent);
struct i2c_adapter *adapter = client->adapter;
struct hwmon_channel_info *info;
struct regulator *regulator;
struct device *hwmon_dev;
@ -1873,14 +1901,8 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
(alarms & data->alert_alarms)) {
int config;
dev_dbg(&client->dev, "Disabling ALERT#\n");
config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
if (config >= 0)
i2c_smbus_write_byte_data(client,
LM90_REG_W_CONFIG1,
config | 0x80);
lm90_update_confreg(data, data->config | 0x80);
}
} else {
dev_info(&client->dev, "Everything OK\n");

View File

@ -92,7 +92,8 @@ module_param(clock, int, 0444);
#define FAN_RPM_MIN 240
#define FAN_RPM_MAX 30000
#define DIV_FROM_REG(reg) (1 << (reg & 7))
#define DIV_FROM_REG(reg) (1 << ((reg) & 7))
#define DAC_LIMIT(v12) ((v12) ? 180 : 76)
/*
* Client data (each client gets its own)
@ -100,11 +101,9 @@ module_param(clock, int, 0444);
struct max6650_data {
struct i2c_client *client;
const struct attribute_group *groups[3];
struct thermal_cooling_device *cooling_dev;
struct mutex update_lock;
struct mutex update_lock; /* protect alarm register updates */
int nr_fans;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
@ -114,6 +113,7 @@ struct max6650_data {
u8 count;
u8 dac;
u8 alarm;
u8 alarm_en;
unsigned long cooling_dev_state;
};
@ -137,41 +137,60 @@ static const struct of_device_id __maybe_unused max6650_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, max6650_dt_match);
static int dac_to_pwm(int dac, bool v12)
{
/*
* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
* Lower DAC values mean higher speeds.
*/
return clamp_val(255 - (255 * dac) / DAC_LIMIT(v12), 0, 255);
}
static u8 pwm_to_dac(unsigned int pwm, bool v12)
{
int limit = DAC_LIMIT(v12);
return limit - (limit * pwm) / 255;
}
static struct max6650_data *max6650_update_device(struct device *dev)
{
struct max6650_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int reg, err = 0;
int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->speed = i2c_smbus_read_byte_data(client,
MAX6650_REG_SPEED);
data->config = i2c_smbus_read_byte_data(client,
MAX6650_REG_CONFIG);
for (i = 0; i < data->nr_fans; i++) {
data->tach[i] = i2c_smbus_read_byte_data(client,
tach_reg[i]);
reg = i2c_smbus_read_byte_data(client, tach_reg[i]);
if (reg < 0) {
err = reg;
goto error;
}
data->tach[i] = reg;
}
data->count = i2c_smbus_read_byte_data(client,
MAX6650_REG_COUNT);
data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
/*
* Alarms are cleared on read in case the condition that
* caused the alarm is removed. Keep the value latched here
* for providing the register through different alarm files.
*/
data->alarm |= i2c_smbus_read_byte_data(client,
MAX6650_REG_ALARM);
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM);
if (reg < 0) {
err = reg;
goto error;
}
data->alarm |= reg;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
error:
mutex_unlock(&data->update_lock);
if (err)
data = ERR_PTR(err);
return data;
}
@ -199,26 +218,6 @@ static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)
return 0;
}
static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
int rpm;
/*
* Calculation details:
*
* Each tachometer counts over an interval given by the "count"
* register (0.25, 0.5, 1 or 2 seconds). This module assumes
* that the fans produce two pulses per revolution (this seems
* to be the most common).
*/
rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
return sprintf(buf, "%d\n", rpm);
}
/*
* Set the fan speed to the specified RPM (or read back the RPM setting).
* This works in closed loop mode only. Use pwm1 for open loop speed setting.
@ -260,26 +259,6 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
* controlled.
*/
static ssize_t fan1_target_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct max6650_data *data = max6650_update_device(dev);
int kscale, ktach, rpm;
/*
* Use the datasheet equation:
*
* FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
*
* then multiply by 60 to give rpm.
*/
kscale = DIV_FROM_REG(data->config);
ktach = data->speed;
rpm = 60 * kscale * clock / (256 * (ktach + 1));
return sprintf(buf, "%d\n", rpm);
}
static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
{
int kscale, ktach;
@ -308,197 +287,8 @@ static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
data->speed);
}
static ssize_t fan1_target_store(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct max6650_data *data = dev_get_drvdata(dev);
unsigned long rpm;
int err;
err = kstrtoul(buf, 10, &rpm);
if (err)
return err;
mutex_lock(&data->update_lock);
err = max6650_set_target(data, rpm);
mutex_unlock(&data->update_lock);
if (err < 0)
return err;
return count;
}
/*
* Get/set the fan speed in open loop mode using pwm1 sysfs file.
* Speed is given as a relative value from 0 to 255, where 255 is maximum
* speed. Note that this is done by writing directly to the chip's DAC,
* it won't change the closed loop speed set by fan1_target.
* Also note that due to rounding errors it is possible that you don't read
* back exactly the value you have set.
*/
static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
int pwm;
struct max6650_data *data = max6650_update_device(dev);
/*
* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
* Lower DAC values mean higher speeds.
*/
if (data->config & MAX6650_CFG_V12)
pwm = 255 - (255 * (int)data->dac)/180;
else
pwm = 255 - (255 * (int)data->dac)/76;
if (pwm < 0)
pwm = 0;
return sprintf(buf, "%d\n", pwm);
}
static ssize_t pwm1_store(struct device *dev,
struct device_attribute *devattr, const char *buf,
size_t count)
{
struct max6650_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;
pwm = clamp_val(pwm, 0, 255);
mutex_lock(&data->update_lock);
if (data->config & MAX6650_CFG_V12)
data->dac = 180 - (180 * pwm)/255;
else
data->dac = 76 - (76 * pwm)/255;
err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
mutex_unlock(&data->update_lock);
return err < 0 ? err : count;
}
/*
* Get/Set controller mode:
* Possible values:
* 0 = Fan always on
* 1 = Open loop, Voltage is set according to speed, not regulated.
* 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
* 3 = Fan off
*/
static ssize_t pwm1_enable_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct max6650_data *data = max6650_update_device(dev);
int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
int sysfs_modes[4] = {0, 3, 2, 1};
return sprintf(buf, "%d\n", sysfs_modes[mode]);
}
static ssize_t pwm1_enable_store(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct max6650_data *data = dev_get_drvdata(dev);
unsigned long mode;
int err;
const u8 max6650_modes[] = {
MAX6650_CFG_MODE_ON,
MAX6650_CFG_MODE_OPEN_LOOP,
MAX6650_CFG_MODE_CLOSED_LOOP,
MAX6650_CFG_MODE_OFF,
};
err = kstrtoul(buf, 10, &mode);
if (err)
return err;
if (mode >= ARRAY_SIZE(max6650_modes))
return -EINVAL;
mutex_lock(&data->update_lock);
max6650_set_operating_mode(data, max6650_modes[mode]);
mutex_unlock(&data->update_lock);
return count;
}
/*
* Read/write functions for fan1_div sysfs file. The MAX6650 has no such
* divider. We handle this by converting between divider and counttime:
*
* (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
*
* Lower values of k allow to connect a faster fan without the risk of
* counter overflow. The price is lower resolution. You can also set counttime
* using the module parameter. Note that the module parameter "prescaler" also
* influences the behaviour. Unfortunately, there's no sysfs attribute
* defined for that. See the data sheet for details.
*/
static ssize_t fan1_div_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct max6650_data *data = max6650_update_device(dev);
return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
}
static ssize_t fan1_div_store(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct max6650_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long div;
int err;
err = kstrtoul(buf, 10, &div);
if (err)
return err;
mutex_lock(&data->update_lock);
switch (div) {
case 1:
data->count = 0;
break;
case 2:
data->count = 1;
break;
case 4:
data->count = 2;
break;
case 8:
data->count = 3;
break;
default:
mutex_unlock(&data->update_lock);
return -EINVAL;
}
i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
mutex_unlock(&data->update_lock);
return count;
}
/*
* Get alarm stati:
* Get gpio alarm status:
* Possible values:
* 0 = no alarm
* 1 = alarm
@ -509,42 +299,30 @@ static ssize_t alarm_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
struct i2c_client *client = data->client;
int alarm = 0;
bool alarm;
if (data->alarm & attr->index) {
if (IS_ERR(data))
return PTR_ERR(data);
alarm = data->alarm & attr->index;
if (alarm) {
mutex_lock(&data->update_lock);
alarm = 1;
data->alarm &= ~attr->index;
data->alarm |= i2c_smbus_read_byte_data(client,
MAX6650_REG_ALARM);
data->valid = false;
mutex_unlock(&data->update_lock);
}
return sprintf(buf, "%d\n", alarm);
}
static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
static DEVICE_ATTR_RW(fan1_target);
static DEVICE_ATTR_RW(fan1_div);
static DEVICE_ATTR_RW(pwm1_enable);
static DEVICE_ATTR_RW(pwm1);
static SENSOR_DEVICE_ATTR_RO(fan1_max_alarm, alarm, MAX6650_ALRM_MAX);
static SENSOR_DEVICE_ATTR_RO(fan1_min_alarm, alarm, MAX6650_ALRM_MIN);
static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, MAX6650_ALRM_TACH);
static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1);
static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2);
static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct max6650_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
struct device_attribute *devattr;
/*
@ -552,12 +330,9 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
*/
devattr = container_of(a, struct device_attribute, attr);
if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
|| devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
|| devattr == &sensor_dev_attr_fan1_fault.dev_attr
|| devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
|| devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
if (devattr == &sensor_dev_attr_gpio1_alarm.dev_attr ||
devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
if (!(data->alarm_en & to_sensor_dev_attr(devattr)->index))
return 0;
}
@ -565,14 +340,6 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
}
static struct attribute *max6650_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&dev_attr_fan1_target.attr,
&dev_attr_fan1_div.attr,
&dev_attr_pwm1_enable.attr,
&dev_attr_pwm1.attr,
&sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_fault.dev_attr.attr,
&sensor_dev_attr_gpio1_alarm.dev_attr.attr,
&sensor_dev_attr_gpio2_alarm.dev_attr.attr,
NULL
@ -583,27 +350,17 @@ static const struct attribute_group max6650_group = {
.is_visible = max6650_attrs_visible,
};
static struct attribute *max6651_attrs[] = {
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
static const struct attribute_group *max6650_groups[] = {
&max6650_group,
NULL
};
static const struct attribute_group max6651_group = {
.attrs = max6651_attrs,
};
/*
* Real code
*/
static int max6650_init_client(struct max6650_data *data,
struct i2c_client *client)
{
struct device *dev = &client->dev;
int config;
int err = -EIO;
int reg;
int err;
u32 voltage;
u32 prescale;
u32 target_rpm;
@ -617,21 +374,20 @@ static int max6650_init_client(struct max6650_data *data,
&prescale))
prescale = prescaler;
config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
if (config < 0) {
dev_err(dev, "Error reading config, aborting.\n");
return err;
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
if (reg < 0) {
dev_err(dev, "Error reading config register, aborting.\n");
return reg;
}
switch (voltage) {
case 0:
break;
case 5:
config &= ~MAX6650_CFG_V12;
reg &= ~MAX6650_CFG_V12;
break;
case 12:
config |= MAX6650_CFG_V12;
reg |= MAX6650_CFG_V12;
break;
default:
dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);
@ -641,22 +397,22 @@ static int max6650_init_client(struct max6650_data *data,
case 0:
break;
case 1:
config &= ~MAX6650_CFG_PRESCALER_MASK;
reg &= ~MAX6650_CFG_PRESCALER_MASK;
break;
case 2:
config = (config & ~MAX6650_CFG_PRESCALER_MASK)
reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_2;
break;
case 4:
config = (config & ~MAX6650_CFG_PRESCALER_MASK)
reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_4;
break;
case 8:
config = (config & ~MAX6650_CFG_PRESCALER_MASK)
reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_8;
break;
case 16:
config = (config & ~MAX6650_CFG_PRESCALER_MASK)
reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_16;
break;
default:
@ -664,16 +420,43 @@ static int max6650_init_client(struct max6650_data *data,
}
dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",
(config & MAX6650_CFG_V12) ? 12 : 5,
1 << (config & MAX6650_CFG_PRESCALER_MASK));
(reg & MAX6650_CFG_V12) ? 12 : 5,
1 << (reg & MAX6650_CFG_PRESCALER_MASK));
if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
err = i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, reg);
if (err) {
dev_err(dev, "Config write error, aborting.\n");
return err;
}
data->config = reg;
data->config = config;
data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_SPEED);
if (reg < 0) {
dev_err(dev, "Failed to read speed register, aborting.\n");
return reg;
}
data->speed = reg;
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
if (reg < 0) {
dev_err(dev, "Failed to read DAC register, aborting.\n");
return reg;
}
data->dac = reg;
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
if (reg < 0) {
dev_err(dev, "Failed to read count register, aborting.\n");
return reg;
}
data->count = reg;
reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
if (reg < 0) {
dev_err(dev, "Failed to read alarm configuration, aborting.\n");
return reg;
}
data->alarm_en = reg;
if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",
&target_rpm)) {
@ -684,8 +467,6 @@ static int max6650_init_client(struct max6650_data *data,
return 0;
}
#if IS_ENABLED(CONFIG_THERMAL)
static int max6650_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
@ -715,23 +496,18 @@ static int max6650_set_cur_state(struct thermal_cooling_device *cdev,
mutex_lock(&data->update_lock);
if (data->config & MAX6650_CFG_V12)
data->dac = 180 - (180 * state)/255;
else
data->dac = 76 - (76 * state)/255;
data->dac = pwm_to_dac(state, data->config & MAX6650_CFG_V12);
err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
if (!err) {
max6650_set_operating_mode(data, state ?
MAX6650_CFG_MODE_OPEN_LOOP :
MAX6650_CFG_MODE_OFF);
MAX6650_CFG_MODE_OPEN_LOOP :
MAX6650_CFG_MODE_OFF);
data->cooling_dev_state = state;
}
mutex_unlock(&data->update_lock);
return err < 0 ? err : 0;
return err;
}
static const struct thermal_cooling_device_ops max6650_cooling_ops = {
@ -739,11 +515,252 @@ static const struct thermal_cooling_device_ops max6650_cooling_ops = {
.get_cur_state = max6650_get_cur_state,
.set_cur_state = max6650_set_cur_state,
};
#endif
static int max6650_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct max6650_data *data = max6650_update_device(dev);
int mode;
if (IS_ERR(data))
return PTR_ERR(data);
switch (type) {
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_input:
*val = dac_to_pwm(data->dac,
data->config & MAX6650_CFG_V12);
break;
case hwmon_pwm_enable:
/*
* Possible values:
* 0 = Fan always on
* 1 = Open loop, Voltage is set according to speed,
* not regulated.
* 2 = Closed loop, RPM for all fans regulated by fan1
* tachometer
* 3 = Fan off
*/
mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
*val = (4 - mode) & 3; /* {0 1 2 3} -> {0 3 2 1} */
break;
default:
return -EOPNOTSUPP;
}
break;
case hwmon_fan:
switch (attr) {
case hwmon_fan_input:
/*
* Calculation details:
*
* Each tachometer counts over an interval given by the
* "count" register (0.25, 0.5, 1 or 2 seconds).
* The driver assumes that the fans produce two pulses
* per revolution (this seems to be the most common).
*/
*val = DIV_ROUND_CLOSEST(data->tach[channel] * 120,
DIV_FROM_REG(data->count));
break;
case hwmon_fan_div:
*val = DIV_FROM_REG(data->count);
break;
case hwmon_fan_target:
/*
* Use the datasheet equation:
* FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
* then multiply by 60 to give rpm.
*/
*val = 60 * DIV_FROM_REG(data->config) * clock /
(256 * (data->speed + 1));
break;
case hwmon_fan_min_alarm:
*val = !!(data->alarm & MAX6650_ALRM_MIN);
data->alarm &= ~MAX6650_ALRM_MIN;
data->valid = false;
break;
case hwmon_fan_max_alarm:
*val = !!(data->alarm & MAX6650_ALRM_MAX);
data->alarm &= ~MAX6650_ALRM_MAX;
data->valid = false;
break;
case hwmon_fan_fault:
*val = !!(data->alarm & MAX6650_ALRM_TACH);
data->alarm &= ~MAX6650_ALRM_TACH;
data->valid = false;
break;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static const u8 max6650_pwm_modes[] = {
MAX6650_CFG_MODE_ON,
MAX6650_CFG_MODE_OPEN_LOOP,
MAX6650_CFG_MODE_CLOSED_LOOP,
MAX6650_CFG_MODE_OFF,
};
static int max6650_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct max6650_data *data = dev_get_drvdata(dev);
int ret = 0;
u8 reg;
mutex_lock(&data->update_lock);
switch (type) {
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_input:
reg = pwm_to_dac(clamp_val(val, 0, 255),
data->config & MAX6650_CFG_V12);
ret = i2c_smbus_write_byte_data(data->client,
MAX6650_REG_DAC, reg);
if (ret)
break;
data->dac = reg;
break;
case hwmon_pwm_enable:
if (val < 0 || val >= ARRAY_SIZE(max6650_pwm_modes)) {
ret = -EINVAL;
break;
}
ret = max6650_set_operating_mode(data,
max6650_pwm_modes[val]);
break;
default:
ret = -EOPNOTSUPP;
break;
}
break;
case hwmon_fan:
switch (attr) {
case hwmon_fan_div:
switch (val) {
case 1:
reg = 0;
break;
case 2:
reg = 1;
break;
case 4:
reg = 2;
break;
case 8:
reg = 3;
break;
default:
ret = -EINVAL;
goto error;
}
ret = i2c_smbus_write_byte_data(data->client,
MAX6650_REG_COUNT, reg);
if (ret)
break;
data->count = reg;
break;
case hwmon_fan_target:
if (val < 0) {
ret = -EINVAL;
break;
}
ret = max6650_set_target(data, val);
break;
default:
ret = -EOPNOTSUPP;
break;
}
break;
default:
ret = -EOPNOTSUPP;
break;
}
error:
mutex_unlock(&data->update_lock);
return ret;
}
static umode_t max6650_is_visible(const void *_data,
enum hwmon_sensor_types type, u32 attr,
int channel)
{
const struct max6650_data *data = _data;
if (channel && (channel >= data->nr_fans || type != hwmon_fan))
return 0;
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_input:
return 0444;
case hwmon_fan_target:
case hwmon_fan_div:
return 0644;
case hwmon_fan_min_alarm:
if (data->alarm_en & MAX6650_ALRM_MIN)
return 0444;
break;
case hwmon_fan_max_alarm:
if (data->alarm_en & MAX6650_ALRM_MAX)
return 0444;
break;
case hwmon_fan_fault:
if (data->alarm_en & MAX6650_ALRM_TACH)
return 0444;
break;
default:
break;
}
break;
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_input:
case hwmon_pwm_enable:
return 0644;
default:
break;
}
break;
default:
break;
}
return 0;
}
static const struct hwmon_channel_info *max6650_info[] = {
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM |
HWMON_F_FAULT,
HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),
HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
NULL
};
static const struct hwmon_ops max6650_hwmon_ops = {
.read = max6650_read,
.write = max6650_write,
.is_visible = max6650_is_visible,
};
static const struct hwmon_chip_info max6650_chip_info = {
.ops = &max6650_hwmon_ops,
.info = max6650_info,
};
static int max6650_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct thermal_cooling_device *cooling_dev;
struct device *dev = &client->dev;
const struct of_device_id *of_id =
of_match_device(of_match_ptr(max6650_dt_match), dev);
@ -767,37 +784,23 @@ static int max6650_probe(struct i2c_client *client,
if (err)
return err;
data->groups[0] = &max6650_group;
/* 3 additional fan inputs for the MAX6651 */
if (data->nr_fans == 4)
data->groups[1] = &max6651_group;
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
client->name, data,
data->groups);
hwmon_dev = devm_hwmon_device_register_with_info(dev,
client->name, data,
&max6650_chip_info,
max6650_groups);
err = PTR_ERR_OR_ZERO(hwmon_dev);
if (err)
return err;
#if IS_ENABLED(CONFIG_THERMAL)
data->cooling_dev =
thermal_of_cooling_device_register(client->dev.of_node,
client->name, data,
&max6650_cooling_ops);
if (IS_ERR(data->cooling_dev))
dev_warn(&client->dev,
"thermal cooling device register failed: %ld\n",
PTR_ERR(data->cooling_dev));
#endif
return 0;
}
static int max6650_remove(struct i2c_client *client)
{
struct max6650_data *data = i2c_get_clientdata(client);
if (!IS_ERR(data->cooling_dev))
thermal_cooling_device_unregister(data->cooling_dev);
if (IS_ENABLED(CONFIG_THERMAL)) {
cooling_dev = devm_thermal_of_cooling_device_register(dev,
dev->of_node, client->name,
data, &max6650_cooling_ops);
if (IS_ERR(cooling_dev)) {
dev_warn(dev, "thermal cooling device register failed: %ld\n",
PTR_ERR(cooling_dev));
}
}
return 0;
}
@ -815,7 +818,6 @@ static struct i2c_driver max6650_driver = {
.of_match_table = of_match_ptr(max6650_dt_match),
},
.probe = max6650_probe,
.remove = max6650_remove,
.id_table = max6650_id,
};

View File

@ -4,6 +4,9 @@
*
* Copyright (c) 2015 Kontron
* Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>
*
* Copyright (c) 2019 Advantech
* Author: Amy.Shih <amy.shih@advantech.com.tw>
*/
#include <linux/module.h>
@ -50,6 +53,8 @@
#define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */
#define PRTS_REG 0x03 /* Bank 2 */
#define PFE_REG 0x00 /* Bank 2; PECI Function Enable */
#define TSI_CTRL_REG 0x50 /* Bank 2; TSI Control Register */
#define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */
#define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */
@ -65,6 +70,8 @@ struct nct7904_data {
u32 vsen_mask;
u32 tcpu_mask;
u8 fan_mode[FANCTL_MAX];
u8 enable_dts;
u8 has_dts;
};
/* Access functions */
@ -229,11 +236,15 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
switch (attr) {
case hwmon_temp_input:
if (channel == 0)
if (channel == 4)
ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG);
else if (channel < 5)
ret = nct7904_read_reg16(data, BANK_0,
TEMP_CH1_HV_REG + channel * 4);
else
ret = nct7904_read_reg16(data, BANK_0,
T_CPU1_HV_REG + (channel - 1) * 2);
T_CPU1_HV_REG + (channel - 5)
* 2);
if (ret < 0)
return ret;
temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
@ -249,11 +260,11 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
const struct nct7904_data *data = _data;
if (attr == hwmon_temp_input) {
if (channel == 0) {
if (data->vsen_mask & BIT(17))
if (channel < 5) {
if (data->tcpu_mask & BIT(channel))
return 0444;
} else {
if (data->tcpu_mask & BIT(channel - 1))
if (data->has_dts & BIT(channel - 5))
return 0444;
}
}
@ -460,6 +471,7 @@ static int nct7904_probe(struct i2c_client *client,
struct device *dev = &client->dev;
int ret, i;
u32 mask;
u8 val, bit;
data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
if (!data)
@ -493,10 +505,65 @@ static int nct7904_probe(struct i2c_client *client,
data->vsen_mask = mask;
/* CPU_TEMP attributes */
ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG);
ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL0_REG);
if (ret < 0)
return ret;
data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4);
if ((ret & 0x6) == 0x6)
data->tcpu_mask |= 1; /* TR1 */
if ((ret & 0x18) == 0x18)
data->tcpu_mask |= 2; /* TR2 */
if ((ret & 0x20) == 0x20)
data->tcpu_mask |= 4; /* TR3 */
if ((ret & 0x80) == 0x80)
data->tcpu_mask |= 8; /* TR4 */
/* LTD */
ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
if (ret < 0)
return ret;
if ((ret & 0x02) == 0x02)
data->tcpu_mask |= 0x10;
/* Multi-Function detecting for Volt and TR/TD */
ret = nct7904_read_reg(data, BANK_0, VT_ADC_MD_REG);
if (ret < 0)
return ret;
for (i = 0; i < 4; i++) {
val = (ret & (0x03 << i)) >> (i * 2);
bit = (1 << i);
if (val == 0)
data->tcpu_mask &= ~bit;
}
/* PECI */
ret = nct7904_read_reg(data, BANK_2, PFE_REG);
if (ret < 0)
return ret;
if (ret & 0x80) {
data->enable_dts = 1; /* Enable DTS & PECI */
} else {
ret = nct7904_read_reg(data, BANK_2, TSI_CTRL_REG);
if (ret < 0)
return ret;
if (ret & 0x80)
data->enable_dts = 0x3; /* Enable DTS & TSI */
}
/* Check DTS enable status */
if (data->enable_dts) {
ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL0_REG);
if (ret < 0)
return ret;
data->has_dts = ret & 0xF;
if (data->enable_dts & 0x2) {
ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
if (ret < 0)
return ret;
data->has_dts |= (ret & 0xF) << 4;
}
}
for (i = 0; i < FANCTL_MAX; i++) {
ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);

View File

@ -241,6 +241,12 @@ static ssize_t occ_show_temp_1(struct device *dev,
val = get_unaligned_be16(&temp->sensor_id);
break;
case 1:
/*
* If a sensor reading has expired and couldn't be refreshed,
* OCC returns 0xFFFF for that sensor.
*/
if (temp->value == 0xFFFF)
return -EREMOTEIO;
val = get_unaligned_be16(&temp->value) * 1000;
break;
default:

View File

@ -64,6 +64,15 @@ config SENSORS_IR38064
This driver can also be built as a module. If so, the module will
be called ir38064.
config SENSORS_IRPS5401
tristate "Infineon IRPS5401"
help
If you say yes here you get hardware monitoring support for the
Infineon IRPS5401 controller.
This driver can also be built as a module. If so, the module will
be called irps5401.
config SENSORS_ISL68137
tristate "Intersil ISL68137"
help
@ -154,6 +163,15 @@ config SENSORS_MAX8688
This driver can also be built as a module. If so, the module will
be called max8688.
config SENSORS_PXE1610
tristate "Infineon PXE1610"
help
If you say yes here you get hardware monitoring support for Infineon
PXE1610.
This driver can also be built as a module. If so, the module will
be called pxe1610.
config SENSORS_TPS40422
tristate "TI TPS40422"
help

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_IR38064) += ir38064.o
obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
@ -18,6 +19,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o

View File

@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/log2.h>
#include "pmbus.h"
enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
@ -69,6 +71,18 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
#define ADM1075_VAUX_OV_WARN BIT(7)
#define ADM1075_VAUX_UV_WARN BIT(6)
#define ADM1275_VI_AVG_SHIFT 0
#define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \
ADM1275_VI_AVG_SHIFT)
#define ADM1275_SAMPLES_AVG_MAX 128
#define ADM1278_PWR_AVG_SHIFT 11
#define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \
ADM1278_PWR_AVG_SHIFT)
#define ADM1278_VI_AVG_SHIFT 8
#define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \
ADM1278_VI_AVG_SHIFT)
struct adm1275_data {
int id;
bool have_oc_fault;
@ -80,6 +94,7 @@ struct adm1275_data {
bool have_pin_min;
bool have_pin_max;
bool have_temp_max;
bool have_power_sampling;
struct pmbus_driver_info info;
};
@ -155,6 +170,62 @@ static const struct coefficients adm1293_coefficients[] = {
[18] = { 7658, 0, -3 }, /* power, 21V, irange200 */
};
static int adm1275_read_pmon_config(const struct adm1275_data *data,
struct i2c_client *client, bool is_power)
{
int shift, ret;
u16 mask;
/*
* The PMON configuration register is a 16-bit register only on chips
* supporting power average sampling. On other chips it is an 8-bit
* register.
*/
if (data->have_power_sampling) {
ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
} else {
ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
mask = ADM1275_VI_AVG_MASK;
shift = ADM1275_VI_AVG_SHIFT;
}
if (ret < 0)
return ret;
return (ret & mask) >> shift;
}
static int adm1275_write_pmon_config(const struct adm1275_data *data,
struct i2c_client *client,
bool is_power, u16 word)
{
int shift, ret;
u16 mask;
if (data->have_power_sampling) {
ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
} else {
ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
mask = ADM1275_VI_AVG_MASK;
shift = ADM1275_VI_AVG_SHIFT;
}
if (ret < 0)
return ret;
word = (ret & ~mask) | ((word << shift) & mask);
if (data->have_power_sampling)
ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
word);
else
ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
word);
return ret;
}
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@ -233,6 +304,21 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
if (!data->have_temp_max)
return -ENXIO;
break;
case PMBUS_VIRT_POWER_SAMPLES:
if (!data->have_power_sampling)
return -ENXIO;
ret = adm1275_read_pmon_config(data, client, true);
if (ret < 0)
break;
ret = BIT(ret);
break;
case PMBUS_VIRT_IN_SAMPLES:
case PMBUS_VIRT_CURR_SAMPLES:
ret = adm1275_read_pmon_config(data, client, false);
if (ret < 0)
break;
ret = BIT(ret);
break;
default:
ret = -ENODATA;
break;
@ -277,6 +363,19 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
case PMBUS_VIRT_RESET_TEMP_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
break;
case PMBUS_VIRT_POWER_SAMPLES:
if (!data->have_power_sampling)
return -ENXIO;
word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
ret = adm1275_write_pmon_config(data, client, true,
ilog2(word));
break;
case PMBUS_VIRT_IN_SAMPLES:
case PMBUS_VIRT_CURR_SAMPLES:
word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
ret = adm1275_write_pmon_config(data, client, false,
ilog2(word));
break;
default:
ret = -ENODATA;
break;
@ -430,7 +529,8 @@ static int adm1275_probe(struct i2c_client *client,
info->format[PSC_CURRENT_OUT] = direct;
info->format[PSC_POWER] = direct;
info->format[PSC_TEMPERATURE] = direct;
info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_SAMPLES;
info->read_word_data = adm1275_read_word_data;
info->read_byte_data = adm1275_read_byte_data;
@ -471,6 +571,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
data->have_power_sampling = true;
coefficients = adm1272_coefficients;
vindex = (config & ADM1275_VRANGE) ? 1 : 0;
@ -556,6 +657,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
data->have_power_sampling = true;
coefficients = adm1278_coefficients;
vindex = 0;
@ -591,6 +693,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_pin_min = true;
data->have_pin_max = true;
data->have_mfr_vaux_status = true;
data->have_power_sampling = true;
coefficients = adm1293_coefficients;

View File

@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for the Infineon IRPS5401M PMIC.
*
* Copyright (c) 2019 SED Systems, a division of Calian Ltd.
*
* The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however
* this driver does not currently support them.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
#define IRPS5401_SW_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | \
PMBUS_HAVE_STATUS_INPUT | \
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
#define IRPS5401_LDO_FUNC (PMBUS_HAVE_VIN | \
PMBUS_HAVE_STATUS_INPUT | \
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
static struct pmbus_driver_info irps5401_info = {
.pages = 5,
.func[0] = IRPS5401_SW_FUNC,
.func[1] = IRPS5401_SW_FUNC,
.func[2] = IRPS5401_SW_FUNC,
.func[3] = IRPS5401_SW_FUNC,
.func[4] = IRPS5401_LDO_FUNC,
};
static int irps5401_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
return pmbus_do_probe(client, id, &irps5401_info);
}
static const struct i2c_device_id irps5401_id[] = {
{"irps5401", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, irps5401_id);
static struct i2c_driver irps5401_driver = {
.driver = {
.name = "irps5401",
},
.probe = irps5401_probe,
.remove = pmbus_do_remove,
.id_table = irps5401_id,
};
module_i2c_driver(irps5401_driver);
MODULE_AUTHOR("Robert Hancock");
MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for Infineon PXE1610
*
* Copyright (c) 2019 Facebook Inc
*
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
#define PXE1610_NUM_PAGES 3
/* Identify chip parameters. */
static int pxe1610_identify(struct i2c_client *client,
struct pmbus_driver_info *info)
{
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
u8 vout_mode;
int ret;
/* Read the register with VOUT scaling value.*/
ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (ret < 0)
return ret;
vout_mode = ret & GENMASK(4, 0);
switch (vout_mode) {
case 1:
info->vrm_version = vr12;
break;
case 2:
info->vrm_version = vr13;
break;
default:
return -ENODEV;
}
}
return 0;
}
static struct pmbus_driver_info pxe1610_info = {
.pages = PXE1610_NUM_PAGES,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = vid,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_POWER] = linear,
.func[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
.func[1] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
.func[2] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
.identify = pxe1610_identify,
};
static int pxe1610_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pmbus_driver_info *info;
u8 buf[I2C_SMBUS_BLOCK_MAX];
int ret;
if (!i2c_check_functionality(
client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA
| I2C_FUNC_SMBUS_READ_WORD_DATA
| I2C_FUNC_SMBUS_READ_BLOCK_DATA))
return -ENODEV;
/*
* By default this device doesn't boot to page 0, so set page 0
* to access all pmbus registers.
*/
i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
/* Read Manufacturer id */
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
if (ret < 0) {
dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
return ret;
}
if (ret != 2 || strncmp(buf, "XP", 2)) {
dev_err(&client->dev, "MFR_ID unrecognized\n");
return -ENODEV;
}
info = devm_kmemdup(&client->dev, &pxe1610_info,
sizeof(struct pmbus_driver_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
return pmbus_do_probe(client, id, info);
}
static const struct i2c_device_id pxe1610_id[] = {
{"pxe1610", 0},
{"pxe1110", 0},
{"pxm1310", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pxe1610_id);
static struct i2c_driver pxe1610_driver = {
.driver = {
.name = "pxe1610",
},
.probe = pxe1610_probe,
.remove = pmbus_do_remove,
.id_table = pxe1610_id,
};
module_i2c_driver(pxe1610_driver);
MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
MODULE_LICENSE("GPL");

View File

@ -320,8 +320,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
dev_err(dev, "Failed to enable fan supply: %d\n", ret);
return ret;
}
devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
ctx->reg_en);
ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
ctx->reg_en);
if (ret)
return ret;
}
ctx->pwm_value = MAX_PWM;
@ -337,7 +339,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
return ret;
}
timer_setup(&ctx->rpm_timer, sample_timer, 0);
devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
if (ret)
return ret;
of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
ctx->pulses_per_revolution = ppr;

View File

@ -1,17 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Power Interface(SCPI) based hwmon sensor driver
*
* Copyright (C) 2015 ARM Ltd.
* Punit Agrawal <punit.agrawal@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/hwmon.h>

View File

@ -351,6 +351,8 @@ static ssize_t fan_div_store(struct device *dev,
tmp |= data->fan_div[2] << 4;
smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
break;
default:
BUG();
}
/* Preserve fan min */