cregit-Linux how code gets into the kernel

Release 4.11 drivers/hwmon/lm85.c

Directory: drivers/hwmon
/*
 * lm85.c - Part of lm_sensors, Linux kernel modules for hardware
 *          monitoring
 * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
 * Copyright (c) 2002, 2003  Philip Pokorny <ppokorny@penguincomputing.com>
 * Copyright (c) 2003        Margit Schubert-While <margitsw@t-online.de>
 * Copyright (c) 2004        Justin Thiessen <jthiessen@penguincomputing.com>
 * Copyright (C) 2007--2014  Jean Delvare <jdelvare@suse.de>
 *
 * Chip details at            <http://www.national.com/ds/LM/LM85.pdf>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/util_macros.h>

/* Addresses to scan */

static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };


enum chips {
	
lm85,
	


adm1027, adt7463, adt7468,
	



emc6d100, emc6d102, emc6d103, emc6d103s
};

/* The LM85 registers */


#define LM85_REG_IN(nr)			(0x20 + (nr))

#define LM85_REG_IN_MIN(nr)		(0x44 + (nr) * 2)

#define LM85_REG_IN_MAX(nr)		(0x45 + (nr) * 2)


#define LM85_REG_TEMP(nr)		(0x25 + (nr))

#define LM85_REG_TEMP_MIN(nr)		(0x4e + (nr) * 2)

#define LM85_REG_TEMP_MAX(nr)		(0x4f + (nr) * 2)

/* Fan speeds are LSB, MSB (2 bytes) */

#define LM85_REG_FAN(nr)		(0x28 + (nr) * 2)

#define LM85_REG_FAN_MIN(nr)		(0x54 + (nr) * 2)


#define LM85_REG_PWM(nr)		(0x30 + (nr))


#define LM85_REG_COMPANY		0x3e

#define LM85_REG_VERSTEP		0x3f


#define ADT7468_REG_CFG5		0x7c

#define ADT7468_OFF64			(1 << 0)

#define ADT7468_HFPWM			(1 << 1)

#define IS_ADT7468_OFF64(data)		\
	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))

#define IS_ADT7468_HFPWM(data)		\
	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_HFPWM))

/* These are the recognized values for the above regs */

#define LM85_COMPANY_NATIONAL		0x01

#define LM85_COMPANY_ANALOG_DEV		0x41

#define LM85_COMPANY_SMSC		0x5c

#define LM85_VERSTEP_LM85C		0x60

#define LM85_VERSTEP_LM85B		0x62

#define LM85_VERSTEP_LM96000_1		0x68

#define LM85_VERSTEP_LM96000_2		0x69

#define LM85_VERSTEP_ADM1027		0x60

#define LM85_VERSTEP_ADT7463		0x62

#define LM85_VERSTEP_ADT7463C		0x6A

#define LM85_VERSTEP_ADT7468_1		0x71

#define LM85_VERSTEP_ADT7468_2		0x72

#define LM85_VERSTEP_EMC6D100_A0        0x60

#define LM85_VERSTEP_EMC6D100_A1        0x61

#define LM85_VERSTEP_EMC6D102		0x65

#define LM85_VERSTEP_EMC6D103_A0	0x68

#define LM85_VERSTEP_EMC6D103_A1	0x69

#define LM85_VERSTEP_EMC6D103S		0x6A	
/* Also known as EMC6D103:A2 */


#define LM85_REG_CONFIG			0x40


#define LM85_REG_ALARM1			0x41

#define LM85_REG_ALARM2			0x42


#define LM85_REG_VID			0x43

/* Automated FAN control */

#define LM85_REG_AFAN_CONFIG(nr)	(0x5c + (nr))

#define LM85_REG_AFAN_RANGE(nr)		(0x5f + (nr))

#define LM85_REG_AFAN_SPIKE1		0x62

#define LM85_REG_AFAN_MINPWM(nr)	(0x64 + (nr))

#define LM85_REG_AFAN_LIMIT(nr)		(0x67 + (nr))

#define LM85_REG_AFAN_CRITICAL(nr)	(0x6a + (nr))

#define LM85_REG_AFAN_HYST1		0x6d

#define LM85_REG_AFAN_HYST2		0x6e


#define ADM1027_REG_EXTEND_ADC1		0x76

#define ADM1027_REG_EXTEND_ADC2		0x77


#define EMC6D100_REG_ALARM3             0x7d
/* IN5, IN6 and IN7 */

#define EMC6D100_REG_IN(nr)             (0x70 + ((nr) - 5))

#define EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr) - 5) * 2)

#define EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr) - 5) * 2)

#define EMC6D102_REG_EXTEND_ADC1	0x85

#define EMC6D102_REG_EXTEND_ADC2	0x86

#define EMC6D102_REG_EXTEND_ADC3	0x87

#define EMC6D102_REG_EXTEND_ADC4	0x88

/*
 * Conversions. Rounding and limit checking is only done on the TO_REG
 * variants. Note that you should be a bit careful with which arguments
 * these macros are called: arguments may be evaluated more than once.
 */

/* IN are scaled according to built-in resistors */

static const int lm85_scaling[] = {  /* .001 Volts */
	2500, 2250, 3300, 5000, 12000,
	3300, 1500, 1800 /*EMC6D100*/
};

#define SCALE(val, from, to)	(((val) * (to) + ((from) / 2)) / (from))


