Blame view

drivers/hwmon/gl520sm.c 28 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
      gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
                  monitoring
      Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
96de0e252   Jan Engelhardt   Convert files to ...
5
                                Kyösti Mälkki <kmalkki@cc.hut.fi>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
      Copyright (c) 2005        Maarten Deprez <maartendeprez@users.sourceforge.net>
  
      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.
  
  */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
0cacdf298   Jean Delvare   [PATCH] I2C: use ...
27
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
29
  #include <linux/hwmon.h>
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
30
  #include <linux/hwmon-sysfs.h>
303760b44   Jean Delvare   [PATCH] hwmon: hw...
31
  #include <linux/hwmon-vid.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
32
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
33
  #include <linux/mutex.h>
87808be4f   Jean Delvare   Fix unchecked ret...
34
  #include <linux/sysfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
  
  /* Type of the extra sensor */
  static unsigned short extra_sensor_type;
  module_param(extra_sensor_type, ushort, 0);
  MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)");
  
  /* Addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
42
  static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
44
  /* Many GL520 constants specified below
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  One of the inputs can be configured as either temp or voltage.
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
46
  That's why _TEMP2 and _IN4 access the same register
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
  */
  
  /* The GL520 registers */
  #define GL520_REG_CHIP_ID		0x00
  #define GL520_REG_REVISION		0x01
  #define GL520_REG_CONF			0x03
  #define GL520_REG_MASK			0x11
  
  #define GL520_REG_VID_INPUT		0x02
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
56
57
58
59
60
61
62
63
  static const u8 GL520_REG_IN_INPUT[]	= { 0x15, 0x14, 0x13, 0x0d, 0x0e };
  static const u8 GL520_REG_IN_LIMIT[]	= { 0x0c, 0x09, 0x0a, 0x0b };
  static const u8 GL520_REG_IN_MIN[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x18 };
  static const u8 GL520_REG_IN_MAX[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x17 };
  
  static const u8 GL520_REG_TEMP_INPUT[]		= { 0x04, 0x0e };
  static const u8 GL520_REG_TEMP_MAX[]		= { 0x05, 0x17 };
  static const u8 GL520_REG_TEMP_MAX_HYST[]	= { 0x06, 0x18 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
70
71
72
73
74
75
76
  
  #define GL520_REG_FAN_INPUT		0x07
  #define GL520_REG_FAN_MIN		0x08
  #define GL520_REG_FAN_DIV		0x0f
  #define GL520_REG_FAN_OFF		GL520_REG_FAN_DIV
  
  #define GL520_REG_ALARMS		0x12
  #define GL520_REG_BEEP_MASK		0x10
  #define GL520_REG_BEEP_ENABLE		GL520_REG_CONF
  
  /*
   * Function declarations
   */
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
77
78
  static int gl520_probe(struct i2c_client *client,
  		       const struct i2c_device_id *id);
310ec7921   Jean Delvare   i2c: Drop the kin...
79
  static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  static void gl520_init_client(struct i2c_client *client);
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
81
  static int gl520_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
  static int gl520_read_value(struct i2c_client *client, u8 reg);
  static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
  static struct gl520_data *gl520_update_device(struct device *dev);
  
  /* Driver data */
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
87
  static const struct i2c_device_id gl520_id[] = {
1f86df49d   Jean Delvare   i2c: Drop I2C_CLI...
88
  	{ "gl520sm", 0 },
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
89
90
91
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, gl520_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  static struct i2c_driver gl520_driver = {
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
93
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
94
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
95
96
  		.name	= "gl520sm",
  	},
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
97
98
99
100
  	.probe		= gl520_probe,
  	.remove		= gl520_remove,
  	.id_table	= gl520_id,
  	.detect		= gl520_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
101
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
  };
  
  /* Client data */
  struct gl520_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
106
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
107
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  	char valid;		/* zero until the following fields are valid */
  	unsigned long last_updated;	/* in jiffies */
  
  	u8 vid;
  	u8 vrm;
  	u8 in_input[5];		/* [0] = VVD */
  	u8 in_min[5];		/* [0] = VDD */
  	u8 in_max[5];		/* [0] = VDD */
  	u8 fan_input[2];
  	u8 fan_min[2];
  	u8 fan_div[2];
  	u8 fan_off;
  	u8 temp_input[2];
  	u8 temp_max[2];
  	u8 temp_max_hyst[2];
  	u8 alarms;
  	u8 beep_enable;
  	u8 beep_mask;
  	u8 alarm_mask;
  	u8 two_temps;
  };
  
  /*
   * Sysfs stuff
   */
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
133
134
  static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
