Blame view

drivers/hwmon/lm63.c 23 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
53
54
  
  /*
   * Addresses to scan
   * Address is fully defined internally and cannot be changed.
   */
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
55
  static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
   * The LM63 registers
   */
  
  #define LM63_REG_CONFIG1		0x03
  #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
  
  #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
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
92
93
  #define LM96163_REG_REMOTE_TEMP_U_MSB	0x31
  #define LM96163_REG_REMOTE_TEMP_U_LSB	0x32
210961c43   Guenter Roeck   hwmon: (lm63) Add...
94
  #define LM96163_REG_CONFIG_ENHANCED	0x45
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  /*
   * 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 ...
99
   * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
   * For remote temperature, low and high limits, it uses signed 11-bit values
44bbe87e9   Steven Cole   [PATCH] Spelling ...
101
   * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
102
103
104
   * 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
   */
  
  #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)
  #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...
121
122
123
  #define TEMP11U_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 255875 ? 0xFFE0 : \
  				 ((val) + 62) / 125 * 32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
130
  #define HYST_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 127000 ? 127 : \
  				 ((val) + 500) / 1000)
  
  /*
   * Functions declaration
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
131
132
133
  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
134
135
  
  static struct lm63_data *lm63_update_device(struct device *dev);
310ec7921   Jean Delvare   i2c: Drop the kin...
136
  static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  static void lm63_init_client(struct i2c_client *client);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
138
  enum chips { lm63, lm64, lm96163 };
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
139

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
  /*
   * Driver data (common to all clients)
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
143
  static const struct i2c_device_id lm63_id[] = {
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
144
145
  	{ "lm63", lm63 },
  	{ "lm64", lm64 },
210961c43   Guenter Roeck   hwmon: (lm63) Add...
146
  	{ "lm96163", lm96163 },
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
147
148
149
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, lm63_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  static struct i2c_driver lm63_driver = {
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
151
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
152
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
153
154
  		.name	= "lm63",
  	},
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
155
156
157
158
  	.probe		= lm63_probe,
  	.remove		= lm63_remove,
  	.id_table	= lm63_id,
  	.detect		= lm63_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
159
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
  };
  
  /*
   * Client data (each client gets its own)
   */
  
  struct lm63_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
167
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
168
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  	char valid; /* zero until following fields are valid */
  	unsigned long last_updated; /* in jiffies */
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
171
172
  	int kind;
  	int temp2_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  
  	/* registers values */
  	u8 config, config_fan;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
176
177
  	u16 fan[2];	/* 0: input
  			   1: low limit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  	u8 pwm1_freq;
  	u8 pwm1_value;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
180
181
182
  	s8 temp8[3];	/* 0: local input
  			   1: local high limit
  			   2: remote critical limit */
786375f72   Guenter Roeck   hwmon: (lm63) Add...
183
  	s16 temp11[4];	/* 0: remote input
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
184
  			   1: remote low limit
786375f72   Guenter Roeck   hwmon: (lm63) Add...
185
186
  			   2: remote high limit
  			   3: remote offset */
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
187
  	u16 temp11u;	/* remote input (unsigned) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
  	u8 temp2_crit_hyst;
  	u8 alarms;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
190
  	bool pwm_highres;
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
191
  	bool remote_unsigned; /* true if unsigned remote upper limits */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  };
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
193
194
195
196
197
198
  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]);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
  /*
   * Sysfs callback functions and files
   */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
202
203
204
205
206
207
208
  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
209
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
211
212
  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
213
214
215
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
216
217
218
219
220
221
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
223
  	mutex_lock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
224
  	data->fan[1] = FAN_TO_REG(val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
226
  				  data->fan[1] & 0xFF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
228
  				  data->fan[1] >> 8);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