#define INS_TO_REG(n, val)	\
		SCALE(clamp_val(val, 0, 255 * lm85_scaling[n] / 192), \
                      lm85_scaling[n], 192)


#define INSEXT_FROM_REG(n, val, ext)	\
		SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])


#define INS_FROM_REG(n, val)	SCALE((val), 192, lm85_scaling[n])

/* FAN speed is measured using 90kHz clock */

static inline u16 FAN_TO_REG(unsigned long val) { if (!val) return 0xffff; return clamp_val(5400000 / val, 1, 0xfffe); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare2683.87%133.33%
Margit Schubert-While412.90%133.33%
Guenter Roeck13.23%133.33%
Total31100.00%3100.00%

#define FAN_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ 5400000 / (val)) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ DIV_ROUND_CLOSEST(clamp_val((val), -127000, 127000), 1000) #define TEMPEXT_FROM_REG(val, ext) \ SCALE(((val) << 4) + (ext), 16, 1000) #define TEMP_FROM_REG(val) ((val) * 1000) #define PWM_TO_REG(val) clamp_val(val, 0, 255) #define PWM_FROM_REG(val) (val) /* * ZONEs have the following parameters: * Limit (low) temp, 1. degC * Hysteresis (below limit), 1. degC (0-15) * Range of speed control, .1 degC (2-80) * Critical (high) temp, 1. degC * * FAN PWMs have the following parameters: * Reference Zone, 1, 2, 3, etc. * Spinup time, .05 sec * PWM value at limit/low temp, 1 count * PWM Frequency, 1. Hz * PWM is Min or OFF below limit, flag * Invert PWM output, flag * * Some chips filter the temp, others the fan. * Filter constant (or disabled) .1 seconds */ /* These are the zone temperature range encodings in .001 degree C */ static const int lm85_range_map[] = { 2000, 2500, 3300, 4000, 5000, 6600, 8000, 10000, 13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000 };
static int RANGE_TO_REG(long range) { return find_closest(range, lm85_range_map, ARRAY_SIZE(lm85_range_map)); }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While1150.00%125.00%
Bartosz Golaszewski940.91%125.00%
Justin Thiessen14.55%125.00%
Guenter Roeck14.55%125.00%
Total22100.00%4100.00%

#define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f] /* These are the PWM frequency encodings */ static const int lm85_freq_map[8] = { /* 1 Hz */ 10, 15, 23, 30, 38, 47, 61, 94 }; static const int adm1027_freq_map[8] = { /* 1 Hz */ 11, 15, 22, 29, 35, 44, 59, 88 }; #define FREQ_MAP_LEN 8
static int FREQ_TO_REG(const int *map, unsigned int map_size, unsigned long freq) { return find_closest(freq, map, map_size); }

Contributors

PersonTokensPropCommitsCommitProp
Bartosz Golaszewski1137.93%125.00%
Margit Schubert-While1034.48%125.00%
Jean Delvare620.69%125.00%
Guenter Roeck26.90%125.00%
Total29100.00%4100.00%


static int FREQ_FROM_REG(const int *map, u8 reg) { return map[reg & 0x07]; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare1986.36%150.00%
Margit Schubert-While313.64%150.00%
Total22100.00%2100.00%

/* * Since we can't use strings, I'm abusing these numbers * to stand in for the following meanings: * 1 -- PWM responds to Zone 1 * 2 -- PWM responds to Zone 2 * 3 -- PWM responds to Zone 3 * 23 -- PWM responds to the higher temp of Zone 2 or 3 * 123 -- PWM responds to highest of Zone 1, 2, or 3 * 0 -- PWM is always at 0% (ie, off) * -1 -- PWM is always at 100% * -2 -- PWM responds to manual control */ static const int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; #define ZONE_FROM_REG(val) lm85_zone_map[(val) >> 5]
static int ZONE_TO_REG(int zone) { int i; for (i = 0; i <= 7; ++i) if (zone == lm85_zone_map[i]) break; if (i > 7) /* Not found. */ i = 3; /* Always 100% */ return i << 5; }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While5198.08%150.00%
Jean Delvare11.92%150.00%
Total52100.00%2100.00%

#define HYST_TO_REG(val) clamp_val(((val) + 500) / 1000, 0, 15) #define HYST_FROM_REG(val) ((val) * 1000) /* * Chip sampling rates * * Some sensors are not updated more frequently than once per second * so it doesn't make sense to read them more often than that. * We cache the results and return the saved data if the driver * is called again before a second has elapsed. * * Also, there is significant configuration data for this chip * given the automatic PWM fan control that is possible. There * are about 47 bytes of config data to only 22 bytes of actual * readings. So, we keep the config data up to date in the cache * when it is written and only sample it once every 1 *minute* */ #define LM85_DATA_INTERVAL (HZ + HZ / 2) #define LM85_CONFIG_INTERVAL (1 * 60 * HZ) /* * LM85 can automatically adjust fan speeds based on temperature * This structure encapsulates an entire Zone config. There are * three zones (one for each temperature input) on the lm85 */ struct lm85_zone { s8 limit; /* Low temp limit */ u8 hyst; /* Low limit hysteresis. (0-15) */ u8 range; /* Temp range, encoded */ s8 critical; /* "All fans ON" temp limit */ u8 max_desired; /* * Actual "max" temperature specified. Preserved * to prevent "drift" as other autofan control * values change. */ }; struct lm85_autofan { u8 config; /* Register value */ u8 min_pwm; /* Minimum PWM value, encoded */ u8 min_off; /* Min PWM or OFF below "limit", flag */ }; /* * For each registered chip, we need to keep some data in memory. * The structure is dynamically allocated. */ struct lm85_data { struct i2c_client *client; const struct attribute_group *groups[6]; const int *freq_map; enum chips type; bool has_vid5; /* true if VID5 is configured for ADT7463 or ADT7468 */ struct mutex update_lock; int valid; /* !=0 if following fields are valid */ unsigned long last_reading; /* In jiffies */ unsigned long last_config; /* In jiffies */ u8 in[8]; /* Register value */ u8 in_max[8]; /* Register value */ u8 in_min[8]; /* Register value */ s8 temp[3]; /* Register value */ s8 temp_min[3]; /* Register value */ s8 temp_max[3]; /* Register value */ u16 fan[4]; /* Register value */ u16 fan_min[4]; /* Register value */ u8 pwm[3]; /* Register value */ u8 pwm_freq[3]; /* Register encoding */ u8 temp_ext[3]; /* Decoded values */ u8 in_ext[8]; /* Decoded values */ u8 vid; /* Register value */ u8 vrm; /* VRM version */ u32 alarms; /* Register encoding, combined */ u8 cfg5; /* Config Register 5 on ADT7468 */ struct lm85_autofan autofan[3]; struct lm85_zone zone[3]; };
static int lm85_read_value(struct i2c_client *client, u8 reg) { int res; /* What size location is it? */ switch (reg) { case LM85_REG_FAN(0): /* Read WORD data */ case LM85_REG_FAN(1): case LM85_REG_FAN(2): case LM85_REG_FAN(3): case LM85_REG_FAN_MIN(0): case LM85_REG_FAN_MIN(1): case LM85_REG_FAN_MIN(2): case LM85_REG_FAN_MIN(3): case LM85_REG_ALARM1: /* Read both bytes at once */ res = i2c_smbus_read_byte_data(client, reg) & 0xff; res |= i2c_smbus_read_byte_data(client, reg + 1) << 8; break; default: /* Read BYTE data */ res = i2c_smbus_read_byte_data(client, reg); break; } return res; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin10388.03%125.00%
Margit Schubert-While97.69%125.00%
Jean Delvare43.42%125.00%
Darren Jenkins10.85%125.00%
Total117100.00%4100.00%


static void lm85_write_value(struct i2c_client *client, u8 reg, int value) { switch (reg) { case LM85_REG_FAN(0): /* Write WORD data */ case LM85_REG_FAN(1): case LM85_REG_FAN(2): case LM85_REG_FAN(3): case LM85_REG_FAN_MIN(0): case LM85_REG_FAN_MIN(1): case LM85_REG_FAN_MIN(2): case LM85_REG_FAN_MIN(3): /* NOTE: ALARM is read only, so not included here */ i2c_smbus_write_byte_data(client, reg, value & 0xff); i2c_smbus_write_byte_data(client, reg + 1, value >> 8); break; default: /* Write BYTE data */ i2c_smbus_write_byte_data(client, reg, value); break; } }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin9586.36%125.00%
Margit Schubert-While1311.82%125.00%
Jean Delvare10.91%125.00%
Darren Jenkins10.91%125.00%
Total110100.00%4100.00%


static struct lm85_data *lm85_update_device(struct device *dev) { struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int i; mutex_lock(&data->update_lock); if (!data->valid || time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL)) { /* Things that change quickly */ dev_dbg(&client->dev, "Reading sensor values\n"); /* * Have to read extended bits first to "freeze" the * more significant bits that are read later. * There are 2 additional resolution bits per channel and we * have room for 4, so we shift them to the left. */ if (data->type == adm1027 || data->type == adt7463 || data->type == adt7468) { int ext1 = lm85_read_value(client, ADM1027_REG_EXTEND_ADC1); int ext2 = lm85_read_value(client, ADM1027_REG_EXTEND_ADC2); int val = (ext1 << 8) + ext2; for (i = 0; i <= 4; i++) data->in_ext[i] = ((val >> (i * 2)) & 0x03) << 2; for (i = 0; i <= 2; i++) data->temp_ext[i] = (val >> ((i + 4) * 2)) & 0x0c; } data->vid = lm85_read_value(client, LM85_REG_VID); for (i = 0; i <= 3; ++i) { data->in[i] = lm85_read_value(client, LM85_REG_IN(i)); data->fan[i] = lm85_read_value(client, LM85_REG_FAN(i)); } if (!data->has_vid5) data->in[4] = lm85_read_value(client, LM85_REG_IN(4)); if (data->type == adt7468) data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5); for (i = 0; i <= 2; ++i) { data->temp[i] = lm85_read_value(client, LM85_REG_TEMP(i)); data->pwm[i] = lm85_read_value(client, LM85_REG_PWM(i)); if (IS_ADT7468_OFF64(data)) data->temp[i] -= 64; } data->alarms = lm85_read_value(client, LM85_REG_ALARM1); if (data->type == emc6d100) { /* Three more voltage sensors */ for (i = 5; i <= 7; ++i) { data->in[i] = lm85_read_value(client, EMC6D100_REG_IN(i)); } /* More alarm bits */ data->alarms |= lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; } else if (data->type == emc6d102 || data->type == emc6d103 || data->type == emc6d103s) { /* * Have to read LSB bits after the MSB ones because * the reading of the MSB bits has frozen the * LSBs (backward from the ADM1027). */ int ext1 = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC1); int ext2 = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC2); int ext3 = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC3); int ext4 = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC4); data->in_ext[0] = ext3 & 0x0f; data->in_ext[1] = ext4 & 0x0f; data->in_ext[2] = ext4 >> 4; data->in_ext[3] = ext3 >> 4; data->in_ext[4] = ext2 >> 4; data->temp_ext[0] = ext1 & 0x0f; data->temp_ext[1] = ext2 & 0x0f; data->temp_ext[2] = ext1 >> 4; } data->last_reading = jiffies; } /* last_reading */ if (!data->valid || time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL)) { /* Things that don't change often */ dev_dbg(&client->dev, "Reading config values\n"); for (i = 0; i <= 3; ++i) { data->in_min[i] = lm85_read_value(client, LM85_REG_IN_MIN(i)); data->in_max[i] = lm85_read_value(client, LM85_REG_IN_MAX(i)); data->fan_min[i] = lm85_read_value(client, LM85_REG_FAN_MIN(i)); } if (!data->has_vid5) { data->in_min[4] = lm85_read_value(client, LM85_REG_IN_MIN(4)); data->in_max[4] = lm85_read_value(client, LM85_REG_IN_MAX(4)); } if (data->type == emc6d100) { for (i = 5; i <= 7; ++i) { data->in_min[i] = lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); data->in_max[i] = lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); } } for (i = 0; i <= 2; ++i) { int val; data->temp_min[i] = lm85_read_value(client, LM85_REG_TEMP_MIN(i)); data->temp_max[i] = lm85_read_value(client, LM85_REG_TEMP_MAX(i)); data->autofan[i].config = lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); data->pwm_freq[i] = val & 0x07; data->zone[i].range = val >> 4; data->autofan[i].min_pwm = lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); data->zone[i].limit = lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); data->zone[i].critical = lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); if (IS_ADT7468_OFF64(data)) { data->temp_min[i] -= 64; data->temp_max[i] -= 64; data->zone[i].limit -= 64; data->zone[i].critical -= 64; } } if (data->type != emc6d103s) { i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); data->autofan[0].min_off = (i & 0x20) != 0; data->autofan[1].min_off = (i & 0x40) != 0; data->autofan[2].min_off = (i & 0x80) != 0; i = lm85_read_value(client, LM85_REG_AFAN_HYST1); data->zone[0].hyst = i >> 4; data->zone[1].hyst = i & 0x0f; i = lm85_read_value(client, LM85_REG_AFAN_HYST2); data->zone[2].hyst = i >> 4; } data->last_config = jiffies; } /* last_config */ data->valid = 1; mutex_unlock(&data->update_lock); return data; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin93180.40%216.67%
Margit Schubert-While1129.67%216.67%
Jean Delvare917.86%541.67%
Guenter Roeck131.12%18.33%
Mark M. Hoffman70.60%18.33%
Greg Kroah-Hartman40.35%18.33%
Total1158100.00%12100.00%

