xref: /openbmc/linux/drivers/hwmon/adm9240.c (revision 1f57ff89)
18d5d45fbSJean Delvare /*
28d5d45fbSJean Delvare  * adm9240.c	Part of lm_sensors, Linux kernel modules for hardware
38d5d45fbSJean Delvare  * 		monitoring
48d5d45fbSJean Delvare  *
58d5d45fbSJean Delvare  * Copyright (C) 1999	Frodo Looijaard <frodol@dds.nl>
68d5d45fbSJean Delvare  *			Philip Edelbrock <phil@netroedge.com>
78d5d45fbSJean Delvare  * Copyright (C) 2003	Michiel Rook <michiel@grendelproject.nl>
88d5d45fbSJean Delvare  * Copyright (C) 2005	Grant Coady <gcoady@gmail.com> with valuable
98d5d45fbSJean Delvare  * 				guidance from Jean Delvare
108d5d45fbSJean Delvare  *
118d5d45fbSJean Delvare  * Driver supports	Analog Devices		ADM9240
128d5d45fbSJean Delvare  *			Dallas Semiconductor	DS1780
138d5d45fbSJean Delvare  *			National Semiconductor	LM81
148d5d45fbSJean Delvare  *
158d5d45fbSJean Delvare  * ADM9240 is the reference, DS1780 and LM81 are register compatibles
168d5d45fbSJean Delvare  *
178d5d45fbSJean Delvare  * Voltage	Six inputs are scaled by chip, VID also reported
188d5d45fbSJean Delvare  * Temperature	Chip temperature to 0.5'C, maximum and max_hysteris
198d5d45fbSJean Delvare  * Fans		2 fans, low speed alarm, automatic fan clock divider
208d5d45fbSJean Delvare  * Alarms	16-bit map of active alarms
218d5d45fbSJean Delvare  * Analog Out	0..1250 mV output
228d5d45fbSJean Delvare  *
238d5d45fbSJean Delvare  * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear'
248d5d45fbSJean Delvare  *
258d5d45fbSJean Delvare  * Test hardware: Intel SE440BX-2 desktop motherboard --Grant
268d5d45fbSJean Delvare  *
278d5d45fbSJean Delvare  * LM81 extended temp reading not implemented
288d5d45fbSJean Delvare  *
298d5d45fbSJean Delvare  * This program is free software; you can redistribute it and/or modify
308d5d45fbSJean Delvare  * it under the terms of the GNU General Public License as published by
318d5d45fbSJean Delvare  * the Free Software Foundation; either version 2 of the License, or
328d5d45fbSJean Delvare  * (at your option) any later version.
338d5d45fbSJean Delvare  *
348d5d45fbSJean Delvare  * This program is distributed in the hope that it will be useful,
358d5d45fbSJean Delvare  * but WITHOUT ANY WARRANTY; without even the implied warranty of
368d5d45fbSJean Delvare  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
378d5d45fbSJean Delvare  * GNU General Public License for more details.
388d5d45fbSJean Delvare  *
398d5d45fbSJean Delvare  * You should have received a copy of the GNU General Public License
408d5d45fbSJean Delvare  * along with this program; if not, write to the Free Software
418d5d45fbSJean Delvare  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
428d5d45fbSJean Delvare  */
438d5d45fbSJean Delvare 
448d5d45fbSJean Delvare #include <linux/init.h>
458d5d45fbSJean Delvare #include <linux/module.h>
468d5d45fbSJean Delvare #include <linux/slab.h>
478d5d45fbSJean Delvare #include <linux/i2c.h>
488d5d45fbSJean Delvare #include <linux/i2c-sensor.h>
498d5d45fbSJean Delvare #include <linux/i2c-vid.h>
508d5d45fbSJean Delvare 
518d5d45fbSJean Delvare /* Addresses to scan */
528d5d45fbSJean Delvare static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
538d5d45fbSJean Delvare 					I2C_CLIENT_END };
548d5d45fbSJean Delvare 
558d5d45fbSJean Delvare static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
568d5d45fbSJean Delvare 
578d5d45fbSJean Delvare /* Insmod parameters */
588d5d45fbSJean Delvare SENSORS_INSMOD_3(adm9240, ds1780, lm81);
598d5d45fbSJean Delvare 
608d5d45fbSJean Delvare /* ADM9240 registers */
618d5d45fbSJean Delvare #define ADM9240_REG_MAN_ID		0x3e
628d5d45fbSJean Delvare #define ADM9240_REG_DIE_REV		0x3f
638d5d45fbSJean Delvare #define ADM9240_REG_CONFIG		0x40
648d5d45fbSJean Delvare 
658d5d45fbSJean Delvare #define ADM9240_REG_IN(nr)		(0x20 + (nr))   /* 0..5 */
668d5d45fbSJean Delvare #define ADM9240_REG_IN_MAX(nr)		(0x2b + (nr) * 2)
678d5d45fbSJean Delvare #define ADM9240_REG_IN_MIN(nr)		(0x2c + (nr) * 2)
688d5d45fbSJean Delvare #define ADM9240_REG_FAN(nr)		(0x28 + (nr))   /* 0..1 */
698d5d45fbSJean Delvare #define ADM9240_REG_FAN_MIN(nr)		(0x3b + (nr))
708d5d45fbSJean Delvare #define ADM9240_REG_INT(nr)		(0x41 + (nr))
718d5d45fbSJean Delvare #define ADM9240_REG_INT_MASK(nr)	(0x43 + (nr))
728d5d45fbSJean Delvare #define ADM9240_REG_TEMP		0x27
738d5d45fbSJean Delvare #define ADM9240_REG_TEMP_HIGH		0x39
748d5d45fbSJean Delvare #define ADM9240_REG_TEMP_HYST		0x3a
758d5d45fbSJean Delvare #define ADM9240_REG_ANALOG_OUT		0x19
768d5d45fbSJean Delvare #define ADM9240_REG_CHASSIS_CLEAR	0x46
778d5d45fbSJean Delvare #define ADM9240_REG_VID_FAN_DIV		0x47
788d5d45fbSJean Delvare #define ADM9240_REG_I2C_ADDR		0x48
798d5d45fbSJean Delvare #define ADM9240_REG_VID4		0x49
808d5d45fbSJean Delvare #define ADM9240_REG_TEMP_CONF		0x4b
818d5d45fbSJean Delvare 
828d5d45fbSJean Delvare /* generalised scaling with integer rounding */
838d5d45fbSJean Delvare static inline int SCALE(long val, int mul, int div)
848d5d45fbSJean Delvare {
858d5d45fbSJean Delvare 	if (val < 0)
868d5d45fbSJean Delvare 		return (val * mul - div / 2) / div;
878d5d45fbSJean Delvare 	else
888d5d45fbSJean Delvare 		return (val * mul + div / 2) / div;
898d5d45fbSJean Delvare }
908d5d45fbSJean Delvare 
918d5d45fbSJean Delvare /* adm9240 internally scales voltage measurements */
928d5d45fbSJean Delvare static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
938d5d45fbSJean Delvare 
948d5d45fbSJean Delvare static inline unsigned int IN_FROM_REG(u8 reg, int n)
958d5d45fbSJean Delvare {
968d5d45fbSJean Delvare 	return SCALE(reg, nom_mv[n], 192);
978d5d45fbSJean Delvare }
988d5d45fbSJean Delvare 
998d5d45fbSJean Delvare static inline u8 IN_TO_REG(unsigned long val, int n)
1008d5d45fbSJean Delvare {
1018d5d45fbSJean Delvare 	return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
1028d5d45fbSJean Delvare }
1038d5d45fbSJean Delvare 
1048d5d45fbSJean Delvare /* temperature range: -40..125, 127 disables temperature alarm */
1058d5d45fbSJean Delvare static inline s8 TEMP_TO_REG(long val)
1068d5d45fbSJean Delvare {
1078d5d45fbSJean Delvare 	return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
1088d5d45fbSJean Delvare }
1098d5d45fbSJean Delvare 
1108d5d45fbSJean Delvare /* two fans, each with low fan speed limit */
1118d5d45fbSJean Delvare static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
1128d5d45fbSJean Delvare {
1138d5d45fbSJean Delvare 	if (!reg) /* error */
1148d5d45fbSJean Delvare 		return -1;
1158d5d45fbSJean Delvare 
1168d5d45fbSJean Delvare 	if (reg == 255)
1178d5d45fbSJean Delvare 		return 0;
1188d5d45fbSJean Delvare 
1198d5d45fbSJean Delvare 	return SCALE(1350000, 1, reg * div);
1208d5d45fbSJean Delvare }
1218d5d45fbSJean Delvare 
1228d5d45fbSJean Delvare /* analog out 0..1250mV */
1238d5d45fbSJean Delvare static inline u8 AOUT_TO_REG(unsigned long val)
1248d5d45fbSJean Delvare {
1258d5d45fbSJean Delvare 	return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
1268d5d45fbSJean Delvare }
1278d5d45fbSJean Delvare 
1288d5d45fbSJean Delvare static inline unsigned int AOUT_FROM_REG(u8 reg)
1298d5d45fbSJean Delvare {
1308d5d45fbSJean Delvare 	return SCALE(reg, 1250, 255);
1318d5d45fbSJean Delvare }
1328d5d45fbSJean Delvare 
1338d5d45fbSJean Delvare static int adm9240_attach_adapter(struct i2c_adapter *adapter);
1348d5d45fbSJean Delvare static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
1358d5d45fbSJean Delvare static void adm9240_init_client(struct i2c_client *client);
1368d5d45fbSJean Delvare static int adm9240_detach_client(struct i2c_client *client);
1378d5d45fbSJean Delvare static struct adm9240_data *adm9240_update_device(struct device *dev);
1388d5d45fbSJean Delvare 
1398d5d45fbSJean Delvare /* driver data */
1408d5d45fbSJean Delvare static struct i2c_driver adm9240_driver = {
1418d5d45fbSJean Delvare 	.owner		= THIS_MODULE,
1428d5d45fbSJean Delvare 	.name		= "adm9240",
1438d5d45fbSJean Delvare 	.id		= I2C_DRIVERID_ADM9240,
1448d5d45fbSJean Delvare 	.flags		= I2C_DF_NOTIFY,
1458d5d45fbSJean Delvare 	.attach_adapter	= adm9240_attach_adapter,
1468d5d45fbSJean Delvare 	.detach_client	= adm9240_detach_client,
1478d5d45fbSJean Delvare };
1488d5d45fbSJean Delvare 
1498d5d45fbSJean Delvare /* per client data */
1508d5d45fbSJean Delvare struct adm9240_data {
1518d5d45fbSJean Delvare 	enum chips type;
1528d5d45fbSJean Delvare 	struct i2c_client client;
1538d5d45fbSJean Delvare 	struct semaphore update_lock;
1548d5d45fbSJean Delvare 	char valid;
1558d5d45fbSJean Delvare 	unsigned long last_updated_measure;
1568d5d45fbSJean Delvare 	unsigned long last_updated_config;
1578d5d45fbSJean Delvare 
1588d5d45fbSJean Delvare 	u8 in[6];		/* ro	in0_input */
1598d5d45fbSJean Delvare 	u8 in_max[6];		/* rw	in0_max */
1608d5d45fbSJean Delvare 	u8 in_min[6];		/* rw	in0_min */
1618d5d45fbSJean Delvare 	u8 fan[2];		/* ro	fan1_input */
1628d5d45fbSJean Delvare 	u8 fan_min[2];		/* rw	fan1_min */
1638d5d45fbSJean Delvare 	u8 fan_div[2];		/* rw	fan1_div, read-only accessor */
1648d5d45fbSJean Delvare 	s16 temp;		/* ro	temp1_input, 9-bit sign-extended */
1658d5d45fbSJean Delvare 	s8 temp_high;		/* rw	temp1_max */
1668d5d45fbSJean Delvare 	s8 temp_hyst;		/* rw	temp1_max_hyst */
1678d5d45fbSJean Delvare 	u16 alarms;		/* ro	alarms */
1688d5d45fbSJean Delvare 	u8 aout;		/* rw	aout_output */
1698d5d45fbSJean Delvare 	u8 vid;			/* ro	vid */
1708d5d45fbSJean Delvare 	u8 vrm;			/* --	vrm set on startup, no accessor */
1718d5d45fbSJean Delvare };
1728d5d45fbSJean Delvare 
1738d5d45fbSJean Delvare /* i2c byte read/write interface */
1748d5d45fbSJean Delvare static int adm9240_read_value(struct i2c_client *client, u8 reg)
1758d5d45fbSJean Delvare {
1768d5d45fbSJean Delvare 	return i2c_smbus_read_byte_data(client, reg);
1778d5d45fbSJean Delvare }
1788d5d45fbSJean Delvare 
1798d5d45fbSJean Delvare static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
1808d5d45fbSJean Delvare {
1818d5d45fbSJean Delvare 	return i2c_smbus_write_byte_data(client, reg, value);
1828d5d45fbSJean Delvare }
1838d5d45fbSJean Delvare 
1848d5d45fbSJean Delvare /*** sysfs accessors ***/
1858d5d45fbSJean Delvare 
1868d5d45fbSJean Delvare /* temperature */
1878d5d45fbSJean Delvare #define show_temp(value, scale)					\
1888d5d45fbSJean Delvare static ssize_t show_##value(struct device *dev,			\
1898d5d45fbSJean Delvare 			    struct device_attribute *attr,	\
1908d5d45fbSJean Delvare 			    char *buf)				\
1918d5d45fbSJean Delvare {								\
1928d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);	\
1938d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->value * scale);	\
1948d5d45fbSJean Delvare }
1958d5d45fbSJean Delvare show_temp(temp_high, 1000);
1968d5d45fbSJean Delvare show_temp(temp_hyst, 1000);
1978d5d45fbSJean Delvare show_temp(temp, 500); /* 0.5'C per bit */
1988d5d45fbSJean Delvare 
1998d5d45fbSJean Delvare #define set_temp(value, reg)					\
2008d5d45fbSJean Delvare static ssize_t set_##value(struct device *dev, 			\
2018d5d45fbSJean Delvare 			   struct device_attribute *attr,	\
2028d5d45fbSJean Delvare 			   const char *buf, size_t count)	\
2038d5d45fbSJean Delvare {								\
2048d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);		\
2058d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);	\
2068d5d45fbSJean Delvare 	long temp = simple_strtoul(buf, NULL, 10);		\
2078d5d45fbSJean Delvare 								\
2088d5d45fbSJean Delvare 	down(&data->update_lock);				\
2098d5d45fbSJean Delvare 	data->value = TEMP_TO_REG(temp);			\
2108d5d45fbSJean Delvare 	adm9240_write_value(client, reg, data->value);		\
2118d5d45fbSJean Delvare 	up(&data->update_lock);					\
2128d5d45fbSJean Delvare 	return count;						\
2138d5d45fbSJean Delvare }
2148d5d45fbSJean Delvare 
2158d5d45fbSJean Delvare set_temp(temp_high, ADM9240_REG_TEMP_HIGH);
2168d5d45fbSJean Delvare set_temp(temp_hyst, ADM9240_REG_TEMP_HYST);
2178d5d45fbSJean Delvare 
2188d5d45fbSJean Delvare static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
2198d5d45fbSJean Delvare 		show_temp_high, set_temp_high);
2208d5d45fbSJean Delvare static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
2218d5d45fbSJean Delvare 		show_temp_hyst, set_temp_hyst);
2228d5d45fbSJean Delvare static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
2238d5d45fbSJean Delvare 
2248d5d45fbSJean Delvare /* voltage */
2258d5d45fbSJean Delvare static ssize_t show_in(struct device *dev, char *buf, int nr)
2268d5d45fbSJean Delvare {
2278d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
2288d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
2298d5d45fbSJean Delvare }
2308d5d45fbSJean Delvare 
2318d5d45fbSJean Delvare static ssize_t show_in_min(struct device *dev, char *buf, int nr)
2328d5d45fbSJean Delvare {
2338d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
2348d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
2358d5d45fbSJean Delvare }
2368d5d45fbSJean Delvare 
2378d5d45fbSJean Delvare static ssize_t show_in_max(struct device *dev, char *buf, int nr)
2388d5d45fbSJean Delvare {
2398d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
2408d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
2418d5d45fbSJean Delvare }
2428d5d45fbSJean Delvare 
2438d5d45fbSJean Delvare static ssize_t set_in_min(struct device *dev, const char *buf,
2448d5d45fbSJean Delvare 		size_t count, int nr)
2458d5d45fbSJean Delvare {
2468d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
2478d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
2488d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
2498d5d45fbSJean Delvare 
2508d5d45fbSJean Delvare 	down(&data->update_lock);
2518d5d45fbSJean Delvare 	data->in_min[nr] = IN_TO_REG(val, nr);
2528d5d45fbSJean Delvare 	adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]);
2538d5d45fbSJean Delvare 	up(&data->update_lock);
2548d5d45fbSJean Delvare 	return count;
2558d5d45fbSJean Delvare }
2568d5d45fbSJean Delvare 
2578d5d45fbSJean Delvare static ssize_t set_in_max(struct device *dev, const char *buf,
2588d5d45fbSJean Delvare 		size_t count, int nr)
2598d5d45fbSJean Delvare {
2608d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
2618d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
2628d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
2638d5d45fbSJean Delvare 
2648d5d45fbSJean Delvare 	down(&data->update_lock);
2658d5d45fbSJean Delvare 	data->in_max[nr] = IN_TO_REG(val, nr);
2668d5d45fbSJean Delvare 	adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]);
2678d5d45fbSJean Delvare 	up(&data->update_lock);
2688d5d45fbSJean Delvare 	return count;
2698d5d45fbSJean Delvare }
2708d5d45fbSJean Delvare 
2718d5d45fbSJean Delvare #define show_in_offset(offset)						\
2728d5d45fbSJean Delvare static ssize_t show_in##offset(struct device *dev,			\
2738d5d45fbSJean Delvare 			       struct device_attribute *attr,		\
2748d5d45fbSJean Delvare 			       char *buf)				\
2758d5d45fbSJean Delvare {									\
2768d5d45fbSJean Delvare 	return show_in(dev, buf, offset);				\
2778d5d45fbSJean Delvare }									\
2788d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);	\
2798d5d45fbSJean Delvare static ssize_t show_in##offset##_min(struct device *dev,		\
2808d5d45fbSJean Delvare 				     struct device_attribute *attr,	\
2818d5d45fbSJean Delvare 				     char *buf)				\
2828d5d45fbSJean Delvare {									\
2838d5d45fbSJean Delvare 	return show_in_min(dev, buf, offset);				\
2848d5d45fbSJean Delvare }									\
2858d5d45fbSJean Delvare static ssize_t show_in##offset##_max(struct device *dev,		\
2868d5d45fbSJean Delvare 				     struct device_attribute *attr,	\
2878d5d45fbSJean Delvare 				     char *buf)				\
2888d5d45fbSJean Delvare {									\
2898d5d45fbSJean Delvare 	return show_in_max(dev, buf, offset);				\
2908d5d45fbSJean Delvare }									\
2918d5d45fbSJean Delvare static ssize_t								\
2928d5d45fbSJean Delvare set_in##offset##_min(struct device *dev,				\
2938d5d45fbSJean Delvare 		     struct device_attribute *attr, const char *buf,	\
2948d5d45fbSJean Delvare 		     size_t count)					\
2958d5d45fbSJean Delvare {									\
2968d5d45fbSJean Delvare 	return set_in_min(dev, buf, count, offset);			\
2978d5d45fbSJean Delvare }									\
2988d5d45fbSJean Delvare static ssize_t								\
2998d5d45fbSJean Delvare set_in##offset##_max(struct device *dev,				\
3008d5d45fbSJean Delvare 		     struct device_attribute *attr, const char *buf,	\
3018d5d45fbSJean Delvare 		     size_t count)					\
3028d5d45fbSJean Delvare {									\
3038d5d45fbSJean Delvare 	return set_in_max(dev, buf, count, offset);			\
3048d5d45fbSJean Delvare }									\
3058d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,			\
3068d5d45fbSJean Delvare 		show_in##offset##_min, set_in##offset##_min);		\
3078d5d45fbSJean Delvare static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,			\
3088d5d45fbSJean Delvare 		show_in##offset##_max, set_in##offset##_max);
3098d5d45fbSJean Delvare 
3108d5d45fbSJean Delvare show_in_offset(0);
3118d5d45fbSJean Delvare show_in_offset(1);
3128d5d45fbSJean Delvare show_in_offset(2);
3138d5d45fbSJean Delvare show_in_offset(3);
3148d5d45fbSJean Delvare show_in_offset(4);
3158d5d45fbSJean Delvare show_in_offset(5);
3168d5d45fbSJean Delvare 
3178d5d45fbSJean Delvare /* fans */
3188d5d45fbSJean Delvare static ssize_t show_fan(struct device *dev, char *buf, int nr)
3198d5d45fbSJean Delvare {
3208d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
3218d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
3228d5d45fbSJean Delvare 				1 << data->fan_div[nr]));
3238d5d45fbSJean Delvare }
3248d5d45fbSJean Delvare 
3258d5d45fbSJean Delvare static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
3268d5d45fbSJean Delvare {
3278d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
3288d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
3298d5d45fbSJean Delvare 				1 << data->fan_div[nr]));
3308d5d45fbSJean Delvare }
3318d5d45fbSJean Delvare 
3328d5d45fbSJean Delvare static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
3338d5d45fbSJean Delvare {
3348d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
3358d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", 1 << data->fan_div[nr]);
3368d5d45fbSJean Delvare }
3378d5d45fbSJean Delvare 
3388d5d45fbSJean Delvare /* write new fan div, callers must hold data->update_lock */
3398d5d45fbSJean Delvare static void adm9240_write_fan_div(struct i2c_client *client, int nr,
3408d5d45fbSJean Delvare 		u8 fan_div)
3418d5d45fbSJean Delvare {
3428d5d45fbSJean Delvare 	u8 reg, old, shift = (nr + 2) * 2;
3438d5d45fbSJean Delvare 
3448d5d45fbSJean Delvare 	reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
3458d5d45fbSJean Delvare 	old = (reg >> shift) & 3;
3468d5d45fbSJean Delvare 	reg &= ~(3 << shift);
3478d5d45fbSJean Delvare 	reg |= (fan_div << shift);
3488d5d45fbSJean Delvare 	adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg);
3498d5d45fbSJean Delvare 	dev_dbg(&client->dev, "fan%d clock divider changed from %u "
3508d5d45fbSJean Delvare 			"to %u\n", nr + 1, 1 << old, 1 << fan_div);
3518d5d45fbSJean Delvare }
3528d5d45fbSJean Delvare 
3538d5d45fbSJean Delvare /*
3548d5d45fbSJean Delvare  * set fan speed low limit:
3558d5d45fbSJean Delvare  *
3568d5d45fbSJean Delvare  * - value is zero: disable fan speed low limit alarm
3578d5d45fbSJean Delvare  *
3588d5d45fbSJean Delvare  * - value is below fan speed measurement range: enable fan speed low
3598d5d45fbSJean Delvare  *   limit alarm to be asserted while fan speed too slow to measure
3608d5d45fbSJean Delvare  *
3618d5d45fbSJean Delvare  * - otherwise: select fan clock divider to suit fan speed low limit,
3628d5d45fbSJean Delvare  *   measurement code may adjust registers to ensure fan speed reading
3638d5d45fbSJean Delvare  */
3648d5d45fbSJean Delvare static ssize_t set_fan_min(struct device *dev, const char *buf,
3658d5d45fbSJean Delvare 		size_t count, int nr)
3668d5d45fbSJean Delvare {
3678d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
3688d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
3698d5d45fbSJean Delvare 	unsigned long val = simple_strtoul(buf, NULL, 10);
3708d5d45fbSJean Delvare 	u8 new_div;
3718d5d45fbSJean Delvare 
3728d5d45fbSJean Delvare 	down(&data->update_lock);
3738d5d45fbSJean Delvare 
3748d5d45fbSJean Delvare 	if (!val) {
3758d5d45fbSJean Delvare 		data->fan_min[nr] = 255;
3768d5d45fbSJean Delvare 		new_div = data->fan_div[nr];
3778d5d45fbSJean Delvare 
3788d5d45fbSJean Delvare 		dev_dbg(&client->dev, "fan%u low limit set disabled\n",
3798d5d45fbSJean Delvare 				nr + 1);
3808d5d45fbSJean Delvare 
3818d5d45fbSJean Delvare 	} else if (val < 1350000 / (8 * 254)) {
3828d5d45fbSJean Delvare 		new_div = 3;
3838d5d45fbSJean Delvare 		data->fan_min[nr] = 254;
3848d5d45fbSJean Delvare 
3858d5d45fbSJean Delvare 		dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
3868d5d45fbSJean Delvare 				nr + 1, FAN_FROM_REG(254, 1 << new_div));
3878d5d45fbSJean Delvare 
3888d5d45fbSJean Delvare 	} else {
3898d5d45fbSJean Delvare 		unsigned int new_min = 1350000 / val;
3908d5d45fbSJean Delvare 
3918d5d45fbSJean Delvare 		new_div = 0;
3928d5d45fbSJean Delvare 		while (new_min > 192 && new_div < 3) {
3938d5d45fbSJean Delvare 			new_div++;
3948d5d45fbSJean Delvare 			new_min /= 2;
3958d5d45fbSJean Delvare 		}
3968d5d45fbSJean Delvare 		if (!new_min) /* keep > 0 */
3978d5d45fbSJean Delvare 			new_min++;
3988d5d45fbSJean Delvare 
3998d5d45fbSJean Delvare 		data->fan_min[nr] = new_min;
4008d5d45fbSJean Delvare 
4018d5d45fbSJean Delvare 		dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
4028d5d45fbSJean Delvare 				nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
4038d5d45fbSJean Delvare 	}
4048d5d45fbSJean Delvare 
4058d5d45fbSJean Delvare 	if (new_div != data->fan_div[nr]) {
4068d5d45fbSJean Delvare 		data->fan_div[nr] = new_div;
4078d5d45fbSJean Delvare 		adm9240_write_fan_div(client, nr, new_div);
4088d5d45fbSJean Delvare 	}
4098d5d45fbSJean Delvare 	adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr),
4108d5d45fbSJean Delvare 			data->fan_min[nr]);
4118d5d45fbSJean Delvare 
4128d5d45fbSJean Delvare 	up(&data->update_lock);
4138d5d45fbSJean Delvare 	return count;
4148d5d45fbSJean Delvare }
4158d5d45fbSJean Delvare 
4168d5d45fbSJean Delvare #define show_fan_offset(offset)						\
4178d5d45fbSJean Delvare static ssize_t show_fan_##offset (struct device *dev,			\
4188d5d45fbSJean Delvare 				  struct device_attribute *attr,	\
4198d5d45fbSJean Delvare 				  char *buf)				\
4208d5d45fbSJean Delvare {									\
4218d5d45fbSJean Delvare return show_fan(dev, buf, offset - 1);					\
4228d5d45fbSJean Delvare }									\
4238d5d45fbSJean Delvare static ssize_t show_fan_##offset##_div (struct device *dev,		\
4248d5d45fbSJean Delvare 					struct device_attribute *attr,	\
4258d5d45fbSJean Delvare 					char *buf)			\
4268d5d45fbSJean Delvare {									\
4278d5d45fbSJean Delvare return show_fan_div(dev, buf, offset - 1);				\
4288d5d45fbSJean Delvare }									\
4298d5d45fbSJean Delvare static ssize_t show_fan_##offset##_min (struct device *dev,		\
4308d5d45fbSJean Delvare 					struct device_attribute *attr,	\
4318d5d45fbSJean Delvare 					char *buf)			\
4328d5d45fbSJean Delvare {									\
4338d5d45fbSJean Delvare return show_fan_min(dev, buf, offset - 1);				\
4348d5d45fbSJean Delvare }									\
4358d5d45fbSJean Delvare static ssize_t set_fan_##offset##_min (struct device *dev, 		\
4368d5d45fbSJean Delvare 				       struct device_attribute *attr,	\
4378d5d45fbSJean Delvare 				       const char *buf, size_t count)	\
4388d5d45fbSJean Delvare {									\
4398d5d45fbSJean Delvare return set_fan_min(dev, buf, count, offset - 1);			\
4408d5d45fbSJean Delvare }									\
4418d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_input, S_IRUGO, 			\
4428d5d45fbSJean Delvare 		show_fan_##offset, NULL);				\
4438d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_div, S_IRUGO, 				\
4448d5d45fbSJean Delvare 		show_fan_##offset##_div, NULL);				\
4458d5d45fbSJean Delvare static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
4468d5d45fbSJean Delvare 		show_fan_##offset##_min, set_fan_##offset##_min);
4478d5d45fbSJean Delvare 
4488d5d45fbSJean Delvare show_fan_offset(1);
4498d5d45fbSJean Delvare show_fan_offset(2);
4508d5d45fbSJean Delvare 
4518d5d45fbSJean Delvare /* alarms */
4528d5d45fbSJean Delvare static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
4538d5d45fbSJean Delvare {
4548d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
4558d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
4568d5d45fbSJean Delvare }
4578d5d45fbSJean Delvare static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
4588d5d45fbSJean Delvare 
4598d5d45fbSJean Delvare /* vid */
4608d5d45fbSJean Delvare static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
4618d5d45fbSJean Delvare {
4628d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
4638d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
4648d5d45fbSJean Delvare }
4658d5d45fbSJean Delvare static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
4668d5d45fbSJean Delvare 
4678d5d45fbSJean Delvare /* analog output */
4688d5d45fbSJean Delvare static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf)
4698d5d45fbSJean Delvare {
4708d5d45fbSJean Delvare 	struct adm9240_data *data = adm9240_update_device(dev);
4718d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
4728d5d45fbSJean Delvare }
4738d5d45fbSJean Delvare 
4748d5d45fbSJean Delvare static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
4758d5d45fbSJean Delvare {
4768d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
4778d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
4788d5d45fbSJean Delvare 	unsigned long val = simple_strtol(buf, NULL, 10);
4798d5d45fbSJean Delvare 
4808d5d45fbSJean Delvare 	down(&data->update_lock);
4818d5d45fbSJean Delvare 	data->aout = AOUT_TO_REG(val);
4828d5d45fbSJean Delvare 	adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout);
4838d5d45fbSJean Delvare 	up(&data->update_lock);
4848d5d45fbSJean Delvare 	return count;
4858d5d45fbSJean Delvare }
4868d5d45fbSJean Delvare static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
4878d5d45fbSJean Delvare 
4888d5d45fbSJean Delvare /* chassis_clear */
4898d5d45fbSJean Delvare static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
4908d5d45fbSJean Delvare {
4918d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
4928d5d45fbSJean Delvare 	unsigned long val = simple_strtol(buf, NULL, 10);
4938d5d45fbSJean Delvare 
4948d5d45fbSJean Delvare 	if (val == 1) {
4958d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
4968d5d45fbSJean Delvare 		dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
4978d5d45fbSJean Delvare 	}
4988d5d45fbSJean Delvare 	return count;
4998d5d45fbSJean Delvare }
5008d5d45fbSJean Delvare static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
5018d5d45fbSJean Delvare 
5028d5d45fbSJean Delvare 
5038d5d45fbSJean Delvare /*** sensor chip detect and driver install ***/
5048d5d45fbSJean Delvare 
5058d5d45fbSJean Delvare static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
5068d5d45fbSJean Delvare {
5078d5d45fbSJean Delvare 	struct i2c_client *new_client;
5088d5d45fbSJean Delvare 	struct adm9240_data *data;
5098d5d45fbSJean Delvare 	int err = 0;
5108d5d45fbSJean Delvare 	const char *name = "";
5118d5d45fbSJean Delvare 	u8 man_id, die_rev;
5128d5d45fbSJean Delvare 
5138d5d45fbSJean Delvare 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
5148d5d45fbSJean Delvare 		goto exit;
5158d5d45fbSJean Delvare 
5168d5d45fbSJean Delvare 	if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) {
5178d5d45fbSJean Delvare 		err = -ENOMEM;
5188d5d45fbSJean Delvare 		goto exit;
5198d5d45fbSJean Delvare 	}
5208d5d45fbSJean Delvare 	memset(data, 0, sizeof(struct adm9240_data));
5218d5d45fbSJean Delvare 
5228d5d45fbSJean Delvare 	new_client = &data->client;
5238d5d45fbSJean Delvare 	i2c_set_clientdata(new_client, data);
5248d5d45fbSJean Delvare 	new_client->addr = address;
5258d5d45fbSJean Delvare 	new_client->adapter = adapter;
5268d5d45fbSJean Delvare 	new_client->driver = &adm9240_driver;
5278d5d45fbSJean Delvare 	new_client->flags = 0;
5288d5d45fbSJean Delvare 
5298d5d45fbSJean Delvare 	if (kind == 0) {
5308d5d45fbSJean Delvare 		kind = adm9240;
5318d5d45fbSJean Delvare 	}
5328d5d45fbSJean Delvare 
5338d5d45fbSJean Delvare 	if (kind < 0) {
5348d5d45fbSJean Delvare 
5358d5d45fbSJean Delvare 		/* verify chip: reg address should match i2c address */
5368d5d45fbSJean Delvare 		if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
5378d5d45fbSJean Delvare 				!= address) {
5388d5d45fbSJean Delvare 			dev_err(&adapter->dev, "detect fail: address match, "
5398d5d45fbSJean Delvare 					"0x%02x\n", address);
5408d5d45fbSJean Delvare 			goto exit_free;
5418d5d45fbSJean Delvare 		}
5428d5d45fbSJean Delvare 
5438d5d45fbSJean Delvare 		/* check known chip manufacturer */
5448d5d45fbSJean Delvare 		man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID);
5458d5d45fbSJean Delvare 
5468d5d45fbSJean Delvare 		if (man_id == 0x23) {
5478d5d45fbSJean Delvare 			kind = adm9240;
5488d5d45fbSJean Delvare 		} else if (man_id == 0xda) {
5498d5d45fbSJean Delvare 			kind = ds1780;
5508d5d45fbSJean Delvare 		} else if (man_id == 0x01) {
5518d5d45fbSJean Delvare 			kind = lm81;
5528d5d45fbSJean Delvare 		} else {
5538d5d45fbSJean Delvare 			dev_err(&adapter->dev, "detect fail: unknown manuf, "
5548d5d45fbSJean Delvare 					"0x%02x\n", man_id);
5558d5d45fbSJean Delvare 			goto exit_free;
5568d5d45fbSJean Delvare 		}
5578d5d45fbSJean Delvare 
5588d5d45fbSJean Delvare 		/* successful detect, print chip info */
5598d5d45fbSJean Delvare 		die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV);
5608d5d45fbSJean Delvare 		dev_info(&adapter->dev, "found %s revision %u\n",
5618d5d45fbSJean Delvare 				man_id == 0x23 ? "ADM9240" :
5628d5d45fbSJean Delvare 				man_id == 0xda ? "DS1780" : "LM81", die_rev);
5638d5d45fbSJean Delvare 	}
5648d5d45fbSJean Delvare 
5658d5d45fbSJean Delvare 	/* either forced or detected chip kind */
5668d5d45fbSJean Delvare 	if (kind == adm9240) {
5678d5d45fbSJean Delvare 		name = "adm9240";
5688d5d45fbSJean Delvare 	} else if (kind == ds1780) {
5698d5d45fbSJean Delvare 		name = "ds1780";
5708d5d45fbSJean Delvare 	} else if (kind == lm81) {
5718d5d45fbSJean Delvare 		name = "lm81";
5728d5d45fbSJean Delvare 	}
5738d5d45fbSJean Delvare 
5748d5d45fbSJean Delvare 	/* fill in the remaining client fields and attach */
5758d5d45fbSJean Delvare 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
5768d5d45fbSJean Delvare 	data->type = kind;
5778d5d45fbSJean Delvare 	init_MUTEX(&data->update_lock);
5788d5d45fbSJean Delvare 
5798d5d45fbSJean Delvare 	if ((err = i2c_attach_client(new_client)))
5808d5d45fbSJean Delvare 		goto exit_free;
5818d5d45fbSJean Delvare 
5828d5d45fbSJean Delvare 	adm9240_init_client(new_client);
5838d5d45fbSJean Delvare 
5848d5d45fbSJean Delvare 	/* populate sysfs filesystem */
5858d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_input);
5868d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_min);
5878d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in0_max);
5888d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_input);
5898d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_min);
5908d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in1_max);
5918d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_input);
5928d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_min);
5938d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in2_max);
5948d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_input);
5958d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_min);
5968d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in3_max);
5978d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_input);
5988d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_min);
5998d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in4_max);
6008d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in5_input);
6018d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in5_min);
6028d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_in5_max);
6038d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_max);
6048d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
6058d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_temp1_input);
6068d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_input);
6078d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_div);
6088d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan1_min);
6098d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_input);
6108d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_div);
6118d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_fan2_min);
6128d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_alarms);
6138d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_aout_output);
6148d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_chassis_clear);
6158d5d45fbSJean Delvare 	device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
6168d5d45fbSJean Delvare 
6178d5d45fbSJean Delvare 	return 0;
6188d5d45fbSJean Delvare exit_free:
6191f57ff89SAlexey Dobriyan 	kfree(data);
6208d5d45fbSJean Delvare exit:
6218d5d45fbSJean Delvare 	return err;
6228d5d45fbSJean Delvare }
6238d5d45fbSJean Delvare 
6248d5d45fbSJean Delvare static int adm9240_attach_adapter(struct i2c_adapter *adapter)
6258d5d45fbSJean Delvare {
6268d5d45fbSJean Delvare 	if (!(adapter->class & I2C_CLASS_HWMON))
6278d5d45fbSJean Delvare 		return 0;
6288d5d45fbSJean Delvare 	return i2c_detect(adapter, &addr_data, adm9240_detect);
6298d5d45fbSJean Delvare }
6308d5d45fbSJean Delvare 
6318d5d45fbSJean Delvare static int adm9240_detach_client(struct i2c_client *client)
6328d5d45fbSJean Delvare {
6338d5d45fbSJean Delvare 	int err;
6348d5d45fbSJean Delvare 
6358d5d45fbSJean Delvare 	if ((err = i2c_detach_client(client))) {
6368d5d45fbSJean Delvare 		dev_err(&client->dev, "Client deregistration failed, "
6378d5d45fbSJean Delvare 				"client not detached.\n");
6388d5d45fbSJean Delvare 		return err;
6398d5d45fbSJean Delvare 	}
6408d5d45fbSJean Delvare 
6418d5d45fbSJean Delvare 	kfree(i2c_get_clientdata(client));
6428d5d45fbSJean Delvare 	return 0;
6438d5d45fbSJean Delvare }
6448d5d45fbSJean Delvare 
6458d5d45fbSJean Delvare static void adm9240_init_client(struct i2c_client *client)
6468d5d45fbSJean Delvare {
6478d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
6488d5d45fbSJean Delvare 	u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
6498d5d45fbSJean Delvare 	u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
6508d5d45fbSJean Delvare 
6518d5d45fbSJean Delvare 	data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
6528d5d45fbSJean Delvare 
6538d5d45fbSJean Delvare 	dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
6548d5d45fbSJean Delvare 			data->vrm % 10);
6558d5d45fbSJean Delvare 
6568d5d45fbSJean Delvare 	if (conf & 1) { /* measurement cycle running: report state */
6578d5d45fbSJean Delvare 
6588d5d45fbSJean Delvare 		dev_info(&client->dev, "status: config 0x%02x mode %u\n",
6598d5d45fbSJean Delvare 				conf, mode);
6608d5d45fbSJean Delvare 
6618d5d45fbSJean Delvare 	} else { /* cold start: open limits before starting chip */
6628d5d45fbSJean Delvare 		int i;
6638d5d45fbSJean Delvare 
6648d5d45fbSJean Delvare 		for (i = 0; i < 6; i++)
6658d5d45fbSJean Delvare 		{
6668d5d45fbSJean Delvare 			adm9240_write_value(client,
6678d5d45fbSJean Delvare 					ADM9240_REG_IN_MIN(i), 0);
6688d5d45fbSJean Delvare 			adm9240_write_value(client,
6698d5d45fbSJean Delvare 					ADM9240_REG_IN_MAX(i), 255);
6708d5d45fbSJean Delvare 		}
6718d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255);
6728d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255);
6738d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127);
6748d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127);
6758d5d45fbSJean Delvare 
6768d5d45fbSJean Delvare 		/* start measurement cycle */
6778d5d45fbSJean Delvare 		adm9240_write_value(client, ADM9240_REG_CONFIG, 1);
6788d5d45fbSJean Delvare 
6798d5d45fbSJean Delvare 		dev_info(&client->dev, "cold start: config was 0x%02x "
6808d5d45fbSJean Delvare 				"mode %u\n", conf, mode);
6818d5d45fbSJean Delvare 	}
6828d5d45fbSJean Delvare }
6838d5d45fbSJean Delvare 
6848d5d45fbSJean Delvare static struct adm9240_data *adm9240_update_device(struct device *dev)
6858d5d45fbSJean Delvare {
6868d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
6878d5d45fbSJean Delvare 	struct adm9240_data *data = i2c_get_clientdata(client);
6888d5d45fbSJean Delvare 	int i;
6898d5d45fbSJean Delvare 
6908d5d45fbSJean Delvare 	down(&data->update_lock);
6918d5d45fbSJean Delvare 
6928d5d45fbSJean Delvare 	/* minimum measurement cycle: 1.75 seconds */
6938d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
6948d5d45fbSJean Delvare 			|| !data->valid) {
6958d5d45fbSJean Delvare 
6968d5d45fbSJean Delvare 		for (i = 0; i < 6; i++) /* read voltages */
6978d5d45fbSJean Delvare 		{
6988d5d45fbSJean Delvare 			data->in[i] = adm9240_read_value(client,
6998d5d45fbSJean Delvare 					ADM9240_REG_IN(i));
7008d5d45fbSJean Delvare 		}
7018d5d45fbSJean Delvare 		data->alarms = adm9240_read_value(client,
7028d5d45fbSJean Delvare 					ADM9240_REG_INT(0)) |
7038d5d45fbSJean Delvare 					adm9240_read_value(client,
7048d5d45fbSJean Delvare 					ADM9240_REG_INT(1)) << 8;
7058d5d45fbSJean Delvare 
7068d5d45fbSJean Delvare 		/* read temperature: assume temperature changes less than
7078d5d45fbSJean Delvare 		 * 0.5'C per two measurement cycles thus ignore possible
7088d5d45fbSJean Delvare 		 * but unlikely aliasing error on lsb reading. --Grant */
7098d5d45fbSJean Delvare 		data->temp = ((adm9240_read_value(client,
7108d5d45fbSJean Delvare 					ADM9240_REG_TEMP) << 8) |
7118d5d45fbSJean Delvare 					adm9240_read_value(client,
7128d5d45fbSJean Delvare 					ADM9240_REG_TEMP_CONF)) / 128;
7138d5d45fbSJean Delvare 
7148d5d45fbSJean Delvare 		for (i = 0; i < 2; i++) /* read fans */
7158d5d45fbSJean Delvare 		{
7168d5d45fbSJean Delvare 			data->fan[i] = adm9240_read_value(client,
7178d5d45fbSJean Delvare 					ADM9240_REG_FAN(i));
7188d5d45fbSJean Delvare 
7198d5d45fbSJean Delvare 			/* adjust fan clock divider on overflow */
7208d5d45fbSJean Delvare 			if (data->valid && data->fan[i] == 255 &&
7218d5d45fbSJean Delvare 					data->fan_div[i] < 3) {
7228d5d45fbSJean Delvare 
7238d5d45fbSJean Delvare 				adm9240_write_fan_div(client, i,
7248d5d45fbSJean Delvare 						++data->fan_div[i]);
7258d5d45fbSJean Delvare 
7268d5d45fbSJean Delvare 				/* adjust fan_min if active, but not to 0 */
7278d5d45fbSJean Delvare 				if (data->fan_min[i] < 255 &&
7288d5d45fbSJean Delvare 						data->fan_min[i] >= 2)
7298d5d45fbSJean Delvare 					data->fan_min[i] /= 2;
7308d5d45fbSJean Delvare 			}
7318d5d45fbSJean Delvare 		}
7328d5d45fbSJean Delvare 		data->last_updated_measure = jiffies;
7338d5d45fbSJean Delvare 	}
7348d5d45fbSJean Delvare 
7358d5d45fbSJean Delvare 	/* minimum config reading cycle: 300 seconds */
7368d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated_config + (HZ * 300))
7378d5d45fbSJean Delvare 			|| !data->valid) {
7388d5d45fbSJean Delvare 
7398d5d45fbSJean Delvare 		for (i = 0; i < 6; i++)
7408d5d45fbSJean Delvare 		{
7418d5d45fbSJean Delvare 			data->in_min[i] = adm9240_read_value(client,
7428d5d45fbSJean Delvare 					ADM9240_REG_IN_MIN(i));
7438d5d45fbSJean Delvare 			data->in_max[i] = adm9240_read_value(client,
7448d5d45fbSJean Delvare 					ADM9240_REG_IN_MAX(i));
7458d5d45fbSJean Delvare 		}
7468d5d45fbSJean Delvare 		for (i = 0; i < 2; i++)
7478d5d45fbSJean Delvare 		{
7488d5d45fbSJean Delvare 			data->fan_min[i] = adm9240_read_value(client,
7498d5d45fbSJean Delvare 					ADM9240_REG_FAN_MIN(i));
7508d5d45fbSJean Delvare 		}
7518d5d45fbSJean Delvare 		data->temp_high = adm9240_read_value(client,
7528d5d45fbSJean Delvare 				ADM9240_REG_TEMP_HIGH);
7538d5d45fbSJean Delvare 		data->temp_hyst = adm9240_read_value(client,
7548d5d45fbSJean Delvare 				ADM9240_REG_TEMP_HYST);
7558d5d45fbSJean Delvare 
7568d5d45fbSJean Delvare 		/* read fan divs and 5-bit VID */
7578d5d45fbSJean Delvare 		i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
7588d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 3;
7598d5d45fbSJean Delvare 		data->fan_div[1] = (i >> 6) & 3;
7608d5d45fbSJean Delvare 		data->vid = i & 0x0f;
7618d5d45fbSJean Delvare 		data->vid |= (adm9240_read_value(client,
7628d5d45fbSJean Delvare 					ADM9240_REG_VID4) & 1) << 4;
7638d5d45fbSJean Delvare 		/* read analog out */
7648d5d45fbSJean Delvare 		data->aout = adm9240_read_value(client,
7658d5d45fbSJean Delvare 				ADM9240_REG_ANALOG_OUT);
7668d5d45fbSJean Delvare 
7678d5d45fbSJean Delvare 		data->last_updated_config = jiffies;
7688d5d45fbSJean Delvare 		data->valid = 1;
7698d5d45fbSJean Delvare 	}
7708d5d45fbSJean Delvare 	up(&data->update_lock);
7718d5d45fbSJean Delvare 	return data;
7728d5d45fbSJean Delvare }
7738d5d45fbSJean Delvare 
7748d5d45fbSJean Delvare static int __init sensors_adm9240_init(void)
7758d5d45fbSJean Delvare {
7768d5d45fbSJean Delvare 	return i2c_add_driver(&adm9240_driver);
7778d5d45fbSJean Delvare }
7788d5d45fbSJean Delvare 
7798d5d45fbSJean Delvare static void __exit sensors_adm9240_exit(void)
7808d5d45fbSJean Delvare {
7818d5d45fbSJean Delvare 	i2c_del_driver(&adm9240_driver);
7828d5d45fbSJean Delvare }
7838d5d45fbSJean Delvare 
7848d5d45fbSJean Delvare MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
7858d5d45fbSJean Delvare 		"Grant Coady <gcoady@gmail.com> and others");
7868d5d45fbSJean Delvare MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
7878d5d45fbSJean Delvare MODULE_LICENSE("GPL");
7888d5d45fbSJean Delvare 
7898d5d45fbSJean Delvare module_init(sensors_adm9240_init);
7908d5d45fbSJean Delvare module_exit(sensors_adm9240_exit);
7918d5d45fbSJean Delvare 
792