Blame view

drivers/hwmon/lm63.c 33.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * lm63.c - driver for the National Semiconductor LM63 temperature sensor
   *          with integrated fan control
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
4
   * Copyright (C) 2004-2008  Jean Delvare <khali@linux-fr.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   * Based on the lm90 driver.
   *
   * The LM63 is a sensor chip made by National Semiconductor. It measures
   * two temperatures (its own and one external one) and the speed of one
   * fan, those speed it can additionally control. Complete datasheet can be
   * obtained from National's website at:
   *   http://www.national.com/pf/LM/LM63.html
   *
   * The LM63 is basically an LM86 with fan speed monitoring and control
   * capabilities added. It misses some of the LM86 features though:
   *  - No low limit for local temperature.
   *  - No critical limit for local temperature.
   *  - Critical limit for remote temperature can be changed only once. We
   *    will consider that the critical limit is read-only.
   *
   * The datasheet isn't very clear about what the tachometer reading is.
   * I had a explanation from National Semiconductor though. The two lower
   * bits of the read value have to be masked out. The value is still 16 bit
   * in width.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
10c08f810   Jean Delvare   [PATCH] I2C: rena...
44
  #include <linux/hwmon-sysfs.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
45
46
  #include <linux/hwmon.h>
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
47
  #include <linux/mutex.h>
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
48
  #include <linux/sysfs.h>
210961c43   Guenter Roeck   hwmon: (lm63) Add...
49
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
  
  /*
   * Addresses to scan
d93ab7807   Jean Delvare   hwmon: (lm63) Fix...
53
54
55
56
   * Address is fully defined internally and cannot be changed except for
   * LM64 which has one pin dedicated to address selection.
   * LM63 and LM96163 have address 0x4c.
   * LM64 can have address 0x18 or 0x4e.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
   */
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
58
  static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
   * The LM63 registers
   */
  
  #define LM63_REG_CONFIG1		0x03
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
65
  #define LM63_REG_CONVRATE		0x04
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
  #define LM63_REG_CONFIG2		0xBF
  #define LM63_REG_CONFIG_FAN		0x4A
  
  #define LM63_REG_TACH_COUNT_MSB		0x47
  #define LM63_REG_TACH_COUNT_LSB		0x46
  #define LM63_REG_TACH_LIMIT_MSB		0x49
  #define LM63_REG_TACH_LIMIT_LSB		0x48
  
  #define LM63_REG_PWM_VALUE		0x4C
  #define LM63_REG_PWM_FREQ		0x4D
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
76
77
78
  #define LM63_REG_LUT_TEMP_HYST		0x4F
  #define LM63_REG_LUT_TEMP(nr)		(0x50 + 2 * (nr))
  #define LM63_REG_LUT_PWM(nr)		(0x51 + 2 * (nr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  #define LM63_REG_LOCAL_TEMP		0x00
  #define LM63_REG_LOCAL_HIGH		0x05
  
  #define LM63_REG_REMOTE_TEMP_MSB	0x01
  #define LM63_REG_REMOTE_TEMP_LSB	0x10
  #define LM63_REG_REMOTE_OFFSET_MSB	0x11
  #define LM63_REG_REMOTE_OFFSET_LSB	0x12
  #define LM63_REG_REMOTE_HIGH_MSB	0x07
  #define LM63_REG_REMOTE_HIGH_LSB	0x13
  #define LM63_REG_REMOTE_LOW_MSB		0x08
  #define LM63_REG_REMOTE_LOW_LSB		0x14
  #define LM63_REG_REMOTE_TCRIT		0x19
  #define LM63_REG_REMOTE_TCRIT_HYST	0x21
  
  #define LM63_REG_ALERT_STATUS		0x02
  #define LM63_REG_ALERT_MASK		0x16
  
  #define LM63_REG_MAN_ID			0xFE
  #define LM63_REG_CHIP_ID		0xFF
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
99
  #define LM96163_REG_TRUTHERM		0x30
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
100
101
  #define LM96163_REG_REMOTE_TEMP_U_MSB	0x31
  #define LM96163_REG_REMOTE_TEMP_U_LSB	0x32