/* 4 Fans */
static ssize_t show_fan(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While3153.45%125.00%
Jean Delvare1525.86%125.00%
Axel Lin1017.24%125.00%
Mark M. Hoffman23.45%125.00%
Total58100.00%4100.00%


static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin2950.00%150.00%
Jean Delvare2950.00%150.00%
Total58100.00%2100.00%


static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val); lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare6248.82%125.00%
Axel Lin4636.22%250.00%
Guenter Roeck1914.96%125.00%
Total127100.00%4100.00%

#define show_fan_offset(offset) \ static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ show_fan, NULL, offset - 1); \ static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_min, set_fan_min, offset - 1) show_fan_offset(1); show_fan_offset(2); show_fan_offset(3); show_fan_offset(4); /* vid, vrm, alarms */
static ssize_t cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); int vid; if (data->has_vid5) { /* 6-pin VID (VRM 10) */ vid = vid_from_reg(data->vid & 0x3f, data->vrm); } else { /* 5-pin VID (VRM 9) */ vid = vid_from_reg(data->vid & 0x1f, data->vrm); } return sprintf(buf, "%d\n", vid); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare5665.12%360.00%
Axel Lin2933.72%120.00%
Julia Lawall11.16%120.00%
Total86100.00%5100.00%

static DEVICE_ATTR_RO(cpu0_vid);
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare2351.11%133.33%
Axel Lin2146.67%133.33%
Julia Lawall12.22%133.33%
Total45100.00%3100.00%


