gl520sm.c 28.4 KB
Newer Older
L
Linus Torvalds 已提交
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>,
5
                              Kyösti Mälkki <kmalkki@cc.hut.fi>
L
Linus Torvalds 已提交
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>
27
#include <linux/jiffies.h>
L
Linus Torvalds 已提交
28
#include <linux/i2c.h>
29
#include <linux/hwmon.h>
30
#include <linux/hwmon-sysfs.h>
31
#include <linux/hwmon-vid.h>
32
#include <linux/err.h>
33
#include <linux/mutex.h>
34
#include <linux/sysfs.h>
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44

/* 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 */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };

/* Insmod parameters */
45
I2C_CLIENT_INSMOD_1(gl520sm);
L
Linus Torvalds 已提交
46

J
Jean Delvare 已提交
47
/* Many GL520 constants specified below
L
Linus Torvalds 已提交
48
One of the inputs can be configured as either temp or voltage.
J
Jean Delvare 已提交
49
That's why _TEMP2 and _IN4 access the same register
L
Linus Torvalds 已提交
50 51 52 53 54 55 56 57 58 59
*/

/* 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

60 61 62 63 64 65 66 67
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 };
L
Linus Torvalds 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

#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
 */

static int gl520_attach_adapter(struct i2c_adapter *adapter);
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind);
static void gl520_init_client(struct i2c_client *client);
static int gl520_detach_client(struct i2c_client *client);
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 */
static struct i2c_driver gl520_driver = {
92 93 94
	.driver = {
		.name	= "gl520sm",
	},
L
Linus Torvalds 已提交
95 96 97 98 99 100 101
	.attach_adapter	= gl520_attach_adapter,
	.detach_client	= gl520_detach_client,
};

/* Client data */
struct gl520_data {
	struct i2c_client client;
102
	struct device *hwmon_dev;
103
	struct mutex update_lock;
L
Linus Torvalds 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
	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
 */

130 131
static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
132
{
133
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
134 135
	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
}
136
static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
L
Linus Torvalds 已提交
137 138 139 140 141 142 143

#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))

144 145
static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
146
{
147 148
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
149 150 151 152 153 154 155 156
	u8 r = data->in_input[n];

	if (n == 0)
		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
	else
		return sprintf(buf, "%d\n", IN_FROM_REG(r));
}

157 158
static ssize_t get_in_min(struct device *dev, struct device_attribute *attr,
			  char *buf)
L
Linus Torvalds 已提交
159
{
160 161
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169
	u8 r = data->in_min[n];

	if (n == 0)
		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
	else
		return sprintf(buf, "%d\n", IN_FROM_REG(r));
}

170 171
static ssize_t get_in_max(struct device *dev, struct device_attribute *attr,
			  char *buf)
L
Linus Torvalds 已提交
172
{
173 174
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
175 176 177 178 179 180 181 182
	u8 r = data->in_max[n];

	if (n == 0)
		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
	else
		return sprintf(buf, "%d\n", IN_FROM_REG(r));
}

183 184
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
L
Linus Torvalds 已提交
185
{
186 187 188
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
	int n = to_sensor_dev_attr(attr)->index;
L
Linus Torvalds 已提交
189 190 191
	long v = simple_strtol(buf, NULL, 10);
	u8 r;

192
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200 201

	if (n == 0)
		r = VDD_TO_REG(v);
	else
		r = IN_TO_REG(v);

	data->in_min[n] = r;

	if (n < 4)
202 203 204
		gl520_write_value(client, GL520_REG_IN_MIN[n],
				  (gl520_read_value(client, GL520_REG_IN_MIN[n])
				   & ~0xff) | r);
L
Linus Torvalds 已提交
205
	else
206
		gl520_write_value(client, GL520_REG_IN_MIN[n], r);
L
Linus Torvalds 已提交
207

208
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
209 210 211
	return count;
}

212 213
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
L
Linus Torvalds 已提交
214
{
215 216 217
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
	int n = to_sensor_dev_attr(attr)->index;
L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225
	long v = simple_strtol(buf, NULL, 10);
	u8 r;

	if (n == 0)
		r = VDD_TO_REG(v);
	else
		r = IN_TO_REG(v);

226
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
227 228 229 230

	data->in_max[n] = r;

	if (n < 4)
231 232 233
		gl520_write_value(client, GL520_REG_IN_MAX[n],
				  (gl520_read_value(client, GL520_REG_IN_MAX[n])
				   & ~0xff00) | (r << 8));
L
Linus Torvalds 已提交
234
	else
235
		gl520_write_value(client, GL520_REG_IN_MAX[n], r);
L
Linus Torvalds 已提交
236

237
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
238 239 240
	return count;
}

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
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);