210961c43   Guenter Roeck   hwmon: (lm63) Add...
102
  #define LM96163_REG_CONFIG_ENHANCED	0x45
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
103
104
105
106
  #define LM63_MAX_CONVRATE		9
  
  #define LM63_MAX_CONVRATE_HZ		32
  #define LM96163_MAX_CONVRATE_HZ		26
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
  /*
   * Conversions and various macros
   * For tachometer counts, the LM63 uses 16-bit values.
   * For local temperature and high limit, remote critical limit and hysteresis
44bbe87e9   Steven Cole   [PATCH] Spelling ...
111
   * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
   * For remote temperature, low and high limits, it uses signed 11-bit values
44bbe87e9   Steven Cole   [PATCH] Spelling ...
113
   * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
114
115
116
   * For LM64 the actual remote diode temperature is 16 degree Celsius higher
   * than the register reading. Remote temperature setpoints have to be
   * adapted accordingly.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
   */
  
  #define FAN_FROM_REG(reg)	((reg) == 0xFFFC || (reg) == 0 ? 0 : \
  				 5400000 / (reg))
  #define FAN_TO_REG(val)		((val) <= 82 ? 0xFFFC : \
  				 (5400000 / (val)) & 0xFFFC)
  #define TEMP8_FROM_REG(reg)	((reg) * 1000)
  #define TEMP8_TO_REG(val)	((val) <= -128000 ? -128 : \
  				 (val) >= 127000 ? 127 : \
  				 (val) < 0 ? ((val) - 500) / 1000 : \
  				 ((val) + 500) / 1000)
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
128
129
130
  #define TEMP8U_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 255000 ? 255 : \
  				 ((val) + 500) / 1000)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
  #define TEMP11_FROM_REG(reg)	((reg) / 32 * 125)
  #define TEMP11_TO_REG(val)	((val) <= -128000 ? 0x8000 : \
  				 (val) >= 127875 ? 0x7FE0 : \
  				 (val) < 0 ? ((val) - 62) / 125 * 32 : \
  				 ((val) + 62) / 125 * 32)
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
136
137
138
  #define TEMP11U_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 255875 ? 0xFFE0 : \
  				 ((val) + 62) / 125 * 32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
  #define HYST_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 127000 ? 127 : \
  				 ((val) + 500) / 1000)
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
142
143
  #define UPDATE_INTERVAL(max, rate) \
  			((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  /*
   * Functions declaration
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
147
148
149
  static int lm63_probe(struct i2c_client *client,
  		      const struct i2c_device_id *id);
  static int lm63_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  
  static struct lm63_data *lm63_update_device(struct device *dev);
310ec7921   Jean Delvare   i2c: Drop the kin...
152
  static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  static void lm63_init_client(struct i2c_client *client);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
154
  enum chips { lm63, lm64, lm96163 };
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
155

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
  /*
   * Driver data (common to all clients)
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
159
  static const struct i2c_device_id lm63_id[] = {
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
160
161
  	{ "lm63", lm63 },
  	{ "lm64", lm64 },
210961c43   Guenter Roeck   hwmon: (lm63) Add...
162
  	{ "lm96163", lm96163 },
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
163
164
165
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, lm63_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  static struct i2c_driver lm63_driver = {
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
167
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
168
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
169
170
  		.name	= "lm63",
  	},
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
171
172
173
174
  	.probe		= lm63_probe,
  	.remove		= lm63_remove,
  	.id_table	= lm63_id,
  	.detect		= lm63_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
175
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
182
  };
  
  /*
   * Client data (each client gets its own)
   */
  
  struct lm63_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
183
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
184
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	char valid; /* zero until following fields are valid */
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
186
  	char lut_valid; /* zero until lut fields are valid */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	unsigned long last_updated; /* in jiffies */
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
188
  	unsigned long lut_last_updated; /* in jiffies */
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
189
  	enum chips kind;
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
190
  	int temp2_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191

04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
192
193
  	int update_interval;	/* in milliseconds */
  	int max_convrate_hz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
  	/* registers values */
  	u8 config, config_fan;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
196
197
  	u16 fan[2];	/* 0: input
  			   1: low limit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  	u8 pwm1_freq;
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
199
200
201
  	u8 pwm1[9];	/* 0: current output
  			   1-8: lookup table */
  	s8 temp8[11];	/* 0: local input
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
202
  			   1: local high limit
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
203
204
  			   2: remote critical limit
  			   3-10: lookup table */
786375f72   Guenter Roeck   hwmon: (lm63) Add...
205
  	s16 temp11[4];	/* 0: remote input
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
206
  			   1: remote low limit
786375f72   Guenter Roeck   hwmon: (lm63) Add...
207
208
  			   2: remote high limit
  			   3: remote offset */
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
209
  	u16 temp11u;	/* remote input (unsigned) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	u8 temp2_crit_hyst;
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
211
  	u8 lut_temp_hyst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	u8 alarms;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
213
  	bool pwm_highres;
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
214
  	bool lut_temp_highres;
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
215
  	bool remote_unsigned; /* true if unsigned remote upper limits */
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
216
  	bool trutherm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  };
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
218
219
220
221
222
223
  static inline int temp8_from_reg(struct lm63_data *data, int nr)
  {
  	if (data->remote_unsigned)
  		return TEMP8_FROM_REG((u8)data->temp8[nr]);
  	return TEMP8_FROM_REG(data->temp8[nr]);
  }
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
224
225
226
227
  static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
  {
  	return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  /*
   * Sysfs callback functions and files
   */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
231
232
233
234
235
236
237
  static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
  			char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[attr->index]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
240
241
  static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
  		       const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
245
246
247
248
249
250
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
252
  	mutex_lock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
253
  	data->fan[1] = FAN_TO_REG(val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
255
  				  data->fan[1] & 0xFF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
257
  				  data->fan[1] >> 8);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
258
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  	return count;
  }
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
261
  static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
262
  			 char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  {
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
264
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  	struct lm63_data *data = lm63_update_device(dev);
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
266
  	int nr = attr->index;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
267
268
269
  	int pwm;
  
  	if (data->pwm_highres)
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
270
  		pwm = data->pwm1[nr];
210961c43   Guenter Roeck   hwmon: (lm63) Add...
271
  	else
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
272
273
  		pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
  		       255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
210961c43   Guenter Roeck   hwmon: (lm63) Add...
274
275
276
277
  		       (2 * data->pwm1_freq);
  
  	return sprintf(buf, "%d
  ", pwm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
279
280
  static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
  			const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
  	unsigned long val;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
285
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
  	if (!(data->config_fan & 0x20)) /* register is read-only */
  		return -EPERM;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
288
289
290
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
291
  	val = SENSORS_LIMIT(val, 0, 255);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
292
  	mutex_lock(&data->update_lock);
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
293
294
295
  	data->pwm1[0] = data->pwm_highres ? val :
  			(val * data->pwm1_freq * 2 + 127) / 255;
  	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
296
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  	return count;
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
299
300
  static ssize_t show_pwm1_enable(struct device *dev,
  				struct device_attribute *dummy, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
  {
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%d
  ", data->config_fan & 0x20 ? 1 : 2);
  }
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
306
307
308
309
310
311
312
313
314
  /*
   * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
   * For remote sensor registers temp2_offset has to be considered,
   * for local sensor it must not.
   * So we need separate 8bit accessors for local and remote sensor.
   */
  static ssize_t show_local_temp8(struct device *dev,
  				struct device_attribute *devattr,
  				char *buf)
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
315
316
317
318
319
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%d
  ", TEMP8_FROM_REG(data->temp8[attr->index]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
321

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
322
323
324
325
326
327
  static ssize_t show_remote_temp8(struct device *dev,
  				 struct device_attribute *devattr,
  				 char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
328
329
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, attr->index)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
330
331
  		       + data->temp2_offset);
  }
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
332
333
334
335
336
337
338
339
340
341
  static ssize_t show_lut_temp(struct device *dev,
  			      struct device_attribute *devattr,
  			      char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%d
  ", lut_temp_from_reg(data, attr->index)
  		       + data->temp2_offset);
  }
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
342
343
  static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
  			 const char *buf, size_t count)
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
344
  {
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
345
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
346
347
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
348
349
  	int nr = attr->index;
  	int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
350
351
  	long val;
  	int err;
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
352
  	int temp;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
353
354
355
356
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
357

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
358
  	mutex_lock(&data->update_lock);
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
359
360
361
362
363
364
365
366
367
368
  	if (nr == 2) {
  		if (data->remote_unsigned)
  			temp = TEMP8U_TO_REG(val - data->temp2_offset);
  		else
  			temp = TEMP8_TO_REG(val - data->temp2_offset);
  	} else {
  		temp = TEMP8_TO_REG(val);
  	}
  	data->temp8[nr] = temp;
  	i2c_smbus_write_byte_data(client, reg, temp);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
369
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
370
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
372
373
374
375
376
377
  
  static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
  			   char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  	int nr = attr->index;
  	int temp;
  
  	if (!nr) {
  		/*
  		 * Use unsigned temperature unless its value is zero.
  		 * If it is zero, use signed temperature.
  		 */
  		if (data->temp11u)
  			temp = TEMP11_FROM_REG(data->temp11u);
  		else
  			temp = TEMP11_FROM_REG(data->temp11[nr]);
  	} else {
  		if (data->remote_unsigned && nr == 2)
  			temp = TEMP11_FROM_REG((u16)data->temp11[nr]);
  		else
  			temp = TEMP11_FROM_REG(data->temp11[nr]);
  	}
  	return sprintf(buf, "%d
  ", temp + data->temp2_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
399
400
401
402
  
  static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
  			  const char *buf, size_t count)
  {
786375f72   Guenter Roeck   hwmon: (lm63) Add...
403
  	static const u8 reg[6] = {
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
404
405
406
407
  		LM63_REG_REMOTE_LOW_MSB,
  		LM63_REG_REMOTE_LOW_LSB,
  		LM63_REG_REMOTE_HIGH_MSB,
  		LM63_REG_REMOTE_HIGH_LSB,
786375f72   Guenter Roeck   hwmon: (lm63) Add...
408
409
  		LM63_REG_REMOTE_OFFSET_MSB,
  		LM63_REG_REMOTE_OFFSET_LSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
410
411
412
413
414
  	};
  
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
415
416
  	long val;
  	int err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
417
  	int nr = attr->index;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
418
419
420
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
421
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
422
423
424
425
  	if (data->remote_unsigned && nr == 2)
  		data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset);
  	else
  		data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
426
427
428
429
  	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
  				  data->temp11[nr] >> 8);
  	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
  				  data->temp11[nr] & 0xff);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