static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lm85_data *data = dev_get_drvdata(dev); unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; if (val > 255) return -EINVAL; data->vrm = val; return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin3139.24%120.00%
Jean Delvare2835.44%240.00%
Guenter Roeck1924.05%120.00%
Julia Lawall11.27%120.00%
Total79100.00%5100.00%

static DEVICE_ATTR_RW(vrm);
static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%u\n", data->alarms); }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While2969.05%116.67%
Jean Delvare511.90%116.67%
Rafael Ávila de Espíndola37.14%116.67%
Mark M. Hoffman24.76%116.67%
Axel Lin24.76%116.67%
Julia Lawall12.38%116.67%
Total42100.00%6100.00%

static DEVICE_ATTR_RO(alarms);
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While3356.90%125.00%
Jean Delvare1525.86%125.00%
Axel Lin813.79%125.00%
Mark M. Hoffman23.45%125.00%
Total58100.00%4100.00%

static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18); static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16); static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17); static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11); static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12); static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13); /* pwm */
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While3763.79%125.00%
Jean Delvare1525.86%125.00%
Axel Lin46.90%125.00%
Mark M. Hoffman23.45%125.00%
Total58100.00%4100.00%


static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->pwm[nr] = PWM_TO_REG(val); lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Margit Schubert-While7256.69%225.00%
Jean Delvare2217.32%225.00%
Guenter Roeck1713.39%112.50%
Axel Lin1411.02%225.00%
Ingo Molnar21.57%112.50%
Total127100.00%8100.00%


