OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [hwmon/] [fscpos.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
        fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips
3
        Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
4
 
5
        This program is free software; you can redistribute it and/or modify
6
        it under the terms of the GNU General Public License as published by
7
        the Free Software Foundation; either version 2 of the License, or
8
        (at your option) any later version.
9
 
10
        This program is distributed in the hope that it will be useful,
11
        but WITHOUT ANY WARRANTY; without even the implied warranty of
12
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
        GNU General Public License for more details.
14
 
15
        You should have received a copy of the GNU General Public License
16
        along with this program; if not, write to the Free Software
17
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
*/
19
 
20
/*
21
        fujitsu siemens poseidon chip,
22
        module based on the old fscpos module by Hermann Jung <hej@odn.de> and
23
        the fscher module by Reinhard Nissl <rnissl@gmx.de>
24
 
25
        original module based on lm80.c
26
        Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
27
        and Philip Edelbrock <phil@netroedge.com>
28
 
29
        Thanks to Jean Delvare for reviewing my code and suggesting a lot of
30
        improvements.
31
*/
32
 
33
#include <linux/module.h>
34
#include <linux/slab.h>
35
#include <linux/jiffies.h>
36
#include <linux/i2c.h>
37
#include <linux/init.h>
38
#include <linux/hwmon.h>
39
#include <linux/err.h>
40
#include <linux/mutex.h>
41
#include <linux/sysfs.h>
42
 
43
/*
44
 * Addresses to scan
45
 */
46
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
47
 
48
/*
49
 * Insmod parameters
50
 */
51
I2C_CLIENT_INSMOD_1(fscpos);
52
 
53
/*
54
 * The FSCPOS registers
55
 */
56
 
57
/* chip identification */
58
#define FSCPOS_REG_IDENT_0              0x00
59
#define FSCPOS_REG_IDENT_1              0x01
60
#define FSCPOS_REG_IDENT_2              0x02
61
#define FSCPOS_REG_REVISION             0x03
62
 
63
/* global control and status */
64
#define FSCPOS_REG_EVENT_STATE          0x04
65
#define FSCPOS_REG_CONTROL              0x05
66
 
67
/* watchdog */
68
#define FSCPOS_REG_WDOG_PRESET          0x28
69
#define FSCPOS_REG_WDOG_STATE           0x23
70
#define FSCPOS_REG_WDOG_CONTROL         0x21
71
 
72
/* voltages */
73
#define FSCPOS_REG_VOLT_12              0x45
74
#define FSCPOS_REG_VOLT_5               0x42
75
#define FSCPOS_REG_VOLT_BATT            0x48
76
 
77
/* fans - the chip does not support minimum speed for fan2 */
78
static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 };
79
static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab };
80
static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 };
81
static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf };
82
 
83
/* temperatures */
84
static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 };
85
static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 };
86
 
87
/*
88
 * Functions declaration
89
 */
90
static int fscpos_attach_adapter(struct i2c_adapter *adapter);
91
static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind);
92
static int fscpos_detach_client(struct i2c_client *client);
93
 
94
static int fscpos_read_value(struct i2c_client *client, u8 reg);
95
static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value);
96
static struct fscpos_data *fscpos_update_device(struct device *dev);
97
static void fscpos_init_client(struct i2c_client *client);
98
 
99
static void reset_fan_alarm(struct i2c_client *client, int nr);
100
 
101
/*
102
 * Driver data (common to all clients)
103
 */
104
static struct i2c_driver fscpos_driver = {
105
        .driver = {
106
                .name   = "fscpos",
107
        },
108
        .id             = I2C_DRIVERID_FSCPOS,
109
        .attach_adapter = fscpos_attach_adapter,
110
        .detach_client  = fscpos_detach_client,
111
};
112
 
113
/*
114
 * Client data (each client gets its own)
115
 */