430
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
431
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433

662bda283   Guenter Roeck   hwmon: (lm63) Fix...
434
435
436
437
438
439
  /*
   * Hysteresis register holds a relative value, while we want to present
   * an absolute to user-space
   */
  static ssize_t show_temp2_crit_hyst(struct device *dev,
  				    struct device_attribute *dummy, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  {
  	struct lm63_data *data = lm63_update_device(dev);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
442
443
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, 2)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
444
  		       + data->temp2_offset
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
  		       - TEMP8_FROM_REG(data->temp2_crit_hyst));
  }
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
447
448
449
450
451
452
453
454
455
456
457
  static ssize_t show_lut_temp_hyst(struct device *dev,
  				  struct device_attribute *devattr, char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
  
  	return sprintf(buf, "%d
  ", lut_temp_from_reg(data, attr->index)
  		       + data->temp2_offset
  		       - TEMP8_FROM_REG(data->lut_temp_hyst));
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
458
459
460
461
462
463
  /*
   * And now the other way around, user-space provides an absolute
   * hysteresis value and we have to store a relative one
   */
  static ssize_t set_temp2_crit_hyst(struct device *dev,
  				   struct device_attribute *dummy,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
464
  				   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
468
469
  	long val;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	long hyst;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
471
472
473
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
474
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
475
  	hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
  				  HYST_TO_REG(hyst));
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
478
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  	return count;
  }
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  /*
   * Set conversion rate.
   * client->update_lock must be held when calling this function.
   */
  static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data,
  			      unsigned int interval)
  {
  	int i;
  	unsigned int update_interval;
  
  	/* Shift calculations to avoid rounding errors */
  	interval <<= 6;
  
  	/* find the nearest update rate */
  	update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000
  	  / data->max_convrate_hz;
  	for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1)
  		if (interval >= update_interval * 3 / 4)
  			break;
  
  	i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
  	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
  }
  
  static ssize_t show_update_interval(struct device *dev,
  				    struct device_attribute *attr, char *buf)
  {
  	struct lm63_data *data = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%u
  ", data->update_interval);
  }
  
  static ssize_t set_update_interval(struct device *dev,
  				   struct device_attribute *attr,
  				   const char *buf, size_t count)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
  
  	mutex_lock(&data->update_lock);
  	lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  static ssize_t show_type(struct device *dev, struct device_attribute *attr,
  			 char *buf)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
  
  	return sprintf(buf, data->trutherm ? "1
  " : "2
  ");
  }
  
  static ssize_t set_type(struct device *dev, struct device_attribute *attr,
  			const char *buf, size_t count)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
  	unsigned long val;
  	int ret;
  	u8 reg;
  
  	ret = kstrtoul(buf, 10, &val);
  	if (ret < 0)
  		return ret;
  	if (val != 1 && val != 2)
  		return -EINVAL;
  
  	mutex_lock(&data->update_lock);
  	data->trutherm = val == 1;
  	reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
  	i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
  				  reg | (data->trutherm ? 0x02 : 0x00));
  	data->valid = 0;
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
569
570
  static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
  {
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%u
  ", data->alarms);
  }
