xref: /openbmc/linux/drivers/hwmon/w83781d.c (revision c531eb3f229bcc3b4ee7fb471e580caff86dafad)
18d5d45fbSJean Delvare /*
28d5d45fbSJean Delvare     w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
38d5d45fbSJean Delvare 		monitoring
48d5d45fbSJean Delvare     Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>,
58d5d45fbSJean Delvare 			       Philip Edelbrock <phil@netroedge.com>,
68d5d45fbSJean Delvare 			       and Mark Studebaker <mdsxyz123@yahoo.com>
7360782ddSJean Delvare     Copyright (c) 2007 - 2008  Jean Delvare <khali@linux-fr.org>
88d5d45fbSJean Delvare 
98d5d45fbSJean Delvare     This program is free software; you can redistribute it and/or modify
108d5d45fbSJean Delvare     it under the terms of the GNU General Public License as published by
118d5d45fbSJean Delvare     the Free Software Foundation; either version 2 of the License, or
128d5d45fbSJean Delvare     (at your option) any later version.
138d5d45fbSJean Delvare 
148d5d45fbSJean Delvare     This program is distributed in the hope that it will be useful,
158d5d45fbSJean Delvare     but WITHOUT ANY WARRANTY; without even the implied warranty of
168d5d45fbSJean Delvare     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
178d5d45fbSJean Delvare     GNU General Public License for more details.
188d5d45fbSJean Delvare 
198d5d45fbSJean Delvare     You should have received a copy of the GNU General Public License
208d5d45fbSJean Delvare     along with this program; if not, write to the Free Software
218d5d45fbSJean Delvare     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
228d5d45fbSJean Delvare */
238d5d45fbSJean Delvare 
248d5d45fbSJean Delvare /*
258d5d45fbSJean Delvare     Supports following chips:
268d5d45fbSJean Delvare 
278d5d45fbSJean Delvare     Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
288d5d45fbSJean Delvare     as99127f	7	3	0	3	0x31	0x12c3	yes	no
298d5d45fbSJean Delvare     as99127f rev.2 (type_name = as99127f)	0x31	0x5ca3	yes	no
308d5d45fbSJean Delvare     w83781d	7	3	0	3	0x10-1	0x5ca3	yes	yes
318d5d45fbSJean Delvare     w83782d	9	3	2-4	3	0x30	0x5ca3	yes	yes
328d5d45fbSJean Delvare     w83783s	5-6	3	2	1-2	0x40	0x5ca3	yes	no
338d5d45fbSJean Delvare 
348d5d45fbSJean Delvare */
358d5d45fbSJean Delvare 
361ca28218SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
371ca28218SJoe Perches 
388d5d45fbSJean Delvare #include <linux/module.h>
398d5d45fbSJean Delvare #include <linux/init.h>
408d5d45fbSJean Delvare #include <linux/slab.h>
418d5d45fbSJean Delvare #include <linux/jiffies.h>
428d5d45fbSJean Delvare #include <linux/i2c.h>
43943b0830SMark M. Hoffman #include <linux/hwmon.h>
44303760b4SJean Delvare #include <linux/hwmon-vid.h>
4534875337SJean Delvare #include <linux/hwmon-sysfs.h>
46311ce2efSJim Cromie #include <linux/sysfs.h>
47943b0830SMark M. Hoffman #include <linux/err.h>
489a61bf63SIngo Molnar #include <linux/mutex.h>
498d5d45fbSJean Delvare 
50443850ceSWolfgang Grandegger #ifdef CONFIG_ISA
51443850ceSWolfgang Grandegger #include <linux/platform_device.h>
52443850ceSWolfgang Grandegger #include <linux/ioport.h>
536055fae8SH Hartley Sweeten #include <linux/io.h>
54443850ceSWolfgang Grandegger #endif
55443850ceSWolfgang Grandegger 
56443850ceSWolfgang Grandegger #include "lm75.h"
577666c13cSJean Delvare 
588d5d45fbSJean Delvare /* Addresses to scan */
5925e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
606722feadSJean Delvare 						0x2e, 0x2f, I2C_CLIENT_END };
613aed198cSJean Delvare 
62e5e9f44cSJean Delvare enum chips { w83781d, w83782d, w83783s, as99127f };
63e5e9f44cSJean Delvare 
64e5e9f44cSJean Delvare /* Insmod parameters */
653aed198cSJean Delvare static unsigned short force_subclients[4];
663aed198cSJean Delvare module_param_array(force_subclients, short, NULL, 0);
673aed198cSJean Delvare MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
688d5d45fbSJean Delvare 		    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
698d5d45fbSJean Delvare 
7090ab5ee9SRusty Russell static bool reset;
71fabddcd4SJean Delvare module_param(reset, bool, 0);
72fabddcd4SJean Delvare MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
73fabddcd4SJean Delvare 
7490ab5ee9SRusty Russell static bool init = 1;
758d5d45fbSJean Delvare module_param(init, bool, 0);
768d5d45fbSJean Delvare MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
778d5d45fbSJean Delvare 
788d5d45fbSJean Delvare /* Constants specified below */
798d5d45fbSJean Delvare 
808d5d45fbSJean Delvare /* Length of ISA address segment */
818d5d45fbSJean Delvare #define W83781D_EXTENT			8
828d5d45fbSJean Delvare 
838d5d45fbSJean Delvare /* Where are the ISA address/data registers relative to the base address */
848d5d45fbSJean Delvare #define W83781D_ADDR_REG_OFFSET		5
858d5d45fbSJean Delvare #define W83781D_DATA_REG_OFFSET		6
868d5d45fbSJean Delvare 
8734875337SJean Delvare /* The device registers */
8834875337SJean Delvare /* in nr from 0 to 8 */
898d5d45fbSJean Delvare #define W83781D_REG_IN_MAX(nr)		((nr < 7) ? (0x2b + (nr) * 2) : \
908d5d45fbSJean Delvare 						    (0x554 + (((nr) - 7) * 2)))
918d5d45fbSJean Delvare #define W83781D_REG_IN_MIN(nr)		((nr < 7) ? (0x2c + (nr) * 2) : \
928d5d45fbSJean Delvare 						    (0x555 + (((nr) - 7) * 2)))
938d5d45fbSJean Delvare #define W83781D_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
948d5d45fbSJean Delvare 						    (0x550 + (nr) - 7))
958d5d45fbSJean Delvare 
9634875337SJean Delvare /* fan nr from 0 to 2 */
9734875337SJean Delvare #define W83781D_REG_FAN_MIN(nr)		(0x3b + (nr))
9834875337SJean Delvare #define W83781D_REG_FAN(nr)		(0x28 + (nr))
998d5d45fbSJean Delvare 
1008d5d45fbSJean Delvare #define W83781D_REG_BANK		0x4E
1018d5d45fbSJean Delvare #define W83781D_REG_TEMP2_CONFIG	0x152
1028d5d45fbSJean Delvare #define W83781D_REG_TEMP3_CONFIG	0x252
10334875337SJean Delvare /* temp nr from 1 to 3 */
1048d5d45fbSJean Delvare #define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
1058d5d45fbSJean Delvare 					((nr == 2) ? (0x0150) : \
1068d5d45fbSJean Delvare 						     (0x27)))
1078d5d45fbSJean Delvare #define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
1088d5d45fbSJean Delvare 					((nr == 2) ? (0x153) : \
1098d5d45fbSJean Delvare 						     (0x3A)))
1108d5d45fbSJean Delvare #define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
1118d5d45fbSJean Delvare 					((nr == 2) ? (0x155) : \
1128d5d45fbSJean Delvare 						     (0x39)))
1138d5d45fbSJean Delvare 
1148d5d45fbSJean Delvare #define W83781D_REG_CONFIG		0x40
115c7f5d7edSJean Delvare 
116c7f5d7edSJean Delvare /* Interrupt status (W83781D, AS99127F) */
1178d5d45fbSJean Delvare #define W83781D_REG_ALARM1		0x41
1188d5d45fbSJean Delvare #define W83781D_REG_ALARM2		0x42
1198d5d45fbSJean Delvare 
12005663368SJean Delvare /* Real-time status (W83782D, W83783S) */
121c7f5d7edSJean Delvare #define W83782D_REG_ALARM1		0x459
122c7f5d7edSJean Delvare #define W83782D_REG_ALARM2		0x45A
123c7f5d7edSJean Delvare #define W83782D_REG_ALARM3		0x45B
124c7f5d7edSJean Delvare 
1258d5d45fbSJean Delvare #define W83781D_REG_BEEP_CONFIG		0x4D
1268d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS1		0x56
1278d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS2		0x57
1288d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS3		0x453	/* not on W83781D */
1298d5d45fbSJean Delvare 
1308d5d45fbSJean Delvare #define W83781D_REG_VID_FANDIV		0x47
1318d5d45fbSJean Delvare 
1328d5d45fbSJean Delvare #define W83781D_REG_CHIPID		0x49
1338d5d45fbSJean Delvare #define W83781D_REG_WCHIPID		0x58
1348d5d45fbSJean Delvare #define W83781D_REG_CHIPMAN		0x4F
1358d5d45fbSJean Delvare #define W83781D_REG_PIN			0x4B
1368d5d45fbSJean Delvare 
1378d5d45fbSJean Delvare /* 782D/783S only */
1388d5d45fbSJean Delvare #define W83781D_REG_VBAT		0x5D
1398d5d45fbSJean Delvare 
1408d5d45fbSJean Delvare /* PWM 782D (1-4) and 783S (1-2) only */
14134875337SJean Delvare static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
1428d5d45fbSJean Delvare #define W83781D_REG_PWMCLK12		0x5C
1438d5d45fbSJean Delvare #define W83781D_REG_PWMCLK34		0x45C
1448d5d45fbSJean Delvare 
1458d5d45fbSJean Delvare #define W83781D_REG_I2C_ADDR		0x48
1468d5d45fbSJean Delvare #define W83781D_REG_I2C_SUBADDR		0x4A
1478d5d45fbSJean Delvare 
1488d5d45fbSJean Delvare /* The following are undocumented in the data sheets however we
1498d5d45fbSJean Delvare    received the information in an email from Winbond tech support */
1508d5d45fbSJean Delvare /* Sensor selection - not on 781d */
1518d5d45fbSJean Delvare #define W83781D_REG_SCFG1		0x5D
1528d5d45fbSJean Delvare static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
1538d5d45fbSJean Delvare 
1548d5d45fbSJean Delvare #define W83781D_REG_SCFG2		0x59
1558d5d45fbSJean Delvare static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
1568d5d45fbSJean Delvare 
1578d5d45fbSJean Delvare #define W83781D_DEFAULT_BETA		3435
1588d5d45fbSJean Delvare 
159474d00a8SJean Delvare /* Conversions */
160474d00a8SJean Delvare #define IN_TO_REG(val)			SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
161474d00a8SJean Delvare #define IN_FROM_REG(val)		((val) * 16)
1628d5d45fbSJean Delvare 
1638d5d45fbSJean Delvare static inline u8
1648d5d45fbSJean Delvare FAN_TO_REG(long rpm, int div)
1658d5d45fbSJean Delvare {
1668d5d45fbSJean Delvare 	if (rpm == 0)
1678d5d45fbSJean Delvare 		return 255;
1688d5d45fbSJean Delvare 	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
1698d5d45fbSJean Delvare 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1708d5d45fbSJean Delvare }
1718d5d45fbSJean Delvare 
172474d00a8SJean Delvare static inline long
173474d00a8SJean Delvare FAN_FROM_REG(u8 val, int div)
174474d00a8SJean Delvare {
175474d00a8SJean Delvare 	if (val == 0)
176474d00a8SJean Delvare 		return -1;
177474d00a8SJean Delvare 	if (val == 255)
178474d00a8SJean Delvare 		return 0;
179474d00a8SJean Delvare 	return 1350000 / (val * div);
180474d00a8SJean Delvare }
1818d5d45fbSJean Delvare 
182474d00a8SJean Delvare #define TEMP_TO_REG(val)		SENSORS_LIMIT((val) / 1000, -127, 128)
183474d00a8SJean Delvare #define TEMP_FROM_REG(val)		((val) * 1000)
1848d5d45fbSJean Delvare 
1858d5d45fbSJean Delvare #define BEEP_MASK_FROM_REG(val, type)	((type) == as99127f ? \
1862fbbbf14SJean Delvare 					 (~(val)) & 0x7fff : (val) & 0xff7fff)
1878d5d45fbSJean Delvare #define BEEP_MASK_TO_REG(val, type)	((type) == as99127f ? \
1882fbbbf14SJean Delvare 					 (~(val)) & 0x7fff : (val) & 0xff7fff)
1898d5d45fbSJean Delvare 
1908d5d45fbSJean Delvare #define DIV_FROM_REG(val)		(1 << (val))
1918d5d45fbSJean Delvare 
1928d5d45fbSJean Delvare static inline u8
1938d5d45fbSJean Delvare DIV_TO_REG(long val, enum chips type)
1948d5d45fbSJean Delvare {
1958d5d45fbSJean Delvare 	int i;
1968d5d45fbSJean Delvare 	val = SENSORS_LIMIT(val, 1,
1978d5d45fbSJean Delvare 			    ((type == w83781d
1988d5d45fbSJean Delvare 			      || type == as99127f) ? 8 : 128)) >> 1;
1998d5d45fbSJean Delvare 	for (i = 0; i < 7; i++) {
2008d5d45fbSJean Delvare 		if (val == 0)
2018d5d45fbSJean Delvare 			break;
2028d5d45fbSJean Delvare 		val >>= 1;
2038d5d45fbSJean Delvare 	}
204474d00a8SJean Delvare 	return i;
2058d5d45fbSJean Delvare }
2068d5d45fbSJean Delvare 
2078d5d45fbSJean Delvare struct w83781d_data {
2080217eae3SWolfgang Grandegger 	struct i2c_client *client;
2091beeffe4STony Jones 	struct device *hwmon_dev;
2109a61bf63SIngo Molnar 	struct mutex lock;
2118d5d45fbSJean Delvare 	enum chips type;
2128d5d45fbSJean Delvare 
213360782ddSJean Delvare 	/* For ISA device only */
214360782ddSJean Delvare 	const char *name;
215360782ddSJean Delvare 	int isa_addr;
216360782ddSJean Delvare 
2179a61bf63SIngo Molnar 	struct mutex update_lock;
2188d5d45fbSJean Delvare 	char valid;		/* !=0 if following fields are valid */
2198d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
2208d5d45fbSJean Delvare 
2218d5d45fbSJean Delvare 	struct i2c_client *lm75[2];	/* for secondary I2C addresses */
2228d5d45fbSJean Delvare 	/* array of 2 pointers to subclients */
2238d5d45fbSJean Delvare 
2248d5d45fbSJean Delvare 	u8 in[9];		/* Register value - 8 & 9 for 782D only */
2258d5d45fbSJean Delvare 	u8 in_max[9];		/* Register value - 8 & 9 for 782D only */
2268d5d45fbSJean Delvare 	u8 in_min[9];		/* Register value - 8 & 9 for 782D only */
2278d5d45fbSJean Delvare 	u8 fan[3];		/* Register value */
2288d5d45fbSJean Delvare 	u8 fan_min[3];		/* Register value */
229474d00a8SJean Delvare 	s8 temp;		/* Register value */
230474d00a8SJean Delvare 	s8 temp_max;		/* Register value */
231474d00a8SJean Delvare 	s8 temp_max_hyst;	/* Register value */
2328d5d45fbSJean Delvare 	u16 temp_add[2];	/* Register value */
2338d5d45fbSJean Delvare 	u16 temp_max_add[2];	/* Register value */
2348d5d45fbSJean Delvare 	u16 temp_max_hyst_add[2];	/* Register value */
2358d5d45fbSJean Delvare 	u8 fan_div[3];		/* Register encoding, shifted right */
2368d5d45fbSJean Delvare 	u8 vid;			/* Register encoding, combined */
2378d5d45fbSJean Delvare 	u32 alarms;		/* Register encoding, combined */
2388d5d45fbSJean Delvare 	u32 beep_mask;		/* Register encoding, combined */
2398d5d45fbSJean Delvare 	u8 pwm[4];		/* Register value */
24034875337SJean Delvare 	u8 pwm2_enable;		/* Boolean */
2418d5d45fbSJean Delvare 	u16 sens[3];		/* 782D/783S only.
2428d5d45fbSJean Delvare 				   1 = pentium diode; 2 = 3904 diode;
243b26f9330SJean Delvare 				   4 = thermistor */
2448d5d45fbSJean Delvare 	u8 vrm;
2458d5d45fbSJean Delvare };
2468d5d45fbSJean Delvare 
247443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void);
248443850ceSWolfgang Grandegger static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
249443850ceSWolfgang Grandegger 
25031b8dc4dSJean Delvare static int w83781d_read_value(struct w83781d_data *data, u16 reg);
25131b8dc4dSJean Delvare static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
2528d5d45fbSJean Delvare static struct w83781d_data *w83781d_update_device(struct device *dev);
2537666c13cSJean Delvare static void w83781d_init_device(struct device *dev);
2548d5d45fbSJean Delvare 
2558d5d45fbSJean Delvare /* following are the sysfs callback functions */
2568d5d45fbSJean Delvare #define show_in_reg(reg) \
25734875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
25834875337SJean Delvare 		char *buf) \
2598d5d45fbSJean Delvare { \
26034875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
2618d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
26234875337SJean Delvare 	return sprintf(buf, "%ld\n", \
26334875337SJean Delvare 		       (long)IN_FROM_REG(data->reg[attr->index])); \
2648d5d45fbSJean Delvare }
2658d5d45fbSJean Delvare show_in_reg(in);
2668d5d45fbSJean Delvare show_in_reg(in_min);
2678d5d45fbSJean Delvare show_in_reg(in_max);
2688d5d45fbSJean Delvare 
2698d5d45fbSJean Delvare #define store_in_reg(REG, reg) \
27034875337SJean Delvare static ssize_t store_in_##reg(struct device *dev, struct device_attribute \
27134875337SJean Delvare 		*da, const char *buf, size_t count) \
2728d5d45fbSJean Delvare { \
27334875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
2747666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev); \
27534875337SJean Delvare 	int nr = attr->index; \
276*c531eb3fSGuenter Roeck 	unsigned long val; \
277*c531eb3fSGuenter Roeck 	int err = kstrtoul(buf, 10, &val); \
278*c531eb3fSGuenter Roeck 	if (err) \
279*c531eb3fSGuenter Roeck 		return err; \
2809a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
2818d5d45fbSJean Delvare 	data->in_##reg[nr] = IN_TO_REG(val); \
282*c531eb3fSGuenter Roeck 	w83781d_write_value(data, W83781D_REG_IN_##REG(nr), \
283*c531eb3fSGuenter Roeck 			    data->in_##reg[nr]); \
2848d5d45fbSJean Delvare 	\
2859a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
2868d5d45fbSJean Delvare 	return count; \
2878d5d45fbSJean Delvare }
2888d5d45fbSJean Delvare store_in_reg(MIN, min);
2898d5d45fbSJean Delvare store_in_reg(MAX, max);
2908d5d45fbSJean Delvare 
2918d5d45fbSJean Delvare #define sysfs_in_offsets(offset) \
29234875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
29334875337SJean Delvare 		show_in, NULL, offset); \
29434875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
29534875337SJean Delvare 		show_in_min, store_in_min, offset); \
29634875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
29734875337SJean Delvare 		show_in_max, store_in_max, offset)
2988d5d45fbSJean Delvare 
2998d5d45fbSJean Delvare sysfs_in_offsets(0);
3008d5d45fbSJean Delvare sysfs_in_offsets(1);
3018d5d45fbSJean Delvare sysfs_in_offsets(2);
3028d5d45fbSJean Delvare sysfs_in_offsets(3);
3038d5d45fbSJean Delvare sysfs_in_offsets(4);
3048d5d45fbSJean Delvare sysfs_in_offsets(5);
3058d5d45fbSJean Delvare sysfs_in_offsets(6);
3068d5d45fbSJean Delvare sysfs_in_offsets(7);
3078d5d45fbSJean Delvare sysfs_in_offsets(8);
3088d5d45fbSJean Delvare 
3098d5d45fbSJean Delvare #define show_fan_reg(reg) \
31034875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
31134875337SJean Delvare 		char *buf) \
3128d5d45fbSJean Delvare { \
31334875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3148d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
3158d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", \
31634875337SJean Delvare 		FAN_FROM_REG(data->reg[attr->index], \
31734875337SJean Delvare 			DIV_FROM_REG(data->fan_div[attr->index]))); \
3188d5d45fbSJean Delvare }
3198d5d45fbSJean Delvare show_fan_reg(fan);
3208d5d45fbSJean Delvare show_fan_reg(fan_min);
3218d5d45fbSJean Delvare 
3228d5d45fbSJean Delvare static ssize_t
32334875337SJean Delvare store_fan_min(struct device *dev, struct device_attribute *da,
32434875337SJean Delvare 		const char *buf, size_t count)
3258d5d45fbSJean Delvare {
32634875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3277666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
32834875337SJean Delvare 	int nr = attr->index;
329*c531eb3fSGuenter Roeck 	unsigned long val;
330*c531eb3fSGuenter Roeck 	int err;
3318d5d45fbSJean Delvare 
332*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
333*c531eb3fSGuenter Roeck 	if (err)
334*c531eb3fSGuenter Roeck 		return err;
3358d5d45fbSJean Delvare 
3369a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
33734875337SJean Delvare 	data->fan_min[nr] =
33834875337SJean Delvare 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
33931b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
34034875337SJean Delvare 			    data->fan_min[nr]);
3418d5d45fbSJean Delvare 
3429a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3438d5d45fbSJean Delvare 	return count;
3448d5d45fbSJean Delvare }
3458d5d45fbSJean Delvare 
34634875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
34734875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
34834875337SJean Delvare 		show_fan_min, store_fan_min, 0);
34934875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
35034875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
35134875337SJean Delvare 		show_fan_min, store_fan_min, 1);
35234875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
35334875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
35434875337SJean Delvare 		show_fan_min, store_fan_min, 2);
3558d5d45fbSJean Delvare 
3568d5d45fbSJean Delvare #define show_temp_reg(reg) \
35734875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
35834875337SJean Delvare 		char *buf) \
3598d5d45fbSJean Delvare { \
36034875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3618d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
36234875337SJean Delvare 	int nr = attr->index; \
3638d5d45fbSJean Delvare 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
3648d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", \
3658d5d45fbSJean Delvare 			LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
3668d5d45fbSJean Delvare 	} else {	/* TEMP1 */ \
3678d5d45fbSJean Delvare 		return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->reg)); \
3688d5d45fbSJean Delvare 	} \
3698d5d45fbSJean Delvare }
3708d5d45fbSJean Delvare show_temp_reg(temp);
3718d5d45fbSJean Delvare show_temp_reg(temp_max);
3728d5d45fbSJean Delvare show_temp_reg(temp_max_hyst);
3738d5d45fbSJean Delvare 
3748d5d45fbSJean Delvare #define store_temp_reg(REG, reg) \
37534875337SJean Delvare static ssize_t store_temp_##reg(struct device *dev, \
37634875337SJean Delvare 		struct device_attribute *da, const char *buf, size_t count) \
3778d5d45fbSJean Delvare { \
37834875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3797666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev); \
38034875337SJean Delvare 	int nr = attr->index; \
3815bfedac0SChristian Hohnstaedt 	long val; \
382*c531eb3fSGuenter Roeck 	int err = kstrtol(buf, 10, &val); \
383*c531eb3fSGuenter Roeck 	if (err) \
384*c531eb3fSGuenter Roeck 		return err; \
3859a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
3868d5d45fbSJean Delvare 	 \
3878d5d45fbSJean Delvare 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
3888d5d45fbSJean Delvare 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
38931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
3908d5d45fbSJean Delvare 				data->temp_##reg##_add[nr-2]); \
3918d5d45fbSJean Delvare 	} else {	/* TEMP1 */ \
3928d5d45fbSJean Delvare 		data->temp_##reg = TEMP_TO_REG(val); \
39331b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
3948d5d45fbSJean Delvare 			data->temp_##reg); \
3958d5d45fbSJean Delvare 	} \
3968d5d45fbSJean Delvare 	 \
3979a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
3988d5d45fbSJean Delvare 	return count; \
3998d5d45fbSJean Delvare }
4008d5d45fbSJean Delvare store_temp_reg(OVER, max);
4018d5d45fbSJean Delvare store_temp_reg(HYST, max_hyst);
4028d5d45fbSJean Delvare 
4038d5d45fbSJean Delvare #define sysfs_temp_offsets(offset) \
40434875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
40534875337SJean Delvare 		show_temp, NULL, offset); \
40634875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
40734875337SJean Delvare 		show_temp_max, store_temp_max, offset); \
40834875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
40934875337SJean Delvare 		show_temp_max_hyst, store_temp_max_hyst, offset);
4108d5d45fbSJean Delvare 
4118d5d45fbSJean Delvare sysfs_temp_offsets(1);
4128d5d45fbSJean Delvare sysfs_temp_offsets(2);
4138d5d45fbSJean Delvare sysfs_temp_offsets(3);
4148d5d45fbSJean Delvare 
4158d5d45fbSJean Delvare static ssize_t
4168d5d45fbSJean Delvare show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
4178d5d45fbSJean Delvare {
4188d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4198d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
4208d5d45fbSJean Delvare }
4218d5d45fbSJean Delvare 
422311ce2efSJim Cromie static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
423311ce2efSJim Cromie 
4248d5d45fbSJean Delvare static ssize_t
4258d5d45fbSJean Delvare show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
4268d5d45fbSJean Delvare {
42790d6619aSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
4288d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", (long) data->vrm);
4298d5d45fbSJean Delvare }
4308d5d45fbSJean Delvare 
4318d5d45fbSJean Delvare static ssize_t
432*c531eb3fSGuenter Roeck store_vrm_reg(struct device *dev, struct device_attribute *attr,
433*c531eb3fSGuenter Roeck 	      const char *buf, size_t count)
4348d5d45fbSJean Delvare {
4357666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
436*c531eb3fSGuenter Roeck 	unsigned long val;
437*c531eb3fSGuenter Roeck 	int err;
4388d5d45fbSJean Delvare 
439*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
440*c531eb3fSGuenter Roeck 	if (err)
441*c531eb3fSGuenter Roeck 		return err;
442*c531eb3fSGuenter Roeck 	data->vrm = SENSORS_LIMIT(val, 0, 255);
4438d5d45fbSJean Delvare 
4448d5d45fbSJean Delvare 	return count;
4458d5d45fbSJean Delvare }
4468d5d45fbSJean Delvare 
447311ce2efSJim Cromie static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
448311ce2efSJim Cromie 
4498d5d45fbSJean Delvare static ssize_t
4508d5d45fbSJean Delvare show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
4518d5d45fbSJean Delvare {
4528d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4538d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
4548d5d45fbSJean Delvare }
4558d5d45fbSJean Delvare 
456311ce2efSJim Cromie static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
457311ce2efSJim Cromie 
4587d4a1374SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
4597d4a1374SJean Delvare 		char *buf)
4607d4a1374SJean Delvare {
4617d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4627d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
4637d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
4647d4a1374SJean Delvare }
4657d4a1374SJean Delvare 
4667d4a1374SJean Delvare /* The W83781D has a single alarm bit for temp2 and temp3 */
4677d4a1374SJean Delvare static ssize_t show_temp3_alarm(struct device *dev,
4687d4a1374SJean Delvare 		struct device_attribute *attr, char *buf)
4697d4a1374SJean Delvare {
4707d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4717d4a1374SJean Delvare 	int bitnr = (data->type == w83781d) ? 5 : 13;
4727d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
4737d4a1374SJean Delvare }
4747d4a1374SJean Delvare 
4757d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
4767d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
4777d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
4787d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
4797d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
4807d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
4817d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
4827d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
4837d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
4847d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
4857d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
4867d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
4877d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
4887d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
4897d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
4907d4a1374SJean Delvare 
491*c531eb3fSGuenter Roeck static ssize_t show_beep_mask(struct device *dev,
492*c531eb3fSGuenter Roeck 			       struct device_attribute *attr, char *buf)
4938d5d45fbSJean Delvare {
4948d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4958d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n",
4968d5d45fbSJean Delvare 		       (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
4978d5d45fbSJean Delvare }
4988d5d45fbSJean Delvare 
4998d5d45fbSJean Delvare static ssize_t
50034875337SJean Delvare store_beep_mask(struct device *dev, struct device_attribute *attr,
50134875337SJean Delvare 		const char *buf, size_t count)
5028d5d45fbSJean Delvare {
5037666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
504*c531eb3fSGuenter Roeck 	unsigned long val;
505*c531eb3fSGuenter Roeck 	int err;
5068d5d45fbSJean Delvare 
507*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
508*c531eb3fSGuenter Roeck 	if (err)
509*c531eb3fSGuenter Roeck 		return err;
5108d5d45fbSJean Delvare 
5119a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5122fbbbf14SJean Delvare 	data->beep_mask &= 0x8000; /* preserve beep enable */
5132fbbbf14SJean Delvare 	data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
51431b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
5158d5d45fbSJean Delvare 			    data->beep_mask & 0xff);
51634875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
5172fbbbf14SJean Delvare 			    (data->beep_mask >> 8) & 0xff);
51834875337SJean Delvare 	if (data->type != w83781d && data->type != as99127f) {
51931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
5208d5d45fbSJean Delvare 				    ((data->beep_mask) >> 16) & 0xff);
5218d5d45fbSJean Delvare 	}
5229a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
52334875337SJean Delvare 
5248d5d45fbSJean Delvare 	return count;
5258d5d45fbSJean Delvare }
5268d5d45fbSJean Delvare 
52734875337SJean Delvare static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
52834875337SJean Delvare 		show_beep_mask, store_beep_mask);
5298d5d45fbSJean Delvare 
5307d4a1374SJean Delvare static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
5317d4a1374SJean Delvare 		char *buf)
5327d4a1374SJean Delvare {
5337d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
5347d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
5357d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
5367d4a1374SJean Delvare }
5377d4a1374SJean Delvare 
5387d4a1374SJean Delvare static ssize_t
5397d4a1374SJean Delvare store_beep(struct device *dev, struct device_attribute *attr,
5407d4a1374SJean Delvare 		const char *buf, size_t count)
5417d4a1374SJean Delvare {
5427d4a1374SJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
5437d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
5447d4a1374SJean Delvare 	u8 reg;
545*c531eb3fSGuenter Roeck 	unsigned long bit;
546*c531eb3fSGuenter Roeck 	int err;
5477d4a1374SJean Delvare 
548*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &bit);
549*c531eb3fSGuenter Roeck 	if (err)
550*c531eb3fSGuenter Roeck 		return err;
551*c531eb3fSGuenter Roeck 
5527d4a1374SJean Delvare 	if (bit & ~1)
5537d4a1374SJean Delvare 		return -EINVAL;
5547d4a1374SJean Delvare 
5557d4a1374SJean Delvare 	mutex_lock(&data->update_lock);
5567d4a1374SJean Delvare 	if (bit)
5577d4a1374SJean Delvare 		data->beep_mask |= (1 << bitnr);
5587d4a1374SJean Delvare 	else
5597d4a1374SJean Delvare 		data->beep_mask &= ~(1 << bitnr);
5607d4a1374SJean Delvare 
5617d4a1374SJean Delvare 	if (bitnr < 8) {
5627d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
5637d4a1374SJean Delvare 		if (bit)
5647d4a1374SJean Delvare 			reg |= (1 << bitnr);
5657d4a1374SJean Delvare 		else
5667d4a1374SJean Delvare 			reg &= ~(1 << bitnr);
5677d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
5687d4a1374SJean Delvare 	} else if (bitnr < 16) {
5697d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
5707d4a1374SJean Delvare 		if (bit)
5717d4a1374SJean Delvare 			reg |= (1 << (bitnr - 8));
5727d4a1374SJean Delvare 		else
5737d4a1374SJean Delvare 			reg &= ~(1 << (bitnr - 8));
5747d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
5757d4a1374SJean Delvare 	} else {
5767d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
5777d4a1374SJean Delvare 		if (bit)
5787d4a1374SJean Delvare 			reg |= (1 << (bitnr - 16));
5797d4a1374SJean Delvare 		else
5807d4a1374SJean Delvare 			reg &= ~(1 << (bitnr - 16));
5817d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
5827d4a1374SJean Delvare 	}
5837d4a1374SJean Delvare 	mutex_unlock(&data->update_lock);
5847d4a1374SJean Delvare 
5857d4a1374SJean Delvare 	return count;
5867d4a1374SJean Delvare }
5877d4a1374SJean Delvare 
5887d4a1374SJean Delvare /* The W83781D has a single beep bit for temp2 and temp3 */
5897d4a1374SJean Delvare static ssize_t show_temp3_beep(struct device *dev,
5907d4a1374SJean Delvare 		struct device_attribute *attr, char *buf)
5917d4a1374SJean Delvare {
5927d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
5937d4a1374SJean Delvare 	int bitnr = (data->type == w83781d) ? 5 : 13;
5947d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
5957d4a1374SJean Delvare }
5967d4a1374SJean Delvare 
5977d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
5987d4a1374SJean Delvare 			show_beep, store_beep, 0);
5997d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
6007d4a1374SJean Delvare 			show_beep, store_beep, 1);
6017d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
6027d4a1374SJean Delvare 			show_beep, store_beep, 2);
6037d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
6047d4a1374SJean Delvare 			show_beep, store_beep, 3);
6057d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
6067d4a1374SJean Delvare 			show_beep, store_beep, 8);
6077d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
6087d4a1374SJean Delvare 			show_beep, store_beep, 9);
6097d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
6107d4a1374SJean Delvare 			show_beep, store_beep, 10);
6117d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
6127d4a1374SJean Delvare 			show_beep, store_beep, 16);
6137d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
6147d4a1374SJean Delvare 			show_beep, store_beep, 17);
6157d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
6167d4a1374SJean Delvare 			show_beep, store_beep, 6);
6177d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
6187d4a1374SJean Delvare 			show_beep, store_beep, 7);
6197d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
6207d4a1374SJean Delvare 			show_beep, store_beep, 11);
6217d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
6227d4a1374SJean Delvare 			show_beep, store_beep, 4);
6237d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
6247d4a1374SJean Delvare 			show_beep, store_beep, 5);
6257d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
6267d4a1374SJean Delvare 			show_temp3_beep, store_beep, 13);
6272fbbbf14SJean Delvare static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
6282fbbbf14SJean Delvare 			show_beep, store_beep, 15);
6297d4a1374SJean Delvare 
6308d5d45fbSJean Delvare static ssize_t
63134875337SJean Delvare show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
6328d5d45fbSJean Delvare {
63334875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6348d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
6358d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n",
63634875337SJean Delvare 		       (long) DIV_FROM_REG(data->fan_div[attr->index]));
6378d5d45fbSJean Delvare }
6388d5d45fbSJean Delvare 
6398d5d45fbSJean Delvare /* Note: we save and restore the fan minimum here, because its value is
6408d5d45fbSJean Delvare    determined in part by the fan divisor.  This follows the principle of
641d6e05edcSAndreas Mohr    least surprise; the user doesn't expect the fan minimum to change just
6428d5d45fbSJean Delvare    because the divisor changed. */
6438d5d45fbSJean Delvare static ssize_t
64434875337SJean Delvare store_fan_div(struct device *dev, struct device_attribute *da,
64534875337SJean Delvare 		const char *buf, size_t count)
6468d5d45fbSJean Delvare {
64734875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6487666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
6498d5d45fbSJean Delvare 	unsigned long min;
65034875337SJean Delvare 	int nr = attr->index;
6518d5d45fbSJean Delvare 	u8 reg;
652*c531eb3fSGuenter Roeck 	unsigned long val;
653*c531eb3fSGuenter Roeck 	int err;
654*c531eb3fSGuenter Roeck 
655*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
656*c531eb3fSGuenter Roeck 	if (err)
657*c531eb3fSGuenter Roeck 		return err;
6588d5d45fbSJean Delvare 
6599a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6608d5d45fbSJean Delvare 
6618d5d45fbSJean Delvare 	/* Save fan_min */
6628d5d45fbSJean Delvare 	min = FAN_FROM_REG(data->fan_min[nr],
6638d5d45fbSJean Delvare 			   DIV_FROM_REG(data->fan_div[nr]));
6648d5d45fbSJean Delvare 
6658d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val, data->type);
6668d5d45fbSJean Delvare 
667*c531eb3fSGuenter Roeck 	reg = (w83781d_read_value(data, nr == 2 ?
668*c531eb3fSGuenter Roeck 				  W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
6698d5d45fbSJean Delvare 		& (nr == 0 ? 0xcf : 0x3f))
6708d5d45fbSJean Delvare 	      | ((data->fan_div[nr] & 0x03) << (nr == 0 ? 4 : 6));
671*c531eb3fSGuenter Roeck 	w83781d_write_value(data, nr == 2 ?
672*c531eb3fSGuenter Roeck 			    W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
6738d5d45fbSJean Delvare 
6748d5d45fbSJean Delvare 	/* w83781d and as99127f don't have extended divisor bits */
6758d5d45fbSJean Delvare 	if (data->type != w83781d && data->type != as99127f) {
67631b8dc4dSJean Delvare 		reg = (w83781d_read_value(data, W83781D_REG_VBAT)
6778d5d45fbSJean Delvare 		       & ~(1 << (5 + nr)))
6788d5d45fbSJean Delvare 		    | ((data->fan_div[nr] & 0x04) << (3 + nr));
67931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_VBAT, reg);
6808d5d45fbSJean Delvare 	}
6818d5d45fbSJean Delvare 
6828d5d45fbSJean Delvare 	/* Restore fan_min */
6838d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
68434875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
6858d5d45fbSJean Delvare 
6869a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6878d5d45fbSJean Delvare 	return count;
6888d5d45fbSJean Delvare }
6898d5d45fbSJean Delvare 
69034875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
69134875337SJean Delvare 		show_fan_div, store_fan_div, 0);
69234875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
69334875337SJean Delvare 		show_fan_div, store_fan_div, 1);
69434875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
69534875337SJean Delvare 		show_fan_div, store_fan_div, 2);
6968d5d45fbSJean Delvare 
6978d5d45fbSJean Delvare static ssize_t
69834875337SJean Delvare show_pwm(struct device *dev, struct device_attribute *da, char *buf)
6998d5d45fbSJean Delvare {
70034875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7018d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
70234875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
7038d5d45fbSJean Delvare }
7048d5d45fbSJean Delvare 
7058d5d45fbSJean Delvare static ssize_t
70634875337SJean Delvare show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
7078d5d45fbSJean Delvare {
7088d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
70934875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->pwm2_enable);
7108d5d45fbSJean Delvare }
7118d5d45fbSJean Delvare 
7128d5d45fbSJean Delvare static ssize_t
71334875337SJean Delvare store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
71434875337SJean Delvare 		size_t count)
7158d5d45fbSJean Delvare {
71634875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7177666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
71834875337SJean Delvare 	int nr = attr->index;
719*c531eb3fSGuenter Roeck 	unsigned long val;
720*c531eb3fSGuenter Roeck 	int err;
7218d5d45fbSJean Delvare 
722*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
723*c531eb3fSGuenter Roeck 	if (err)
724*c531eb3fSGuenter Roeck 		return err;
7258d5d45fbSJean Delvare 
7269a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
72734875337SJean Delvare 	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
72834875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
7299a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7308d5d45fbSJean Delvare 	return count;
7318d5d45fbSJean Delvare }
7328d5d45fbSJean Delvare 
7338d5d45fbSJean Delvare static ssize_t
73434875337SJean Delvare store_pwm2_enable(struct device *dev, struct device_attribute *da,
73534875337SJean Delvare 		const char *buf, size_t count)
7368d5d45fbSJean Delvare {
7377666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
738*c531eb3fSGuenter Roeck 	unsigned long val;
739*c531eb3fSGuenter Roeck 	u32 reg;
740*c531eb3fSGuenter Roeck 	int err;
7418d5d45fbSJean Delvare 
742*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
743*c531eb3fSGuenter Roeck 	if (err)
744*c531eb3fSGuenter Roeck 		return err;
7458d5d45fbSJean Delvare 
7469a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7478d5d45fbSJean Delvare 
7488d5d45fbSJean Delvare 	switch (val) {
7498d5d45fbSJean Delvare 	case 0:
7508d5d45fbSJean Delvare 	case 1:
75131b8dc4dSJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
75231b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_PWMCLK12,
7538d5d45fbSJean Delvare 				    (reg & 0xf7) | (val << 3));
7548d5d45fbSJean Delvare 
75531b8dc4dSJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
75631b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
7578d5d45fbSJean Delvare 				    (reg & 0xef) | (!val << 4));
7588d5d45fbSJean Delvare 
75934875337SJean Delvare 		data->pwm2_enable = val;
7608d5d45fbSJean Delvare 		break;
7618d5d45fbSJean Delvare 
7628d5d45fbSJean Delvare 	default:
7639a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
7648d5d45fbSJean Delvare 		return -EINVAL;
7658d5d45fbSJean Delvare 	}
7668d5d45fbSJean Delvare 
7679a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7688d5d45fbSJean Delvare 	return count;
7698d5d45fbSJean Delvare }
7708d5d45fbSJean Delvare 
77134875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
77234875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
77334875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
77434875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
77534875337SJean Delvare /* only PWM2 can be enabled/disabled */
77634875337SJean Delvare static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
77734875337SJean Delvare 		show_pwm2_enable, store_pwm2_enable);
7788d5d45fbSJean Delvare 
7798d5d45fbSJean Delvare static ssize_t
78034875337SJean Delvare show_sensor(struct device *dev, struct device_attribute *da, char *buf)
7818d5d45fbSJean Delvare {
78234875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7838d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
78434875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
7858d5d45fbSJean Delvare }
7868d5d45fbSJean Delvare 
7878d5d45fbSJean Delvare static ssize_t
78834875337SJean Delvare store_sensor(struct device *dev, struct device_attribute *da,
78934875337SJean Delvare 		const char *buf, size_t count)
7908d5d45fbSJean Delvare {
79134875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7927666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
79334875337SJean Delvare 	int nr = attr->index;
794*c531eb3fSGuenter Roeck 	unsigned long val;
795*c531eb3fSGuenter Roeck 	u32 tmp;
796*c531eb3fSGuenter Roeck 	int err;
7978d5d45fbSJean Delvare 
798*c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
799*c531eb3fSGuenter Roeck 	if (err)
800*c531eb3fSGuenter Roeck 		return err;
8018d5d45fbSJean Delvare 
8029a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
8038d5d45fbSJean Delvare 
8048d5d45fbSJean Delvare 	switch (val) {
8058d5d45fbSJean Delvare 	case 1:		/* PII/Celeron diode */
80631b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
80731b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
80834875337SJean Delvare 				    tmp | BIT_SCFG1[nr]);
80931b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
81031b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG2,
81134875337SJean Delvare 				    tmp | BIT_SCFG2[nr]);
81234875337SJean Delvare 		data->sens[nr] = val;
8138d5d45fbSJean Delvare 		break;
8148d5d45fbSJean Delvare 	case 2:		/* 3904 */
81531b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
81631b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
81734875337SJean Delvare 				    tmp | BIT_SCFG1[nr]);
81831b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
81931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG2,
82034875337SJean Delvare 				    tmp & ~BIT_SCFG2[nr]);
82134875337SJean Delvare 		data->sens[nr] = val;
8228d5d45fbSJean Delvare 		break;
823b26f9330SJean Delvare 	case W83781D_DEFAULT_BETA:
824b26f9330SJean Delvare 		dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
825b26f9330SJean Delvare 			 "instead\n", W83781D_DEFAULT_BETA);
826b26f9330SJean Delvare 		/* fall through */
827b26f9330SJean Delvare 	case 4:		/* thermistor */
82831b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
82931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
83034875337SJean Delvare 				    tmp & ~BIT_SCFG1[nr]);
83134875337SJean Delvare 		data->sens[nr] = val;
8328d5d45fbSJean Delvare 		break;
8338d5d45fbSJean Delvare 	default:
834b26f9330SJean Delvare 		dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
835b26f9330SJean Delvare 		       (long) val);
8368d5d45fbSJean Delvare 		break;
8378d5d45fbSJean Delvare 	}
8388d5d45fbSJean Delvare 
8399a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8408d5d45fbSJean Delvare 	return count;
8418d5d45fbSJean Delvare }
8428d5d45fbSJean Delvare 
84334875337SJean Delvare static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
84434875337SJean Delvare 	show_sensor, store_sensor, 0);
84534875337SJean Delvare static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
846393cdad6SMark M. Hoffman 	show_sensor, store_sensor, 1);
84734875337SJean Delvare static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
848393cdad6SMark M. Hoffman 	show_sensor, store_sensor, 2);
8498d5d45fbSJean Delvare 
8508d5d45fbSJean Delvare /* Assumes that adapter is of I2C, not ISA variety.
8518d5d45fbSJean Delvare  * OTHERWISE DON'T CALL THIS
8528d5d45fbSJean Delvare  */
8538d5d45fbSJean Delvare static int
8540217eae3SWolfgang Grandegger w83781d_detect_subclients(struct i2c_client *new_client)
8558d5d45fbSJean Delvare {
8568d5d45fbSJean Delvare 	int i, val1 = 0, id;
8578d5d45fbSJean Delvare 	int err;
8580217eae3SWolfgang Grandegger 	int address = new_client->addr;
8590217eae3SWolfgang Grandegger 	unsigned short sc_addr[2];
8600217eae3SWolfgang Grandegger 	struct i2c_adapter *adapter = new_client->adapter;
8618d5d45fbSJean Delvare 	struct w83781d_data *data = i2c_get_clientdata(new_client);
8620217eae3SWolfgang Grandegger 	enum chips kind = data->type;
8638d5d45fbSJean Delvare 
8648d5d45fbSJean Delvare 	id = i2c_adapter_id(adapter);
8658d5d45fbSJean Delvare 
8668d5d45fbSJean Delvare 	if (force_subclients[0] == id && force_subclients[1] == address) {
8678d5d45fbSJean Delvare 		for (i = 2; i <= 3; i++) {
8688d5d45fbSJean Delvare 			if (force_subclients[i] < 0x48 ||
8698d5d45fbSJean Delvare 			    force_subclients[i] > 0x4f) {
8708d5d45fbSJean Delvare 				dev_err(&new_client->dev, "Invalid subclient "
8718d5d45fbSJean Delvare 					"address %d; must be 0x48-0x4f\n",
8728d5d45fbSJean Delvare 					force_subclients[i]);
8738d5d45fbSJean Delvare 				err = -EINVAL;
8748d5d45fbSJean Delvare 				goto ERROR_SC_1;
8758d5d45fbSJean Delvare 			}
8768d5d45fbSJean Delvare 		}
87731b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
8788d5d45fbSJean Delvare 				(force_subclients[2] & 0x07) |
8798d5d45fbSJean Delvare 				((force_subclients[3] & 0x07) << 4));
8800217eae3SWolfgang Grandegger 		sc_addr[0] = force_subclients[2];
8818d5d45fbSJean Delvare 	} else {
88231b8dc4dSJean Delvare 		val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
8830217eae3SWolfgang Grandegger 		sc_addr[0] = 0x48 + (val1 & 0x07);
8848d5d45fbSJean Delvare 	}
8858d5d45fbSJean Delvare 
8868d5d45fbSJean Delvare 	if (kind != w83783s) {
8878d5d45fbSJean Delvare 		if (force_subclients[0] == id &&
8888d5d45fbSJean Delvare 		    force_subclients[1] == address) {
8890217eae3SWolfgang Grandegger 			sc_addr[1] = force_subclients[3];
8908d5d45fbSJean Delvare 		} else {
8910217eae3SWolfgang Grandegger 			sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
8928d5d45fbSJean Delvare 		}
8930217eae3SWolfgang Grandegger 		if (sc_addr[0] == sc_addr[1]) {
8948d5d45fbSJean Delvare 			dev_err(&new_client->dev,
8958d5d45fbSJean Delvare 			       "Duplicate addresses 0x%x for subclients.\n",
8960217eae3SWolfgang Grandegger 			       sc_addr[0]);
8978d5d45fbSJean Delvare 			err = -EBUSY;
8988d5d45fbSJean Delvare 			goto ERROR_SC_2;
8998d5d45fbSJean Delvare 		}
9008d5d45fbSJean Delvare 	}
9018d5d45fbSJean Delvare 
9028d5d45fbSJean Delvare 	for (i = 0; i <= 1; i++) {
9030217eae3SWolfgang Grandegger 		data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
9040217eae3SWolfgang Grandegger 		if (!data->lm75[i]) {
9058d5d45fbSJean Delvare 			dev_err(&new_client->dev, "Subclient %d "
9068d5d45fbSJean Delvare 				"registration at address 0x%x "
9070217eae3SWolfgang Grandegger 				"failed.\n", i, sc_addr[i]);
9080217eae3SWolfgang Grandegger 			err = -ENOMEM;
9098d5d45fbSJean Delvare 			if (i == 1)
9108d5d45fbSJean Delvare 				goto ERROR_SC_3;
9118d5d45fbSJean Delvare 			goto ERROR_SC_2;
9128d5d45fbSJean Delvare 		}
9138d5d45fbSJean Delvare 		if (kind == w83783s)
9148d5d45fbSJean Delvare 			break;
9158d5d45fbSJean Delvare 	}
9168d5d45fbSJean Delvare 
9178d5d45fbSJean Delvare 	return 0;
9188d5d45fbSJean Delvare 
9198d5d45fbSJean Delvare /* Undo inits in case of errors */
9208d5d45fbSJean Delvare ERROR_SC_3:
9210217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[0]);
9228d5d45fbSJean Delvare ERROR_SC_2:
9238d5d45fbSJean Delvare ERROR_SC_1:
9248d5d45fbSJean Delvare 	return err;
9258d5d45fbSJean Delvare }
9268d5d45fbSJean Delvare 
927311ce2efSJim Cromie #define IN_UNIT_ATTRS(X)					\
92834875337SJean Delvare 	&sensor_dev_attr_in##X##_input.dev_attr.attr,		\
92934875337SJean Delvare 	&sensor_dev_attr_in##X##_min.dev_attr.attr,		\
9307d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_max.dev_attr.attr,		\
9317d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_alarm.dev_attr.attr,		\
9327d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_beep.dev_attr.attr
933311ce2efSJim Cromie 
934311ce2efSJim Cromie #define FAN_UNIT_ATTRS(X)					\
93534875337SJean Delvare 	&sensor_dev_attr_fan##X##_input.dev_attr.attr,		\
93634875337SJean Delvare 	&sensor_dev_attr_fan##X##_min.dev_attr.attr,		\
9377d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_div.dev_attr.attr,		\
9387d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_alarm.dev_attr.attr,		\
9397d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_beep.dev_attr.attr
940311ce2efSJim Cromie 
941311ce2efSJim Cromie #define TEMP_UNIT_ATTRS(X)					\
94234875337SJean Delvare 	&sensor_dev_attr_temp##X##_input.dev_attr.attr,		\
94334875337SJean Delvare 	&sensor_dev_attr_temp##X##_max.dev_attr.attr,		\
9447d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr,	\
9457d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_alarm.dev_attr.attr,		\
9467d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_beep.dev_attr.attr
947311ce2efSJim Cromie 
948311ce2efSJim Cromie static struct attribute *w83781d_attributes[] = {
949311ce2efSJim Cromie 	IN_UNIT_ATTRS(0),
950311ce2efSJim Cromie 	IN_UNIT_ATTRS(2),
951311ce2efSJim Cromie 	IN_UNIT_ATTRS(3),
952311ce2efSJim Cromie 	IN_UNIT_ATTRS(4),
953311ce2efSJim Cromie 	IN_UNIT_ATTRS(5),
954311ce2efSJim Cromie 	IN_UNIT_ATTRS(6),
955311ce2efSJim Cromie 	FAN_UNIT_ATTRS(1),
956311ce2efSJim Cromie 	FAN_UNIT_ATTRS(2),
957311ce2efSJim Cromie 	FAN_UNIT_ATTRS(3),
958311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(1),
959311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(2),
960311ce2efSJim Cromie 	&dev_attr_cpu0_vid.attr,
961311ce2efSJim Cromie 	&dev_attr_vrm.attr,
962311ce2efSJim Cromie 	&dev_attr_alarms.attr,
963311ce2efSJim Cromie 	&dev_attr_beep_mask.attr,
9642fbbbf14SJean Delvare 	&sensor_dev_attr_beep_enable.dev_attr.attr,
965311ce2efSJim Cromie 	NULL
966311ce2efSJim Cromie };
967311ce2efSJim Cromie static const struct attribute_group w83781d_group = {
968311ce2efSJim Cromie 	.attrs = w83781d_attributes,
969311ce2efSJim Cromie };
970311ce2efSJim Cromie 
971311ce2efSJim Cromie static struct attribute *w83781d_attributes_opt[] = {
972311ce2efSJim Cromie 	IN_UNIT_ATTRS(1),
973311ce2efSJim Cromie 	IN_UNIT_ATTRS(7),
974311ce2efSJim Cromie 	IN_UNIT_ATTRS(8),
975311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(3),
97634875337SJean Delvare 	&sensor_dev_attr_pwm1.dev_attr.attr,
97734875337SJean Delvare 	&sensor_dev_attr_pwm2.dev_attr.attr,
97834875337SJean Delvare 	&sensor_dev_attr_pwm3.dev_attr.attr,
97934875337SJean Delvare 	&sensor_dev_attr_pwm4.dev_attr.attr,
980311ce2efSJim Cromie 	&dev_attr_pwm2_enable.attr,
98134875337SJean Delvare 	&sensor_dev_attr_temp1_type.dev_attr.attr,
98234875337SJean Delvare 	&sensor_dev_attr_temp2_type.dev_attr.attr,
98334875337SJean Delvare 	&sensor_dev_attr_temp3_type.dev_attr.attr,
984311ce2efSJim Cromie 	NULL
985311ce2efSJim Cromie };
986311ce2efSJim Cromie static const struct attribute_group w83781d_group_opt = {
987311ce2efSJim Cromie 	.attrs = w83781d_attributes_opt,
988311ce2efSJim Cromie };
989311ce2efSJim Cromie 
9907666c13cSJean Delvare /* No clean up is done on error, it's up to the caller */
9917666c13cSJean Delvare static int
9927666c13cSJean Delvare w83781d_create_files(struct device *dev, int kind, int is_isa)
9937666c13cSJean Delvare {
9947666c13cSJean Delvare 	int err;
9957666c13cSJean Delvare 
996*c531eb3fSGuenter Roeck 	err = sysfs_create_group(&dev->kobj, &w83781d_group);
997*c531eb3fSGuenter Roeck 	if (err)
9987666c13cSJean Delvare 		return err;
9997666c13cSJean Delvare 
10007666c13cSJean Delvare 	if (kind != w83783s) {
100134875337SJean Delvare 		if ((err = device_create_file(dev,
100234875337SJean Delvare 				&sensor_dev_attr_in1_input.dev_attr))
100334875337SJean Delvare 		    || (err = device_create_file(dev,
100434875337SJean Delvare 				&sensor_dev_attr_in1_min.dev_attr))
100534875337SJean Delvare 		    || (err = device_create_file(dev,
10067d4a1374SJean Delvare 				&sensor_dev_attr_in1_max.dev_attr))
10077d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10087d4a1374SJean Delvare 				&sensor_dev_attr_in1_alarm.dev_attr))
10097d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10107d4a1374SJean Delvare 				&sensor_dev_attr_in1_beep.dev_attr)))
10117666c13cSJean Delvare 			return err;
10127666c13cSJean Delvare 	}
10137666c13cSJean Delvare 	if (kind != as99127f && kind != w83781d && kind != w83783s) {
101434875337SJean Delvare 		if ((err = device_create_file(dev,
101534875337SJean Delvare 				&sensor_dev_attr_in7_input.dev_attr))
101634875337SJean Delvare 		    || (err = device_create_file(dev,
101734875337SJean Delvare 				&sensor_dev_attr_in7_min.dev_attr))
101834875337SJean Delvare 		    || (err = device_create_file(dev,
101934875337SJean Delvare 				&sensor_dev_attr_in7_max.dev_attr))
102034875337SJean Delvare 		    || (err = device_create_file(dev,
10217d4a1374SJean Delvare 				&sensor_dev_attr_in7_alarm.dev_attr))
10227d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10237d4a1374SJean Delvare 				&sensor_dev_attr_in7_beep.dev_attr))
10247d4a1374SJean Delvare 		    || (err = device_create_file(dev,
102534875337SJean Delvare 				&sensor_dev_attr_in8_input.dev_attr))
102634875337SJean Delvare 		    || (err = device_create_file(dev,
102734875337SJean Delvare 				&sensor_dev_attr_in8_min.dev_attr))
102834875337SJean Delvare 		    || (err = device_create_file(dev,
10297d4a1374SJean Delvare 				&sensor_dev_attr_in8_max.dev_attr))
10307d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10317d4a1374SJean Delvare 				&sensor_dev_attr_in8_alarm.dev_attr))
10327d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10337d4a1374SJean Delvare 				&sensor_dev_attr_in8_beep.dev_attr)))
10347666c13cSJean Delvare 			return err;
10357666c13cSJean Delvare 	}
10367666c13cSJean Delvare 	if (kind != w83783s) {
103734875337SJean Delvare 		if ((err = device_create_file(dev,
103834875337SJean Delvare 				&sensor_dev_attr_temp3_input.dev_attr))
10397666c13cSJean Delvare 		    || (err = device_create_file(dev,
104034875337SJean Delvare 				&sensor_dev_attr_temp3_max.dev_attr))
104134875337SJean Delvare 		    || (err = device_create_file(dev,
10427d4a1374SJean Delvare 				&sensor_dev_attr_temp3_max_hyst.dev_attr))
10437d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10447d4a1374SJean Delvare 				&sensor_dev_attr_temp3_alarm.dev_attr))
10457d4a1374SJean Delvare 		    || (err = device_create_file(dev,
10467d4a1374SJean Delvare 				&sensor_dev_attr_temp3_beep.dev_attr)))
10477d4a1374SJean Delvare 			return err;
10487d4a1374SJean Delvare 
10497768aa76SJean Delvare 		if (kind != w83781d) {
10507d4a1374SJean Delvare 			err = sysfs_chmod_file(&dev->kobj,
10517d4a1374SJean Delvare 				&sensor_dev_attr_temp3_alarm.dev_attr.attr,
10527d4a1374SJean Delvare 				S_IRUGO | S_IWUSR);
10537d4a1374SJean Delvare 			if (err)
10547666c13cSJean Delvare 				return err;
10557666c13cSJean Delvare 		}
10567768aa76SJean Delvare 	}
10577666c13cSJean Delvare 
10587666c13cSJean Delvare 	if (kind != w83781d && kind != as99127f) {
105934875337SJean Delvare 		if ((err = device_create_file(dev,
106034875337SJean Delvare 				&sensor_dev_attr_pwm1.dev_attr))
106134875337SJean Delvare 		    || (err = device_create_file(dev,
106234875337SJean Delvare 				&sensor_dev_attr_pwm2.dev_attr))
10637666c13cSJean Delvare 		    || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
10647666c13cSJean Delvare 			return err;
10657666c13cSJean Delvare 	}
10667666c13cSJean Delvare 	if (kind == w83782d && !is_isa) {
106734875337SJean Delvare 		if ((err = device_create_file(dev,
106834875337SJean Delvare 				&sensor_dev_attr_pwm3.dev_attr))
106934875337SJean Delvare 		    || (err = device_create_file(dev,
107034875337SJean Delvare 				&sensor_dev_attr_pwm4.dev_attr)))
10717666c13cSJean Delvare 			return err;
10727666c13cSJean Delvare 	}
10737666c13cSJean Delvare 
10747666c13cSJean Delvare 	if (kind != as99127f && kind != w83781d) {
107534875337SJean Delvare 		if ((err = device_create_file(dev,
107634875337SJean Delvare 				&sensor_dev_attr_temp1_type.dev_attr))
10777666c13cSJean Delvare 		    || (err = device_create_file(dev,
107834875337SJean Delvare 				&sensor_dev_attr_temp2_type.dev_attr)))
10797666c13cSJean Delvare 			return err;
10807666c13cSJean Delvare 		if (kind != w83783s) {
1081*c531eb3fSGuenter Roeck 			err = device_create_file(dev,
1082*c531eb3fSGuenter Roeck 				&sensor_dev_attr_temp3_type.dev_attr);
1083*c531eb3fSGuenter Roeck 			if (err)
10847666c13cSJean Delvare 				return err;
10857666c13cSJean Delvare 		}
10867666c13cSJean Delvare 	}
10877666c13cSJean Delvare 
10887666c13cSJean Delvare 	return 0;
10897666c13cSJean Delvare }
10907666c13cSJean Delvare 
10910217eae3SWolfgang Grandegger /* Return 0 if detection is successful, -ENODEV otherwise */
10928d5d45fbSJean Delvare static int
1093310ec792SJean Delvare w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
10948d5d45fbSJean Delvare {
1095bab2bf44SJean Delvare 	int val1, val2;
10960217eae3SWolfgang Grandegger 	struct w83781d_data *isa = w83781d_data_if_isa();
10970217eae3SWolfgang Grandegger 	struct i2c_adapter *adapter = client->adapter;
10980217eae3SWolfgang Grandegger 	int address = client->addr;
1099bab2bf44SJean Delvare 	const char *client_name;
11008d5d45fbSJean Delvare 	enum vendor { winbond, asus } vendid;
11018d5d45fbSJean Delvare 
11020217eae3SWolfgang Grandegger 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
11030217eae3SWolfgang Grandegger 		return -ENODEV;
11048d5d45fbSJean Delvare 
11050217eae3SWolfgang Grandegger 	/* We block updates of the ISA device to minimize the risk of
11060217eae3SWolfgang Grandegger 	   concurrent access to the same W83781D chip through different
11070217eae3SWolfgang Grandegger 	   interfaces. */
11080217eae3SWolfgang Grandegger 	if (isa)
11090217eae3SWolfgang Grandegger 		mutex_lock(&isa->update_lock);
11108d5d45fbSJean Delvare 
1111bab2bf44SJean Delvare 	if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1112bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1113bab2bf44SJean Delvare 			"Detection of w83781d chip failed at step 3\n");
11140217eae3SWolfgang Grandegger 		goto err_nodev;
11158d5d45fbSJean Delvare 	}
1116bab2bf44SJean Delvare 
11170217eae3SWolfgang Grandegger 	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
11180217eae3SWolfgang Grandegger 	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
11198d5d45fbSJean Delvare 	/* Check for Winbond or Asus ID if in bank 0 */
1120bab2bf44SJean Delvare 	if (!(val1 & 0x07) &&
1121bab2bf44SJean Delvare 	    ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
1122bab2bf44SJean Delvare 	     ((val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
1123bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1124bab2bf44SJean Delvare 			"Detection of w83781d chip failed at step 4\n");
11250217eae3SWolfgang Grandegger 		goto err_nodev;
11268d5d45fbSJean Delvare 	}
11278d5d45fbSJean Delvare 	/* If Winbond SMBus, check address at 0x48.
11288d5d45fbSJean Delvare 	   Asus doesn't support, except for as99127f rev.2 */
1129bab2bf44SJean Delvare 	if ((!(val1 & 0x80) && val2 == 0xa3) ||
1130bab2bf44SJean Delvare 	    ((val1 & 0x80) && val2 == 0x5c)) {
1131bab2bf44SJean Delvare 		if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1132bab2bf44SJean Delvare 		    != address) {
1133bab2bf44SJean Delvare 			dev_dbg(&adapter->dev,
1134bab2bf44SJean Delvare 				"Detection of w83781d chip failed at step 5\n");
11350217eae3SWolfgang Grandegger 			goto err_nodev;
11368d5d45fbSJean Delvare 		}
11378d5d45fbSJean Delvare 	}
11388d5d45fbSJean Delvare 
1139bab2bf44SJean Delvare 	/* Put it now into bank 0 and Vendor ID High Byte */
11400217eae3SWolfgang Grandegger 	i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
11410217eae3SWolfgang Grandegger 		(i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1142311ce2efSJim Cromie 		 & 0x78) | 0x80);
11438d5d45fbSJean Delvare 
1144bab2bf44SJean Delvare 	/* Get the vendor ID */
11450217eae3SWolfgang Grandegger 	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
11468d5d45fbSJean Delvare 	if (val2 == 0x5c)
11478d5d45fbSJean Delvare 		vendid = winbond;
11488d5d45fbSJean Delvare 	else if (val2 == 0x12)
11498d5d45fbSJean Delvare 		vendid = asus;
11508d5d45fbSJean Delvare 	else {
1151bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1152bab2bf44SJean Delvare 			"w83781d chip vendor is neither Winbond nor Asus\n");
11530217eae3SWolfgang Grandegger 		goto err_nodev;
11548d5d45fbSJean Delvare 	}
11558d5d45fbSJean Delvare 
1156bab2bf44SJean Delvare 	/* Determine the chip type. */
11570217eae3SWolfgang Grandegger 	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
11588d5d45fbSJean Delvare 	if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1159bab2bf44SJean Delvare 		client_name = "w83781d";
11608d5d45fbSJean Delvare 	else if (val1 == 0x30 && vendid == winbond)
1161bab2bf44SJean Delvare 		client_name = "w83782d";
11627666c13cSJean Delvare 	else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1163bab2bf44SJean Delvare 		client_name = "w83783s";
11646722feadSJean Delvare 	else if (val1 == 0x31)
1165bab2bf44SJean Delvare 		client_name = "as99127f";
1166bab2bf44SJean Delvare 	else
11670217eae3SWolfgang Grandegger 		goto err_nodev;
1168c6566206SJean Delvare 
1169bab2bf44SJean Delvare 	if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1170c6566206SJean Delvare 		dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
1171c6566206SJean Delvare 			"be the same as ISA device\n", address);
11720217eae3SWolfgang Grandegger 		goto err_nodev;
1173c6566206SJean Delvare 	}
11748d5d45fbSJean Delvare 
11750217eae3SWolfgang Grandegger 	if (isa)
11760217eae3SWolfgang Grandegger 		mutex_unlock(&isa->update_lock);
11770217eae3SWolfgang Grandegger 
11780217eae3SWolfgang Grandegger 	strlcpy(info->type, client_name, I2C_NAME_SIZE);
11798d5d45fbSJean Delvare 
11800217eae3SWolfgang Grandegger 	return 0;
11810217eae3SWolfgang Grandegger 
11820217eae3SWolfgang Grandegger  err_nodev:
11830217eae3SWolfgang Grandegger 	if (isa)
11840217eae3SWolfgang Grandegger 		mutex_unlock(&isa->update_lock);
11850217eae3SWolfgang Grandegger 	return -ENODEV;
11860217eae3SWolfgang Grandegger }
11870217eae3SWolfgang Grandegger 
11880217eae3SWolfgang Grandegger static int
11890217eae3SWolfgang Grandegger w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id)
11900217eae3SWolfgang Grandegger {
11910217eae3SWolfgang Grandegger 	struct device *dev = &client->dev;
11920217eae3SWolfgang Grandegger 	struct w83781d_data *data;
11930217eae3SWolfgang Grandegger 	int err;
11940217eae3SWolfgang Grandegger 
11950217eae3SWolfgang Grandegger 	data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
11960217eae3SWolfgang Grandegger 	if (!data) {
11970217eae3SWolfgang Grandegger 		err = -ENOMEM;
11980217eae3SWolfgang Grandegger 		goto ERROR1;
11990217eae3SWolfgang Grandegger 	}
12000217eae3SWolfgang Grandegger 
12010217eae3SWolfgang Grandegger 	i2c_set_clientdata(client, data);
12020217eae3SWolfgang Grandegger 	mutex_init(&data->lock);
12030217eae3SWolfgang Grandegger 	mutex_init(&data->update_lock);
12040217eae3SWolfgang Grandegger 
12050217eae3SWolfgang Grandegger 	data->type = id->driver_data;
12060217eae3SWolfgang Grandegger 	data->client = client;
12078d5d45fbSJean Delvare 
12088d5d45fbSJean Delvare 	/* attach secondary i2c lm75-like clients */
12090217eae3SWolfgang Grandegger 	err = w83781d_detect_subclients(client);
12100217eae3SWolfgang Grandegger 	if (err)
12118d5d45fbSJean Delvare 		goto ERROR3;
12128d5d45fbSJean Delvare 
12138d5d45fbSJean Delvare 	/* Initialize the chip */
12147666c13cSJean Delvare 	w83781d_init_device(dev);
12158d5d45fbSJean Delvare 
12168d5d45fbSJean Delvare 	/* Register sysfs hooks */
12170217eae3SWolfgang Grandegger 	err = w83781d_create_files(dev, data->type, 0);
12187666c13cSJean Delvare 	if (err)
1219311ce2efSJim Cromie 		goto ERROR4;
1220311ce2efSJim Cromie 
12211beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(dev);
12221beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
12231beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
1224943b0830SMark M. Hoffman 		goto ERROR4;
1225943b0830SMark M. Hoffman 	}
1226943b0830SMark M. Hoffman 
12278d5d45fbSJean Delvare 	return 0;
12288d5d45fbSJean Delvare 
1229943b0830SMark M. Hoffman ERROR4:
1230311ce2efSJim Cromie 	sysfs_remove_group(&dev->kobj, &w83781d_group);
1231311ce2efSJim Cromie 	sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
1232311ce2efSJim Cromie 
12330217eae3SWolfgang Grandegger 	if (data->lm75[0])
12340217eae3SWolfgang Grandegger 		i2c_unregister_device(data->lm75[0]);
12350217eae3SWolfgang Grandegger 	if (data->lm75[1])
12360217eae3SWolfgang Grandegger 		i2c_unregister_device(data->lm75[1]);
12378d5d45fbSJean Delvare ERROR3:
12388d5d45fbSJean Delvare 	kfree(data);
12398d5d45fbSJean Delvare ERROR1:
12408d5d45fbSJean Delvare 	return err;
12418d5d45fbSJean Delvare }
12428d5d45fbSJean Delvare 
12438d5d45fbSJean Delvare static int
12440217eae3SWolfgang Grandegger w83781d_remove(struct i2c_client *client)
12458d5d45fbSJean Delvare {
1246943b0830SMark M. Hoffman 	struct w83781d_data *data = i2c_get_clientdata(client);
12470217eae3SWolfgang Grandegger 	struct device *dev = &client->dev;
12488d5d45fbSJean Delvare 
12491beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
12508d5d45fbSJean Delvare 
12510217eae3SWolfgang Grandegger 	sysfs_remove_group(&dev->kobj, &w83781d_group);
12520217eae3SWolfgang Grandegger 	sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
12538d5d45fbSJean Delvare 
12540217eae3SWolfgang Grandegger 	if (data->lm75[0])
12550217eae3SWolfgang Grandegger 		i2c_unregister_device(data->lm75[0]);
12560217eae3SWolfgang Grandegger 	if (data->lm75[1])
12570217eae3SWolfgang Grandegger 		i2c_unregister_device(data->lm75[1]);
12580217eae3SWolfgang Grandegger 
1259943b0830SMark M. Hoffman 	kfree(data);
1260943b0830SMark M. Hoffman 
12618d5d45fbSJean Delvare 	return 0;
12628d5d45fbSJean Delvare }
12638d5d45fbSJean Delvare 
12648d5d45fbSJean Delvare static int
1265443850ceSWolfgang Grandegger w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
12668d5d45fbSJean Delvare {
12670217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1268443850ceSWolfgang Grandegger 	int res, bank;
12698d5d45fbSJean Delvare 	struct i2c_client *cl;
12708d5d45fbSJean Delvare 
12718d5d45fbSJean Delvare 	bank = (reg >> 8) & 0x0f;
12728d5d45fbSJean Delvare 	if (bank > 2)
12738d5d45fbSJean Delvare 		/* switch banks */
12748d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
12758d5d45fbSJean Delvare 					  bank);
12768d5d45fbSJean Delvare 	if (bank == 0 || bank > 2) {
12778d5d45fbSJean Delvare 		res = i2c_smbus_read_byte_data(client, reg & 0xff);
12788d5d45fbSJean Delvare 	} else {
12798d5d45fbSJean Delvare 		/* switch to subclient */
12808d5d45fbSJean Delvare 		cl = data->lm75[bank - 1];
12818d5d45fbSJean Delvare 		/* convert from ISA to LM75 I2C addresses */
12828d5d45fbSJean Delvare 		switch (reg & 0xff) {
12838d5d45fbSJean Delvare 		case 0x50:	/* TEMP */
128490f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 0);
12858d5d45fbSJean Delvare 			break;
12868d5d45fbSJean Delvare 		case 0x52:	/* CONFIG */
12878d5d45fbSJean Delvare 			res = i2c_smbus_read_byte_data(cl, 1);
12888d5d45fbSJean Delvare 			break;
12898d5d45fbSJean Delvare 		case 0x53:	/* HYST */
129090f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 2);
12918d5d45fbSJean Delvare 			break;
12928d5d45fbSJean Delvare 		case 0x55:	/* OVER */
12938d5d45fbSJean Delvare 		default:
129490f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 3);
12958d5d45fbSJean Delvare 			break;
12968d5d45fbSJean Delvare 		}
12978d5d45fbSJean Delvare 	}
12988d5d45fbSJean Delvare 	if (bank > 2)
12998d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1300443850ceSWolfgang Grandegger 
13018d5d45fbSJean Delvare 	return res;
13028d5d45fbSJean Delvare }
13038d5d45fbSJean Delvare 
13048d5d45fbSJean Delvare static int
1305443850ceSWolfgang Grandegger w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
13068d5d45fbSJean Delvare {
13070217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1308443850ceSWolfgang Grandegger 	int bank;
13098d5d45fbSJean Delvare 	struct i2c_client *cl;
13108d5d45fbSJean Delvare 
13118d5d45fbSJean Delvare 	bank = (reg >> 8) & 0x0f;
13128d5d45fbSJean Delvare 	if (bank > 2)
13138d5d45fbSJean Delvare 		/* switch banks */
13148d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
13158d5d45fbSJean Delvare 					  bank);
13168d5d45fbSJean Delvare 	if (bank == 0 || bank > 2) {
13178d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, reg & 0xff,
13188d5d45fbSJean Delvare 					  value & 0xff);
13198d5d45fbSJean Delvare 	} else {
13208d5d45fbSJean Delvare 		/* switch to subclient */
13218d5d45fbSJean Delvare 		cl = data->lm75[bank - 1];
13228d5d45fbSJean Delvare 		/* convert from ISA to LM75 I2C addresses */
13238d5d45fbSJean Delvare 		switch (reg & 0xff) {
13248d5d45fbSJean Delvare 		case 0x52:	/* CONFIG */
13258d5d45fbSJean Delvare 			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
13268d5d45fbSJean Delvare 			break;
13278d5d45fbSJean Delvare 		case 0x53:	/* HYST */
132890f4102cSJean Delvare 			i2c_smbus_write_word_swapped(cl, 2, value);
13298d5d45fbSJean Delvare 			break;
13308d5d45fbSJean Delvare 		case 0x55:	/* OVER */
133190f4102cSJean Delvare 			i2c_smbus_write_word_swapped(cl, 3, value);
13328d5d45fbSJean Delvare 			break;
13338d5d45fbSJean Delvare 		}
13348d5d45fbSJean Delvare 	}
13358d5d45fbSJean Delvare 	if (bank > 2)
13368d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1337443850ceSWolfgang Grandegger 
13388d5d45fbSJean Delvare 	return 0;
13398d5d45fbSJean Delvare }
13408d5d45fbSJean Delvare 
13418d5d45fbSJean Delvare static void
13427666c13cSJean Delvare w83781d_init_device(struct device *dev)
13438d5d45fbSJean Delvare {
13447666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
13458d5d45fbSJean Delvare 	int i, p;
13468d5d45fbSJean Delvare 	int type = data->type;
13478d5d45fbSJean Delvare 	u8 tmp;
13488d5d45fbSJean Delvare 
1349fabddcd4SJean Delvare 	if (reset && type != as99127f) { /* this resets registers we don't have
13508d5d45fbSJean Delvare 					   documentation for on the as99127f */
1351fabddcd4SJean Delvare 		/* Resetting the chip has been the default for a long time,
1352fabddcd4SJean Delvare 		   but it causes the BIOS initializations (fan clock dividers,
1353fabddcd4SJean Delvare 		   thermal sensor types...) to be lost, so it is now optional.
1354fabddcd4SJean Delvare 		   It might even go away if nobody reports it as being useful,
1355fabddcd4SJean Delvare 		   as I see very little reason why this would be needed at
1356fabddcd4SJean Delvare 		   all. */
13577666c13cSJean Delvare 		dev_info(dev, "If reset=1 solved a problem you were "
1358fabddcd4SJean Delvare 			 "having, please report!\n");
1359fabddcd4SJean Delvare 
13608d5d45fbSJean Delvare 		/* save these registers */
136131b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
136231b8dc4dSJean Delvare 		p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
13638d5d45fbSJean Delvare 		/* Reset all except Watchdog values and last conversion values
13648d5d45fbSJean Delvare 		   This sets fan-divs to 2, among others */
136531b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
13668d5d45fbSJean Delvare 		/* Restore the registers and disable power-on abnormal beep.
13678d5d45fbSJean Delvare 		   This saves FAN 1/2/3 input/output values set by BIOS. */
136831b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
136931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
1370*c531eb3fSGuenter Roeck 		/*
1371*c531eb3fSGuenter Roeck 		 * Disable master beep-enable (reset turns it on).
1372*c531eb3fSGuenter Roeck 		 * Individual beep_mask should be reset to off but for some
1373*c531eb3fSGuenter Roeck 		 * reason disabling this bit helps some people not get beeped
1374*c531eb3fSGuenter Roeck 		 */
137531b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
13768d5d45fbSJean Delvare 	}
13778d5d45fbSJean Delvare 
1378fabddcd4SJean Delvare 	/* Disable power-on abnormal beep, as advised by the datasheet.
1379fabddcd4SJean Delvare 	   Already done if reset=1. */
1380fabddcd4SJean Delvare 	if (init && !reset && type != as99127f) {
138131b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
138231b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1383fabddcd4SJean Delvare 	}
1384fabddcd4SJean Delvare 
1385303760b4SJean Delvare 	data->vrm = vid_which_vrm();
13868d5d45fbSJean Delvare 
13878d5d45fbSJean Delvare 	if ((type != w83781d) && (type != as99127f)) {
138831b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
13898d5d45fbSJean Delvare 		for (i = 1; i <= 3; i++) {
13908d5d45fbSJean Delvare 			if (!(tmp & BIT_SCFG1[i - 1])) {
1391b26f9330SJean Delvare 				data->sens[i - 1] = 4;
13928d5d45fbSJean Delvare 			} else {
13938d5d45fbSJean Delvare 				if (w83781d_read_value
139431b8dc4dSJean Delvare 				    (data,
13958d5d45fbSJean Delvare 				     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
13968d5d45fbSJean Delvare 					data->sens[i - 1] = 1;
13978d5d45fbSJean Delvare 				else
13988d5d45fbSJean Delvare 					data->sens[i - 1] = 2;
13998d5d45fbSJean Delvare 			}
14008d5d45fbSJean Delvare 			if (type == w83783s && i == 2)
14018d5d45fbSJean Delvare 				break;
14028d5d45fbSJean Delvare 		}
14038d5d45fbSJean Delvare 	}
14048d5d45fbSJean Delvare 
14058d5d45fbSJean Delvare 	if (init && type != as99127f) {
14068d5d45fbSJean Delvare 		/* Enable temp2 */
140731b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
14088d5d45fbSJean Delvare 		if (tmp & 0x01) {
14097666c13cSJean Delvare 			dev_warn(dev, "Enabling temp2, readings "
14108d5d45fbSJean Delvare 				 "might not make sense\n");
141131b8dc4dSJean Delvare 			w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
14128d5d45fbSJean Delvare 				tmp & 0xfe);
14138d5d45fbSJean Delvare 		}
14148d5d45fbSJean Delvare 
14158d5d45fbSJean Delvare 		/* Enable temp3 */
14168d5d45fbSJean Delvare 		if (type != w83783s) {
141731b8dc4dSJean Delvare 			tmp = w83781d_read_value(data,
14188d5d45fbSJean Delvare 				W83781D_REG_TEMP3_CONFIG);
14198d5d45fbSJean Delvare 			if (tmp & 0x01) {
14207666c13cSJean Delvare 				dev_warn(dev, "Enabling temp3, "
14218d5d45fbSJean Delvare 					 "readings might not make sense\n");
142231b8dc4dSJean Delvare 				w83781d_write_value(data,
14238d5d45fbSJean Delvare 					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
14248d5d45fbSJean Delvare 			}
14258d5d45fbSJean Delvare 		}
14268d5d45fbSJean Delvare 	}
14278d5d45fbSJean Delvare 
14288d5d45fbSJean Delvare 	/* Start monitoring */
142931b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_CONFIG,
143031b8dc4dSJean Delvare 			    (w83781d_read_value(data,
14318d5d45fbSJean Delvare 						W83781D_REG_CONFIG) & 0xf7)
14328d5d45fbSJean Delvare 			    | 0x01);
14337666c13cSJean Delvare 
14347666c13cSJean Delvare 	/* A few vars need to be filled upon startup */
143534875337SJean Delvare 	for (i = 0; i < 3; i++) {
143634875337SJean Delvare 		data->fan_min[i] = w83781d_read_value(data,
14377666c13cSJean Delvare 					W83781D_REG_FAN_MIN(i));
14387666c13cSJean Delvare 	}
14397666c13cSJean Delvare 
14407666c13cSJean Delvare 	mutex_init(&data->update_lock);
14418d5d45fbSJean Delvare }
14428d5d45fbSJean Delvare 
14438d5d45fbSJean Delvare static struct w83781d_data *w83781d_update_device(struct device *dev)
14448d5d45fbSJean Delvare {
14457666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
14460217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
14478d5d45fbSJean Delvare 	int i;
14488d5d45fbSJean Delvare 
14499a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
14508d5d45fbSJean Delvare 
14518d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
14528d5d45fbSJean Delvare 	    || !data->valid) {
14538d5d45fbSJean Delvare 		dev_dbg(dev, "Starting device update\n");
14548d5d45fbSJean Delvare 
14558d5d45fbSJean Delvare 		for (i = 0; i <= 8; i++) {
14568d5d45fbSJean Delvare 			if (data->type == w83783s && i == 1)
14578d5d45fbSJean Delvare 				continue;	/* 783S has no in1 */
14588d5d45fbSJean Delvare 			data->in[i] =
145931b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN(i));
14608d5d45fbSJean Delvare 			data->in_min[i] =
146131b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN_MIN(i));
14628d5d45fbSJean Delvare 			data->in_max[i] =
146331b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN_MAX(i));
146405663368SJean Delvare 			if ((data->type != w83782d) && (i == 6))
14658d5d45fbSJean Delvare 				break;
14668d5d45fbSJean Delvare 		}
146734875337SJean Delvare 		for (i = 0; i < 3; i++) {
146834875337SJean Delvare 			data->fan[i] =
146931b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_FAN(i));
147034875337SJean Delvare 			data->fan_min[i] =
147131b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
14728d5d45fbSJean Delvare 		}
14738d5d45fbSJean Delvare 		if (data->type != w83781d && data->type != as99127f) {
147434875337SJean Delvare 			for (i = 0; i < 4; i++) {
147534875337SJean Delvare 				data->pwm[i] =
147631b8dc4dSJean Delvare 				    w83781d_read_value(data,
147734875337SJean Delvare 						       W83781D_REG_PWM[i]);
1478848ddf11SJean Delvare 				/* Only W83782D on SMBus has PWM3 and PWM4 */
1479848ddf11SJean Delvare 				if ((data->type != w83782d || !client)
148034875337SJean Delvare 				    && i == 1)
14818d5d45fbSJean Delvare 					break;
14828d5d45fbSJean Delvare 			}
14838d5d45fbSJean Delvare 			/* Only PWM2 can be disabled */
148434875337SJean Delvare 			data->pwm2_enable = (w83781d_read_value(data,
14858d5d45fbSJean Delvare 					     W83781D_REG_PWMCLK12) & 0x08) >> 3;
14868d5d45fbSJean Delvare 		}
14878d5d45fbSJean Delvare 
148831b8dc4dSJean Delvare 		data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
14898d5d45fbSJean Delvare 		data->temp_max =
149031b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
14918d5d45fbSJean Delvare 		data->temp_max_hyst =
149231b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
14938d5d45fbSJean Delvare 		data->temp_add[0] =
149431b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP(2));
14958d5d45fbSJean Delvare 		data->temp_max_add[0] =
149631b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
14978d5d45fbSJean Delvare 		data->temp_max_hyst_add[0] =
149831b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
14998d5d45fbSJean Delvare 		if (data->type != w83783s) {
15008d5d45fbSJean Delvare 			data->temp_add[1] =
150131b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_TEMP(3));
15028d5d45fbSJean Delvare 			data->temp_max_add[1] =
150331b8dc4dSJean Delvare 			    w83781d_read_value(data,
15048d5d45fbSJean Delvare 					       W83781D_REG_TEMP_OVER(3));
15058d5d45fbSJean Delvare 			data->temp_max_hyst_add[1] =
150631b8dc4dSJean Delvare 			    w83781d_read_value(data,
15078d5d45fbSJean Delvare 					       W83781D_REG_TEMP_HYST(3));
15088d5d45fbSJean Delvare 		}
150931b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
15108d5d45fbSJean Delvare 		data->vid = i & 0x0f;
151131b8dc4dSJean Delvare 		data->vid |= (w83781d_read_value(data,
15128d5d45fbSJean Delvare 					W83781D_REG_CHIPID) & 0x01) << 4;
15138d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 0x03;
15148d5d45fbSJean Delvare 		data->fan_div[1] = (i >> 6) & 0x03;
151531b8dc4dSJean Delvare 		data->fan_div[2] = (w83781d_read_value(data,
15168d5d45fbSJean Delvare 					W83781D_REG_PIN) >> 6) & 0x03;
15178d5d45fbSJean Delvare 		if ((data->type != w83781d) && (data->type != as99127f)) {
151831b8dc4dSJean Delvare 			i = w83781d_read_value(data, W83781D_REG_VBAT);
15198d5d45fbSJean Delvare 			data->fan_div[0] |= (i >> 3) & 0x04;
15208d5d45fbSJean Delvare 			data->fan_div[1] |= (i >> 4) & 0x04;
15218d5d45fbSJean Delvare 			data->fan_div[2] |= (i >> 5) & 0x04;
15228d5d45fbSJean Delvare 		}
152305663368SJean Delvare 		if (data->type == w83782d) {
152431b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1525c7f5d7edSJean Delvare 						W83782D_REG_ALARM1)
152631b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1527c7f5d7edSJean Delvare 						W83782D_REG_ALARM2) << 8)
152831b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1529c7f5d7edSJean Delvare 						W83782D_REG_ALARM3) << 16);
1530c7f5d7edSJean Delvare 		} else if (data->type == w83783s) {
153131b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1532c7f5d7edSJean Delvare 						W83782D_REG_ALARM1)
153331b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1534c7f5d7edSJean Delvare 						W83782D_REG_ALARM2) << 8);
1535c7f5d7edSJean Delvare 		} else {
1536c7f5d7edSJean Delvare 			/* No real-time status registers, fall back to
1537c7f5d7edSJean Delvare 			   interrupt status registers */
153831b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1539c7f5d7edSJean Delvare 						W83781D_REG_ALARM1)
154031b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1541c7f5d7edSJean Delvare 						W83781D_REG_ALARM2) << 8);
15428d5d45fbSJean Delvare 		}
154331b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
15442fbbbf14SJean Delvare 		data->beep_mask = (i << 8) +
154531b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
15468d5d45fbSJean Delvare 		if ((data->type != w83781d) && (data->type != as99127f)) {
15478d5d45fbSJean Delvare 			data->beep_mask |=
154831b8dc4dSJean Delvare 			    w83781d_read_value(data,
15498d5d45fbSJean Delvare 					       W83781D_REG_BEEP_INTS3) << 16;
15508d5d45fbSJean Delvare 		}
15518d5d45fbSJean Delvare 		data->last_updated = jiffies;
15528d5d45fbSJean Delvare 		data->valid = 1;
15538d5d45fbSJean Delvare 	}
15548d5d45fbSJean Delvare 
15559a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
15568d5d45fbSJean Delvare 
15578d5d45fbSJean Delvare 	return data;
15588d5d45fbSJean Delvare }
15598d5d45fbSJean Delvare 
15600217eae3SWolfgang Grandegger static const struct i2c_device_id w83781d_ids[] = {
15610217eae3SWolfgang Grandegger 	{ "w83781d", w83781d, },
15620217eae3SWolfgang Grandegger 	{ "w83782d", w83782d, },
15630217eae3SWolfgang Grandegger 	{ "w83783s", w83783s, },
15640217eae3SWolfgang Grandegger 	{ "as99127f", as99127f },
15650217eae3SWolfgang Grandegger 	{ /* LIST END */ }
15660217eae3SWolfgang Grandegger };
15670217eae3SWolfgang Grandegger MODULE_DEVICE_TABLE(i2c, w83781d_ids);
15680217eae3SWolfgang Grandegger 
15690217eae3SWolfgang Grandegger static struct i2c_driver w83781d_driver = {
15700217eae3SWolfgang Grandegger 	.class		= I2C_CLASS_HWMON,
15710217eae3SWolfgang Grandegger 	.driver = {
15720217eae3SWolfgang Grandegger 		.name = "w83781d",
15730217eae3SWolfgang Grandegger 	},
15740217eae3SWolfgang Grandegger 	.probe		= w83781d_probe,
15750217eae3SWolfgang Grandegger 	.remove		= w83781d_remove,
15760217eae3SWolfgang Grandegger 	.id_table	= w83781d_ids,
15770217eae3SWolfgang Grandegger 	.detect		= w83781d_detect,
1578c3813d6aSJean Delvare 	.address_list	= normal_i2c,
15790217eae3SWolfgang Grandegger };
15800217eae3SWolfgang Grandegger 
15810217eae3SWolfgang Grandegger /*
15820217eae3SWolfgang Grandegger  * ISA related code
15830217eae3SWolfgang Grandegger  */
1584443850ceSWolfgang Grandegger #ifdef CONFIG_ISA
1585443850ceSWolfgang Grandegger 
1586443850ceSWolfgang Grandegger /* ISA device, if found */
1587443850ceSWolfgang Grandegger static struct platform_device *pdev;
1588443850ceSWolfgang Grandegger 
1589443850ceSWolfgang Grandegger static unsigned short isa_address = 0x290;
1590443850ceSWolfgang Grandegger 
1591443850ceSWolfgang Grandegger /* I2C devices get this name attribute automatically, but for ISA devices
1592443850ceSWolfgang Grandegger    we must create it by ourselves. */
1593443850ceSWolfgang Grandegger static ssize_t
1594443850ceSWolfgang Grandegger show_name(struct device *dev, struct device_attribute *devattr, char *buf)
1595443850ceSWolfgang Grandegger {
1596443850ceSWolfgang Grandegger 	struct w83781d_data *data = dev_get_drvdata(dev);
1597360782ddSJean Delvare 	return sprintf(buf, "%s\n", data->name);
1598443850ceSWolfgang Grandegger }
1599443850ceSWolfgang Grandegger static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
1600443850ceSWolfgang Grandegger 
1601443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void)
1602443850ceSWolfgang Grandegger {
1603443850ceSWolfgang Grandegger 	return pdev ? platform_get_drvdata(pdev) : NULL;
1604443850ceSWolfgang Grandegger }
1605443850ceSWolfgang Grandegger 
1606443850ceSWolfgang Grandegger /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
1607443850ceSWolfgang Grandegger static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1608443850ceSWolfgang Grandegger {
16090217eae3SWolfgang Grandegger 	struct w83781d_data *isa;
1610443850ceSWolfgang Grandegger 	int i;
1611443850ceSWolfgang Grandegger 
1612443850ceSWolfgang Grandegger 	if (!pdev)	/* No ISA chip */
1613443850ceSWolfgang Grandegger 		return 0;
1614443850ceSWolfgang Grandegger 
1615443850ceSWolfgang Grandegger 	isa = platform_get_drvdata(pdev);
1616443850ceSWolfgang Grandegger 
1617443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1618443850ceSWolfgang Grandegger 		return 0;	/* Address doesn't match */
1619443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1620443850ceSWolfgang Grandegger 		return 0;	/* Chip type doesn't match */
1621443850ceSWolfgang Grandegger 
1622443850ceSWolfgang Grandegger 	/* We compare all the limit registers, the config register and the
1623443850ceSWolfgang Grandegger 	 * interrupt mask registers */
1624443850ceSWolfgang Grandegger 	for (i = 0x2b; i <= 0x3d; i++) {
16250217eae3SWolfgang Grandegger 		if (w83781d_read_value(isa, i) !=
16260217eae3SWolfgang Grandegger 		    i2c_smbus_read_byte_data(client, i))
1627443850ceSWolfgang Grandegger 			return 0;
1628443850ceSWolfgang Grandegger 	}
1629443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
16300217eae3SWolfgang Grandegger 	    i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
1631443850ceSWolfgang Grandegger 		return 0;
1632443850ceSWolfgang Grandegger 	for (i = 0x43; i <= 0x46; i++) {
16330217eae3SWolfgang Grandegger 		if (w83781d_read_value(isa, i) !=
16340217eae3SWolfgang Grandegger 		    i2c_smbus_read_byte_data(client, i))
1635443850ceSWolfgang Grandegger 			return 0;
1636443850ceSWolfgang Grandegger 	}
1637443850ceSWolfgang Grandegger 
1638443850ceSWolfgang Grandegger 	return 1;
1639443850ceSWolfgang Grandegger }
1640443850ceSWolfgang Grandegger 
1641443850ceSWolfgang Grandegger static int
1642443850ceSWolfgang Grandegger w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1643443850ceSWolfgang Grandegger {
1644443850ceSWolfgang Grandegger 	int word_sized, res;
1645443850ceSWolfgang Grandegger 
1646443850ceSWolfgang Grandegger 	word_sized = (((reg & 0xff00) == 0x100)
1647443850ceSWolfgang Grandegger 		      || ((reg & 0xff00) == 0x200))
1648443850ceSWolfgang Grandegger 	    && (((reg & 0x00ff) == 0x50)
1649443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x53)
1650443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x55));
1651443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1652443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1653360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1654443850ceSWolfgang Grandegger 		outb_p(reg >> 8,
1655360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1656443850ceSWolfgang Grandegger 	}
1657360782ddSJean Delvare 	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1658360782ddSJean Delvare 	res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
1659443850ceSWolfgang Grandegger 	if (word_sized) {
1660443850ceSWolfgang Grandegger 		outb_p((reg & 0xff) + 1,
1661360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1662443850ceSWolfgang Grandegger 		res =
1663360782ddSJean Delvare 		    (res << 8) + inb_p(data->isa_addr +
1664443850ceSWolfgang Grandegger 				       W83781D_DATA_REG_OFFSET);
1665443850ceSWolfgang Grandegger 	}
1666443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1667443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1668360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1669360782ddSJean Delvare 		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
1670443850ceSWolfgang Grandegger 	}
1671443850ceSWolfgang Grandegger 	return res;
1672443850ceSWolfgang Grandegger }
1673443850ceSWolfgang Grandegger 
1674443850ceSWolfgang Grandegger static void
1675443850ceSWolfgang Grandegger w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1676443850ceSWolfgang Grandegger {
1677443850ceSWolfgang Grandegger 	int word_sized;
1678443850ceSWolfgang Grandegger 
1679443850ceSWolfgang Grandegger 	word_sized = (((reg & 0xff00) == 0x100)
1680443850ceSWolfgang Grandegger 		      || ((reg & 0xff00) == 0x200))
1681443850ceSWolfgang Grandegger 	    && (((reg & 0x00ff) == 0x53)
1682443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x55));
1683443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1684443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1685360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1686443850ceSWolfgang Grandegger 		outb_p(reg >> 8,
1687360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1688443850ceSWolfgang Grandegger 	}
1689360782ddSJean Delvare 	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1690443850ceSWolfgang Grandegger 	if (word_sized) {
1691443850ceSWolfgang Grandegger 		outb_p(value >> 8,
1692360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1693443850ceSWolfgang Grandegger 		outb_p((reg & 0xff) + 1,
1694360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1695443850ceSWolfgang Grandegger 	}
1696360782ddSJean Delvare 	outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
1697443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1698443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1699360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1700360782ddSJean Delvare 		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
1701443850ceSWolfgang Grandegger 	}
1702443850ceSWolfgang Grandegger }
1703443850ceSWolfgang Grandegger 
1704443850ceSWolfgang Grandegger /* The SMBus locks itself, usually, but nothing may access the Winbond between
1705443850ceSWolfgang Grandegger    bank switches. ISA access must always be locked explicitly!
1706443850ceSWolfgang Grandegger    We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1707443850ceSWolfgang Grandegger    would slow down the W83781D access and should not be necessary.
1708443850ceSWolfgang Grandegger    There are some ugly typecasts here, but the good news is - they should
1709443850ceSWolfgang Grandegger    nowhere else be necessary! */
1710443850ceSWolfgang Grandegger static int
1711443850ceSWolfgang Grandegger w83781d_read_value(struct w83781d_data *data, u16 reg)
1712443850ceSWolfgang Grandegger {
17130217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1714443850ceSWolfgang Grandegger 	int res;
1715443850ceSWolfgang Grandegger 
1716443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
17170217eae3SWolfgang Grandegger 	if (client)
1718443850ceSWolfgang Grandegger 		res = w83781d_read_value_i2c(data, reg);
1719443850ceSWolfgang Grandegger 	else
1720443850ceSWolfgang Grandegger 		res = w83781d_read_value_isa(data, reg);
1721443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
1722443850ceSWolfgang Grandegger 	return res;
1723443850ceSWolfgang Grandegger }
1724443850ceSWolfgang Grandegger 
1725443850ceSWolfgang Grandegger static int
1726443850ceSWolfgang Grandegger w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1727443850ceSWolfgang Grandegger {
17280217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1729443850ceSWolfgang Grandegger 
1730443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
17310217eae3SWolfgang Grandegger 	if (client)
1732443850ceSWolfgang Grandegger 		w83781d_write_value_i2c(data, reg, value);
1733443850ceSWolfgang Grandegger 	else
1734443850ceSWolfgang Grandegger 		w83781d_write_value_isa(data, reg, value);
1735443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
1736443850ceSWolfgang Grandegger 	return 0;
1737443850ceSWolfgang Grandegger }
1738443850ceSWolfgang Grandegger 
1739443850ceSWolfgang Grandegger static int __devinit
1740443850ceSWolfgang Grandegger w83781d_isa_probe(struct platform_device *pdev)
1741443850ceSWolfgang Grandegger {
1742443850ceSWolfgang Grandegger 	int err, reg;
1743443850ceSWolfgang Grandegger 	struct w83781d_data *data;
1744443850ceSWolfgang Grandegger 	struct resource *res;
1745443850ceSWolfgang Grandegger 
1746443850ceSWolfgang Grandegger 	/* Reserve the ISA region */
1747443850ceSWolfgang Grandegger 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1748443850ceSWolfgang Grandegger 	if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
1749443850ceSWolfgang Grandegger 			    "w83781d")) {
1750443850ceSWolfgang Grandegger 		err = -EBUSY;
1751443850ceSWolfgang Grandegger 		goto exit;
1752443850ceSWolfgang Grandegger 	}
1753443850ceSWolfgang Grandegger 
1754443850ceSWolfgang Grandegger 	data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
1755443850ceSWolfgang Grandegger 	if (!data) {
1756443850ceSWolfgang Grandegger 		err = -ENOMEM;
1757443850ceSWolfgang Grandegger 		goto exit_release_region;
1758443850ceSWolfgang Grandegger 	}
1759443850ceSWolfgang Grandegger 	mutex_init(&data->lock);
1760360782ddSJean Delvare 	data->isa_addr = res->start;
1761443850ceSWolfgang Grandegger 	platform_set_drvdata(pdev, data);
1762443850ceSWolfgang Grandegger 
1763443850ceSWolfgang Grandegger 	reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1764443850ceSWolfgang Grandegger 	switch (reg) {
1765443850ceSWolfgang Grandegger 	case 0x30:
1766443850ceSWolfgang Grandegger 		data->type = w83782d;
1767360782ddSJean Delvare 		data->name = "w83782d";
1768443850ceSWolfgang Grandegger 		break;
1769443850ceSWolfgang Grandegger 	default:
1770443850ceSWolfgang Grandegger 		data->type = w83781d;
1771360782ddSJean Delvare 		data->name = "w83781d";
1772443850ceSWolfgang Grandegger 	}
1773443850ceSWolfgang Grandegger 
1774443850ceSWolfgang Grandegger 	/* Initialize the W83781D chip */
1775443850ceSWolfgang Grandegger 	w83781d_init_device(&pdev->dev);
1776443850ceSWolfgang Grandegger 
1777443850ceSWolfgang Grandegger 	/* Register sysfs hooks */
1778443850ceSWolfgang Grandegger 	err = w83781d_create_files(&pdev->dev, data->type, 1);
1779443850ceSWolfgang Grandegger 	if (err)
1780443850ceSWolfgang Grandegger 		goto exit_remove_files;
1781443850ceSWolfgang Grandegger 
1782443850ceSWolfgang Grandegger 	err = device_create_file(&pdev->dev, &dev_attr_name);
1783443850ceSWolfgang Grandegger 	if (err)
1784443850ceSWolfgang Grandegger 		goto exit_remove_files;
1785443850ceSWolfgang Grandegger 
1786443850ceSWolfgang Grandegger 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
1787443850ceSWolfgang Grandegger 	if (IS_ERR(data->hwmon_dev)) {
1788443850ceSWolfgang Grandegger 		err = PTR_ERR(data->hwmon_dev);
1789443850ceSWolfgang Grandegger 		goto exit_remove_files;
1790443850ceSWolfgang Grandegger 	}
1791443850ceSWolfgang Grandegger 
1792443850ceSWolfgang Grandegger 	return 0;
1793443850ceSWolfgang Grandegger 
1794443850ceSWolfgang Grandegger  exit_remove_files:
1795443850ceSWolfgang Grandegger 	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1796443850ceSWolfgang Grandegger 	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1797443850ceSWolfgang Grandegger 	device_remove_file(&pdev->dev, &dev_attr_name);
1798443850ceSWolfgang Grandegger 	kfree(data);
1799443850ceSWolfgang Grandegger  exit_release_region:
1800443850ceSWolfgang Grandegger 	release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
1801443850ceSWolfgang Grandegger  exit:
1802443850ceSWolfgang Grandegger 	return err;
1803443850ceSWolfgang Grandegger }
1804443850ceSWolfgang Grandegger 
1805443850ceSWolfgang Grandegger static int __devexit
1806443850ceSWolfgang Grandegger w83781d_isa_remove(struct platform_device *pdev)
1807443850ceSWolfgang Grandegger {
1808443850ceSWolfgang Grandegger 	struct w83781d_data *data = platform_get_drvdata(pdev);
1809443850ceSWolfgang Grandegger 
1810443850ceSWolfgang Grandegger 	hwmon_device_unregister(data->hwmon_dev);
1811443850ceSWolfgang Grandegger 	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
1812443850ceSWolfgang Grandegger 	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
1813443850ceSWolfgang Grandegger 	device_remove_file(&pdev->dev, &dev_attr_name);
1814360782ddSJean Delvare 	release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2);
1815443850ceSWolfgang Grandegger 	kfree(data);
1816443850ceSWolfgang Grandegger 
1817443850ceSWolfgang Grandegger 	return 0;
1818443850ceSWolfgang Grandegger }
1819443850ceSWolfgang Grandegger 
1820443850ceSWolfgang Grandegger static struct platform_driver w83781d_isa_driver = {
1821443850ceSWolfgang Grandegger 	.driver = {
1822443850ceSWolfgang Grandegger 		.owner = THIS_MODULE,
1823443850ceSWolfgang Grandegger 		.name = "w83781d",
1824443850ceSWolfgang Grandegger 	},
1825443850ceSWolfgang Grandegger 	.probe = w83781d_isa_probe,
1826443850ceSWolfgang Grandegger 	.remove = __devexit_p(w83781d_isa_remove),
1827443850ceSWolfgang Grandegger };
1828443850ceSWolfgang Grandegger 
18297666c13cSJean Delvare /* return 1 if a supported chip is found, 0 otherwise */
18307666c13cSJean Delvare static int __init
18317666c13cSJean Delvare w83781d_isa_found(unsigned short address)
18327666c13cSJean Delvare {
18337666c13cSJean Delvare 	int val, save, found = 0;
1834b0bcdd3cSJean Delvare 	int port;
18357666c13cSJean Delvare 
1836b0bcdd3cSJean Delvare 	/* Some boards declare base+0 to base+7 as a PNP device, some base+4
1837b0bcdd3cSJean Delvare 	 * to base+7 and some base+5 to base+6. So we better request each port
1838b0bcdd3cSJean Delvare 	 * individually for the probing phase. */
1839b0bcdd3cSJean Delvare 	for (port = address; port < address + W83781D_EXTENT; port++) {
1840b0bcdd3cSJean Delvare 		if (!request_region(port, 1, "w83781d")) {
18411ca28218SJoe Perches 			pr_debug("Failed to request port 0x%x\n", port);
1842b0bcdd3cSJean Delvare 			goto release;
18432961cb22SJean Delvare 		}
18442961cb22SJean Delvare 	}
18457666c13cSJean Delvare 
18467666c13cSJean Delvare #define REALLY_SLOW_IO
18477666c13cSJean Delvare 	/* We need the timeouts for at least some W83781D-like
18487666c13cSJean Delvare 	   chips. But only if we read 'undefined' registers. */
18497666c13cSJean Delvare 	val = inb_p(address + 1);
18507666c13cSJean Delvare 	if (inb_p(address + 2) != val
18517666c13cSJean Delvare 	 || inb_p(address + 3) != val
18527666c13cSJean Delvare 	 || inb_p(address + 7) != val) {
18531ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 1);
18547666c13cSJean Delvare 		goto release;
18557666c13cSJean Delvare 	}
18567666c13cSJean Delvare #undef REALLY_SLOW_IO
18577666c13cSJean Delvare 
18587666c13cSJean Delvare 	/* We should be able to change the 7 LSB of the address port. The
18597666c13cSJean Delvare 	   MSB (busy flag) should be clear initially, set after the write. */
18607666c13cSJean Delvare 	save = inb_p(address + W83781D_ADDR_REG_OFFSET);
18617666c13cSJean Delvare 	if (save & 0x80) {
18621ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 2);
18637666c13cSJean Delvare 		goto release;
18647666c13cSJean Delvare 	}
18657666c13cSJean Delvare 	val = ~save & 0x7f;
18667666c13cSJean Delvare 	outb_p(val, address + W83781D_ADDR_REG_OFFSET);
18677666c13cSJean Delvare 	if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
18687666c13cSJean Delvare 		outb_p(save, address + W83781D_ADDR_REG_OFFSET);
18691ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 3);
18707666c13cSJean Delvare 		goto release;
18717666c13cSJean Delvare 	}
18727666c13cSJean Delvare 
18737666c13cSJean Delvare 	/* We found a device, now see if it could be a W83781D */
18747666c13cSJean Delvare 	outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
18757666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
18767666c13cSJean Delvare 	if (val & 0x80) {
18771ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 4);
18787666c13cSJean Delvare 		goto release;
18797666c13cSJean Delvare 	}
18807666c13cSJean Delvare 	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
18817666c13cSJean Delvare 	save = inb_p(address + W83781D_DATA_REG_OFFSET);
18827666c13cSJean Delvare 	outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
18837666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
18847666c13cSJean Delvare 	if ((!(save & 0x80) && (val != 0xa3))
18857666c13cSJean Delvare 	 || ((save & 0x80) && (val != 0x5c))) {
18861ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 5);
18877666c13cSJean Delvare 		goto release;
18887666c13cSJean Delvare 	}
18897666c13cSJean Delvare 	outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
18907666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
18917666c13cSJean Delvare 	if (val < 0x03 || val > 0x77) {	/* Not a valid I2C address */
18921ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 6);
18937666c13cSJean Delvare 		goto release;
18947666c13cSJean Delvare 	}
18957666c13cSJean Delvare 
18967666c13cSJean Delvare 	/* The busy flag should be clear again */
18977666c13cSJean Delvare 	if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
18981ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 7);
18997666c13cSJean Delvare 		goto release;
19007666c13cSJean Delvare 	}
19017666c13cSJean Delvare 
19027666c13cSJean Delvare 	/* Determine the chip type */
19037666c13cSJean Delvare 	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
19047666c13cSJean Delvare 	save = inb_p(address + W83781D_DATA_REG_OFFSET);
19057666c13cSJean Delvare 	outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
19067666c13cSJean Delvare 	outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
19077666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
19087666c13cSJean Delvare 	if ((val & 0xfe) == 0x10	/* W83781D */
190905663368SJean Delvare 	 || val == 0x30)		/* W83782D */
19107666c13cSJean Delvare 		found = 1;
19117666c13cSJean Delvare 
19127666c13cSJean Delvare 	if (found)
19131ca28218SJoe Perches 		pr_info("Found a %s chip at %#x\n",
19147666c13cSJean Delvare 			val == 0x30 ? "W83782D" : "W83781D", (int)address);
19157666c13cSJean Delvare 
19167666c13cSJean Delvare  release:
1917b0bcdd3cSJean Delvare 	for (port--; port >= address; port--)
1918b0bcdd3cSJean Delvare 		release_region(port, 1);
19197666c13cSJean Delvare 	return found;
19207666c13cSJean Delvare }
19217666c13cSJean Delvare 
19227666c13cSJean Delvare static int __init
19237666c13cSJean Delvare w83781d_isa_device_add(unsigned short address)
19247666c13cSJean Delvare {
19257666c13cSJean Delvare 	struct resource res = {
19267666c13cSJean Delvare 		.start	= address,
192715bde2f1SJean Delvare 		.end	= address + W83781D_EXTENT - 1,
19287666c13cSJean Delvare 		.name	= "w83781d",
19297666c13cSJean Delvare 		.flags	= IORESOURCE_IO,
19307666c13cSJean Delvare 	};
19317666c13cSJean Delvare 	int err;
19327666c13cSJean Delvare 
19337666c13cSJean Delvare 	pdev = platform_device_alloc("w83781d", address);
19347666c13cSJean Delvare 	if (!pdev) {
19357666c13cSJean Delvare 		err = -ENOMEM;
19361ca28218SJoe Perches 		pr_err("Device allocation failed\n");
19377666c13cSJean Delvare 		goto exit;
19387666c13cSJean Delvare 	}
19397666c13cSJean Delvare 
19407666c13cSJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
19417666c13cSJean Delvare 	if (err) {
19421ca28218SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
19437666c13cSJean Delvare 		goto exit_device_put;
19447666c13cSJean Delvare 	}
19457666c13cSJean Delvare 
19467666c13cSJean Delvare 	err = platform_device_add(pdev);
19477666c13cSJean Delvare 	if (err) {
19481ca28218SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
19497666c13cSJean Delvare 		goto exit_device_put;
19507666c13cSJean Delvare 	}
19517666c13cSJean Delvare 
19527666c13cSJean Delvare 	return 0;
19537666c13cSJean Delvare 
19547666c13cSJean Delvare  exit_device_put:
19557666c13cSJean Delvare 	platform_device_put(pdev);
19567666c13cSJean Delvare  exit:
19577666c13cSJean Delvare 	pdev = NULL;
19587666c13cSJean Delvare 	return err;
19597666c13cSJean Delvare }
19607666c13cSJean Delvare 
19618d5d45fbSJean Delvare static int __init
1962443850ceSWolfgang Grandegger w83781d_isa_register(void)
19638d5d45fbSJean Delvare {
1964fde09509SJean Delvare 	int res;
1965fde09509SJean Delvare 
19667666c13cSJean Delvare 	if (w83781d_isa_found(isa_address)) {
19677666c13cSJean Delvare 		res = platform_driver_register(&w83781d_isa_driver);
19687666c13cSJean Delvare 		if (res)
1969c6566206SJean Delvare 			goto exit;
19707666c13cSJean Delvare 
19717666c13cSJean Delvare 		/* Sets global pdev as a side effect */
19727666c13cSJean Delvare 		res = w83781d_isa_device_add(isa_address);
19737666c13cSJean Delvare 		if (res)
19747666c13cSJean Delvare 			goto exit_unreg_isa_driver;
19757666c13cSJean Delvare 	}
1976fde09509SJean Delvare 
1977fde09509SJean Delvare 	return 0;
19787666c13cSJean Delvare 
19797666c13cSJean Delvare exit_unreg_isa_driver:
19807666c13cSJean Delvare 	platform_driver_unregister(&w83781d_isa_driver);
19817666c13cSJean Delvare exit:
19827666c13cSJean Delvare 	return res;
19838d5d45fbSJean Delvare }
19848d5d45fbSJean Delvare 
1985dd56b638SGeert Uytterhoeven static void
1986443850ceSWolfgang Grandegger w83781d_isa_unregister(void)
19878d5d45fbSJean Delvare {
19887666c13cSJean Delvare 	if (pdev) {
19897666c13cSJean Delvare 		platform_device_unregister(pdev);
19907666c13cSJean Delvare 		platform_driver_unregister(&w83781d_isa_driver);
19917666c13cSJean Delvare 	}
1992443850ceSWolfgang Grandegger }
1993443850ceSWolfgang Grandegger #else /* !CONFIG_ISA */
1994443850ceSWolfgang Grandegger 
1995443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void)
1996443850ceSWolfgang Grandegger {
1997443850ceSWolfgang Grandegger 	return NULL;
1998443850ceSWolfgang Grandegger }
1999443850ceSWolfgang Grandegger 
2000443850ceSWolfgang Grandegger static int
2001443850ceSWolfgang Grandegger w83781d_alias_detect(struct i2c_client *client, u8 chipid)
2002443850ceSWolfgang Grandegger {
2003443850ceSWolfgang Grandegger 	return 0;
2004443850ceSWolfgang Grandegger }
2005443850ceSWolfgang Grandegger 
2006443850ceSWolfgang Grandegger static int
2007443850ceSWolfgang Grandegger w83781d_read_value(struct w83781d_data *data, u16 reg)
2008443850ceSWolfgang Grandegger {
2009443850ceSWolfgang Grandegger 	int res;
2010443850ceSWolfgang Grandegger 
2011443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
2012443850ceSWolfgang Grandegger 	res = w83781d_read_value_i2c(data, reg);
2013443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
2014443850ceSWolfgang Grandegger 
2015443850ceSWolfgang Grandegger 	return res;
2016443850ceSWolfgang Grandegger }
2017443850ceSWolfgang Grandegger 
2018443850ceSWolfgang Grandegger static int
2019443850ceSWolfgang Grandegger w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2020443850ceSWolfgang Grandegger {
2021443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
2022443850ceSWolfgang Grandegger 	w83781d_write_value_i2c(data, reg, value);
2023443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
2024443850ceSWolfgang Grandegger 
2025443850ceSWolfgang Grandegger 	return 0;
2026443850ceSWolfgang Grandegger }
2027443850ceSWolfgang Grandegger 
2028443850ceSWolfgang Grandegger static int __init
2029443850ceSWolfgang Grandegger w83781d_isa_register(void)
2030443850ceSWolfgang Grandegger {
2031443850ceSWolfgang Grandegger 	return 0;
2032443850ceSWolfgang Grandegger }
2033443850ceSWolfgang Grandegger 
2034dd56b638SGeert Uytterhoeven static void
2035443850ceSWolfgang Grandegger w83781d_isa_unregister(void)
2036443850ceSWolfgang Grandegger {
2037443850ceSWolfgang Grandegger }
2038443850ceSWolfgang Grandegger #endif /* CONFIG_ISA */
2039443850ceSWolfgang Grandegger 
2040443850ceSWolfgang Grandegger static int __init
2041443850ceSWolfgang Grandegger sensors_w83781d_init(void)
2042443850ceSWolfgang Grandegger {
2043443850ceSWolfgang Grandegger 	int res;
2044443850ceSWolfgang Grandegger 
2045443850ceSWolfgang Grandegger 	/* We register the ISA device first, so that we can skip the
2046443850ceSWolfgang Grandegger 	 * registration of an I2C interface to the same device. */
2047443850ceSWolfgang Grandegger 	res = w83781d_isa_register();
2048443850ceSWolfgang Grandegger 	if (res)
2049443850ceSWolfgang Grandegger 		goto exit;
2050443850ceSWolfgang Grandegger 
2051443850ceSWolfgang Grandegger 	res = i2c_add_driver(&w83781d_driver);
2052443850ceSWolfgang Grandegger 	if (res)
2053443850ceSWolfgang Grandegger 		goto exit_unreg_isa;
2054443850ceSWolfgang Grandegger 
2055443850ceSWolfgang Grandegger 	return 0;
2056443850ceSWolfgang Grandegger 
2057443850ceSWolfgang Grandegger  exit_unreg_isa:
2058443850ceSWolfgang Grandegger 	w83781d_isa_unregister();
2059443850ceSWolfgang Grandegger  exit:
2060443850ceSWolfgang Grandegger 	return res;
2061443850ceSWolfgang Grandegger }
2062443850ceSWolfgang Grandegger 
2063443850ceSWolfgang Grandegger static void __exit
2064443850ceSWolfgang Grandegger sensors_w83781d_exit(void)
2065443850ceSWolfgang Grandegger {
2066443850ceSWolfgang Grandegger 	w83781d_isa_unregister();
20678d5d45fbSJean Delvare 	i2c_del_driver(&w83781d_driver);
20688d5d45fbSJean Delvare }
20698d5d45fbSJean Delvare 
20708d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
20718d5d45fbSJean Delvare 	      "Philip Edelbrock <phil@netroedge.com>, "
20728d5d45fbSJean Delvare 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
20738d5d45fbSJean Delvare MODULE_DESCRIPTION("W83781D driver");
20748d5d45fbSJean Delvare MODULE_LICENSE("GPL");
20758d5d45fbSJean Delvare 
20768d5d45fbSJean Delvare module_init(sensors_w83781d_init);
20778d5d45fbSJean Delvare module_exit(sensors_w83781d_exit);
2078