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
  #define DIV_FROM_REG(val) (1 << (val))
  #define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div))))
497888cf6   Phil Carmody   treewide: fix pot...
270
  #define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
272
273
  static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
  			     char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
275
276
277
278
279
280
  	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
281
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
282
283
  static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
285
286
287
288
289
290
  	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
291
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
292
293
  static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
295
296
297
298
299
  	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
300
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
301
302
  static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
304
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
  	return sprintf(buf, "%d
  ", data->fan_off);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
308
309
  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
310
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
311
312
313
  	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
314
315
  	unsigned long v = simple_strtoul(buf, NULL, 10);
  	u8 r;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
316
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
317
318
  	r = FAN_TO_REG(v, data->fan_div[n]);
  	data->fan_min[n] = r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
320
321
322
323
  	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
324
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
325
326
327
  		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
328
329
  
  	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
330
331
  	if (data->fan_min[n] == 0)
  		data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
333
  		data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  	data->beep_mask &= data->alarm_mask;
  	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
336
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
339
340
  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
341
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
342
343
344
  	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
345
346
347
348
349
350
351
352
353
354
355
356
357
  	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...
358
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
359
  	data->fan_div[n] = r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
361
362
363
364
  	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
365
  	else
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
366
367
368
  		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
369

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
370
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
373
374
  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
375
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
376
377
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  	u8 r = simple_strtoul(buf, NULL, 10)?1:0;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
379
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	data->fan_off = r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
381
382
383
  	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...
384
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
387
388
389
390
391
392
393
394
395
396
397
398
  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
399
400
  #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) ...
401
402
  static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
  			      char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
404
405
406
407
408
  	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
409
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
410
411
  static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
  			    char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
413
414
415
416
417
  	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
418
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
419
420
  static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute
  				 *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
422
423
424
425
426
  	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
427
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
428
429
  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
430
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
431
432
433
  	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
434
  	long v = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
435
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
436
437
  	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...
438
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
441
442
  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
443
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
444
445
446
  	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
447
  	long v = simple_strtol(buf, NULL, 10);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
448
  	mutex_lock(&data->update_lock);
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
449
450
451
  	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...
452
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
455
456
457
458
459
460
461
462
463
464
465
466
467
  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
468
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
469
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
  	return sprintf(buf, "%d
  ", data->alarms);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
473
474
  static ssize_t get_beep_enable(struct device *dev, struct device_attribute
  			       *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
476
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
  	return sprintf(buf, "%d
  ", data->beep_enable);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
480
481
  static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
  			     char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
483
  	struct gl520_data *data = gl520_update_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
  	return sprintf(buf, "%d
  ", data->beep_mask);
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
487
488
  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
489
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
490
491
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  	u8 r = simple_strtoul(buf, NULL, 10)?0:1;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
493
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  	data->beep_enable = !r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
495
496
497
  	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...
498
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
501
502
  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
503
  {
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
504
505
  	struct i2c_client *client = to_i2c_client(dev);
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	u8 r = simple_strtoul(buf, NULL, 10);
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
507

9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
508
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  	r &= data->alarm_mask;
  	data->beep_mask = r;
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
511
  	gl520_write_value(client, GL520_REG_BEEP_MASK, r);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
512
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
  	return count;
  }
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
515
516
517
518
519
  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) ...
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
581
  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...
582
583
  static struct attribute *gl520_attributes[] = {
  	&dev_attr_cpu0_vid.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
584
585
586
  	&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) ...
587
588
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
  	&sensor_dev_attr_in0_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
589
590
591
  	&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) ...
592
593
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
  	&sensor_dev_attr_in1_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
594
595
596
  	&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) ...
597
598
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
  	&sensor_dev_attr_in2_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
599
600
601
  	&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) ...
602
603
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
  	&sensor_dev_attr_in3_beep.dev_attr.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
604
605
606
607
  
  	&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) ...
608
609
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan1_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
610
  	&dev_attr_fan1_off.attr,
86d47f127   Jean Delvare   hwmon: (gl520sm) ...
611
612
613
  	&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) ...
614
615
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan2_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
616

86d47f127   Jean Delvare   hwmon: (gl520sm) ...
617
618
619
  	&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) ...
620
621
  	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
622
623
624
625
626
627
628
629
630
631
632
633
  
  	&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) ...
634
635
636
  	&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) ...
637
638
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
  	&sensor_dev_attr_in4_beep.dev_attr.attr,
87808be4f   Jean Delvare   Fix unchecked ret...
639

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

a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  	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
691
692
  
  	/* Initialize the GL520SM chip */
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
693
  	gl520_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
  
  	/* Register sysfs hooks */
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
696
  	if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
a23a9fe1d   Jean Delvare   hwmon: (gl520sm) ...
697
  		goto exit_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725

f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
726
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
727
728
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
87808be4f   Jean Delvare   Fix unchecked ret...
729
730
  		goto exit_remove_files;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
  
  	return 0;
87808be4f   Jean Delvare   Fix unchecked ret...
733
  exit_remove_files:
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
734
735
  	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
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
  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...
752
  	data->vrm = vid_which_vrm();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
779
  
  	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) ...
780
  static int gl520_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
782
  	struct gl520_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783

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

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
788
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
  	return 0;
  }
f28dc2f78   Jean Delvare   hwmon: (gl520sm) ...
791
  /* Registers 0x07 to 0x0c are word-sized, others are byte-sized
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
     GL520 uses a high-byte first convention */
  static int gl520_read_value(struct i2c_client *client, u8 reg)
  {
  	if ((reg >= 0x07) && (reg <= 0x0c))
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
796
  		return i2c_smbus_read_word_swapped(client, reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
800
801
802
803
  	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))
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
804
  		return i2c_smbus_write_word_swapped(client, reg, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
808
809
810
811
812
813
  	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) ...
814
  	int val, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815

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

0cacdf298   Jean Delvare   [PATCH] I2C: use ...
818
  	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
824
825
  
  		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) ...
826
827
828
829
830
831
832
  		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
833
834
835
836
837
838
839
840
  
  		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) ...
841
842
843
844
845
846
  		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
847
848
849
850
851
852
853
854
855
856
  
  		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
857
858
  		/* Temp1 and Vin4 are the same input */
  		if (data->two_temps) {
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
859
860
861
862
863
864
  			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
865
  		} else {
8b4b0ab41   Jean Delvare   hwmon: (gl520sm) ...
866
867
868
869
870
871
  			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
872
873
874
875
876
  		}
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
877
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  
  	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 ...
895
  	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
  	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
  MODULE_DESCRIPTION("GL520SM driver");
  MODULE_LICENSE("GPL");
  
  module_init(sensors_gl520sm_init);
  module_exit(sensors_gl520sm_exit);