229
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
  	return count;
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
232
233
  static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
  			 char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  {
  	struct lm63_data *data = lm63_update_device(dev);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
236
237
238
239
240
241
  	int pwm;
  
  	if (data->pwm_highres)
  		pwm = data->pwm1_value;
  	else
  		pwm = data->pwm1_value >= 2 * data->pwm1_freq ?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  		       255 : (data->pwm1_value * 255 + data->pwm1_freq) /
210961c43   Guenter Roeck   hwmon: (lm63) Add...
243
244
245
246
  		       (2 * data->pwm1_freq);
  
  	return sprintf(buf, "%d
  ", pwm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
248
249
  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
250
251
252
253
  {
  	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...
254
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  	if (!(data->config_fan & 0x20)) /* register is read-only */
  		return -EPERM;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
257
258
259
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
260
  	val = SENSORS_LIMIT(val, 0, 255);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
261
  	mutex_lock(&data->update_lock);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
262
  	data->pwm1_value = data->pwm_highres ? val :
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
  			   (val * data->pwm1_freq * 2 + 127) / 255;
  	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
265
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
  	return count;
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
268
269
  static ssize_t show_pwm1_enable(struct device *dev,
  				struct device_attribute *dummy, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
  {
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%d
  ", data->config_fan & 0x20 ? 1 : 2);
  }
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
275
276
277
278
279
280
281
282
283
  /*
   * 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...
284
285
286
287
288
  {
  	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
289
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
290

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
291
292
293
294
295
296
  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...
297
298
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, attr->index)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
299
300
301
302
303
304
  		       + data->temp2_offset);
  }
  
  static ssize_t set_local_temp8(struct device *dev,
  			       struct device_attribute *dummy,
  			       const char *buf, size_t count)
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
305
306
307
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
308
309
310
311
312
313
  	long val;
  	int err;
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
314

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
315
  	mutex_lock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
316
317
  	data->temp8[1] = TEMP8_TO_REG(val);
  	i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
318
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
319
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
321
322
323
324
325
326
  
  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...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  	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
347
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
348
349
350
351
  
  static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
  			  const char *buf, size_t count)
  {
786375f72   Guenter Roeck   hwmon: (lm63) Add...
352
  	static const u8 reg[6] = {
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
353
354
355
356
  		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...
357
358
  		LM63_REG_REMOTE_OFFSET_MSB,
  		LM63_REG_REMOTE_OFFSET_LSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
359
360
361
362
363
  	};
  
  	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...
364
365
  	long val;
  	int err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
366
  	int nr = attr->index;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
367
368
369
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
370
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
371
372
373
374
  	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...
375
376
377
378
  	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...
379
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
380
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

662bda283   Guenter Roeck   hwmon: (lm63) Fix...
383
384
385
386
387
388
  /*
   * 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
389
390
  {
  	struct lm63_data *data = lm63_update_device(dev);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
391
392
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, 2)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
393
  		       + data->temp2_offset
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
  		       - TEMP8_FROM_REG(data->temp2_crit_hyst));
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
396
397
398
399
400
401
  /*
   * 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...
402
  				   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
406
407
  	long val;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  	long hyst;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
409
410
411
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
412
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
413
  	hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
  	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
  				  HYST_TO_REG(hyst));
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
416
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  	return count;
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
419
420
  static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
  {
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%u
  ", data->alarms);
  }
2d45771e6   Jean Delvare   hwmon: Add indivi...
426
427
428
429
430
431
432
433
434
435
  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...
436
437
438
  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
439
440
441
  
  static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
  static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
442
443
444
  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,
  	set_local_temp8, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
446
447
448
449
450
  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...
451
452
  static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
  	set_temp11, 3);
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
453
454
455
456
457
458
  /*
   * On LM63, temp2_crit can be set only once, which should be job
   * of the bootloader.
   */
  static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
  	NULL, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
  	set_temp2_crit_hyst);
2d45771e6   Jean Delvare   hwmon: Add indivi...
461
462
463
  /* 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...
464
  static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
2d45771e6   Jean Delvare   hwmon: Add indivi...
465
466
467
468
  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
469
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
470
471
472
473
474
475
476
477
  static struct attribute *lm63_attributes[] = {
  	&dev_attr_pwm1.attr,
  	&dev_attr_pwm1_enable.attr,
  	&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...
478
  	&sensor_dev_attr_temp2_offset.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
479
480
481
482
  	&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...
483
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  	&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,
  	NULL
  };
  
  static const struct attribute_group lm63_group = {
  	.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
506
507
508
  /*
   * Real code
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
509
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
510
  static int lm63_detect(struct i2c_client *new_client,
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
511
  		       struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  {
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
513
  	struct i2c_adapter *adapter = new_client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
514
515
  	u8 man_id, chip_id, reg_config1, reg_config2;
  	u8 reg_alert_status, reg_alert_mask;
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
516
  	int address = new_client->addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
519
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520

52df6440a   Jean Delvare   hwmon: Clean up d...
521
522
523
524
525
526
527
528
529
530
531
532
533
  	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...
534
535
536
537
538
539
540
541
542
  	 || (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
543
  	}
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
544
545
546
547
  	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...
548
549
  	else if (chip_id == 0x49 && address == 0x4c)
  		strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
550
551
  	else
  		return -ENODEV;
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  
  	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
569
  	data->valid = 0;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
570
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
572
573
574
575
576
577
  	/* 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
578
579
580
  	lm63_init_client(new_client);
  
  	/* Register sysfs hooks */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
581
582
  	err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
  	if (err)
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
583
  		goto exit_free;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
584
  	if (data->config & 0x04) { /* tachometer enabled */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
585
586
587
  		err = sysfs_create_group(&new_client->dev.kobj,
  					 &lm63_group_fan1);
  		if (err)
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
588
  			goto exit_remove_files;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
589
  	}
1beeffe43   Tony Jones   hwmon: Convert fr...
590
591
592
  	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...
593
  		goto exit_remove_files;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
  
  	return 0;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
597
598
599
  exit_remove_files:
  	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
600
601
602
603
604
  exit_free:
  	kfree(data);
  exit:
  	return err;
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
605
606
607
608
  /*
   * 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
609
610
611
612
613
614
615
616
617
618
  static void lm63_init_client(struct i2c_client *client)
  {
  	struct lm63_data *data = i2c_get_clientdata(client);
  
  	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...
619
620
  		dev_dbg(&client->dev, "Switching to operational mode
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
  		data->config &= 0xA7;
  		i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
  					  data->config);
  	}
  
  	/* 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;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
630
  	/*
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
631
632
  	 * For LM96163, check if high resolution PWM
  	 * and unsigned temperature format is enabled.
210961c43   Guenter Roeck   hwmon: (lm63) Add...
633
634
635
636
637
638
639
640
641
  	 */
  	if (data->kind == lm96163) {
  		u8 config_enhanced
  		  = i2c_smbus_read_byte_data(client,
  					     LM96163_REG_CONFIG_ENHANCED);
  		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...
642
  			data->remote_unsigned = true;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
643
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  	/* Show some debug info about the LM63 configuration */
  	dev_dbg(&client->dev, "Alert/tach pin configured for %s
  ",
  		(data->config & 0x04) ? "tachometer input" :
  		"alert output");
  	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...
658
  static int lm63_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
660
  	struct lm63_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661

1beeffe43   Tony Jones   hwmon: Convert fr...
662
  	hwmon_device_unregister(data->hwmon_dev);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
663
664
  	sysfs_remove_group(&client->dev.kobj, &lm63_group);
  	sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
665

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
666
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
672
673
  	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);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
674
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
  
  	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
  		if (data->config & 0x04) { /* tachometer enabled  */
  			/* order matters for fan1_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
679
680
681
682
683
684
685
686
  			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
687
688
689
690
691
692
693
694
  		}
  
  		data->pwm1_freq = i2c_smbus_read_byte_data(client,
  				  LM63_REG_PWM_FREQ);
  		if (data->pwm1_freq == 0)
  			data->pwm1_freq = 1;
  		data->pwm1_value = i2c_smbus_read_byte_data(client,
  				   LM63_REG_PWM_VALUE);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
695
696
697
698
  		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
699
700
  
  		/* order matters for temp2_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
701
702
703
704
705
  		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
706
707
708
  				  LM63_REG_REMOTE_LOW_MSB) << 8)
  				| i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_LOW_LSB);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
709
710
711
712
  		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...
713
714
715
716
  		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...
717
718
719
720
721
722
  
  		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...
723
724
  		data->temp8[2] = i2c_smbus_read_byte_data(client,
  				 LM63_REG_REMOTE_TCRIT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
730
731
732
733
  		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;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
734
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  
  	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);