2d45771e6   Jean Delvare   hwmon: Add indivi...
576
577
578
579
580
581
582
583
584
585
  static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
  			  char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  	struct lm63_data *data = lm63_update_device(dev);
  	int bitnr = attr->index;
  
  	return sprintf(buf, "%u
  ", (data->alarms >> bitnr) & 1);
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
586
587
588
  static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
  static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
  	set_fan, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589

d216f6809   Jean Delvare   hwmon: (lm63) Exp...
590
  static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
  	show_lut_temp, NULL, 3);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 3);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
  	show_lut_temp, NULL, 4);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 4);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
  	show_lut_temp, NULL, 5);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 5);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
  	show_lut_temp, NULL, 6);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 6);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
  	show_lut_temp, NULL, 7);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 7);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
  	show_lut_temp, NULL, 8);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 8);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
  	show_lut_temp, NULL, 9);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 9);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
  	show_lut_temp, NULL, 10);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
  	show_lut_temp_hyst, NULL, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
633
634
  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
635
  	set_temp8, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
637
638
639
640
641
  static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
  	set_temp11, 1);
  static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
  	set_temp11, 2);
786375f72   Guenter Roeck   hwmon: (lm63) Add...
642
643
  static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
  	set_temp11, 3);
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
644
  static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
645
  	set_temp8, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
  	set_temp2_crit_hyst);
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
648
  static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