136
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
  	return sprintf(buf, "%u
  ", vid_from_reg(data->vid, data->vrm));
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
140
  static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
  
  #define VDD_FROM_REG(val) (((val)*95+2)/4)
  #define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
  
  #define IN_FROM_REG(val) ((val)*19)
  #define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
147
148
  static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
  			    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
150
151
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
  	u8 r = data->in_input[n];
  
  	if (n == 0)
  		return sprintf(buf, "%d
  ", VDD_FROM_REG(r));
  	else
  		return sprintf(buf, "%d
  ", IN_FROM_REG(r));
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
161
162
  static ssize_t get_in_min(struct device *dev, struct device_attribute *attr,
  			  char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
164
165
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
170
171
172
173
174
  	u8 r = data->in_min[n];
  
  	if (n == 0)
  		return sprintf(buf, "%d
  ", VDD_FROM_REG(r));
  	else
  		return sprintf(buf, "%d
  ", IN_FROM_REG(r));
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
175
176
  static ssize_t get_in_max(struct device *dev, struct device_attribute *attr,
  			  char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
178
179
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
  	u8 r = data->in_max[n];
  
  	if (n == 0)
  		return sprintf(buf, "%d
  ", VDD_FROM_REG(r));
  	else
  		return sprintf(buf, "%d
  ", IN_FROM_REG(r));
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
189
190
  static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
192
193
194
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
  	long v = simple_strtol(buf, NULL, 10);
  	u8 r;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
197
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
  
  	if (n == 0)
  		r = VDD_TO_REG(v);
  	else
  		r = IN_TO_REG(v);
  
  	data->in_min[n] = r;
  
  	if (n < 4)
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
207
208
209
  		gl520_write_value(client, GL520_REG_IN_MIN[n],
  				  (gl520_read_value(client, GL520_REG_IN_MIN[n])
  				   & ~0xff) | r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
211
  		gl520_write_value(client, GL520_REG_IN_MIN[n], r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
213
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
216
217
  static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
219
220
221
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
  	long v = simple_strtol(buf, NULL, 10);
  	u8 r;
  
  	if (n == 0)
  		r = VDD_TO_REG(v);
  	else
  		r = IN_TO_REG(v);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
229
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
  
  	data->in_max[n] = r;
  
  	if (n < 4)
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
234
235
236
  		gl520_write_value(client, GL520_REG_IN_MAX[n],
  				  (gl520_read_value(client, GL520_REG_IN_MAX[n])
  				   & ~0xff00) | (r << 8));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
238
  		gl520_write_value(client, GL520_REG_IN_MAX[n], r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
240
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, get_in_input, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, get_in_input, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, get_in_input, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, get_in_input, NULL, 3);
  static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, get_in_input, NULL, 4);
  static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
  		get_in_min, set_in_min, 0);
  static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
  		get_in_min, set_in_min, 1);
  static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
  		get_in_min, set_in_min, 2);
  static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
  		get_in_min, set_in_min, 3);
  static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
  		get_in_min, set_in_min, 4);
  static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
  		get_in_max, set_in_max, 0);
  static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
  		get_in_max, set_in_max, 1);
  static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
  		get_in_max, set_in_max, 2);
  static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
  		get_in_max, set_in_max, 3);
  static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
  		get_in_max, set_in_max, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  #define DIV_FROM_REG(val) (1 << (val))
  #define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div))))
  #define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255));
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
271
272
  static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
  			     char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
274
275
276
277
278
279
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan_input[n],
  						 data->fan_div[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
281
282
  static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
284
285
286
287
288
289
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan_min[n],
  						 data->fan_div[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
291
292
  static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
294
295
296
297
298
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", DIV_FROM_REG(data->fan_div[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
300
301
  static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
303
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
  	return sprintf(buf, "%d
  ", data->fan_off);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
307
308
  static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
  			   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
310
311
312
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
  	unsigned long v = simple_strtoul(buf, NULL, 10);
  	u8 r;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
315
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
316
317
  	r = FAN_TO_REG(v, data->fan_div[n]);
  	data->fan_min[n] = r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
319
320
321
322
  	if (n == 0)
  		gl520_write_value(client, GL520_REG_FAN_MIN,
  				  (gl520_read_value(client, GL520_REG_FAN_MIN)
  				   & ~0xff00) | (r << 8));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
324
325
326
  		gl520_write_value(client, GL520_REG_FAN_MIN,
  				  (gl520_read_value(client, GL520_REG_FAN_MIN)
  				   & ~0xff) | r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  
  	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
329
330
  	if (data->fan_min[n] == 0)
  		data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
332
  		data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  	data->beep_mask &= data->alarm_mask;
  	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
335
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
338
339
  static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
  			   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
341
342
343
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
355
356
  	unsigned long v = simple_strtoul(buf, NULL, 10);
  	u8 r;
  
  	switch (v) {
  	case 1: r = 0; break;
  	case 2: r = 1; break;
  	case 4: r = 2; break;
  	case 8: r = 3; break;
  	default:
  		dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!
  ", v);
  		return -EINVAL;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
357
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
358
  	data->fan_div[n] = r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
360
361
362
363
  	if (n == 0)
  		gl520_write_value(client, GL520_REG_FAN_DIV,
  				  (gl520_read_value(client, GL520_REG_FAN_DIV)
  				   & ~0xc0) | (r << 6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
365
366
367
  		gl520_write_value(client, GL520_REG_FAN_DIV,
  				  (gl520_read_value(client, GL520_REG_FAN_DIV)
  				   & ~0x30) | (r << 4));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
369
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
372
373
  static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
  			   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
375
376
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  	u8 r = simple_strtoul(buf, NULL, 10)?1:0;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
378
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  	data->fan_off = r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
380
381
382
  	gl520_write_value(client, GL520_REG_FAN_OFF,
  			  (gl520_read_value(client, GL520_REG_FAN_OFF)
  			   & ~0x0c) | (r << 2));
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
383
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
386
387
388
389
390
391
392
393
394
395
396
397
  static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_input, NULL, 0);
  static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan_input, NULL, 1);
  static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
  		get_fan_min, set_fan_min, 0);
  static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
  		get_fan_min, set_fan_min, 1);
  static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
  		get_fan_div, set_fan_div, 0);
  static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
  		get_fan_div, set_fan_div, 1);
  static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
  		get_fan_off, set_fan_off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
  #define TEMP_FROM_REG(val) (((val) - 130) * 1000)
  #define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255))
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
400
401
  static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
  			      char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
403
404
405
406
407
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_input[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
409
410
  static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
  			    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
412
413
414
415
416
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_max[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
418
419
  static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute
  				 *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
421
422
423
424
425
  	int n = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_max_hyst[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
427
428
  static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
  			    const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
430
431
432
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  	long v = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
434
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
435
436
  	data->temp_max[n] = TEMP_TO_REG(v);
  	gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
437
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
440
441
  static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
  				 *attr, const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
443
444
445
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int n = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	long v = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
447
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
448
449
450
  	data->temp_max_hyst[n] = TEMP_TO_REG(v);
  	gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n],
  			  data->temp_max_hyst[n]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
451
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
454
455
456
457
458
459
460
461
462
463
464
465
466
  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp_input, NULL, 0);
  static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp_input, NULL, 1);
  static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
  		get_temp_max, set_temp_max, 0);
  static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
  		get_temp_max, set_temp_max, 1);
  static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
  		get_temp_max_hyst, set_temp_max_hyst, 0);
  static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
  		get_temp_max_hyst, set_temp_max_hyst, 1);
  
  static ssize_t get_alarms(struct device *dev, struct device_attribute *attr,
  			  char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
468
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
  	return sprintf(buf, "%d
  ", data->alarms);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
472
473
  static ssize_t get_beep_enable(struct device *dev, struct device_attribute
  			       *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
475
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
  	return sprintf(buf, "%d
  ", data->beep_enable);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
479
480
  static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
  			     char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
482
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  	return sprintf(buf, "%d
  ", data->beep_mask);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
486
487
  static ssize_t set_beep_enable(struct device *dev, struct device_attribute
  			       *attr, const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
489
490
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	u8 r = simple_strtoul(buf, NULL, 10)?0:1;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
492
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  	data->beep_enable = !r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
494
495
496
  	gl520_write_value(client, GL520_REG_BEEP_ENABLE,
  			  (gl520_read_value(client, GL520_REG_BEEP_ENABLE)
  			   & ~0x04) | (r << 2));
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
497
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
500
501
  static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
  			     const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
503
504
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  	u8 r = simple_strtoul(buf, NULL, 10);
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
506

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
507
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  	r &= data->alarm_mask;
  	data->beep_mask = r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
510
  	gl520_write_value(client, GL520_REG_BEEP_MASK, r);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
511
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
514
515
516
517
518
  static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
  static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
  		get_beep_enable, set_beep_enable);
  static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
  		get_beep_mask, set_beep_mask);
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
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
569
570
571
572
573
574
575
576
577
578
579
580
  static ssize_t get_alarm(struct device *dev, struct device_attribute *attr,
  			 char *buf)
  {
  	int bit_nr = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", (data->alarms >> bit_nr) & 1);
  }
  
  static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, get_alarm, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, get_alarm, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, get_alarm, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, get_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, get_alarm, NULL, 4);
  static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, get_alarm, NULL, 5);
  static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, get_alarm, NULL, 6);
  static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, get_alarm, NULL, 7);
  static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, get_alarm, NULL, 7);
  
  static ssize_t get_beep(struct device *dev, struct device_attribute *attr,
  			char *buf)
  {
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	struct gl520_data *data = gl520_update_device(dev);
  
  	return sprintf(buf, "%d
  ", (data->beep_mask >> bitnr) & 1);
  }
  
  static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
  			const char *buf, size_t count)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	unsigned long bit;
  
  	bit = simple_strtoul(buf, NULL, 10);
  	if (bit & ~1)
  		return -EINVAL;
  
  	mutex_lock(&data->update_lock);
  	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
  	if (bit)
  		data->beep_mask |= (1 << bitnr);
  	else
  		data->beep_mask &= ~(1 << bitnr);
  	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
  	mutex_unlock(&data->update_lock);
  	return count;
  }
  
  static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 0);
  static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 1);
  static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 2);
  static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 3);
  static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 4);
  static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 5);
  static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 6);
  static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
  static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