static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); int pwm_zone, enable; pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); switch (pwm_zone) { case -1: /* PWM is always at 100% */ enable = 0; break; case 0: /* PWM is always at 0% */ case -2: /* PWM responds to manual control */ enable = 1; break; default: /* PWM in automatic mode */ enable = 2; } return sprintf(buf, "%d\n", enable); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin8177.14%133.33%
Margit Schubert-While1918.10%133.33%
Rafael Ávila de Espíndola54.76%133.33%
Total105100.00%3100.00%


static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; u8 config; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; switch (val) { case 0: config = 3; break; case 1: config = 7; break; case 2: /* * Here we have to choose arbitrarily one of the 5 possible * configurations; I go for the safest */ config = 6; break; default: return -EINVAL; } mutex_lock(&data->update_lock); data->autofan[nr].config = lm85_read_value(client, LM85_REG_AFAN_CONFIG(nr)); data->autofan[nr].config = (data->autofan[nr].config & ~0xe0) | (config << 5); lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), data->autofan[nr].config); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin9345.59%222.22%
Margit Schubert-While6732.84%222.22%
Jean Delvare2210.78%222.22%
Guenter Roeck178.33%111.11%
Darrick J. Wong31.47%111.11%
Ingo Molnar20.98%111.11%
Total204100.00%9100.00%


static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); int freq; if (IS_ADT7468_HFPWM(data)) freq = 22500; else freq = FREQ_FROM_REG(data->freq_map, data->pwm_freq[nr]); return sprintf(buf, "%d\n", freq); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin3239.51%125.00%
Margit Schubert-While3239.51%125.00%
Jean Delvare1518.52%125.00%
Mark M. Hoffman22.47%125.00%
Total81100.00%4100.00%


static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); /* * The ADT7468 has a special high-frequency PWM output mode, * where all PWM outputs are driven by a 22.5 kHz clock. * This might confuse the user, but there's not much we can do. */ if (data->type == adt7468 && val >= 11300) { /* High freq. mode */ data->cfg5 &= ~ADT7468_HFPWM; lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5); } else { /* Low freq. mode */ data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, FREQ_MAP_LEN, val); lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), (data->zone[nr].range << 4) | data->pwm_freq[nr]); if (data->type == adt7468) { data->cfg5 |= ADT7468_HFPWM; lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5); } } mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin9444.55%220.00%
Margit Schubert-While7033.18%220.00%
Jean Delvare2210.43%220.00%
Guenter Roeck178.06%110.00%
Darrick J. Wong52.37%110.00%
Bartosz Golaszewski20.95%110.00%
Ingo Molnar10.47%110.00%
Total211100.00%10100.00%