2d45771e6   Jean Delvare   hwmon: Add indivi...
649
650
651
  /* Individual alarm files */
  static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
7817a39e6   Jean Delvare   hwmon: Fault file...
652
  static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
2d45771e6   Jean Delvare   hwmon: Add indivi...
653
654
655
656
  static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
  static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
  /* Raw alarm file for compatibility */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
658
659
  static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
  		   set_update_interval);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
660
  static struct attribute *lm63_attributes[] = {
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
661
  	&sensor_dev_attr_pwm1.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
662
  	&dev_attr_pwm1_enable.attr,
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
  	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
  	&sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
687
688
689
690
691
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_min.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
786375f72   Guenter Roeck   hwmon: (lm63) Add...
692
  	&sensor_dev_attr_temp2_offset.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
693
694
695
696
  	&sensor_dev_attr_temp2_crit.dev_attr.attr,
  	&dev_attr_temp2_crit_hyst.attr,
  
  	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
7817a39e6   Jean Delvare   hwmon: Fault file...
697
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
698
699
700
701
  	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  	&dev_attr_alarms.attr,
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
702
  	&dev_attr_update_interval.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
703
704
  	NULL
  };
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  /*
   * On LM63, temp2_crit can be set only once, which should be job
   * of the bootloader.
   * On LM64, temp2_crit can always be set.
   * On LM96163, temp2_crit can be set if bit 1 of the configuration
   * register is true.
   */
  static umode_t lm63_attribute_mode(struct kobject *kobj,
  				   struct attribute *attr, int index)
  {
  	struct device *dev = container_of(kobj, struct device, kobj);
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
  
  	if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
  	    && (data->kind == lm64 ||
  		(data->kind == lm96163 && (data->config & 0x02))))
  		return attr->mode | S_IWUSR;
  
  	return attr->mode;
  }
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
726
  static const struct attribute_group lm63_group = {
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
727
  	.is_visible = lm63_attribute_mode,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  	.attrs = lm63_attributes,
  };
  
  static struct attribute *lm63_attributes_fan1[] = {
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  
  	&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
  	NULL
  };
  
  static const struct attribute_group lm63_group_fan1 = {
  	.attrs = lm63_attributes_fan1,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
  /*
   * Real code
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
745
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
746
  static int lm63_detect(struct i2c_client *new_client,
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
747
  		       struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  {
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
749
  	struct i2c_adapter *adapter = new_client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
750
751
  	u8 man_id, chip_id, reg_config1, reg_config2;
  	u8 reg_alert_status, reg_alert_mask;
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
752
  	int address = new_client->addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
755
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

52df6440a   Jean Delvare   hwmon: Clean up d...
757
758
759
760
761
762
763
764
765
766
767
768
769
  	man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
  	chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
  
  	reg_config1 = i2c_smbus_read_byte_data(new_client,
  		      LM63_REG_CONFIG1);
  	reg_config2 = i2c_smbus_read_byte_data(new_client,
  		      LM63_REG_CONFIG2);
  	reg_alert_status = i2c_smbus_read_byte_data(new_client,
  			   LM63_REG_ALERT_STATUS);
  	reg_alert_mask = i2c_smbus_read_byte_data(new_client,
  			 LM63_REG_ALERT_MASK);
  
  	if (man_id != 0x01 /* National Semiconductor */
52df6440a   Jean Delvare   hwmon: Clean up d...
770
771
772
773
774
775
776
777
778
  	 || (reg_config1 & 0x18) != 0x00
  	 || (reg_config2 & 0xF8) != 0x00
  	 || (reg_alert_status & 0x20) != 0x00
  	 || (reg_alert_mask & 0xA4) != 0xA4) {
  		dev_dbg(&adapter->dev,
  			"Unsupported chip (man_id=0x%02X, chip_id=0x%02X)
  ",
  			man_id, chip_id);
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  	}
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
780
781
782
783
  	if (chip_id == 0x41 && address == 0x4c)
  		strlcpy(info->type, "lm63", I2C_NAME_SIZE);
  	else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
  		strlcpy(info->type, "lm64", I2C_NAME_SIZE);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