116
struct fscpos_data {
117
        struct i2c_client client;
118
        struct device *hwmon_dev;
119
        struct mutex update_lock;
120
        char valid;             /* 0 until following fields are valid */
121
        unsigned long last_updated;     /* In jiffies */
122
 
123
        /* register values */
124
        u8 revision;            /* revision of chip */
125
        u8 global_event;        /* global event status */
126
        u8 global_control;      /* global control register */
127
        u8 wdog_control;        /* watchdog control */
128
        u8 wdog_state;          /* watchdog status */
129
        u8 wdog_preset;         /* watchdog preset */
130
        u8 volt[3];             /* 12, 5, battery current */
131
        u8 temp_act[3];         /* temperature */
132
        u8 temp_status[3];      /* status of sensor */
133
        u8 fan_act[3];          /* fans revolutions per second */
134
        u8 fan_status[3];       /* fan status */
135
        u8 pwm[2];              /* fan min value for rps */
136
        u8 fan_ripple[3];       /* divider for rps */
137
};
138
 
139
/* Temperature */
140
#define TEMP_FROM_REG(val)      (((val) - 128) * 1000)
141
 
142
static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr)
143
{
144
        return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1]));
145
}
146
 
147
static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr)
148
{
149
        /* bits 2..7 reserved => mask with 0x03 */
150
        return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03);
151
}
152
 
153
static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr)
154
{
155
        return sprintf(buf, "1\n");
156
}
157
 
158
static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data
159
                        *data, const char *buf, size_t count, int nr, int reg)
160
{
161
        unsigned long v = simple_strtoul(buf, NULL, 10);
162
        if (v != 1) {
163
                dev_err(&client->dev, "temp_reset value %ld not supported. "
164
                                        "Use 1 to reset the alarm!\n", v);
165
                return -EINVAL;
166
        }
167
 
168
        dev_info(&client->dev, "You used the temp_reset feature which has not "
169
                                "been proplerly tested. Please report your "
170
                                "experience to the module author.\n");
171
 
172
        /* Supported value: 2 (clears the status) */
173
        fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr - 1], 2);
174
        return count;
175
}
176
 
177
/* Fans */
178
#define RPM_FROM_REG(val)       ((val) * 60)
179
 
180
static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr)
181
{
182
        /* bits 0..1, 3..7 reserved => mask with 0x04 */
183
        return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04);
184
}
185
 
186
static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr)
187
{
188
        return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1]));
189
}
190
 
191
static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr)
192
{
193
        /* bits 2..7 reserved => mask with 0x03 */
194
        return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03);
195
}
196
 
197
static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data
198
                        *data, const char *buf, size_t count, int nr, int reg)
199
{
200
        /* supported values: 2, 4, 8 */
201
        unsigned long v = simple_strtoul(buf, NULL, 10);
202
 
203
        switch (v) {
204
                case 2: v = 1; break;
205
                case 4: v = 2; break;
206
                case 8: v = 3; break;
207
        default:
208
                dev_err(&client->dev, "fan_ripple value %ld not supported. "
209
                                        "Must be one of 2, 4 or 8!\n", v);
210
                return -EINVAL;
211
        }
212
 
213
        mutex_lock(&data->update_lock);
214
        /* bits 2..7 reserved => mask with 0x03 */
215
        data->fan_ripple[nr - 1] &= ~0x03;
216
        data->fan_ripple[nr - 1] |= v;
217
 
218
        fscpos_write_value(client, reg, data->fan_ripple[nr - 1]);
219
        mutex_unlock(&data->update_lock);
220
        return count;
221
}
222
 
223
static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr)
224
{
225
        return sprintf(buf, "%u\n", data->pwm[nr - 1]);
226
}
227
 
228
static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data,
229
                                const char *buf, size_t count, int nr, int reg)
