diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 11:32:24 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 11:32:24 -0800 | 
| commit | 66b019967845a5af58802fd9af77f2317e5298a1 (patch) | |
| tree | d666203e78fb29d9b9e23a29a6d3ff04febf680d /drivers | |
| parent | a5ad88ce8c7fae7ddc72ee49a11a75aa837788e0 (diff) | |
| parent | 3b5ea47dbff0c934b7b979bcc772427a2404ed3d (diff) | |
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
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hwmon/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
| -rw-r--r-- | drivers/hwmon/abx500.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/coretemp.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/fam15h_power.c | 87 | ||||
| -rw-r--r-- | drivers/hwmon/ibmpowernv.c | 7 | ||||
| -rw-r--r-- | drivers/hwmon/ina2xx.c | 243 | ||||
| -rw-r--r-- | drivers/hwmon/lm75.c | 7 | ||||
| -rw-r--r-- | drivers/hwmon/max31790.c | 603 | ||||
| -rw-r--r-- | drivers/hwmon/nct6775.c | 101 | 
10 files changed, 886 insertions, 177 deletions
| diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e13c902e8966..796569eeaf1d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -840,6 +840,16 @@ config SENSORS_MAX6697  	  This driver can also be built as a module.  If so, the module  	  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  	tristate "Measurement Specialties HTU21D humidity/temperature sensors"  	depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 9e0f3dd2841d..01855ee641d1 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o  obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o  obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o  obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o +obj-$(CONFIG_SENSORS_MAX31790)	+= max31790.o  obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o  obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o  obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c index 1fd46859ed29..d87cae8c635f 100644 --- a/drivers/hwmon/abx500.c +++ b/drivers/hwmon/abx500.c @@ -377,7 +377,7 @@ static int setup_irqs(struct platform_device *pdev)  	}  	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)  		dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 3e03379e7c5d..6a27eb2fed17 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -52,7 +52,7 @@ module_param_named(tjmax, force_tjmax, int, 0444);  MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");  #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 MAX_CORE_ATTRS		4	/* Maximum no of basic attrs */  #define TOTAL_ATTRS		(MAX_CORE_ATTRS + 1) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index e80ee23b62d3..5f7067d7b625 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -26,6 +26,7 @@  #include <linux/pci.h>  #include <linux/bitops.h>  #include <asm/processor.h> +#include <asm/msr.h>  MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");  MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>"); @@ -41,12 +42,21 @@ MODULE_LICENSE("GPL");  #define REG_TDP_RUNNING_AVERAGE		0xe0  #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 pci_dev *pdev;  	unsigned int tdp_to_watts;  	unsigned int base_tdp;  	unsigned int processor_pwr_watts;  	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, @@ -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 umode_t fam15h_power_is_visible(struct kobject *kobj, -				       struct attribute *attr, -				       int index) +static int fam15h_power_init_attrs(struct pci_dev *pdev, +				   struct fam15h_power_data *data)  { -	/* power1_input is only reported for Fam15h, Models 00h-0fh */ -	if (attr == &dev_attr_power1_input.attr && -	   (boot_cpu_data.x86 != 0x15 || boot_cpu_data.x86_model > 0xf)) -		return 0; +	int n = FAM15H_MIN_NUM_ATTRS; +	struct attribute **fam15h_power_attrs; +	struct cpuinfo_x86 *c = &boot_cpu_data; -	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[] = { -	&dev_attr_power1_input.attr, -	&dev_attr_power1_crit.attr, -	NULL -}; +	fam15h_power_attrs = devm_kcalloc(&pdev->dev, n, +					  sizeof(*fam15h_power_attrs), +					  GFP_KERNEL); -static const struct attribute_group fam15h_power_group = { -	.attrs = fam15h_power_attrs, -	.is_visible = fam15h_power_is_visible, -}; -__ATTRIBUTE_GROUPS(fam15h_power); +	if (!fam15h_power_attrs) +		return -ENOMEM; + +	n = 0; +	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)  { @@ -186,11 +203,12 @@ static int fam15h_power_resume(struct pci_dev *pdev)  #define fam15h_power_resume NULL  #endif -static void fam15h_power_init_data(struct pci_dev *f4, -					     struct fam15h_power_data *data) +static int fam15h_power_init_data(struct pci_dev *f4, +				  struct fam15h_power_data *data)  {  	u32 val, eax, ebx, ecx, edx;  	u64 tmp; +	int ret;  	pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);  	data->base_tdp = val >> 16; @@ -211,11 +229,15 @@ static void fam15h_power_init_data(struct pci_dev *f4,  	/* convert to microWatt */  	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 Fn8000_0007:EDX[12] indicates to support accumulated power */  	if (!(edx & BIT(12))) -		return; +		return 0;  	/*  	 * determine the ratio of the compute unit power accumulator @@ -223,14 +245,24 @@ static void fam15h_power_init_data(struct pci_dev *f4,  	 * Fn8000_0007: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, -					const struct pci_device_id *id) +			      const struct pci_device_id *id)  {  	struct fam15h_power_data *data;  	struct device *dev = &pdev->dev;  	struct device *hwmon_dev; +	int ret;  	/*  	 * though we ignore every other northbridge, we still have to @@ -246,12 +278,17 @@ static int fam15h_power_probe(struct pci_dev *pdev,  	if (!data)  		return -ENOMEM; -	fam15h_power_init_data(pdev, data); +	ret = fam15h_power_init_data(pdev, data); +	if (ret) +		return ret; +  	data->pdev = pdev; +	data->groups[0] = &data->group; +  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power",  							   data, -							   fam15h_power_groups); +							   &data->groups[0]);  	return PTR_ERR_OR_ZERO(hwmon_dev);  } diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index 4255514b2c72..55b5a8ff1cfe 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -474,11 +474,18 @@ static const struct platform_device_id 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 = {  	.probe		= ibmpowernv_probe,  	.id_table	= opal_sensor_driver_ids,  	.driver		= {  		.name	= DRVNAME, +		.of_match_table	= opal_sensor_match,  	},  }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 4d2815079fc2..b24f1d3045f0 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -37,6 +37,7 @@  #include <linux/of.h>  #include <linux/delay.h>  #include <linux/util_macros.h> +#include <linux/regmap.h>  #include <linux/platform_data/ina2xx.h> @@ -84,6 +85,11 @@   */  #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 };  struct ina2xx_config { @@ -97,20 +103,13 @@ struct ina2xx_config {  };  struct ina2xx_data { -	struct i2c_client *client;  	const struct ina2xx_config *config;  	long rshunt; -	u16 curr_config; - -	struct mutex update_lock; -	bool valid; -	unsigned long last_updated; -	int update_interval; /* in jiffies */ +	struct mutex config_lock; +	struct regmap *regmap; -	int kind;  	const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS]; -	u16 regs[INA2XX_MAX_REGISTERS];  };  static const struct ina2xx_config ina2xx_config[] = { @@ -153,7 +152,11 @@ static int ina226_reg_to_interval(u16 config)  	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; @@ -162,15 +165,7 @@ static u16 ina226_interval_to_reg(int interval, u16 config)  	avg_bits = find_closest(avg, ina226_avg_tab,  				ARRAY_SIZE(ina226_avg_tab)); -	return (config & ~INA226_AVG_RD_MASK) | 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); +	return INA226_SHIFT_AVG(avg_bits);  }  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,  				    data->rshunt); -	return i2c_smbus_write_word_swapped(data->client, -					    INA2XX_CALIBRATION, val); +	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);  }  /* @@ -187,12 +181,8 @@ static int ina2xx_calibrate(struct ina2xx_data *data)   */  static int ina2xx_init(struct ina2xx_data *data)  { -	struct i2c_client *client = data->client; -	int ret; - -	/* device configuration */ -	ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, -					   data->curr_config); +	int ret = regmap_write(data->regmap, INA2XX_CONFIG, +			       data->config->config_default);  	if (ret < 0)  		return ret; @@ -203,47 +193,52 @@ static int ina2xx_init(struct ina2xx_data *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 i2c_client *client = data->client; -	int i, rv, retry; +	int ret, retry; -	dev_dbg(&client->dev, "Starting ina2xx update\n"); +	dev_dbg(dev, "Starting register %d read\n", reg);  	for (retry = 5; retry; retry--) { -		/* Read all registers */ -		for (i = 0; i < data->config->registers; i++) { -			rv = i2c_smbus_read_word_swapped(client, i); -			if (rv < 0) -				return rv; -			data->regs[i] = rv; -		} + +		ret = regmap_read(data->regmap, reg, regval); +		if (ret < 0) +			return ret; + +		dev_dbg(dev, "read %d, val = 0x%04x\n", reg, *regval);  		/*  		 * If the current value in the calibration register is 0, the  		 * power and current registers will also remain at 0. In case  		 * the chip has been reset let's check the calibration  		 * 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) { -			dev_warn(dev, "chip not calibrated, reinitializing\n"); - -			rv = ina2xx_init(data); -			if (rv < 0) -				return rv; - -			/* -			 * Let's make sure the power and current registers -			 * have been updated before trying again. -			 */ -			msleep(INA2XX_MAX_DELAY); -			continue; +		if (*regval == 0) { +			unsigned int cal; + +			ret = regmap_read(data->regmap, INA2XX_CALIBRATION, +					  &cal); +			if (ret < 0) +				return ret; + +			if (cal == 0) { +				dev_warn(dev, "chip not calibrated, reinitializing\n"); + +				ret = ina2xx_init(data); +				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;  	} @@ -256,51 +251,31 @@ static int ina2xx_do_update(struct device *dev)  	return -ENODEV;  } -static struct ina2xx_data *ina2xx_update_device(struct device *dev) -{ -	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) +static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, +			    unsigned int regval)  {  	int val;  	switch (reg) {  	case INA2XX_SHUNT_VOLTAGE:  		/* signed register */ -		val = DIV_ROUND_CLOSEST((s16)data->regs[reg], -					data->config->shunt_div); +		val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div);  		break;  	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;  		val = DIV_ROUND_CLOSEST(val, 1000);  		break;  	case INA2XX_POWER: -		val = data->regs[reg] * data->config->power_lsb; +		val = regval * data->config->power_lsb;  		break;  	case INA2XX_CURRENT:  		/* signed register, LSB=1mA (selected), in mA */ -		val = (s16)data->regs[reg]; +		val = (s16)regval;  		break;  	case INA2XX_CALIBRATION:  		val = DIV_ROUND_CLOSEST(data->config->calibration_factor, -					data->regs[reg]); +					regval);  		break;  	default:  		/* programmer goofed */ @@ -316,25 +291,25 @@ static ssize_t ina2xx_show_value(struct device *dev,  				 struct device_attribute *da, char *buf)  {  	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, ®val); -	if (IS_ERR(data)) -		return PTR_ERR(data); +	if (err < 0) +		return err;  	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,  				struct device_attribute *da,  				const char *buf, size_t count)  { -	struct ina2xx_data *data = ina2xx_update_device(dev);  	unsigned long val;  	int status; - -	if (IS_ERR(data)) -		return PTR_ERR(data); +	struct ina2xx_data *data = dev_get_drvdata(dev);  	status = kstrtoul(buf, 10, &val);  	if (status < 0) @@ -345,10 +320,10 @@ static ssize_t ina2xx_set_shunt(struct device *dev,  	    val > data->config->calibration_factor)  		return -EINVAL; -	mutex_lock(&data->update_lock); +	mutex_lock(&data->config_lock);  	data->rshunt = val;  	status = ina2xx_calibrate(data); -	mutex_unlock(&data->update_lock); +	mutex_unlock(&data->config_lock);  	if (status < 0)  		return status; @@ -370,17 +345,9 @@ static ssize_t ina226_set_interval(struct device *dev,  	if (val > INT_MAX || val == 0)  		return -EINVAL; -	mutex_lock(&data->update_lock); -	data->curr_config = ina226_interval_to_reg(val, -						   data->regs[INA2XX_CONFIG]); -	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); +	status = regmap_update_bits(data->regmap, INA2XX_CONFIG, +				    INA226_AVG_RD_MASK, +				    ina226_interval_to_reg(val));  	if (status < 0)  		return status; @@ -390,18 +357,15 @@ static ssize_t ina226_set_interval(struct device *dev,  static ssize_t ina226_show_interval(struct device *dev,  				    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)) -		return PTR_ERR(data); +	status = regmap_read(data->regmap, INA2XX_CONFIG, ®val); +	if (status) +		return status; -	/* -	 * 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])); +	return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));  }  /* shunt voltage */ @@ -455,60 +419,51 @@ static const struct attribute_group ina226_group = {  static int ina2xx_probe(struct i2c_client *client,  			const struct i2c_device_id *id)  { -	struct i2c_adapter *adapter = client->adapter; -	struct ina2xx_platform_data *pdata;  	struct device *dev = &client->dev;  	struct ina2xx_data *data;  	struct device *hwmon_dev;  	u32 val;  	int ret, group = 0; -	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) -		return -ENODEV; -  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);  	if (!data)  		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 */ -	data->kind = id->driver_data; -	data->config = &ina2xx_config[data->kind]; -	data->curr_config = data->config->config_default; -	data->client = client; +	data->config = &ina2xx_config[id->driver_data]; -	/* -	 * Ina226 has a variable update_interval. For ina219 we -	 * use a constant value. -	 */ -	if (data->kind == ina226) -		ina226_set_update_interval(data); -	else -		data->update_interval = HZ / INA2XX_CONVERSION_RATE; +	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) { +		struct ina2xx_platform_data *pdata = dev_get_platdata(dev); + +		if (pdata) +			val = pdata->shunt_uohms; +		else +			val = INA2XX_RSHUNT_DEFAULT; +	} -	if (data->rshunt <= 0 || -	    data->rshunt > data->config->calibration_factor) +	if (val <= 0 || val > data->config->calibration_factor)  		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);  	if (ret < 0) {  		dev_err(dev, "error configuring the device: %d\n", ret);  		return -ENODEV;  	} -	mutex_init(&data->update_lock); +	mutex_init(&data->config_lock);  	data->groups[group++] = &ina2xx_group; -	if (data->kind == ina226) +	if (id->driver_data == ina226)  		data->groups[group++] = &ina226_group;  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index e4e57bbafb10..0addc84ba948 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -57,6 +57,7 @@ enum lm75_type {		/* keep sorted in alphabetical order */  	tmp175,  	tmp275,  	tmp75, +	tmp75c,  };  /* Addresses scanned */ @@ -280,6 +281,11 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)  		data->resolution = 12;  		data->sample_time = HZ / 2;  		break; +	case tmp75c: +		clr_mask |= 1 << 5;		/* not one-shot mode */ +		data->resolution = 12; +		data->sample_time = HZ / 4; +		break;  	}  	/* configure as specified */ @@ -343,6 +349,7 @@ static const struct i2c_device_id lm75_ids[] = {  	{ "tmp175", tmp175, },  	{ "tmp275", tmp275, },  	{ "tmp75", tmp75, }, +	{ "tmp75c", tmp75c, },  	{ /* LIST END */ }  };  MODULE_DEVICE_TABLE(i2c, lm75_ids); diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c new file mode 100644 index 000000000000..69c0ac80a946 --- /dev/null +++ b/drivers/hwmon/max31790.c @@ -0,0 +1,603 @@ +/* + * 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"); diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 8b4fa55e46c6..d7ebdf8651f5 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -515,16 +515,24 @@ static const char *const nct6779_temp_label[] = {  	"PCH_DIM1_TEMP",  	"PCH_DIM2_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,  	    0, 0, 0, 0, 0, 0, 0, 0,  	    0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,  	    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 };  /* NCT6791 specific data */ @@ -557,6 +565,76 @@ static const u16 NCT6792_REG_TEMP_MON[] = {  static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {  	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 */  #define NCT6106_REG_VBAT	0x318 @@ -3605,7 +3683,7 @@ static int nct6775_probe(struct platform_device *pdev)  		data->speed_tolerance_limit = 63;  		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_VBAT = NCT6775_REG_VBAT; @@ -3682,8 +3760,19 @@ static int nct6775_probe(struct platform_device *pdev)  		data->tolerance_mask = 0x07;  		data->speed_tolerance_limit = 63; -		data->temp_label = nct6779_temp_label; -		data->temp_label_num = ARRAY_SIZE(nct6779_temp_label); +		switch (data->kind) { +		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_VBAT = NCT6775_REG_VBAT; | 