784
785
  	else if (chip_id == 0x49 && address == 0x4c)
  		strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
786
787
  	else
  		return -ENODEV;
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  
  	return 0;
  }
  
  static int lm63_probe(struct i2c_client *new_client,
  		      const struct i2c_device_id *id)
  {
  	struct lm63_data *data;
  	int err;
  
  	data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
  	if (!data) {
  		err = -ENOMEM;
  		goto exit;
  	}
  
  	i2c_set_clientdata(new_client, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  	data->valid = 0;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
806
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
808
809
810
811
812
813
  	/* Set the device type */
  	data->kind = id->driver_data;
  	if (data->kind == lm64)
  		data->temp2_offset = 16000;
  
  	/* Initialize chip */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
  	lm63_init_client(new_client);
  
  	/* Register sysfs hooks */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
817
818
  	err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
  	if (err)
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
819
  		goto exit_free;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
820
  	if (data->config & 0x04) { /* tachometer enabled */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
821
822
823
  		err = sysfs_create_group(&new_client->dev.kobj,
  					 &lm63_group_fan1);
  		if (err)
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
824
  			goto exit_remove_files;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
825
  	}
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
826
827
828
829
830
831
  	if (data->kind == lm96163) {
  		err = device_create_file(&new_client->dev,
  					 &dev_attr_temp2_type);
  		if (err)
  			goto exit_remove_files;
  	}
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
832

1beeffe43   Tony Jones   hwmon: Convert fr...
833
834
835
  	data->hwmon_dev = hwmon_device_register(&new_client->dev);
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
836
  		goto exit_remove_files;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  
  	return 0;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
840
  exit_remove_files:
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
841
  	device_remove_file(&new_client->dev, &dev_attr_temp2_type);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
842
843
  	sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
  	sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
847
848
  exit_free:
  	kfree(data);
  exit:
  	return err;
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
849
850
851
852
  /*
   * Ideally we shouldn't have to initialize anything, since the BIOS
   * should have taken care of everything
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
  static void lm63_init_client(struct i2c_client *client)
  {
  	struct lm63_data *data = i2c_get_clientdata(client);
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
856
  	u8 convrate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
860
861
862
863
  
  	data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
  	data->config_fan = i2c_smbus_read_byte_data(client,
  						    LM63_REG_CONFIG_FAN);
  
  	/* Start converting if needed */
  	if (data->config & 0x40) { /* standby */
898eb71cb   Joe Perches   Add missing newli...
864
865
  		dev_dbg(&client->dev, "Switching to operational mode
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
868
869
  		data->config &= 0xA7;
  		i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
  					  data->config);
  	}
409c0b5bd   Jean Delvare   hwmon: (lm63) LM6...
870
871
872
  	/* Tachometer is always enabled on LM64 */
  	if (data->kind == lm64)
  		data->config |= 0x04;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
  
  	/* We may need pwm1_freq before ever updating the client data */
  	data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
  	if (data->pwm1_freq == 0)
  		data->pwm1_freq = 1;
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
878
879
880
881
882
883
884
  	switch (data->kind) {
  	case lm63:
  	case lm64:
  		data->max_convrate_hz = LM63_MAX_CONVRATE_HZ;
  		break;
  	case lm96163:
  		data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
885
886
887
  		data->trutherm
  		  = i2c_smbus_read_byte_data(client,
  					     LM96163_REG_TRUTHERM) & 0x02;
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
888
889
890
891
892
893
894
  		break;
  	}
  	convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
  	if (unlikely(convrate > LM63_MAX_CONVRATE))
  		convrate = LM63_MAX_CONVRATE;
  	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
  						convrate);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
895
  	/*
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
896
897
  	 * For LM96163, check if high resolution PWM
  	 * and unsigned temperature format is enabled.
210961c43   Guenter Roeck   hwmon: (lm63) Add...
898
899
900
901
902
  	 */
  	if (data->kind == lm96163) {
  		u8 config_enhanced
  		  = i2c_smbus_read_byte_data(client,
  					     LM96163_REG_CONFIG_ENHANCED);
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
903
904
  		if (config_enhanced & 0x20)
  			data->lut_temp_highres = true;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
905
906
907
908
  		if ((config_enhanced & 0x10)
  		    && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
  			data->pwm_highres = true;
  		if (config_enhanced & 0x08)
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
909
  			data->remote_unsigned = true;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
910
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	/* Show some debug info about the LM63 configuration */
409c0b5bd   Jean Delvare   hwmon: (lm63) LM6...
912
913
914
915
916
  	if (data->kind == lm63)
  		dev_dbg(&client->dev, "Alert/tach pin configured for %s
  ",
  			(data->config & 0x04) ? "tachometer input" :
  			"alert output");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
  	dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz
  ",
  		(data->config_fan & 0x08) ? "1.4" : "360",
  		((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
  	dev_dbg(&client->dev, "PWM output active %s, %s mode
  ",
  		(data->config_fan & 0x10) ? "low" : "high",
  		(data->config_fan & 0x20) ? "manual" : "auto");
  }
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
926
  static int lm63_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
928
  	struct lm63_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929

1beeffe43   Tony Jones   hwmon: Convert fr...
930
  	hwmon_device_unregister(data->hwmon_dev);
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
931
  	device_remove_file(&client->dev, &dev_attr_temp2_type);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
932
933
  	sysfs_remove_group(&client->dev.kobj, &lm63_group);
  	sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
934

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
935
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
942
  	return 0;
  }
  
  static struct lm63_data *lm63_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
943
  	unsigned long next_update;
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
944
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
946
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
948
949
950
951
  	next_update = data->last_updated
  	  + msecs_to_jiffies(data->update_interval) + 1;
  
  	if (time_after(jiffies, next_update) || !data->valid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  		if (data->config & 0x04) { /* tachometer enabled  */
  			/* order matters for fan1_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
954
955
956
957
958
959
960
961
  			data->fan[0] = i2c_smbus_read_byte_data(client,
  				       LM63_REG_TACH_COUNT_LSB) & 0xFC;
  			data->fan[0] |= i2c_smbus_read_byte_data(client,
  					LM63_REG_TACH_COUNT_MSB) << 8;
  			data->fan[1] = (i2c_smbus_read_byte_data(client,
  					LM63_REG_TACH_LIMIT_LSB) & 0xFC)
  				     | (i2c_smbus_read_byte_data(client,
  					LM63_REG_TACH_LIMIT_MSB) << 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
966
967
  		}
  
  		data->pwm1_freq = i2c_smbus_read_byte_data(client,
  				  LM63_REG_PWM_FREQ);
  		if (data->pwm1_freq == 0)
  			data->pwm1_freq = 1;
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
968
969
  		data->pwm1[0] = i2c_smbus_read_byte_data(client,
  				LM63_REG_PWM_VALUE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
971
972
973
974
  		data->temp8[0] = i2c_smbus_read_byte_data(client,
  				 LM63_REG_LOCAL_TEMP);
  		data->temp8[1] = i2c_smbus_read_byte_data(client,
  				 LM63_REG_LOCAL_HIGH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
  
  		/* order matters for temp2_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
977
978
979
980
981
  		data->temp11[0] = i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_TEMP_MSB) << 8;
  		data->temp11[0] |= i2c_smbus_read_byte_data(client,
  				   LM63_REG_REMOTE_TEMP_LSB);
  		data->temp11[1] = (i2c_smbus_read_byte_data(client,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
  				  LM63_REG_REMOTE_LOW_MSB) << 8)
  				| i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_LOW_LSB);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
985
986
987
988
  		data->temp11[2] = (i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_HIGH_MSB) << 8)
  				| i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_HIGH_LSB);
786375f72   Guenter Roeck   hwmon: (lm63) Add...
989
990
991
992
  		data->temp11[3] = (i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_OFFSET_MSB) << 8)
  				| i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_OFFSET_LSB);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
993
994
995
996
997
998
  
  		if (data->kind == lm96163)
  			data->temp11u = (i2c_smbus_read_byte_data(client,
  					LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
  				      | i2c_smbus_read_byte_data(client,
  					LM96163_REG_REMOTE_TEMP_U_LSB);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
999
1000
  		data->temp8[2] = i2c_smbus_read_byte_data(client,
  				 LM63_REG_REMOTE_TCRIT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
1005
1006
1007
1008
1009
  		data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
  					LM63_REG_REMOTE_TCRIT_HYST);
  
  		data->alarms = i2c_smbus_read_byte_data(client,
  			       LM63_REG_ALERT_STATUS) & 0x7F;
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
d216f6809   Jean Delvare   hwmon: (lm63) Exp...
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
  	    !data->lut_valid) {
  		for (i = 0; i < 8; i++) {
  			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
  					    LM63_REG_LUT_PWM(i));
  			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
  					     LM63_REG_LUT_TEMP(i));
  		}
  		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
  				      LM63_REG_LUT_TEMP_HYST);
  
  		data->lut_last_updated = jiffies;
  		data->lut_valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
1024
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  
  	return data;
  }
  
  static int __init sensors_lm63_init(void)
  {
  	return i2c_add_driver(&lm63_driver);
  }
  
  static void __exit sensors_lm63_exit(void)
  {
  	i2c_del_driver(&lm63_driver);
  }
  
  MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
  MODULE_DESCRIPTION("LM63 driver");
  MODULE_LICENSE("GPL");
  
  module_init(sensors_lm63_init);
  module_exit(sensors_lm63_exit);