xref: /openbmc/linux/drivers/hwmon/w83781d.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
3aff6e00eSGuenter Roeck  * w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
4aff6e00eSGuenter Roeck  *	       monitoring
5aff6e00eSGuenter Roeck  * Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>,
6aff6e00eSGuenter Roeck  *			      Philip Edelbrock <phil@netroedge.com>,
7aff6e00eSGuenter Roeck  *			      and Mark Studebaker <mdsxyz123@yahoo.com>
87c81c60fSJean Delvare  * Copyright (c) 2007 - 2008  Jean Delvare <jdelvare@suse.de>
98d5d45fbSJean Delvare  */
108d5d45fbSJean Delvare 
118d5d45fbSJean Delvare /*
12aff6e00eSGuenter Roeck  * Supports following chips:
13aff6e00eSGuenter Roeck  *
14aff6e00eSGuenter Roeck  * Chip		#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA
15aff6e00eSGuenter Roeck  * as99127f	7	3	0	3	0x31	0x12c3	yes	no
16aff6e00eSGuenter Roeck  * as99127f rev.2 (type_name = as99127f)	0x31	0x5ca3	yes	no
17aff6e00eSGuenter Roeck  * w83781d	7	3	0	3	0x10-1	0x5ca3	yes	yes
18aff6e00eSGuenter Roeck  * w83782d	9	3	2-4	3	0x30	0x5ca3	yes	yes
19aff6e00eSGuenter Roeck  * w83783s	5-6	3	2	1-2	0x40	0x5ca3	yes	no
20aff6e00eSGuenter Roeck  *
218d5d45fbSJean Delvare  */
228d5d45fbSJean Delvare 
231ca28218SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
241ca28218SJoe Perches 
258d5d45fbSJean Delvare #include <linux/module.h>
268d5d45fbSJean Delvare #include <linux/init.h>
278d5d45fbSJean Delvare #include <linux/slab.h>
288d5d45fbSJean Delvare #include <linux/jiffies.h>
298d5d45fbSJean Delvare #include <linux/i2c.h>
30943b0830SMark M. Hoffman #include <linux/hwmon.h>
31303760b4SJean Delvare #include <linux/hwmon-vid.h>
3234875337SJean Delvare #include <linux/hwmon-sysfs.h>
33311ce2efSJim Cromie #include <linux/sysfs.h>
34943b0830SMark M. Hoffman #include <linux/err.h>
359a61bf63SIngo Molnar #include <linux/mutex.h>
368d5d45fbSJean Delvare 
37443850ceSWolfgang Grandegger #ifdef CONFIG_ISA
38443850ceSWolfgang Grandegger #include <linux/platform_device.h>
39443850ceSWolfgang Grandegger #include <linux/ioport.h>
406055fae8SH Hartley Sweeten #include <linux/io.h>
41443850ceSWolfgang Grandegger #endif
42443850ceSWolfgang Grandegger 
43443850ceSWolfgang Grandegger #include "lm75.h"
447666c13cSJean Delvare 
458d5d45fbSJean Delvare /* Addresses to scan */
4625e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
476722feadSJean Delvare 						0x2e, 0x2f, I2C_CLIENT_END };
483aed198cSJean Delvare 
49e5e9f44cSJean Delvare enum chips { w83781d, w83782d, w83783s, as99127f };
50e5e9f44cSJean Delvare 
51e5e9f44cSJean Delvare /* Insmod parameters */
523aed198cSJean Delvare static unsigned short force_subclients[4];
533aed198cSJean Delvare module_param_array(force_subclients, short, NULL, 0);
54b55f3757SGuenter Roeck MODULE_PARM_DESC(force_subclients,
55b55f3757SGuenter Roeck 		 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
568d5d45fbSJean Delvare 
5790ab5ee9SRusty Russell static bool reset;
58fabddcd4SJean Delvare module_param(reset, bool, 0);
59fabddcd4SJean Delvare MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
60fabddcd4SJean Delvare 
6190ab5ee9SRusty Russell static bool init = 1;
628d5d45fbSJean Delvare module_param(init, bool, 0);
638d5d45fbSJean Delvare MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
648d5d45fbSJean Delvare 
658d5d45fbSJean Delvare /* Constants specified below */
668d5d45fbSJean Delvare 
678d5d45fbSJean Delvare /* Length of ISA address segment */
688d5d45fbSJean Delvare #define W83781D_EXTENT			8
698d5d45fbSJean Delvare 
708d5d45fbSJean Delvare /* Where are the ISA address/data registers relative to the base address */
718d5d45fbSJean Delvare #define W83781D_ADDR_REG_OFFSET		5
728d5d45fbSJean Delvare #define W83781D_DATA_REG_OFFSET		6
738d5d45fbSJean Delvare 
7434875337SJean Delvare /* The device registers */
7534875337SJean Delvare /* in nr from 0 to 8 */
768d5d45fbSJean Delvare #define W83781D_REG_IN_MAX(nr)		((nr < 7) ? (0x2b + (nr) * 2) : \
778d5d45fbSJean Delvare 						    (0x554 + (((nr) - 7) * 2)))
788d5d45fbSJean Delvare #define W83781D_REG_IN_MIN(nr)		((nr < 7) ? (0x2c + (nr) * 2) : \
798d5d45fbSJean Delvare 						    (0x555 + (((nr) - 7) * 2)))
808d5d45fbSJean Delvare #define W83781D_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
818d5d45fbSJean Delvare 						    (0x550 + (nr) - 7))
828d5d45fbSJean Delvare 
8334875337SJean Delvare /* fan nr from 0 to 2 */
8434875337SJean Delvare #define W83781D_REG_FAN_MIN(nr)		(0x3b + (nr))
8534875337SJean Delvare #define W83781D_REG_FAN(nr)		(0x28 + (nr))
868d5d45fbSJean Delvare 
878d5d45fbSJean Delvare #define W83781D_REG_BANK		0x4E
888d5d45fbSJean Delvare #define W83781D_REG_TEMP2_CONFIG	0x152
898d5d45fbSJean Delvare #define W83781D_REG_TEMP3_CONFIG	0x252
9034875337SJean Delvare /* temp nr from 1 to 3 */
918d5d45fbSJean Delvare #define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
928d5d45fbSJean Delvare 					((nr == 2) ? (0x0150) : \
938d5d45fbSJean Delvare 						     (0x27)))
948d5d45fbSJean Delvare #define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
958d5d45fbSJean Delvare 					((nr == 2) ? (0x153) : \
968d5d45fbSJean Delvare 						     (0x3A)))
978d5d45fbSJean Delvare #define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
988d5d45fbSJean Delvare 					((nr == 2) ? (0x155) : \
998d5d45fbSJean Delvare 						     (0x39)))
1008d5d45fbSJean Delvare 
1018d5d45fbSJean Delvare #define W83781D_REG_CONFIG		0x40
102c7f5d7edSJean Delvare 
103c7f5d7edSJean Delvare /* Interrupt status (W83781D, AS99127F) */
1048d5d45fbSJean Delvare #define W83781D_REG_ALARM1		0x41
1058d5d45fbSJean Delvare #define W83781D_REG_ALARM2		0x42
1068d5d45fbSJean Delvare 
10705663368SJean Delvare /* Real-time status (W83782D, W83783S) */
108c7f5d7edSJean Delvare #define W83782D_REG_ALARM1		0x459
109c7f5d7edSJean Delvare #define W83782D_REG_ALARM2		0x45A
110c7f5d7edSJean Delvare #define W83782D_REG_ALARM3		0x45B
111c7f5d7edSJean Delvare 
1128d5d45fbSJean Delvare #define W83781D_REG_BEEP_CONFIG		0x4D
1138d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS1		0x56
1148d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS2		0x57
1158d5d45fbSJean Delvare #define W83781D_REG_BEEP_INTS3		0x453	/* not on W83781D */
1168d5d45fbSJean Delvare 
1178d5d45fbSJean Delvare #define W83781D_REG_VID_FANDIV		0x47
1188d5d45fbSJean Delvare 
1198d5d45fbSJean Delvare #define W83781D_REG_CHIPID		0x49
1208d5d45fbSJean Delvare #define W83781D_REG_WCHIPID		0x58
1218d5d45fbSJean Delvare #define W83781D_REG_CHIPMAN		0x4F
1228d5d45fbSJean Delvare #define W83781D_REG_PIN			0x4B
1238d5d45fbSJean Delvare 
1248d5d45fbSJean Delvare /* 782D/783S only */
1258d5d45fbSJean Delvare #define W83781D_REG_VBAT		0x5D
1268d5d45fbSJean Delvare 
1278d5d45fbSJean Delvare /* PWM 782D (1-4) and 783S (1-2) only */
12834875337SJean Delvare static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
1298d5d45fbSJean Delvare #define W83781D_REG_PWMCLK12		0x5C
1308d5d45fbSJean Delvare #define W83781D_REG_PWMCLK34		0x45C
1318d5d45fbSJean Delvare 
1328d5d45fbSJean Delvare #define W83781D_REG_I2C_ADDR		0x48
1338d5d45fbSJean Delvare #define W83781D_REG_I2C_SUBADDR		0x4A
1348d5d45fbSJean Delvare 
135aff6e00eSGuenter Roeck /*
136aff6e00eSGuenter Roeck  * The following are undocumented in the data sheets however we
137aff6e00eSGuenter Roeck  * received the information in an email from Winbond tech support
138aff6e00eSGuenter Roeck  */
1398d5d45fbSJean Delvare /* Sensor selection - not on 781d */
1408d5d45fbSJean Delvare #define W83781D_REG_SCFG1		0x5D
1418d5d45fbSJean Delvare static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
1428d5d45fbSJean Delvare 
1438d5d45fbSJean Delvare #define W83781D_REG_SCFG2		0x59
1448d5d45fbSJean Delvare static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
1458d5d45fbSJean Delvare 
1468d5d45fbSJean Delvare #define W83781D_DEFAULT_BETA		3435
1478d5d45fbSJean Delvare 
148474d00a8SJean Delvare /* Conversions */
1492a844c14SGuenter Roeck #define IN_TO_REG(val)			clamp_val(((val) + 8) / 16, 0, 255)
150474d00a8SJean Delvare #define IN_FROM_REG(val)		((val) * 16)
1518d5d45fbSJean Delvare 
1528d5d45fbSJean Delvare static inline u8
FAN_TO_REG(long rpm,int div)1538d5d45fbSJean Delvare FAN_TO_REG(long rpm, int div)
1548d5d45fbSJean Delvare {
1558d5d45fbSJean Delvare 	if (rpm == 0)
1568d5d45fbSJean Delvare 		return 255;
1572a844c14SGuenter Roeck 	rpm = clamp_val(rpm, 1, 1000000);
1582a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1598d5d45fbSJean Delvare }
1608d5d45fbSJean Delvare 
161474d00a8SJean Delvare static inline long
FAN_FROM_REG(u8 val,int div)162474d00a8SJean Delvare FAN_FROM_REG(u8 val, int div)
163474d00a8SJean Delvare {
164474d00a8SJean Delvare 	if (val == 0)
165474d00a8SJean Delvare 		return -1;
166474d00a8SJean Delvare 	if (val == 255)
167474d00a8SJean Delvare 		return 0;
168474d00a8SJean Delvare 	return 1350000 / (val * div);
169474d00a8SJean Delvare }
1708d5d45fbSJean Delvare 
1712a844c14SGuenter Roeck #define TEMP_TO_REG(val)		clamp_val((val) / 1000, -127, 128)
172474d00a8SJean Delvare #define TEMP_FROM_REG(val)		((val) * 1000)
1738d5d45fbSJean Delvare 
1748d5d45fbSJean Delvare #define BEEP_MASK_FROM_REG(val, type)	((type) == as99127f ? \
1752fbbbf14SJean Delvare 					 (~(val)) & 0x7fff : (val) & 0xff7fff)
1768d5d45fbSJean Delvare #define BEEP_MASK_TO_REG(val, type)	((type) == as99127f ? \
1772fbbbf14SJean Delvare 					 (~(val)) & 0x7fff : (val) & 0xff7fff)
1788d5d45fbSJean Delvare 
1798d5d45fbSJean Delvare #define DIV_FROM_REG(val)		(1 << (val))
1808d5d45fbSJean Delvare 
1818d5d45fbSJean Delvare static inline u8
DIV_TO_REG(long val,enum chips type)1828d5d45fbSJean Delvare DIV_TO_REG(long val, enum chips type)
1838d5d45fbSJean Delvare {
1848d5d45fbSJean Delvare 	int i;
1852a844c14SGuenter Roeck 	val = clamp_val(val, 1,
1862a844c14SGuenter Roeck 			((type == w83781d || type == as99127f) ? 8 : 128)) >> 1;
1878d5d45fbSJean Delvare 	for (i = 0; i < 7; i++) {
1888d5d45fbSJean Delvare 		if (val == 0)
1898d5d45fbSJean Delvare 			break;
1908d5d45fbSJean Delvare 		val >>= 1;
1918d5d45fbSJean Delvare 	}
192474d00a8SJean Delvare 	return i;
1938d5d45fbSJean Delvare }
1948d5d45fbSJean Delvare 
1958d5d45fbSJean Delvare struct w83781d_data {
1960217eae3SWolfgang Grandegger 	struct i2c_client *client;
1971beeffe4STony Jones 	struct device *hwmon_dev;
1989a61bf63SIngo Molnar 	struct mutex lock;
1998d5d45fbSJean Delvare 	enum chips type;
2008d5d45fbSJean Delvare 
201360782ddSJean Delvare 	/* For ISA device only */
202360782ddSJean Delvare 	const char *name;
203360782ddSJean Delvare 	int isa_addr;
204360782ddSJean Delvare 
2059a61bf63SIngo Molnar 	struct mutex update_lock;
206952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
2078d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
2088d5d45fbSJean Delvare 
2098d5d45fbSJean Delvare 	struct i2c_client *lm75[2];	/* for secondary I2C addresses */
2108d5d45fbSJean Delvare 	/* array of 2 pointers to subclients */
2118d5d45fbSJean Delvare 
2128d5d45fbSJean Delvare 	u8 in[9];		/* Register value - 8 & 9 for 782D only */
2138d5d45fbSJean Delvare 	u8 in_max[9];		/* Register value - 8 & 9 for 782D only */
2148d5d45fbSJean Delvare 	u8 in_min[9];		/* Register value - 8 & 9 for 782D only */
2158d5d45fbSJean Delvare 	u8 fan[3];		/* Register value */
2168d5d45fbSJean Delvare 	u8 fan_min[3];		/* Register value */
217474d00a8SJean Delvare 	s8 temp;		/* Register value */
218474d00a8SJean Delvare 	s8 temp_max;		/* Register value */
219474d00a8SJean Delvare 	s8 temp_max_hyst;	/* Register value */
2208d5d45fbSJean Delvare 	u16 temp_add[2];	/* Register value */
2218d5d45fbSJean Delvare 	u16 temp_max_add[2];	/* Register value */
2228d5d45fbSJean Delvare 	u16 temp_max_hyst_add[2];	/* Register value */
2238d5d45fbSJean Delvare 	u8 fan_div[3];		/* Register encoding, shifted right */
2248d5d45fbSJean Delvare 	u8 vid;			/* Register encoding, combined */
2258d5d45fbSJean Delvare 	u32 alarms;		/* Register encoding, combined */
2268d5d45fbSJean Delvare 	u32 beep_mask;		/* Register encoding, combined */
2278d5d45fbSJean Delvare 	u8 pwm[4];		/* Register value */
22834875337SJean Delvare 	u8 pwm2_enable;		/* Boolean */
229aff6e00eSGuenter Roeck 	u16 sens[3];		/*
230aff6e00eSGuenter Roeck 				 * 782D/783S only.
231aff6e00eSGuenter Roeck 				 * 1 = pentium diode; 2 = 3904 diode;
232aff6e00eSGuenter Roeck 				 * 4 = thermistor
233aff6e00eSGuenter Roeck 				 */
2348d5d45fbSJean Delvare 	u8 vrm;
2358d5d45fbSJean Delvare };
2368d5d45fbSJean Delvare 
237443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void);
238443850ceSWolfgang Grandegger static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
239443850ceSWolfgang Grandegger 
24031b8dc4dSJean Delvare static int w83781d_read_value(struct w83781d_data *data, u16 reg);
24131b8dc4dSJean Delvare static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
2428d5d45fbSJean Delvare static struct w83781d_data *w83781d_update_device(struct device *dev);
2437666c13cSJean Delvare static void w83781d_init_device(struct device *dev);
2448d5d45fbSJean Delvare 
2458d5d45fbSJean Delvare /* following are the sysfs callback functions */
2468d5d45fbSJean Delvare #define show_in_reg(reg) \
24734875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
24834875337SJean Delvare 		char *buf) \
2498d5d45fbSJean Delvare { \
25034875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
2518d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
25234875337SJean Delvare 	return sprintf(buf, "%ld\n", \
25334875337SJean Delvare 		       (long)IN_FROM_REG(data->reg[attr->index])); \
2548d5d45fbSJean Delvare }
2558d5d45fbSJean Delvare show_in_reg(in);
2568d5d45fbSJean Delvare show_in_reg(in_min);
2578d5d45fbSJean Delvare show_in_reg(in_max);
2588d5d45fbSJean Delvare 
2598d5d45fbSJean Delvare #define store_in_reg(REG, reg) \
26034875337SJean Delvare static ssize_t store_in_##reg(struct device *dev, struct device_attribute \
26134875337SJean Delvare 		*da, const char *buf, size_t count) \
2628d5d45fbSJean Delvare { \
26334875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
2647666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev); \
26534875337SJean Delvare 	int nr = attr->index; \
266c531eb3fSGuenter Roeck 	unsigned long val; \
267c531eb3fSGuenter Roeck 	int err = kstrtoul(buf, 10, &val); \
268c531eb3fSGuenter Roeck 	if (err) \
269c531eb3fSGuenter Roeck 		return err; \
2709a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
2718d5d45fbSJean Delvare 	data->in_##reg[nr] = IN_TO_REG(val); \
272c531eb3fSGuenter Roeck 	w83781d_write_value(data, W83781D_REG_IN_##REG(nr), \
273c531eb3fSGuenter Roeck 			    data->in_##reg[nr]); \
2748d5d45fbSJean Delvare 	\
2759a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
2768d5d45fbSJean Delvare 	return count; \
2778d5d45fbSJean Delvare }
2788d5d45fbSJean Delvare store_in_reg(MIN, min);
2798d5d45fbSJean Delvare store_in_reg(MAX, max);
2808d5d45fbSJean Delvare 
2818d5d45fbSJean Delvare #define sysfs_in_offsets(offset) \
28234875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
28334875337SJean Delvare 		show_in, NULL, offset); \
28434875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
28534875337SJean Delvare 		show_in_min, store_in_min, offset); \
28634875337SJean Delvare static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
28734875337SJean Delvare 		show_in_max, store_in_max, offset)
2888d5d45fbSJean Delvare 
2898d5d45fbSJean Delvare sysfs_in_offsets(0);
2908d5d45fbSJean Delvare sysfs_in_offsets(1);
2918d5d45fbSJean Delvare sysfs_in_offsets(2);
2928d5d45fbSJean Delvare sysfs_in_offsets(3);
2938d5d45fbSJean Delvare sysfs_in_offsets(4);
2948d5d45fbSJean Delvare sysfs_in_offsets(5);
2958d5d45fbSJean Delvare sysfs_in_offsets(6);
2968d5d45fbSJean Delvare sysfs_in_offsets(7);
2978d5d45fbSJean Delvare sysfs_in_offsets(8);
2988d5d45fbSJean Delvare 
2998d5d45fbSJean Delvare #define show_fan_reg(reg) \
30034875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
30134875337SJean Delvare 		char *buf) \
3028d5d45fbSJean Delvare { \
30334875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3048d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
3058d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", \
30634875337SJean Delvare 		FAN_FROM_REG(data->reg[attr->index], \
30734875337SJean Delvare 			DIV_FROM_REG(data->fan_div[attr->index]))); \
3088d5d45fbSJean Delvare }
3098d5d45fbSJean Delvare show_fan_reg(fan);
3108d5d45fbSJean Delvare show_fan_reg(fan_min);
3118d5d45fbSJean Delvare 
3128d5d45fbSJean Delvare static ssize_t
store_fan_min(struct device * dev,struct device_attribute * da,const char * buf,size_t count)31334875337SJean Delvare store_fan_min(struct device *dev, struct device_attribute *da,
31434875337SJean Delvare 		const char *buf, size_t count)
3158d5d45fbSJean Delvare {
31634875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
3177666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
31834875337SJean Delvare 	int nr = attr->index;
319c531eb3fSGuenter Roeck 	unsigned long val;
320c531eb3fSGuenter Roeck 	int err;
3218d5d45fbSJean Delvare 
322c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
323c531eb3fSGuenter Roeck 	if (err)
324c531eb3fSGuenter Roeck 		return err;
3258d5d45fbSJean Delvare 
3269a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
32734875337SJean Delvare 	data->fan_min[nr] =
32834875337SJean Delvare 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
32931b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
33034875337SJean Delvare 			    data->fan_min[nr]);
3318d5d45fbSJean Delvare 
3329a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3338d5d45fbSJean Delvare 	return count;
3348d5d45fbSJean Delvare }
3358d5d45fbSJean Delvare 
33634875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
33734875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
33834875337SJean Delvare 		show_fan_min, store_fan_min, 0);
33934875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
34034875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
34134875337SJean Delvare 		show_fan_min, store_fan_min, 1);
34234875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
34334875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
34434875337SJean Delvare 		show_fan_min, store_fan_min, 2);
3458d5d45fbSJean Delvare 
3468d5d45fbSJean Delvare #define show_temp_reg(reg) \
34734875337SJean Delvare static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \
34834875337SJean Delvare 		char *buf) \
3498d5d45fbSJean Delvare { \
35034875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3518d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev); \
35234875337SJean Delvare 	int nr = attr->index; \
3538d5d45fbSJean Delvare 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
3548d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", \
3558d5d45fbSJean Delvare 			LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
3568d5d45fbSJean Delvare 	} else {	/* TEMP1 */ \
3578d5d45fbSJean Delvare 		return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->reg)); \
3588d5d45fbSJean Delvare 	} \
3598d5d45fbSJean Delvare }
3608d5d45fbSJean Delvare show_temp_reg(temp);
3618d5d45fbSJean Delvare show_temp_reg(temp_max);
3628d5d45fbSJean Delvare show_temp_reg(temp_max_hyst);
3638d5d45fbSJean Delvare 
3648d5d45fbSJean Delvare #define store_temp_reg(REG, reg) \
36534875337SJean Delvare static ssize_t store_temp_##reg(struct device *dev, \
36634875337SJean Delvare 		struct device_attribute *da, const char *buf, size_t count) \
3678d5d45fbSJean Delvare { \
36834875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
3697666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev); \
37034875337SJean Delvare 	int nr = attr->index; \
3715bfedac0SChristian Hohnstaedt 	long val; \
372c531eb3fSGuenter Roeck 	int err = kstrtol(buf, 10, &val); \
373c531eb3fSGuenter Roeck 	if (err) \
374c531eb3fSGuenter Roeck 		return err; \
3759a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
3768d5d45fbSJean Delvare 	 \
3778d5d45fbSJean Delvare 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
3788d5d45fbSJean Delvare 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
37931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
3808d5d45fbSJean Delvare 				data->temp_##reg##_add[nr-2]); \
3818d5d45fbSJean Delvare 	} else {	/* TEMP1 */ \
3828d5d45fbSJean Delvare 		data->temp_##reg = TEMP_TO_REG(val); \
38331b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
3848d5d45fbSJean Delvare 			data->temp_##reg); \
3858d5d45fbSJean Delvare 	} \
3868d5d45fbSJean Delvare 	 \
3879a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
3888d5d45fbSJean Delvare 	return count; \
3898d5d45fbSJean Delvare }
3908d5d45fbSJean Delvare store_temp_reg(OVER, max);
3918d5d45fbSJean Delvare store_temp_reg(HYST, max_hyst);
3928d5d45fbSJean Delvare 
3938d5d45fbSJean Delvare #define sysfs_temp_offsets(offset) \
39434875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
39534875337SJean Delvare 		show_temp, NULL, offset); \
39634875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
39734875337SJean Delvare 		show_temp_max, store_temp_max, offset); \
39834875337SJean Delvare static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
39934875337SJean Delvare 		show_temp_max_hyst, store_temp_max_hyst, offset);
4008d5d45fbSJean Delvare 
4018d5d45fbSJean Delvare sysfs_temp_offsets(1);
4028d5d45fbSJean Delvare sysfs_temp_offsets(2);
4038d5d45fbSJean Delvare sysfs_temp_offsets(3);
4048d5d45fbSJean Delvare 
4058d5d45fbSJean Delvare static ssize_t
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)406b80b814bSJulia Lawall cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
4078d5d45fbSJean Delvare {
4088d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4098d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
4108d5d45fbSJean Delvare }
4118d5d45fbSJean Delvare 
412b80b814bSJulia Lawall static DEVICE_ATTR_RO(cpu0_vid);
413311ce2efSJim Cromie 
4148d5d45fbSJean Delvare static ssize_t
vrm_show(struct device * dev,struct device_attribute * attr,char * buf)415b80b814bSJulia Lawall vrm_show(struct device *dev, struct device_attribute *attr, char *buf)
4168d5d45fbSJean Delvare {
41790d6619aSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
4188d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", (long) data->vrm);
4198d5d45fbSJean Delvare }
4208d5d45fbSJean Delvare 
4218d5d45fbSJean Delvare static ssize_t
vrm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)422b80b814bSJulia Lawall vrm_store(struct device *dev, struct device_attribute *attr, const char *buf,
423b80b814bSJulia Lawall 	  size_t count)
4248d5d45fbSJean Delvare {
4257666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
426c531eb3fSGuenter Roeck 	unsigned long val;
427c531eb3fSGuenter Roeck 	int err;
4288d5d45fbSJean Delvare 
429c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
430c531eb3fSGuenter Roeck 	if (err)
431c531eb3fSGuenter Roeck 		return err;
4322a844c14SGuenter Roeck 	data->vrm = clamp_val(val, 0, 255);
4338d5d45fbSJean Delvare 
4348d5d45fbSJean Delvare 	return count;
4358d5d45fbSJean Delvare }
4368d5d45fbSJean Delvare 
437b80b814bSJulia Lawall static DEVICE_ATTR_RW(vrm);
438311ce2efSJim Cromie 
4398d5d45fbSJean Delvare static ssize_t
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)440b80b814bSJulia Lawall alarms_show(struct device *dev, struct device_attribute *attr, char *buf)
4418d5d45fbSJean Delvare {
4428d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4438d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
4448d5d45fbSJean Delvare }
4458d5d45fbSJean Delvare 
446b80b814bSJulia Lawall static DEVICE_ATTR_RO(alarms);
447311ce2efSJim Cromie 
show_alarm(struct device * dev,struct device_attribute * attr,char * buf)4487d4a1374SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
4497d4a1374SJean Delvare 		char *buf)
4507d4a1374SJean Delvare {
4517d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4527d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
4537d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
4547d4a1374SJean Delvare }
4557d4a1374SJean Delvare 
4567d4a1374SJean Delvare /* The W83781D has a single alarm bit for temp2 and temp3 */
show_temp3_alarm(struct device * dev,struct device_attribute * attr,char * buf)4577d4a1374SJean Delvare static ssize_t show_temp3_alarm(struct device *dev,
4587d4a1374SJean Delvare 		struct device_attribute *attr, char *buf)
4597d4a1374SJean Delvare {
4607d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4617d4a1374SJean Delvare 	int bitnr = (data->type == w83781d) ? 5 : 13;
4627d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
4637d4a1374SJean Delvare }
4647d4a1374SJean Delvare 
4657d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
4667d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
4677d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
4687d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
4697d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
4707d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
4717d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
4727d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
4737d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
4747d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
4757d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
4767d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
4777d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
4787d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
4797d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
4807d4a1374SJean Delvare 
beep_mask_show(struct device * dev,struct device_attribute * attr,char * buf)481b80b814bSJulia Lawall static ssize_t beep_mask_show(struct device *dev,
482c531eb3fSGuenter Roeck 			       struct device_attribute *attr, char *buf)
4838d5d45fbSJean Delvare {
4848d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
4858d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n",
4868d5d45fbSJean Delvare 		       (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type));
4878d5d45fbSJean Delvare }
4888d5d45fbSJean Delvare 
4898d5d45fbSJean Delvare static ssize_t
beep_mask_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)490b80b814bSJulia Lawall beep_mask_store(struct device *dev, struct device_attribute *attr,
49134875337SJean Delvare 		const char *buf, size_t count)
4928d5d45fbSJean Delvare {
4937666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
494c531eb3fSGuenter Roeck 	unsigned long val;
495c531eb3fSGuenter Roeck 	int err;
4968d5d45fbSJean Delvare 
497c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
498c531eb3fSGuenter Roeck 	if (err)
499c531eb3fSGuenter Roeck 		return err;
5008d5d45fbSJean Delvare 
5019a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
5022fbbbf14SJean Delvare 	data->beep_mask &= 0x8000; /* preserve beep enable */
5032fbbbf14SJean Delvare 	data->beep_mask |= BEEP_MASK_TO_REG(val, data->type);
50431b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
5058d5d45fbSJean Delvare 			    data->beep_mask & 0xff);
50634875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
5072fbbbf14SJean Delvare 			    (data->beep_mask >> 8) & 0xff);
50834875337SJean Delvare 	if (data->type != w83781d && data->type != as99127f) {
50931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
5108d5d45fbSJean Delvare 				    ((data->beep_mask) >> 16) & 0xff);
5118d5d45fbSJean Delvare 	}
5129a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
51334875337SJean Delvare 
5148d5d45fbSJean Delvare 	return count;
5158d5d45fbSJean Delvare }
5168d5d45fbSJean Delvare 
517b80b814bSJulia Lawall static DEVICE_ATTR_RW(beep_mask);
5188d5d45fbSJean Delvare 
show_beep(struct device * dev,struct device_attribute * attr,char * buf)5197d4a1374SJean Delvare static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
5207d4a1374SJean Delvare 		char *buf)
5217d4a1374SJean Delvare {
5227d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
5237d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
5247d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
5257d4a1374SJean Delvare }
5267d4a1374SJean Delvare 
5277d4a1374SJean Delvare static ssize_t
store_beep(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5287d4a1374SJean Delvare store_beep(struct device *dev, struct device_attribute *attr,
5297d4a1374SJean Delvare 		const char *buf, size_t count)
5307d4a1374SJean Delvare {
5317d4a1374SJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
5327d4a1374SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
5337d4a1374SJean Delvare 	u8 reg;
534c531eb3fSGuenter Roeck 	unsigned long bit;
535c531eb3fSGuenter Roeck 	int err;
5367d4a1374SJean Delvare 
537c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &bit);
538c531eb3fSGuenter Roeck 	if (err)
539c531eb3fSGuenter Roeck 		return err;
540c531eb3fSGuenter Roeck 
5417d4a1374SJean Delvare 	if (bit & ~1)
5427d4a1374SJean Delvare 		return -EINVAL;
5437d4a1374SJean Delvare 
5447d4a1374SJean Delvare 	mutex_lock(&data->update_lock);
5457d4a1374SJean Delvare 	if (bit)
5467d4a1374SJean Delvare 		data->beep_mask |= (1 << bitnr);
5477d4a1374SJean Delvare 	else
5487d4a1374SJean Delvare 		data->beep_mask &= ~(1 << bitnr);
5497d4a1374SJean Delvare 
5507d4a1374SJean Delvare 	if (bitnr < 8) {
5517d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
5527d4a1374SJean Delvare 		if (bit)
5537d4a1374SJean Delvare 			reg |= (1 << bitnr);
5547d4a1374SJean Delvare 		else
5557d4a1374SJean Delvare 			reg &= ~(1 << bitnr);
5567d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
5577d4a1374SJean Delvare 	} else if (bitnr < 16) {
5587d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
5597d4a1374SJean Delvare 		if (bit)
5607d4a1374SJean Delvare 			reg |= (1 << (bitnr - 8));
5617d4a1374SJean Delvare 		else
5627d4a1374SJean Delvare 			reg &= ~(1 << (bitnr - 8));
5637d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
5647d4a1374SJean Delvare 	} else {
5657d4a1374SJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
5667d4a1374SJean Delvare 		if (bit)
5677d4a1374SJean Delvare 			reg |= (1 << (bitnr - 16));
5687d4a1374SJean Delvare 		else
5697d4a1374SJean Delvare 			reg &= ~(1 << (bitnr - 16));
5707d4a1374SJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
5717d4a1374SJean Delvare 	}
5727d4a1374SJean Delvare 	mutex_unlock(&data->update_lock);
5737d4a1374SJean Delvare 
5747d4a1374SJean Delvare 	return count;
5757d4a1374SJean Delvare }
5767d4a1374SJean Delvare 
5777d4a1374SJean Delvare /* The W83781D has a single beep bit for temp2 and temp3 */
show_temp3_beep(struct device * dev,struct device_attribute * attr,char * buf)5787d4a1374SJean Delvare static ssize_t show_temp3_beep(struct device *dev,
5797d4a1374SJean Delvare 		struct device_attribute *attr, char *buf)
5807d4a1374SJean Delvare {
5817d4a1374SJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
5827d4a1374SJean Delvare 	int bitnr = (data->type == w83781d) ? 5 : 13;
5837d4a1374SJean Delvare 	return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
5847d4a1374SJean Delvare }
5857d4a1374SJean Delvare 
5867d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
5877d4a1374SJean Delvare 			show_beep, store_beep, 0);
5887d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
5897d4a1374SJean Delvare 			show_beep, store_beep, 1);
5907d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
5917d4a1374SJean Delvare 			show_beep, store_beep, 2);
5927d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
5937d4a1374SJean Delvare 			show_beep, store_beep, 3);
5947d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
5957d4a1374SJean Delvare 			show_beep, store_beep, 8);
5967d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
5977d4a1374SJean Delvare 			show_beep, store_beep, 9);
5987d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
5997d4a1374SJean Delvare 			show_beep, store_beep, 10);
6007d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
6017d4a1374SJean Delvare 			show_beep, store_beep, 16);
6027d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
6037d4a1374SJean Delvare 			show_beep, store_beep, 17);
6047d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
6057d4a1374SJean Delvare 			show_beep, store_beep, 6);
6067d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
6077d4a1374SJean Delvare 			show_beep, store_beep, 7);
6087d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
6097d4a1374SJean Delvare 			show_beep, store_beep, 11);
6107d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
6117d4a1374SJean Delvare 			show_beep, store_beep, 4);
6127d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
6137d4a1374SJean Delvare 			show_beep, store_beep, 5);
6147d4a1374SJean Delvare static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
6157d4a1374SJean Delvare 			show_temp3_beep, store_beep, 13);
6162fbbbf14SJean Delvare static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
6172fbbbf14SJean Delvare 			show_beep, store_beep, 15);
6187d4a1374SJean Delvare 
6198d5d45fbSJean Delvare static ssize_t
show_fan_div(struct device * dev,struct device_attribute * da,char * buf)62034875337SJean Delvare show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
6218d5d45fbSJean Delvare {
62234875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6238d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
6248d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n",
62534875337SJean Delvare 		       (long) DIV_FROM_REG(data->fan_div[attr->index]));
6268d5d45fbSJean Delvare }
6278d5d45fbSJean Delvare 
628aff6e00eSGuenter Roeck /*
629aff6e00eSGuenter Roeck  * Note: we save and restore the fan minimum here, because its value is
630aff6e00eSGuenter Roeck  * determined in part by the fan divisor.  This follows the principle of
631aff6e00eSGuenter Roeck  * least surprise; the user doesn't expect the fan minimum to change just
632aff6e00eSGuenter Roeck  * because the divisor changed.
633aff6e00eSGuenter Roeck  */
6348d5d45fbSJean Delvare static ssize_t
store_fan_div(struct device * dev,struct device_attribute * da,const char * buf,size_t count)63534875337SJean Delvare store_fan_div(struct device *dev, struct device_attribute *da,
63634875337SJean Delvare 		const char *buf, size_t count)
6378d5d45fbSJean Delvare {
63834875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6397666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
6408d5d45fbSJean Delvare 	unsigned long min;
64134875337SJean Delvare 	int nr = attr->index;
6428d5d45fbSJean Delvare 	u8 reg;
643c531eb3fSGuenter Roeck 	unsigned long val;
644c531eb3fSGuenter Roeck 	int err;
645c531eb3fSGuenter Roeck 
646c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
647c531eb3fSGuenter Roeck 	if (err)
648c531eb3fSGuenter Roeck 		return err;
6498d5d45fbSJean Delvare 
6509a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6518d5d45fbSJean Delvare 
6528d5d45fbSJean Delvare 	/* Save fan_min */
6538d5d45fbSJean Delvare 	min = FAN_FROM_REG(data->fan_min[nr],
6548d5d45fbSJean Delvare 			   DIV_FROM_REG(data->fan_div[nr]));
6558d5d45fbSJean Delvare 
6568d5d45fbSJean Delvare 	data->fan_div[nr] = DIV_TO_REG(val, data->type);
6578d5d45fbSJean Delvare 
658c531eb3fSGuenter Roeck 	reg = (w83781d_read_value(data, nr == 2 ?
659c531eb3fSGuenter Roeck 				  W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
6608d5d45fbSJean Delvare 		& (nr == 0 ? 0xcf : 0x3f))
6618d5d45fbSJean Delvare 	      | ((data->fan_div[nr] & 0x03) << (nr == 0 ? 4 : 6));
662c531eb3fSGuenter Roeck 	w83781d_write_value(data, nr == 2 ?
663c531eb3fSGuenter Roeck 			    W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
6648d5d45fbSJean Delvare 
6658d5d45fbSJean Delvare 	/* w83781d and as99127f don't have extended divisor bits */
6668d5d45fbSJean Delvare 	if (data->type != w83781d && data->type != as99127f) {
66731b8dc4dSJean Delvare 		reg = (w83781d_read_value(data, W83781D_REG_VBAT)
6688d5d45fbSJean Delvare 		       & ~(1 << (5 + nr)))
6698d5d45fbSJean Delvare 		    | ((data->fan_div[nr] & 0x04) << (3 + nr));
67031b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_VBAT, reg);
6718d5d45fbSJean Delvare 	}
6728d5d45fbSJean Delvare 
6738d5d45fbSJean Delvare 	/* Restore fan_min */
6748d5d45fbSJean Delvare 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
67534875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
6768d5d45fbSJean Delvare 
6779a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6788d5d45fbSJean Delvare 	return count;
6798d5d45fbSJean Delvare }
6808d5d45fbSJean Delvare 
68134875337SJean Delvare static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
68234875337SJean Delvare 		show_fan_div, store_fan_div, 0);
68334875337SJean Delvare static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
68434875337SJean Delvare 		show_fan_div, store_fan_div, 1);
68534875337SJean Delvare static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
68634875337SJean Delvare 		show_fan_div, store_fan_div, 2);
6878d5d45fbSJean Delvare 
6888d5d45fbSJean Delvare static ssize_t
show_pwm(struct device * dev,struct device_attribute * da,char * buf)68934875337SJean Delvare show_pwm(struct device *dev, struct device_attribute *da, char *buf)
6908d5d45fbSJean Delvare {
69134875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
6928d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
69334875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
6948d5d45fbSJean Delvare }
6958d5d45fbSJean Delvare 
6968d5d45fbSJean Delvare static ssize_t
pwm2_enable_show(struct device * dev,struct device_attribute * da,char * buf)697b80b814bSJulia Lawall pwm2_enable_show(struct device *dev, struct device_attribute *da, char *buf)
6988d5d45fbSJean Delvare {
6998d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
70034875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->pwm2_enable);
7018d5d45fbSJean Delvare }
7028d5d45fbSJean Delvare 
7038d5d45fbSJean Delvare static ssize_t
store_pwm(struct device * dev,struct device_attribute * da,const char * buf,size_t count)70434875337SJean Delvare store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
70534875337SJean Delvare 		size_t count)
7068d5d45fbSJean Delvare {
70734875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7087666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
70934875337SJean Delvare 	int nr = attr->index;
710c531eb3fSGuenter Roeck 	unsigned long val;
711c531eb3fSGuenter Roeck 	int err;
7128d5d45fbSJean Delvare 
713c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
714c531eb3fSGuenter Roeck 	if (err)
715c531eb3fSGuenter Roeck 		return err;
7168d5d45fbSJean Delvare 
7179a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7182a844c14SGuenter Roeck 	data->pwm[nr] = clamp_val(val, 0, 255);
71934875337SJean Delvare 	w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
7209a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7218d5d45fbSJean Delvare 	return count;
7228d5d45fbSJean Delvare }
7238d5d45fbSJean Delvare 
7248d5d45fbSJean Delvare static ssize_t
pwm2_enable_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)725b80b814bSJulia Lawall pwm2_enable_store(struct device *dev, struct device_attribute *da,
72634875337SJean Delvare 		const char *buf, size_t count)
7278d5d45fbSJean Delvare {
7287666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
729c531eb3fSGuenter Roeck 	unsigned long val;
730c531eb3fSGuenter Roeck 	u32 reg;
731c531eb3fSGuenter Roeck 	int err;
7328d5d45fbSJean Delvare 
733c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
734c531eb3fSGuenter Roeck 	if (err)
735c531eb3fSGuenter Roeck 		return err;
7368d5d45fbSJean Delvare 
7379a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7388d5d45fbSJean Delvare 
7398d5d45fbSJean Delvare 	switch (val) {
7408d5d45fbSJean Delvare 	case 0:
7418d5d45fbSJean Delvare 	case 1:
74231b8dc4dSJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
74331b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_PWMCLK12,
7448d5d45fbSJean Delvare 				    (reg & 0xf7) | (val << 3));
7458d5d45fbSJean Delvare 
74631b8dc4dSJean Delvare 		reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
74731b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
7488d5d45fbSJean Delvare 				    (reg & 0xef) | (!val << 4));
7498d5d45fbSJean Delvare 
75034875337SJean Delvare 		data->pwm2_enable = val;
7518d5d45fbSJean Delvare 		break;
7528d5d45fbSJean Delvare 
7538d5d45fbSJean Delvare 	default:
7549a61bf63SIngo Molnar 		mutex_unlock(&data->update_lock);
7558d5d45fbSJean Delvare 		return -EINVAL;
7568d5d45fbSJean Delvare 	}
7578d5d45fbSJean Delvare 
7589a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
7598d5d45fbSJean Delvare 	return count;
7608d5d45fbSJean Delvare }
7618d5d45fbSJean Delvare 
76234875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
76334875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
76434875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
76534875337SJean Delvare static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
76634875337SJean Delvare /* only PWM2 can be enabled/disabled */
767b80b814bSJulia Lawall static DEVICE_ATTR_RW(pwm2_enable);
7688d5d45fbSJean Delvare 
7698d5d45fbSJean Delvare static ssize_t
show_sensor(struct device * dev,struct device_attribute * da,char * buf)77034875337SJean Delvare show_sensor(struct device *dev, struct device_attribute *da, char *buf)
7718d5d45fbSJean Delvare {
77234875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7738d5d45fbSJean Delvare 	struct w83781d_data *data = w83781d_update_device(dev);
77434875337SJean Delvare 	return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
7758d5d45fbSJean Delvare }
7768d5d45fbSJean Delvare 
7778d5d45fbSJean Delvare static ssize_t
store_sensor(struct device * dev,struct device_attribute * da,const char * buf,size_t count)77834875337SJean Delvare store_sensor(struct device *dev, struct device_attribute *da,
77934875337SJean Delvare 		const char *buf, size_t count)
7808d5d45fbSJean Delvare {
78134875337SJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
7827666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
78334875337SJean Delvare 	int nr = attr->index;
784c531eb3fSGuenter Roeck 	unsigned long val;
785c531eb3fSGuenter Roeck 	u32 tmp;
786c531eb3fSGuenter Roeck 	int err;
7878d5d45fbSJean Delvare 
788c531eb3fSGuenter Roeck 	err = kstrtoul(buf, 10, &val);
789c531eb3fSGuenter Roeck 	if (err)
790c531eb3fSGuenter Roeck 		return err;
7918d5d45fbSJean Delvare 
7929a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
7938d5d45fbSJean Delvare 
7948d5d45fbSJean Delvare 	switch (val) {
7958d5d45fbSJean Delvare 	case 1:		/* PII/Celeron diode */
79631b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
79731b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
79834875337SJean Delvare 				    tmp | BIT_SCFG1[nr]);
79931b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
80031b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG2,
80134875337SJean Delvare 				    tmp | BIT_SCFG2[nr]);
80234875337SJean Delvare 		data->sens[nr] = val;
8038d5d45fbSJean Delvare 		break;
8048d5d45fbSJean Delvare 	case 2:		/* 3904 */
80531b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
80631b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
80734875337SJean Delvare 				    tmp | BIT_SCFG1[nr]);
80831b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
80931b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG2,
81034875337SJean Delvare 				    tmp & ~BIT_SCFG2[nr]);
81134875337SJean Delvare 		data->sens[nr] = val;
8128d5d45fbSJean Delvare 		break;
813b26f9330SJean Delvare 	case W83781D_DEFAULT_BETA:
814b55f3757SGuenter Roeck 		dev_warn(dev,
815b55f3757SGuenter Roeck 			 "Sensor type %d is deprecated, please use 4 instead\n",
816b55f3757SGuenter Roeck 			 W83781D_DEFAULT_BETA);
817df561f66SGustavo A. R. Silva 		fallthrough;
818b26f9330SJean Delvare 	case 4:		/* thermistor */
81931b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
82031b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_SCFG1,
82134875337SJean Delvare 				    tmp & ~BIT_SCFG1[nr]);
82234875337SJean Delvare 		data->sens[nr] = val;
8238d5d45fbSJean Delvare 		break;
8248d5d45fbSJean Delvare 	default:
825b26f9330SJean Delvare 		dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
826b26f9330SJean Delvare 		       (long) val);
8278d5d45fbSJean Delvare 		break;
8288d5d45fbSJean Delvare 	}
8298d5d45fbSJean Delvare 
8309a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
8318d5d45fbSJean Delvare 	return count;
8328d5d45fbSJean Delvare }
8338d5d45fbSJean Delvare 
83434875337SJean Delvare static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
83534875337SJean Delvare 	show_sensor, store_sensor, 0);
83634875337SJean Delvare static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
837393cdad6SMark M. Hoffman 	show_sensor, store_sensor, 1);
83834875337SJean Delvare static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
839393cdad6SMark M. Hoffman 	show_sensor, store_sensor, 2);
8408d5d45fbSJean Delvare 
841aff6e00eSGuenter Roeck /*
842aff6e00eSGuenter Roeck  * Assumes that adapter is of I2C, not ISA variety.
8438d5d45fbSJean Delvare  * OTHERWISE DON'T CALL THIS
8448d5d45fbSJean Delvare  */
8458d5d45fbSJean Delvare static int
w83781d_detect_subclients(struct i2c_client * new_client)8460217eae3SWolfgang Grandegger w83781d_detect_subclients(struct i2c_client *new_client)
8478d5d45fbSJean Delvare {
8488d5d45fbSJean Delvare 	int i, val1 = 0, id;
8498d5d45fbSJean Delvare 	int err;
8500217eae3SWolfgang Grandegger 	int address = new_client->addr;
8510217eae3SWolfgang Grandegger 	unsigned short sc_addr[2];
8520217eae3SWolfgang Grandegger 	struct i2c_adapter *adapter = new_client->adapter;
8538d5d45fbSJean Delvare 	struct w83781d_data *data = i2c_get_clientdata(new_client);
8540217eae3SWolfgang Grandegger 	enum chips kind = data->type;
855bbc8a569SGuenter Roeck 	int num_sc = 1;
8568d5d45fbSJean Delvare 
8578d5d45fbSJean Delvare 	id = i2c_adapter_id(adapter);
8588d5d45fbSJean Delvare 
8598d5d45fbSJean Delvare 	if (force_subclients[0] == id && force_subclients[1] == address) {
8608d5d45fbSJean Delvare 		for (i = 2; i <= 3; i++) {
8618d5d45fbSJean Delvare 			if (force_subclients[i] < 0x48 ||
8628d5d45fbSJean Delvare 			    force_subclients[i] > 0x4f) {
863b55f3757SGuenter Roeck 				dev_err(&new_client->dev,
864b55f3757SGuenter Roeck 					"Invalid subclient address %d; must be 0x48-0x4f\n",
8658d5d45fbSJean Delvare 					force_subclients[i]);
8668d5d45fbSJean Delvare 				err = -EINVAL;
8678d5d45fbSJean Delvare 				goto ERROR_SC_1;
8688d5d45fbSJean Delvare 			}
8698d5d45fbSJean Delvare 		}
87031b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
8718d5d45fbSJean Delvare 				(force_subclients[2] & 0x07) |
8728d5d45fbSJean Delvare 				((force_subclients[3] & 0x07) << 4));
8730217eae3SWolfgang Grandegger 		sc_addr[0] = force_subclients[2];
8748d5d45fbSJean Delvare 	} else {
87531b8dc4dSJean Delvare 		val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
8760217eae3SWolfgang Grandegger 		sc_addr[0] = 0x48 + (val1 & 0x07);
8778d5d45fbSJean Delvare 	}
8788d5d45fbSJean Delvare 
8798d5d45fbSJean Delvare 	if (kind != w83783s) {
880bbc8a569SGuenter Roeck 		num_sc = 2;
8818d5d45fbSJean Delvare 		if (force_subclients[0] == id &&
8828d5d45fbSJean Delvare 		    force_subclients[1] == address) {
8830217eae3SWolfgang Grandegger 			sc_addr[1] = force_subclients[3];
8848d5d45fbSJean Delvare 		} else {
8850217eae3SWolfgang Grandegger 			sc_addr[1] = 0x48 + ((val1 >> 4) & 0x07);
8868d5d45fbSJean Delvare 		}
8870217eae3SWolfgang Grandegger 		if (sc_addr[0] == sc_addr[1]) {
8888d5d45fbSJean Delvare 			dev_err(&new_client->dev,
8898d5d45fbSJean Delvare 			       "Duplicate addresses 0x%x for subclients.\n",
8900217eae3SWolfgang Grandegger 			       sc_addr[0]);
8918d5d45fbSJean Delvare 			err = -EBUSY;
8928d5d45fbSJean Delvare 			goto ERROR_SC_2;
8938d5d45fbSJean Delvare 		}
8948d5d45fbSJean Delvare 	}
8958d5d45fbSJean Delvare 
896bbc8a569SGuenter Roeck 	for (i = 0; i < num_sc; i++) {
89722e96ce3SWolfram Sang 		data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]);
89822e96ce3SWolfram Sang 		if (IS_ERR(data->lm75[i])) {
899b55f3757SGuenter Roeck 			dev_err(&new_client->dev,
900b55f3757SGuenter Roeck 				"Subclient %d registration at address 0x%x failed.\n",
901b55f3757SGuenter Roeck 				i, sc_addr[i]);
90222e96ce3SWolfram Sang 			err = PTR_ERR(data->lm75[i]);
9038d5d45fbSJean Delvare 			if (i == 1)
9048d5d45fbSJean Delvare 				goto ERROR_SC_3;
9058d5d45fbSJean Delvare 			goto ERROR_SC_2;
9068d5d45fbSJean Delvare 		}
9078d5d45fbSJean Delvare 	}
9088d5d45fbSJean Delvare 
9098d5d45fbSJean Delvare 	return 0;
9108d5d45fbSJean Delvare 
9118d5d45fbSJean Delvare /* Undo inits in case of errors */
9128d5d45fbSJean Delvare ERROR_SC_3:
9130217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[0]);
9148d5d45fbSJean Delvare ERROR_SC_2:
9158d5d45fbSJean Delvare ERROR_SC_1:
9168d5d45fbSJean Delvare 	return err;
9178d5d45fbSJean Delvare }
9188d5d45fbSJean Delvare 
919311ce2efSJim Cromie #define IN_UNIT_ATTRS(X)					\
92034875337SJean Delvare 	&sensor_dev_attr_in##X##_input.dev_attr.attr,		\
92134875337SJean Delvare 	&sensor_dev_attr_in##X##_min.dev_attr.attr,		\
9227d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_max.dev_attr.attr,		\
9237d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_alarm.dev_attr.attr,		\
9247d4a1374SJean Delvare 	&sensor_dev_attr_in##X##_beep.dev_attr.attr
925311ce2efSJim Cromie 
926311ce2efSJim Cromie #define FAN_UNIT_ATTRS(X)					\
92734875337SJean Delvare 	&sensor_dev_attr_fan##X##_input.dev_attr.attr,		\
92834875337SJean Delvare 	&sensor_dev_attr_fan##X##_min.dev_attr.attr,		\
9297d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_div.dev_attr.attr,		\
9307d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_alarm.dev_attr.attr,		\
9317d4a1374SJean Delvare 	&sensor_dev_attr_fan##X##_beep.dev_attr.attr
932311ce2efSJim Cromie 
933311ce2efSJim Cromie #define TEMP_UNIT_ATTRS(X)					\
93434875337SJean Delvare 	&sensor_dev_attr_temp##X##_input.dev_attr.attr,		\
93534875337SJean Delvare 	&sensor_dev_attr_temp##X##_max.dev_attr.attr,		\
9367d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr,	\
9377d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_alarm.dev_attr.attr,		\
9387d4a1374SJean Delvare 	&sensor_dev_attr_temp##X##_beep.dev_attr.attr
939311ce2efSJim Cromie 
940311ce2efSJim Cromie static struct attribute *w83781d_attributes[] = {
941311ce2efSJim Cromie 	IN_UNIT_ATTRS(0),
942311ce2efSJim Cromie 	IN_UNIT_ATTRS(2),
943311ce2efSJim Cromie 	IN_UNIT_ATTRS(3),
944311ce2efSJim Cromie 	IN_UNIT_ATTRS(4),
945311ce2efSJim Cromie 	IN_UNIT_ATTRS(5),
946311ce2efSJim Cromie 	IN_UNIT_ATTRS(6),
947311ce2efSJim Cromie 	FAN_UNIT_ATTRS(1),
948311ce2efSJim Cromie 	FAN_UNIT_ATTRS(2),
949311ce2efSJim Cromie 	FAN_UNIT_ATTRS(3),
950311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(1),
951311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(2),
952311ce2efSJim Cromie 	&dev_attr_cpu0_vid.attr,
953311ce2efSJim Cromie 	&dev_attr_vrm.attr,
954311ce2efSJim Cromie 	&dev_attr_alarms.attr,
955311ce2efSJim Cromie 	&dev_attr_beep_mask.attr,
9562fbbbf14SJean Delvare 	&sensor_dev_attr_beep_enable.dev_attr.attr,
957311ce2efSJim Cromie 	NULL
958311ce2efSJim Cromie };
959311ce2efSJim Cromie static const struct attribute_group w83781d_group = {
960311ce2efSJim Cromie 	.attrs = w83781d_attributes,
961311ce2efSJim Cromie };
962311ce2efSJim Cromie 
96379501333SGuenter Roeck static struct attribute *w83781d_attributes_in1[] = {
964311ce2efSJim Cromie 	IN_UNIT_ATTRS(1),
96579501333SGuenter Roeck 	NULL
96679501333SGuenter Roeck };
96779501333SGuenter Roeck static const struct attribute_group w83781d_group_in1 = {
96879501333SGuenter Roeck 	.attrs = w83781d_attributes_in1,
96979501333SGuenter Roeck };
97079501333SGuenter Roeck 
97179501333SGuenter Roeck static struct attribute *w83781d_attributes_in78[] = {
972311ce2efSJim Cromie 	IN_UNIT_ATTRS(7),
973311ce2efSJim Cromie 	IN_UNIT_ATTRS(8),
97479501333SGuenter Roeck 	NULL
97579501333SGuenter Roeck };
97679501333SGuenter Roeck static const struct attribute_group w83781d_group_in78 = {
97779501333SGuenter Roeck 	.attrs = w83781d_attributes_in78,
97879501333SGuenter Roeck };
97979501333SGuenter Roeck 
98079501333SGuenter Roeck static struct attribute *w83781d_attributes_temp3[] = {
981311ce2efSJim Cromie 	TEMP_UNIT_ATTRS(3),
98279501333SGuenter Roeck 	NULL
98379501333SGuenter Roeck };
98479501333SGuenter Roeck static const struct attribute_group w83781d_group_temp3 = {
98579501333SGuenter Roeck 	.attrs = w83781d_attributes_temp3,
98679501333SGuenter Roeck };
98779501333SGuenter Roeck 
98879501333SGuenter Roeck static struct attribute *w83781d_attributes_pwm12[] = {
98934875337SJean Delvare 	&sensor_dev_attr_pwm1.dev_attr.attr,
99034875337SJean Delvare 	&sensor_dev_attr_pwm2.dev_attr.attr,
99179501333SGuenter Roeck 	&dev_attr_pwm2_enable.attr,
99279501333SGuenter Roeck 	NULL
99379501333SGuenter Roeck };
99479501333SGuenter Roeck static const struct attribute_group w83781d_group_pwm12 = {
99579501333SGuenter Roeck 	.attrs = w83781d_attributes_pwm12,
99679501333SGuenter Roeck };
99779501333SGuenter Roeck 
99879501333SGuenter Roeck static struct attribute *w83781d_attributes_pwm34[] = {
99934875337SJean Delvare 	&sensor_dev_attr_pwm3.dev_attr.attr,
100034875337SJean Delvare 	&sensor_dev_attr_pwm4.dev_attr.attr,
100179501333SGuenter Roeck 	NULL
100279501333SGuenter Roeck };
100379501333SGuenter Roeck static const struct attribute_group w83781d_group_pwm34 = {
100479501333SGuenter Roeck 	.attrs = w83781d_attributes_pwm34,
100579501333SGuenter Roeck };
100679501333SGuenter Roeck 
100779501333SGuenter Roeck static struct attribute *w83781d_attributes_other[] = {
100834875337SJean Delvare 	&sensor_dev_attr_temp1_type.dev_attr.attr,
100934875337SJean Delvare 	&sensor_dev_attr_temp2_type.dev_attr.attr,
101034875337SJean Delvare 	&sensor_dev_attr_temp3_type.dev_attr.attr,
1011311ce2efSJim Cromie 	NULL
1012311ce2efSJim Cromie };
101379501333SGuenter Roeck static const struct attribute_group w83781d_group_other = {
101479501333SGuenter Roeck 	.attrs = w83781d_attributes_other,
1015311ce2efSJim Cromie };
1016311ce2efSJim Cromie 
10177666c13cSJean Delvare /* No clean up is done on error, it's up to the caller */
10187666c13cSJean Delvare static int
w83781d_create_files(struct device * dev,int kind,int is_isa)10197666c13cSJean Delvare w83781d_create_files(struct device *dev, int kind, int is_isa)
10207666c13cSJean Delvare {
10217666c13cSJean Delvare 	int err;
10227666c13cSJean Delvare 
1023c531eb3fSGuenter Roeck 	err = sysfs_create_group(&dev->kobj, &w83781d_group);
1024c531eb3fSGuenter Roeck 	if (err)
10257666c13cSJean Delvare 		return err;
10267666c13cSJean Delvare 
10277666c13cSJean Delvare 	if (kind != w83783s) {
102879501333SGuenter Roeck 		err = sysfs_create_group(&dev->kobj, &w83781d_group_in1);
102979501333SGuenter Roeck 		if (err)
10307666c13cSJean Delvare 			return err;
10317666c13cSJean Delvare 	}
10327666c13cSJean Delvare 	if (kind != as99127f && kind != w83781d && kind != w83783s) {
103379501333SGuenter Roeck 		err = sysfs_create_group(&dev->kobj, &w83781d_group_in78);
103479501333SGuenter Roeck 		if (err)
10357666c13cSJean Delvare 			return err;
10367666c13cSJean Delvare 	}
10377666c13cSJean Delvare 	if (kind != w83783s) {
103879501333SGuenter Roeck 		err = sysfs_create_group(&dev->kobj, &w83781d_group_temp3);
103979501333SGuenter Roeck 		if (err)
10407d4a1374SJean Delvare 			return err;
10417d4a1374SJean Delvare 
10427768aa76SJean Delvare 		if (kind != w83781d) {
10437d4a1374SJean Delvare 			err = sysfs_chmod_file(&dev->kobj,
10447d4a1374SJean Delvare 				&sensor_dev_attr_temp3_alarm.dev_attr.attr,
10457d4a1374SJean Delvare 				S_IRUGO | S_IWUSR);
10467d4a1374SJean Delvare 			if (err)
10477666c13cSJean Delvare 				return err;
10487666c13cSJean Delvare 		}
10497768aa76SJean Delvare 	}
10507666c13cSJean Delvare 
10517666c13cSJean Delvare 	if (kind != w83781d && kind != as99127f) {
105279501333SGuenter Roeck 		err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm12);
105379501333SGuenter Roeck 		if (err)
10547666c13cSJean Delvare 			return err;
10557666c13cSJean Delvare 	}
10567666c13cSJean Delvare 	if (kind == w83782d && !is_isa) {
105779501333SGuenter Roeck 		err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm34);
105879501333SGuenter Roeck 		if (err)
10597666c13cSJean Delvare 			return err;
10607666c13cSJean Delvare 	}
10617666c13cSJean Delvare 
10627666c13cSJean Delvare 	if (kind != as99127f && kind != w83781d) {
106379501333SGuenter Roeck 		err = device_create_file(dev,
106479501333SGuenter Roeck 					 &sensor_dev_attr_temp1_type.dev_attr);
106579501333SGuenter Roeck 		if (err)
106679501333SGuenter Roeck 			return err;
106779501333SGuenter Roeck 		err = device_create_file(dev,
106879501333SGuenter Roeck 					 &sensor_dev_attr_temp2_type.dev_attr);
106979501333SGuenter Roeck 		if (err)
10707666c13cSJean Delvare 			return err;
10717666c13cSJean Delvare 		if (kind != w83783s) {
1072c531eb3fSGuenter Roeck 			err = device_create_file(dev,
1073c531eb3fSGuenter Roeck 					&sensor_dev_attr_temp3_type.dev_attr);
1074c531eb3fSGuenter Roeck 			if (err)
10757666c13cSJean Delvare 				return err;
10767666c13cSJean Delvare 		}
10777666c13cSJean Delvare 	}
10787666c13cSJean Delvare 
10797666c13cSJean Delvare 	return 0;
10807666c13cSJean Delvare }
10817666c13cSJean Delvare 
10820217eae3SWolfgang Grandegger /* Return 0 if detection is successful, -ENODEV otherwise */
10838d5d45fbSJean Delvare static int
w83781d_detect(struct i2c_client * client,struct i2c_board_info * info)1084310ec792SJean Delvare w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
10858d5d45fbSJean Delvare {
1086bab2bf44SJean Delvare 	int val1, val2;
10870217eae3SWolfgang Grandegger 	struct w83781d_data *isa = w83781d_data_if_isa();
10880217eae3SWolfgang Grandegger 	struct i2c_adapter *adapter = client->adapter;
10890217eae3SWolfgang Grandegger 	int address = client->addr;
1090bab2bf44SJean Delvare 	const char *client_name;
10918d5d45fbSJean Delvare 	enum vendor { winbond, asus } vendid;
10928d5d45fbSJean Delvare 
10930217eae3SWolfgang Grandegger 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
10940217eae3SWolfgang Grandegger 		return -ENODEV;
10958d5d45fbSJean Delvare 
1096aff6e00eSGuenter Roeck 	/*
1097aff6e00eSGuenter Roeck 	 * We block updates of the ISA device to minimize the risk of
1098aff6e00eSGuenter Roeck 	 * concurrent access to the same W83781D chip through different
1099aff6e00eSGuenter Roeck 	 * interfaces.
1100aff6e00eSGuenter Roeck 	 */
11010217eae3SWolfgang Grandegger 	if (isa)
11020217eae3SWolfgang Grandegger 		mutex_lock(&isa->update_lock);
11038d5d45fbSJean Delvare 
1104bab2bf44SJean Delvare 	if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
1105bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1106bab2bf44SJean Delvare 			"Detection of w83781d chip failed at step 3\n");
11070217eae3SWolfgang Grandegger 		goto err_nodev;
11088d5d45fbSJean Delvare 	}
1109bab2bf44SJean Delvare 
11100217eae3SWolfgang Grandegger 	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
11110217eae3SWolfgang Grandegger 	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
11128d5d45fbSJean Delvare 	/* Check for Winbond or Asus ID if in bank 0 */
1113bab2bf44SJean Delvare 	if (!(val1 & 0x07) &&
1114bab2bf44SJean Delvare 	    ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
1115bab2bf44SJean Delvare 	     ((val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
1116bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1117bab2bf44SJean Delvare 			"Detection of w83781d chip failed at step 4\n");
11180217eae3SWolfgang Grandegger 		goto err_nodev;
11198d5d45fbSJean Delvare 	}
1120aff6e00eSGuenter Roeck 	/*
1121aff6e00eSGuenter Roeck 	 * If Winbond SMBus, check address at 0x48.
1122aff6e00eSGuenter Roeck 	 * Asus doesn't support, except for as99127f rev.2
1123aff6e00eSGuenter Roeck 	 */
1124bab2bf44SJean Delvare 	if ((!(val1 & 0x80) && val2 == 0xa3) ||
1125bab2bf44SJean Delvare 	    ((val1 & 0x80) && val2 == 0x5c)) {
1126bab2bf44SJean Delvare 		if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
1127bab2bf44SJean Delvare 		    != address) {
1128bab2bf44SJean Delvare 			dev_dbg(&adapter->dev,
1129bab2bf44SJean Delvare 				"Detection of w83781d chip failed at step 5\n");
11300217eae3SWolfgang Grandegger 			goto err_nodev;
11318d5d45fbSJean Delvare 		}
11328d5d45fbSJean Delvare 	}
11338d5d45fbSJean Delvare 
1134bab2bf44SJean Delvare 	/* Put it now into bank 0 and Vendor ID High Byte */
11350217eae3SWolfgang Grandegger 	i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
11360217eae3SWolfgang Grandegger 		(i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
1137311ce2efSJim Cromie 		 & 0x78) | 0x80);
11388d5d45fbSJean Delvare 
1139bab2bf44SJean Delvare 	/* Get the vendor ID */
11400217eae3SWolfgang Grandegger 	val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
11418d5d45fbSJean Delvare 	if (val2 == 0x5c)
11428d5d45fbSJean Delvare 		vendid = winbond;
11438d5d45fbSJean Delvare 	else if (val2 == 0x12)
11448d5d45fbSJean Delvare 		vendid = asus;
11458d5d45fbSJean Delvare 	else {
1146bab2bf44SJean Delvare 		dev_dbg(&adapter->dev,
1147bab2bf44SJean Delvare 			"w83781d chip vendor is neither Winbond nor Asus\n");
11480217eae3SWolfgang Grandegger 		goto err_nodev;
11498d5d45fbSJean Delvare 	}
11508d5d45fbSJean Delvare 
1151bab2bf44SJean Delvare 	/* Determine the chip type. */
11520217eae3SWolfgang Grandegger 	val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
11538d5d45fbSJean Delvare 	if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
1154bab2bf44SJean Delvare 		client_name = "w83781d";
11558d5d45fbSJean Delvare 	else if (val1 == 0x30 && vendid == winbond)
1156bab2bf44SJean Delvare 		client_name = "w83782d";
11577666c13cSJean Delvare 	else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
1158bab2bf44SJean Delvare 		client_name = "w83783s";
11596722feadSJean Delvare 	else if (val1 == 0x31)
1160bab2bf44SJean Delvare 		client_name = "as99127f";
1161bab2bf44SJean Delvare 	else
11620217eae3SWolfgang Grandegger 		goto err_nodev;
1163c6566206SJean Delvare 
1164bab2bf44SJean Delvare 	if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
1165b55f3757SGuenter Roeck 		dev_dbg(&adapter->dev,
1166b55f3757SGuenter Roeck 			"Device at 0x%02x appears to be the same as ISA device\n",
1167b55f3757SGuenter Roeck 			address);
11680217eae3SWolfgang Grandegger 		goto err_nodev;
1169c6566206SJean Delvare 	}
11708d5d45fbSJean Delvare 
11710217eae3SWolfgang Grandegger 	if (isa)
11720217eae3SWolfgang Grandegger 		mutex_unlock(&isa->update_lock);
11730217eae3SWolfgang Grandegger 
1174f2f394dbSWolfram Sang 	strscpy(info->type, client_name, I2C_NAME_SIZE);
11758d5d45fbSJean Delvare 
11760217eae3SWolfgang Grandegger 	return 0;
11770217eae3SWolfgang Grandegger 
11780217eae3SWolfgang Grandegger  err_nodev:
11790217eae3SWolfgang Grandegger 	if (isa)
11800217eae3SWolfgang Grandegger 		mutex_unlock(&isa->update_lock);
11810217eae3SWolfgang Grandegger 	return -ENODEV;
11820217eae3SWolfgang Grandegger }
11830217eae3SWolfgang Grandegger 
w83781d_remove_files(struct device * dev)118479501333SGuenter Roeck static void w83781d_remove_files(struct device *dev)
118579501333SGuenter Roeck {
118679501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group);
118779501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_in1);
118879501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_in78);
118979501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_temp3);
119079501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_pwm12);
119179501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_pwm34);
119279501333SGuenter Roeck 	sysfs_remove_group(&dev->kobj, &w83781d_group_other);
119379501333SGuenter Roeck }
119479501333SGuenter Roeck 
119567487038SStephen Kitt static const struct i2c_device_id w83781d_ids[];
119667487038SStephen Kitt 
w83781d_probe(struct i2c_client * client)119767487038SStephen Kitt static int w83781d_probe(struct i2c_client *client)
11980217eae3SWolfgang Grandegger {
11990217eae3SWolfgang Grandegger 	struct device *dev = &client->dev;
12000217eae3SWolfgang Grandegger 	struct w83781d_data *data;
12010217eae3SWolfgang Grandegger 	int err;
12020217eae3SWolfgang Grandegger 
1203144d2b99SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(struct w83781d_data), GFP_KERNEL);
1204144d2b99SGuenter Roeck 	if (!data)
1205144d2b99SGuenter Roeck 		return -ENOMEM;
12060217eae3SWolfgang Grandegger 
12070217eae3SWolfgang Grandegger 	i2c_set_clientdata(client, data);
12080217eae3SWolfgang Grandegger 	mutex_init(&data->lock);
12090217eae3SWolfgang Grandegger 	mutex_init(&data->update_lock);
12100217eae3SWolfgang Grandegger 
121167487038SStephen Kitt 	data->type = i2c_match_id(w83781d_ids, client)->driver_data;
12120217eae3SWolfgang Grandegger 	data->client = client;
12138d5d45fbSJean Delvare 
12148d5d45fbSJean Delvare 	/* attach secondary i2c lm75-like clients */
12150217eae3SWolfgang Grandegger 	err = w83781d_detect_subclients(client);
12160217eae3SWolfgang Grandegger 	if (err)
1217144d2b99SGuenter Roeck 		return err;
12188d5d45fbSJean Delvare 
12198d5d45fbSJean Delvare 	/* Initialize the chip */
12207666c13cSJean Delvare 	w83781d_init_device(dev);
12218d5d45fbSJean Delvare 
12228d5d45fbSJean Delvare 	/* Register sysfs hooks */
12230217eae3SWolfgang Grandegger 	err = w83781d_create_files(dev, data->type, 0);
12247666c13cSJean Delvare 	if (err)
1225144d2b99SGuenter Roeck 		goto exit_remove_files;
1226311ce2efSJim Cromie 
12271beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(dev);
12281beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
12291beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
1230144d2b99SGuenter Roeck 		goto exit_remove_files;
1231943b0830SMark M. Hoffman 	}
1232943b0830SMark M. Hoffman 
12338d5d45fbSJean Delvare 	return 0;
12348d5d45fbSJean Delvare 
1235144d2b99SGuenter Roeck  exit_remove_files:
123679501333SGuenter Roeck 	w83781d_remove_files(dev);
12370217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[0]);
12380217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[1]);
12398d5d45fbSJean Delvare 	return err;
12408d5d45fbSJean Delvare }
12418d5d45fbSJean Delvare 
1242ed5c2f5fSUwe Kleine-König static void
w83781d_remove(struct i2c_client * client)12430217eae3SWolfgang Grandegger w83781d_remove(struct i2c_client *client)
12448d5d45fbSJean Delvare {
1245943b0830SMark M. Hoffman 	struct w83781d_data *data = i2c_get_clientdata(client);
12460217eae3SWolfgang Grandegger 	struct device *dev = &client->dev;
12478d5d45fbSJean Delvare 
12481beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
124979501333SGuenter Roeck 	w83781d_remove_files(dev);
12508d5d45fbSJean Delvare 
12510217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[0]);
12520217eae3SWolfgang Grandegger 	i2c_unregister_device(data->lm75[1]);
12538d5d45fbSJean Delvare }
12548d5d45fbSJean Delvare 
12558d5d45fbSJean Delvare static int
w83781d_read_value_i2c(struct w83781d_data * data,u16 reg)1256443850ceSWolfgang Grandegger w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
12578d5d45fbSJean Delvare {
12580217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1259443850ceSWolfgang Grandegger 	int res, bank;
12608d5d45fbSJean Delvare 	struct i2c_client *cl;
12618d5d45fbSJean Delvare 
12628d5d45fbSJean Delvare 	bank = (reg >> 8) & 0x0f;
12638d5d45fbSJean Delvare 	if (bank > 2)
12648d5d45fbSJean Delvare 		/* switch banks */
12658d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
12668d5d45fbSJean Delvare 					  bank);
12678d5d45fbSJean Delvare 	if (bank == 0 || bank > 2) {
12688d5d45fbSJean Delvare 		res = i2c_smbus_read_byte_data(client, reg & 0xff);
12698d5d45fbSJean Delvare 	} else {
12708d5d45fbSJean Delvare 		/* switch to subclient */
12718d5d45fbSJean Delvare 		cl = data->lm75[bank - 1];
12728d5d45fbSJean Delvare 		/* convert from ISA to LM75 I2C addresses */
12738d5d45fbSJean Delvare 		switch (reg & 0xff) {
12748d5d45fbSJean Delvare 		case 0x50:	/* TEMP */
127590f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 0);
12768d5d45fbSJean Delvare 			break;
12778d5d45fbSJean Delvare 		case 0x52:	/* CONFIG */
12788d5d45fbSJean Delvare 			res = i2c_smbus_read_byte_data(cl, 1);
12798d5d45fbSJean Delvare 			break;
12808d5d45fbSJean Delvare 		case 0x53:	/* HYST */
128190f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 2);
12828d5d45fbSJean Delvare 			break;
12838d5d45fbSJean Delvare 		case 0x55:	/* OVER */
12848d5d45fbSJean Delvare 		default:
128590f4102cSJean Delvare 			res = i2c_smbus_read_word_swapped(cl, 3);
12868d5d45fbSJean Delvare 			break;
12878d5d45fbSJean Delvare 		}
12888d5d45fbSJean Delvare 	}
12898d5d45fbSJean Delvare 	if (bank > 2)
12908d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1291443850ceSWolfgang Grandegger 
12928d5d45fbSJean Delvare 	return res;
12938d5d45fbSJean Delvare }
12948d5d45fbSJean Delvare 
12958d5d45fbSJean Delvare static int
w83781d_write_value_i2c(struct w83781d_data * data,u16 reg,u16 value)1296443850ceSWolfgang Grandegger w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
12978d5d45fbSJean Delvare {
12980217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1299443850ceSWolfgang Grandegger 	int bank;
13008d5d45fbSJean Delvare 	struct i2c_client *cl;
13018d5d45fbSJean Delvare 
13028d5d45fbSJean Delvare 	bank = (reg >> 8) & 0x0f;
13038d5d45fbSJean Delvare 	if (bank > 2)
13048d5d45fbSJean Delvare 		/* switch banks */
13058d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
13068d5d45fbSJean Delvare 					  bank);
13078d5d45fbSJean Delvare 	if (bank == 0 || bank > 2) {
13088d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, reg & 0xff,
13098d5d45fbSJean Delvare 					  value & 0xff);
13108d5d45fbSJean Delvare 	} else {
13118d5d45fbSJean Delvare 		/* switch to subclient */
13128d5d45fbSJean Delvare 		cl = data->lm75[bank - 1];
13138d5d45fbSJean Delvare 		/* convert from ISA to LM75 I2C addresses */
13148d5d45fbSJean Delvare 		switch (reg & 0xff) {
13158d5d45fbSJean Delvare 		case 0x52:	/* CONFIG */
13168d5d45fbSJean Delvare 			i2c_smbus_write_byte_data(cl, 1, value & 0xff);
13178d5d45fbSJean Delvare 			break;
13188d5d45fbSJean Delvare 		case 0x53:	/* HYST */
131990f4102cSJean Delvare 			i2c_smbus_write_word_swapped(cl, 2, value);
13208d5d45fbSJean Delvare 			break;
13218d5d45fbSJean Delvare 		case 0x55:	/* OVER */
132290f4102cSJean Delvare 			i2c_smbus_write_word_swapped(cl, 3, value);
13238d5d45fbSJean Delvare 			break;
13248d5d45fbSJean Delvare 		}
13258d5d45fbSJean Delvare 	}
13268d5d45fbSJean Delvare 	if (bank > 2)
13278d5d45fbSJean Delvare 		i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
1328443850ceSWolfgang Grandegger 
13298d5d45fbSJean Delvare 	return 0;
13308d5d45fbSJean Delvare }
13318d5d45fbSJean Delvare 
13328d5d45fbSJean Delvare static void
w83781d_init_device(struct device * dev)13337666c13cSJean Delvare w83781d_init_device(struct device *dev)
13348d5d45fbSJean Delvare {
13357666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
13368d5d45fbSJean Delvare 	int i, p;
13378d5d45fbSJean Delvare 	int type = data->type;
13388d5d45fbSJean Delvare 	u8 tmp;
13398d5d45fbSJean Delvare 
1340aff6e00eSGuenter Roeck 	if (reset && type != as99127f) { /*
1341aff6e00eSGuenter Roeck 					  * this resets registers we don't have
1342aff6e00eSGuenter Roeck 					  * documentation for on the as99127f
1343aff6e00eSGuenter Roeck 					  */
1344aff6e00eSGuenter Roeck 		/*
1345aff6e00eSGuenter Roeck 		 * Resetting the chip has been the default for a long time,
1346aff6e00eSGuenter Roeck 		 * but it causes the BIOS initializations (fan clock dividers,
1347aff6e00eSGuenter Roeck 		 * thermal sensor types...) to be lost, so it is now optional.
1348aff6e00eSGuenter Roeck 		 * It might even go away if nobody reports it as being useful,
1349aff6e00eSGuenter Roeck 		 * as I see very little reason why this would be needed at
1350aff6e00eSGuenter Roeck 		 * all.
1351aff6e00eSGuenter Roeck 		 */
1352b55f3757SGuenter Roeck 		dev_info(dev,
1353b55f3757SGuenter Roeck 			 "If reset=1 solved a problem you were having, please report!\n");
1354fabddcd4SJean Delvare 
13558d5d45fbSJean Delvare 		/* save these registers */
135631b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
135731b8dc4dSJean Delvare 		p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
1358aff6e00eSGuenter Roeck 		/*
1359aff6e00eSGuenter Roeck 		 * Reset all except Watchdog values and last conversion values
1360aff6e00eSGuenter Roeck 		 * This sets fan-divs to 2, among others
1361aff6e00eSGuenter Roeck 		 */
136231b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
1363aff6e00eSGuenter Roeck 		/*
1364aff6e00eSGuenter Roeck 		 * Restore the registers and disable power-on abnormal beep.
1365aff6e00eSGuenter Roeck 		 * This saves FAN 1/2/3 input/output values set by BIOS.
1366aff6e00eSGuenter Roeck 		 */
136731b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
136831b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
1369c531eb3fSGuenter Roeck 		/*
1370c531eb3fSGuenter Roeck 		 * Disable master beep-enable (reset turns it on).
1371c531eb3fSGuenter Roeck 		 * Individual beep_mask should be reset to off but for some
1372c531eb3fSGuenter Roeck 		 * reason disabling this bit helps some people not get beeped
1373c531eb3fSGuenter Roeck 		 */
137431b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
13758d5d45fbSJean Delvare 	}
13768d5d45fbSJean Delvare 
1377aff6e00eSGuenter Roeck 	/*
1378aff6e00eSGuenter Roeck 	 * Disable power-on abnormal beep, as advised by the datasheet.
1379aff6e00eSGuenter Roeck 	 * Already done if reset=1.
1380aff6e00eSGuenter Roeck 	 */
1381fabddcd4SJean Delvare 	if (init && !reset && type != as99127f) {
138231b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
138331b8dc4dSJean Delvare 		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
1384fabddcd4SJean Delvare 	}
1385fabddcd4SJean Delvare 
1386303760b4SJean Delvare 	data->vrm = vid_which_vrm();
13878d5d45fbSJean Delvare 
13888d5d45fbSJean Delvare 	if ((type != w83781d) && (type != as99127f)) {
138931b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
13908d5d45fbSJean Delvare 		for (i = 1; i <= 3; i++) {
13918d5d45fbSJean Delvare 			if (!(tmp & BIT_SCFG1[i - 1])) {
1392b26f9330SJean Delvare 				data->sens[i - 1] = 4;
13938d5d45fbSJean Delvare 			} else {
13948d5d45fbSJean Delvare 				if (w83781d_read_value
139531b8dc4dSJean Delvare 				    (data,
13968d5d45fbSJean Delvare 				     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
13978d5d45fbSJean Delvare 					data->sens[i - 1] = 1;
13988d5d45fbSJean Delvare 				else
13998d5d45fbSJean Delvare 					data->sens[i - 1] = 2;
14008d5d45fbSJean Delvare 			}
14018d5d45fbSJean Delvare 			if (type == w83783s && i == 2)
14028d5d45fbSJean Delvare 				break;
14038d5d45fbSJean Delvare 		}
14048d5d45fbSJean Delvare 	}
14058d5d45fbSJean Delvare 
14068d5d45fbSJean Delvare 	if (init && type != as99127f) {
14078d5d45fbSJean Delvare 		/* Enable temp2 */
140831b8dc4dSJean Delvare 		tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
14098d5d45fbSJean Delvare 		if (tmp & 0x01) {
1410b55f3757SGuenter Roeck 			dev_warn(dev,
1411b55f3757SGuenter Roeck 				 "Enabling temp2, readings might not make sense\n");
141231b8dc4dSJean Delvare 			w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
14138d5d45fbSJean Delvare 				tmp & 0xfe);
14148d5d45fbSJean Delvare 		}
14158d5d45fbSJean Delvare 
14168d5d45fbSJean Delvare 		/* Enable temp3 */
14178d5d45fbSJean Delvare 		if (type != w83783s) {
141831b8dc4dSJean Delvare 			tmp = w83781d_read_value(data,
14198d5d45fbSJean Delvare 				W83781D_REG_TEMP3_CONFIG);
14208d5d45fbSJean Delvare 			if (tmp & 0x01) {
1421b55f3757SGuenter Roeck 				dev_warn(dev,
1422b55f3757SGuenter Roeck 					 "Enabling temp3, readings might not make sense\n");
142331b8dc4dSJean Delvare 				w83781d_write_value(data,
14248d5d45fbSJean Delvare 					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
14258d5d45fbSJean Delvare 			}
14268d5d45fbSJean Delvare 		}
14278d5d45fbSJean Delvare 	}
14288d5d45fbSJean Delvare 
14298d5d45fbSJean Delvare 	/* Start monitoring */
143031b8dc4dSJean Delvare 	w83781d_write_value(data, W83781D_REG_CONFIG,
143131b8dc4dSJean Delvare 			    (w83781d_read_value(data,
14328d5d45fbSJean Delvare 						W83781D_REG_CONFIG) & 0xf7)
14338d5d45fbSJean Delvare 			    | 0x01);
14347666c13cSJean Delvare 
14357666c13cSJean Delvare 	/* A few vars need to be filled upon startup */
143634875337SJean Delvare 	for (i = 0; i < 3; i++) {
143734875337SJean Delvare 		data->fan_min[i] = w83781d_read_value(data,
14387666c13cSJean Delvare 					W83781D_REG_FAN_MIN(i));
14397666c13cSJean Delvare 	}
14407666c13cSJean Delvare 
14417666c13cSJean Delvare 	mutex_init(&data->update_lock);
14428d5d45fbSJean Delvare }
14438d5d45fbSJean Delvare 
w83781d_update_device(struct device * dev)14448d5d45fbSJean Delvare static struct w83781d_data *w83781d_update_device(struct device *dev)
14458d5d45fbSJean Delvare {
14467666c13cSJean Delvare 	struct w83781d_data *data = dev_get_drvdata(dev);
14470217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
14488d5d45fbSJean Delvare 	int i;
14498d5d45fbSJean Delvare 
14509a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
14518d5d45fbSJean Delvare 
14528d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
14538d5d45fbSJean Delvare 	    || !data->valid) {
14548d5d45fbSJean Delvare 		dev_dbg(dev, "Starting device update\n");
14558d5d45fbSJean Delvare 
14568d5d45fbSJean Delvare 		for (i = 0; i <= 8; i++) {
14578d5d45fbSJean Delvare 			if (data->type == w83783s && i == 1)
14588d5d45fbSJean Delvare 				continue;	/* 783S has no in1 */
14598d5d45fbSJean Delvare 			data->in[i] =
146031b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN(i));
14618d5d45fbSJean Delvare 			data->in_min[i] =
146231b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN_MIN(i));
14638d5d45fbSJean Delvare 			data->in_max[i] =
146431b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_IN_MAX(i));
146505663368SJean Delvare 			if ((data->type != w83782d) && (i == 6))
14668d5d45fbSJean Delvare 				break;
14678d5d45fbSJean Delvare 		}
146834875337SJean Delvare 		for (i = 0; i < 3; i++) {
146934875337SJean Delvare 			data->fan[i] =
147031b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_FAN(i));
147134875337SJean Delvare 			data->fan_min[i] =
147231b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
14738d5d45fbSJean Delvare 		}
14748d5d45fbSJean Delvare 		if (data->type != w83781d && data->type != as99127f) {
147534875337SJean Delvare 			for (i = 0; i < 4; i++) {
147634875337SJean Delvare 				data->pwm[i] =
147731b8dc4dSJean Delvare 				    w83781d_read_value(data,
147834875337SJean Delvare 						       W83781D_REG_PWM[i]);
1479848ddf11SJean Delvare 				/* Only W83782D on SMBus has PWM3 and PWM4 */
1480848ddf11SJean Delvare 				if ((data->type != w83782d || !client)
148134875337SJean Delvare 				    && i == 1)
14828d5d45fbSJean Delvare 					break;
14838d5d45fbSJean Delvare 			}
14848d5d45fbSJean Delvare 			/* Only PWM2 can be disabled */
148534875337SJean Delvare 			data->pwm2_enable = (w83781d_read_value(data,
14868d5d45fbSJean Delvare 					     W83781D_REG_PWMCLK12) & 0x08) >> 3;
14878d5d45fbSJean Delvare 		}
14888d5d45fbSJean Delvare 
148931b8dc4dSJean Delvare 		data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
14908d5d45fbSJean Delvare 		data->temp_max =
149131b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
14928d5d45fbSJean Delvare 		data->temp_max_hyst =
149331b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
14948d5d45fbSJean Delvare 		data->temp_add[0] =
149531b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP(2));
14968d5d45fbSJean Delvare 		data->temp_max_add[0] =
149731b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
14988d5d45fbSJean Delvare 		data->temp_max_hyst_add[0] =
149931b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
15008d5d45fbSJean Delvare 		if (data->type != w83783s) {
15018d5d45fbSJean Delvare 			data->temp_add[1] =
150231b8dc4dSJean Delvare 			    w83781d_read_value(data, W83781D_REG_TEMP(3));
15038d5d45fbSJean Delvare 			data->temp_max_add[1] =
150431b8dc4dSJean Delvare 			    w83781d_read_value(data,
15058d5d45fbSJean Delvare 					       W83781D_REG_TEMP_OVER(3));
15068d5d45fbSJean Delvare 			data->temp_max_hyst_add[1] =
150731b8dc4dSJean Delvare 			    w83781d_read_value(data,
15088d5d45fbSJean Delvare 					       W83781D_REG_TEMP_HYST(3));
15098d5d45fbSJean Delvare 		}
151031b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
15118d5d45fbSJean Delvare 		data->vid = i & 0x0f;
151231b8dc4dSJean Delvare 		data->vid |= (w83781d_read_value(data,
15138d5d45fbSJean Delvare 					W83781D_REG_CHIPID) & 0x01) << 4;
15148d5d45fbSJean Delvare 		data->fan_div[0] = (i >> 4) & 0x03;
15158d5d45fbSJean Delvare 		data->fan_div[1] = (i >> 6) & 0x03;
151631b8dc4dSJean Delvare 		data->fan_div[2] = (w83781d_read_value(data,
15178d5d45fbSJean Delvare 					W83781D_REG_PIN) >> 6) & 0x03;
15188d5d45fbSJean Delvare 		if ((data->type != w83781d) && (data->type != as99127f)) {
151931b8dc4dSJean Delvare 			i = w83781d_read_value(data, W83781D_REG_VBAT);
15208d5d45fbSJean Delvare 			data->fan_div[0] |= (i >> 3) & 0x04;
15218d5d45fbSJean Delvare 			data->fan_div[1] |= (i >> 4) & 0x04;
15228d5d45fbSJean Delvare 			data->fan_div[2] |= (i >> 5) & 0x04;
15238d5d45fbSJean Delvare 		}
152405663368SJean Delvare 		if (data->type == w83782d) {
152531b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1526c7f5d7edSJean Delvare 						W83782D_REG_ALARM1)
152731b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1528c7f5d7edSJean Delvare 						W83782D_REG_ALARM2) << 8)
152931b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1530c7f5d7edSJean Delvare 						W83782D_REG_ALARM3) << 16);
1531c7f5d7edSJean Delvare 		} else if (data->type == w83783s) {
153231b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1533c7f5d7edSJean Delvare 						W83782D_REG_ALARM1)
153431b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1535c7f5d7edSJean Delvare 						W83782D_REG_ALARM2) << 8);
1536c7f5d7edSJean Delvare 		} else {
1537aff6e00eSGuenter Roeck 			/*
1538aff6e00eSGuenter Roeck 			 * No real-time status registers, fall back to
1539aff6e00eSGuenter Roeck 			 * interrupt status registers
1540aff6e00eSGuenter Roeck 			 */
154131b8dc4dSJean Delvare 			data->alarms = w83781d_read_value(data,
1542c7f5d7edSJean Delvare 						W83781D_REG_ALARM1)
154331b8dc4dSJean Delvare 				     | (w83781d_read_value(data,
1544c7f5d7edSJean Delvare 						W83781D_REG_ALARM2) << 8);
15458d5d45fbSJean Delvare 		}
154631b8dc4dSJean Delvare 		i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
15472fbbbf14SJean Delvare 		data->beep_mask = (i << 8) +
154831b8dc4dSJean Delvare 		    w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
15498d5d45fbSJean Delvare 		if ((data->type != w83781d) && (data->type != as99127f)) {
15508d5d45fbSJean Delvare 			data->beep_mask |=
155131b8dc4dSJean Delvare 			    w83781d_read_value(data,
15528d5d45fbSJean Delvare 					       W83781D_REG_BEEP_INTS3) << 16;
15538d5d45fbSJean Delvare 		}
15548d5d45fbSJean Delvare 		data->last_updated = jiffies;
1555952a11caSPaul Fertser 		data->valid = true;
15568d5d45fbSJean Delvare 	}
15578d5d45fbSJean Delvare 
15589a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
15598d5d45fbSJean Delvare 
15608d5d45fbSJean Delvare 	return data;
15618d5d45fbSJean Delvare }
15628d5d45fbSJean Delvare 
15630217eae3SWolfgang Grandegger static const struct i2c_device_id w83781d_ids[] = {
15640217eae3SWolfgang Grandegger 	{ "w83781d", w83781d, },
15650217eae3SWolfgang Grandegger 	{ "w83782d", w83782d, },
15660217eae3SWolfgang Grandegger 	{ "w83783s", w83783s, },
15670217eae3SWolfgang Grandegger 	{ "as99127f", as99127f },
15680217eae3SWolfgang Grandegger 	{ /* LIST END */ }
15690217eae3SWolfgang Grandegger };
15700217eae3SWolfgang Grandegger MODULE_DEVICE_TABLE(i2c, w83781d_ids);
15710217eae3SWolfgang Grandegger 
15722284ed9fSLinus Walleij static const struct of_device_id w83781d_of_match[] = {
15732284ed9fSLinus Walleij 	{ .compatible = "winbond,w83781d" },
15742284ed9fSLinus Walleij 	{ .compatible = "winbond,w83781g" },
15752284ed9fSLinus Walleij 	{ .compatible = "winbond,w83782d" },
15762284ed9fSLinus Walleij 	{ .compatible = "winbond,w83783s" },
15772284ed9fSLinus Walleij 	{ .compatible = "asus,as99127f" },
15782284ed9fSLinus Walleij 	{ },
15792284ed9fSLinus Walleij };
15802284ed9fSLinus Walleij MODULE_DEVICE_TABLE(of, w83781d_of_match);
15812284ed9fSLinus Walleij 
15820217eae3SWolfgang Grandegger static struct i2c_driver w83781d_driver = {
15830217eae3SWolfgang Grandegger 	.class		= I2C_CLASS_HWMON,
15840217eae3SWolfgang Grandegger 	.driver = {
15850217eae3SWolfgang Grandegger 		.name = "w83781d",
15862284ed9fSLinus Walleij 		.of_match_table = w83781d_of_match,
15870217eae3SWolfgang Grandegger 	},
1588*1975d167SUwe Kleine-König 	.probe		= w83781d_probe,
15890217eae3SWolfgang Grandegger 	.remove		= w83781d_remove,
15900217eae3SWolfgang Grandegger 	.id_table	= w83781d_ids,
15910217eae3SWolfgang Grandegger 	.detect		= w83781d_detect,
1592c3813d6aSJean Delvare 	.address_list	= normal_i2c,
15930217eae3SWolfgang Grandegger };
15940217eae3SWolfgang Grandegger 
15950217eae3SWolfgang Grandegger /*
15960217eae3SWolfgang Grandegger  * ISA related code
15970217eae3SWolfgang Grandegger  */
1598443850ceSWolfgang Grandegger #ifdef CONFIG_ISA
1599443850ceSWolfgang Grandegger 
1600443850ceSWolfgang Grandegger /* ISA device, if found */
1601443850ceSWolfgang Grandegger static struct platform_device *pdev;
1602443850ceSWolfgang Grandegger 
1603443850ceSWolfgang Grandegger static unsigned short isa_address = 0x290;
1604443850ceSWolfgang Grandegger 
1605aff6e00eSGuenter Roeck /*
1606aff6e00eSGuenter Roeck  * I2C devices get this name attribute automatically, but for ISA devices
1607aff6e00eSGuenter Roeck  * we must create it by ourselves.
1608aff6e00eSGuenter Roeck  */
1609443850ceSWolfgang Grandegger static ssize_t
name_show(struct device * dev,struct device_attribute * devattr,char * buf)1610b80b814bSJulia Lawall name_show(struct device *dev, struct device_attribute *devattr, char *buf)
1611443850ceSWolfgang Grandegger {
1612443850ceSWolfgang Grandegger 	struct w83781d_data *data = dev_get_drvdata(dev);
1613360782ddSJean Delvare 	return sprintf(buf, "%s\n", data->name);
1614443850ceSWolfgang Grandegger }
1615b80b814bSJulia Lawall static DEVICE_ATTR_RO(name);
1616443850ceSWolfgang Grandegger 
w83781d_data_if_isa(void)1617443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void)
1618443850ceSWolfgang Grandegger {
1619443850ceSWolfgang Grandegger 	return pdev ? platform_get_drvdata(pdev) : NULL;
1620443850ceSWolfgang Grandegger }
1621443850ceSWolfgang Grandegger 
1622443850ceSWolfgang Grandegger /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
w83781d_alias_detect(struct i2c_client * client,u8 chipid)1623443850ceSWolfgang Grandegger static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
1624443850ceSWolfgang Grandegger {
16250217eae3SWolfgang Grandegger 	struct w83781d_data *isa;
1626443850ceSWolfgang Grandegger 	int i;
1627443850ceSWolfgang Grandegger 
1628443850ceSWolfgang Grandegger 	if (!pdev)	/* No ISA chip */
1629443850ceSWolfgang Grandegger 		return 0;
1630443850ceSWolfgang Grandegger 
1631443850ceSWolfgang Grandegger 	isa = platform_get_drvdata(pdev);
1632443850ceSWolfgang Grandegger 
1633443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
1634443850ceSWolfgang Grandegger 		return 0;	/* Address doesn't match */
1635443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
1636443850ceSWolfgang Grandegger 		return 0;	/* Chip type doesn't match */
1637443850ceSWolfgang Grandegger 
1638aff6e00eSGuenter Roeck 	/*
1639aff6e00eSGuenter Roeck 	 * We compare all the limit registers, the config register and the
1640aff6e00eSGuenter Roeck 	 * interrupt mask registers
1641aff6e00eSGuenter Roeck 	 */
1642443850ceSWolfgang Grandegger 	for (i = 0x2b; i <= 0x3d; i++) {
16430217eae3SWolfgang Grandegger 		if (w83781d_read_value(isa, i) !=
16440217eae3SWolfgang Grandegger 		    i2c_smbus_read_byte_data(client, i))
1645443850ceSWolfgang Grandegger 			return 0;
1646443850ceSWolfgang Grandegger 	}
1647443850ceSWolfgang Grandegger 	if (w83781d_read_value(isa, W83781D_REG_CONFIG) !=
16480217eae3SWolfgang Grandegger 	    i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG))
1649443850ceSWolfgang Grandegger 		return 0;
1650443850ceSWolfgang Grandegger 	for (i = 0x43; i <= 0x46; i++) {
16510217eae3SWolfgang Grandegger 		if (w83781d_read_value(isa, i) !=
16520217eae3SWolfgang Grandegger 		    i2c_smbus_read_byte_data(client, i))
1653443850ceSWolfgang Grandegger 			return 0;
1654443850ceSWolfgang Grandegger 	}
1655443850ceSWolfgang Grandegger 
1656443850ceSWolfgang Grandegger 	return 1;
1657443850ceSWolfgang Grandegger }
1658443850ceSWolfgang Grandegger 
1659443850ceSWolfgang Grandegger static int
w83781d_read_value_isa(struct w83781d_data * data,u16 reg)1660443850ceSWolfgang Grandegger w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
1661443850ceSWolfgang Grandegger {
1662443850ceSWolfgang Grandegger 	int word_sized, res;
1663443850ceSWolfgang Grandegger 
1664443850ceSWolfgang Grandegger 	word_sized = (((reg & 0xff00) == 0x100)
1665443850ceSWolfgang Grandegger 		      || ((reg & 0xff00) == 0x200))
1666443850ceSWolfgang Grandegger 	    && (((reg & 0x00ff) == 0x50)
1667443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x53)
1668443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x55));
1669443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1670443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1671360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1672443850ceSWolfgang Grandegger 		outb_p(reg >> 8,
1673360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1674443850ceSWolfgang Grandegger 	}
1675360782ddSJean Delvare 	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1676360782ddSJean Delvare 	res = inb_p(data->isa_addr + W83781D_DATA_REG_OFFSET);
1677443850ceSWolfgang Grandegger 	if (word_sized) {
1678443850ceSWolfgang Grandegger 		outb_p((reg & 0xff) + 1,
1679360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1680443850ceSWolfgang Grandegger 		res =
1681360782ddSJean Delvare 		    (res << 8) + inb_p(data->isa_addr +
1682443850ceSWolfgang Grandegger 				       W83781D_DATA_REG_OFFSET);
1683443850ceSWolfgang Grandegger 	}
1684443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1685443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1686360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1687360782ddSJean Delvare 		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
1688443850ceSWolfgang Grandegger 	}
1689443850ceSWolfgang Grandegger 	return res;
1690443850ceSWolfgang Grandegger }
1691443850ceSWolfgang Grandegger 
1692443850ceSWolfgang Grandegger static void
w83781d_write_value_isa(struct w83781d_data * data,u16 reg,u16 value)1693443850ceSWolfgang Grandegger w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
1694443850ceSWolfgang Grandegger {
1695443850ceSWolfgang Grandegger 	int word_sized;
1696443850ceSWolfgang Grandegger 
1697443850ceSWolfgang Grandegger 	word_sized = (((reg & 0xff00) == 0x100)
1698443850ceSWolfgang Grandegger 		      || ((reg & 0xff00) == 0x200))
1699443850ceSWolfgang Grandegger 	    && (((reg & 0x00ff) == 0x53)
1700443850ceSWolfgang Grandegger 		|| ((reg & 0x00ff) == 0x55));
1701443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1702443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1703360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1704443850ceSWolfgang Grandegger 		outb_p(reg >> 8,
1705360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1706443850ceSWolfgang Grandegger 	}
1707360782ddSJean Delvare 	outb_p(reg & 0xff, data->isa_addr + W83781D_ADDR_REG_OFFSET);
1708443850ceSWolfgang Grandegger 	if (word_sized) {
1709443850ceSWolfgang Grandegger 		outb_p(value >> 8,
1710360782ddSJean Delvare 		       data->isa_addr + W83781D_DATA_REG_OFFSET);
1711443850ceSWolfgang Grandegger 		outb_p((reg & 0xff) + 1,
1712360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1713443850ceSWolfgang Grandegger 	}
1714360782ddSJean Delvare 	outb_p(value & 0xff, data->isa_addr + W83781D_DATA_REG_OFFSET);
1715443850ceSWolfgang Grandegger 	if (reg & 0xff00) {
1716443850ceSWolfgang Grandegger 		outb_p(W83781D_REG_BANK,
1717360782ddSJean Delvare 		       data->isa_addr + W83781D_ADDR_REG_OFFSET);
1718360782ddSJean Delvare 		outb_p(0, data->isa_addr + W83781D_DATA_REG_OFFSET);
1719443850ceSWolfgang Grandegger 	}
1720443850ceSWolfgang Grandegger }
1721443850ceSWolfgang Grandegger 
1722aff6e00eSGuenter Roeck /*
1723aff6e00eSGuenter Roeck  * The SMBus locks itself, usually, but nothing may access the Winbond between
1724aff6e00eSGuenter Roeck  * bank switches. ISA access must always be locked explicitly!
1725aff6e00eSGuenter Roeck  * We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
1726aff6e00eSGuenter Roeck  * would slow down the W83781D access and should not be necessary.
1727aff6e00eSGuenter Roeck  * There are some ugly typecasts here, but the good news is - they should
1728aff6e00eSGuenter Roeck  * nowhere else be necessary!
1729aff6e00eSGuenter Roeck  */
1730443850ceSWolfgang Grandegger static int
w83781d_read_value(struct w83781d_data * data,u16 reg)1731443850ceSWolfgang Grandegger w83781d_read_value(struct w83781d_data *data, u16 reg)
1732443850ceSWolfgang Grandegger {
17330217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1734443850ceSWolfgang Grandegger 	int res;
1735443850ceSWolfgang Grandegger 
1736443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
17370217eae3SWolfgang Grandegger 	if (client)
1738443850ceSWolfgang Grandegger 		res = w83781d_read_value_i2c(data, reg);
1739443850ceSWolfgang Grandegger 	else
1740443850ceSWolfgang Grandegger 		res = w83781d_read_value_isa(data, reg);
1741443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
1742443850ceSWolfgang Grandegger 	return res;
1743443850ceSWolfgang Grandegger }
1744443850ceSWolfgang Grandegger 
1745443850ceSWolfgang Grandegger static int
w83781d_write_value(struct w83781d_data * data,u16 reg,u16 value)1746443850ceSWolfgang Grandegger w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
1747443850ceSWolfgang Grandegger {
17480217eae3SWolfgang Grandegger 	struct i2c_client *client = data->client;
1749443850ceSWolfgang Grandegger 
1750443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
17510217eae3SWolfgang Grandegger 	if (client)
1752443850ceSWolfgang Grandegger 		w83781d_write_value_i2c(data, reg, value);
1753443850ceSWolfgang Grandegger 	else
1754443850ceSWolfgang Grandegger 		w83781d_write_value_isa(data, reg, value);
1755443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
1756443850ceSWolfgang Grandegger 	return 0;
1757443850ceSWolfgang Grandegger }
1758443850ceSWolfgang Grandegger 
17596c931ae1SBill Pemberton static int
w83781d_isa_probe(struct platform_device * pdev)1760443850ceSWolfgang Grandegger w83781d_isa_probe(struct platform_device *pdev)
1761443850ceSWolfgang Grandegger {
1762443850ceSWolfgang Grandegger 	int err, reg;
1763443850ceSWolfgang Grandegger 	struct w83781d_data *data;
1764443850ceSWolfgang Grandegger 	struct resource *res;
1765443850ceSWolfgang Grandegger 
1766443850ceSWolfgang Grandegger 	/* Reserve the ISA region */
1767443850ceSWolfgang Grandegger 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1768144d2b99SGuenter Roeck 	if (!devm_request_region(&pdev->dev,
1769144d2b99SGuenter Roeck 				 res->start + W83781D_ADDR_REG_OFFSET, 2,
1770144d2b99SGuenter Roeck 				 "w83781d"))
1771144d2b99SGuenter Roeck 		return -EBUSY;
1772443850ceSWolfgang Grandegger 
1773144d2b99SGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct w83781d_data),
1774144d2b99SGuenter Roeck 			    GFP_KERNEL);
1775144d2b99SGuenter Roeck 	if (!data)
1776144d2b99SGuenter Roeck 		return -ENOMEM;
1777144d2b99SGuenter Roeck 
1778443850ceSWolfgang Grandegger 	mutex_init(&data->lock);
1779360782ddSJean Delvare 	data->isa_addr = res->start;
1780443850ceSWolfgang Grandegger 	platform_set_drvdata(pdev, data);
1781443850ceSWolfgang Grandegger 
1782443850ceSWolfgang Grandegger 	reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
1783443850ceSWolfgang Grandegger 	switch (reg) {
1784443850ceSWolfgang Grandegger 	case 0x30:
1785443850ceSWolfgang Grandegger 		data->type = w83782d;
1786360782ddSJean Delvare 		data->name = "w83782d";
1787443850ceSWolfgang Grandegger 		break;
1788443850ceSWolfgang Grandegger 	default:
1789443850ceSWolfgang Grandegger 		data->type = w83781d;
1790360782ddSJean Delvare 		data->name = "w83781d";
1791443850ceSWolfgang Grandegger 	}
1792443850ceSWolfgang Grandegger 
1793443850ceSWolfgang Grandegger 	/* Initialize the W83781D chip */
1794443850ceSWolfgang Grandegger 	w83781d_init_device(&pdev->dev);
1795443850ceSWolfgang Grandegger 
1796443850ceSWolfgang Grandegger 	/* Register sysfs hooks */
1797443850ceSWolfgang Grandegger 	err = w83781d_create_files(&pdev->dev, data->type, 1);
1798443850ceSWolfgang Grandegger 	if (err)
1799443850ceSWolfgang Grandegger 		goto exit_remove_files;
1800443850ceSWolfgang Grandegger 
1801443850ceSWolfgang Grandegger 	err = device_create_file(&pdev->dev, &dev_attr_name);
1802443850ceSWolfgang Grandegger 	if (err)
1803443850ceSWolfgang Grandegger 		goto exit_remove_files;
1804443850ceSWolfgang Grandegger 
1805443850ceSWolfgang Grandegger 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
1806443850ceSWolfgang Grandegger 	if (IS_ERR(data->hwmon_dev)) {
1807443850ceSWolfgang Grandegger 		err = PTR_ERR(data->hwmon_dev);
1808443850ceSWolfgang Grandegger 		goto exit_remove_files;
1809443850ceSWolfgang Grandegger 	}
1810443850ceSWolfgang Grandegger 
1811443850ceSWolfgang Grandegger 	return 0;
1812443850ceSWolfgang Grandegger 
1813443850ceSWolfgang Grandegger  exit_remove_files:
181479501333SGuenter Roeck 	w83781d_remove_files(&pdev->dev);
1815443850ceSWolfgang Grandegger 	device_remove_file(&pdev->dev, &dev_attr_name);
1816443850ceSWolfgang Grandegger 	return err;
1817443850ceSWolfgang Grandegger }
1818443850ceSWolfgang Grandegger 
1819281dfd0bSBill Pemberton static int
w83781d_isa_remove(struct platform_device * pdev)1820443850ceSWolfgang Grandegger w83781d_isa_remove(struct platform_device *pdev)
1821443850ceSWolfgang Grandegger {
1822443850ceSWolfgang Grandegger 	struct w83781d_data *data = platform_get_drvdata(pdev);
1823443850ceSWolfgang Grandegger 
1824443850ceSWolfgang Grandegger 	hwmon_device_unregister(data->hwmon_dev);
182579501333SGuenter Roeck 	w83781d_remove_files(&pdev->dev);
1826443850ceSWolfgang Grandegger 	device_remove_file(&pdev->dev, &dev_attr_name);
1827443850ceSWolfgang Grandegger 
1828443850ceSWolfgang Grandegger 	return 0;
1829443850ceSWolfgang Grandegger }
1830443850ceSWolfgang Grandegger 
1831443850ceSWolfgang Grandegger static struct platform_driver w83781d_isa_driver = {
1832443850ceSWolfgang Grandegger 	.driver = {
1833443850ceSWolfgang Grandegger 		.name = "w83781d",
1834443850ceSWolfgang Grandegger 	},
1835443850ceSWolfgang Grandegger 	.probe = w83781d_isa_probe,
18369e5e9b7aSBill Pemberton 	.remove = w83781d_isa_remove,
1837443850ceSWolfgang Grandegger };
1838443850ceSWolfgang Grandegger 
18397666c13cSJean Delvare /* return 1 if a supported chip is found, 0 otherwise */
18407666c13cSJean Delvare static int __init
w83781d_isa_found(unsigned short address)18417666c13cSJean Delvare w83781d_isa_found(unsigned short address)
18427666c13cSJean Delvare {
18437666c13cSJean Delvare 	int val, save, found = 0;
1844b0bcdd3cSJean Delvare 	int port;
18457666c13cSJean Delvare 
1846aff6e00eSGuenter Roeck 	/*
1847aff6e00eSGuenter Roeck 	 * Some boards declare base+0 to base+7 as a PNP device, some base+4
1848b0bcdd3cSJean Delvare 	 * to base+7 and some base+5 to base+6. So we better request each port
1849aff6e00eSGuenter Roeck 	 * individually for the probing phase.
1850aff6e00eSGuenter Roeck 	 */
1851b0bcdd3cSJean Delvare 	for (port = address; port < address + W83781D_EXTENT; port++) {
1852b0bcdd3cSJean Delvare 		if (!request_region(port, 1, "w83781d")) {
18531ca28218SJoe Perches 			pr_debug("Failed to request port 0x%x\n", port);
1854b0bcdd3cSJean Delvare 			goto release;
18552961cb22SJean Delvare 		}
18562961cb22SJean Delvare 	}
18577666c13cSJean Delvare 
18587666c13cSJean Delvare #define REALLY_SLOW_IO
1859aff6e00eSGuenter Roeck 	/*
1860aff6e00eSGuenter Roeck 	 * We need the timeouts for at least some W83781D-like
1861aff6e00eSGuenter Roeck 	 * chips. But only if we read 'undefined' registers.
1862aff6e00eSGuenter Roeck 	 */
18637666c13cSJean Delvare 	val = inb_p(address + 1);
18647666c13cSJean Delvare 	if (inb_p(address + 2) != val
18657666c13cSJean Delvare 	 || inb_p(address + 3) != val
18667666c13cSJean Delvare 	 || inb_p(address + 7) != val) {
18671ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 1);
18687666c13cSJean Delvare 		goto release;
18697666c13cSJean Delvare 	}
18707666c13cSJean Delvare #undef REALLY_SLOW_IO
18717666c13cSJean Delvare 
1872aff6e00eSGuenter Roeck 	/*
1873aff6e00eSGuenter Roeck 	 * We should be able to change the 7 LSB of the address port. The
1874aff6e00eSGuenter Roeck 	 * MSB (busy flag) should be clear initially, set after the write.
1875aff6e00eSGuenter Roeck 	 */
18767666c13cSJean Delvare 	save = inb_p(address + W83781D_ADDR_REG_OFFSET);
18777666c13cSJean Delvare 	if (save & 0x80) {
18781ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 2);
18797666c13cSJean Delvare 		goto release;
18807666c13cSJean Delvare 	}
18817666c13cSJean Delvare 	val = ~save & 0x7f;
18827666c13cSJean Delvare 	outb_p(val, address + W83781D_ADDR_REG_OFFSET);
18837666c13cSJean Delvare 	if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
18847666c13cSJean Delvare 		outb_p(save, address + W83781D_ADDR_REG_OFFSET);
18851ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 3);
18867666c13cSJean Delvare 		goto release;
18877666c13cSJean Delvare 	}
18887666c13cSJean Delvare 
18897666c13cSJean Delvare 	/* We found a device, now see if it could be a W83781D */
18907666c13cSJean Delvare 	outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
18917666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
18927666c13cSJean Delvare 	if (val & 0x80) {
18931ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 4);
18947666c13cSJean Delvare 		goto release;
18957666c13cSJean Delvare 	}
18967666c13cSJean Delvare 	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
18977666c13cSJean Delvare 	save = inb_p(address + W83781D_DATA_REG_OFFSET);
18987666c13cSJean Delvare 	outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
18997666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
19007666c13cSJean Delvare 	if ((!(save & 0x80) && (val != 0xa3))
19017666c13cSJean Delvare 	 || ((save & 0x80) && (val != 0x5c))) {
19021ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 5);
19037666c13cSJean Delvare 		goto release;
19047666c13cSJean Delvare 	}
19057666c13cSJean Delvare 	outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
19067666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
19077666c13cSJean Delvare 	if (val < 0x03 || val > 0x77) {	/* Not a valid I2C address */
19081ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 6);
19097666c13cSJean Delvare 		goto release;
19107666c13cSJean Delvare 	}
19117666c13cSJean Delvare 
19127666c13cSJean Delvare 	/* The busy flag should be clear again */
19137666c13cSJean Delvare 	if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
19141ca28218SJoe Perches 		pr_debug("Detection failed at step %d\n", 7);
19157666c13cSJean Delvare 		goto release;
19167666c13cSJean Delvare 	}
19177666c13cSJean Delvare 
19187666c13cSJean Delvare 	/* Determine the chip type */
19197666c13cSJean Delvare 	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
19207666c13cSJean Delvare 	save = inb_p(address + W83781D_DATA_REG_OFFSET);
19217666c13cSJean Delvare 	outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
19227666c13cSJean Delvare 	outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
19237666c13cSJean Delvare 	val = inb_p(address + W83781D_DATA_REG_OFFSET);
19247666c13cSJean Delvare 	if ((val & 0xfe) == 0x10	/* W83781D */
192505663368SJean Delvare 	 || val == 0x30)		/* W83782D */
19267666c13cSJean Delvare 		found = 1;
19277666c13cSJean Delvare 
19287666c13cSJean Delvare 	if (found)
19291ca28218SJoe Perches 		pr_info("Found a %s chip at %#x\n",
19307666c13cSJean Delvare 			val == 0x30 ? "W83782D" : "W83781D", (int)address);
19317666c13cSJean Delvare 
19327666c13cSJean Delvare  release:
1933b0bcdd3cSJean Delvare 	for (port--; port >= address; port--)
1934b0bcdd3cSJean Delvare 		release_region(port, 1);
19357666c13cSJean Delvare 	return found;
19367666c13cSJean Delvare }
19377666c13cSJean Delvare 
19387666c13cSJean Delvare static int __init
w83781d_isa_device_add(unsigned short address)19397666c13cSJean Delvare w83781d_isa_device_add(unsigned short address)
19407666c13cSJean Delvare {
19417666c13cSJean Delvare 	struct resource res = {
19427666c13cSJean Delvare 		.start	= address,
194315bde2f1SJean Delvare 		.end	= address + W83781D_EXTENT - 1,
19447666c13cSJean Delvare 		.name	= "w83781d",
19457666c13cSJean Delvare 		.flags	= IORESOURCE_IO,
19467666c13cSJean Delvare 	};
19477666c13cSJean Delvare 	int err;
19487666c13cSJean Delvare 
19497666c13cSJean Delvare 	pdev = platform_device_alloc("w83781d", address);
19507666c13cSJean Delvare 	if (!pdev) {
19517666c13cSJean Delvare 		err = -ENOMEM;
19521ca28218SJoe Perches 		pr_err("Device allocation failed\n");
19537666c13cSJean Delvare 		goto exit;
19547666c13cSJean Delvare 	}
19557666c13cSJean Delvare 
19567666c13cSJean Delvare 	err = platform_device_add_resources(pdev, &res, 1);
19577666c13cSJean Delvare 	if (err) {
19581ca28218SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
19597666c13cSJean Delvare 		goto exit_device_put;
19607666c13cSJean Delvare 	}
19617666c13cSJean Delvare 
19627666c13cSJean Delvare 	err = platform_device_add(pdev);
19637666c13cSJean Delvare 	if (err) {
19641ca28218SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
19657666c13cSJean Delvare 		goto exit_device_put;
19667666c13cSJean Delvare 	}
19677666c13cSJean Delvare 
19687666c13cSJean Delvare 	return 0;
19697666c13cSJean Delvare 
19707666c13cSJean Delvare  exit_device_put:
19717666c13cSJean Delvare 	platform_device_put(pdev);
19727666c13cSJean Delvare  exit:
19737666c13cSJean Delvare 	pdev = NULL;
19747666c13cSJean Delvare 	return err;
19757666c13cSJean Delvare }
19767666c13cSJean Delvare 
19778d5d45fbSJean Delvare static int __init
w83781d_isa_register(void)1978443850ceSWolfgang Grandegger w83781d_isa_register(void)
19798d5d45fbSJean Delvare {
1980fde09509SJean Delvare 	int res;
1981fde09509SJean Delvare 
19827666c13cSJean Delvare 	if (w83781d_isa_found(isa_address)) {
19837666c13cSJean Delvare 		res = platform_driver_register(&w83781d_isa_driver);
19847666c13cSJean Delvare 		if (res)
1985c6566206SJean Delvare 			goto exit;
19867666c13cSJean Delvare 
19877666c13cSJean Delvare 		/* Sets global pdev as a side effect */
19887666c13cSJean Delvare 		res = w83781d_isa_device_add(isa_address);
19897666c13cSJean Delvare 		if (res)
19907666c13cSJean Delvare 			goto exit_unreg_isa_driver;
19917666c13cSJean Delvare 	}
1992fde09509SJean Delvare 
1993fde09509SJean Delvare 	return 0;
19947666c13cSJean Delvare 
19957666c13cSJean Delvare exit_unreg_isa_driver:
19967666c13cSJean Delvare 	platform_driver_unregister(&w83781d_isa_driver);
19977666c13cSJean Delvare exit:
19987666c13cSJean Delvare 	return res;
19998d5d45fbSJean Delvare }
20008d5d45fbSJean Delvare 
2001dd56b638SGeert Uytterhoeven static void
w83781d_isa_unregister(void)2002443850ceSWolfgang Grandegger w83781d_isa_unregister(void)
20038d5d45fbSJean Delvare {
20047666c13cSJean Delvare 	if (pdev) {
20057666c13cSJean Delvare 		platform_device_unregister(pdev);
20067666c13cSJean Delvare 		platform_driver_unregister(&w83781d_isa_driver);
20077666c13cSJean Delvare 	}
2008443850ceSWolfgang Grandegger }
2009443850ceSWolfgang Grandegger #else /* !CONFIG_ISA */
2010443850ceSWolfgang Grandegger 
w83781d_data_if_isa(void)2011443850ceSWolfgang Grandegger static struct w83781d_data *w83781d_data_if_isa(void)
2012443850ceSWolfgang Grandegger {
2013443850ceSWolfgang Grandegger 	return NULL;
2014443850ceSWolfgang Grandegger }
2015443850ceSWolfgang Grandegger 
2016443850ceSWolfgang Grandegger static int
w83781d_alias_detect(struct i2c_client * client,u8 chipid)2017443850ceSWolfgang Grandegger w83781d_alias_detect(struct i2c_client *client, u8 chipid)
2018443850ceSWolfgang Grandegger {
2019443850ceSWolfgang Grandegger 	return 0;
2020443850ceSWolfgang Grandegger }
2021443850ceSWolfgang Grandegger 
2022443850ceSWolfgang Grandegger static int
w83781d_read_value(struct w83781d_data * data,u16 reg)2023443850ceSWolfgang Grandegger w83781d_read_value(struct w83781d_data *data, u16 reg)
2024443850ceSWolfgang Grandegger {
2025443850ceSWolfgang Grandegger 	int res;
2026443850ceSWolfgang Grandegger 
2027443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
2028443850ceSWolfgang Grandegger 	res = w83781d_read_value_i2c(data, reg);
2029443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
2030443850ceSWolfgang Grandegger 
2031443850ceSWolfgang Grandegger 	return res;
2032443850ceSWolfgang Grandegger }
2033443850ceSWolfgang Grandegger 
2034443850ceSWolfgang Grandegger static int
w83781d_write_value(struct w83781d_data * data,u16 reg,u16 value)2035443850ceSWolfgang Grandegger w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
2036443850ceSWolfgang Grandegger {
2037443850ceSWolfgang Grandegger 	mutex_lock(&data->lock);
2038443850ceSWolfgang Grandegger 	w83781d_write_value_i2c(data, reg, value);
2039443850ceSWolfgang Grandegger 	mutex_unlock(&data->lock);
2040443850ceSWolfgang Grandegger 
2041443850ceSWolfgang Grandegger 	return 0;
2042443850ceSWolfgang Grandegger }
2043443850ceSWolfgang Grandegger 
2044443850ceSWolfgang Grandegger static int __init
w83781d_isa_register(void)2045443850ceSWolfgang Grandegger w83781d_isa_register(void)
2046443850ceSWolfgang Grandegger {
2047443850ceSWolfgang Grandegger 	return 0;
2048443850ceSWolfgang Grandegger }
2049443850ceSWolfgang Grandegger 
2050dd56b638SGeert Uytterhoeven static void
w83781d_isa_unregister(void)2051443850ceSWolfgang Grandegger w83781d_isa_unregister(void)
2052443850ceSWolfgang Grandegger {
2053443850ceSWolfgang Grandegger }
2054443850ceSWolfgang Grandegger #endif /* CONFIG_ISA */
2055443850ceSWolfgang Grandegger 
2056443850ceSWolfgang Grandegger static int __init
sensors_w83781d_init(void)2057443850ceSWolfgang Grandegger sensors_w83781d_init(void)
2058443850ceSWolfgang Grandegger {
2059443850ceSWolfgang Grandegger 	int res;
2060443850ceSWolfgang Grandegger 
2061aff6e00eSGuenter Roeck 	/*
2062aff6e00eSGuenter Roeck 	 * We register the ISA device first, so that we can skip the
2063aff6e00eSGuenter Roeck 	 * registration of an I2C interface to the same device.
2064aff6e00eSGuenter Roeck 	 */
2065443850ceSWolfgang Grandegger 	res = w83781d_isa_register();
2066443850ceSWolfgang Grandegger 	if (res)
2067443850ceSWolfgang Grandegger 		goto exit;
2068443850ceSWolfgang Grandegger 
2069443850ceSWolfgang Grandegger 	res = i2c_add_driver(&w83781d_driver);
2070443850ceSWolfgang Grandegger 	if (res)
2071443850ceSWolfgang Grandegger 		goto exit_unreg_isa;
2072443850ceSWolfgang Grandegger 
2073443850ceSWolfgang Grandegger 	return 0;
2074443850ceSWolfgang Grandegger 
2075443850ceSWolfgang Grandegger  exit_unreg_isa:
2076443850ceSWolfgang Grandegger 	w83781d_isa_unregister();
2077443850ceSWolfgang Grandegger  exit:
2078443850ceSWolfgang Grandegger 	return res;
2079443850ceSWolfgang Grandegger }
2080443850ceSWolfgang Grandegger 
2081443850ceSWolfgang Grandegger static void __exit
sensors_w83781d_exit(void)2082443850ceSWolfgang Grandegger sensors_w83781d_exit(void)
2083443850ceSWolfgang Grandegger {
2084443850ceSWolfgang Grandegger 	w83781d_isa_unregister();
20858d5d45fbSJean Delvare 	i2c_del_driver(&w83781d_driver);
20868d5d45fbSJean Delvare }
20878d5d45fbSJean Delvare 
20888d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
20898d5d45fbSJean Delvare 	      "Philip Edelbrock <phil@netroedge.com>, "
20908d5d45fbSJean Delvare 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
20918d5d45fbSJean Delvare MODULE_DESCRIPTION("W83781D driver");
20928d5d45fbSJean Delvare MODULE_LICENSE("GPL");
20938d5d45fbSJean Delvare 
20948d5d45fbSJean Delvare module_init(sensors_w83781d_init);
20958d5d45fbSJean Delvare module_exit(sensors_w83781d_exit);
2096