aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHartmut Rick <linux@rick.claranet.de>2006-03-23 10:37:23 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-22 14:10:32 -0400
commit59ac83677f72ea2cc25b5426e7df9589aa7a5384 (patch)
treea15039b9744a87832af8efa048cc9d229440aa97
parenta4589dbb4e2dc758d1aadb8b5d7e5a598ccb0341 (diff)
[PATCH] smsc47m192: New hwmon driver for SMSC LPC47M192/997
New driver (smsc47m192) which supports voltage and temperature measurement features of SMSC LPC47M192 and LPC47M997 chips. Signed-off-by: Hartmut Rick <linux@rick.claranet.de> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/hwmon/smsc47m192102
-rw-r--r--Documentation/hwmon/sysfs-interface6
-rw-r--r--drivers/hwmon/Kconfig23
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/smsc47m192.c648
5 files changed, 779 insertions, 1 deletions
diff --git a/Documentation/hwmon/smsc47m192 b/Documentation/hwmon/smsc47m192
new file mode 100644
index 000000000000..45d6453cd435
--- /dev/null
+++ b/Documentation/hwmon/smsc47m192
@@ -0,0 +1,102 @@
1Kernel driver smsc47m192
2========================
3
4Supported chips:
5 * SMSC LPC47M192 and LPC47M997
6 Prefix: 'smsc47m192'
7 Addresses scanned: I2C 0x2c - 0x2d
8 Datasheet: The datasheet for LPC47M192 is publicly available from
9 http://www.smsc.com/
10 The LPC47M997 is compatible for hardware monitoring.
11
12Author: Hartmut Rick <linux@rick.claranet.de>
13 Special thanks to Jean Delvare for careful checking
14 of the code and many helpful comments and suggestions.
15
16
17Description
18-----------
19
20This driver implements support for the hardware sensor capabilities
21of the SMSC LPC47M192 and LPC47M997 Super-I/O chips.
22
23These chips support 3 temperature channels and 8 voltage inputs
24as well as CPU voltage VID input.
25
26They do also have fan monitoring and control capabilities, but the
27these features are accessed via ISA bus and are not supported by this
28driver. Use the 'smsc47m1' driver for fan monitoring and control.
29
30Voltages and temperatures are measured by an 8-bit ADC, the resolution
31of the temperatures is 1 bit per degree C.
32Voltages are scaled such that the nominal voltage corresponds to
33192 counts, i.e. 3/4 of the full range. Thus the available range for
34each voltage channel is 0V ... 255/192*(nominal voltage), the resolution
35is 1 bit per (nominal voltage)/192.
36Both voltage and temperature values are scaled by 1000, the sys files
37show voltages in mV and temperatures in units of 0.001 degC.
38
39The +12V analog voltage input channel (in4_input) is multiplexed with
40bit 4 of the encoded CPU voltage. This means that you either get
41a +12V voltage measurement or a 5 bit CPU VID, but not both.
42The default setting is to use the pin as 12V input, and use only 4 bit VID.
43This driver assumes that the information in the configuration register
44is correct, i.e. that the BIOS has updated the configuration if
45the motherboard has this input wired to VID4.
46
47The temperature and voltage readings are updated once every 1.5 seconds.
48Reading them more often repeats the same values.
49
50
51sysfs interface
52---------------
53
54in0_input - +2.5V voltage input
55in1_input - CPU voltage input (nominal 2.25V)
56in2_input - +3.3V voltage input
57in3_input - +5V voltage input
58in4_input - +12V voltage input (may be missing if used as VID4)
59in5_input - Vcc voltage input (nominal 3.3V)
60 This is the supply voltage of the sensor chip itself.
61in6_input - +1.5V voltage input
62in7_input - +1.8V voltage input
63
64in[0-7]_min,
65in[0-7]_max - lower and upper alarm thresholds for in[0-7]_input reading
66
67 All voltages are read and written in mV.
68
69in[0-7]_alarm - alarm flags for voltage inputs
70 These files read '1' in case of alarm, '0' otherwise.
71
72temp1_input - chip temperature measured by on-chip diode
73temp[2-3]_input - temperature measured by external diodes (one of these would
74 typically be wired to the diode inside the CPU)
75
76temp[1-3]_min,
77temp[1-3]_max - lower and upper alarm thresholds for temperatures
78
79temp[1-3]_offset - temperature offset registers
80 The chip adds the offsets stored in these registers to
81 the corresponding temperature readings.
82 Note that temp1 and temp2 offsets share the same register,
83 they cannot both be different from zero at the same time.
84 Writing a non-zero number to one of them will reset the other
85 offset to zero.
86
87 All temperatures and offsets are read and written in
88 units of 0.001 degC.
89
90temp[1-3]_alarm - alarm flags for temperature inputs, '1' in case of alarm,
91 '0' otherwise.
92temp[2-3]_input_fault - diode fault flags for temperature inputs 2 and 3.
93 A fault is detected if the two pins for the corresponding
94 sensor are open or shorted, or any of the two is shorted
95 to ground or Vcc. '1' indicates a diode fault.
96
97cpu0_vid - CPU voltage as received from the CPU
98
99vrm - CPU VID standard used for decoding CPU voltage
100
101 The *_min, *_max, *_offset and vrm files can be read and
102 written, all others are read-only.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index a0d0ab24288e..2d16e1e4017d 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -218,6 +218,12 @@ temp[1-2]_crit_hyst
218 from the critical value. 218 from the critical value.
219 Read/Write value. 219 Read/Write value.
220 220
221temp[1-4]_offset
222 Temperature offset which is added to the temperature reading
223 by the chip.
224 Unit: millidegree Celsius
225 Read/Write value.
226
221 If there are multiple temperature sensors, temp1_* is 227 If there are multiple temperature sensors, temp1_* is
222 generally the sensor inside the chip itself, 228 generally the sensor inside the chip itself,
223 reported as "motherboard temperature". temp2_* to 229 reported as "motherboard temperature". temp2_* to
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a6a8d66129b3..9cf3d9c5962f 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -333,11 +333,32 @@ config SENSORS_SMSC47M1
333 help 333 help
334 If you say yes here you get support for the integrated fan 334 If you say yes here you get support for the integrated fan
335 monitoring and control capabilities of the SMSC LPC47B27x, 335 monitoring and control capabilities of the SMSC LPC47B27x,
336 LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. 336 LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and
337 LPC47M997 chips.
338
339 The temperature and voltage sensor features of the LPC47M192
340 and LPC47M997 are supported by another driver, select also
341 "SMSC LPC47M192 and compatibles" below for those.
337 342
338 This driver can also be built as a module. If so, the module 343 This driver can also be built as a module. If so, the module
339 will be called smsc47m1. 344 will be called smsc47m1.
340 345
346config SENSORS_SMSC47M192
347 tristate "SMSC LPC47M192 and compatibles"
348 depends on HWMON && I2C && EXPERIMENTAL
349 select HWMON_VID
350 help
351 If you say yes here you get support for the temperature and
352 voltage sensors of the SMSC LPC47M192 and LPC47M997 chips.
353
354 The fan monitoring and control capabilities of these chips
355 are supported by another driver, select
356 "SMSC LPC47M10x and compatibles" above. You need both drivers
357 if you want fan control and voltage/temperature sensor support.
358
359 This driver can also be built as a module. If so, the module
360 will be called smsc47m192.
361
341config SENSORS_SMSC47B397 362config SENSORS_SMSC47B397
342 tristate "SMSC LPC47B397-NC" 363 tristate "SMSC LPC47B397-NC"
343 depends on HWMON && I2C && EXPERIMENTAL 364 depends on HWMON && I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index fbdb8d911a72..d0904593c9ea 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
40obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o 40obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
41obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o 41obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
42obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o 42obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
43obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
43obj-$(CONFIG_SENSORS_VIA686A) += via686a.o 44obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
44obj-$(CONFIG_SENSORS_VT8231) += vt8231.o 45obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
45obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o 46obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
new file mode 100644
index 000000000000..bdc4570acf9a
--- /dev/null
+++ b/drivers/hwmon/smsc47m192.c
@@ -0,0 +1,648 @@
1/*
2 smsc47m192.c - Support for hardware monitoring block of
3 SMSC LPC47M192 and LPC47M997 Super I/O chips
4
5 Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de>
6
7 Derived from lm78.c and other chip drivers.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/slab.h>
27#include <linux/jiffies.h>
28#include <linux/i2c.h>
29#include <linux/hwmon.h>
30#include <linux/hwmon-sysfs.h>
31#include <linux/hwmon-vid.h>
32#include <linux/err.h>
33
34/* Addresses to scan */
35static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
36
37/* Insmod parameters */
38I2C_CLIENT_INSMOD_1(smsc47m192);
39
40/* SMSC47M192 registers */
41#define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \
42 (0x50 + (nr) - 6))
43#define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \
44 (0x54 + (((nr) - 6) * 2)))
45#define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \
46 (0x55 + (((nr) - 6) * 2)))
47static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 };
48static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 };
49static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 };
50#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f)
51#define SMSC47M192_REG_ALARM1 0x41
52#define SMSC47M192_REG_ALARM2 0x42
53#define SMSC47M192_REG_VID 0x47
54#define SMSC47M192_REG_VID4 0x49
55#define SMSC47M192_REG_CONFIG 0x40
56#define SMSC47M192_REG_SFR 0x4f
57#define SMSC47M192_REG_COMPANY_ID 0x3e
58#define SMSC47M192_REG_VERSION 0x3f
59
60/* generalised scaling with integer rounding */
61static inline int SCALE(long val, int mul, int div)
62{
63 if (val < 0)
64 return (val * mul - div / 2) / div;
65 else
66 return (val * mul + div / 2) / div;
67}
68
69/* Conversions */
70
71/* smsc47m192 internally scales voltage measurements */
72static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };
73
74static inline unsigned int IN_FROM_REG(u8 reg, int n)
75{
76 return SCALE(reg, nom_mv[n], 192);
77}
78
79static inline u8 IN_TO_REG(unsigned long val, int n)
80{
81 return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
82}
83
84/* TEMP: 0.001 degC units (-128C to +127C)
85 REG: 1C/bit, two's complement */
86static inline s8 TEMP_TO_REG(int val)
87{
88 return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
89}
90
91static inline int TEMP_FROM_REG(s8 val)
92{
93 return val * 1000;
94}
95
96struct smsc47m192_data {
97 struct i2c_client client;
98 struct class_device *class_dev;
99 struct semaphore update_lock;
100 char valid; /* !=0 if following fields are valid */
101 unsigned long last_updated; /* In jiffies */
102
103 u8 in[8]; /* Register value */
104 u8 in_max[8]; /* Register value */
105 u8 in_min[8]; /* Register value */
106 s8 temp[3]; /* Register value */
107 s8 temp_max[3]; /* Register value */
108 s8 temp_min[3]; /* Register value */
109 s8 temp_offset[3]; /* Register value */
110 u16 alarms; /* Register encoding, combined */
111 u8 vid; /* Register encoding, combined */
112 u8 vrm;
113};
114
115static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);
116static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
117 int kind);
118static int smsc47m192_detach_client(struct i2c_client *client);
119static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
120
121static struct i2c_driver smsc47m192_driver = {
122 .driver = {
123 .name = "smsc47m192",
124 },
125 .attach_adapter = smsc47m192_attach_adapter,
126 .detach_client = smsc47m192_detach_client,
127};
128
129/* Voltages */
130static ssize_t show_in(struct device *dev, struct device_attribute *attr,
131 char *buf)
132{
133 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
134 int nr = sensor_attr->index;
135 struct smsc47m192_data *data = smsc47m192_update_device(dev);
136 return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
137}
138
139static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
140 char *buf)
141{
142 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
143 int nr = sensor_attr->index;
144 struct smsc47m192_data *data = smsc47m192_update_device(dev);
145 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
146}
147
148static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
149 char *buf)
150{
151 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
152 int nr = sensor_attr->index;
153 struct smsc47m192_data *data = smsc47m192_update_device(dev);
154 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
155}
156
157static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
158 const char *buf, size_t count)
159{
160 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
161 int nr = sensor_attr->index;
162 struct i2c_client *client = to_i2c_client(dev);
163 struct smsc47m192_data *data = i2c_get_clientdata(client);
164 unsigned long val = simple_strtoul(buf, NULL, 10);
165
166 down(&data->update_lock);
167 data->in_min[nr] = IN_TO_REG(val, nr);
168 i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
169 data->in_min[nr]);
170 up(&data->update_lock);
171 return count;
172}
173
174static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
175 const char *buf, size_t count)
176{
177 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
178 int nr = sensor_attr->index;
179 struct i2c_client *client = to_i2c_client(dev);
180 struct smsc47m192_data *data = i2c_get_clientdata(client);
181 unsigned long val = simple_strtoul(buf, NULL, 10);
182
183 down(&data->update_lock);
184 data->in_max[nr] = IN_TO_REG(val, nr);
185 i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
186 data->in_max[nr]);
187 up(&data->update_lock);
188 return count;
189}
190
191#define show_in_offset(offset) \
192static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
193 show_in, NULL, offset); \
194static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
195 show_in_min, set_in_min, offset); \
196static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
197 show_in_max, set_in_max, offset);
198
199show_in_offset(0)
200show_in_offset(1)
201show_in_offset(2)
202show_in_offset(3)
203show_in_offset(4)
204show_in_offset(5)
205show_in_offset(6)
206show_in_offset(7)
207
208/* Temperatures */
209static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
210 char *buf)
211{
212 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
213 int nr = sensor_attr->index;
214 struct smsc47m192_data *data = smsc47m192_update_device(dev);
215 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
216}
217
218static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
219 char *buf)
220{
221 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
222 int nr = sensor_attr->index;
223 struct smsc47m192_data *data = smsc47m192_update_device(dev);
224 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
225}
226
227static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
228 char *buf)
229{
230 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
231 int nr = sensor_attr->index;
232 struct smsc47m192_data *data = smsc47m192_update_device(dev);
233 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
234}
235
236static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
237 const char *buf, size_t count)
238{
239 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
240 int nr = sensor_attr->index;
241 struct i2c_client *client = to_i2c_client(dev);
242 struct smsc47m192_data *data = i2c_get_clientdata(client);
243 long val = simple_strtol(buf, NULL, 10);
244
245 down(&data->update_lock);
246 data->temp_min[nr] = TEMP_TO_REG(val);
247 i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
248 data->temp_min[nr]);
249 up(&data->update_lock);
250 return count;
251}
252
253static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
254 const char *buf, size_t count)
255{
256 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
257 int nr = sensor_attr->index;
258 struct i2c_client *client = to_i2c_client(dev);
259 struct smsc47m192_data *data = i2c_get_clientdata(client);
260 long val = simple_strtol(buf, NULL, 10);
261
262 down(&data->update_lock);
263 data->temp_max[nr] = TEMP_TO_REG(val);
264 i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
265 data->temp_max[nr]);
266 up(&data->update_lock);
267 return count;
268}
269
270static ssize_t show_temp_offset(struct device *dev, struct device_attribute
271 *attr, char *buf)
272{
273 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
274 int nr = sensor_attr->index;
275 struct smsc47m192_data *data = smsc47m192_update_device(dev);
276 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
277}
278
279static ssize_t set_temp_offset(struct device *dev, struct device_attribute
280 *attr, const char *buf, size_t count)
281{
282 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
283 int nr = sensor_attr->index;
284 struct i2c_client *client = to_i2c_client(dev);
285 struct smsc47m192_data *data = i2c_get_clientdata(client);
286 u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
287 long val = simple_strtol(buf, NULL, 10);
288
289 down(&data->update_lock);
290 data->temp_offset[nr] = TEMP_TO_REG(val);
291 if (nr>1)
292 i2c_smbus_write_byte_data(client,
293 SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
294 else if (data->temp_offset[nr] != 0) {
295 /* offset[0] and offset[1] share the same register,
296 SFR bit 4 activates offset[0] */
297 i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
298 (sfr & 0xef) | (nr==0 ? 0x10 : 0));
299 data->temp_offset[1-nr] = 0;
300 i2c_smbus_write_byte_data(client,
301 SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
302 } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
303 i2c_smbus_write_byte_data(client,
304 SMSC47M192_REG_TEMP_OFFSET(nr), 0);
305 up(&data->update_lock);
306 return count;
307}
308
309#define show_temp_index(index) \
310static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, \
311 show_temp, NULL, index-1); \
312static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR, \
313 show_temp_min, set_temp_min, index-1); \
314static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR, \
315 show_temp_max, set_temp_max, index-1); \
316static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR, \
317 show_temp_offset, set_temp_offset, index-1);
318
319show_temp_index(1)
320show_temp_index(2)
321show_temp_index(3)
322
323/* VID */
324static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
325 char *buf)
326{
327 struct smsc47m192_data *data = smsc47m192_update_device(dev);
328 return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
329}
330static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
331
332static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
333 char *buf)
334{
335 struct smsc47m192_data *data = smsc47m192_update_device(dev);
336 return sprintf(buf, "%d\n", data->vrm);
337}
338
339static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
340 const char *buf, size_t count)
341{
342 struct i2c_client *client = to_i2c_client(dev);
343 struct smsc47m192_data *data = i2c_get_clientdata(client);
344 data->vrm = simple_strtoul(buf, NULL, 10);
345 return count;
346}
347static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
348
349/* Alarms */
350static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
351 char *buf)
352{
353 struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
354 int nr = sensor_attr->index;
355 struct smsc47m192_data *data = smsc47m192_update_device(dev);
356 return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0);
357}
358
359static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
360static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
361static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
362static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
363static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
364static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
365static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
366static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
367static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008);
368static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100);
369static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
370static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
371static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
372
373/* This function is called when:
374 * smsc47m192_driver is inserted (when this module is loaded), for each
375 available adapter
376 * when a new adapter is inserted (and smsc47m192_driver is still present) */
377static int smsc47m192_attach_adapter(struct i2c_adapter *adapter)
378{
379 if (!(adapter->class & I2C_CLASS_HWMON))
380 return 0;
381 return i2c_probe(adapter, &addr_data, smsc47m192_detect);
382}
383
384static void smsc47m192_init_client(struct i2c_client *client)
385{
386 int i;
387 u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
388 u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
389
390 /* select cycle mode (pause 1 sec between updates) */
391 i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
392 (sfr & 0xfd) | 0x02);
393 if (!(config & 0x01)) {
394 /* initialize alarm limits */
395 for (i=0; i<8; i++) {
396 i2c_smbus_write_byte_data(client,
397 SMSC47M192_REG_IN_MIN(i), 0);
398 i2c_smbus_write_byte_data(client,
399 SMSC47M192_REG_IN_MAX(i), 0xff);
400 }
401 for (i=0; i<3; i++) {
402 i2c_smbus_write_byte_data(client,
403 SMSC47M192_REG_TEMP_MIN[i], 0x80);
404 i2c_smbus_write_byte_data(client,
405 SMSC47M192_REG_TEMP_MAX[i], 0x7f);
406 }
407
408 /* start monitoring */
409 i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG,
410 (config & 0xf7) | 0x01);
411 }
412}
413
414/* This function is called by i2c_probe */
415static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
416 int kind)
417{
418 struct i2c_client *client;
419 struct smsc47m192_data *data;
420 int err = 0;
421 int version, config;
422
423 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
424 goto exit;
425
426 if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) {
427 err = -ENOMEM;
428 goto exit;
429 }
430
431 client = &data->client;
432 i2c_set_clientdata(client, data);
433 client->addr = address;
434 client->adapter = adapter;
435 client->driver = &smsc47m192_driver;
436
437 if (kind == 0)
438 kind = smsc47m192;
439
440 /* Detection criteria from sensors_detect script */
441 if (kind < 0) {
442 if (i2c_smbus_read_byte_data(client,
443 SMSC47M192_REG_COMPANY_ID) == 0x55
444 && ((version = i2c_smbus_read_byte_data(client,
445 SMSC47M192_REG_VERSION)) & 0xf0) == 0x20
446 && (i2c_smbus_read_byte_data(client,
447 SMSC47M192_REG_VID) & 0x70) == 0x00
448 && (i2c_smbus_read_byte_data(client,
449 SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
450 dev_info(&adapter->dev,
451 "found SMSC47M192 or SMSC47M997, "
452 "version 2, stepping A%d\n", version & 0x0f);
453 } else {
454 dev_dbg(&adapter->dev,
455 "SMSC47M192 detection failed at 0x%02x\n",
456 address);
457 goto exit_free;
458 }
459 }
460
461 /* Fill in the remaining client fields and put into the global list */
462 strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
463 data->vrm = vid_which_vrm();
464 init_MUTEX(&data->update_lock);
465
466 /* Tell the I2C layer a new client has arrived */
467 if ((err = i2c_attach_client(client)))
468 goto exit_free;
469
470 /* Initialize the SMSC47M192 chip */
471 smsc47m192_init_client(client);
472
473 /* Register sysfs hooks */
474 data->class_dev = hwmon_device_register(&client->dev);
475 if (IS_ERR(data->class_dev)) {
476 err = PTR_ERR(data->class_dev);
477 goto exit_detach;
478 }
479
480 device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
481 device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
482 device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
483 device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
484 device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
485 device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
486 device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
487 device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
488 device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
489 device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
490 device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
491 device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
492 device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
493 device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
494 device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
495 device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
496
497 /* Pin 110 is either in4 (+12V) or VID4 */
498 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
499 if (!(config & 0x20)) {
500 device_create_file(&client->dev,
501 &sensor_dev_attr_in4_input.dev_attr);
502 device_create_file(&client->dev,
503 &sensor_dev_attr_in4_min.dev_attr);
504 device_create_file(&client->dev,
505 &sensor_dev_attr_in4_max.dev_attr);
506 device_create_file(&client->dev,
507 &sensor_dev_attr_in4_alarm.dev_attr);
508 }
509 device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
510 device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
511 device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
512 device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
513 device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
514 device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
515 device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
516 device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
517 device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
518 device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
519 device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
520 device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
521 device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
522 device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
523 device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
524 device_create_file(&client->dev,
525 &sensor_dev_attr_temp1_offset.dev_attr);
526 device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
527 device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
528 device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
529 device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
530 device_create_file(&client->dev,
531 &sensor_dev_attr_temp2_offset.dev_attr);
532 device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
533 device_create_file(&client->dev,
534 &sensor_dev_attr_temp2_input_fault.dev_attr);
535 device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
536 device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
537 device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
538 device_create_file(&client->dev,
539 &sensor_dev_attr_temp3_offset.dev_attr);
540 device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
541 device_create_file(&client->dev,
542 &sensor_dev_attr_temp3_input_fault.dev_attr);
543 device_create_file(&client->dev, &dev_attr_cpu0_vid);
544 device_create_file(&client->dev, &dev_attr_vrm);
545
546 return 0;
547
548exit_detach:
549 i2c_detach_client(client);
550exit_free:
551 kfree(data);
552exit:
553 return err;
554}
555
556static int smsc47m192_detach_client(struct i2c_client *client)
557{
558 struct smsc47m192_data *data = i2c_get_clientdata(client);
559 int err;
560
561 hwmon_device_unregister(data->class_dev);
562
563 if ((err = i2c_detach_client(client)))
564 return err;
565
566 kfree(data);
567
568 return 0;
569}
570
571static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
572{
573 struct i2c_client *client = to_i2c_client(dev);
574 struct smsc47m192_data *data = i2c_get_clientdata(client);
575 int i, config;
576
577 down(&data->update_lock);
578
579 if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
580 || !data->valid) {
581 u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
582
583 dev_dbg(&client->dev, "Starting smsc47m192 update\n");
584
585 for (i = 0; i <= 7; i++) {
586 data->in[i] = i2c_smbus_read_byte_data(client,
587 SMSC47M192_REG_IN(i));
588 data->in_min[i] = i2c_smbus_read_byte_data(client,
589 SMSC47M192_REG_IN_MIN(i));
590 data->in_max[i] = i2c_smbus_read_byte_data(client,
591 SMSC47M192_REG_IN_MAX(i));
592 }
593 for (i = 0; i < 3; i++) {
594 data->temp[i] = i2c_smbus_read_byte_data(client,
595 SMSC47M192_REG_TEMP[i]);
596 data->temp_max[i] = i2c_smbus_read_byte_data(client,
597 SMSC47M192_REG_TEMP_MAX[i]);
598 data->temp_min[i] = i2c_smbus_read_byte_data(client,
599 SMSC47M192_REG_TEMP_MIN[i]);
600 }
601 for (i = 1; i < 3; i++)
602 data->temp_offset[i] = i2c_smbus_read_byte_data(client,
603 SMSC47M192_REG_TEMP_OFFSET(i));
604 /* first offset is temp_offset[0] if SFR bit 4 is set,
605 temp_offset[1] otherwise */
606 if (sfr & 0x10) {
607 data->temp_offset[0] = data->temp_offset[1];
608 data->temp_offset[1] = 0;
609 } else
610 data->temp_offset[0] = 0;
611
612 data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
613 & 0x0f;
614 config = i2c_smbus_read_byte_data(client,
615 SMSC47M192_REG_CONFIG);
616 if (config & 0x20)
617 data->vid |= (i2c_smbus_read_byte_data(client,
618 SMSC47M192_REG_VID4) & 0x01) << 4;
619 data->alarms = i2c_smbus_read_byte_data(client,
620 SMSC47M192_REG_ALARM1) |
621 (i2c_smbus_read_byte_data(client,
622 SMSC47M192_REG_ALARM2) << 8);
623
624 data->last_updated = jiffies;
625 data->valid = 1;
626 }
627
628 up(&data->update_lock);
629
630 return data;
631}
632
633static int __init smsc47m192_init(void)
634{
635 return i2c_add_driver(&smsc47m192_driver);
636}
637
638static void __exit smsc47m192_exit(void)
639{
640 i2c_del_driver(&smsc47m192_driver);
641}
642
643MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>");
644MODULE_DESCRIPTION("SMSC47M192 driver");
645MODULE_LICENSE("GPL");
646
647module_init(smsc47m192_init);
648module_exit(smsc47m192_exit);