230
{
231
        unsigned long v = simple_strtoul(buf, NULL, 10);
232
 
233
        /* Range: 0..255 */
234
        if (v < 0) v = 0;
235
        if (v > 255) v = 255;
236
 
237
        mutex_lock(&data->update_lock);
238
        data->pwm[nr - 1] = v;
239
        fscpos_write_value(client, reg, data->pwm[nr - 1]);
240
        mutex_unlock(&data->update_lock);
241
        return count;
242
}
243
 
244
static void reset_fan_alarm(struct i2c_client *client, int nr)
245
{
246
        fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4);
247
}
248
 
249
/* Volts */
250
#define VOLT_FROM_REG(val, mult)        ((val) * (mult) / 255)
251
 
252
static ssize_t show_volt_12(struct device *dev, struct device_attribute *attr, char *buf)
253
{
254
        struct fscpos_data *data = fscpos_update_device(dev);
255
        return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200));
256
}
257
 
258
static ssize_t show_volt_5(struct device *dev, struct device_attribute *attr, char *buf)
259
{
260
        struct fscpos_data *data = fscpos_update_device(dev);
261
        return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600));
262
}
263
 
264
static ssize_t show_volt_batt(struct device *dev, struct device_attribute *attr, char *buf)
265
{
266
        struct fscpos_data *data = fscpos_update_device(dev);
267
        return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300));
268
}
269
 
270
/* Watchdog */
271
static ssize_t show_wdog_control(struct fscpos_data *data, char *buf)
272
{
273
        /* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */
274
        return sprintf(buf, "%u\n", data->wdog_control & 0xb0);
275
}
276
 
277
static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data
278
                                *data, const char *buf, size_t count, int reg)
279
{
280
        /* bits 0..3 reserved => mask with 0xf0 */
281
        unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
282
 
283
        mutex_lock(&data->update_lock);
284
        data->wdog_control &= ~0xf0;
285
        data->wdog_control |= v;
286
        fscpos_write_value(client, reg, data->wdog_control);
287
        mutex_unlock(&data->update_lock);
288
        return count;
289
}
290
 
291
static ssize_t show_wdog_state(struct fscpos_data *data, char *buf)
292
{
293
        /* bits 0, 2..7 reserved => mask with 0x02 */
294
        return sprintf(buf, "%u\n", data->wdog_state & 0x02);
295
}
296
 
297
static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data
298
                                *data, const char *buf, size_t count, int reg)
299
{
300
        unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
301
 
302
        /* Valid values: 2 (clear) */
303
        if (v != 2) {
304
                dev_err(&client->dev, "wdog_state value %ld not supported. "
305
                                        "Must be 2 to clear the state!\n", v);
306
                return -EINVAL;
307
        }
308
 
309
        mutex_lock(&data->update_lock);
310
        data->wdog_state &= ~v;
311
        fscpos_write_value(client, reg, v);
312
        mutex_unlock(&data->update_lock);
313
        return count;
314
}
315
 
316
static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf)
317
{
318
        return sprintf(buf, "%u\n", data->wdog_preset);
319
}
320
 
321
static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data
322
                                *data, const char *buf, size_t count, int reg)
323
{
324
        unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
325
 
326
        mutex_lock(&data->update_lock);
327
        data->wdog_preset = v;
328
        fscpos_write_value(client, reg, data->wdog_preset);
329
        mutex_unlock(&data->update_lock);
330
        return count;
331
}
332
 
333
/* Event */
334
static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf)
335
{
336
        /* bits 5..7 reserved => mask with 0x1f */
337
        struct fscpos_data *data = fscpos_update_device(dev);
338
        return sprintf(buf, "%u\n", data->global_event & 0x9b);
339
}
340
 
341
/*
342
 * Sysfs stuff
343
 */
344
#define create_getter(kind, sub) \
345
        static ssize_t sysfs_show_##kind##sub(struct device *dev, struct device_attribute *attr, char *buf) \
346
        { \
347
                struct fscpos_data *data = fscpos_update_device(dev); \
348
                return show_##kind##sub(data, buf); \
349
        }
350
 
351
#define create_getter_n(kind, offset, sub) \
352
        static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, struct device_attribute *attr, char\