#define show_pwm_reg(offset) \ static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ show_pwm, set_pwm, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ show_pwm_enable, set_pwm_enable, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \ show_pwm_freq, set_pwm_freq, offset - 1) show_pwm_reg(1); show_pwm_reg(2); show_pwm_reg(3); /* Voltages */
static ssize_t show_in(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", INSEXT_FROM_REG(nr, data->in[nr], data->in_ext[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen2841.79%125.00%
Jean Delvare1522.39%125.00%
Axel Lin1217.91%125.00%
Margit Schubert-While1217.91%125.00%
Total67100.00%4100.00%


static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen2643.33%125.00%
Jean Delvare1525.00%125.00%
Margit Schubert-While1220.00%125.00%
Axel Lin711.67%125.00%
Total60100.00%4100.00%


static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->in_min[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen7256.25%114.29%
Jean Delvare2217.19%228.57%
Guenter Roeck1713.28%114.29%
Axel Lin1511.72%228.57%
Ingo Molnar21.56%114.29%
Total128100.00%7100.00%


static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen3863.33%133.33%
Jean Delvare1525.00%133.33%
Axel Lin711.67%133.33%
Total60100.00%3100.00%


static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->in_max[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen6450.00%112.50%
Jean Delvare2418.75%337.50%
Axel Lin2015.62%225.00%
Guenter Roeck1814.06%112.50%
Ingo Molnar21.56%112.50%
Total128100.00%8100.00%

#define show_in_reg(offset) \ static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in, NULL, offset); \ static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ show_in_min, set_in_min, offset); \ static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ show_in_max, set_in_max, offset) show_in_reg(0); show_in_reg(1); show_in_reg(2); show_in_reg(3); show_in_reg(4); show_in_reg(5); show_in_reg(6); show_in_reg(7); /* Temps */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMPEXT_FROM_REG(data->temp[nr], data->temp_ext[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen2944.62%133.33%
Axel Lin2132.31%133.33%
Jean Delvare1523.08%133.33%
Total65100.00%3100.00%


static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin4882.76%150.00%
Justin Thiessen1017.24%150.00%
Total58100.00%2100.00%


static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; if (IS_ADT7468_OFF64(data)) val += 64; mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen7454.01%114.29%
Axel Lin2518.25%228.57%
Jean Delvare1913.87%228.57%
Guenter Roeck1813.14%114.29%
Ingo Molnar10.73%114.29%
Total137100.00%7100.00%


static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen4170.69%133.33%
Jean Delvare1525.86%133.33%
Axel Lin23.45%133.33%
Total58100.00%3100.00%


static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; if (IS_ADT7468_OFF64(data)) val += 64; mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen6547.45%114.29%
Axel Lin3122.63%228.57%
Jean Delvare2216.06%228.57%
Guenter Roeck1813.14%114.29%
Ingo Molnar10.73%114.29%
Total137100.00%7100.00%

#define show_temp_reg(offset) \ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ show_temp, NULL, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ show_temp_min, set_temp_min, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ show_temp_max, set_temp_max, offset - 1); show_temp_reg(1); show_temp_reg(2); show_temp_reg(3); /* Automatic PWM control */
static ssize_t show_pwm_auto_channels(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", ZONE_FROM_REG(data->autofan[nr].config)); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen4168.33%133.33%
Jean Delvare1525.00%133.33%
Axel Lin46.67%133.33%
Total60100.00%3100.00%


static ssize_t set_pwm_auto_channels(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) | ZONE_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), data->autofan[nr].config); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen8155.48%114.29%
Axel Lin2416.44%228.57%
Jean Delvare2114.38%228.57%
Guenter Roeck1812.33%114.29%
Ingo Molnar21.37%114.29%
Total146100.00%7100.00%


static ssize_t show_pwm_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen4168.33%133.33%
Jean Delvare1525.00%133.33%
Axel Lin46.67%133.33%
Total60100.00%3100.00%


static ssize_t set_pwm_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->autofan[nr].min_pwm = PWM_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), data->autofan[nr].min_pwm); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Justin Thiessen7456.49%114.29%
Jean Delvare2216.79%228.57%
Guenter Roeck1712.98%114.29%
Axel Lin1612.21%228.57%
Ingo Molnar21.53%114.29%
Total131100.00%7100.00%


static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", data->autofan[nr].min_off); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin5494.74%150.00%
Justin Thiessen35.26%150.00%
Total57100.00%2100.00%


static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; u8 tmp; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->autofan[nr].min_off = val; tmp = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); tmp &= ~(0x20 << nr); if (data->autofan[nr].min_off) tmp |= 0x20 << nr; lm85_write_value(client, LM85_REG_AFAN_SPIKE1, tmp); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin155100.00%2100.00%
Total155100.00%2100.00%

#define pwm_auto(offset) \ static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels, \ S_IRUGO | S_IWUSR, show_pwm_auto_channels, \ set_pwm_auto_channels, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min, \ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min, \ set_pwm_auto_pwm_min, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, \ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl, \ set_pwm_auto_pwm_minctl, offset - 1) pwm_auto(1); pwm_auto(2); pwm_auto(3); /* Temperature settings for automatic PWM control */
static ssize_t show_temp_auto_temp_off(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) - HYST_FROM_REG(data->zone[nr].hyst)); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin6590.28%120.00%
Mark M. Hoffman34.17%120.00%
Justin Thiessen22.78%120.00%
Jean Delvare11.39%120.00%
Ben Dooks11.39%120.00%
Total72100.00%5100.00%


static ssize_t set_temp_auto_temp_off(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int min; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); min = TEMP_FROM_REG(data->zone[nr].limit); data->zone[nr].hyst = HYST_TO_REG(min - val); if (nr == 0 || nr == 1) { lm85_write_value(client, LM85_REG_AFAN_HYST1, (data->zone[0].hyst << 4) | data->zone[1].hyst); } else { lm85_write_value(client, LM85_REG_AFAN_HYST2, (data->zone[2].hyst << 4)); } mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin18494.85%233.33%
Mark M. Hoffman52.58%116.67%
Jean Delvare21.03%116.67%
Margit Schubert-While21.03%116.67%
Greg Kroah-Hartman10.52%116.67%
Total194100.00%6100.00%


static ssize_t show_temp_auto_temp_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit)); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin5795.00%150.00%
Jean Delvare35.00%150.00%
Total60100.00%2100.00%


static ssize_t set_temp_auto_temp_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->zone[nr].limit = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), data->zone[nr].limit); /* Update temp_auto_max and temp_auto_range */ data->zone[nr].range = RANGE_TO_REG( TEMP_FROM_REG(data->zone[nr].max_desired) - TEMP_FROM_REG(data->zone[nr].limit)); lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), ((data->zone[nr].range & 0x0f) << 4) | (data->pwm_freq[nr] & 0x07)); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin19293.66%225.00%
Jean Delvare62.93%337.50%
Mark M. Hoffman41.95%112.50%
Greg Kroah-Hartman20.98%112.50%
Rafael Ávila de Espíndola10.49%112.50%
Total205100.00%8100.00%


static ssize_t show_temp_auto_temp_max(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) + RANGE_FROM_REG(data->zone[nr].range)); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin6894.44%125.00%
Jean Delvare34.17%250.00%
Mark M. Hoffman11.39%125.00%
Total72100.00%4100.00%


static ssize_t set_temp_auto_temp_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int min; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); min = TEMP_FROM_REG(data->zone[nr].limit); data->zone[nr].max_desired = TEMP_TO_REG(val); data->zone[nr].range = RANGE_TO_REG( val - min); lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), ((data->zone[nr].range & 0x0f) << 4) | (data->pwm_freq[nr] & 0x07)); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin17193.96%240.00%
Mark M. Hoffman94.95%240.00%
Jean Delvare21.10%120.00%
Total182100.00%5100.00%


static ssize_t show_temp_auto_temp_crit(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].critical)); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin5795.00%150.00%
Jean Delvare35.00%150.00%
Total60100.00%2100.00%


static ssize_t set_temp_auto_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->zone[nr].critical = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), data->zone[nr].critical); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin12898.46%266.67%
Jean Delvare21.54%133.33%
Total130100.00%3100.00%

#define temp_auto(offset) \ static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off, \ S_IRUGO | S_IWUSR, show_temp_auto_temp_off, \ set_temp_auto_temp_off, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min, \ S_IRUGO | S_IWUSR, show_temp_auto_temp_min, \ set_temp_auto_temp_min, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max, \ S_IRUGO | S_IWUSR, show_temp_auto_temp_max, \ set_temp_auto_temp_max, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit, \ S_IRUGO | S_IWUSR, show_temp_auto_temp_crit, \ set_temp_auto_temp_crit, offset - 1); temp_auto(1); temp_auto(2); temp_auto(3); static struct attribute *lm85_attributes[] = { &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_fan1_min.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr, &sensor_dev_attr_fan4_alarm.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_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm1_freq.dev_attr.attr, &sensor_dev_attr_pwm2_freq.dev_attr.attr, &sensor_dev_attr_pwm3_freq.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_temp2_alarm.dev_attr.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_temp1_fault.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr, &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr, &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr, &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr, &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr, &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr, &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, &dev_attr_alarms.attr, NULL }; static const struct attribute_group lm85_group = { .attrs = lm85_attributes, }; static struct attribute *lm85_attributes_minctl[] = { &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, NULL }; static const struct attribute_group lm85_group_minctl = { .attrs = lm85_attributes_minctl, }; static struct attribute *lm85_attributes_temp_off[] = { &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, NULL }; static const struct attribute_group lm85_group_temp_off = { .attrs = lm85_attributes_temp_off, }; static struct attribute *lm85_attributes_in4[] = { &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, &sensor_dev_attr_in4_alarm.dev_attr.attr, NULL }; static const struct attribute_group lm85_group_in4 = { .attrs = lm85_attributes_in4, }; static struct attribute *lm85_attributes_in567[] = { &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, &sensor_dev_attr_in6_min.dev_attr.attr, &sensor_dev_attr_in7_min.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, &sensor_dev_attr_in7_max.dev_attr.attr, &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_in7_alarm.dev_attr.attr, NULL }; static const struct attribute_group lm85_group_in567 = { .attrs = lm85_attributes_in567, };
static void lm85_init_client(struct i2c_client *client) { int value; /* Start monitoring if needed */ value = lm85_read_value(client, LM85_REG_CONFIG); if (!(value & 0x01)) { dev_info(&client->dev, "Starting monitoring\n"); lm85_write_value(client, LM85_REG_CONFIG, value | 0x01); } /* Warn about unusual configuration bits */ if (value & 0x02) dev_warn(&client->dev, "Device configuration is locked\n"); if (!(value & 0x04)) dev_warn(&client->dev, "Device is not ready\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin5660.87%116.67%
Jean Delvare1314.13%233.33%
Margit Schubert-While1111.96%116.67%
Darrick J. Wong77.61%116.67%
Rafael Ávila de Espíndola55.43%116.67%
Total92100.00%6100.00%


static int lm85_is_fake(struct i2c_client *client) { /* * Differenciate between real LM96000 and Winbond WPCD377I. The latter * emulate the former except that it has no hardware monitoring function * so the readings are always 0. */ int i; u8 in_temp, fan; for (i = 0; i < 8; i++) { in_temp = i2c_smbus_read_byte_data(client, 0x20 + i); fan = i2c_smbus_read_byte_data(client, 0x28 + i); if (in_temp != 0x00 || fan != 0xff) return 0; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin4865.75%120.00%
Rafael Ávila de Espíndola1824.66%240.00%
Margit Schubert-While68.22%120.00%
Guenter Roeck11.37%120.00%
Total73100.00%5100.00%

/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; int address = client->addr; const char *type_name = NULL; int company, verstep; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { /* We need to be able to do byte I/O */ return -ENODEV; } /* Determine the chip type */ company = lm85_read_value(client, LM85_REG_COMPANY); verstep = lm85_read_value(client, LM85_REG_VERSTEP); dev_dbg(&adapter->dev, "Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n", address, company, verstep); if (company == LM85_COMPANY_NATIONAL) { switch (verstep) { case LM85_VERSTEP_LM85C: type_name = "lm85c"; break; case LM85_VERSTEP_LM85B: type_name = "lm85b"; break; case LM85_VERSTEP_LM96000_1: case LM85_VERSTEP_LM96000_2: /* Check for Winbond WPCD377I */ if (lm85_is_fake(client)) { dev_dbg(&adapter->dev, "Found Winbond WPCD377I, ignoring\n"); return -ENODEV; } type_name = "lm85"; break; } } else if (company == LM85_COMPANY_ANALOG_DEV) { switch (verstep) { case LM85_VERSTEP_ADM1027: type_name = "adm1027"; break; case LM85_VERSTEP_ADT7463: case LM85_VERSTEP_ADT7463C: type_name = "adt7463"; break; case LM85_VERSTEP_ADT7468_1: case LM85_VERSTEP_ADT7468_2: type_name = "adt7468"; break; } } else if (company == LM85_COMPANY_SMSC) { switch (verstep) { case LM85_VERSTEP_EMC6D100_A0: case LM85_VERSTEP_EMC6D100_A1: /* Note: we can't tell a '100 from a '101 */ type_name = "emc6d100"; break; case LM85_VERSTEP_EMC6D102: type_name = "emc6d102"; break; case LM85_VERSTEP_EMC6D103_A0: case LM85_VERSTEP_EMC6D103_A1: type_name = "emc6d103"; break; case LM85_VERSTEP_EMC6D103S: type_name = "emc6d103s"; break; } } if (!type_name) return -ENODEV; strlcpy(info->type, type_name, I2C_NAME_SIZE); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin23382.33%125.00%
Rafael Ávila de Espíndola3713.07%125.00%
Margit Schubert-While124.24%125.00%
Greg Kroah-Hartman10.35%125.00%
Total283100.00%4100.00%


static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device *hwmon_dev; struct lm85_data *data; int idx = 0; data = devm_kzalloc(dev, sizeof(struct lm85_data), GFP_KERNEL); if (!data) return -ENOMEM; data->client = client; data->type = id->driver_data; mutex_init(&data->update_lock); /* Fill in the chip specific driver values */ switch (data->type) { case adm1027: case adt7463: case adt7468: case emc6d100: case emc6d102: case emc6d103: case emc6d103s: data->freq_map = adm1027_freq_map; break; default: data->freq_map = lm85_freq_map; } /* Set the VRM version */ data->vrm = vid_which_vrm(); /* Initialize the LM85 chip */ lm85_init_client(client); /* sysfs hooks */ data->groups[idx++] = &lm85_group; /* minctl and temp_off exist on all chips except emc6d103s */ if (data->type != emc6d103s) { data->groups[idx++] = &lm85_group_minctl; data->groups[idx++] = &lm85_group_temp_off; } /* * The ADT7463/68 have an optional VRM 10 mode where pin 21 is used * as a sixth digital VID input rather than an analog input. */ if (data->type == adt7463 || data->type == adt7468) { u8 vid = lm85_read_value(client, LM85_REG_VID); if (vid & 0x80) data->has_vid5 = true; } if (!data->has_vid5) data->groups[idx++] = &lm85_group_in4; /* The EMC6D100 has 3 additional voltage inputs */ if (data->type == emc6d100) data->groups[idx++] = &lm85_group_in567; hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, data->groups); return PTR_ERR_OR_ZERO(hwmon_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Axel Lin22175.95%225.00%
Margit Schubert-While5017.18%112.50%
Darrick J. Wong103.44%112.50%
Guenter Roeck51.72%112.50%
Rafael Ávila de Espíndola20.69%112.50%
Jean Delvare20.69%112.50%
Mark M. Hoffman10.34%112.50%
Total291100.00%8100.00%

static const struct i2c_device_id lm85_id[] = { { "adm1027", adm1027 }, { "adt7463", adt7463 }, { "adt7468", adt7468 }, { "lm85", lm85 }, { "lm85b", lm85 }, { "lm85c", lm85 }, { "emc6d100", emc6d100 }, { "emc6d101", emc6d100 }, { "emc6d102", emc6d102 }, { "emc6d103", emc6d103 }, { "emc6d103s", emc6d103s }, { } }; MODULE_DEVICE_TABLE(i2c, lm85_id); static struct i2c_driver lm85_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "lm85", }, .probe = lm85_probe, .id_table = lm85_id, .detect = lm85_detect, .address_list = normal_i2c, }; module_i2c_driver(lm85_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, " "Margit Schubert-While <margitsw@t-online.de>, " "Justin Thiessen <jthiessen@penguincomputing.com>"); MODULE_DESCRIPTION("LM85-B, LM85-C driver");

Overall Contributors

PersonTokensPropCommitsCommitProp
Axel Lin441753.32%35.88%
Margit Schubert-While134016.18%23.92%
Jean Delvare105412.72%2243.14%
Justin Thiessen7479.02%11.96%
Guenter Roeck2452.96%611.76%
Mark M. Hoffman1812.18%47.84%
Rafael Ávila de Espíndola1621.96%23.92%
Darrick J. Wong530.64%11.96%
Bartosz Golaszewski290.35%11.96%
Ingo Molnar190.23%11.96%
Jan Beulich150.18%11.96%
Greg Kroah-Hartman80.10%23.92%
Julia Lawall70.08%11.96%
Alexey Dobriyan30.04%11.96%
Darren Jenkins20.02%11.96%
Ben Dooks10.01%11.96%
Lucas De Marchi10.01%11.96%
Total8284100.00%51100.00%
Directory: drivers/hwmon
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.