Commit 66b01996 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.4' of...

Merge tag 'hwmon-for-linus-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:
 "New driver for MAX31790, added support for TMP75C, as well as cleanups
  and minor improvements in various drivers"

* tag 'hwmon-for-linus-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (fam15h_power) Add max compute unit accumulated power
  hwmon: (fam15h_power) Enable power1_input on AMD Carrizo
  hwmon: (fam15h_power) Refactor attributes for dynamically added
  hwmon: (ina2xx) remove no longer used variable 'kind'
  hwmon: (nct6775) Introduce separate temperature labels for NCT6792 and NCT6793
  hwmon: (nct6775) NCT6791D and NCT6792D have an additional temperature source
  hwmon: (ina2xx) give precedence to DT over checking for platform data.
  hwmon: (ina2xx) convert driver to using regmap
  hwmon: (coretemp) Increase limit of maximum core ID from 32 to 128.
  hwmon: (lm75) Add support for TMP75C
  hwmon: (ibmpowernv) Add OF compatibility table entry
  hwmon: (abx500) drop the use of IRQF_NO_SUSPEND
  hwmon: (max31790) Fix dereference of ERR_PTR
  hwmon: Driver for Maxim MAX31790
parents a5ad88ce 3b5ea47d
...@@ -42,8 +42,8 @@ Supported chips: ...@@ -42,8 +42,8 @@ Supported chips:
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the ST website Datasheet: Publicly available at the ST website
http://www.st.com/internet/analog/product/121769.jsp http://www.st.com/internet/analog/product/121769.jsp
* Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP175, TMP275 * Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP75C, TMP175, TMP275
Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp275' Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp75c', 'tmp275'
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the Texas Instruments website Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/product/tmp100 http://www.ti.com/product/tmp100
...@@ -51,6 +51,7 @@ Supported chips: ...@@ -51,6 +51,7 @@ Supported chips:
http://www.ti.com/product/tmp105 http://www.ti.com/product/tmp105
http://www.ti.com/product/tmp112 http://www.ti.com/product/tmp112
http://www.ti.com/product/tmp75 http://www.ti.com/product/tmp75
http://www.ti.com/product/tmp75c
http://www.ti.com/product/tmp175 http://www.ti.com/product/tmp175
http://www.ti.com/product/tmp275 http://www.ti.com/product/tmp275
* NXP LM75B * NXP LM75B
......
Kernel driver max31790
======================
Supported chips:
* Maxim MAX31790
Prefix: 'max31790'
Addresses scanned: -
Datasheet: http://pdfserv.maximintegrated.com/en/ds/MAX31790.pdf
Author: Il Han <corone.il.han@gmail.com>
Description
-----------
This driver implements support for the Maxim MAX31790 chip.
The MAX31790 controls the speeds of up to six fans using six independent
PWM outputs. The desired fan speeds (or PWM duty cycles) are written
through the I2C interface. The outputs drive "4-wire" fans directly,
or can be used to modulate the fan's power terminals using an external
pass transistor.
Tachometer inputs monitor fan tachometer logic outputs for precise (+/-1%)
monitoring and control of fan RPM as well as detection of fan failure.
Six pins are dedicated tachometer inputs. Any of the six PWM outputs can
also be configured to serve as tachometer inputs.
Sysfs entries
-------------
fan[1-12]_input RO fan tachometer speed in RPM
fan[1-12]_fault RO fan experienced fault
fan[1-6]_target RW desired fan speed in RPM
pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode
pwm[1-6] RW fan target duty cycle (0-255)
...@@ -840,6 +840,16 @@ config SENSORS_MAX6697 ...@@ -840,6 +840,16 @@ config SENSORS_MAX6697
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called max6697. will be called max6697.
config SENSORS_MAX31790
tristate "Maxim MAX31790 sensor chip"
depends on I2C
help
If you say yes here you get support for 6-Channel PWM-Output
Fan RPM Controller.
This driver can also be built as a module. If so, the module
will be called max31790.
config SENSORS_HTU21 config SENSORS_HTU21
tristate "Measurement Specialties HTU21D humidity/temperature sensors" tristate "Measurement Specialties HTU21D humidity/temperature sensors"
depends on I2C depends on I2C
......
...@@ -115,6 +115,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o ...@@ -115,6 +115,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o
......
...@@ -377,7 +377,7 @@ static int setup_irqs(struct platform_device *pdev) ...@@ -377,7 +377,7 @@ static int setup_irqs(struct platform_device *pdev)
} }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
abx500_temp_irq_handler, IRQF_NO_SUSPEND, "abx500-temp", pdev); abx500_temp_irq_handler, 0, "abx500-temp", pdev);
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret);
......
...@@ -52,7 +52,7 @@ module_param_named(tjmax, force_tjmax, int, 0444); ...@@ -52,7 +52,7 @@ module_param_named(tjmax, force_tjmax, int, 0444);
MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
#define NUM_REAL_CORES 32 /* Number of Real cores per cpu */ #define NUM_REAL_CORES 128 /* Number of Real cores per cpu */
#define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */ #define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */ #define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/msr.h>
MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>"); MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
...@@ -41,12 +42,21 @@ MODULE_LICENSE("GPL"); ...@@ -41,12 +42,21 @@ MODULE_LICENSE("GPL");
#define REG_TDP_RUNNING_AVERAGE 0xe0 #define REG_TDP_RUNNING_AVERAGE 0xe0
#define REG_TDP_LIMIT3 0xe8 #define REG_TDP_LIMIT3 0xe8
#define FAM15H_MIN_NUM_ATTRS 2
#define FAM15H_NUM_GROUPS 2
#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b
struct fam15h_power_data { struct fam15h_power_data {
struct pci_dev *pdev; struct pci_dev *pdev;
unsigned int tdp_to_watts; unsigned int tdp_to_watts;
unsigned int base_tdp; unsigned int base_tdp;
unsigned int processor_pwr_watts; unsigned int processor_pwr_watts;
unsigned int cpu_pwr_sample_ratio; unsigned int cpu_pwr_sample_ratio;
const struct attribute_group *groups[FAM15H_NUM_GROUPS];
struct attribute_group group;
/* maximum accumulated power of a compute unit */
u64 max_cu_acc_power;
}; };
static ssize_t show_power(struct device *dev, static ssize_t show_power(struct device *dev,
...@@ -105,29 +115,36 @@ static ssize_t show_power_crit(struct device *dev, ...@@ -105,29 +115,36 @@ static ssize_t show_power_crit(struct device *dev,
} }
static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL); static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
static umode_t fam15h_power_is_visible(struct kobject *kobj, static int fam15h_power_init_attrs(struct pci_dev *pdev,
struct attribute *attr, struct fam15h_power_data *data)
int index)
{ {
/* power1_input is only reported for Fam15h, Models 00h-0fh */ int n = FAM15H_MIN_NUM_ATTRS;
if (attr == &dev_attr_power1_input.attr && struct attribute **fam15h_power_attrs;
(boot_cpu_data.x86 != 0x15 || boot_cpu_data.x86_model > 0xf)) struct cpuinfo_x86 *c = &boot_cpu_data;
return 0;
return attr->mode; if (c->x86 == 0x15 &&
} (c->x86_model <= 0xf ||
(c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
n += 1;
static struct attribute *fam15h_power_attrs[] = { fam15h_power_attrs = devm_kcalloc(&pdev->dev, n,
&dev_attr_power1_input.attr, sizeof(*fam15h_power_attrs),
&dev_attr_power1_crit.attr, GFP_KERNEL);
NULL
};
static const struct attribute_group fam15h_power_group = { if (!fam15h_power_attrs)
.attrs = fam15h_power_attrs, return -ENOMEM;
.is_visible = fam15h_power_is_visible,
}; n = 0;
__ATTRIBUTE_GROUPS(fam15h_power); fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr;
if (c->x86 == 0x15 &&
(c->x86_model <= 0xf ||
(c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
fam15h_power_attrs[n++] = &dev_attr_power1_input.attr;
data->group.attrs = fam15h_power_attrs;
return 0;
}
static bool should_load_on_this_node(struct pci_dev *f4) static bool should_load_on_this_node(struct pci_dev *f4)
{ {
...@@ -186,11 +203,12 @@ static int fam15h_power_resume(struct pci_dev *pdev) ...@@ -186,11 +203,12 @@ static int fam15h_power_resume(struct pci_dev *pdev)
#define fam15h_power_resume NULL #define fam15h_power_resume NULL
#endif #endif
static void fam15h_power_init_data(struct pci_dev *f4, static int fam15h_power_init_data(struct pci_dev *f4,
struct fam15h_power_data *data) struct fam15h_power_data *data)
{ {
u32 val, eax, ebx, ecx, edx; u32 val, eax, ebx, ecx, edx;
u64 tmp; u64 tmp;
int ret;
pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val); pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
data->base_tdp = val >> 16; data->base_tdp = val >> 16;
...@@ -211,11 +229,15 @@ static void fam15h_power_init_data(struct pci_dev *f4, ...@@ -211,11 +229,15 @@ static void fam15h_power_init_data(struct pci_dev *f4,
/* convert to microWatt */ /* convert to microWatt */
data->processor_pwr_watts = (tmp * 15625) >> 10; data->processor_pwr_watts = (tmp * 15625) >> 10;
ret = fam15h_power_init_attrs(f4, data);
if (ret)
return ret;
cpuid(0x80000007, &eax, &ebx, &ecx, &edx); cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
/* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */ /* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */
if (!(edx & BIT(12))) if (!(edx & BIT(12)))
return; return 0;
/* /*
* determine the ratio of the compute unit power accumulator * determine the ratio of the compute unit power accumulator
...@@ -223,14 +245,24 @@ static void fam15h_power_init_data(struct pci_dev *f4, ...@@ -223,14 +245,24 @@ static void fam15h_power_init_data(struct pci_dev *f4,
* Fn8000_0007:ECX * Fn8000_0007:ECX
*/ */
data->cpu_pwr_sample_ratio = ecx; data->cpu_pwr_sample_ratio = ecx;
if (rdmsrl_safe(MSR_F15H_CU_MAX_PWR_ACCUMULATOR, &tmp)) {
pr_err("Failed to read max compute unit power accumulator MSR\n");
return -ENODEV;
}
data->max_cu_acc_power = tmp;
return 0;
} }
static int fam15h_power_probe(struct pci_dev *pdev, static int fam15h_power_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
struct fam15h_power_data *data; struct fam15h_power_data *data;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device *hwmon_dev; struct device *hwmon_dev;
int ret;
/* /*
* though we ignore every other northbridge, we still have to * though we ignore every other northbridge, we still have to
...@@ -246,12 +278,17 @@ static int fam15h_power_probe(struct pci_dev *pdev, ...@@ -246,12 +278,17 @@ static int fam15h_power_probe(struct pci_dev *pdev,
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
fam15h_power_init_data(pdev, data); ret = fam15h_power_init_data(pdev, data);
if (ret)
return ret;
data->pdev = pdev; data->pdev = pdev;
data->groups[0] = &data->group;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power", hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power",
data, data,
fam15h_power_groups); &data->groups[0]);
return PTR_ERR_OR_ZERO(hwmon_dev); return PTR_ERR_OR_ZERO(hwmon_dev);
} }
......
...@@ -474,11 +474,18 @@ static const struct platform_device_id opal_sensor_driver_ids[] = { ...@@ -474,11 +474,18 @@ static const struct platform_device_id opal_sensor_driver_ids[] = {
}; };
MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids); MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
static const struct of_device_id opal_sensor_match[] = {
{ .compatible = "ibm,opal-sensor" },
{ },
};
MODULE_DEVICE_TABLE(of, opal_sensor_match);
static struct platform_driver ibmpowernv_driver = { static struct platform_driver ibmpowernv_driver = {
.probe = ibmpowernv_probe, .probe = ibmpowernv_probe,
.id_table = opal_sensor_driver_ids, .id_table = opal_sensor_driver_ids,
.driver = { .driver = {
.name = DRVNAME, .name = DRVNAME,
.of_match_table = opal_sensor_match,
}, },
}; };
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/util_macros.h> #include <linux/util_macros.h>
#include <linux/regmap.h>
#include <linux/platform_data/ina2xx.h> #include <linux/platform_data/ina2xx.h>
...@@ -84,6 +85,11 @@ ...@@ -84,6 +85,11 @@
*/ */
#define INA226_TOTAL_CONV_TIME_DEFAULT 2200 #define INA226_TOTAL_CONV_TIME_DEFAULT 2200
static struct regmap_config ina2xx_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
};
enum ina2xx_ids { ina219, ina226 }; enum ina2xx_ids { ina219, ina226 };
struct ina2xx_config { struct ina2xx_config {
...@@ -97,20 +103,13 @@ struct ina2xx_config { ...@@ -97,20 +103,13 @@ struct ina2xx_config {
}; };
struct ina2xx_data { struct ina2xx_data {
struct i2c_client *client;
const struct ina2xx_config *config; const struct ina2xx_config *config;
long rshunt; long rshunt;
u16 curr_config; struct mutex config_lock;
struct regmap *regmap;
struct mutex update_lock;
bool valid;
unsigned long last_updated;
int update_interval; /* in jiffies */
int kind;
const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS]; const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
u16 regs[INA2XX_MAX_REGISTERS];
}; };
static const struct ina2xx_config ina2xx_config[] = { static const struct ina2xx_config ina2xx_config[] = {
...@@ -153,7 +152,11 @@ static int ina226_reg_to_interval(u16 config) ...@@ -153,7 +152,11 @@ static int ina226_reg_to_interval(u16 config)
return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000); return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000);
} }
static u16 ina226_interval_to_reg(int interval, u16 config) /*
* Return the new, shifted AVG field value of CONFIG register,
* to use with regmap_update_bits
*/
static u16 ina226_interval_to_reg(int interval)
{ {
int avg, avg_bits; int avg, avg_bits;
...@@ -162,15 +165,7 @@ static u16 ina226_interval_to_reg(int interval, u16 config) ...@@ -162,15 +165,7 @@ static u16 ina226_interval_to_reg(int interval, u16 config)
avg_bits = find_closest(avg, ina226_avg_tab, avg_bits = find_closest(avg, ina226_avg_tab,
ARRAY_SIZE(ina226_avg_tab)); ARRAY_SIZE(ina226_avg_tab));
return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits); return INA226_SHIFT_AVG(avg_bits);
}
static void ina226_set_update_interval(struct ina2xx_data *data)
{
int ms;
ms = ina226_reg_to_interval(data->curr_config);
data->update_interval = msecs_to_jiffies(ms);
} }
static int ina2xx_calibrate(struct ina2xx_data *data) static int ina2xx_calibrate(struct ina2xx_data *data)
...@@ -178,8 +173,7 @@ static int ina2xx_calibrate(struct ina2xx_data *data) ...@@ -178,8 +173,7 @@ static int ina2xx_calibrate(struct ina2xx_data *data)
u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
data->rshunt); data->rshunt);
return i2c_smbus_write_word_swapped(data->client, return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
INA2XX_CALIBRATION, val);
} }
/* /*
...@@ -187,12 +181,8 @@ static int ina2xx_calibrate(struct ina2xx_data *data) ...@@ -187,12 +181,8 @@ static int ina2xx_calibrate(struct ina2xx_data *data)
*/ */
static int ina2xx_init(struct ina2xx_data *data) static int ina2xx_init(struct ina2xx_data *data)
{ {
struct i2c_client *client = data->client; int ret = regmap_write(data->regmap, INA2XX_CONFIG,
int ret; data->config->config_default);
/* device configuration */
ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
data->curr_config);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -203,47 +193,52 @@ static int ina2xx_init(struct ina2xx_data *data) ...@@ -203,47 +193,52 @@ static int ina2xx_init(struct ina2xx_data *data)
return ina2xx_calibrate(data); return ina2xx_calibrate(data);
} }
static int ina2xx_do_update(struct device *dev) static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval)
{ {
struct ina2xx_data *data = dev_get_drvdata(dev); struct ina2xx_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client; int ret, retry;
int i, rv, retry;
dev_dbg(&client->dev, "Starting ina2xx update\n"); dev_dbg(dev, "Starting register %d read\n", reg);
for (retry = 5; retry; retry--) { for (retry = 5; retry; retry--) {
/* Read all registers */
for (i = 0; i < data->config->registers; i++) { ret = regmap_read(data->regmap, reg, regval);
rv = i2c_smbus_read_word_swapped(client, i); if (ret < 0)
if (rv < 0) return ret;
return rv;
data->regs[i] = rv; dev_dbg(dev, "read %d, val = 0x%04x\n", reg, *regval);
}
/* /*
* If the current value in the calibration register is 0, the * If the current value in the calibration register is 0, the
* power and current registers will also remain at 0. In case * power and current registers will also remain at 0. In case
* the chip has been reset let's check the calibration * the chip has been reset let's check the calibration
* register and reinitialize if needed. * register and reinitialize if needed.
* We do that extra read of the calibration register if there
* is some hint of a chip reset.
*/ */
if (data->regs[INA2XX_CALIBRATION] == 0) { if (*regval == 0) {
dev_warn(dev, "chip not calibrated, reinitializing\n"); unsigned int cal;
rv = ina2xx_init(data); ret = regmap_read(data->regmap, INA2XX_CALIBRATION,
if (rv < 0) &cal);
return rv; if (ret < 0)
return ret;
/*
* Let's make sure the power and current registers if (cal == 0) {
* have been updated before trying again. dev_warn(dev, "chip not calibrated, reinitializing\n");
*/
msleep(INA2XX_MAX_DELAY); ret = ina2xx_init(data);
continue; if (ret < 0)
return ret;
/*
* Let's make sure the power and current
* registers have been updated before trying
* again.
*/
msleep(INA2XX_MAX_DELAY);
continue;
}
} }
data->last_updated = jiffies;
data->valid = 1;
return 0; return 0;
} }
...@@ -256,51 +251,31 @@ static int ina2xx_do_update(struct device *dev) ...@@ -256,51 +251,31 @@ static int ina2xx_do_update(struct device *dev)
return -ENODEV; return -ENODEV;
} }
static struct ina2xx_data *ina2xx_update_device(struct device *dev) static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
{ unsigned int regval)
struct ina2xx_data *data = dev_get_drvdata(dev);
struct ina2xx_data *ret = data;
unsigned long after;
int rv;
mutex_lock(&data->update_lock);
after = data->last_updated + data->update_interval;
if (time_after(jiffies, after) || !data->valid) {
rv = ina2xx_do_update(dev);
if (rv < 0)
ret = ERR_PTR(rv);
}
mutex_unlock(&data->update_lock);
return ret;
}
static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
{ {
int val; int val;
switch (reg) { switch (reg) {
case INA2XX_SHUNT_VOLTAGE: case INA2XX_SHUNT_VOLTAGE:
/* signed register */ /* signed register */
val = DIV_ROUND_CLOSEST((s16)data->regs[reg], val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div);
data->config->shunt_div);
break; break;
case INA2XX_BUS_VOLTAGE: case INA2XX_BUS_VOLTAGE:
val = (data->regs[reg] >> data->config->bus_voltage_shift) val = (regval >> data->config->bus_voltage_shift)
* data->config->bus_voltage_lsb; * data->config->bus_voltage_lsb;
val = DIV_ROUND_CLOSEST(val, 1000); val = DIV_ROUND_CLOSEST(val, 1000);
break; break;
case INA2XX_POWER: case INA2XX_POWER:
val = data->regs[reg] * data->config->power_lsb; val = regval * data->config->power_lsb;
break; break;
case INA2XX_CURRENT: case INA2XX_CURRENT:
/* signed register, LSB=1mA (selected), in mA */ /* signed register, LSB=1mA (selected), in mA */
val = (s16)data->regs[reg]; val = (s16)regval;
break; break;
case INA2XX_CALIBRATION: case INA2XX_CALIBRATION:
val = DIV_ROUND_CLOSEST(data->config->calibration_factor, val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
data->regs[reg]); regval);
break; break;
default: default:
/* programmer goofed */ /* programmer goofed */
...@@ -316,25 +291,25 @@ static ssize_t ina2xx_show_value(struct device *dev, ...@@ -316,25 +291,25 @@ static ssize_t ina2xx_show_value(struct device *dev,
struct device_attribute *da, char *buf) struct device_attribute *da, char *buf)
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ina2xx_data *data = ina2xx_update_device(dev); struct ina2xx_data *data = dev_get_drvdata(dev);
unsigned int regval;
int err = ina2xx_read_reg(dev, attr->index, &regval);
if (IS_ERR(data)) if (err < 0)
return PTR_ERR(data); return err;
return snprintf(buf, PAGE_SIZE, "%d\n", return snprintf(buf, PAGE_SIZE, "%d\n",
ina2xx_get_value(data, attr->index)); ina2xx_get_value(data, attr->index, regval));
} }
static ssize_t ina2xx_set_shunt(struct device *dev, static ssize_t ina2xx_set_shunt(struct device *dev,
struct device_attribute *da, struct device_attribute *da,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct ina2xx_data *data = ina2xx_update_device(dev);
unsigned long val; unsigned long val;
int status; int status;
struct ina2xx_data *data = dev_get_drvdata(dev);
if (IS_ERR(data))
return PTR_ERR(data);
status = kstrtoul(buf, 10, &val); status = kstrtoul(buf, 10, &val);
if (status < 0) if (status < 0)
...@@ -345,10 +320,10 @@ static ssize_t ina2xx_set_shunt(struct device *dev, ...@@ -345,10 +320,10 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
val > data->config->calibration_factor) val > data->config->calibration_factor)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->config_lock);
data->rshunt = val; data->rshunt = val;
status = ina2xx_calibrate(data); status = ina2xx_calibrate(data);
mutex_unlock(&data->update_lock); mutex_unlock(&data->config_lock);
if (status < 0) if (status < 0)
return status; return status;
...@@ -370,17 +345,9 @@ static ssize_t ina226_set_interval(struct device *dev, ...@@ -370,17 +345,9 @@ static ssize_t ina226_set_interval(struct device *dev,
if (val > INT_MAX || val == 0) if (val > INT_MAX || val == 0)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); status = regmap_update_bits(data->regmap, INA2XX_CONFIG,
data->curr_config = ina226_interval_to_reg(val, INA226_AVG_RD_MASK,
data->regs[INA2XX_CONFIG]); ina226_interval_to_reg(val));
status = i2c_smbus_write_word_swapped(data->client,
INA2XX_CONFIG,
data->curr_config);
ina226_set_update_interval(data);
/* Make sure the next access re-reads all registers. */
data->valid = 0;
mutex_unlock(&data->update_lock);
if (status < 0) if (status < 0)
return status; return status;
...@@ -390,18 +357,15 @@ static ssize_t ina226_set_interval(struct device *dev, ...@@ -390,18 +357,15 @@ static ssize_t ina226_set_interval(struct device *dev,
static ssize_t ina226_show_interval(struct device *dev, static ssize_t ina226_show_interval(struct device *dev,
struct device_attribute *da, char *buf) struct device_attribute *da, char *buf)
{ {
struct ina2xx_data *data = ina2xx_update_device(dev); struct ina2xx_data *data = dev_get_drvdata(dev);
int status;
unsigned int regval;
if (IS_ERR(data)) status = regmap_read(data->regmap, INA2XX_CONFIG, &regval);
return PTR_ERR(data); if (status)
return status;
/* return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));
* We don't use data->update_interval here as we want to display
* the actual interval used by the chip and jiffies_to_msecs()
* doesn't seem to be accurate enough.
*/
return snprintf(buf, PAGE_SIZE, "%d\n",
ina226_reg_to_interval(data->regs[INA2XX_CONFIG]));
} }
/* shunt voltage */ /* shunt voltage */
...@@ -455,60 +419,51 @@ static const struct attribute_group ina226_group = { ...@@ -455,60 +419,51 @@ static const struct attribute_group ina226_group = {
static int ina2xx_probe(struct i2c_client *client, static int ina2xx_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct i2c_adapter *adapter = client->adapter;
struct ina2xx_platform_data *pdata;
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct ina2xx_data *data; struct ina2xx_data *data;
struct device *hwmon_dev; struct device *hwmon_dev;
u32 val; u32 val;
int ret, group = 0; int ret, group = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
if (dev_get_platdata(dev)) {
pdata = dev_get_platdata(dev);
data->rshunt = pdata->shunt_uohms;
} else if (!of_property_read_u32(dev->of_node,
"shunt-resistor", &val)) {
data->rshunt = val;
} else {
data->rshunt = INA2XX_RSHUNT_DEFAULT;
}
/* set the device type */ /* set the device type */
data->kind = id->driver_data; data->config = &ina2xx_config[id->driver_data];
data->config = &ina2xx_config[data->kind];
data->curr_config = data->config->config_default;
data->client = client;
/* if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
* Ina226 has a variable update_interval. For ina219 we struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
* use a constant value.
*/ if (pdata)
if (data->kind == ina226) val = pdata->shunt_uohms;
ina226_set_update_interval(data); else
else val = INA2XX_RSHUNT_DEFAULT;
data->update_interval = HZ / INA2XX_CONVERSION_RATE; }
if (data->rshunt <= 0 || if (val <= 0 || val > data->config->calibration_factor)
data->rshunt > data->config->calibration_factor)
return -ENODEV; return -ENODEV;
data->rshunt = val;
ina2xx_regmap_config.max_register = data->config->registers;
data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(dev, "failed to allocate register map\n");
return PTR_ERR(data->regmap);
}
ret = ina2xx_init(data); ret = ina2xx_init(data);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "error configuring the device: %d\n", ret); dev_err(dev, "error configuring the device: %d\n", ret);
return -ENODEV; return -ENODEV;
} }
mutex_init(&data->update_lock); mutex_init(&data->config_lock);
data->groups[group++] = &ina2xx_group; data->groups[group++] = &ina2xx_group;
if (data->kind == ina226) if (id->driver_data == ina226)
data->groups[group++] = &ina226_group; data->groups[group++] = &ina226_group;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
......
...@@ -57,6 +57,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ ...@@ -57,6 +57,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
tmp175, tmp175,
tmp275, tmp275,
tmp75, tmp75,
tmp75c,
}; };
/* Addresses scanned */ /* Addresses scanned */
...@@ -280,6 +281,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -280,6 +281,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->resolution = 12; data->resolution = 12;
data->sample_time = HZ / 2; data->sample_time = HZ / 2;
break; break;
case tmp75c:
clr_mask |= 1 << 5; /* not one-shot mode */
data->resolution = 12;
data->sample_time = HZ / 4;
break;
} }
/* configure as specified */ /* configure as specified */
...@@ -343,6 +349,7 @@ static const struct i2c_device_id lm75_ids[] = { ...@@ -343,6 +349,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "tmp175", tmp175, }, { "tmp175", tmp175, },
{ "tmp275", tmp275, }, { "tmp275", tmp275, },
{ "tmp75", tmp75, }, { "tmp75", tmp75, },
{ "tmp75c", tmp75c, },
{ /* LIST END */ } { /* LIST END */ }
}; };
MODULE_DEVICE_TABLE(i2c, lm75_ids); MODULE_DEVICE_TABLE(i2c, lm75_ids);
......
/*
* max31790.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring.
*
* (C) 2015 by Il Han <corone.il.han@gmail.com>
*
* 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>
/* MAX31790 registers */
#define MAX31790_REG_GLOBAL_CONFIG 0x00
#define MAX31790_REG_FAN_CONFIG(ch) (0x02 + (ch))
#define MAX31790_REG_FAN_DYNAMICS(ch) (0x08 + (ch))
#define MAX31790_REG_FAN_FAULT_STATUS2 0x10
#define MAX31790_REG_FAN_FAULT_STATUS1 0x11
#define MAX31790_REG_TACH_COUNT(ch) (0x18 + (ch) * 2)
#define MAX31790_REG_PWM_DUTY_CYCLE(ch) (0x30 + (ch) * 2)
#define MAX31790_REG_PWMOUT(ch) (0x40 + (ch) * 2)
#define MAX31790_REG_TARGET_COUNT(ch) (0x50 + (ch) * 2)
/* Fan Config register bits */
#define MAX31790_FAN_CFG_RPM_MODE 0x80
#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08
#define MAX31790_FAN_CFG_TACH_INPUT 0x01
/* Fan Dynamics register bits */
#define MAX31790_FAN_DYN_SR_SHIFT 5
#define MAX31790_FAN_DYN_SR_MASK 0xE0
#define SR_FROM_REG(reg) (((reg) & MAX31790_FAN_DYN_SR_MASK) \
>> MAX31790_FAN_DYN_SR_SHIFT)
#define FAN_RPM_MIN 120
#define FAN_RPM_MAX 7864320
#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \
((60 * (sr) * 8192) / ((reg) >> 4)) : \
FAN_RPM_MAX)
#define RPM_TO_REG(rpm, sr) ((60 * (sr) * 8192) / ((rpm) * 2))
#define NR_CHANNEL 6
/*
* Client data (each client gets its own)
*/
struct max31790_data {
struct i2c_client *client;
struct mutex update_lock;
bool valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
u8 fan_config[NR_CHANNEL];
u8 fan_dynamics[NR_CHANNEL];
u16 fault_status;
u16 tach[NR_CHANNEL * 2];
u16 pwm[NR_CHANNEL];
u16 target_count[NR_CHANNEL];
};
static struct max31790_data *max31790_update_device(struct device *dev)
{
struct max31790_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
struct max31790_data *ret = data;
int i;
int rv;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_FAULT_STATUS1);
if (rv < 0)
goto abort;
data->fault_status = rv & 0x3F;
rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_FAULT_STATUS2);
if (rv < 0)
goto abort;
data->fault_status |= (rv & 0x3F) << 6;
for (i = 0; i < NR_CHANNEL; i++) {
rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_TACH_COUNT(i));
if (rv < 0)
goto abort;
data->tach[i] = rv;
if (data->fan_config[i]
& MAX31790_FAN_CFG_TACH_INPUT) {
rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_TACH_COUNT(NR_CHANNEL
+ i));
if (rv < 0)
goto abort;
data->tach[NR_CHANNEL + i] = rv;
} else {
rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_PWMOUT(i));
if (rv < 0)
goto abort;
data->pwm[i] = rv;
rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_TARGET_COUNT(i));
if (rv < 0)
goto abort;
data->target_count[i] = rv;
}
}
data->last_updated = jiffies;
data->valid = true;
}
goto done;
abort:
data->valid = false;
ret = ERR_PTR(rv);
done:
mutex_unlock(&data->update_lock);
return ret;
}
static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 };
static u8 get_tach_period(u8 fan_dynamics)
{
return tach_period[SR_FROM_REG(fan_dynamics)];
}
static u8 bits_for_tach_period(int rpm)
{
u8 bits;
if (rpm < 500)
bits = 0x0;
else if (rpm < 1000)
bits = 0x1;
else if (rpm < 2000)
bits = 0x2;
else if (rpm < 4000)
bits = 0x3;
else if (rpm < 8000)
bits = 0x4;
else
bits = 0x5;
return bits;
}
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 max31790_data *data = max31790_update_device(dev);
int sr, rpm;
if (IS_ERR(data))
return PTR_ERR(data);
sr = get_tach_period(data->fan_dynamics[attr->index]);
rpm = RPM_FROM_REG(data->tach[attr->index], sr);
return sprintf(buf, "%d\n", rpm);
}
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 max31790_data *data = max31790_update_device(dev);
int sr, rpm;
if (IS_ERR(data))
return PTR_ERR(data);
sr = get_tach_period(data->fan_dynamics[attr->index]);
rpm = RPM_FROM_REG(data->target_count[attr->index], sr);
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 max31790_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
u8 bits;
int sr;
int target_count;
unsigned long rpm;
int err;
err = kstrtoul(buf, 10, &rpm);
if (err)
return err;
mutex_lock(&data->update_lock);
rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
bits = bits_for_tach_period(rpm);
data->fan_dynamics[attr->index] =
((data->fan_dynamics[attr->index]
& ~MAX31790_FAN_DYN_SR_MASK)
| (bits << MAX31790_FAN_DYN_SR_SHIFT));
err = i2c_smbus_write_byte_data(client,
MAX31790_REG_FAN_DYNAMICS(attr->index),
data->fan_dynamics[attr->index]);
if (err < 0) {
mutex_unlock(&data->update_lock);
return err;
}
sr = get_tach_period(data->fan_dynamics[attr->index]);
target_count = RPM_TO_REG(rpm, sr);
target_count = clamp_val(target_count, 0x1, 0x7FF);
data->target_count[attr->index] = target_count << 5;
err = i2c_smbus_write_word_swapped(client,
MAX31790_REG_TARGET_COUNT(attr->index),
data->target_count[attr->index]);
mutex_unlock(&data->update_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 max31790_data *data = max31790_update_device(dev);
int pwm;
if (IS_ERR(data))
return PTR_ERR(data);
pwm = data->pwm[attr->index] >> 8;
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 max31790_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->update_lock);
data->pwm[attr->index] = pwm << 8;
err = i2c_smbus_write_word_swapped(client,
MAX31790_REG_PWMOUT(attr->index),
data->pwm[attr->index]);
mutex_unlock(&data->update_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 max31790_data *data = max31790_update_device(dev);
int mode;
if (IS_ERR(data))
return PTR_ERR(data);
if (data->fan_config[attr->index] & MAX31790_FAN_CFG_RPM_MODE)
mode = 2;
else if (data->fan_config[attr->index] & MAX31790_FAN_CFG_TACH_INPUT_EN)
mode = 1;
else
mode = 0;
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 max31790_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]
& ~(MAX31790_FAN_CFG_TACH_INPUT_EN
| MAX31790_FAN_CFG_RPM_MODE);
break;
case 1:
data->fan_config[attr->index] =
(data->fan_config[attr->index]
| MAX31790_FAN_CFG_TACH_INPUT_EN)
& ~MAX31790_FAN_CFG_RPM_MODE;
break;
case 2:
data->fan_config[attr->index] =
data->fan_config[attr->index]
| MAX31790_FAN_CFG_TACH_INPUT_EN
| MAX31790_FAN_CFG_RPM_MODE;
break;
default:
return -EINVAL;
}
mutex_lock(&data->update_lock);
err = i2c_smbus_write_byte_data(client,
MAX31790_REG_FAN_CONFIG(attr->index),
data->fan_config[attr->index]);
mutex_unlock(&data->update_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 max31790_data *data = max31790_update_device(dev);
int fault;
if (IS_ERR(data))
return PTR_ERR(data);
fault = !!(data->fault_status & (1 << attr->index));
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(fan7_input, S_IRUGO, get_fan, NULL, 6);
static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, get_fan, NULL, 7);
static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, get_fan, NULL, 8);
static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, get_fan, NULL, 9);
static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, get_fan, NULL, 10);
static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, get_fan, NULL, 11);
static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, get_fan_fault, NULL, 6);
static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, get_fan_fault, NULL, 7);
static SENSOR_DEVICE_ATTR(fan9_fault, S_IRUGO, get_fan_fault, NULL, 8);
static SENSOR_DEVICE_ATTR(fan10_fault, S_IRUGO, get_fan_fault, NULL, 9);
static SENSOR_DEVICE_ATTR(fan11_fault, S_IRUGO, get_fan_fault, NULL, 10);
static SENSOR_DEVICE_ATTR(fan12_fault, S_IRUGO, get_fan_fault, NULL, 11);
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(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 *max31790_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_fan7_input.dev_attr.attr,
&sensor_dev_attr_fan8_input.dev_attr.attr,
&sensor_dev_attr_fan9_input.dev_attr.attr,
&sensor_dev_attr_fan10_input.dev_attr.attr,
&sensor_dev_attr_fan11_input.dev_attr.attr,
&sensor_dev_attr_fan12_input.dev_attr.attr,
&sensor_dev_attr_fan7_fault.dev_attr.attr,
&sensor_dev_attr_fan8_fault.dev_attr.attr,
&sensor_dev_attr_fan9_fault.dev_attr.attr,
&sensor_dev_attr_fan10_fault.dev_attr.attr,
&sensor_dev_attr_fan11_fault.dev_attr.attr,
&sensor_dev_attr_fan12_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_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 max31790_attrs_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct max31790_data *data = dev_get_drvdata(dev);
struct device_attribute *devattr =
container_of(a, struct device_attribute, attr);
int index = to_sensor_dev_attr(devattr)->index % NR_CHANNEL;
u8 fan_config;
fan_config = data->fan_config[index];
if (n >= NR_CHANNEL * 2 && n < NR_CHANNEL * 4 &&
!(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
return 0;
if (n >= NR_CHANNEL * 4 && (fan_config & MAX31790_FAN_CFG_TACH_INPUT))
return 0;
return a->mode;
}
static const struct attribute_group max31790_group = {
.attrs = max31790_attrs,
.is_visible = max31790_attrs_visible,
};
__ATTRIBUTE_GROUPS(max31790);
static int max31790_init_client(struct i2c_client *client,
struct max31790_data *data)
{
int i, rv;
for (i = 0; i < NR_CHANNEL; i++) {
rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_CONFIG(i));
if (rv < 0)
return rv;
data->fan_config[i] = rv;
rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_DYNAMICS(i));
if (rv < 0)
return rv;
data->fan_dynamics[i] = rv;
}
return 0;
}
static int max31790_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct max31790_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 max31790_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->update_lock);
/*
* Initialize the max31790 chip
*/
err = max31790_init_client(client, data);
if (err)
return err;
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
client->name, data, max31790_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max31790_id[] = {
{ "max31790", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31790_id);
static struct i2c_driver max31790_driver = {
.class = I2C_CLASS_HWMON,
.probe = max31790_probe,
.driver = {
.name = "max31790",
},
.id_table = max31790_id,
};
module_i2c_driver(max31790_driver);
MODULE_AUTHOR("Il Han <corone.il.han@gmail.com>");
MODULE_DESCRIPTION("MAX31790 sensor driver");
MODULE_LICENSE("GPL");
...@@ -515,16 +515,24 @@ static const char *const nct6779_temp_label[] = { ...@@ -515,16 +515,24 @@ static const char *const nct6779_temp_label[] = {
"PCH_DIM1_TEMP", "PCH_DIM1_TEMP",
"PCH_DIM2_TEMP", "PCH_DIM2_TEMP",
"PCH_DIM3_TEMP", "PCH_DIM3_TEMP",
"BYTE_TEMP" "BYTE_TEMP",
"",
"",
"",
"",
"Virtual_TEMP"
}; };
static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1] #define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5)
#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label)
static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1]
= { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0, = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
0x408, 0 }; 0x408, 0 };
static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1]
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
/* NCT6791 specific data */ /* NCT6791 specific data */
...@@ -557,6 +565,76 @@ static const u16 NCT6792_REG_TEMP_MON[] = { ...@@ -557,6 +565,76 @@ static const u16 NCT6792_REG_TEMP_MON[] = {
static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = { static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
0xb2, 0xb3, 0xb4, 0xb5, 0xbf }; 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
static const char *const nct6792_temp_label[] = {
"",
"SYSTIN",
"CPUTIN",
"AUXTIN0",
"AUXTIN1",
"AUXTIN2",
"AUXTIN3",
"",
"SMBUSMASTER 0",
"SMBUSMASTER 1",
"SMBUSMASTER 2",
"SMBUSMASTER 3",
"SMBUSMASTER 4",
"SMBUSMASTER 5",
"SMBUSMASTER 6",
"SMBUSMASTER 7",
"PECI Agent 0",
"PECI Agent 1",
"PCH_CHIP_CPU_MAX_TEMP",
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
"PCH_DIM0_TEMP",
"PCH_DIM1_TEMP",
"PCH_DIM2_TEMP",
"PCH_DIM3_TEMP",
"BYTE_TEMP",
"PECI Agent 0 Calibration",
"PECI Agent 1 Calibration",
"",
"",
"Virtual_TEMP"
};
static const char *const nct6793_temp_label[] = {
"",
"SYSTIN",
"CPUTIN",
"AUXTIN0",
"AUXTIN1",
"AUXTIN2",
"AUXTIN3",
"",
"SMBUSMASTER 0",
"SMBUSMASTER 1",
"",
"",
"",
"",
"",
"",
"PECI Agent 0",
"PECI Agent 1",
"PCH_CHIP_CPU_MAX_TEMP",
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
"Agent0 Dimm0 ",
"Agent0 Dimm1",
"Agent1 Dimm0",
"Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration",
"PECI Agent 1 Calibration",
"",
"Virtual_TEMP"
};
/* NCT6102D/NCT6106D specific data */ /* NCT6102D/NCT6106D specific data */
#define NCT6106_REG_VBAT 0x318 #define NCT6106_REG_VBAT 0x318
...@@ -3605,7 +3683,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3605,7 +3683,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->speed_tolerance_limit = 63; data->speed_tolerance_limit = 63;
data->temp_label = nct6779_temp_label; data->temp_label = nct6779_temp_label;
data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); data->temp_label_num = NCT6779_NUM_LABELS;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
...@@ -3682,8 +3760,19 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3682,8 +3760,19 @@ static int nct6775_probe(struct platform_device *pdev)
data->tolerance_mask = 0x07; data->tolerance_mask = 0x07;
data->speed_tolerance_limit = 63; data->speed_tolerance_limit = 63;
data->temp_label = nct6779_temp_label; switch (data->kind) {
data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); default:
case nct6791:
data->temp_label = nct6779_temp_label;
break;
case nct6792:
data->temp_label = nct6792_temp_label;
break;
case nct6793:
data->temp_label = nct6793_temp_label;
break;
}
data->temp_label_num = NCT6791_NUM_LABELS;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment