Blame view

drivers/hwmon/lm63.c 28 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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  #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
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
96
  #define LM96163_REG_TRUTHERM		0x30
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
97
98
  #define LM96163_REG_REMOTE_TEMP_U_MSB	0x31
  #define LM96163_REG_REMOTE_TEMP_U_LSB	0x32
210961c43   Guenter Roeck   hwmon: (lm63) Add...
99
  #define LM96163_REG_CONFIG_ENHANCED	0x45
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
100
101
102
103
  #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
104
105
106
107
  /*
   * 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 ...
108
   * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
   * For remote temperature, low and high limits, it uses signed 11-bit values
44bbe87e9   Steven Cole   [PATCH] Spelling ...
110
   * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
111
112
113
   * 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
114
115
116
117
118
119
120
121
122
123
124
   */
  
  #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...
125
126
127
  #define TEMP8U_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 255000 ? 255 : \
  				 ((val) + 500) / 1000)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
  #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...
133
134
135
  #define TEMP11U_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 255875 ? 0xFFE0 : \
  				 ((val) + 62) / 125 * 32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
  #define HYST_TO_REG(val)	((val) <= 0 ? 0 : \
  				 (val) >= 127000 ? 127 : \
  				 ((val) + 500) / 1000)
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
139
140
  #define UPDATE_INTERVAL(max, rate) \
  			((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  /*
   * Functions declaration
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
144
145
146
  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
147
148
  
  static struct lm63_data *lm63_update_device(struct device *dev);
310ec7921   Jean Delvare   i2c: Drop the kin...
149
  static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  static void lm63_init_client(struct i2c_client *client);
210961c43   Guenter Roeck   hwmon: (lm63) Add...
151
  enum chips { lm63, lm64, lm96163 };
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
152

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

04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
187
188
  	int update_interval;	/* in milliseconds */
  	int max_convrate_hz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  	/* registers values */
  	u8 config, config_fan;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
191
192
  	u16 fan[2];	/* 0: input
  			   1: low limit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  	u8 pwm1_freq;
  	u8 pwm1_value;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
195
196
197
  	s8 temp8[3];	/* 0: local input
  			   1: local high limit
  			   2: remote critical limit */
786375f72   Guenter Roeck   hwmon: (lm63) Add...
198
  	s16 temp11[4];	/* 0: remote input
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
199
  			   1: remote low limit
786375f72   Guenter Roeck   hwmon: (lm63) Add...
200
201
  			   2: remote high limit
  			   3: remote offset */
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
202
  	u16 temp11u;	/* remote input (unsigned) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  	u8 temp2_crit_hyst;
  	u8 alarms;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
205
  	bool pwm_highres;
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
206
  	bool remote_unsigned; /* true if unsigned remote upper limits */
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
207
  	bool trutherm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  };
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
209
210
211
212
213
214
  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
215
216
217
  /*
   * Sysfs callback functions and files
   */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
218
219
220
221
222
223
224
  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
225
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
227
228
  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
229
230
231
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
232
233
234
235
236
237
  	unsigned long val;
  	int err;
  
  	err = kstrtoul(buf, 10, &val);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

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

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
307
308
309
310
311
312
  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...
313
314
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, attr->index)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
315
316
  		       + data->temp2_offset);
  }
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
317
318
  static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
  			 const char *buf, size_t count)
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
319
  {
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
320
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
321
322
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
323
324
  	int nr = attr->index;
  	int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
325
326
  	long val;
  	int err;
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
327
  	int temp;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
328
329
330
331
  
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
332

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
333
  	mutex_lock(&data->update_lock);
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
334
335
336
337
338
339
340
341
342
343
  	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...
344
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
345
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
347
348
349
350
351
352
  
  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...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  	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
373
  }
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
374
375
376
377
  
  static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
  			  const char *buf, size_t count)
  {
786375f72   Guenter Roeck   hwmon: (lm63) Add...
378
  	static const u8 reg[6] = {
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
379
380
381
382
  		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...
383
384
  		LM63_REG_REMOTE_OFFSET_MSB,
  		LM63_REG_REMOTE_OFFSET_LSB,
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
385
386
387
388
389
  	};
  
  	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...
390
391
  	long val;
  	int err;
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
392
  	int nr = attr->index;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
393
394
395
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
396
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
397
398
399
400
  	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...
401
402
403
404
  	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...
405
  	mutex_unlock(&data->update_lock);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
406
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

662bda283   Guenter Roeck   hwmon: (lm63) Fix...
409
410
411
412
413
414
  /*
   * 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
415
416
  {
  	struct lm63_data *data = lm63_update_device(dev);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
417
418
  	return sprintf(buf, "%d
  ", temp8_from_reg(data, 2)
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
419
  		       + data->temp2_offset
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  		       - TEMP8_FROM_REG(data->temp2_crit_hyst));
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
422
423
424
425
426
427
  /*
   * 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...
428
  				   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm63_data *data = i2c_get_clientdata(client);
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
432
433
  	long val;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
  	long hyst;
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
435
436
437
  	err = kstrtol(buf, 10, &val);
  	if (err)
  		return err;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
438
  	mutex_lock(&data->update_lock);
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
439
  	hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
  				  HYST_TO_REG(hyst));
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
442
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  	return count;
  }
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  /*
   * 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...
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
  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...
533
534
  static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
  {
  	struct lm63_data *data = lm63_update_device(dev);
  	return sprintf(buf, "%u
  ", data->alarms);
  }
2d45771e6   Jean Delvare   hwmon: Add indivi...
540
541
542
543
544
545
546
547
548
549
  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...
550
551
552
  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
553
554
555
  
  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...
556
557
  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...
558
  	set_temp8, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
560
561
562
563
564
  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...
565
566
  static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
  	set_temp11, 3);
2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
567
  static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
568
  	set_temp8, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
  static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
  	set_temp2_crit_hyst);
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
571
  static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
2d45771e6   Jean Delvare   hwmon: Add indivi...
572
573
574
  /* 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...
575
  static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
2d45771e6   Jean Delvare   hwmon: Add indivi...
576
577
578
579
  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
580
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
581
582
  static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
  		   set_update_interval);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
583
584
585
586
587
588
589
590
  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...
591
  	&sensor_dev_attr_temp2_offset.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
592
593
594
595
  	&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...
596
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
597
598
599
600
  	&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...
601
  	&dev_attr_update_interval.attr,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
602
603
  	NULL
  };
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
  /*
   * 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...
625
  static const struct attribute_group lm63_group = {
94e55df48   Guenter Roeck   hwmon: (lm63) Add...
626
  	.is_visible = lm63_attribute_mode,
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  	.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
641
642
643
  /*
   * Real code
   */
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
644
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
645
  static int lm63_detect(struct i2c_client *new_client,
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
646
  		       struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  {
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
648
  	struct i2c_adapter *adapter = new_client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
649
650
  	u8 man_id, chip_id, reg_config1, reg_config2;
  	u8 reg_alert_status, reg_alert_mask;
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
651
  	int address = new_client->addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
654
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

52df6440a   Jean Delvare   hwmon: Clean up d...
656
657
658
659
660
661
662
663
664
665
666
667
668
  	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...
669
670
671
672
673
674
675
676
677
  	 || (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
678
  	}
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
679
680
681
682
  	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...
683
684
  	else if (chip_id == 0x49 && address == 0x4c)
  		strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
10f2ed31a   Matthew Garrett   hwmon: (lm63) Add...
685
686
  	else
  		return -ENODEV;
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  
  	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
704
  	data->valid = 0;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
705
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

2778fb13b   Dirk Eibach   hwmon: (lm63) Con...
707
708
709
710
711
712
  	/* 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
713
714
715
  	lm63_init_client(new_client);
  
  	/* Register sysfs hooks */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
716
717
  	err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
  	if (err)
d5957be2f   Jean Delvare   hwmon: (lm63) Con...
718
  		goto exit_free;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
719
  	if (data->config & 0x04) { /* tachometer enabled */
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
720
721
722
  		err = sysfs_create_group(&new_client->dev.kobj,
  					 &lm63_group_fan1);
  		if (err)
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
723
  			goto exit_remove_files;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
724
  	}
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
725
726
727
728
729
730
  	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...
731

1beeffe43   Tony Jones   hwmon: Convert fr...
732
733
734
  	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...
735
  		goto exit_remove_files;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
  
  	return 0;
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
739
  exit_remove_files:
f496b2d4f   Guenter Roeck   hwmon: (lm63) Add...
740
  	device_remove_file(&new_client->dev, &dev_attr_temp2_type);
0e39e01c9   Jean Delvare   hwmon: Fix unchec...
741
742
  	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
743
744
745
746
747
  exit_free:
  	kfree(data);
  exit:
  	return err;
  }
662bda283   Guenter Roeck   hwmon: (lm63) Fix...
748
749
750
751
  /*
   * 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
752
753
754
  static void lm63_init_client(struct i2c_client *client)
  {
  	struct lm63_data *data = i2c_get_clientdata(client);
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
755
  	u8 convrate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
761
762
  
  	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...
763
764
  		dev_dbg(&client->dev, "Switching to operational mode
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
  		data->config &= 0xA7;
  		i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
  					  data->config);
  	}
409c0b5bd   Jean Delvare   hwmon: (lm63) LM6...
769
770
771
  	/* Tachometer is always enabled on LM64 */
  	if (data->kind == lm64)
  		data->config |= 0x04;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
776
  
  	/* 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...
777
778
779
780
781
782
783
  	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...
784
785
786
  		data->trutherm
  		  = i2c_smbus_read_byte_data(client,
  					     LM96163_REG_TRUTHERM) & 0x02;
04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
787
788
789
790
791
792
793
  		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...
794
  	/*
e872c91e7   Guenter Roeck   hwmon: (lm63) Add...
795
796
  	 * For LM96163, check if high resolution PWM
  	 * and unsigned temperature format is enabled.
210961c43   Guenter Roeck   hwmon: (lm63) Add...
797
798
799
800
801
802
803
804
805
  	 */
  	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...
806
  			data->remote_unsigned = true;
210961c43   Guenter Roeck   hwmon: (lm63) Add...
807
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  	/* Show some debug info about the LM63 configuration */
409c0b5bd   Jean Delvare   hwmon: (lm63) LM6...
809
810
811
812
813
  	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
814
815
816
817
818
819
820
821
822
  	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...
823
  static int lm63_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
825
  	struct lm63_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826

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

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
832
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
836
837
838
839
  	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...
840
  	unsigned long next_update;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841

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

04738b2b2   Guenter Roeck   hwmon: (lm63) Add...
844
845
846
847
  	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
848
849
  		if (data->config & 0x04) { /* tachometer enabled  */
  			/* order matters for fan1_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
850
851
852
853
854
855
856
857
  			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
858
859
860
861
862
863
864
865
  		}
  
  		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...
866
867
868
869
  		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
870
871
  
  		/* order matters for temp2_input */
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
872
873
874
875
876
  		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
877
878
879
  				  LM63_REG_REMOTE_LOW_MSB) << 8)
  				| i2c_smbus_read_byte_data(client,
  				  LM63_REG_REMOTE_LOW_LSB);
bc51ae115   Jean Delvare   [PATCH] I2C: lm63...
880
881
882
883
  		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...
884
885
886
887
  		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...
888
889
890
891
892
893
  
  		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...
894
895
  		data->temp8[2] = i2c_smbus_read_byte_data(client,
  				 LM63_REG_REMOTE_TCRIT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
902
903
904
  		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...
905
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  
  	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);