87808be4f   Jean Delvare   Fix unchecked ret...
581
582
  static struct attribute *gl520_attributes[] = {
  	&dev_attr_cpu0_vid.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
583
584
585
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
586
587
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
  	&sensor_dev_attr_in0_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
588
589
590
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
591
592
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
  	&sensor_dev_attr_in1_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
593
594
595
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
596
597
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
  	&sensor_dev_attr_in2_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
598
599
600
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
601
602
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
  	&sensor_dev_attr_in3_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
603
604
605
606
  
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
607
608
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan1_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
609
  	&dev_attr_fan1_off.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
610
611
612
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
613
614
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan2_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
615

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
616
617
618
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
619
620
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
621
622
623
624
625
626
627
628
629
630
631
632
  
  	&dev_attr_alarms.attr,
  	&dev_attr_beep_enable.attr,
  	&dev_attr_beep_mask.attr,
  	NULL
  };
  
  static const struct attribute_group gl520_group = {
  	.attrs = gl520_attributes,
  };
  
  static struct attribute *gl520_attributes_opt[] = {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
633
634
635
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
636
637
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
  	&sensor_dev_attr_in4_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
638

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
639
640
641
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
642
643
  	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
644
645
646
647
648
649
  	NULL
  };
  
  static const struct attribute_group gl520_group_opt = {
  	.attrs = gl520_attributes_opt,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
  
  /*
   * Real code
   */
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
654
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
655
  static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  {
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
657
  	struct i2c_adapter *adapter = client->adapter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
  				     I2C_FUNC_SMBUS_WORD_DATA))
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
661
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
  
  	/* Determine the chip type. */
52df6440a   Jean Delvare   hwmon: Clean up d...
664
665
666
667
668
669
  	if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
  	    ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
  	    ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
  		dev_dbg(&client->dev, "Unknown chip type, skipping
  ");
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  	}
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
671
  	strlcpy(info->type, "gl520sm", I2C_NAME_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672

a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
  	return 0;
  }
  
  static int gl520_probe(struct i2c_client *client,
  		       const struct i2c_device_id *id)
  {
  	struct gl520_data *data;
  	int err;
  
  	data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL);
  	if (!data) {
  		err = -ENOMEM;
  		goto exit;
  	}
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
  
  	/* Initialize the GL520SM chip */
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
692
  	gl520_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  
  	/* Register sysfs hooks */
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
695
  	if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
696
  		goto exit_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

87808be4f   Jean Delvare   Fix unchecked ret...
698
  	if (data->two_temps) {
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
699
  		if ((err = device_create_file(&client->dev,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
700
  				&sensor_dev_attr_temp2_input.dev_attr))
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
701
  		 || (err = device_create_file(&client->dev,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
702
  				&sensor_dev_attr_temp2_max.dev_attr))
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
703
  		 || (err = device_create_file(&client->dev,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
704
705
706
707
708
  				&sensor_dev_attr_temp2_max_hyst.dev_attr))
  		 || (err = device_create_file(&client->dev,
  				&sensor_dev_attr_temp2_alarm.dev_attr))
  		 || (err = device_create_file(&client->dev,
  				&sensor_dev_attr_temp2_beep.dev_attr)))
87808be4f   Jean Delvare   Fix unchecked ret...
709
710
  			goto exit_remove_files;
  	} else {
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
711
  		if ((err = device_create_file(&client->dev,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
712
  				&sensor_dev_attr_in4_input.dev_attr))
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
713
  		 || (err = device_create_file(&client->dev,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
714
  				&sensor_dev_attr_in4_min.dev_attr))
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
715
  		 || (err = device_create_file(&client->dev,
e86a77609   Jean Delvare   hwmon: (gl520sm) ...
716
717
718
719
720
  				&sensor_dev_attr_in4_max.dev_attr))
  		 || (err = device_create_file(&client->dev,
  				&sensor_dev_attr_in4_alarm.dev_attr))
  		 || (err = device_create_file(&client->dev,
  				&sensor_dev_attr_in4_beep.dev_attr)))
87808be4f   Jean Delvare   Fix unchecked ret...
721
722
  			goto exit_remove_files;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724

f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
725
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
726
727
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
87808be4f   Jean Delvare   Fix unchecked ret...
728
729
  		goto exit_remove_files;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  
  	return 0;
87808be4f   Jean Delvare   Fix unchecked ret...
732
  exit_remove_files:
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
733
734
  	sysfs_remove_group(&client->dev.kobj, &gl520_group);
  	sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
  exit_free:
  	kfree(data);
  exit:
  	return err;
  }
  
  
  /* Called when we have found a new GL520SM. */
  static void gl520_init_client(struct i2c_client *client)
  {
  	struct gl520_data *data = i2c_get_clientdata(client);
  	u8 oldconf, conf;
  
  	conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
  
  	data->alarm_mask = 0xff;
303760b44   Jean Delvare   [PATCH] hwmon: hw...
751
  	data->vrm = vid_which_vrm();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
  
  	if (extra_sensor_type == 1)
  		conf &= ~0x10;
  	else if (extra_sensor_type == 2)
  		conf |= 0x10;
  	data->two_temps = !(conf & 0x10);
  
  	/* If IRQ# is disabled, we can safely force comparator mode */
  	if (!(conf & 0x20))
  		conf &= 0xf7;
  
  	/* Enable monitoring if needed */
  	conf |= 0x40;
  
  	if (conf != oldconf)
  		gl520_write_value(client, GL520_REG_CONF, conf);
  
  	gl520_update_device(&(client->dev));
  
  	if (data->fan_min[0] == 0)
  		data->alarm_mask &= ~0x20;
  	if (data->fan_min[1] == 0)
  		data->alarm_mask &= ~0x40;
  
  	data->beep_mask &= data->alarm_mask;
  	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
  }
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
779
  static int gl520_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
781
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

1beeffe43   Tony Jones   hwmon: Convert fr...
783
  	hwmon_device_unregister(data->hwmon_dev);
87808be4f   Jean Delvare   Fix unchecked ret...
784
785
  	sysfs_remove_group(&client->dev.kobj, &gl520_group);
  	sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
786

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
787
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
  	return 0;
  }
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
790
  /* Registers 0x07 to 0x0c are word-sized, others are byte-sized
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
     GL520 uses a high-byte first convention */
  static int gl520_read_value(struct i2c_client *client, u8 reg)
  {
  	if ((reg >= 0x07) && (reg <= 0x0c))
  		return swab16(i2c_smbus_read_word_data(client, reg));
  	else
  		return i2c_smbus_read_byte_data(client, reg);
  }
  
  static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
  {
  	if ((reg >= 0x07) && (reg <= 0x0c))
  		return i2c_smbus_write_word_data(client, reg, swab16(value));
  	else
  		return i2c_smbus_write_byte_data(client, reg, value);
  }
  
  
  static struct gl520_data *gl520_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
813
  	int val, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

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

0cacdf298   Jean Delvare   [PATCH] I2C: use ...
817
  	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
822
823
824
  
  		dev_dbg(&client->dev, "Starting gl520sm update
  ");
  
  		data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
  		data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
  		data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f;
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
825
826
827
828
829
830
831
  		for (i = 0; i < 4; i++) {
  			data->in_input[i] = gl520_read_value(client,
  							GL520_REG_IN_INPUT[i]);
  			val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
  			data->in_min[i] = val & 0xff;
  			data->in_max[i] = (val >> 8) & 0xff;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
834
835
836
837
838
839
  
  		val = gl520_read_value(client, GL520_REG_FAN_INPUT);
  		data->fan_input[0] = (val >> 8) & 0xff;
  		data->fan_input[1] = val & 0xff;
  
  		val = gl520_read_value(client, GL520_REG_FAN_MIN);
  		data->fan_min[0] = (val >> 8) & 0xff;
  		data->fan_min[1] = val & 0xff;
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
840
841
842
843
844
845
  		data->temp_input[0] = gl520_read_value(client,
  						GL520_REG_TEMP_INPUT[0]);
  		data->temp_max[0] = gl520_read_value(client,
  						GL520_REG_TEMP_MAX[0]);
  		data->temp_max_hyst[0] = gl520_read_value(client,
  						GL520_REG_TEMP_MAX_HYST[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
850
851
852
853
854
855
  
  		val = gl520_read_value(client, GL520_REG_FAN_DIV);
  		data->fan_div[0] = (val >> 6) & 0x03;
  		data->fan_div[1] = (val >> 4) & 0x03;
  		data->fan_off = (val >> 2) & 0x01;
  
  		data->alarms &= data->alarm_mask;
  
  		val = gl520_read_value(client, GL520_REG_CONF);
  		data->beep_enable = !((val >> 2) & 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  		/* Temp1 and Vin4 are the same input */
  		if (data->two_temps) {
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
858
859
860
861
862
863
  			data->temp_input[1] = gl520_read_value(client,
  						GL520_REG_TEMP_INPUT[1]);
  			data->temp_max[1] = gl520_read_value(client,
  						GL520_REG_TEMP_MAX[1]);
  			data->temp_max_hyst[1] = gl520_read_value(client,
  						GL520_REG_TEMP_MAX_HYST[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  		} else {
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
865
866
867
868
869
870
  			data->in_input[4] = gl520_read_value(client,
  						GL520_REG_IN_INPUT[4]);
  			data->in_min[4] = gl520_read_value(client,
  						GL520_REG_IN_MIN[4]);
  			data->in_max[4] = gl520_read_value(client,
  						GL520_REG_IN_MAX[4]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
  		}
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
876
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
  
  	return data;
  }
  
  
  static int __init sensors_gl520sm_init(void)
  {
  	return i2c_add_driver(&gl520_driver);
  }
  
  static void __exit sensors_gl520sm_exit(void)
  {
  	i2c_del_driver(&gl520_driver);
  }
  
  
  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
96de0e252   Jan Engelhardt   Convert files to ...
894
  	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
900
  	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
  MODULE_DESCRIPTION("GL520SM driver");
  MODULE_LICENSE("GPL");
  
  module_init(sensors_gl520sm_init);
  module_exit(sensors_gl520sm_exit);