353
                                                                        *buf) \
354
        { \
355
                struct fscpos_data *data = fscpos_update_device(dev); \
356
                return show_##kind##sub(data, buf, offset); \
357
        }
358
 
359
#define create_setter(kind, sub, reg) \
360
        static ssize_t sysfs_set_##kind##sub (struct device *dev, struct device_attribute *attr, const char \
361
                                                        *buf, size_t count) \
362
        { \
363
                struct i2c_client *client = to_i2c_client(dev); \
364
                struct fscpos_data *data = i2c_get_clientdata(client); \
365
                return set_##kind##sub(client, data, buf, count, reg); \
366
        }
367
 
368
#define create_setter_n(kind, offset, sub, reg) \
369
        static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, \
370
                                        const char *buf, size_t count) \
371
        { \
372
                struct i2c_client *client = to_i2c_client(dev); \
373
                struct fscpos_data *data = i2c_get_clientdata(client); \
374
                return set_##kind##sub(client, data, buf, count, offset, reg);\
375
        }
376
 
377
#define create_sysfs_device_ro(kind, sub, offset) \
378
        static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \
379
                                        sysfs_show_##kind##offset##sub, NULL);
380
 
381
#define create_sysfs_device_rw(kind, sub, offset) \
382
        static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \
383
                sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub);
384
 
385
#define sysfs_ro_n(kind, sub, offset) \
386
        create_getter_n(kind, offset, sub); \
387
        create_sysfs_device_ro(kind, sub, offset);
388
 
389
#define sysfs_rw_n(kind, sub, offset, reg) \
390
        create_getter_n(kind, offset, sub); \
391
        create_setter_n(kind, offset, sub, reg); \
392
        create_sysfs_device_rw(kind, sub, offset);
393
 
394
#define sysfs_rw(kind, sub, reg) \
395
        create_getter(kind, sub); \
396
        create_setter(kind, sub, reg); \
397
        create_sysfs_device_rw(kind, sub,);
398
 
399
#define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \
400
        sysfs_fan(offset, reg_status, reg_ripple); \
401
        sysfs_rw_n(pwm,, offset, reg_min);
402
 
403
#define sysfs_fan(offset, reg_status, reg_ripple) \
404
        sysfs_ro_n(fan, _input, offset); \
405
        sysfs_ro_n(fan, _status, offset); \
406
        sysfs_rw_n(fan, _ripple, offset, reg_ripple);
407
 
408
#define sysfs_temp(offset, reg_status) \
409
        sysfs_ro_n(temp, _input, offset); \
410
        sysfs_ro_n(temp, _status, offset); \
411
        sysfs_rw_n(temp, _reset, offset, reg_status);
412
 
413
#define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \
414
        sysfs_rw(wdog, _control, reg_wdog_control); \
415
        sysfs_rw(wdog, _preset, reg_wdog_preset); \
416
        sysfs_rw(wdog, _state, reg_wdog_state);
417
 
418
sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0],
419
                                                        FSCPOS_REG_PWM[0]);
420
sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1],
421
                                                        FSCPOS_REG_PWM[1]);
422
sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]);
423
 
424
sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]);
425
sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]);
426
sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]);
427
 
428
sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE,
429
                                                FSCPOS_REG_WDOG_CONTROL);
430
 
431
static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
432
static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
433
static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
434
static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
435
 