L
Linus Torvalds 已提交
267 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));

271 272
static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
			     char *buf)
L
Linus Torvalds 已提交
273
{
274 275 276 277 278
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n],
						 data->fan_div[n]));
L
Linus Torvalds 已提交
279 280
}

281 282
static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
283
{
284 285 286 287 288
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n],
						 data->fan_div[n]));
L
Linus Torvalds 已提交
289 290
}

291 292
static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
293
{
294 295 296 297
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n]));
L
Linus Torvalds 已提交
298 299
}

300 301
static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
302
{
303
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
304 305 306
	return sprintf(buf, "%d\n", data->fan_off);
}

307 308
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
L
Linus Torvalds 已提交
309
{
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;
L
Linus Torvalds 已提交
313 314 315
	unsigned long v = simple_strtoul(buf, NULL, 10);
	u8 r;

316
	mutex_lock(&data->update_lock);
317 318
	r = FAN_TO_REG(v, data->fan_div[n]);
	data->fan_min[n] = r;
L
Linus Torvalds 已提交
319

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));
L
Linus Torvalds 已提交
324
	else
325 326 327
		gl520_write_value(client, GL520_REG_FAN_MIN,
				  (gl520_read_value(client, GL520_REG_FAN_MIN)
				   & ~0xff) | r);
L
Linus Torvalds 已提交
328 329

	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
330 331
	if (data->fan_min[n] == 0)
		data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
L
Linus Torvalds 已提交
332
	else
333
		data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
L
Linus Torvalds 已提交
334 335 336
	data->beep_mask &= data->alarm_mask;
	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);

337
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
338 339 340
	return count;
}

341 342
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
L
Linus Torvalds 已提交
343
{
344 345 346
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
	int n = to_sensor_dev_attr(attr)->index;
L
Linus Torvalds 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359
	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!\n", v);
		return -EINVAL;
	}

360
	mutex_lock(&data->update_lock);
361
	data->fan_div[n] = r;
L
Linus Torvalds 已提交
362

363 364 365 366
	if (n == 0)
		gl520_write_value(client, GL520_REG_FAN_DIV,
				  (gl520_read_value(client, GL520_REG_FAN_DIV)
				   & ~0xc0) | (r << 6));
L
Linus Torvalds 已提交
367
	else
368 369 370
		gl520_write_value(client, GL520_REG_FAN_DIV,
				  (gl520_read_value(client, GL520_REG_FAN_DIV)
				   & ~0x30) | (r << 4));
L
Linus Torvalds 已提交
371

372
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
373 374 375
	return count;
}

376 377
static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
L
Linus Torvalds 已提交
378
{
379 380
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
381 382
	u8 r = simple_strtoul(buf, NULL, 10)?1:0;

383
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
384
	data->fan_off = r;
385 386 387
	gl520_write_value(client, GL520_REG_FAN_OFF,
			  (gl520_read_value(client, GL520_REG_FAN_OFF)
			   & ~0x0c) | (r << 2));
388
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
389 390 391
	return count;
}

392 393 394 395 396 397 398 399 400 401 402 403 404
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);

L
Linus Torvalds 已提交
405 406 407
#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))

408 409
static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
			      char *buf)
L
Linus Torvalds 已提交
410
{
411 412 413 414
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n]));
L
Linus Torvalds 已提交
415 416
}

417 418
static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
419
{
420 421 422 423
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n]));
L
Linus Torvalds 已提交
424 425
}

426 427
static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute
				 *attr, char *buf)
L
Linus Torvalds 已提交
428
{
429 430 431 432
	int n = to_sensor_dev_attr(attr)->index;
	struct gl520_data *data = gl520_update_device(dev);

	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n]));
L
Linus Torvalds 已提交
433 434
}

435 436
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
437
{
438 439 440
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
	int n = to_sensor_dev_attr(attr)->index;
L
Linus Torvalds 已提交
441 442
	long v = simple_strtol(buf, NULL, 10);

443
	mutex_lock(&data->update_lock);
444 445
	data->temp_max[n] = TEMP_TO_REG(v);
	gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]);
446
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
447 448 449
	return count;
}

450 451
static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
				 *attr, const char *buf, size_t count)
L
Linus Torvalds 已提交
452
{
453 454 455
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
	int n = to_sensor_dev_attr(attr)->index;
L
Linus Torvalds 已提交
456 457
	long v = simple_strtol(buf, NULL, 10);

458
	mutex_lock(&data->update_lock);
459 460 461
	data->temp_max_hyst[n] = TEMP_TO_REG(v);
	gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n],
			  data->temp_max_hyst[n]);
462
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
463 464 465
	return count;
}

466 467 468 469 470 471 472 473 474 475 476 477 478
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)
L
Linus Torvalds 已提交
479
{
480
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
481 482 483
	return sprintf(buf, "%d\n", data->alarms);
}

484 485
static ssize_t get_beep_enable(struct device *dev, struct device_attribute
			       *attr, char *buf)
L
Linus Torvalds 已提交
486
{
487
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
488 489 490
	return sprintf(buf, "%d\n", data->beep_enable);
}

491 492
static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
			     char *buf)
L
Linus Torvalds 已提交
493
{
494
	struct gl520_data *data = gl520_update_device(dev);
L
Linus Torvalds 已提交
495 496 497
	return sprintf(buf, "%d\n", data->beep_mask);
}

498 499
static ssize_t set_beep_enable(struct device *dev, struct device_attribute
			       *attr, const char *buf, size_t count)
L
Linus Torvalds 已提交
500
{
501 502
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
503 504
	u8 r = simple_strtoul(buf, NULL, 10)?0:1;

505
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
506
	data->beep_enable = !r;
507 508 509
	gl520_write_value(client, GL520_REG_BEEP_ENABLE,
			  (gl520_read_value(client, GL520_REG_BEEP_ENABLE)
			   & ~0x04) | (r << 2));
510
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
511 512 513
	return count;
}

514 515
static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
516
{
517 518
	struct i2c_client *client = to_i2c_client(dev);
	struct gl520_data *data = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
519
	u8 r = simple_strtoul(buf, NULL, 10);
J
Jean Delvare 已提交
520

521
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
522 523
	r &= data->alarm_mask;
	data->beep_mask = r;
524
	gl520_write_value(client, GL520_REG_BEEP_MASK, r);
525
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
526 527 528
	return count;
}

529 530 531 532 533 534
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);

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 582 583 584 585 586 587 588 589 590 591 592 593 594 595
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\n", (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\n", (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);

596 597 598
static struct attribute *gl520_attributes[] = {
	&dev_attr_cpu0_vid.attr,

599 600 601
	&sensor_dev_attr_in0_input.dev_attr.attr,
	&sensor_dev_attr_in0_min.dev_attr.attr,
	&sensor_dev_attr_in0_max.dev_attr.attr,
602 603
	&sensor_dev_attr_in0_alarm.dev_attr.attr,
	&sensor_dev_attr_in0_beep.dev_attr.attr,
604 605 606
	&sensor_dev_attr_in1_input.dev_attr.attr,
	&sensor_dev_attr_in1_min.dev_attr.attr,
	&sensor_dev_attr_in1_max.dev_attr.attr,
607 608
	&sensor_dev_attr_in1_alarm.dev_attr.attr,
	&sensor_dev_attr_in1_beep.dev_attr.attr,
609 610 611
	&sensor_dev_attr_in2_input.dev_attr.attr,
	&sensor_dev_attr_in2_min.dev_attr.attr,
	&sensor_dev_attr_in2_max.dev_attr.attr,
612 613
	&sensor_dev_attr_in2_alarm.dev_attr.attr,
	&sensor_dev_attr_in2_beep.dev_attr.attr,
614 615 616
	&sensor_dev_attr_in3_input.dev_attr.attr,
	&sensor_dev_attr_in3_min.dev_attr.attr,
	&sensor_dev_attr_in3_max.dev_attr.attr,
617 618
	&sensor_dev_attr_in3_alarm.dev_attr.attr,
	&sensor_dev_attr_in3_beep.dev_attr.attr,
619 620 621 622

	&sensor_dev_attr_fan1_input.dev_attr.attr,
	&sensor_dev_attr_fan1_min.dev_attr.attr,
	&sensor_dev_attr_fan1_div.dev_attr.attr,
623 624
	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
	&sensor_dev_attr_fan1_beep.dev_attr.attr,
625
	&dev_attr_fan1_off.attr,
626 627 628
	&sensor_dev_attr_fan2_input.dev_attr.attr,
	&sensor_dev_attr_fan2_min.dev_attr.attr,
	&sensor_dev_attr_fan2_div.dev_attr.attr,
629 630
	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
	&sensor_dev_attr_fan2_beep.dev_attr.attr,
631

632 633 634
	&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,
635 636
	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
	&sensor_dev_attr_temp1_beep.dev_attr.attr,
637 638 639 640 641 642 643 644 645 646 647 648

	&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[] = {
649 650 651
	&sensor_dev_attr_in4_input.dev_attr.attr,
	&sensor_dev_attr_in4_min.dev_attr.attr,
	&sensor_dev_attr_in4_max.dev_attr.attr,
652 653
	&sensor_dev_attr_in4_alarm.dev_attr.attr,
	&sensor_dev_attr_in4_beep.dev_attr.attr,
654

655 656 657
	&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,
658 659
	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
	&sensor_dev_attr_temp2_beep.dev_attr.attr,
660 661 662 663 664 665 666
	NULL
};

static const struct attribute_group gl520_group_opt = {
	.attrs = gl520_attributes_opt,
};

L
Linus Torvalds 已提交
667 668 669 670 671 672 673 674 675

/*
 * Real code
 */

static int gl520_attach_adapter(struct i2c_adapter *adapter)
{
	if (!(adapter->class & I2C_CLASS_HWMON))
		return 0;
676
	return i2c_probe(adapter, &addr_data, gl520_detect);
L
Linus Torvalds 已提交
677 678 679 680
}

static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
{
J
Jean Delvare 已提交
681
	struct i2c_client *client;
L
Linus Torvalds 已提交
682 683 684 685 686 687 688 689 690 691 692
	struct gl520_data *data;
	int err = 0;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
				     I2C_FUNC_SMBUS_WORD_DATA))
		goto exit;

	/* OK. For now, we presume we have a valid client. We now create the
	   client structure, even though we cannot fill it completely yet.
	   But it allows us to access gl520_{read,write}_value. */

D
Deepak Saxena 已提交
693
	if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
L
Linus Torvalds 已提交
694 695 696 697
		err = -ENOMEM;
		goto exit;
	}

J
Jean Delvare 已提交
698 699 700 701 702
	client = &data->client;
	i2c_set_clientdata(client, data);
	client->addr = address;
	client->adapter = adapter;
	client->driver = &gl520_driver;
L
Linus Torvalds 已提交
703 704 705

	/* Determine the chip type. */
	if (kind < 0) {
J
Jean Delvare 已提交
706 707 708 709
		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\n");
L
Linus Torvalds 已提交
710 711 712 713 714
			goto exit_free;
		}
	}

	/* Fill in the remaining client fields */
J
Jean Delvare 已提交
715
	strlcpy(client->name, "gl520sm", I2C_NAME_SIZE);
716
	mutex_init(&data->update_lock);
L
Linus Torvalds 已提交
717 718

	/* Tell the I2C layer a new client has arrived */
J
Jean Delvare 已提交
719
	if ((err = i2c_attach_client(client)))
L
Linus Torvalds 已提交
720 721 722
		goto exit_free;

	/* Initialize the GL520SM chip */
J
Jean Delvare 已提交
723
	gl520_init_client(client);
L
Linus Torvalds 已提交
724 725

	/* Register sysfs hooks */
J
Jean Delvare 已提交
726
	if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
727
		goto exit_detach;
L
Linus Torvalds 已提交
728

729
	if (data->two_temps) {
J
Jean Delvare 已提交
730
		if ((err = device_create_file(&client->dev,
731
				&sensor_dev_attr_temp2_input.dev_attr))
J
Jean Delvare 已提交
732
		 || (err = device_create_file(&client->dev,
733
				&sensor_dev_attr_temp2_max.dev_attr))
J
Jean Delvare 已提交
734
		 || (err = device_create_file(&client->dev,
735 736 737 738 739
				&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)))
740 741
			goto exit_remove_files;
	} else {
J
Jean Delvare 已提交
742
		if ((err = device_create_file(&client->dev,
743
				&sensor_dev_attr_in4_input.dev_attr))
J
Jean Delvare 已提交
744
		 || (err = device_create_file(&client->dev,
745
				&sensor_dev_attr_in4_min.dev_attr))
J
Jean Delvare 已提交
746
		 || (err = device_create_file(&client->dev,
747 748 749 750 751
				&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)))
752 753
			goto exit_remove_files;
	}
L
Linus Torvalds 已提交
754 755


J
Jean Delvare 已提交
756
	data->hwmon_dev = hwmon_device_register(&client->dev);
757 758
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
759 760
		goto exit_remove_files;
	}
L
Linus Torvalds 已提交
761 762 763

	return 0;

764
exit_remove_files:
J
Jean Delvare 已提交
765 766
	sysfs_remove_group(&client->dev.kobj, &gl520_group);
	sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
767
exit_detach:
J
Jean Delvare 已提交
768
	i2c_detach_client(client);
L
Linus Torvalds 已提交
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
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;
785
	data->vrm = vid_which_vrm();
L
Linus Torvalds 已提交
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815

	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);
}

static int gl520_detach_client(struct i2c_client *client)
{
816
	struct gl520_data *data = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
817 818
	int err;

819
	hwmon_device_unregister(data->hwmon_dev);
820 821
	sysfs_remove_group(&client->dev.kobj, &gl520_group);
	sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
822

823
	if ((err = i2c_detach_client(client)))
L
Linus Torvalds 已提交
824 825
		return err;

826
	kfree(data);
L
Linus Torvalds 已提交
827 828 829 830
	return 0;
}


J
Jean Delvare 已提交
831
/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
L
Linus Torvalds 已提交
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
   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);
854
	int val, i;
L
Linus Torvalds 已提交
855

856
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
857

858
	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
L
Linus Torvalds 已提交
859 860 861 862 863 864 865

		dev_dbg(&client->dev, "Starting gl520sm update\n");

		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;

866 867 868 869 870 871 872
		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;
		}
L
Linus Torvalds 已提交
873 874 875 876 877 878 879 880 881

		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;

882 883 884 885 886 887
		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]);
L
Linus Torvalds 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900

		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);

		/* Temp1 and Vin4 are the same input */
		if (data->two_temps) {
901 902 903 904 905 906
			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]);
L
Linus Torvalds 已提交
907
		} else {
908 909 910 911 912 913
			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]);
L
Linus Torvalds 已提交
914 915 916 917 918 919
		}

		data->last_updated = jiffies;
		data->valid = 1;
	}

920
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937

	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>, "
938
	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
L
Linus Torvalds 已提交
939 940 941 942 943 944
	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
MODULE_DESCRIPTION("GL520SM driver");
MODULE_LICENSE("GPL");

module_init(sensors_gl520sm_init);
module_exit(sensors_gl520sm_exit);