436
static struct attribute *fscpos_attributes[] = {
437
        &dev_attr_event.attr,
438
        &dev_attr_in0_input.attr,
439
        &dev_attr_in1_input.attr,
440
        &dev_attr_in2_input.attr,
441
 
442
        &dev_attr_wdog_control.attr,
443
        &dev_attr_wdog_preset.attr,
444
        &dev_attr_wdog_state.attr,
445
 
446
        &dev_attr_temp1_input.attr,
447
        &dev_attr_temp1_status.attr,
448
        &dev_attr_temp1_reset.attr,
449
        &dev_attr_temp2_input.attr,
450
        &dev_attr_temp2_status.attr,
451
        &dev_attr_temp2_reset.attr,
452
        &dev_attr_temp3_input.attr,
453
        &dev_attr_temp3_status.attr,
454
        &dev_attr_temp3_reset.attr,
455
 
456
        &dev_attr_fan1_input.attr,
457
        &dev_attr_fan1_status.attr,
458
        &dev_attr_fan1_ripple.attr,
459
        &dev_attr_pwm1.attr,
460
        &dev_attr_fan2_input.attr,
461
        &dev_attr_fan2_status.attr,
462
        &dev_attr_fan2_ripple.attr,
463
        &dev_attr_pwm2.attr,
464
        &dev_attr_fan3_input.attr,
465
        &dev_attr_fan3_status.attr,
466
        &dev_attr_fan3_ripple.attr,
467
        NULL
468
};
469
 
470
static const struct attribute_group fscpos_group = {
471
        .attrs = fscpos_attributes,
472
};
473
 
474
static int fscpos_attach_adapter(struct i2c_adapter *adapter)
475
{
476
        if (!(adapter->class & I2C_CLASS_HWMON))
477
                return 0;
478
        return i2c_probe(adapter, &addr_data, fscpos_detect);
479
}
480
 
481
static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
482
{
483
        struct i2c_client *new_client;
484
        struct fscpos_data *data;
485
        int err = 0;
486
 
487
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
488
                goto exit;
489
 
490
        /*
491
         * OK. For now, we presume we have a valid client. We now create the
492
         * client structure, even though we cannot fill it completely yet.
493
         * But it allows us to access fscpos_{read,write}_value.
494
         */
495
 
496
        if (!(data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL))) {
497
                err = -ENOMEM;
498
                goto exit;
499
        }
500
 
501
        new_client = &data->client;
502
        i2c_set_clientdata(new_client, data);
503
        new_client->addr = address;
504
        new_client->adapter = adapter;
505
        new_client->driver = &fscpos_driver;
506
        new_client->flags = 0;
507
 
508
        /* Do the remaining detection unless force or force_fscpos parameter */
509
        if (kind < 0) {
510
                if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0)
511
                        != 0x50) /* 'P' */
512
                || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1)
513
                        != 0x45) /* 'E' */
514
                || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
515
                        != 0x47))/* 'G' */
516
                {
517
                        dev_dbg(&new_client->dev, "fscpos detection failed\n");
518
                        goto exit_free;
519
                }
520
        }
521
 
522
        /* Fill in the remaining client fields and put it in the global list */
523
        strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE);
524
 
525
        data->valid = 0;
526
        mutex_init(&data->update_lock);
527
 
528
        /* Tell the I2C layer a new client has arrived */
529
        if ((err = i2c_attach_client(new_client)))
530
                goto exit_free;
531
 
532
        /* Inizialize the fscpos chip */
533
        fscpos_init_client(new_client);
534
 
535
        /* Announce that the chip was found */
536
        dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
537
 
538
        /* Register sysfs hooks */
539
        if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
540
                goto exit_detach;
541
 
542
        data->hwmon_dev = hwmon_device_register(&new_client->dev);
543
        if (IS_ERR(data->hwmon_dev)) {
544
                err = PTR_ERR(data->hwmon_dev);
545
                goto exit_remove_files;
546
        }
547
 
548
        return 0;
549
 
550
exit_remove_files:
551
        sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
552
exit_detach:
553
        i2c_detach_client(new_client);
554
exit_free:
555
        kfree(data);
556
exit:
557
        return err;
558
}
559
 
560
static int fscpos_detach_client(struct i2c_client *client)
561
{
562
        struct fscpos_data *data = i2c_get_clientdata(client);
563
        int err;
564
 
565
        hwmon_device_unregister(data->hwmon_dev);
566
        sysfs_remove_group(&client->dev.kobj, &fscpos_group);
567
 
568
        if ((err = i2c_detach_client(client)))
569
                return err;
570
        kfree(data);
571
        return 0;
572
}
573
 
574
static int fscpos_read_value(struct i2c_client *client, u8 reg)
575
{
576
        dev_dbg(&client->dev, "Read reg 0x%02x\n", reg);
577
        return i2c_smbus_read_byte_data(client, reg);
578
}
579
 
580
static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value)
581
{
582
        dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value);
583
        return i2c_smbus_write_byte_data(client, reg, value);
584
}
585
 
586
/* Called when we have found a new FSCPOS chip */
587
static void fscpos_init_client(struct i2c_client *client)
588
{
589
        struct fscpos_data *data = i2c_get_clientdata(client);
590
 
591
        /* read revision from chip */
592
        data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION);
593
}
594
 
595
static struct fscpos_data *fscpos_update_device(struct device *dev)
596
{
597
        struct i2c_client *client = to_i2c_client(dev);
598
        struct fscpos_data *data = i2c_get_clientdata(client);
599
 
600
        mutex_lock(&data->update_lock);
601
 
602
        if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
603
                int i;
604
 
605
                dev_dbg(&client->dev, "Starting fscpos update\n");
606
 
607
                for (i = 0; i < 3; i++) {
608
                        data->temp_act[i] = fscpos_read_value(client,
609
                                                FSCPOS_REG_TEMP_ACT[i]);
610
                        data->temp_status[i] = fscpos_read_value(client,
611
                                                FSCPOS_REG_TEMP_STATE[i]);
612
                        data->fan_act[i] = fscpos_read_value(client,
613
                                                FSCPOS_REG_FAN_ACT[i]);
614
                        data->fan_status[i] = fscpos_read_value(client,
615
                                                FSCPOS_REG_FAN_STATE[i]);
616
                        data->fan_ripple[i] = fscpos_read_value(client,
617
                                                FSCPOS_REG_FAN_RIPPLE[i]);
618
                        if (i < 2) {
619
                                /* fan2_min is not supported by the chip */
620
                                data->pwm[i] = fscpos_read_value(client,
621
                                                        FSCPOS_REG_PWM[i]);
622
                        }
623
                        /* reset fan status if speed is back to > 0 */
624
                        if (data->fan_status[i] != 0 && data->fan_act[i] > 0) {
625
                                reset_fan_alarm(client, i);
626
                        }
627
                }
628
 
629
                data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12);
630
                data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5);
631
                data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT);
632
 
633
                data->wdog_preset = fscpos_read_value(client,
634
                                                        FSCPOS_REG_WDOG_PRESET);
635
                data->wdog_state = fscpos_read_value(client,
636
                                                        FSCPOS_REG_WDOG_STATE);
637
                data->wdog_control = fscpos_read_value(client,
638
                                                FSCPOS_REG_WDOG_CONTROL);
639
 
640
                data->global_event = fscpos_read_value(client,
641
                                                FSCPOS_REG_EVENT_STATE);
642
 
643
                data->last_updated = jiffies;
644
                data->valid = 1;
645
        }
646
        mutex_unlock(&data->update_lock);
647
        return data;
648
}
649
 
650
static int __init sm_fscpos_init(void)
651
{
652
        return i2c_add_driver(&fscpos_driver);
653
}
654
 
655
static void __exit sm_fscpos_exit(void)
656
{
657
        i2c_del_driver(&fscpos_driver);
658
}
659
 
660
MODULE_AUTHOR("Stefan Ott <stefan@desire.ch> based on work from Hermann Jung "
661
                                "<hej@odn.de>, Frodo Looijaard <frodol@dds.nl>"
662
                                " and Philip Edelbrock <phil@netroedge.com>");
663
MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver");
664
MODULE_LICENSE("GPL");
665
 
666
module_init(sm_fscpos_init);
667
module_exit(sm_fscpos_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.